From 297bd9a5123f3c901e11eadf33a51351c1e2f6a4 Mon Sep 17 00:00:00 2001 From: valued mammal Date: Wed, 23 Oct 2024 22:09:14 -0400 Subject: [PATCH 1/9] test(wallet): refactor helper `insert_anchor_from_conf` --- crates/wallet/tests/common.rs | 42 ++++++++++------------- crates/wallet/tests/wallet.rs | 64 ++++++++++++++++------------------- 2 files changed, 48 insertions(+), 58 deletions(-) diff --git a/crates/wallet/tests/common.rs b/crates/wallet/tests/common.rs index a2870c807..59acbb114 100644 --- a/crates/wallet/tests/common.rs +++ b/crates/wallet/tests/common.rs @@ -86,29 +86,29 @@ pub fn get_funded_wallet_with_change(descriptor: &str, change: &str) -> (Wallet, .unwrap(); wallet.insert_tx(tx0.clone()); - insert_anchor_from_conf( + insert_anchor( &mut wallet, tx0.compute_txid(), - ChainPosition::Confirmed(ConfirmationBlockTime { + ConfirmationBlockTime { block_id: BlockId { height: 1_000, hash: BlockHash::all_zeros(), }, confirmation_time: 100, - }), + }, ); wallet.insert_tx(tx1.clone()); - insert_anchor_from_conf( + insert_anchor( &mut wallet, tx1.compute_txid(), - ChainPosition::Confirmed(ConfirmationBlockTime { + ConfirmationBlockTime { block_id: BlockId { height: 2_000, hash: BlockHash::all_zeros(), }, confirmation_time: 200, - }), + }, ); (wallet, tx1.compute_txid()) @@ -208,23 +208,17 @@ pub fn feerate_unchecked(sat_vb: f64) -> FeeRate { FeeRate::from_sat_per_kwu(sat_kwu) } -/// Simulates confirming a tx with `txid` at the specified `position` by inserting an anchor -/// at the lowest height in local chain that is greater or equal to `position`'s height, -/// assuming the confirmation time matches `ConfirmationTime::Confirmed`. -pub fn insert_anchor_from_conf( - wallet: &mut Wallet, - txid: Txid, - position: ChainPosition, -) { - if let ChainPosition::Confirmed(anchor) = position { - wallet - .apply_update(Update { - tx_update: tx_graph::TxUpdate { - anchors: [(anchor, txid)].into(), - ..Default::default() - }, +/// Simulates confirming a tx with `txid` by applying an update to the wallet containing +/// the given `anchor`. Note: to be considered confirmed the anchor block must exist in +/// the current active chain. +pub fn insert_anchor(wallet: &mut Wallet, txid: Txid, anchor: ConfirmationBlockTime) { + wallet + .apply_update(Update { + tx_update: tx_graph::TxUpdate { + anchors: [(anchor, txid)].into(), ..Default::default() - }) - .unwrap(); - } + }, + ..Default::default() + }) + .unwrap(); } diff --git a/crates/wallet/tests/wallet.rs b/crates/wallet/tests/wallet.rs index d51af3352..abf9a9c9f 100644 --- a/crates/wallet/tests/wallet.rs +++ b/crates/wallet/tests/wallet.rs @@ -62,8 +62,8 @@ fn receive_output_to_address( wallet.insert_tx(tx); match height { - ChainPosition::Confirmed { .. } => { - insert_anchor_from_conf(wallet, txid, height); + ChainPosition::Confirmed(anchor) => { + insert_anchor(wallet, txid, anchor); } ChainPosition::Unconfirmed(last_seen) => { insert_seen_at(wallet, txid, last_seen); @@ -1237,11 +1237,11 @@ fn test_create_tx_add_utxo() { }; let txid = small_output_tx.compute_txid(); wallet.insert_tx(small_output_tx); - let chain_position = ChainPosition::Confirmed(ConfirmationBlockTime { - block_id: wallet.latest_checkpoint().get(2000).unwrap().block_id(), + let anchor = ConfirmationBlockTime { + block_id: wallet.latest_checkpoint().block_id(), confirmation_time: 200, - }); - insert_anchor_from_conf(&mut wallet, txid, chain_position); + }; + insert_anchor(&mut wallet, txid, anchor); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX") .unwrap() @@ -1284,11 +1284,11 @@ fn test_create_tx_manually_selected_insufficient() { }; let txid = small_output_tx.compute_txid(); wallet.insert_tx(small_output_tx.clone()); - let chain_position = ChainPosition::Confirmed(ConfirmationBlockTime { - block_id: wallet.latest_checkpoint().get(2000).unwrap().block_id(), + let anchor = ConfirmationBlockTime { + block_id: wallet.latest_checkpoint().block_id(), confirmation_time: 200, - }); - insert_anchor_from_conf(&mut wallet, txid, chain_position); + }; + insert_anchor(&mut wallet, txid, anchor); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX") .unwrap() @@ -1845,11 +1845,11 @@ fn test_bump_fee_confirmed_tx() { wallet.insert_tx(tx); - let chain_position = ChainPosition::Confirmed(ConfirmationBlockTime { + let anchor = ConfirmationBlockTime { block_id: wallet.latest_checkpoint().get(42).unwrap().block_id(), confirmation_time: 42_000, - }); - insert_anchor_from_conf(&mut wallet, txid, chain_position); + }; + insert_anchor(&mut wallet, txid, anchor); wallet.build_fee_bump(txid).unwrap().finish().unwrap(); } @@ -2122,11 +2122,11 @@ fn test_bump_fee_drain_wallet() { }; let txid = tx.compute_txid(); wallet.insert_tx(tx.clone()); - let chain_position = ChainPosition::Confirmed(ConfirmationBlockTime { + let anchor = ConfirmationBlockTime { block_id: wallet.latest_checkpoint().block_id(), confirmation_time: 42_000, - }); - insert_anchor_from_conf(&mut wallet, txid, chain_position); + }; + insert_anchor(&mut wallet, txid, anchor); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX") .unwrap() @@ -2182,15 +2182,13 @@ fn test_bump_fee_remove_output_manually_selected_only() { value: Amount::from_sat(25_000), }], }; - let position: ChainPosition = wallet - .transactions() - .last() - .unwrap() - .chain_position - .cloned(); wallet.insert_tx(init_tx.clone()); - insert_anchor_from_conf(&mut wallet, init_tx.compute_txid(), position); + let anchor = ConfirmationBlockTime { + block_id: wallet.latest_checkpoint().block_id(), + confirmation_time: 200, + }; + insert_anchor(&mut wallet, init_tx.compute_txid(), anchor); let outpoint = OutPoint { txid: init_tx.compute_txid(), @@ -2235,14 +2233,12 @@ fn test_bump_fee_add_input() { }], }; let txid = init_tx.compute_txid(); - let pos: ChainPosition = wallet - .transactions() - .last() - .unwrap() - .chain_position - .cloned(); wallet.insert_tx(init_tx); - insert_anchor_from_conf(&mut wallet, txid, pos); + let anchor = ConfirmationBlockTime { + block_id: wallet.latest_checkpoint().block_id(), + confirmation_time: 200, + }; + insert_anchor(&mut wallet, txid, anchor); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX") .unwrap() @@ -3886,11 +3882,11 @@ fn test_spend_coinbase() { }; let txid = coinbase_tx.compute_txid(); wallet.insert_tx(coinbase_tx); - let chain_position = ChainPosition::Confirmed(ConfirmationBlockTime { + let anchor = ConfirmationBlockTime { block_id: confirmation_block_id, confirmation_time: 30_000, - }); - insert_anchor_from_conf(&mut wallet, txid, chain_position); + }; + insert_anchor(&mut wallet, txid, anchor); let not_yet_mature_time = confirmation_height + COINBASE_MATURITY - 1; let maturity_time = confirmation_height + COINBASE_MATURITY; @@ -4134,7 +4130,7 @@ fn test_keychains_with_overlapping_spks() { .address; let chain_position = ChainPosition::Confirmed(ConfirmationBlockTime { block_id: BlockId { - height: 8000, + height: 2000, hash: BlockHash::all_zeros(), }, confirmation_time: 0, From 823bb39fc1682b42b0e4a33d6a9030f82668656a Mon Sep 17 00:00:00 2001 From: valued mammal Date: Thu, 31 Oct 2024 16:41:41 -0400 Subject: [PATCH 2/9] feat(wallet): add module `test_utils` The common test utils are moved to a public `test_utils` module behind a new test-utils feature flag --- crates/wallet/Cargo.toml | 3 +- crates/wallet/src/lib.rs | 2 ++ .../{tests/common.rs => src/test_utils.rs} | 30 ++++++++++++++----- crates/wallet/tests/psbt.rs | 3 +- crates/wallet/tests/wallet.rs | 4 +-- 5 files changed, 29 insertions(+), 13 deletions(-) rename crates/wallet/{tests/common.rs => src/test_utils.rs} (90%) diff --git a/crates/wallet/Cargo.toml b/crates/wallet/Cargo.toml index 18f72337a..859c712a0 100644 --- a/crates/wallet/Cargo.toml +++ b/crates/wallet/Cargo.toml @@ -35,13 +35,14 @@ all-keys = ["keys-bip39"] keys-bip39 = ["bip39"] rusqlite = ["bdk_chain/rusqlite"] file_store = ["bdk_file_store"] +test-utils = ["std"] [dev-dependencies] lazy_static = "1.4" assert_matches = "1.5.0" tempfile = "3" bdk_chain = { path = "../chain", features = ["rusqlite"] } -bdk_wallet = { path = ".", features = ["rusqlite", "file_store"] } +bdk_wallet = { path = ".", features = ["rusqlite", "file_store", "test-utils"] } bdk_file_store = { path = "../file_store" } anyhow = "1" rand = "^0.8" diff --git a/crates/wallet/src/lib.rs b/crates/wallet/src/lib.rs index 40167a396..d17cc468d 100644 --- a/crates/wallet/src/lib.rs +++ b/crates/wallet/src/lib.rs @@ -28,6 +28,8 @@ pub extern crate serde_json; pub mod descriptor; pub mod keys; pub mod psbt; +#[cfg(feature = "test-utils")] +pub mod test_utils; mod types; mod wallet; diff --git a/crates/wallet/tests/common.rs b/crates/wallet/src/test_utils.rs similarity index 90% rename from crates/wallet/tests/common.rs rename to crates/wallet/src/test_utils.rs index 59acbb114..94a11feac 100644 --- a/crates/wallet/tests/common.rs +++ b/crates/wallet/src/test_utils.rs @@ -1,11 +1,15 @@ -#![allow(unused)] -use bdk_chain::{tx_graph, BlockId, ChainPosition, ConfirmationBlockTime, TxGraph}; -use bdk_wallet::{CreateParams, KeychainKind, LocalOutput, Update, Wallet}; +//! `bdk_wallet` test utilities + +use alloc::string::ToString; +use core::str::FromStr; + +use bdk_chain::{tx_graph, BlockId, ConfirmationBlockTime}; use bitcoin::{ hashes::Hash, transaction, Address, Amount, BlockHash, FeeRate, Network, OutPoint, Transaction, TxIn, TxOut, Txid, }; -use std::str::FromStr; + +use crate::{KeychainKind, Update, Wallet}; /// Return a fake wallet that appears to be funded for testing. /// @@ -128,14 +132,17 @@ pub fn get_funded_wallet(descriptor: &str) -> (Wallet, bitcoin::Txid) { get_funded_wallet_with_change(descriptor, change) } +/// Get funded segwit wallet pub fn get_funded_wallet_wpkh() -> (Wallet, bitcoin::Txid) { get_funded_wallet_with_change(get_test_wpkh(), get_test_wpkh_change()) } +/// `wpkh` single key descriptor pub fn get_test_wpkh() -> &'static str { "wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)" } +/// `wpkh` descriptor and change descriptor pub fn get_test_wpkh_with_change_desc() -> (&'static str, &'static str) { ( "wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)", @@ -143,54 +150,63 @@ pub fn get_test_wpkh_with_change_desc() -> (&'static str, &'static str) { ) } +/// `wpkh` change descriptor fn get_test_wpkh_change() -> &'static str { "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/0)" } +/// `wsh` descriptor with policy `and(pk(A),older(6))` pub fn get_test_single_sig_csv() -> &'static str { - // and(pk(Alice),older(6)) "wsh(and_v(v:pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW),older(6)))" } +/// `wsh` descriptor with policy `or(pk(A),and(pk(B),older(144)))` pub fn get_test_a_or_b_plus_csv() -> &'static str { - // or(pk(Alice),and(pk(Bob),older(144))) "wsh(or_d(pk(cRjo6jqfVNP33HhSS76UhXETZsGTZYx8FMFvR9kpbtCSV1PmdZdu),and_v(v:pk(cMnkdebixpXMPfkcNEjjGin7s94hiehAH4mLbYkZoh9KSiNNmqC8),older(144))))" } +/// `wsh` descriptor with policy `and(pk(A),after(100000))` pub fn get_test_single_sig_cltv() -> &'static str { - // and(pk(Alice),after(100000)) "wsh(and_v(v:pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW),after(100000)))" } +/// taproot single key descriptor pub fn get_test_tr_single_sig() -> &'static str { "tr(cNJmN3fH9DDbDt131fQNkVakkpzawJBSeybCUNmP1BovpmGQ45xG)" } +/// taproot descriptor with taptree pub fn get_test_tr_with_taptree() -> &'static str { "tr(b511bd5771e47ee27558b1765e87b541668304ec567721c7b880edc0a010da55,{pk(cPZzKuNmpuUjD1e8jUU4PVzy2b5LngbSip8mBsxf4e7rSFZVb4Uh),pk(8aee2b8120a5f157f1223f72b5e62b825831a27a9fdf427db7cc697494d4a642)})" } +/// taproot descriptor with private key taptree pub fn get_test_tr_with_taptree_both_priv() -> &'static str { "tr(b511bd5771e47ee27558b1765e87b541668304ec567721c7b880edc0a010da55,{pk(cPZzKuNmpuUjD1e8jUU4PVzy2b5LngbSip8mBsxf4e7rSFZVb4Uh),pk(cNaQCDwmmh4dS9LzCgVtyy1e1xjCJ21GUDHe9K98nzb689JvinGV)})" } +/// taproot descriptor where one key appears in two script paths pub fn get_test_tr_repeated_key() -> &'static str { "tr(b511bd5771e47ee27558b1765e87b541668304ec567721c7b880edc0a010da55,{and_v(v:pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW),after(100)),and_v(v:pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW),after(200))})" } +/// taproot xpriv descriptor pub fn get_test_tr_single_sig_xprv() -> &'static str { "tr(tprv8ZgxMBicQKsPdDArR4xSAECuVxeX1jwwSXR4ApKbkYgZiziDc4LdBy2WvJeGDfUSE4UT4hHhbgEwbdq8ajjUHiKDegkwrNU6V55CxcxonVN/*)" } +/// taproot xpriv and change descriptor pub fn get_test_tr_single_sig_xprv_with_change_desc() -> (&'static str, &'static str) { ("tr(tprv8ZgxMBicQKsPdDArR4xSAECuVxeX1jwwSXR4ApKbkYgZiziDc4LdBy2WvJeGDfUSE4UT4hHhbgEwbdq8ajjUHiKDegkwrNU6V55CxcxonVN/0/*)", "tr(tprv8ZgxMBicQKsPdDArR4xSAECuVxeX1jwwSXR4ApKbkYgZiziDc4LdBy2WvJeGDfUSE4UT4hHhbgEwbdq8ajjUHiKDegkwrNU6V55CxcxonVN/1/*)") } +/// taproot descriptor with taptree pub fn get_test_tr_with_taptree_xprv() -> &'static str { "tr(cNJmN3fH9DDbDt131fQNkVakkpzawJBSeybCUNmP1BovpmGQ45xG,{pk(tprv8ZgxMBicQKsPdDArR4xSAECuVxeX1jwwSXR4ApKbkYgZiziDc4LdBy2WvJeGDfUSE4UT4hHhbgEwbdq8ajjUHiKDegkwrNU6V55CxcxonVN/*),pk(8aee2b8120a5f157f1223f72b5e62b825831a27a9fdf427db7cc697494d4a642)})" } +/// taproot descriptor with duplicate script paths pub fn get_test_tr_dup_keys() -> &'static str { "tr(cNJmN3fH9DDbDt131fQNkVakkpzawJBSeybCUNmP1BovpmGQ45xG,{pk(8aee2b8120a5f157f1223f72b5e62b825831a27a9fdf427db7cc697494d4a642),pk(8aee2b8120a5f157f1223f72b5e62b825831a27a9fdf427db7cc697494d4a642)})" } diff --git a/crates/wallet/tests/psbt.rs b/crates/wallet/tests/psbt.rs index 155bb143a..cbd097c83 100644 --- a/crates/wallet/tests/psbt.rs +++ b/crates/wallet/tests/psbt.rs @@ -1,8 +1,7 @@ use bdk_wallet::bitcoin::{Amount, FeeRate, Psbt, TxIn}; +use bdk_wallet::test_utils::*; use bdk_wallet::{psbt, KeychainKind, SignOptions}; use core::str::FromStr; -mod common; -use common::*; // from bip 174 const PSBT_STR: &str = "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEHakcwRAIgR1lmF5fAGwNrJZKJSGhiGDR9iYZLcZ4ff89X0eURZYcCIFMJ6r9Wqk2Ikf/REf3xM286KdqGbX+EhtdVRs7tr5MZASEDXNxh/HupccC1AaZGoqg7ECy0OIEhfKaC3Ibi1z+ogpIAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIAAAA"; diff --git a/crates/wallet/tests/wallet.rs b/crates/wallet/tests/wallet.rs index abf9a9c9f..825dd930b 100644 --- a/crates/wallet/tests/wallet.rs +++ b/crates/wallet/tests/wallet.rs @@ -12,6 +12,7 @@ use bdk_wallet::descriptor::{calc_checksum, DescriptorError, IntoWalletDescripto use bdk_wallet::error::CreateTxError; use bdk_wallet::psbt::PsbtUtils; use bdk_wallet::signer::{SignOptions, SignerError}; +use bdk_wallet::test_utils::*; use bdk_wallet::tx_builder::AddForeignUtxoError; use bdk_wallet::{AddressInfo, Balance, ChangeSet, Wallet, WalletPersister, WalletTx}; use bdk_wallet::{KeychainKind, LoadError, LoadMismatch, LoadWithPersistError}; @@ -30,9 +31,6 @@ use miniscript::{descriptor::KeyMap, Descriptor, DescriptorPublicKey}; use rand::rngs::StdRng; use rand::SeedableRng; -mod common; -use common::*; - fn receive_output( wallet: &mut Wallet, value: u64, From 3135e291d777d474ab4b76de36d43a96ff104a3c Mon Sep 17 00:00:00 2001 From: valued mammal Date: Mon, 4 Nov 2024 15:02:46 -0500 Subject: [PATCH 3/9] test(wallet): add helpers to `test_utils` --- crates/wallet/src/test_utils.rs | 104 +++++++++++++++++++++++++++++++- crates/wallet/tests/wallet.rs | 69 +-------------------- 2 files changed, 102 insertions(+), 71 deletions(-) diff --git a/crates/wallet/src/test_utils.rs b/crates/wallet/src/test_utils.rs index 94a11feac..8ea0ff470 100644 --- a/crates/wallet/src/test_utils.rs +++ b/crates/wallet/src/test_utils.rs @@ -1,12 +1,13 @@ //! `bdk_wallet` test utilities use alloc::string::ToString; +use alloc::sync::Arc; use core::str::FromStr; -use bdk_chain::{tx_graph, BlockId, ConfirmationBlockTime}; +use bdk_chain::{tx_graph, BlockId, ChainPosition, ConfirmationBlockTime}; use bitcoin::{ - hashes::Hash, transaction, Address, Amount, BlockHash, FeeRate, Network, OutPoint, Transaction, - TxIn, TxOut, Txid, + absolute, hashes::Hash, transaction, Address, Amount, BlockHash, FeeRate, Network, OutPoint, + Transaction, TxIn, TxOut, Txid, }; use crate::{KeychainKind, Update, Wallet}; @@ -224,6 +225,90 @@ pub fn feerate_unchecked(sat_vb: f64) -> FeeRate { FeeRate::from_sat_per_kwu(sat_kwu) } +/// Receive a tx output with the given value in the latest block +pub fn receive_output_in_latest_block(wallet: &mut Wallet, value: u64) -> OutPoint { + let latest_cp = wallet.latest_checkpoint(); + let height = latest_cp.height(); + let anchor = if height == 0 { + ChainPosition::Unconfirmed(0) + } else { + ChainPosition::Confirmed(ConfirmationBlockTime { + block_id: latest_cp.block_id(), + confirmation_time: 0, + }) + }; + receive_output(wallet, value, anchor) +} + +/// Receive a tx output with the given value and chain position +pub fn receive_output( + wallet: &mut Wallet, + value: u64, + pos: ChainPosition, +) -> OutPoint { + let addr = wallet.next_unused_address(KeychainKind::External).address; + receive_output_to_address(wallet, addr, value, pos) +} + +/// Receive a tx output to an address with the given value and chain position +pub fn receive_output_to_address( + wallet: &mut Wallet, + addr: Address, + value: u64, + pos: ChainPosition, +) -> OutPoint { + let tx = Transaction { + version: transaction::Version::ONE, + lock_time: absolute::LockTime::ZERO, + input: vec![], + output: vec![TxOut { + script_pubkey: addr.script_pubkey(), + value: Amount::from_sat(value), + }], + }; + + let txid = tx.compute_txid(); + wallet.insert_tx(tx); + + match pos { + ChainPosition::Confirmed(anchor) => { + insert_anchor(wallet, txid, anchor); + } + ChainPosition::Unconfirmed(last_seen) => { + insert_seen_at(wallet, txid, last_seen); + } + } + + OutPoint { txid, vout: 0 } +} + +/// Insert a checkpoint into the wallet. This can be used to extend the wallet's local chain +/// or to insert a block that did not exist previously. Note that if replacing a block with +/// a different one at the same height, then all later blocks are evicted as well. +pub fn insert_checkpoint(wallet: &mut Wallet, block: BlockId) { + let mut cp = wallet.latest_checkpoint(); + cp = cp.insert(block); + wallet + .apply_update(Update { + chain: Some(cp), + ..Default::default() + }) + .unwrap(); +} + +/// Insert transaction +pub fn insert_tx(wallet: &mut Wallet, tx: Transaction) { + wallet + .apply_update(Update { + tx_update: bdk_chain::TxUpdate { + txs: vec![Arc::new(tx)], + ..Default::default() + }, + ..Default::default() + }) + .unwrap(); +} + /// Simulates confirming a tx with `txid` by applying an update to the wallet containing /// the given `anchor`. Note: to be considered confirmed the anchor block must exist in /// the current active chain. @@ -238,3 +323,16 @@ pub fn insert_anchor(wallet: &mut Wallet, txid: Txid, anchor: ConfirmationBlockT }) .unwrap(); } + +/// Marks the given `txid` seen as unconfirmed at `seen_at` +pub fn insert_seen_at(wallet: &mut Wallet, txid: Txid, seen_at: u64) { + wallet + .apply_update(crate::Update { + tx_update: tx_graph::TxUpdate { + seen_ats: [(txid, seen_at)].into_iter().collect(), + ..Default::default() + }, + ..Default::default() + }) + .unwrap(); +} diff --git a/crates/wallet/tests/wallet.rs b/crates/wallet/tests/wallet.rs index 825dd930b..1ca338542 100644 --- a/crates/wallet/tests/wallet.rs +++ b/crates/wallet/tests/wallet.rs @@ -5,7 +5,7 @@ use std::str::FromStr; use anyhow::Context; use assert_matches::assert_matches; -use bdk_chain::{tx_graph, COINBASE_MATURITY}; +use bdk_chain::COINBASE_MATURITY; use bdk_chain::{BlockId, ChainPosition, ConfirmationBlockTime}; use bdk_wallet::coin_selection::{self, LargestFirstCoinSelection}; use bdk_wallet::descriptor::{calc_checksum, DescriptorError, IntoWalletDescriptor}; @@ -31,73 +31,6 @@ use miniscript::{descriptor::KeyMap, Descriptor, DescriptorPublicKey}; use rand::rngs::StdRng; use rand::SeedableRng; -fn receive_output( - wallet: &mut Wallet, - value: u64, - height: ChainPosition, -) -> OutPoint { - let addr = wallet.next_unused_address(KeychainKind::External).address; - receive_output_to_address(wallet, addr, value, height) -} - -fn receive_output_to_address( - wallet: &mut Wallet, - addr: Address, - value: u64, - height: ChainPosition, -) -> OutPoint { - let tx = Transaction { - version: transaction::Version::ONE, - lock_time: absolute::LockTime::ZERO, - input: vec![], - output: vec![TxOut { - script_pubkey: addr.script_pubkey(), - value: Amount::from_sat(value), - }], - }; - - let txid = tx.compute_txid(); - wallet.insert_tx(tx); - - match height { - ChainPosition::Confirmed(anchor) => { - insert_anchor(wallet, txid, anchor); - } - ChainPosition::Unconfirmed(last_seen) => { - insert_seen_at(wallet, txid, last_seen); - } - } - - OutPoint { txid, vout: 0 } -} - -fn receive_output_in_latest_block(wallet: &mut Wallet, value: u64) -> OutPoint { - let latest_cp = wallet.latest_checkpoint(); - let height = latest_cp.height(); - let anchor = if height == 0 { - ChainPosition::Unconfirmed(0) - } else { - ChainPosition::Confirmed(ConfirmationBlockTime { - block_id: latest_cp.block_id(), - confirmation_time: 0, - }) - }; - receive_output(wallet, value, anchor) -} - -fn insert_seen_at(wallet: &mut Wallet, txid: Txid, seen_at: u64) { - use bdk_wallet::Update; - wallet - .apply_update(Update { - tx_update: tx_graph::TxUpdate { - seen_ats: [(txid, seen_at)].into_iter().collect(), - ..Default::default() - }, - ..Default::default() - }) - .unwrap(); -} - fn parse_descriptor(s: &str) -> (Descriptor, KeyMap) { >::parse_descriptor(&Secp256k1::new(), s) .expect("failed to parse descriptor") From 28d806123f4aa1b40ff1eb2a3148e25eb4104d8e Mon Sep 17 00:00:00 2001 From: valued mammal Date: Mon, 4 Nov 2024 15:59:35 -0500 Subject: [PATCH 4/9] test(wallet): fix test descriptor getters - `get_funded_wallet` requires two descriptors - `get_funded_wallet_single` returns a single-descriptor wallet --- crates/wallet/src/test_utils.rs | 43 +++++---- crates/wallet/tests/psbt.rs | 18 ++-- crates/wallet/tests/wallet.rs | 149 ++++++++++++++++---------------- 3 files changed, 104 insertions(+), 106 deletions(-) diff --git a/crates/wallet/src/test_utils.rs b/crates/wallet/src/test_utils.rs index 8ea0ff470..05b208798 100644 --- a/crates/wallet/src/test_utils.rs +++ b/crates/wallet/src/test_utils.rs @@ -17,8 +17,18 @@ 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_with_change(descriptor: &str, change: &str) -> (Wallet, bitcoin::Txid) { - let mut wallet = Wallet::create(descriptor.to_string(), change.to_string()) +pub fn get_funded_wallet(descriptor: &str, change_descriptor: &str) -> (Wallet, bitcoin::Txid) { + new_funded_wallet(descriptor, Some(change_descriptor)) +} + +fn new_funded_wallet(descriptor: &str, change_descriptor: Option<&str>) -> (Wallet, bitcoin::Txid) { + let params = if let Some(change_desc) = change_descriptor { + Wallet::create(descriptor.to_string(), change_desc.to_string()) + } else { + Wallet::create_single(descriptor.to_string()) + }; + + let mut wallet = params .network(Network::Regtest) .create_wallet_no_persist() .expect("descriptors must be valid"); @@ -124,18 +134,14 @@ pub fn get_funded_wallet_with_change(descriptor: &str, change: &str) -> (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. -/// -/// Note: the change descriptor will have script type `p2wpkh`. If passing some other script type -/// as argument, make sure you're ok with getting a wallet where the keychains have potentially -/// different script types. Otherwise, use `get_funded_wallet_with_change`. -pub fn get_funded_wallet(descriptor: &str) -> (Wallet, bitcoin::Txid) { - let change = get_test_wpkh_change(); - get_funded_wallet_with_change(descriptor, change) +pub fn get_funded_wallet_single(descriptor: &str) -> (Wallet, bitcoin::Txid) { + new_funded_wallet(descriptor, None) } /// Get funded segwit wallet pub fn get_funded_wallet_wpkh() -> (Wallet, bitcoin::Txid) { - get_funded_wallet_with_change(get_test_wpkh(), get_test_wpkh_change()) + let (desc, change_desc) = get_test_wpkh_and_change_desc(); + get_funded_wallet(desc, change_desc) } /// `wpkh` single key descriptor @@ -143,17 +149,10 @@ pub fn get_test_wpkh() -> &'static str { "wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)" } -/// `wpkh` descriptor and change descriptor -pub fn get_test_wpkh_with_change_desc() -> (&'static str, &'static str) { - ( - "wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)", - get_test_wpkh_change(), - ) -} - -/// `wpkh` change descriptor -fn get_test_wpkh_change() -> &'static str { - "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/0)" +/// `wpkh` xpriv and change descriptor +pub fn get_test_wpkh_and_change_desc() -> (&'static str, &'static str) { + ("wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)", + "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)") } /// `wsh` descriptor with policy `and(pk(A),older(6))` @@ -197,7 +196,7 @@ pub fn get_test_tr_single_sig_xprv() -> &'static str { } /// taproot xpriv and change descriptor -pub fn get_test_tr_single_sig_xprv_with_change_desc() -> (&'static str, &'static str) { +pub fn get_test_tr_single_sig_xprv_and_change_desc() -> (&'static str, &'static str) { ("tr(tprv8ZgxMBicQKsPdDArR4xSAECuVxeX1jwwSXR4ApKbkYgZiziDc4LdBy2WvJeGDfUSE4UT4hHhbgEwbdq8ajjUHiKDegkwrNU6V55CxcxonVN/0/*)", "tr(tprv8ZgxMBicQKsPdDArR4xSAECuVxeX1jwwSXR4ApKbkYgZiziDc4LdBy2WvJeGDfUSE4UT4hHhbgEwbdq8ajjUHiKDegkwrNU6V55CxcxonVN/1/*)") } diff --git a/crates/wallet/tests/psbt.rs b/crates/wallet/tests/psbt.rs index cbd097c83..a4d17493d 100644 --- a/crates/wallet/tests/psbt.rs +++ b/crates/wallet/tests/psbt.rs @@ -10,7 +10,7 @@ const PSBT_STR: &str = "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6 #[should_panic(expected = "InputIndexOutOfRange")] fn test_psbt_malformed_psbt_input_legacy() { let psbt_bip = Psbt::from_str(PSBT_STR).unwrap(); - let (mut wallet, _) = get_funded_wallet(get_test_wpkh()); + let (mut wallet, _) = get_funded_wallet_single(get_test_wpkh()); let send_to = wallet.peek_address(KeychainKind::External, 0); let mut builder = wallet.build_tx(); builder.add_recipient(send_to.script_pubkey(), Amount::from_sat(10_000)); @@ -27,7 +27,7 @@ fn test_psbt_malformed_psbt_input_legacy() { #[should_panic(expected = "InputIndexOutOfRange")] fn test_psbt_malformed_psbt_input_segwit() { let psbt_bip = Psbt::from_str(PSBT_STR).unwrap(); - let (mut wallet, _) = get_funded_wallet(get_test_wpkh()); + let (mut wallet, _) = get_funded_wallet_single(get_test_wpkh()); let send_to = wallet.peek_address(KeychainKind::External, 0); let mut builder = wallet.build_tx(); builder.add_recipient(send_to.script_pubkey(), Amount::from_sat(10_000)); @@ -43,7 +43,7 @@ fn test_psbt_malformed_psbt_input_segwit() { #[test] #[should_panic(expected = "InputIndexOutOfRange")] fn test_psbt_malformed_tx_input() { - let (mut wallet, _) = get_funded_wallet(get_test_wpkh()); + let (mut wallet, _) = get_funded_wallet_single(get_test_wpkh()); let send_to = wallet.peek_address(KeychainKind::External, 0); let mut builder = wallet.build_tx(); builder.add_recipient(send_to.script_pubkey(), Amount::from_sat(10_000)); @@ -59,7 +59,7 @@ fn test_psbt_malformed_tx_input() { #[test] fn test_psbt_sign_with_finalized() { let psbt_bip = Psbt::from_str(PSBT_STR).unwrap(); - let (mut wallet, _) = get_funded_wallet(get_test_wpkh()); + let (mut wallet, _) = get_funded_wallet_wpkh(); let send_to = wallet.peek_address(KeychainKind::External, 0); let mut builder = wallet.build_tx(); builder.add_recipient(send_to.script_pubkey(), Amount::from_sat(10_000)); @@ -80,7 +80,7 @@ fn test_psbt_fee_rate_with_witness_utxo() { let expected_fee_rate = FeeRate::from_sat_per_kwu(310); - let (mut wallet, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); + let (mut wallet, _) = get_funded_wallet_single("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); let addr = wallet.peek_address(KeychainKind::External, 0); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); @@ -105,7 +105,7 @@ fn test_psbt_fee_rate_with_nonwitness_utxo() { let expected_fee_rate = FeeRate::from_sat_per_kwu(310); - let (mut wallet, _) = get_funded_wallet("pkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); + let (mut wallet, _) = get_funded_wallet_single("pkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); let addr = wallet.peek_address(KeychainKind::External, 0); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); @@ -129,7 +129,7 @@ fn test_psbt_fee_rate_with_missing_txout() { let expected_fee_rate = FeeRate::from_sat_per_kwu(310); - let (mut wpkh_wallet, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); + let (mut wpkh_wallet, _) = get_funded_wallet_single("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); let addr = wpkh_wallet.peek_address(KeychainKind::External, 0); let mut builder = wpkh_wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); @@ -143,7 +143,7 @@ fn test_psbt_fee_rate_with_missing_txout() { let desc = "pkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/0)"; let change_desc = "pkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/1)"; - let (mut pkh_wallet, _) = get_funded_wallet_with_change(desc, change_desc); + let (mut pkh_wallet, _) = get_funded_wallet(desc, change_desc); let addr = pkh_wallet.peek_address(KeychainKind::External, 0); let mut builder = pkh_wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); @@ -172,7 +172,7 @@ fn test_psbt_multiple_internalkey_signers() { let keypair = Keypair::from_secret_key(&secp, &prv.inner); let change_desc = "tr(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)"; - let (mut wallet, _) = get_funded_wallet_with_change(&desc, change_desc); + let (mut wallet, _) = get_funded_wallet(&desc, change_desc); let to_spend = wallet.balance().total(); let send_to = wallet.peek_address(KeychainKind::External, 0); let mut builder = wallet.build_tx(); diff --git a/crates/wallet/tests/wallet.rs b/crates/wallet/tests/wallet.rs index 1ca338542..168b03d12 100644 --- a/crates/wallet/tests/wallet.rs +++ b/crates/wallet/tests/wallet.rs @@ -61,7 +61,7 @@ fn wallet_is_persisted() -> anyhow::Result<()> { { let temp_dir = tempfile::tempdir().expect("must create tempdir"); let file_path = temp_dir.path().join(filename); - let (external_desc, internal_desc) = get_test_tr_single_sig_xprv_with_change_desc(); + let (external_desc, internal_desc) = get_test_tr_single_sig_xprv_and_change_desc(); // create new wallet let wallet_spk_index = { @@ -145,7 +145,7 @@ fn wallet_load_checks() -> anyhow::Result<()> { let temp_dir = tempfile::tempdir().expect("must create tempdir"); let file_path = temp_dir.path().join(filename); let network = Network::Testnet; - let (external_desc, internal_desc) = get_test_tr_single_sig_xprv_with_change_desc(); + let (external_desc, internal_desc) = get_test_tr_single_sig_xprv_and_change_desc(); // create new wallet let _ = Wallet::create(external_desc, internal_desc) @@ -491,7 +491,7 @@ fn test_create_tx_version_0() { #[test] fn test_create_tx_version_1_csv() { - let (mut wallet, _) = get_funded_wallet(get_test_single_sig_csv()); + let (mut wallet, _) = get_funded_wallet_single(get_test_single_sig_csv()); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder @@ -545,7 +545,7 @@ fn test_create_tx_fee_sniping_locktime_last_sync() { #[test] fn test_create_tx_default_locktime_cltv() { - let (mut wallet, _) = get_funded_wallet(get_test_single_sig_cltv()); + let (mut wallet, _) = get_funded_wallet_single(get_test_single_sig_cltv()); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)); @@ -573,7 +573,7 @@ fn test_create_tx_custom_locktime() { #[test] fn test_create_tx_custom_locktime_compatible_with_cltv() { - let (mut wallet, _) = get_funded_wallet(get_test_single_sig_cltv()); + let (mut wallet, _) = get_funded_wallet_single(get_test_single_sig_cltv()); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder @@ -586,7 +586,7 @@ fn test_create_tx_custom_locktime_compatible_with_cltv() { #[test] fn test_create_tx_custom_locktime_incompatible_with_cltv() { - let (mut wallet, _) = get_funded_wallet(get_test_single_sig_cltv()); + let (mut wallet, _) = get_funded_wallet_single(get_test_single_sig_cltv()); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder @@ -600,7 +600,7 @@ fn test_create_tx_custom_locktime_incompatible_with_cltv() { #[test] fn test_create_tx_custom_csv() { // desc: wsh(and_v(v:pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW),older(6))) - let (mut wallet, _) = get_funded_wallet(get_test_single_sig_csv()); + let (mut wallet, _) = get_funded_wallet_single(get_test_single_sig_csv()); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder @@ -613,7 +613,7 @@ fn test_create_tx_custom_csv() { #[test] fn test_create_tx_no_rbf_csv() { - let (mut wallet, _) = get_funded_wallet(get_test_single_sig_csv()); + let (mut wallet, _) = get_funded_wallet_single(get_test_single_sig_csv()); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)); @@ -624,7 +624,7 @@ fn test_create_tx_no_rbf_csv() { #[test] fn test_create_tx_incompatible_csv() { - let (mut wallet, _) = get_funded_wallet(get_test_single_sig_csv()); + let (mut wallet, _) = get_funded_wallet_single(get_test_single_sig_csv()); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder @@ -637,7 +637,7 @@ fn test_create_tx_incompatible_csv() { #[test] fn test_create_tx_with_default_rbf_csv() { - let (mut wallet, _) = get_funded_wallet(get_test_single_sig_csv()); + let (mut wallet, _) = get_funded_wallet_single(get_test_single_sig_csv()); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)); @@ -649,7 +649,7 @@ fn test_create_tx_with_default_rbf_csv() { #[test] fn test_create_tx_no_rbf_cltv() { - let (mut wallet, _) = get_funded_wallet(get_test_single_sig_cltv()); + let (mut wallet, _) = get_funded_wallet_single(get_test_single_sig_cltv()); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000)); @@ -995,7 +995,7 @@ fn test_create_tx_input_hd_keypaths() { use bitcoin::bip32::{DerivationPath, Fingerprint}; use core::str::FromStr; - let (mut wallet, _) = get_funded_wallet("wpkh([d34db33f/44'/0'/0']tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)"); + let (mut wallet, _) = get_funded_wallet_single("wpkh([d34db33f/44'/0'/0']tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)"); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); @@ -1016,7 +1016,7 @@ fn test_create_tx_output_hd_keypaths() { use bitcoin::bip32::{DerivationPath, Fingerprint}; use core::str::FromStr; - let (mut wallet, _) = get_funded_wallet("wpkh([d34db33f/44'/0'/0']tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)"); + let (mut wallet, _) = get_funded_wallet_single("wpkh([d34db33f/44'/0'/0']tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)"); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); @@ -1039,7 +1039,7 @@ fn test_create_tx_set_redeem_script_p2sh() { use bitcoin::hex::FromHex; let (mut wallet, _) = - get_funded_wallet("sh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); + get_funded_wallet_single("sh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); @@ -1062,7 +1062,7 @@ fn test_create_tx_set_witness_script_p2wsh() { use bitcoin::hex::FromHex; let (mut wallet, _) = - get_funded_wallet("wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); + get_funded_wallet_single("wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); @@ -1082,8 +1082,9 @@ fn test_create_tx_set_witness_script_p2wsh() { #[test] fn test_create_tx_set_redeem_witness_script_p2wsh_p2sh() { - let (mut wallet, _) = - get_funded_wallet("sh(wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)))"); + let (mut wallet, _) = get_funded_wallet_single( + "sh(wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)))", + ); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); @@ -1101,7 +1102,7 @@ fn test_create_tx_set_redeem_witness_script_p2wsh_p2sh() { #[test] fn test_create_tx_non_witness_utxo() { let (mut wallet, _) = - get_funded_wallet("sh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); + get_funded_wallet_single("sh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); @@ -1114,7 +1115,7 @@ fn test_create_tx_non_witness_utxo() { #[test] fn test_create_tx_only_witness_utxo() { let (mut wallet, _) = - get_funded_wallet("wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); + get_funded_wallet_single("wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder @@ -1130,7 +1131,7 @@ fn test_create_tx_only_witness_utxo() { #[test] fn test_create_tx_shwpkh_has_witness_utxo() { let (mut wallet, _) = - get_funded_wallet("sh(wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); + get_funded_wallet_single("sh(wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); @@ -1142,7 +1143,7 @@ fn test_create_tx_shwpkh_has_witness_utxo() { #[test] fn test_create_tx_both_non_witness_utxo_and_witness_utxo_default() { let (mut wallet, _) = - get_funded_wallet("wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); + get_funded_wallet_single("wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); @@ -1236,7 +1237,7 @@ fn test_create_tx_manually_selected_insufficient() { #[test] #[should_panic(expected = "SpendingPolicyRequired(External)")] fn test_create_tx_policy_path_required() { - let (mut wallet, _) = get_funded_wallet(get_test_a_or_b_plus_csv()); + let (mut wallet, _) = get_funded_wallet_single(get_test_a_or_b_plus_csv()); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX") .unwrap() @@ -1248,7 +1249,7 @@ fn test_create_tx_policy_path_required() { #[test] fn test_create_tx_policy_path_no_csv() { - let (descriptor, change_descriptor) = get_test_wpkh_with_change_desc(); + let (descriptor, change_descriptor) = get_test_wpkh_and_change_desc(); let mut wallet = Wallet::create(descriptor, change_descriptor) .network(Network::Regtest) .create_wallet_no_persist() @@ -1288,7 +1289,7 @@ fn test_create_tx_policy_path_no_csv() { #[test] fn test_create_tx_policy_path_use_csv() { - let (mut wallet, _) = get_funded_wallet(get_test_a_or_b_plus_csv()); + let (mut wallet, _) = get_funded_wallet_single(get_test_a_or_b_plus_csv()); let external_policy = wallet.policies(KeychainKind::External).unwrap().unwrap(); let root_id = external_policy.id; @@ -1309,7 +1310,7 @@ fn test_create_tx_policy_path_use_csv() { #[test] fn test_create_tx_policy_path_ignored_subtree_with_csv() { - let (mut wallet, _) = get_funded_wallet("wsh(or_d(pk(cRjo6jqfVNP33HhSS76UhXETZsGTZYx8FMFvR9kpbtCSV1PmdZdu),or_i(and_v(v:pkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW),older(30)),and_v(v:pkh(cMnkdebixpXMPfkcNEjjGin7s94hiehAH4mLbYkZoh9KSiNNmqC8),older(90)))))"); + let (mut wallet, _) = get_funded_wallet_single("wsh(or_d(pk(cRjo6jqfVNP33HhSS76UhXETZsGTZYx8FMFvR9kpbtCSV1PmdZdu),or_i(and_v(v:pkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW),older(30)),and_v(v:pkh(cMnkdebixpXMPfkcNEjjGin7s94hiehAH4mLbYkZoh9KSiNNmqC8),older(90)))))"); let external_policy = wallet.policies(KeychainKind::External).unwrap().unwrap(); let root_id = external_policy.id; @@ -1331,7 +1332,7 @@ fn test_create_tx_policy_path_ignored_subtree_with_csv() { #[test] fn test_create_tx_global_xpubs_with_origin() { use bitcoin::bip32; - let (mut wallet, _) = get_funded_wallet("wpkh([73756c7f/48'/0'/0'/2']tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3/0/*)"); + let (mut wallet, _) = get_funded_wallet_single("wpkh([73756c7f/48'/0'/0'/2']tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3/0/*)"); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder @@ -1343,7 +1344,7 @@ fn test_create_tx_global_xpubs_with_origin() { let fingerprint = bip32::Fingerprint::from_hex("73756c7f").unwrap(); let path = bip32::DerivationPath::from_str("m/48'/0'/0'/2'").unwrap(); - assert_eq!(psbt.xpub.len(), 2); + assert_eq!(psbt.xpub.len(), 1); assert_eq!(psbt.xpub.get(&key), Some(&(fingerprint, path))); } @@ -1368,7 +1369,7 @@ fn test_create_tx_increment_change_index() { .unwrap() .assume_checked() .script_pubkey(); - let (desc, change_desc) = get_test_tr_single_sig_xprv_with_change_desc(); + let (desc, change_desc) = get_test_tr_single_sig_xprv_and_change_desc(); [ TestCase { name: "two wildcard, builder error", @@ -1472,7 +1473,7 @@ fn test_create_tx_increment_change_index() { fn test_add_foreign_utxo() { let (mut wallet1, _) = get_funded_wallet_wpkh(); let (wallet2, _) = - get_funded_wallet("wpkh(cVbZ8ovhye9AoAHFsqobCf7LxbXDAECy9Kb8TZdfsDYMZGBUyCnm)"); + get_funded_wallet_single("wpkh(cVbZ8ovhye9AoAHFsqobCf7LxbXDAECy9Kb8TZdfsDYMZGBUyCnm)"); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX") .unwrap() @@ -1548,7 +1549,7 @@ fn test_add_foreign_utxo() { fn test_calculate_fee_with_missing_foreign_utxo() { let (mut wallet1, _) = get_funded_wallet_wpkh(); let (wallet2, _) = - get_funded_wallet("wpkh(cVbZ8ovhye9AoAHFsqobCf7LxbXDAECy9Kb8TZdfsDYMZGBUyCnm)"); + get_funded_wallet_single("wpkh(cVbZ8ovhye9AoAHFsqobCf7LxbXDAECy9Kb8TZdfsDYMZGBUyCnm)"); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX") .unwrap() @@ -1594,7 +1595,7 @@ fn test_add_foreign_utxo_invalid_psbt_input() { fn test_add_foreign_utxo_where_outpoint_doesnt_match_psbt_input() { let (mut wallet1, txid1) = get_funded_wallet_wpkh(); let (wallet2, txid2) = - get_funded_wallet("wpkh(cVbZ8ovhye9AoAHFsqobCf7LxbXDAECy9Kb8TZdfsDYMZGBUyCnm)"); + get_funded_wallet_single("wpkh(cVbZ8ovhye9AoAHFsqobCf7LxbXDAECy9Kb8TZdfsDYMZGBUyCnm)"); let utxo2 = wallet2.list_unspent().next().unwrap(); let tx1 = wallet1.get_tx(txid1).unwrap().tx_node.tx.clone(); @@ -1638,7 +1639,7 @@ fn test_add_foreign_utxo_where_outpoint_doesnt_match_psbt_input() { fn test_add_foreign_utxo_only_witness_utxo() { let (mut wallet1, _) = get_funded_wallet_wpkh(); let (wallet2, txid2) = - get_funded_wallet("wpkh(cVbZ8ovhye9AoAHFsqobCf7LxbXDAECy9Kb8TZdfsDYMZGBUyCnm)"); + get_funded_wallet_single("wpkh(cVbZ8ovhye9AoAHFsqobCf7LxbXDAECy9Kb8TZdfsDYMZGBUyCnm)"); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX") .unwrap() .assume_checked(); @@ -1715,7 +1716,7 @@ fn test_get_psbt_input() { expected = "MissingKeyOrigin(\"tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3\")" )] fn test_create_tx_global_xpubs_origin_missing() { - let (mut wallet, _) = get_funded_wallet("wpkh(tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3/0/*)"); + let (mut wallet, _) = get_funded_wallet_single("wpkh(tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3/0/*)"); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder @@ -1727,7 +1728,7 @@ fn test_create_tx_global_xpubs_origin_missing() { #[test] fn test_create_tx_global_xpubs_master_without_origin() { use bitcoin::bip32; - let (mut wallet, _) = get_funded_wallet("wpkh(tpubD6NzVbkrYhZ4Y55A58Gv9RSNF5hy84b5AJqYy7sCcjFrkcLpPre8kmgfit6kY1Zs3BLgeypTDBZJM222guPpdz7Cup5yzaMu62u7mYGbwFL/0/*)"); + let (mut wallet, _) = get_funded_wallet_single("wpkh(tpubD6NzVbkrYhZ4Y55A58Gv9RSNF5hy84b5AJqYy7sCcjFrkcLpPre8kmgfit6kY1Zs3BLgeypTDBZJM222guPpdz7Cup5yzaMu62u7mYGbwFL/0/*)"); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder @@ -1738,7 +1739,7 @@ fn test_create_tx_global_xpubs_master_without_origin() { let key = bip32::Xpub::from_str("tpubD6NzVbkrYhZ4Y55A58Gv9RSNF5hy84b5AJqYy7sCcjFrkcLpPre8kmgfit6kY1Zs3BLgeypTDBZJM222guPpdz7Cup5yzaMu62u7mYGbwFL").unwrap(); let fingerprint = bip32::Fingerprint::from_hex("997a323b").unwrap(); - assert_eq!(psbt.xpub.len(), 2); + assert_eq!(psbt.xpub.len(), 1); assert_eq!( psbt.xpub.get(&key), Some(&(fingerprint, bip32::DerivationPath::default())) @@ -2644,7 +2645,7 @@ fn test_fee_amount_negative_drain_val() { #[test] fn test_sign_single_xprv() { - let (mut wallet, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); + let (mut wallet, _) = get_funded_wallet_single("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); @@ -2659,7 +2660,7 @@ fn test_sign_single_xprv() { #[test] fn test_sign_single_xprv_with_master_fingerprint_and_path() { - let (mut wallet, _) = get_funded_wallet("wpkh([d34db33f/84h/1h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); + let (mut wallet, _) = get_funded_wallet_single("wpkh([d34db33f/84h/1h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); @@ -2674,7 +2675,7 @@ fn test_sign_single_xprv_with_master_fingerprint_and_path() { #[test] fn test_sign_single_xprv_bip44_path() { - let (mut wallet, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/44'/0'/0'/0/*)"); + let (mut wallet, _) = get_funded_wallet_single("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/44'/0'/0'/0/*)"); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); @@ -2689,7 +2690,7 @@ fn test_sign_single_xprv_bip44_path() { #[test] fn test_sign_single_xprv_sh_wpkh() { - let (mut wallet, _) = get_funded_wallet("sh(wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*))"); + let (mut wallet, _) = get_funded_wallet_single("sh(wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*))"); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); @@ -2705,7 +2706,7 @@ fn test_sign_single_xprv_sh_wpkh() { #[test] fn test_sign_single_wif() { let (mut wallet, _) = - get_funded_wallet("wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)"); + get_funded_wallet_single("wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)"); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); @@ -2720,7 +2721,7 @@ fn test_sign_single_wif() { #[test] fn test_sign_single_xprv_no_hd_keypaths() { - let (mut wallet, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); + let (mut wallet, _) = get_funded_wallet_single("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); @@ -2740,7 +2741,7 @@ fn test_sign_single_xprv_no_hd_keypaths() { fn test_include_output_redeem_witness_script() { let desc = get_test_wpkh(); let change_desc = "sh(wsh(multi(1,cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW,cRjo6jqfVNP33HhSS76UhXETZsGTZYx8FMFvR9kpbtCSV1PmdZdu)))"; - let (mut wallet, _) = get_funded_wallet_with_change(desc, change_desc); + let (mut wallet, _) = get_funded_wallet(desc, change_desc); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX") .unwrap() .assume_checked(); @@ -2805,7 +2806,7 @@ fn test_signing_only_one_of_multiple_inputs() { #[test] fn test_try_finalize_sign_option() { - let (mut wallet, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); + let (mut wallet, _) = get_funded_wallet_single("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); for try_finalize in &[true, false] { let addr = wallet.next_unused_address(KeychainKind::External); @@ -2839,7 +2840,7 @@ fn test_try_finalize_sign_option() { #[test] fn test_taproot_try_finalize_sign_option() { - let (mut wallet, _) = get_funded_wallet(get_test_tr_with_taptree()); + let (mut wallet, _) = get_funded_wallet_single(get_test_tr_with_taptree()); for try_finalize in &[true, false] { let addr = wallet.next_unused_address(KeychainKind::External); @@ -2890,7 +2891,7 @@ fn test_taproot_try_finalize_sign_option() { fn test_sign_nonstandard_sighash() { let sighash = EcdsaSighashType::NonePlusAnyoneCanPay; - let (mut wallet, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); + let (mut wallet, _) = get_funded_wallet_single("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder @@ -3183,7 +3184,7 @@ fn test_get_address() { #[test] fn test_reveal_addresses() { - let (desc, change_desc) = get_test_tr_single_sig_xprv_with_change_desc(); + let (desc, change_desc) = get_test_tr_single_sig_xprv_and_change_desc(); let mut wallet = Wallet::create(desc, change_desc) .network(Network::Signet) .create_wallet_no_persist() @@ -3229,8 +3230,8 @@ fn test_get_address_no_reuse() { #[test] fn test_taproot_psbt_populate_tap_key_origins() { - let (desc, change_desc) = get_test_tr_single_sig_xprv_with_change_desc(); - let (mut wallet, _) = get_funded_wallet_with_change(desc, change_desc); + let (desc, change_desc) = get_test_tr_single_sig_xprv_and_change_desc(); + let (mut wallet, _) = get_funded_wallet(desc, change_desc); let addr = wallet.reveal_next_address(KeychainKind::External); let mut builder = wallet.build_tx(); @@ -3265,8 +3266,7 @@ fn test_taproot_psbt_populate_tap_key_origins() { #[test] fn test_taproot_psbt_populate_tap_key_origins_repeated_key() { - let (mut wallet, _) = - get_funded_wallet_with_change(get_test_tr_repeated_key(), get_test_tr_single_sig()); + let (mut wallet, _) = get_funded_wallet(get_test_tr_repeated_key(), get_test_tr_single_sig()); let addr = wallet.reveal_next_address(KeychainKind::External); let path = vec![("rn4nre9c".to_string(), vec![0])] @@ -3333,7 +3333,7 @@ fn test_taproot_psbt_input_tap_tree() { use bitcoin::hex::FromHex; use bitcoin::taproot; - let (mut wallet, _) = get_funded_wallet(get_test_tr_with_taptree()); + let (mut wallet, _) = get_funded_wallet_single(get_test_tr_with_taptree()); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); @@ -3376,7 +3376,7 @@ fn test_taproot_psbt_input_tap_tree() { #[test] fn test_taproot_sign_missing_witness_utxo() { - let (mut wallet, _) = get_funded_wallet(get_test_tr_single_sig()); + let (mut wallet, _) = get_funded_wallet_single(get_test_tr_single_sig()); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); @@ -3416,7 +3416,7 @@ fn test_taproot_sign_missing_witness_utxo() { #[test] fn test_taproot_sign_using_non_witness_utxo() { - let (mut wallet, prev_txid) = get_funded_wallet(get_test_tr_single_sig()); + let (mut wallet, prev_txid) = get_funded_wallet_single(get_test_tr_single_sig()); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); @@ -3441,7 +3441,7 @@ fn test_taproot_sign_using_non_witness_utxo() { #[test] fn test_taproot_foreign_utxo() { let (mut wallet1, _) = get_funded_wallet_wpkh(); - let (wallet2, _) = get_funded_wallet(get_test_tr_single_sig()); + let (wallet2, _) = get_funded_wallet_single(get_test_tr_single_sig()); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX") .unwrap() @@ -3499,16 +3499,16 @@ fn test_spend_from_wallet(mut wallet: Wallet) { // #[test] // fn test_taproot_key_spend() { -// let (mut wallet, _) = get_funded_wallet(get_test_tr_single_sig()); +// let (mut wallet, _) = get_funded_wallet_single(get_test_tr_single_sig()); // test_spend_from_wallet(wallet); -// let (mut wallet, _) = get_funded_wallet(get_test_tr_single_sig_xprv()); +// let (mut wallet, _) = get_funded_wallet_single(get_test_tr_single_sig_xprv()); // test_spend_from_wallet(wallet); // } #[test] fn test_taproot_no_key_spend() { - let (mut wallet, _) = get_funded_wallet(get_test_tr_with_taptree_both_priv()); + let (mut wallet, _) = get_funded_wallet_single(get_test_tr_with_taptree_both_priv()); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); @@ -3533,17 +3533,17 @@ fn test_taproot_no_key_spend() { #[test] fn test_taproot_script_spend() { - let (wallet, _) = get_funded_wallet(get_test_tr_with_taptree()); + let (wallet, _) = get_funded_wallet_single(get_test_tr_with_taptree()); test_spend_from_wallet(wallet); - let (wallet, _) = get_funded_wallet(get_test_tr_with_taptree_xprv()); + let (wallet, _) = get_funded_wallet_single(get_test_tr_with_taptree_xprv()); test_spend_from_wallet(wallet); } #[test] fn test_taproot_script_spend_sign_all_leaves() { use bdk_wallet::signer::TapLeavesOptions; - let (mut wallet, _) = get_funded_wallet(get_test_tr_with_taptree_both_priv()); + let (mut wallet, _) = get_funded_wallet_single(get_test_tr_with_taptree_both_priv()); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); @@ -3574,7 +3574,7 @@ fn test_taproot_script_spend_sign_include_some_leaves() { use bdk_wallet::signer::TapLeavesOptions; use bitcoin::taproot::TapLeafHash; - let (mut wallet, _) = get_funded_wallet(get_test_tr_with_taptree_both_priv()); + let (mut wallet, _) = get_funded_wallet_single(get_test_tr_with_taptree_both_priv()); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); @@ -3614,7 +3614,7 @@ fn test_taproot_script_spend_sign_exclude_some_leaves() { use bdk_wallet::signer::TapLeavesOptions; use bitcoin::taproot::TapLeafHash; - let (mut wallet, _) = get_funded_wallet(get_test_tr_with_taptree_both_priv()); + let (mut wallet, _) = get_funded_wallet_single(get_test_tr_with_taptree_both_priv()); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); @@ -3652,7 +3652,7 @@ fn test_taproot_script_spend_sign_exclude_some_leaves() { #[test] fn test_taproot_script_spend_sign_no_leaves() { use bdk_wallet::signer::TapLeavesOptions; - let (mut wallet, _) = get_funded_wallet(get_test_tr_with_taptree_both_priv()); + let (mut wallet, _) = get_funded_wallet_single(get_test_tr_with_taptree_both_priv()); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); @@ -3674,7 +3674,7 @@ fn test_taproot_script_spend_sign_no_leaves() { #[test] fn test_taproot_sign_derive_index_from_psbt() { - let (mut wallet, _) = get_funded_wallet(get_test_tr_single_sig_xprv()); + let (mut wallet, _) = get_funded_wallet_single(get_test_tr_single_sig_xprv()); let addr = wallet.next_unused_address(KeychainKind::External); @@ -3698,7 +3698,7 @@ fn test_taproot_sign_derive_index_from_psbt() { #[test] fn test_taproot_sign_explicit_sighash_all() { - let (mut wallet, _) = get_funded_wallet(get_test_tr_single_sig()); + let (mut wallet, _) = get_funded_wallet_single(get_test_tr_single_sig()); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder @@ -3718,7 +3718,7 @@ fn test_taproot_sign_explicit_sighash_all() { fn test_taproot_sign_non_default_sighash() { let sighash = TapSighashType::NonePlusAnyoneCanPay; - let (mut wallet, _) = get_funded_wallet(get_test_tr_single_sig()); + let (mut wallet, _) = get_funded_wallet_single(get_test_tr_single_sig()); let addr = wallet.next_unused_address(KeychainKind::External); let mut builder = wallet.build_tx(); builder @@ -3785,7 +3785,7 @@ fn test_taproot_sign_non_default_sighash() { #[test] fn test_spend_coinbase() { - let (desc, change_desc) = get_test_wpkh_with_change_desc(); + let (desc, change_desc) = get_test_wpkh_and_change_desc(); let mut wallet = Wallet::create(desc, change_desc) .network(Network::Regtest) .create_wallet_no_persist() @@ -3892,7 +3892,7 @@ fn test_spend_coinbase() { #[test] fn test_allow_dust_limit() { - let (mut wallet, _) = get_funded_wallet(get_test_single_sig_cltv()); + let (mut wallet, _) = get_funded_wallet_single(get_test_single_sig_cltv()); let addr = wallet.next_unused_address(KeychainKind::External); @@ -3919,7 +3919,7 @@ fn test_fee_rate_sign_no_grinding_high_r() { // Our goal is to obtain a transaction with a signature with high-R (71 bytes // instead of 70). We then check that our fee rate and fee calculation is // alright. - let (mut wallet, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); + let (mut wallet, _) = get_funded_wallet_single("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); let addr = wallet.next_unused_address(KeychainKind::External); let fee_rate = FeeRate::from_sat_per_vb_unchecked(1); let mut builder = wallet.build_tx(); @@ -3986,7 +3986,7 @@ fn test_fee_rate_sign_grinding_low_r() { // by setting the `allow_grinding` signing option as true. // We then check that our fee rate and fee calculation is alright and that our // signature is 70 bytes. - let (mut wallet, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); + let (mut wallet, _) = get_funded_wallet_single("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); let addr = wallet.next_unused_address(KeychainKind::External); let fee_rate = FeeRate::from_sat_per_vb_unchecked(1); let mut builder = wallet.build_tx(); @@ -4023,7 +4023,7 @@ fn test_taproot_load_descriptor_duplicated_keys() { // // Having the same key in multiple taproot leaves is safe and should be accepted by BDK - let (wallet, _) = get_funded_wallet(get_test_tr_dup_keys()); + let (wallet, _) = get_funded_wallet_single(get_test_tr_dup_keys()); let addr = wallet.peek_address(KeychainKind::External, 0); assert_eq!( @@ -4051,7 +4051,7 @@ fn test_keychains_with_overlapping_spks() { let wildcard_keychain = "wpkh(tprv8ZgxMBicQKsPdDArR4xSAECuVxeX1jwwSXR4ApKbkYgZiziDc4LdBy2WvJeGDfUSE4UT4hHhbgEwbdq8ajjUHiKDegkwrNU6V55CxcxonVN/*)"; let non_wildcard_keychain = "wpkh(tprv8ZgxMBicQKsPdDArR4xSAECuVxeX1jwwSXR4ApKbkYgZiziDc4LdBy2WvJeGDfUSE4UT4hHhbgEwbdq8ajjUHiKDegkwrNU6V55CxcxonVN/1)"; - let (mut wallet, _) = get_funded_wallet_with_change(wildcard_keychain, non_wildcard_keychain); + let (mut wallet, _) = get_funded_wallet(wildcard_keychain, non_wildcard_keychain); assert_eq!(wallet.balance().confirmed, Amount::from_sat(50000)); let addr = wallet @@ -4087,8 +4087,7 @@ fn test_tx_cancellation() { }}; } - let (mut wallet, _) = - get_funded_wallet_with_change(get_test_wpkh(), get_test_tr_single_sig_xprv()); + let (mut wallet, _) = get_funded_wallet(get_test_wpkh(), get_test_tr_single_sig_xprv()); let psbt1 = new_tx!(wallet); let change_derivation_1 = psbt1 @@ -4150,7 +4149,7 @@ fn test_thread_safety() { #[test] fn test_insert_tx_balance_and_utxos() { // creating many txs has no effect on the wallet's available utxos - let (mut wallet, _) = get_funded_wallet(get_test_tr_single_sig_xprv()); + let (mut wallet, _) = get_funded_wallet_single(get_test_tr_single_sig_xprv()); let addr = Address::from_str("bcrt1qc6fweuf4xjvz4x3gx3t9e0fh4hvqyu2qw4wvxm") .unwrap() .assume_checked(); From 9bdf4cb9829021a868a5e955f5297e632edf5d86 Mon Sep 17 00:00:00 2001 From: valued mammal Date: Mon, 4 Nov 2024 18:10:47 -0500 Subject: [PATCH 5/9] chore: fix imports --- crates/wallet/src/wallet/mod.rs | 77 ++++++++++++++++----------------- crates/wallet/tests/wallet.rs | 5 +-- 2 files changed, 38 insertions(+), 44 deletions(-) diff --git a/crates/wallet/src/wallet/mod.rs b/crates/wallet/src/wallet/mod.rs index 58b504dc9..5ffbe01ee 100644 --- a/crates/wallet/src/wallet/mod.rs +++ b/crates/wallet/src/wallet/mod.rs @@ -12,17 +12,15 @@ //! Wallet //! //! This module defines the [`Wallet`]. -use crate::{ - collections::{BTreeMap, HashMap}, - descriptor::check_wallet_descriptor, -}; + use alloc::{ boxed::Box, string::{String, ToString}, sync::Arc, vec::Vec, }; -pub use bdk_chain::Balance; +use core::{cmp::Ordering, fmt, mem, ops::Deref}; + use bdk_chain::{ indexed_tx_graph, indexer::keychain_txout::KeychainTxOutIndex, @@ -33,63 +31,62 @@ use bdk_chain::{ FullScanRequest, FullScanRequestBuilder, FullScanResult, SyncRequest, SyncRequestBuilder, SyncResult, }, - tx_graph::{CanonicalTx, TxGraph, TxNode, TxUpdate}, + tx_graph::{CalculateFeeError, CanonicalTx, TxGraph, TxNode, TxUpdate}, BlockId, ChainPosition, ConfirmationBlockTime, DescriptorExt, FullTxOut, Indexed, IndexedTxGraph, Merge, }; -use bitcoin::sighash::{EcdsaSighashType, TapSighashType}; use bitcoin::{ - absolute, psbt, Address, Block, FeeRate, Network, OutPoint, ScriptBuf, Sequence, Transaction, - TxOut, Txid, Witness, + absolute, + consensus::encode::serialize, + constants::genesis_block, + psbt, + secp256k1::Secp256k1, + sighash::{EcdsaSighashType, TapSighashType}, + transaction, Address, Amount, Block, BlockHash, FeeRate, Network, OutPoint, Psbt, ScriptBuf, + Sequence, Transaction, TxOut, Txid, Weight, Witness, }; -use bitcoin::{consensus::encode::serialize, transaction, BlockHash, Psbt}; -use bitcoin::{constants::genesis_block, Amount}; -use bitcoin::{secp256k1::Secp256k1, Weight}; -use core::cmp::Ordering; -use core::fmt; -use core::mem; -use core::ops::Deref; -use rand_core::RngCore; - -use descriptor::error::Error as DescriptorError; use miniscript::{ descriptor::KeyMap, psbt::{PsbtExt, PsbtInputExt, PsbtInputSatisfier}, }; - -use bdk_chain::tx_graph::CalculateFeeError; +use rand_core::RngCore; mod changeset; pub mod coin_selection; +pub mod error; pub mod export; mod params; +mod persisted; pub mod signer; pub mod tx_builder; -pub use changeset::*; -pub use params::*; -mod persisted; -pub use persisted::*; pub(crate) mod utils; -pub mod error; - -pub use utils::IsDust; - -use coin_selection::{DefaultCoinSelectionAlgorithm, InsufficientFunds}; -use signer::{SignOptions, SignerOrdering, SignersContainer, TransactionSigner}; -use tx_builder::{FeePolicy, TxBuilder, TxParams}; -use utils::{check_nsequence_rbf, After, Older, SecpCtx}; - -use crate::descriptor::policy::BuildSatisfaction; +use crate::collections::{BTreeMap, HashMap}; use crate::descriptor::{ - self, DerivedDescriptor, DescriptorMeta, ExtendedDescriptor, ExtractPolicy, - IntoWalletDescriptor, Policy, XKeyUtils, + check_wallet_descriptor, error::Error as DescriptorError, policy::BuildSatisfaction, + DerivedDescriptor, DescriptorMeta, ExtendedDescriptor, ExtractPolicy, IntoWalletDescriptor, + Policy, XKeyUtils, }; use crate::psbt::PsbtUtils; -use crate::signer::SignerError; use crate::types::*; -use crate::wallet::coin_selection::Excess::{self, Change, NoChange}; -use crate::wallet::error::{BuildFeeBumpError, CreateTxError, MiniscriptPsbtError}; +use crate::wallet::{ + coin_selection::{ + DefaultCoinSelectionAlgorithm, + Excess::{self, Change, NoChange}, + InsufficientFunds, + }, + error::{BuildFeeBumpError, CreateTxError, MiniscriptPsbtError}, + signer::{SignOptions, SignerError, SignerOrdering, SignersContainer, TransactionSigner}, + tx_builder::{FeePolicy, TxBuilder, TxParams}, + utils::{check_nsequence_rbf, After, Older, SecpCtx}, +}; + +// re-exports +pub use bdk_chain::Balance; +pub use changeset::ChangeSet; +pub use params::*; +pub use persisted::*; +pub use utils::IsDust; const COINBASE_MATURITY: u32 = 100; diff --git a/crates/wallet/tests/wallet.rs b/crates/wallet/tests/wallet.rs index 168b03d12..96c0cb195 100644 --- a/crates/wallet/tests/wallet.rs +++ b/crates/wallet/tests/wallet.rs @@ -1,7 +1,6 @@ -extern crate alloc; - use std::path::Path; use std::str::FromStr; +use std::sync::Arc; use anyhow::Context; use assert_matches::assert_matches; @@ -925,8 +924,6 @@ fn test_create_tx_drain_to_dust_amount() { #[test] fn test_create_tx_ordering_respected() { - use alloc::sync::Arc; - let (mut wallet, _) = get_funded_wallet_wpkh(); let addr = wallet.next_unused_address(KeychainKind::External); From ab278844a9fa2ebaac7da97b23d6a88e5237ab16 Mon Sep 17 00:00:00 2001 From: valued mammal Date: Mon, 4 Nov 2024 21:15:37 -0500 Subject: [PATCH 6/9] 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 | 16 ++--- crates/wallet/tests/wallet.rs | 96 ++++++++++++------------------ 4 files changed, 86 insertions(+), 139 deletions(-) diff --git a/crates/wallet/src/test_utils.rs b/crates/wallet/src/test_utils.rs index 05b208798..050b9fb19 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 5ffbe01ee..2059438d5 100644 --- a/crates/wallet/src/wallet/mod.rs +++ b/crates/wallet/src/wallet/mod.rs @@ -2609,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/*)"; @@ -2628,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(); From 200a16d277f7711a586f46833ab1b2ebf96b73c9 Mon Sep 17 00:00:00 2001 From: valued mammal Date: Tue, 5 Nov 2024 13:49:50 -0500 Subject: [PATCH 7/9] fix(wallet)!: delete method `insert_tx` Inserting unconfirmed txs can be done using the existing method `apply_unconfirmed_txs`. Also removed `insert_checkpoint`, as the API is unclear regarding where in the local chain the given block should connect. Analogs for these methods are found in `test_utils` module and are mainly used to facilitate testing. --- crates/wallet/src/wallet/mod.rs | 46 ++------------------------------- crates/wallet/tests/wallet.rs | 42 ------------------------------ 2 files changed, 2 insertions(+), 86 deletions(-) diff --git a/crates/wallet/src/wallet/mod.rs b/crates/wallet/src/wallet/mod.rs index 2059438d5..a5178eb9e 100644 --- a/crates/wallet/src/wallet/mod.rs +++ b/crates/wallet/src/wallet/mod.rs @@ -24,9 +24,7 @@ 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::{ApplyHeaderError, CannotConnectError, CheckPoint, CheckPointIter, LocalChain}, spk_client::{ FullScanRequest, FullScanRequestBuilder, FullScanResult, SyncRequest, SyncRequestBuilder, SyncResult, @@ -120,7 +118,7 @@ pub struct Wallet { /// An update to [`Wallet`]. /// -/// It updates [`KeychainTxOutIndex`], [`bdk_chain::TxGraph`] and [`local_chain::LocalChain`] atomically. +/// It updates [`KeychainTxOutIndex`], [`bdk_chain::TxGraph`] and [`LocalChain`] atomically. #[derive(Debug, Clone, Default)] pub struct Update { /// Contains the last active derivation indices per keychain (`K`), which is used to update the @@ -131,8 +129,6 @@ pub struct Update { pub tx_update: TxUpdate, /// Update for the wallet's internal [`LocalChain`]. - /// - /// [`LocalChain`]: local_chain::LocalChain pub chain: Option, } @@ -1068,44 +1064,6 @@ impl Wallet { }) } - /// Add a new checkpoint to the wallet's internal view of the chain. - /// - /// Returns whether anything changed with the insertion (e.g. `false` if checkpoint was already - /// there). - /// - /// **WARNING**: You must persist the changes resulting from one or more calls to this method - /// if you need the inserted checkpoint data to be reloaded after closing the wallet. - /// See [`Wallet::reveal_next_address`]. - pub fn insert_checkpoint( - &mut self, - block_id: BlockId, - ) -> Result { - let changeset = self.chain.insert_block(block_id)?; - let changed = !changeset.is_empty(); - self.stage.merge(changeset.into()); - Ok(changed) - } - - /// Add a transaction to the wallet's internal view of the chain. This stages the change, - /// you must persist it later. - /// - /// This method inserts the given `tx` and returns whether anything changed after insertion, - /// which will be false if the same transaction already exists in the wallet's transaction - /// graph. Any changes are staged but not committed. - /// - /// # Note - /// - /// By default the inserted `tx` won't be considered "canonical" because it's not known - /// whether the transaction exists in the best chain. To know whether it exists, the tx - /// must be broadcast to the network and the wallet synced via a chain source. - pub fn insert_tx>>(&mut self, tx: T) -> bool { - let mut changeset = ChangeSet::default(); - changeset.merge(self.indexed_graph.insert_tx(tx).into()); - let ret = !changeset.is_empty(); - self.stage.merge(changeset); - ret - } - /// Iterate over the transactions in the wallet. pub fn transactions(&self) -> impl Iterator + '_ { self.indexed_graph diff --git a/crates/wallet/tests/wallet.rs b/crates/wallet/tests/wallet.rs index 9cf417796..6bfae2ec7 100644 --- a/crates/wallet/tests/wallet.rs +++ b/crates/wallet/tests/wallet.rs @@ -4124,48 +4124,6 @@ fn test_thread_safety() { thread_safe::(); // compiles only if true } -#[test] -fn test_insert_tx_balance_and_utxos() { - // creating many txs has no effect on the wallet's available utxos - let (mut wallet, _) = get_funded_wallet_single(get_test_tr_single_sig_xprv()); - let addr = Address::from_str("bcrt1qc6fweuf4xjvz4x3gx3t9e0fh4hvqyu2qw4wvxm") - .unwrap() - .assume_checked(); - - let unspent: Vec<_> = wallet.list_unspent().collect(); - assert!(!unspent.is_empty()); - - let balance = wallet.balance().total(); - let fee = Amount::from_sat(143); - let amt = balance - fee; - - for _ in 0..3 { - let mut builder = wallet.build_tx(); - builder.add_recipient(addr.script_pubkey(), amt); - let mut psbt = builder.finish().unwrap(); - assert!(wallet.sign(&mut psbt, SignOptions::default()).unwrap()); - let tx = psbt.extract_tx().unwrap(); - let _ = wallet.insert_tx(tx); - } - assert_eq!(wallet.list_unspent().collect::>(), unspent); - assert_eq!(wallet.balance().confirmed, balance); - - // manually setting a tx last_seen will consume the wallet's available utxos - let addr = Address::from_str("bcrt1qfjg5lv3dvc9az8patec8fjddrs4aqtauadnagr") - .unwrap() - .assume_checked(); - let mut builder = wallet.build_tx(); - builder.add_recipient(addr.script_pubkey(), amt); - 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(); - let _ = wallet.insert_tx(tx); - insert_seen_at(&mut wallet, txid, 2); - assert!(wallet.list_unspent().next().is_none()); - assert_eq!(wallet.balance().total().to_sat(), 0); -} - #[test] fn single_descriptor_wallet_can_create_tx_and_receive_change() { // create single descriptor wallet and fund it From 00c568d4c5e020439c7f586075d3aa2003cd4b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BF=97=E5=AE=87?= Date: Wed, 9 Oct 2024 14:19:58 +0000 Subject: [PATCH 8/9] revert(wallet)!: rm `Wallet::unbroadcast_transactions` This is no longer relevant as we direct callers to only insert tx into the wallet after a successful broadcast. --- crates/wallet/src/wallet/mod.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/crates/wallet/src/wallet/mod.rs b/crates/wallet/src/wallet/mod.rs index a5178eb9e..7df48f071 100644 --- a/crates/wallet/src/wallet/mod.rs +++ b/crates/wallet/src/wallet/mod.rs @@ -29,7 +29,7 @@ use bdk_chain::{ FullScanRequest, FullScanRequestBuilder, FullScanResult, SyncRequest, SyncRequestBuilder, SyncResult, }, - tx_graph::{CalculateFeeError, CanonicalTx, TxGraph, TxNode, TxUpdate}, + tx_graph::{CalculateFeeError, CanonicalTx, TxGraph, TxUpdate}, BlockId, ChainPosition, ConfirmationBlockTime, DescriptorExt, FullTxOut, Indexed, IndexedTxGraph, Merge, }; @@ -2323,14 +2323,6 @@ impl Wallet { self.indexed_graph.graph() } - /// Iterate over transactions in the wallet that are unseen and unanchored likely - /// because they haven't been broadcast. - pub fn unbroadcast_transactions( - &self, - ) -> impl Iterator, ConfirmationBlockTime>> { - self.tx_graph().txs_with_no_anchor_or_last_seen() - } - /// Get a reference to the inner [`KeychainTxOutIndex`]. pub fn spk_index(&self) -> &KeychainTxOutIndex { &self.indexed_graph.index From b0dc3ddd3a5f2ff8e5b2fc5654fc2519bc7e728e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BF=97=E5=AE=87?= Date: Wed, 9 Oct 2024 14:36:27 +0000 Subject: [PATCH 9/9] feat(wallet)!: make `seen_at` mandatory for `Wallet::apply_update_at` Not including a `seen_at` alongside the update means the unconfirmed txs of the update will not be considered to be part of the canonical history. Therefore, transactions created with this wallet may replace the update's unconfirmed txs (which is unintuitive behavior). Also updated the docs. --- crates/wallet/src/wallet/mod.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/crates/wallet/src/wallet/mod.rs b/crates/wallet/src/wallet/mod.rs index 7df48f071..68d5e6bec 100644 --- a/crates/wallet/src/wallet/mod.rs +++ b/crates/wallet/src/wallet/mod.rs @@ -2254,10 +2254,10 @@ impl Wallet { let now = SystemTime::now() .duration_since(UNIX_EPOCH) .expect("time now must surpass epoch anchor"); - self.apply_update_at(update, Some(now.as_secs())) + self.apply_update_at(update, now.as_secs()) } - /// Applies an `update` alongside an optional `seen_at` timestamp and stages the changes. + /// Applies an `update` alongside a `seen_at` timestamp and stages the changes. /// /// `seen_at` represents when the update is seen (in unix seconds). It is used to determine the /// `last_seen`s for all transactions in the update which have no corresponding anchor(s). The @@ -2265,15 +2265,12 @@ impl Wallet { /// transactions (where the transaction with the lower `last_seen` value is omitted from the /// canonical history). /// - /// Not setting a `seen_at` value means unconfirmed transactions introduced by this update will - /// not be part of the canonical history of transactions. - /// /// Use [`apply_update`](Wallet::apply_update) to have the `seen_at` value automatically set to /// the current time. pub fn apply_update_at( &mut self, update: impl Into, - seen_at: Option, + seen_at: u64, ) -> Result<(), CannotConnectError> { let update = update.into(); let mut changeset = match update.chain { @@ -2288,7 +2285,7 @@ impl Wallet { changeset.merge(index_changeset.into()); changeset.merge( self.indexed_graph - .apply_update_at(update.tx_update, seen_at) + .apply_update_at(update.tx_update, Some(seen_at)) .into(), ); self.stage.merge(changeset);