From 3c88be6636149d72a15dd2b1f7973420c894a0e0 Mon Sep 17 00:00:00 2001 From: Charlie Little Date: Fri, 29 Mar 2024 17:56:19 -0500 Subject: [PATCH 1/3] Push deposit fees to pending queue --- src/app.rs | 16 ++++++++++------ src/bin/nomic.rs | 16 ++++++++++++---- src/bitcoin/mod.rs | 13 +++++++++++-- src/bitcoin/recovery.rs | 12 ++++++++++-- src/bitcoin/relayer.rs | 30 +++++++++++++++++++++++++----- tests/bitcoin.rs | 5 ++++- 6 files changed, 72 insertions(+), 20 deletions(-) diff --git a/src/app.rs b/src/app.rs index 84c8f6eb1..f53634385 100644 --- a/src/app.rs +++ b/src/app.rs @@ -278,6 +278,7 @@ impl InnerApp { match dest { Dest::Address(addr) => self.bitcoin.accounts.deposit(addr, nbtc), Dest::Ibc(dest) => dest.transfer(nbtc, &mut self.bitcoin, &mut self.ibc), + Dest::Fee => Ok(self.bitcoin.give_rewards(nbtc)?), } } @@ -1011,13 +1012,15 @@ pub struct MsgIbcTransfer { pub enum Dest { Address(Address), Ibc(IbcDest), + Fee, } impl Dest { - pub fn to_receiver_addr(&self) -> String { + pub fn to_receiver_addr(&self) -> Option { match self { - Dest::Address(addr) => addr.to_string(), - Dest::Ibc(dest) => dest.receiver.0.to_string(), + Dest::Address(addr) => Some(addr.to_string()), + Dest::Ibc(dest) => Some(dest.receiver.0.to_string()), + Dest::Fee => None, } } } @@ -1103,12 +1106,13 @@ impl IbcDest { } impl Dest { - pub fn commitment_bytes(&self) -> Result> { + pub fn commitment_bytes(&self) -> Result>> { use sha2::{Digest, Sha256}; use Dest::*; let bytes = match self { - Address(addr) => addr.bytes().into(), - Ibc(dest) => Sha256::digest(dest.encode()?).to_vec(), + Address(addr) => Some(addr.bytes().into()), + Ibc(dest) => Some(Sha256::digest(dest.encode()?).to_vec()), + Fee => None, }; Ok(bytes) diff --git a/src/bin/nomic.rs b/src/bin/nomic.rs index 60685bc79..95c8fd4d0 100644 --- a/src/bin/nomic.rs +++ b/src/bin/nomic.rs @@ -1327,7 +1327,15 @@ async fn deposit( )) }) .await?; - let script = sigset.output_script(dest.commitment_bytes()?.as_slice(), threshold)?; + let commitment_bytes = match dest.commitment_bytes()? { + Some(commitment_bytes) => commitment_bytes, + None => { + return Err(nomic::error::Error::Orga(orga::Error::App( + "Unable to create commitment bytes from fee Dest".to_string(), + ))); + } + }; + let script = sigset.output_script(&commitment_bytes, threshold)?; let btc_addr = bitcoin::Address::from_script(&script, nomic::bitcoin::NETWORK).unwrap(); let mut successes = 0; @@ -2061,7 +2069,7 @@ impl RecoverDepositCmd { dbg!(&dest); let mut i = 0; - let mut dest_bytes = dest.commitment_bytes().unwrap(); + let mut dest_bytes = dest.commitment_bytes().unwrap().unwrap(); loop { for (sigset_index, sigset) in sigsets.iter() { if i % 10_000 == 0 { @@ -2095,7 +2103,7 @@ impl RecoverDepositCmd { if let Dest::Ibc(ibc_dest) = &mut dest { ibc_dest.timeout_timestamp -= 60 * 60 * 1_000_000_000; - dest_bytes = dest.commitment_bytes().unwrap(); + dest_bytes = dest.commitment_bytes().unwrap().unwrap(); } else { unreachable!() } @@ -2103,7 +2111,7 @@ impl RecoverDepositCmd { } let dest = Dest::Address(self.nomic_addr); - let dest_bytes = dest.commitment_bytes().unwrap(); + let dest_bytes = dest.commitment_bytes().unwrap().unwrap(); for (sigset_index, sigset) in sigsets.iter() { let script = sigset.output_script(&dest_bytes, threshold).unwrap(); diff --git a/src/bitcoin/mod.rs b/src/bitcoin/mod.rs index 45b005fec..1491224e2 100644 --- a/src/bitcoin/mod.rs +++ b/src/bitcoin/mod.rs @@ -592,7 +592,14 @@ impl Bitcoin { let checkpoint = self.checkpoints.get(sigset_index)?; let sigset = checkpoint.sigset.clone(); - let dest_bytes = dest.commitment_bytes()?; + let dest_bytes = match dest.commitment_bytes()? { + Some(bytes) => bytes, + None => { + return Err(OrgaError::App( + "Unable to create commitment bytes for fee Dest".to_string(), + ))? + } + }; let expected_script = sigset.output_script(&dest_bytes, self.checkpoints.config.sigset_threshold)?; if output.script_pubkey != expected_script { @@ -662,7 +669,9 @@ impl Bitcoin { // TODO: keep in excess queue if full let deposit_fee = nbtc.take(calc_deposit_fee(nbtc.amount.into()))?; - self.give_rewards(deposit_fee)?; + self.checkpoints + .building_mut()? + .insert_pending(Dest::Fee, deposit_fee)?; self.checkpoints .building_mut()? diff --git a/src/bitcoin/recovery.rs b/src/bitcoin/recovery.rs index 0ff1678cd..87ad4f0af 100644 --- a/src/bitcoin/recovery.rs +++ b/src/bitcoin/recovery.rs @@ -54,17 +54,25 @@ impl RecoveryTxs { .output .get(args.vout as usize) .ok_or_else(|| Error::Signer("Invalid recovery tx vout".to_string()))?; + let commitment_bytes = match args.dest.commitment_bytes()? { + Some(bytes) => bytes, + None => { + return Err(Error::Signer( + "Unable to create commitment bytes for fee Dest".to_string(), + )) + } + }; let input = Input::new( OutPoint::new(args.expired_tx.txid(), args.vout), args.old_sigset, - &args.dest.commitment_bytes()?, + &commitment_bytes, expired_output.value, args.threshold, )?; let script_pubkey = args .new_sigset - .output_script(args.dest.commitment_bytes()?.as_slice(), args.threshold)?; + .output_script(&commitment_bytes, args.threshold)?; let output = TxOut { value: expired_output.value, script_pubkey, diff --git a/src/bitcoin/relayer.rs b/src/bitcoin/relayer.rs index 3fa8bd80b..4f483a5b7 100644 --- a/src/bitcoin/relayer.rs +++ b/src/bitcoin/relayer.rs @@ -204,7 +204,10 @@ impl Relayer { let expected_addr = ::bitcoin::Address::from_script( &sigset .output_script( - dest.commitment_bytes().map_err(|_| reject())?.as_slice(), + dest.commitment_bytes() + .map_err(|_| reject())? + .ok_or(reject())? + .as_slice(), SIGSET_THRESHOLD, ) .map_err(warp::reject::custom)?, @@ -433,8 +436,12 @@ impl Relayer { )?; let mut index = index.lock().await; + let receiver_addr = match dest.to_receiver_addr() { + Some(addr) => addr, + None => continue, + }; index.insert_deposit( - dest.to_receiver_addr(), + receiver_addr, bitcoin_address, Deposit::new(txid, vout as u32, output.value, None), ) @@ -867,6 +874,10 @@ impl Relayer { let txid = tx.txid(); let outpoint = (txid.into_inner(), output.vout); let dest = output.dest.clone(); + if dest.to_receiver_addr().is_none() { + return Ok(()); + } + let receiver_addr = dest.to_receiver_addr().unwrap(); let vout = output.vout; let contains_outpoint = app_client(&self.app_client_addr) .query(|app| app.bitcoin.processed_outpoints.contains(outpoint)) @@ -879,13 +890,13 @@ impl Relayer { if contains_outpoint { let mut index = index.lock().await; - index.remove_deposit(dest.to_receiver_addr(), deposit_address, txid, vout)?; + index.remove_deposit(receiver_addr, deposit_address, txid, vout)?; return Ok(()); } let mut index_guard = index.lock().await; index_guard.insert_deposit( - dest.to_receiver_addr(), + receiver_addr, deposit_address.clone(), Deposit::new( txid, @@ -1190,7 +1201,16 @@ impl WatchedScripts { sigset: &SignatorySet, threshold: (u64, u64), ) -> Result<::bitcoin::Script> { - sigset.output_script(dest.commitment_bytes()?.as_slice(), threshold) + let commitment_bytes = match dest.commitment_bytes()? { + Some(bytes) => bytes, + None => { + return Err(Error::Relayer( + "Could not derive script for fee Dest".to_string(), + )) + } + }; + + sigset.output_script(&commitment_bytes, threshold) } } diff --git a/tests/bitcoin.rs b/tests/bitcoin.rs index 75dc84d76..2d1fab95b 100644 --- a/tests/bitcoin.rs +++ b/tests/bitcoin.rs @@ -69,7 +69,10 @@ async fn generate_deposit_address(address: &Address) -> Result { }) .await?; let script = sigset.output_script( - Dest::Address(*address).commitment_bytes()?.as_slice(), + Dest::Address(*address) + .commitment_bytes()? + .unwrap() + .as_slice(), threshold, )?; From 0de05799d916de2b21ed66cbf5939c79b5271394 Mon Sep 17 00:00:00 2001 From: Charlie Little Date: Wed, 3 Apr 2024 11:24:31 -0500 Subject: [PATCH 2/3] Add commitment bytes to Dest::Fee --- src/app.rs | 8 ++++---- src/bin/nomic.rs | 15 ++++----------- src/bitcoin/mod.rs | 10 +--------- src/bitcoin/recovery.rs | 9 +-------- src/bitcoin/relayer.rs | 16 ++-------------- tests/bitcoin.rs | 5 +---- 6 files changed, 13 insertions(+), 50 deletions(-) diff --git a/src/app.rs b/src/app.rs index f53634385..eaff6ff3e 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1106,13 +1106,13 @@ impl IbcDest { } impl Dest { - pub fn commitment_bytes(&self) -> Result>> { + pub fn commitment_bytes(&self) -> Result> { use sha2::{Digest, Sha256}; use Dest::*; let bytes = match self { - Address(addr) => Some(addr.bytes().into()), - Ibc(dest) => Some(Sha256::digest(dest.encode()?).to_vec()), - Fee => None, + Address(addr) => addr.bytes().into(), + Ibc(dest) => Sha256::digest(dest.encode()?).to_vec(), + Fee => vec![1], }; Ok(bytes) diff --git a/src/bin/nomic.rs b/src/bin/nomic.rs index 95c8fd4d0..1428f0aa1 100644 --- a/src/bin/nomic.rs +++ b/src/bin/nomic.rs @@ -1327,14 +1327,7 @@ async fn deposit( )) }) .await?; - let commitment_bytes = match dest.commitment_bytes()? { - Some(commitment_bytes) => commitment_bytes, - None => { - return Err(nomic::error::Error::Orga(orga::Error::App( - "Unable to create commitment bytes from fee Dest".to_string(), - ))); - } - }; + let commitment_bytes = dest.commitment_bytes()?; let script = sigset.output_script(&commitment_bytes, threshold)?; let btc_addr = bitcoin::Address::from_script(&script, nomic::bitcoin::NETWORK).unwrap(); @@ -2069,7 +2062,7 @@ impl RecoverDepositCmd { dbg!(&dest); let mut i = 0; - let mut dest_bytes = dest.commitment_bytes().unwrap().unwrap(); + let mut dest_bytes = dest.commitment_bytes().unwrap(); loop { for (sigset_index, sigset) in sigsets.iter() { if i % 10_000 == 0 { @@ -2103,7 +2096,7 @@ impl RecoverDepositCmd { if let Dest::Ibc(ibc_dest) = &mut dest { ibc_dest.timeout_timestamp -= 60 * 60 * 1_000_000_000; - dest_bytes = dest.commitment_bytes().unwrap().unwrap(); + dest_bytes = dest.commitment_bytes().unwrap(); } else { unreachable!() } @@ -2111,7 +2104,7 @@ impl RecoverDepositCmd { } let dest = Dest::Address(self.nomic_addr); - let dest_bytes = dest.commitment_bytes().unwrap().unwrap(); + let dest_bytes = dest.commitment_bytes().unwrap(); for (sigset_index, sigset) in sigsets.iter() { let script = sigset.output_script(&dest_bytes, threshold).unwrap(); diff --git a/src/bitcoin/mod.rs b/src/bitcoin/mod.rs index 1491224e2..3c71127c3 100644 --- a/src/bitcoin/mod.rs +++ b/src/bitcoin/mod.rs @@ -591,15 +591,7 @@ impl Bitcoin { let checkpoint = self.checkpoints.get(sigset_index)?; let sigset = checkpoint.sigset.clone(); - - let dest_bytes = match dest.commitment_bytes()? { - Some(bytes) => bytes, - None => { - return Err(OrgaError::App( - "Unable to create commitment bytes for fee Dest".to_string(), - ))? - } - }; + let dest_bytes = dest.commitment_bytes()?; let expected_script = sigset.output_script(&dest_bytes, self.checkpoints.config.sigset_threshold)?; if output.script_pubkey != expected_script { diff --git a/src/bitcoin/recovery.rs b/src/bitcoin/recovery.rs index 87ad4f0af..9c5c842fb 100644 --- a/src/bitcoin/recovery.rs +++ b/src/bitcoin/recovery.rs @@ -54,14 +54,7 @@ impl RecoveryTxs { .output .get(args.vout as usize) .ok_or_else(|| Error::Signer("Invalid recovery tx vout".to_string()))?; - let commitment_bytes = match args.dest.commitment_bytes()? { - Some(bytes) => bytes, - None => { - return Err(Error::Signer( - "Unable to create commitment bytes for fee Dest".to_string(), - )) - } - }; + let commitment_bytes = args.dest.commitment_bytes()?; let input = Input::new( OutPoint::new(args.expired_tx.txid(), args.vout), diff --git a/src/bitcoin/relayer.rs b/src/bitcoin/relayer.rs index 4f483a5b7..077f1da63 100644 --- a/src/bitcoin/relayer.rs +++ b/src/bitcoin/relayer.rs @@ -204,10 +204,7 @@ impl Relayer { let expected_addr = ::bitcoin::Address::from_script( &sigset .output_script( - dest.commitment_bytes() - .map_err(|_| reject())? - .ok_or(reject())? - .as_slice(), + dest.commitment_bytes().map_err(|_| reject())?.as_slice(), SIGSET_THRESHOLD, ) .map_err(warp::reject::custom)?, @@ -1201,16 +1198,7 @@ impl WatchedScripts { sigset: &SignatorySet, threshold: (u64, u64), ) -> Result<::bitcoin::Script> { - let commitment_bytes = match dest.commitment_bytes()? { - Some(bytes) => bytes, - None => { - return Err(Error::Relayer( - "Could not derive script for fee Dest".to_string(), - )) - } - }; - - sigset.output_script(&commitment_bytes, threshold) + sigset.output_script(&dest.commitment_bytes()?, threshold) } } diff --git a/tests/bitcoin.rs b/tests/bitcoin.rs index 2d1fab95b..75dc84d76 100644 --- a/tests/bitcoin.rs +++ b/tests/bitcoin.rs @@ -69,10 +69,7 @@ async fn generate_deposit_address(address: &Address) -> Result { }) .await?; let script = sigset.output_script( - Dest::Address(*address) - .commitment_bytes()? - .unwrap() - .as_slice(), + Dest::Address(*address).commitment_bytes()?.as_slice(), threshold, )?; From 5c98dbfa3f282dcc88d872307daca6a0e44fcb34 Mon Sep 17 00:00:00 2001 From: Charlie Little Date: Wed, 3 Apr 2024 11:25:03 -0500 Subject: [PATCH 3/3] Resolve disbursal timing issue --- tests/bitcoin.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/bitcoin.rs b/tests/bitcoin.rs index 75dc84d76..4b10307ec 100644 --- a/tests/bitcoin.rs +++ b/tests/bitcoin.rs @@ -458,14 +458,6 @@ async fn bitcoin_test() { let balance = poll_for_updated_balance(funded_accounts[1].address, expected_balance).await; assert_eq!(balance, Amount::from(expected_balance)); - withdraw_bitcoin( - &funded_accounts[0], - bitcoin::Amount::from_sat(7000), - &withdraw_address, - ) - .await - .unwrap(); - app_client() .with_wallet(funded_accounts[0].wallet.clone()) .call( @@ -474,6 +466,14 @@ async fn bitcoin_test() { ) .await?; + withdraw_bitcoin( + &funded_accounts[0], + bitcoin::Amount::from_sat(7000), + &withdraw_address, + ) + .await + .unwrap(); + btc_client .generate_to_address(4, &async_wallet_address) .await