From 43de74145df1c26edc808d3f6509fcef267fd91c Mon Sep 17 00:00:00 2001 From: f321x Date: Tue, 9 Jul 2024 16:54:47 +0000 Subject: [PATCH 1/4] working on fixing bond validation --- .../coordinator/src/communication/mod.rs | 7 ++++--- .../coordinator/src/coordinator/monitoring.rs | 7 +++++-- taptrade-cli-demo/coordinator/src/wallet/mod.rs | 7 ++++++- taptrade-cli-demo/trader/src/wallet/bond.rs | 13 ++++++++----- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/taptrade-cli-demo/coordinator/src/communication/mod.rs b/taptrade-cli-demo/coordinator/src/communication/mod.rs index 74c2f11..5917aef 100755 --- a/taptrade-cli-demo/coordinator/src/communication/mod.rs +++ b/taptrade-cli-demo/coordinator/src/communication/mod.rs @@ -25,10 +25,11 @@ async fn receive_order( Extension(database): Extension>, Extension(wallet): Extension>, Json(order): Json, -) -> Result, AppError> { +) -> Result { debug!("{:#?}", &order); if order.sanity_check().is_err() { - return Err(AppError(anyhow!("Invalid order request"))); + warn!("Received order failed sanity check"); + return Ok(StatusCode::NOT_ACCEPTABLE.into_response()); } let bond_requirements = BondRequirementResponse { bond_address: wallet.get_new_address().await?, @@ -39,7 +40,7 @@ async fn receive_order( .insert_new_maker_request(&order, &bond_requirements) .await?; debug!("Coordinator received new offer: {:?}", order); - Ok(Json(bond_requirements)) + Ok(Json(bond_requirements).into_response()) } /// receives the maker bond, verifies it and moves to offer to the active table (orderbook) diff --git a/taptrade-cli-demo/coordinator/src/coordinator/monitoring.rs b/taptrade-cli-demo/coordinator/src/coordinator/monitoring.rs index 835e44d..67b8bb3 100644 --- a/taptrade-cli-demo/coordinator/src/coordinator/monitoring.rs +++ b/taptrade-cli-demo/coordinator/src/coordinator/monitoring.rs @@ -4,11 +4,13 @@ // Also needs to implement punishment logic in case a fraud is detected. use super::*; +#[derive(Debug)] pub enum Table { Orderbook, ActiveTrades, } +#[derive(Debug)] pub struct MonitoringBond { pub bond_tx_hex: String, pub trade_id_hex: String, @@ -42,13 +44,14 @@ pub async fn monitor_bonds(coordinator: Arc) -> Result<()> { loop { // fetch all bonds let bonds = coordinator_db.fetch_all_bonds().await?; - + debug!("Monitoring active bonds: {}", bonds.len()); // verify all bonds and initiate punishment if necessary for bond in bonds { if let Err(e) = coordinator_wallet .validate_bond_tx_hex(&bond.1.bond_tx_hex, &bond.1.requirements) .await { + warn!("Bond validation failed: {:?}", e); match env::var("PUNISHMENT_ENABLED") .unwrap_or_else(|_| "0".to_string()) .as_str() @@ -67,6 +70,6 @@ pub async fn monitor_bonds(coordinator: Arc) -> Result<()> { } // sleep for a while - tokio::time::sleep(tokio::time::Duration::from_secs(30)).await; + tokio::time::sleep(tokio::time::Duration::from_secs(15)).await; } } diff --git a/taptrade-cli-demo/coordinator/src/wallet/mod.rs b/taptrade-cli-demo/coordinator/src/wallet/mod.rs index 11d6ce2..ea33b0f 100644 --- a/taptrade-cli-demo/coordinator/src/wallet/mod.rs +++ b/taptrade-cli-demo/coordinator/src/wallet/mod.rs @@ -75,7 +75,10 @@ impl CoordinatorWallet { let tx: Transaction = deserialize(&hex::decode(bond)?)?; { let wallet = self.wallet.lock().await; - + if let Err(e) = wallet.sync(blockchain, SyncOptions::default()) { + error!("Error syncing wallet: {:?}", e); + return Ok(()); // if the electrum server goes down all bonds will be considered valid. Maybe redundancy should be added. + }; // we need to test this with signed and invalid/unsigned transactions // checks signatures and inputs if let Err(e) = verify_tx(&tx, &*wallet.database(), blockchain) { @@ -111,10 +114,12 @@ impl CoordinatorWallet { if ((input_sum - output_sum) / tx.vsize() as u64) < 200 { return Err(anyhow!("Bond fee rate too low")); } + debug!("validate_bond_tx_hex(): Bond validation successful."); Ok(()) } pub fn publish_bond_tx_hex(&self, bond: &str) -> Result<()> { + warn!("publish_bond_tx_hex(): publishing cheating bond tx!"); let blockchain = &*self.backend; let tx: Transaction = deserialize(&hex::decode(bond)?)?; diff --git a/taptrade-cli-demo/trader/src/wallet/bond.rs b/taptrade-cli-demo/trader/src/wallet/bond.rs index 05bbae8..c37dd8a 100644 --- a/taptrade-cli-demo/trader/src/wallet/bond.rs +++ b/taptrade-cli-demo/trader/src/wallet/bond.rs @@ -7,6 +7,7 @@ use bdk::{ database::MemoryDatabase, wallet::coin_selection::BranchAndBoundCoinSelection, FeeRate, SignOptions, Wallet, }; +use log::debug; use serde::de::value; use std::str::FromStr; @@ -29,6 +30,7 @@ impl Bond { bond_target: &BondRequirementResponse, trader_input: &TraderSettings, ) -> Result { + debug!("Assembling bond transaction"); // parse bond locking address as Address struct and verify network is testnet let address: Address = Address::from_str(&bond_target.bond_address)?.require_network(Network::Testnet)?; @@ -45,15 +47,16 @@ impl Bond { builder .add_recipient(address.script_pubkey(), bond_target.locking_amount_sat) - .do_not_spend_change() + .do_not_spend_change() // reconsider if we need this? .fee_rate(FeeRate::from_sat_per_vb(201.0)); builder.finish()? }; - let finalized = wallet.sign(&mut psbt, SignOptions::default())?; - if !finalized { - return Err(anyhow!("Transaction could not be finalized")); - }; + debug!("Signing bond transaction."); + // let finalized = wallet.sign(&mut psbt, SignOptions::default())?; // deactivated to test bond validation + // if !finalized { + // return Err(anyhow!("Transaction could not be finalized")); + // }; Ok(psbt) } } From 6c9b969d5e3ffcdfd0b781b1ccbd52b3b52cf9eb Mon Sep 17 00:00:00 2001 From: f321x Date: Tue, 9 Jul 2024 18:12:04 +0000 Subject: [PATCH 2/4] debug statements --- taptrade-cli-demo/coordinator/src/wallet/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/taptrade-cli-demo/coordinator/src/wallet/mod.rs b/taptrade-cli-demo/coordinator/src/wallet/mod.rs index ea33b0f..2f00586 100644 --- a/taptrade-cli-demo/coordinator/src/wallet/mod.rs +++ b/taptrade-cli-demo/coordinator/src/wallet/mod.rs @@ -74,6 +74,7 @@ impl CoordinatorWallet { let blockchain = &*self.backend; let tx: Transaction = deserialize(&hex::decode(bond)?)?; { + debug!("Called validate_bond_tx_hex()"); let wallet = self.wallet.lock().await; if let Err(e) = wallet.sync(blockchain, SyncOptions::default()) { error!("Error syncing wallet: {:?}", e); From a48391ad7310fef5f87f5a75fe70850dbc1d860a Mon Sep 17 00:00:00 2001 From: f321x Date: Wed, 10 Jul 2024 09:13:49 +0000 Subject: [PATCH 3/4] making coordinator wallet generic, working on tests for bond verification --- taptrade-cli-demo/coordinator/Cargo.toml | 2 +- .../coordinator/src/communication/mod.rs | 14 +- taptrade-cli-demo/coordinator/src/main.rs | 5 +- .../coordinator/src/wallet/mod.rs | 185 +++++++++++++++--- 4 files changed, 167 insertions(+), 39 deletions(-) diff --git a/taptrade-cli-demo/coordinator/Cargo.toml b/taptrade-cli-demo/coordinator/Cargo.toml index 4307e8b..ca649d0 100644 --- a/taptrade-cli-demo/coordinator/Cargo.toml +++ b/taptrade-cli-demo/coordinator/Cargo.toml @@ -19,7 +19,7 @@ rand = "0.8.5" reqwest = { version = "0.12.4", features = ["blocking", "json"] } serde = "1.0.203" sqlx = { version = "0.7.4", features = ["runtime-tokio", "sqlite"] } -tokio = { version = "1.38.0", features = ["full"] } +tokio = { version = "1.38.0", features = ["full", "test-util"] } tower = "0.4.13" log = "0.4.22" env_logger = "0.11.3" diff --git a/taptrade-cli-demo/coordinator/src/communication/mod.rs b/taptrade-cli-demo/coordinator/src/communication/mod.rs index 5917aef..653025c 100755 --- a/taptrade-cli-demo/coordinator/src/communication/mod.rs +++ b/taptrade-cli-demo/coordinator/src/communication/mod.rs @@ -23,7 +23,7 @@ use tokio::net::TcpListener; /// Handler function to process the received data async fn receive_order( Extension(database): Extension>, - Extension(wallet): Extension>, + Extension(wallet): Extension>>, Json(order): Json, ) -> Result { debug!("{:#?}", &order); @@ -46,7 +46,7 @@ async fn receive_order( /// receives the maker bond, verifies it and moves to offer to the active table (orderbook) async fn submit_maker_bond( Extension(database): Extension>, - Extension(wallet): Extension>, + Extension(wallet): Extension>>, Json(payload): Json, ) -> Result { debug!("\n\nReceived maker bond: {:?}", payload); @@ -112,7 +112,7 @@ async fn fetch_available_offers( /// and moves the offer to the taken table. Will return the trade contract psbt for the taker to sign. async fn submit_taker_bond( Extension(database): Extension>, - Extension(wallet): Extension>, + Extension(wallet): Extension>>, Json(payload): Json, ) -> Result { let bond_requirements = database @@ -175,7 +175,7 @@ async fn request_offer_status_maker( /// Once the coordinator has received both partitial signed PSBTs he can assemble them together to a transaction and publish it to the bitcoin network. async fn submit_escrow_psbt( Extension(database): Extension>, - Extension(wallet): Extension>, + Extension(wallet): Extension>>, Json(payload): Json, ) -> Result { panic!("implement") @@ -188,7 +188,7 @@ async fn submit_escrow_psbt( /// We have to see what makes more sense later, but maybe this would be more elegant. TBD. async fn poll_escrow_confirmation( Extension(database): Extension>, - Extension(wallet): Extension>, + Extension(wallet): Extension>>, Json(payload): Json, ) -> Result { panic!("implement") @@ -196,7 +196,7 @@ async fn poll_escrow_confirmation( async fn submit_obligation_confirmation( Extension(database): Extension>, - Extension(wallet): Extension>, + Extension(wallet): Extension>>, Json(payload): Json, ) -> Result { panic!("implement") @@ -208,7 +208,7 @@ async fn submit_obligation_confirmation( /// endpoint can return 201 and the escrow mediation logic will get executed (tbd). async fn poll_final_payout( Extension(database): Extension>, - Extension(wallet): Extension>, + Extension(wallet): Extension>>, Json(payload): Json, ) -> Result { panic!("implement") diff --git a/taptrade-cli-demo/coordinator/src/main.rs b/taptrade-cli-demo/coordinator/src/main.rs index a7b2c69..6bad234 100755 --- a/taptrade-cli-demo/coordinator/src/main.rs +++ b/taptrade-cli-demo/coordinator/src/main.rs @@ -4,6 +4,7 @@ mod database; mod wallet; use anyhow::{anyhow, Result}; +use bdk::sled; use communication::{api::*, api_server}; use coordinator::monitoring::monitor_bonds; use coordinator::monitoring::*; @@ -17,7 +18,7 @@ use wallet::*; pub struct Coordinator { pub coordinator_db: Arc, - pub coordinator_wallet: Arc, + pub coordinator_wallet: Arc>, } // populate .env with values before starting @@ -32,7 +33,7 @@ async fn main() -> Result<()> { // Initialize the database pool let coordinator = Arc::new(Coordinator { coordinator_db: Arc::new(CoordinatorDB::init().await?), - coordinator_wallet: Arc::new(CoordinatorWallet::init()?), + coordinator_wallet: Arc::new(init_coordinator_wallet()?), }); // begin monitoring bonds diff --git a/taptrade-cli-demo/coordinator/src/wallet/mod.rs b/taptrade-cli-demo/coordinator/src/wallet/mod.rs index 2f00586..a96ed87 100644 --- a/taptrade-cli-demo/coordinator/src/wallet/mod.rs +++ b/taptrade-cli-demo/coordinator/src/wallet/mod.rs @@ -18,8 +18,8 @@ use utils::*; // use verify_tx::*; #[derive(Clone)] -pub struct CoordinatorWallet { - pub wallet: Arc>>, +pub struct CoordinatorWallet { + pub wallet: Arc>>, pub backend: Arc, } @@ -30,34 +30,34 @@ pub struct BondRequirements { pub min_input_sum_sat: u64, } -impl CoordinatorWallet { - pub fn init() -> Result { - let wallet_xprv = ExtendedPrivKey::from_str( - &env::var("WALLET_XPRV").context("loading WALLET_XPRV from .env failed")?, - )?; - let backend = ElectrumBlockchain::from(Client::new( - &env::var("ELECTRUM_BACKEND") - .context("Parsing ELECTRUM_BACKEND from .env failed, is it set?")?, - )?); - // let backend = EsploraBlockchain::new(&env::var("ESPLORA_BACKEND")?, 1000); - let sled_db = sled::open(env::var("BDK_DB_PATH")?)?.open_tree("default_wallet")?; - let wallet = Wallet::new( - Bip86(wallet_xprv, KeychainKind::External), - Some(Bip86(wallet_xprv, KeychainKind::Internal)), - bitcoin::Network::Testnet, - sled_db, - )?; +pub fn init_coordinator_wallet() -> Result> { + let wallet_xprv = ExtendedPrivKey::from_str( + &env::var("WALLET_XPRV").context("loading WALLET_XPRV from .env failed")?, + )?; + let backend = ElectrumBlockchain::from(Client::new( + &env::var("ELECTRUM_BACKEND") + .context("Parsing ELECTRUM_BACKEND from .env failed, is it set?")?, + )?); + // let backend = EsploraBlockchain::new(&env::var("ESPLORA_BACKEND")?, 1000); + let sled_db = sled::open(env::var("BDK_DB_PATH")?)?.open_tree("default_wallet")?; + let wallet = Wallet::new( + Bip86(wallet_xprv, KeychainKind::External), + Some(Bip86(wallet_xprv, KeychainKind::Internal)), + bitcoin::Network::Testnet, + sled_db, + )?; - wallet - .sync(&backend, SyncOptions::default()) - .context("Connection to electrum server failed.")?; // we could also use Esplora to make this async - dbg!(wallet.get_balance()?); - Ok(CoordinatorWallet { - wallet: Arc::new(Mutex::new(wallet)), - backend: Arc::new(backend), - }) - } + wallet + .sync(&backend, SyncOptions::default()) + .context("Connection to electrum server failed.")?; // we could also use Esplora to make this async + dbg!(wallet.get_balance()?); + Ok(CoordinatorWallet { + wallet: Arc::new(Mutex::new(wallet)), + backend: Arc::new(backend), + }) +} +impl CoordinatorWallet { pub async fn get_new_address(&self) -> Result { let wallet = self.wallet.lock().await; let address = wallet.get_address(bdk::wallet::AddressIndex::New)?; @@ -65,6 +65,7 @@ impl CoordinatorWallet { } // validate bond (check amounts, valid inputs, correct addresses, valid signature, feerate) + // also check if inputs are confirmed already pub async fn validate_bond_tx_hex( &self, bond: &String, @@ -129,7 +130,7 @@ impl CoordinatorWallet { } } -impl fmt::Debug for CoordinatorWallet { +impl fmt::Debug for CoordinatorWallet { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("CoordinatorWallet") .field("wallet", &self.wallet) @@ -139,3 +140,129 @@ impl fmt::Debug for CoordinatorWallet { .finish() } } + +#[cfg(test)] +mod tests { + use super::*; + use bdk::bitcoin::{Address, Network}; + use bdk::database::MemoryDatabase; + use bdk::{blockchain::ElectrumBlockchain, Wallet}; + // use tokio::test; + // use bitcoincore_rpc_json::GetRawTransactionResult; + + async fn new_wallet(wallet_xprv: &str) -> CoordinatorWallet { + let backend = ElectrumBlockchain::from(Client::new("ssl://mempool.space:40002").unwrap()); + + let wallet_xprv = ExtendedPrivKey::from_str(wallet_xprv).unwrap(); + let wallet = Wallet::new( + Bip86(wallet_xprv, KeychainKind::External), + Some(Bip86(wallet_xprv, KeychainKind::Internal)), + Network::Testnet, + MemoryDatabase::new(), + ) + .unwrap(); + wallet.sync(&backend, SyncOptions::default()).unwrap(); + + CoordinatorWallet:: { + wallet: Arc::new(Mutex::new(wallet)), + backend: Arc::new(backend), + } + } + + #[tokio::test] + async fn test_valid_bond_tx() { + let test_wallet = new_wallet("xprv9s21ZrQH143K2XqaJ5boFeHgrJTsMgfzrgrsFXdk3UBYtLLhUkCj2QKPmqYpC92zd6bv46Nh8QxXmjH2MwJWVLQzfC6Bv1Tbeoz28nXjeM2").await; + let bond = "020000000001010127a9d96655011fca55dc2667f30b98655e46da98d0f84df676b53d7fb380140000000000010000000250c3000000000000225120a12e5d145a4a3ab43f6cc1188435e74f253eace72bd986f1aaf780fd0c653236aa900000000000002251207dd0d1650cdc22537709e35620f3b5cc3249b305bda1209ba4e5e01bc3ad2d8c014010e19c8b915624bd4aa0ba4d094d26ca031a6f2d8f23fe51372c7ea50e05f3caf81c7e139f6fed3e9ffd20c03d79f78542acb3d8aed664898f1c4b2909c2188c00000000"; + let requirements = BondRequirements { + min_input_sum_sat: 100000, + locking_amount_sat: 50000, + bond_address: "tb1p5yh969z6fgatg0mvcyvggd08fujnat8890vcdud277q06rr9xgmqwfdkcx" + .to_string(), + }; + + let result = test_wallet.validate_bond_tx_hex(&bond, &requirements).await; + assert!(result.is_ok()); + } + + #[tokio::test] + async fn test_invalid_bond_tx_low_input_sum() { + let test_wallet = TestWallet::new().await; + let bond = "020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0502c5080101ffffffff0200f2052a010000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000"; + let requirements = BondRequirements { + min_input_sum_sat: 1000000, // Set higher than the actual input sum + locking_amount_sat: 50000, + bond_address: Address::from_str("tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx").unwrap(), + }; + + test_wallet + .backend + .expect_get_tx() + .returning(|_| Ok(Some(Transaction::default()))); + + let result = test_wallet.validate_bond_tx_hex(&bond, &requirements).await; + assert!(result.is_err()); + assert!(result + .unwrap_err() + .to_string() + .contains("Bond input sum too small")); + } + + #[tokio::test] + async fn test_invalid_bond_tx_low_output_sum() { + let test_wallet = TestWallet::new().await; + let bond = "020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0502c5080101ffffffff0200f2052a010000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000"; + let requirements = BondRequirements { + min_input_sum_sat: 100000, + locking_amount_sat: 1000000, // Set higher than the actual output sum + bond_address: Address::from_str("tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx").unwrap(), + }; + + test_wallet + .backend + .expect_get_tx() + .returning(|_| Ok(Some(Transaction::default()))); + + let result = test_wallet.validate_bond_tx_hex(&bond, &requirements).await; + assert!(result.is_err()); + assert!(result + .unwrap_err() + .to_string() + .contains("Bond output sum too small")); + } + + #[tokio::test] + async fn test_invalid_bond_tx_low_fee_rate() { + let test_wallet = TestWallet::new().await; + let bond = "020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0502c5080101ffffffff0200f2052a010000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000"; + let requirements = BondRequirements { + min_input_sum_sat: 100000, + locking_amount_sat: 50000, + bond_address: Address::from_str("tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx").unwrap(), + }; + + test_wallet + .backend + .expect_get_tx() + .returning(|_| Ok(Some(Transaction::default()))); + + // Modify the transaction to have a very low fee + let mut tx: Transaction = deserialize(&hex::decode(bond).unwrap()).unwrap(); + tx.output[0].value = tx + .input_sum( + &*test_wallet.backend, + &*test_wallet.wallet.lock().await.database(), + ) + .unwrap() - 1; + + let low_fee_bond = hex::encode(serialize(&tx)); + + let result = test_wallet + .validate_bond_tx_hex(&low_fee_bond, &requirements) + .await; + assert!(result.is_err()); + assert!(result + .unwrap_err() + .to_string() + .contains("Bond fee rate too low")); + } +} From 3cb0c9a0a98e97586f04f2e807f96d9174ed37c8 Mon Sep 17 00:00:00 2001 From: f321x Date: Wed, 10 Jul 2024 11:02:03 +0000 Subject: [PATCH 4/4] finish first tests for validate_bond_tx_hex --- .../coordinator/src/wallet/mod.rs | 59 ++++++------------- 1 file changed, 17 insertions(+), 42 deletions(-) diff --git a/taptrade-cli-demo/coordinator/src/wallet/mod.rs b/taptrade-cli-demo/coordinator/src/wallet/mod.rs index a96ed87..0eae6f5 100644 --- a/taptrade-cli-demo/coordinator/src/wallet/mod.rs +++ b/taptrade-cli-demo/coordinator/src/wallet/mod.rs @@ -68,7 +68,7 @@ impl CoordinatorWallet { // also check if inputs are confirmed already pub async fn validate_bond_tx_hex( &self, - bond: &String, + bond: &str, requirements: &BondRequirements, ) -> Result<()> { let input_sum: u64; @@ -150,7 +150,7 @@ mod tests { // use tokio::test; // use bitcoincore_rpc_json::GetRawTransactionResult; - async fn new_wallet(wallet_xprv: &str) -> CoordinatorWallet { + async fn new_test_wallet(wallet_xprv: &str) -> CoordinatorWallet { let backend = ElectrumBlockchain::from(Client::new("ssl://mempool.space:40002").unwrap()); let wallet_xprv = ExtendedPrivKey::from_str(wallet_xprv).unwrap(); @@ -171,7 +171,7 @@ mod tests { #[tokio::test] async fn test_valid_bond_tx() { - let test_wallet = new_wallet("xprv9s21ZrQH143K2XqaJ5boFeHgrJTsMgfzrgrsFXdk3UBYtLLhUkCj2QKPmqYpC92zd6bv46Nh8QxXmjH2MwJWVLQzfC6Bv1Tbeoz28nXjeM2").await; + let test_wallet = new_test_wallet("xprv9s21ZrQH143K2XqaJ5boFeHgrJTsMgfzrgrsFXdk3UBYtLLhUkCj2QKPmqYpC92zd6bv46Nh8QxXmjH2MwJWVLQzfC6Bv1Tbeoz28nXjeM2").await; let bond = "020000000001010127a9d96655011fca55dc2667f30b98655e46da98d0f84df676b53d7fb380140000000000010000000250c3000000000000225120a12e5d145a4a3ab43f6cc1188435e74f253eace72bd986f1aaf780fd0c653236aa900000000000002251207dd0d1650cdc22537709e35620f3b5cc3249b305bda1209ba4e5e01bc3ad2d8c014010e19c8b915624bd4aa0ba4d094d26ca031a6f2d8f23fe51372c7ea50e05f3caf81c7e139f6fed3e9ffd20c03d79f78542acb3d8aed664898f1c4b2909c2188c00000000"; let requirements = BondRequirements { min_input_sum_sat: 100000, @@ -186,19 +186,15 @@ mod tests { #[tokio::test] async fn test_invalid_bond_tx_low_input_sum() { - let test_wallet = TestWallet::new().await; - let bond = "020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0502c5080101ffffffff0200f2052a010000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000"; + let test_wallet = new_test_wallet("xprv9s21ZrQH143K2XqaJ5boFeHgrJTsMgfzrgrsFXdk3UBYtLLhUkCj2QKPmqYpC92zd6bv46Nh8QxXmjH2MwJWVLQzfC6Bv1Tbeoz28nXjeM2").await; + let bond = "020000000001010127a9d96655011fca55dc2667f30b98655e46da98d0f84df676b53d7fb380140000000000010000000250c3000000000000225120a12e5d145a4a3ab43f6cc1188435e74f253eace72bd986f1aaf780fd0c653236aa900000000000002251207dd0d1650cdc22537709e35620f3b5cc3249b305bda1209ba4e5e01bc3ad2d8c014010e19c8b915624bd4aa0ba4d094d26ca031a6f2d8f23fe51372c7ea50e05f3caf81c7e139f6fed3e9ffd20c03d79f78542acb3d8aed664898f1c4b2909c2188c00000000"; let requirements = BondRequirements { - min_input_sum_sat: 1000000, // Set higher than the actual input sum + min_input_sum_sat: 2000000, // Set higher than the actual input sum locking_amount_sat: 50000, - bond_address: Address::from_str("tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx").unwrap(), + bond_address: "tb1p5yh969z6fgatg0mvcyvggd08fujnat8890vcdud277q06rr9xgmqwfdkcx" + .to_string(), }; - test_wallet - .backend - .expect_get_tx() - .returning(|_| Ok(Some(Transaction::default()))); - let result = test_wallet.validate_bond_tx_hex(&bond, &requirements).await; assert!(result.is_err()); assert!(result @@ -209,19 +205,15 @@ mod tests { #[tokio::test] async fn test_invalid_bond_tx_low_output_sum() { - let test_wallet = TestWallet::new().await; - let bond = "020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0502c5080101ffffffff0200f2052a010000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000"; + let test_wallet = new_test_wallet("xprv9s21ZrQH143K2XqaJ5boFeHgrJTsMgfzrgrsFXdk3UBYtLLhUkCj2QKPmqYpC92zd6bv46Nh8QxXmjH2MwJWVLQzfC6Bv1Tbeoz28nXjeM2").await; + let bond = "020000000001010127a9d96655011fca55dc2667f30b98655e46da98d0f84df676b53d7fb380140000000000010000000250c3000000000000225120a12e5d145a4a3ab43f6cc1188435e74f253eace72bd986f1aaf780fd0c653236aa900000000000002251207dd0d1650cdc22537709e35620f3b5cc3249b305bda1209ba4e5e01bc3ad2d8c014010e19c8b915624bd4aa0ba4d094d26ca031a6f2d8f23fe51372c7ea50e05f3caf81c7e139f6fed3e9ffd20c03d79f78542acb3d8aed664898f1c4b2909c2188c00000000"; let requirements = BondRequirements { min_input_sum_sat: 100000, locking_amount_sat: 1000000, // Set higher than the actual output sum - bond_address: Address::from_str("tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx").unwrap(), + bond_address: "tb1p5yh969z6fgatg0mvcyvggd08fujnat8890vcdud277q06rr9xgmqwfdkcx" + .to_string(), }; - test_wallet - .backend - .expect_get_tx() - .returning(|_| Ok(Some(Transaction::default()))); - let result = test_wallet.validate_bond_tx_hex(&bond, &requirements).await; assert!(result.is_err()); assert!(result @@ -232,33 +224,16 @@ mod tests { #[tokio::test] async fn test_invalid_bond_tx_low_fee_rate() { - let test_wallet = TestWallet::new().await; - let bond = "020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0502c5080101ffffffff0200f2052a010000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000"; + let test_wallet = new_test_wallet("xprv9s21ZrQH143K2XqaJ5boFeHgrJTsMgfzrgrsFXdk3UBYtLLhUkCj2QKPmqYpC92zd6bv46Nh8QxXmjH2MwJWVLQzfC6Bv1Tbeoz28nXjeM2").await; + let bond = "020000000001010127a9d96655011fca55dc2667f30b98655e46da98d0f84df676b53d7fb380140000000000fdffffff0259b00000000000002251207dd0d1650cdc22537709e35620f3b5cc3249b305bda1209ba4e5e01bc3ad2d8c50c3000000000000225120a12e5d145a4a3ab43f6cc1188435e74f253eace72bd986f1aaf780fd0c6532360140bee11f7f644cf09d5031683203bbe61109090b1e4be4626e13de7a889d6e5d2f154233a2bfaf9cb983f31ccf01b1be5db2cd37bb0cb9a395e2632bc50105b4583f860000"; let requirements = BondRequirements { min_input_sum_sat: 100000, locking_amount_sat: 50000, - bond_address: Address::from_str("tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx").unwrap(), + bond_address: "tb1p5yh969z6fgatg0mvcyvggd08fujnat8890vcdud277q06rr9xgmqwfdkcx" + .to_string(), }; - test_wallet - .backend - .expect_get_tx() - .returning(|_| Ok(Some(Transaction::default()))); - - // Modify the transaction to have a very low fee - let mut tx: Transaction = deserialize(&hex::decode(bond).unwrap()).unwrap(); - tx.output[0].value = tx - .input_sum( - &*test_wallet.backend, - &*test_wallet.wallet.lock().await.database(), - ) - .unwrap() - 1; - - let low_fee_bond = hex::encode(serialize(&tx)); - - let result = test_wallet - .validate_bond_tx_hex(&low_fee_bond, &requirements) - .await; + let result = test_wallet.validate_bond_tx_hex(&bond, &requirements).await; assert!(result.is_err()); assert!(result .unwrap_err()