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 50% rename from crates/wallet/tests/common.rs rename to crates/wallet/src/test_utils.rs index a2870c807..050b9fb19 100644 --- a/crates/wallet/tests/common.rs +++ b/crates/wallet/src/test_utils.rs @@ -1,19 +1,34 @@ -#![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 alloc::sync::Arc; +use core::str::FromStr; + +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 std::str::FromStr; + +use crate::{KeychainKind, Update, Wallet}; /// Return a fake wallet that appears to be funded for testing. /// /// 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, Txid) { + new_funded_wallet(descriptor, Some(change_descriptor)) +} + +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 { + Wallet::create_single(descriptor.to_string()) + }; + + let mut wallet = params .network(Network::Regtest) .create_wallet_no_persist() .expect("descriptors must be valid"); @@ -25,34 +40,20 @@ pub fn get_funded_wallet_with_change(descriptor: &str, change: &str) -> (Wallet, .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 { @@ -64,51 +65,55 @@ pub fn get_funded_wallet_with_change(descriptor: &str, change: &str) -> (Wallet, 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_anchor_from_conf( + insert_tx(&mut wallet, tx0.clone()); + 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_tx(&mut wallet, tx1.clone()); + 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()) @@ -119,82 +124,93 @@ 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, Txid) { + new_funded_wallet(descriptor, None) } -pub fn get_funded_wallet_wpkh() -> (Wallet, bitcoin::Txid) { - get_funded_wallet_with_change(get_test_wpkh(), get_test_wpkh_change()) +/// Get funded segwit wallet +pub fn get_funded_wallet_wpkh() -> (Wallet, Txid) { + let (desc, change_desc) = get_test_wpkh_and_change_desc(); + get_funded_wallet(desc, change_desc) } +/// `wpkh` single key descriptor pub fn get_test_wpkh() -> &'static str { "wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)" } -pub fn get_test_wpkh_with_change_desc() -> (&'static str, &'static str) { - ( - "wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)", - get_test_wpkh_change(), - ) -} - -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))` 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/*)" } -pub fn get_test_tr_single_sig_xprv_with_change_desc() -> (&'static str, &'static str) { +/// taproot xpriv and change descriptor +pub fn get_test_tr_single_sig_xprv_and_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)})" } +/// 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. @@ -208,23 +224,114 @@ 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( +/// 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, - 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() - }, - ..Default::default() - }) - .unwrap(); + 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(); + insert_tx(wallet, 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. +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() + }, + ..Default::default() + }) + .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/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 58b504dc9..68d5e6bec 100644 --- a/crates/wallet/src/wallet/mod.rs +++ b/crates/wallet/src/wallet/mod.rs @@ -12,84 +12,79 @@ //! 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, - local_chain::{ - self, ApplyHeaderError, CannotConnectError, CheckPoint, CheckPointIter, LocalChain, - }, + local_chain::{ApplyHeaderError, CannotConnectError, CheckPoint, CheckPointIter, LocalChain}, spk_client::{ FullScanRequest, FullScanRequestBuilder, FullScanResult, SyncRequest, SyncRequestBuilder, SyncResult, }, - tx_graph::{CanonicalTx, TxGraph, TxNode, TxUpdate}, + tx_graph::{CalculateFeeError, CanonicalTx, TxGraph, 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; @@ -123,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 @@ -134,8 +129,6 @@ pub struct Update { pub tx_update: TxUpdate, /// Update for the wallet's internal [`LocalChain`]. - /// - /// [`LocalChain`]: local_chain::LocalChain pub chain: Option, } @@ -1071,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 @@ -2299,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 @@ -2310,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 { @@ -2333,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); @@ -2368,14 +2320,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 @@ -2612,6 +2556,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/*)"; @@ -2631,21 +2576,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/psbt.rs b/crates/wallet/tests/psbt.rs index 155bb143a..a4d17493d 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"; @@ -11,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)); @@ -28,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)); @@ -44,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)); @@ -60,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)); @@ -81,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(); @@ -106,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(); @@ -130,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(); @@ -144,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(); @@ -173,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 d51af3352..6bfae2ec7 100644 --- a/crates/wallet/tests/wallet.rs +++ b/crates/wallet/tests/wallet.rs @@ -1,17 +1,17 @@ -extern crate alloc; - use std::path::Path; use std::str::FromStr; +use std::sync::Arc; 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}; 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,76 +30,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, - 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 { .. } => { - insert_anchor_from_conf(wallet, txid, height); - } - 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") @@ -130,7 +60,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 = { @@ -214,7 +144,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) @@ -560,7 +490,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 @@ -614,7 +544,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)); @@ -642,7 +572,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 @@ -655,7 +585,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 @@ -669,7 +599,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 @@ -682,7 +612,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)); @@ -693,7 +623,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 @@ -706,7 +636,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)); @@ -718,7 +648,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)); @@ -994,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); @@ -1064,7 +992,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(); @@ -1085,7 +1013,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(); @@ -1108,7 +1036,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(); @@ -1131,7 +1059,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(); @@ -1151,8 +1079,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(); @@ -1170,7 +1099,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(); @@ -1183,7 +1112,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 @@ -1199,7 +1128,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(); @@ -1211,7 +1140,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,12 +1165,12 @@ fn test_create_tx_add_utxo() { lock_time: absolute::LockTime::ZERO, }; 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(), + insert_tx(&mut wallet, small_output_tx); + 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() @@ -1283,12 +1212,12 @@ 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()); - let chain_position = ChainPosition::Confirmed(ConfirmationBlockTime { - block_id: wallet.latest_checkpoint().get(2000).unwrap().block_id(), + insert_tx(&mut wallet, small_output_tx.clone()); + 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() @@ -1305,7 +1234,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() @@ -1317,7 +1246,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() @@ -1334,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; @@ -1357,7 +1284,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; @@ -1378,7 +1305,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; @@ -1400,7 +1327,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 @@ -1412,7 +1339,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))); } @@ -1437,7 +1364,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", @@ -1541,7 +1468,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() @@ -1611,13 +1538,11 @@ 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("wpkh(cVbZ8ovhye9AoAHFsqobCf7LxbXDAECy9Kb8TZdfsDYMZGBUyCnm)"); + get_funded_wallet_single("wpkh(cVbZ8ovhye9AoAHFsqobCf7LxbXDAECy9Kb8TZdfsDYMZGBUyCnm)"); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX") .unwrap() @@ -1641,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] @@ -1663,7 +1591,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(); @@ -1707,7 +1635,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(); @@ -1784,7 +1712,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 @@ -1796,7 +1724,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 @@ -1807,7 +1735,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())) @@ -1826,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(); } @@ -1843,13 +1770,13 @@ 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 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(); } @@ -1866,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); @@ -1896,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)); @@ -1916,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); @@ -1939,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(); @@ -2032,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(); @@ -2076,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 @@ -2121,12 +2040,12 @@ fn test_bump_fee_drain_wallet() { }], }; let txid = tx.compute_txid(); - wallet.insert_tx(tx.clone()); - let chain_position = ChainPosition::Confirmed(ConfirmationBlockTime { + insert_tx(&mut wallet, tx.clone()); + 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() @@ -2146,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 @@ -2182,15 +2100,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); + insert_tx(&mut wallet, init_tx.clone()); + 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(), @@ -2209,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(); @@ -2235,14 +2150,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); + insert_tx(&mut wallet, init_tx); + 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() @@ -2253,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)); @@ -2307,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)); @@ -2371,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. @@ -2438,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 @@ -2506,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(); @@ -2570,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()` @@ -2641,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(); @@ -2670,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 @@ -2717,7 +2622,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(); @@ -2732,7 +2637,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(); @@ -2747,7 +2652,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(); @@ -2762,7 +2667,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(); @@ -2778,7 +2683,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(); @@ -2793,7 +2698,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(); @@ -2813,7 +2718,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(); @@ -2878,7 +2783,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); @@ -2912,7 +2817,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); @@ -2963,7 +2868,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 @@ -3256,7 +3161,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() @@ -3302,8 +3207,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(); @@ -3338,8 +3243,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])] @@ -3406,7 +3310,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(); @@ -3449,7 +3353,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(); @@ -3489,7 +3393,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(); @@ -3514,7 +3418,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() @@ -3572,16 +3476,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(); @@ -3606,17 +3510,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(); @@ -3647,7 +3551,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(); @@ -3687,7 +3591,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(); @@ -3725,7 +3629,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(); @@ -3747,7 +3651,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); @@ -3771,7 +3675,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 @@ -3791,7 +3695,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 @@ -3858,7 +3762,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() @@ -3869,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, @@ -3885,12 +3789,12 @@ fn test_spend_coinbase() { }], }; let txid = coinbase_tx.compute_txid(); - wallet.insert_tx(coinbase_tx); - let chain_position = ChainPosition::Confirmed(ConfirmationBlockTime { + insert_tx(&mut wallet, coinbase_tx); + 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; @@ -3940,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, @@ -3965,7 +3870,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); @@ -3992,7 +3897,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(); @@ -4059,7 +3964,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(); @@ -4096,7 +4001,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!( @@ -4124,7 +4029,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 @@ -4134,7 +4039,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, @@ -4160,8 +4065,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 @@ -4220,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(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 @@ -4281,9 +4143,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();