From 03c6d30f9fe0886d6ed81041aaabed40991cd12c Mon Sep 17 00:00:00 2001 From: valued mammal Date: Mon, 4 Nov 2024 21:15:37 -0500 Subject: [PATCH] test(wallet): improve usage of test utils --- crates/wallet/src/test_utils.rs | 70 +++++++++++----------- crates/wallet/src/wallet/export.rs | 43 +++---------- crates/wallet/src/wallet/mod.rs | 20 +++---- crates/wallet/tests/wallet.rs | 96 ++++++++++++------------------ 4 files changed, 89 insertions(+), 140 deletions(-) diff --git a/crates/wallet/src/test_utils.rs b/crates/wallet/src/test_utils.rs index 2cb7342d6..18f496398 100644 --- a/crates/wallet/src/test_utils.rs +++ b/crates/wallet/src/test_utils.rs @@ -17,11 +17,11 @@ use crate::{KeychainKind, Update, Wallet}; /// The funded wallet contains a tx with a 76_000 sats input and two outputs, one spending 25_000 /// to a foreign address and one returning 50_000 back to the wallet. The remaining 1000 /// sats are the transaction fee. -pub fn get_funded_wallet(descriptor: &str, change_descriptor: &str) -> (Wallet, bitcoin::Txid) { +pub fn get_funded_wallet(descriptor: &str, change_descriptor: &str) -> (Wallet, Txid) { new_funded_wallet(descriptor, Some(change_descriptor)) } -fn new_funded_wallet(descriptor: &str, change_descriptor: Option<&str>) -> (Wallet, bitcoin::Txid) { +fn new_funded_wallet(descriptor: &str, change_descriptor: Option<&str>) -> (Wallet, Txid) { let params = if let Some(change_desc) = change_descriptor { Wallet::create(descriptor.to_string(), change_desc.to_string()) } else { @@ -40,34 +40,20 @@ fn new_funded_wallet(descriptor: &str, change_descriptor: Option<&str>) -> (Wall .unwrap(); let tx0 = Transaction { - version: transaction::Version::ONE, - lock_time: bitcoin::absolute::LockTime::ZERO, - input: vec![TxIn { - previous_output: OutPoint { - txid: Txid::all_zeros(), - vout: 0, - }, - script_sig: Default::default(), - sequence: Default::default(), - witness: Default::default(), - }], output: vec![TxOut { value: Amount::from_sat(76_000), script_pubkey: receive_address.script_pubkey(), }], + ..new_tx(0) }; let tx1 = Transaction { - version: transaction::Version::ONE, - lock_time: bitcoin::absolute::LockTime::ZERO, input: vec![TxIn { previous_output: OutPoint { txid: tx0.compute_txid(), vout: 0, }, - script_sig: Default::default(), - sequence: Default::default(), - witness: Default::default(), + ..Default::default() }], output: vec![ TxOut { @@ -79,28 +65,32 @@ fn new_funded_wallet(descriptor: &str, change_descriptor: Option<&str>) -> (Wall script_pubkey: sendto_address.script_pubkey(), }, ], + ..new_tx(0) }; - wallet - .insert_checkpoint(BlockId { + insert_checkpoint( + &mut wallet, + BlockId { height: 42, hash: BlockHash::all_zeros(), - }) - .unwrap(); - wallet - .insert_checkpoint(BlockId { + }, + ); + insert_checkpoint( + &mut wallet, + BlockId { height: 1_000, hash: BlockHash::all_zeros(), - }) - .unwrap(); - wallet - .insert_checkpoint(BlockId { + }, + ); + insert_checkpoint( + &mut wallet, + BlockId { height: 2_000, hash: BlockHash::all_zeros(), - }) - .unwrap(); + }, + ); - wallet.insert_tx(tx0.clone()); + insert_tx(&mut wallet, tx0.clone()); insert_anchor( &mut wallet, tx0.compute_txid(), @@ -113,7 +103,7 @@ fn new_funded_wallet(descriptor: &str, change_descriptor: Option<&str>) -> (Wall }, ); - wallet.insert_tx(tx1.clone()); + insert_tx(&mut wallet, tx1.clone()); insert_anchor( &mut wallet, tx1.compute_txid(), @@ -134,12 +124,12 @@ fn new_funded_wallet(descriptor: &str, change_descriptor: Option<&str>) -> (Wall /// The funded wallet contains a tx with a 76_000 sats input and two outputs, one spending 25_000 /// to a foreign address and one returning 50_000 back to the wallet. The remaining 1000 /// sats are the transaction fee. -pub fn get_funded_wallet_single(descriptor: &str) -> (Wallet, bitcoin::Txid) { +pub fn get_funded_wallet_single(descriptor: &str) -> (Wallet, Txid) { new_funded_wallet(descriptor, None) } /// Get funded segwit wallet -pub fn get_funded_wallet_wpkh() -> (Wallet, bitcoin::Txid) { +pub fn get_funded_wallet_wpkh() -> (Wallet, Txid) { let (desc, change_desc) = get_test_wpkh_and_change_desc(); get_funded_wallet(desc, change_desc) } @@ -211,6 +201,16 @@ pub fn get_test_tr_dup_keys() -> &'static str { "tr(cNJmN3fH9DDbDt131fQNkVakkpzawJBSeybCUNmP1BovpmGQ45xG,{pk(8aee2b8120a5f157f1223f72b5e62b825831a27a9fdf427db7cc697494d4a642),pk(8aee2b8120a5f157f1223f72b5e62b825831a27a9fdf427db7cc697494d4a642)})" } +/// A new empty transaction with the given locktime +pub fn new_tx(locktime: u32) -> Transaction { + Transaction { + version: transaction::Version::ONE, + lock_time: absolute::LockTime::from_consensus(locktime), + input: vec![], + output: vec![], + } +} + /// Construct a new [`FeeRate`] from the given raw `sat_vb` feerate. This is /// useful in cases where we want to create a feerate from a `f64`, as the /// traditional [`FeeRate::from_sat_per_vb`] method will only accept an integer. @@ -267,7 +267,7 @@ pub fn receive_output_to_address( }; let txid = tx.compute_txid(); - wallet.insert_tx(tx); + insert_tx(wallet, tx); match pos { ChainPosition::Confirmed(anchor) => { diff --git a/crates/wallet/src/wallet/export.rs b/crates/wallet/src/wallet/export.rs index ad5a6b2a8..6441d3b58 100644 --- a/crates/wallet/src/wallet/export.rs +++ b/crates/wallet/src/wallet/export.rs @@ -213,55 +213,28 @@ impl FullyNodedExport { #[cfg(test)] mod test { + use alloc::string::ToString; use core::str::FromStr; - use crate::std::string::ToString; - use bdk_chain::{BlockId, ConfirmationBlockTime}; - use bitcoin::hashes::Hash; - use bitcoin::{transaction, BlockHash, Network, Transaction}; - use chain::tx_graph; + use bdk_chain::BlockId; + use bitcoin::{hashes::Hash, BlockHash, Network}; use super::*; + use crate::test_utils::*; use crate::Wallet; fn get_test_wallet(descriptor: &str, change_descriptor: &str, network: Network) -> Wallet { - use crate::wallet::Update; let mut wallet = Wallet::create(descriptor.to_string(), change_descriptor.to_string()) .network(network) .create_wallet_no_persist() .expect("must create wallet"); - let transaction = Transaction { - input: vec![], - output: vec![], - version: transaction::Version::non_standard(0), - lock_time: bitcoin::absolute::LockTime::ZERO, - }; - let txid = transaction.compute_txid(); - let block_id = BlockId { + let block = BlockId { height: 5000, hash: BlockHash::all_zeros(), }; - wallet.insert_checkpoint(block_id).unwrap(); - wallet - .insert_checkpoint(BlockId { - height: 5001, - hash: BlockHash::all_zeros(), - }) - .unwrap(); - wallet.insert_tx(transaction); - let anchor = ConfirmationBlockTime { - confirmation_time: 0, - block_id, - }; - wallet - .apply_update(Update { - tx_update: tx_graph::TxUpdate { - anchors: [(anchor, txid)].into_iter().collect(), - ..Default::default() - }, - ..Default::default() - }) - .unwrap(); + insert_checkpoint(&mut wallet, block); + receive_output_in_latest_block(&mut wallet, 10_000); + wallet } diff --git a/crates/wallet/src/wallet/mod.rs b/crates/wallet/src/wallet/mod.rs index f2f909fd2..2059438d5 100644 --- a/crates/wallet/src/wallet/mod.rs +++ b/crates/wallet/src/wallet/mod.rs @@ -24,7 +24,9 @@ use core::{cmp::Ordering, fmt, mem, ops::Deref}; use bdk_chain::{ indexed_tx_graph, indexer::keychain_txout::KeychainTxOutIndex, - local_chain::{self, ApplyHeaderError, CannotConnectError, CheckPoint, CheckPointIter, LocalChain}, + local_chain::{ + self, ApplyHeaderError, CannotConnectError, CheckPoint, CheckPointIter, LocalChain, + }, spk_client::{ FullScanRequest, FullScanRequestBuilder, FullScanResult, SyncRequest, SyncRequestBuilder, SyncResult, @@ -2607,6 +2609,7 @@ macro_rules! doctest_wallet { use $crate::bitcoin::{BlockHash, Transaction, absolute, TxOut, Network, hashes::Hash}; use $crate::chain::{ConfirmationBlockTime, BlockId, TxGraph, tx_graph}; use $crate::{Update, KeychainKind, Wallet}; + use $crate::test_utils::*; let descriptor = "tr([73c5da0a/86'/0'/0']tprv8fMn4hSKPRC1oaCPqxDb1JWtgkpeiQvZhsr8W2xuy3GEMkzoArcAWTfJxYb6Wj8XNNDWEjfYKK4wGQXh3ZUXhDF2NcnsALpWTeSwarJt7Vc/0/*)"; let change_descriptor = "tr([73c5da0a/86'/0'/0']tprv8fMn4hSKPRC1oaCPqxDb1JWtgkpeiQvZhsr8W2xuy3GEMkzoArcAWTfJxYb6Wj8XNNDWEjfYKK4wGQXh3ZUXhDF2NcnsALpWTeSwarJt7Vc/1/*)"; @@ -2626,21 +2629,14 @@ macro_rules! doctest_wallet { }; let txid = tx.compute_txid(); let block_id = BlockId { height: 500, hash: BlockHash::all_zeros() }; - let _ = wallet.insert_checkpoint(block_id); - let _ = wallet.insert_checkpoint(BlockId { height: 1_000, hash: BlockHash::all_zeros() }); - let _ = wallet.insert_tx(tx); + insert_checkpoint(&mut wallet, block_id); + insert_checkpoint(&mut wallet, BlockId { height: 1_000, hash: BlockHash::all_zeros() }); + insert_tx(&mut wallet, tx); let anchor = ConfirmationBlockTime { confirmation_time: 50_000, block_id, }; - let update = Update { - tx_update: tx_graph::TxUpdate { - anchors: [(anchor, txid)].into_iter().collect(), - ..Default::default() - }, - ..Default::default() - }; - wallet.apply_update(update).unwrap(); + insert_anchor(&mut wallet, txid, anchor); wallet }} } diff --git a/crates/wallet/tests/wallet.rs b/crates/wallet/tests/wallet.rs index 96c0cb195..9cf417796 100644 --- a/crates/wallet/tests/wallet.rs +++ b/crates/wallet/tests/wallet.rs @@ -1165,7 +1165,7 @@ fn test_create_tx_add_utxo() { lock_time: absolute::LockTime::ZERO, }; let txid = small_output_tx.compute_txid(); - wallet.insert_tx(small_output_tx); + insert_tx(&mut wallet, small_output_tx); let anchor = ConfirmationBlockTime { block_id: wallet.latest_checkpoint().block_id(), confirmation_time: 200, @@ -1212,7 +1212,7 @@ fn test_create_tx_manually_selected_insufficient() { lock_time: absolute::LockTime::ZERO, }; let txid = small_output_tx.compute_txid(); - wallet.insert_tx(small_output_tx.clone()); + insert_tx(&mut wallet, small_output_tx.clone()); let anchor = ConfirmationBlockTime { block_id: wallet.latest_checkpoint().block_id(), confirmation_time: 200, @@ -1263,9 +1263,7 @@ fn test_create_tx_policy_path_no_csv() { value: Amount::from_sat(50_000), }], }; - let txid = tx.compute_txid(); - wallet.insert_tx(tx); - insert_seen_at(&mut wallet, txid, 0); + insert_tx(&mut wallet, tx); let external_policy = wallet.policies(KeychainKind::External).unwrap().unwrap(); let root_id = external_policy.id; @@ -1540,10 +1538,8 @@ fn test_add_foreign_utxo() { } #[test] -#[should_panic( - expected = "MissingTxOut([OutPoint { txid: 21d7fb1bceda00ab4069fc52d06baa13470803e9050edd16f5736e5d8c4925fd, vout: 0 }])" -)] fn test_calculate_fee_with_missing_foreign_utxo() { + use bdk_chain::tx_graph::CalculateFeeError; let (mut wallet1, _) = get_funded_wallet_wpkh(); let (wallet2, _) = get_funded_wallet_single("wpkh(cVbZ8ovhye9AoAHFsqobCf7LxbXDAECy9Kb8TZdfsDYMZGBUyCnm)"); @@ -1570,7 +1566,10 @@ fn test_calculate_fee_with_missing_foreign_utxo() { .unwrap(); let psbt = builder.finish().unwrap(); let tx = psbt.extract_tx().expect("failed to extract tx"); - wallet1.calculate_fee(&tx).unwrap(); + let res = wallet1.calculate_fee(&tx); + assert!( + matches!(res, Err(CalculateFeeError::MissingTxOut(outpoints)) if outpoints[0] == utxo.outpoint) + ); } #[test] @@ -1755,8 +1754,7 @@ fn test_bump_fee_irreplaceable_tx() { let tx = psbt.extract_tx().expect("failed to extract tx"); let txid = tx.compute_txid(); - wallet.insert_tx(tx); - insert_seen_at(&mut wallet, txid, 0); + insert_tx(&mut wallet, tx); wallet.build_fee_bump(txid).unwrap().finish().unwrap(); } @@ -1772,7 +1770,7 @@ fn test_bump_fee_confirmed_tx() { let tx = psbt.extract_tx().expect("failed to extract tx"); let txid = tx.compute_txid(); - wallet.insert_tx(tx); + insert_tx(&mut wallet, tx); let anchor = ConfirmationBlockTime { block_id: wallet.latest_checkpoint().get(42).unwrap().block_id(), @@ -1795,9 +1793,7 @@ fn test_bump_fee_low_fee_rate() { let tx = psbt.extract_tx().expect("failed to extract tx"); let txid = tx.compute_txid(); - - wallet.insert_tx(tx); - insert_seen_at(&mut wallet, txid, 0); + insert_tx(&mut wallet, tx); let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_rate(FeeRate::BROADCAST_MIN); @@ -1825,9 +1821,7 @@ fn test_bump_fee_low_abs() { let tx = psbt.extract_tx().expect("failed to extract tx"); let txid = tx.compute_txid(); - - wallet.insert_tx(tx); - insert_seen_at(&mut wallet, txid, 0); + insert_tx(&mut wallet, tx); let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_absolute(Amount::from_sat(10)); @@ -1845,8 +1839,7 @@ fn test_bump_fee_zero_abs() { let tx = psbt.extract_tx().expect("failed to extract tx"); let txid = tx.compute_txid(); - wallet.insert_tx(tx); - insert_seen_at(&mut wallet, txid, 0); + insert_tx(&mut wallet, tx); let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_absolute(Amount::ZERO); @@ -1868,8 +1861,7 @@ fn test_bump_fee_reduce_change() { let tx = psbt.extract_tx().expect("failed to extract tx"); let txid = tx.compute_txid(); - wallet.insert_tx(tx); - insert_seen_at(&mut wallet, txid, 0); + insert_tx(&mut wallet, tx); let feerate = FeeRate::from_sat_per_kwu(625); // 2.5 sat/vb let mut builder = wallet.build_fee_bump(txid).unwrap(); @@ -1961,8 +1953,7 @@ fn test_bump_fee_reduce_single_recipient() { let original_sent_received = wallet.sent_and_received(&tx); let original_fee = check_fee!(wallet, psbt); let txid = tx.compute_txid(); - wallet.insert_tx(tx); - insert_seen_at(&mut wallet, txid, 0); + insert_tx(&mut wallet, tx); let feerate = FeeRate::from_sat_per_kwu(625); // 2.5 sat/vb let mut builder = wallet.build_fee_bump(txid).unwrap(); @@ -2005,8 +1996,7 @@ fn test_bump_fee_absolute_reduce_single_recipient() { let tx = psbt.extract_tx().expect("failed to extract tx"); let original_sent_received = wallet.sent_and_received(&tx); let txid = tx.compute_txid(); - wallet.insert_tx(tx); - insert_seen_at(&mut wallet, txid, 0); + insert_tx(&mut wallet, tx); let mut builder = wallet.build_fee_bump(txid).unwrap(); builder @@ -2050,7 +2040,7 @@ fn test_bump_fee_drain_wallet() { }], }; let txid = tx.compute_txid(); - wallet.insert_tx(tx.clone()); + insert_tx(&mut wallet, tx.clone()); let anchor = ConfirmationBlockTime { block_id: wallet.latest_checkpoint().block_id(), confirmation_time: 42_000, @@ -2075,8 +2065,7 @@ fn test_bump_fee_drain_wallet() { let original_sent_received = wallet.sent_and_received(&tx); let txid = tx.compute_txid(); - wallet.insert_tx(tx); - insert_seen_at(&mut wallet, txid, 0); + insert_tx(&mut wallet, tx); assert_eq!(original_sent_received.0, Amount::from_sat(25_000)); // for the new feerate, it should be enough to reduce the output, but since we specify @@ -2112,7 +2101,7 @@ fn test_bump_fee_remove_output_manually_selected_only() { }], }; - wallet.insert_tx(init_tx.clone()); + insert_tx(&mut wallet, init_tx.clone()); let anchor = ConfirmationBlockTime { block_id: wallet.latest_checkpoint().block_id(), confirmation_time: 200, @@ -2136,8 +2125,7 @@ fn test_bump_fee_remove_output_manually_selected_only() { let tx = psbt.extract_tx().expect("failed to extract tx"); let original_sent_received = wallet.sent_and_received(&tx); let txid = tx.compute_txid(); - wallet.insert_tx(tx); - insert_seen_at(&mut wallet, txid, 0); + insert_tx(&mut wallet, tx); assert_eq!(original_sent_received.0, Amount::from_sat(25_000)); let mut builder = wallet.build_fee_bump(txid).unwrap(); @@ -2162,7 +2150,7 @@ fn test_bump_fee_add_input() { }], }; let txid = init_tx.compute_txid(); - wallet.insert_tx(init_tx); + insert_tx(&mut wallet, init_tx); let anchor = ConfirmationBlockTime { block_id: wallet.latest_checkpoint().block_id(), confirmation_time: 200, @@ -2178,8 +2166,7 @@ fn test_bump_fee_add_input() { let tx = psbt.extract_tx().expect("failed to extract tx"); let original_details = wallet.sent_and_received(&tx); let txid = tx.compute_txid(); - wallet.insert_tx(tx); - insert_seen_at(&mut wallet, txid, 0); + insert_tx(&mut wallet, tx); let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_rate(FeeRate::from_sat_per_vb_unchecked(50)); @@ -2232,8 +2219,7 @@ fn test_bump_fee_absolute_add_input() { let tx = psbt.extract_tx().expect("failed to extract tx"); let original_sent_received = wallet.sent_and_received(&tx); let txid = tx.compute_txid(); - wallet.insert_tx(tx); - insert_seen_at(&mut wallet, txid, 0); + insert_tx(&mut wallet, tx); let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_absolute(Amount::from_sat(6_000)); @@ -2296,8 +2282,7 @@ fn test_bump_fee_no_change_add_input_and_change() { let tx = psbt.extract_tx().expect("failed to extract tx"); let txid = tx.compute_txid(); - wallet.insert_tx(tx); - insert_seen_at(&mut wallet, txid, 0); + insert_tx(&mut wallet, tx); // Now bump the fees, the wallet should add an extra input and a change output, and leave // the original output untouched. @@ -2363,8 +2348,7 @@ fn test_bump_fee_add_input_change_dust() { assert_eq!(tx.input.len(), 1); assert_eq!(tx.output.len(), 2); let txid = tx.compute_txid(); - wallet.insert_tx(tx); - insert_seen_at(&mut wallet, txid, 0); + insert_tx(&mut wallet, tx); let mut builder = wallet.build_fee_bump(txid).unwrap(); // We set a fee high enough that during rbf we are forced to add @@ -2431,8 +2415,7 @@ fn test_bump_fee_force_add_input() { for txin in &mut tx.input { txin.witness.push([0x00; P2WPKH_FAKE_WITNESS_SIZE]); // fake signature } - wallet.insert_tx(tx.clone()); - insert_seen_at(&mut wallet, txid, 0); + insert_tx(&mut wallet, tx.clone()); // the new fee_rate is low enough that just reducing the change would be fine, but we force // the addition of an extra input with `add_utxo()` let mut builder = wallet.build_fee_bump(txid).unwrap(); @@ -2495,8 +2478,7 @@ fn test_bump_fee_absolute_force_add_input() { for txin in &mut tx.input { txin.witness.push([0x00; P2WPKH_FAKE_WITNESS_SIZE]); // fake signature } - wallet.insert_tx(tx.clone()); - insert_seen_at(&mut wallet, txid, 0); + insert_tx(&mut wallet, tx.clone()); // the new fee_rate is low enough that just reducing the change would be fine, but we force // the addition of an extra input with `add_utxo()` @@ -2566,8 +2548,7 @@ fn test_bump_fee_unconfirmed_inputs_only() { for txin in &mut tx.input { txin.witness.push([0x00; P2WPKH_FAKE_WITNESS_SIZE]); // fake signature } - wallet.insert_tx(tx); - insert_seen_at(&mut wallet, txid, 0); + insert_tx(&mut wallet, tx); let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_rate(FeeRate::from_sat_per_vb_unchecked(25)); builder.finish().unwrap(); @@ -2595,8 +2576,7 @@ fn test_bump_fee_unconfirmed_input() { for txin in &mut tx.input { txin.witness.push([0x00; P2WPKH_FAKE_WITNESS_SIZE]); // fake signature } - wallet.insert_tx(tx); - insert_seen_at(&mut wallet, txid, 0); + insert_tx(&mut wallet, tx); let mut builder = wallet.build_fee_bump(txid).unwrap(); builder @@ -3793,7 +3773,7 @@ fn test_spend_coinbase() { height: confirmation_height, hash: BlockHash::all_zeros(), }; - wallet.insert_checkpoint(confirmation_block_id).unwrap(); + insert_checkpoint(&mut wallet, confirmation_block_id); let coinbase_tx = Transaction { version: transaction::Version::ONE, lock_time: absolute::LockTime::ZERO, @@ -3809,7 +3789,7 @@ fn test_spend_coinbase() { }], }; let txid = coinbase_tx.compute_txid(); - wallet.insert_tx(coinbase_tx); + insert_tx(&mut wallet, coinbase_tx); let anchor = ConfirmationBlockTime { block_id: confirmation_block_id, confirmation_time: 30_000, @@ -3864,12 +3844,13 @@ fn test_spend_coinbase() { )) ); - wallet - .insert_checkpoint(BlockId { + insert_checkpoint( + &mut wallet, + BlockId { height: maturity_time, hash: BlockHash::all_zeros(), - }) - .unwrap(); + }, + ); let balance = wallet.balance(); assert_eq!( balance, @@ -4204,9 +4185,8 @@ fn single_descriptor_wallet_can_create_tx_and_receive_change() { let mut psbt = builder.finish().unwrap(); assert!(wallet.sign(&mut psbt, SignOptions::default()).unwrap()); let tx = psbt.extract_tx().unwrap(); - let txid = tx.compute_txid(); - wallet.insert_tx(tx); - insert_seen_at(&mut wallet, txid, 4); + let _txid = tx.compute_txid(); + insert_tx(&mut wallet, tx); let unspent: Vec<_> = wallet.list_unspent().collect(); assert_eq!(unspent.len(), 1); let utxo = unspent.first().unwrap();