diff --git a/Cargo.toml b/Cargo.toml index eed208f9f..b68ab6bb6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ serde = { version = "1", features = ["derive"] } # Optional dependencies anyhow = { version = "1.0.98", optional = true } -bdk_file_store = { version = "0.21.1", optional = true } +bdk_file_store = { version = "0.22.0", optional = true } bip39 = { version = "2.0", optional = true } tempfile = { version = "3.20.0", optional = true } @@ -43,7 +43,7 @@ test-utils = ["std", "anyhow", "tempfile"] [dev-dependencies] anyhow = "1" assert_matches = "1.5.0" -bdk_bitcoind_rpc = { version = "0.21.0" } +bdk_bitcoind_rpc = { version = "0.22.0" } bdk_electrum = { version = "0.23.1" } bdk_esplora = { version = "0.22.1", features = ["async-https", "blocking-https", "tokio"] } bdk_wallet = { path = ".", features = ["rusqlite", "file_store", "test-utils"] } @@ -74,3 +74,28 @@ name = "esplora_blocking" [[example]] name = "bitcoind_rpc" + + +[patch.crates-io.bdk_chain] +git = "https://github.com/bitcoindevkit/bdk" +branch = "master" + +[patch.crates-io.bdk_core] +git = "https://github.com/bitcoindevkit/bdk" +branch = "master" + +[patch.crates-io.bdk_bitcoind_rpc] +git = "https://github.com/bitcoindevkit/bdk" +branch = "master" + +[patch.crates-io.bdk_electrum] +git = "https://github.com/bitcoindevkit/bdk" +branch = "master" + +[patch.crates-io.bdk_esplora] +git = "https://github.com/bitcoindevkit/bdk" +branch = "master" + +[patch.crates-io.bdk_file_store] +git = "https://github.com/bitcoindevkit/bdk" +branch = "master" diff --git a/examples/bitcoind_rpc.rs b/examples/bitcoind_rpc.rs index f0bbd7290..733f8950a 100644 --- a/examples/bitcoind_rpc.rs +++ b/examples/bitcoind_rpc.rs @@ -144,7 +144,8 @@ fn main() -> anyhow::Result<()> { args.start_height, wallet .transactions() - .filter(|tx| tx.chain_position.is_unconfirmed()), + .filter(|tx| tx.pos.is_unconfirmed()) + .map(|tx| tx.tx), ); spawn(move || -> Result<(), anyhow::Error> { while let Some(emission) = emitter.next_block()? { diff --git a/src/test_utils.rs b/src/test_utils.rs index 11fd13b18..23594a27a 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -308,7 +308,7 @@ pub fn receive_output_to_address( /// 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); + cp = cp.insert(block.height, block.hash); wallet .apply_update(Update { chain: Some(cp), diff --git a/src/wallet/export.rs b/src/wallet/export.rs index c07bdf482..c65d73a0a 100644 --- a/src/wallet/export.rs +++ b/src/wallet/export.rs @@ -130,7 +130,7 @@ impl FullyNodedExport { let blockheight = if include_blockheight { wallet.transactions().next().map_or(0, |canonical_tx| { canonical_tx - .chain_position + .pos .confirmation_height_upper_bound() .unwrap_or(0) }) diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index bc814589e..8c54241f9 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -29,9 +29,9 @@ use bdk_chain::{ FullScanRequest, FullScanRequestBuilder, FullScanResponse, SyncRequest, SyncRequestBuilder, SyncResponse, }, - tx_graph::{CalculateFeeError, CanonicalTx, TxGraph, TxUpdate}, - BlockId, CanonicalizationParams, ChainPosition, ConfirmationBlockTime, DescriptorExt, - FullTxOut, Indexed, IndexedTxGraph, Indexer, Merge, + tx_graph::{CalculateFeeError, TxGraph, TxUpdate}, + BlockId, CanonicalTx, CanonicalizationParams, ChainPosition, ConfirmationBlockTime, + DescriptorExt, FullTxOut, Indexed, IndexedTxGraph, Indexer, Merge, }; use bitcoin::{ absolute, @@ -109,6 +109,9 @@ pub struct Wallet { stage: ChangeSet, network: Network, secp: SecpCtx, + + // Canonical view. + canonical_view: CanonicalView, } /// An update to [`Wallet`]. @@ -310,8 +313,11 @@ impl fmt::Display for ApplyBlockError { #[cfg(feature = "std")] impl std::error::Error for ApplyBlockError {} +/// A consistent view of canonical transactions. +pub type CanonicalView = chain::CanonicalView; + /// A `CanonicalTx` managed by a `Wallet`. -pub type WalletTx<'a> = CanonicalTx<'a, Arc, ConfirmationBlockTime>; +pub type WalletTx = CanonicalTx; impl Wallet { /// Build a new single descriptor [`Wallet`]. @@ -447,7 +453,7 @@ impl Wallet { let genesis_hash = params .genesis_hash .unwrap_or(genesis_block(network).block_hash()); - let (chain, chain_changeset) = LocalChain::from_genesis_hash(genesis_hash); + let (chain, chain_changeset) = LocalChain::from_genesis(genesis_hash); let (descriptor, mut descriptor_keymap) = (params.descriptor)(&secp, network_kind)?; check_wallet_descriptor(&descriptor)?; @@ -492,6 +498,12 @@ impl Wallet { params.use_spk_cache, )?; + let canonical_view = indexed_graph.canonical_view( + &chain, + chain.tip().block_id(), + CanonicalizationParams::default(), + ); + Ok(Wallet { signers, change_signers, @@ -500,6 +512,7 @@ impl Wallet { indexed_graph, stage, secp, + canonical_view, }) } @@ -690,6 +703,12 @@ impl Wallet { ) .map_err(LoadError::Descriptor)?; + let canonical_view = indexed_graph.canonical_view( + &chain, + chain.tip().block_id(), + CanonicalizationParams::default(), + ); + Ok(Some(Wallet { signers, change_signers, @@ -698,6 +717,7 @@ impl Wallet { stage, network, secp, + canonical_view, })) } @@ -895,14 +915,8 @@ impl Wallet { /// Return the list of unspent outputs of this wallet pub fn list_unspent(&self) -> impl Iterator + '_ { - self.indexed_graph - .graph() - .filter_chain_unspents( - &self.chain, - self.chain.tip().block_id(), - CanonicalizationParams::default(), - self.indexed_graph.index.outpoints().iter().cloned(), - ) + self.canonical_view + .filter_unspent_outpoints(self.indexed_graph.index.outpoints().iter().cloned()) .map(|((k, i), full_txo)| new_local_utxo(k, i, full_txo)) } @@ -911,13 +925,13 @@ impl Wallet { /// If the transaction with txid [`Txid`] cannot be found in the wallet's transactions, `None` /// is returned. pub fn tx_details(&self, txid: Txid) -> Option { - let tx: WalletTx = self.transactions().find(|c| c.tx_node.txid == txid)?; + let tx: WalletTx = self.transactions().find(|c| c.txid == txid)?; - let (sent, received) = self.sent_and_received(&tx.tx_node.tx); - let fee: Option = self.calculate_fee(&tx.tx_node.tx).ok(); - let fee_rate: Option = self.calculate_fee_rate(&tx.tx_node.tx).ok(); - let balance_delta: SignedAmount = self.indexed_graph.index.net_value(&tx.tx_node.tx, ..); - let chain_position = tx.chain_position; + let (sent, received) = self.sent_and_received(&tx.tx); + let fee: Option = self.calculate_fee(&tx.tx).ok(); + let fee_rate: Option = self.calculate_fee_rate(&tx.tx).ok(); + let balance_delta: SignedAmount = self.indexed_graph.index.net_value(&tx.tx, ..); + let chain_position = tx.pos; let tx_details: TxDetails = TxDetails { txid, @@ -927,29 +941,45 @@ impl Wallet { fee_rate, balance_delta, chain_position, - tx: tx.tx_node.tx, + tx: tx.tx, }; Some(tx_details) } + /// Get a reference to the current [`CanonicalView`] of transactions. + pub fn canonical_view(&self) -> &CanonicalView { + &self.canonical_view + } + + /// Obtain a new [`CanonicalView`] modified by the `params`. + /// + /// Note, the result of this call is not stored anywhere. + pub fn canonical_view_with_params(&self, params: CanonicalizationParams) -> CanonicalView { + self.indexed_graph + .canonical_view(&self.chain, self.chain.tip().block_id(), params) + } + + /// Update the wallet's [`CanonicalView`] of transactions. + fn update_canonical_view(&mut self) { + self.canonical_view = self.indexed_graph.canonical_view( + &self.chain, + self.chain.tip().block_id(), + CanonicalizationParams::default(), + ) + } + /// List all relevant outputs (includes both spent and unspent, confirmed and unconfirmed). /// /// To list only unspent outputs (UTXOs), use [`Wallet::list_unspent`] instead. pub fn list_output(&self) -> impl Iterator + '_ { - self.indexed_graph - .graph() - .filter_chain_txouts( - &self.chain, - self.chain.tip().block_id(), - CanonicalizationParams::default(), - self.indexed_graph.index.outpoints().iter().cloned(), - ) - .map(|((k, i), full_txo)| new_local_utxo(k, i, full_txo)) + self.canonical_view + .filter_outpoints(self.indexed_graph.index.outpoints().iter().cloned()) + .map(|((k, i), txo)| new_local_utxo(k, i, txo)) } /// Get all the checkpoints the wallet is currently storing indexed by height. - pub fn checkpoints(&self) -> CheckPointIter { + pub fn checkpoints(&self) -> CheckPointIter { self.chain.iter_checkpoints() } @@ -988,19 +1018,13 @@ impl Wallet { } /// Returns the utxo owned by this wallet corresponding to `outpoint` if it exists in the - /// wallet's database. + /// wallet's transaction graph. pub fn get_utxo(&self, op: OutPoint) -> Option { let ((keychain, index), _) = self.indexed_graph.index.txout(op)?; - self.indexed_graph - .graph() - .filter_chain_unspents( - &self.chain, - self.chain.tip().block_id(), - CanonicalizationParams::default(), - core::iter::once(((), op)), - ) - .map(|(_, full_txo)| new_local_utxo(keychain, index, full_txo)) + self.canonical_view + .filter_unspent_outpoints([((), op)]) .next() + .map(|(_, txo)| new_local_utxo(keychain, index, txo)) } /// Inserts a [`TxOut`] at [`OutPoint`] into the wallet's transaction graph. @@ -1021,8 +1045,13 @@ impl Wallet { /// [`list_unspent`]: Self::list_unspent /// [`list_output`]: Self::list_output pub fn insert_txout(&mut self, outpoint: OutPoint, txout: TxOut) { - let additions = self.indexed_graph.insert_txout(outpoint, txout); - self.stage.merge(additions.into()); + let mut tx_update = TxUpdate::default(); + tx_update.txouts = [(outpoint, txout)].into(); + self.apply_update(Update { + tx_update, + ..Default::default() + }) + .expect("Applying a `TxUpdate` cannot fail") } /// Calculates the fee of a given transaction. Returns [`Amount::ZERO`] if `tx` is a coinbase @@ -1040,7 +1069,7 @@ impl Wallet { /// # use bdk_wallet::Wallet; /// # let mut wallet: Wallet = todo!(); /// # let txid:Txid = todo!(); - /// let tx = wallet.get_tx(txid).expect("transaction").tx_node.tx; + /// let tx = wallet.get_tx(txid).expect("transaction").tx; /// let fee = wallet.calculate_fee(&tx).expect("fee"); /// ``` /// @@ -1071,7 +1100,7 @@ impl Wallet { /// # use bdk_wallet::Wallet; /// # let mut wallet: Wallet = todo!(); /// # let txid:Txid = todo!(); - /// let tx = wallet.get_tx(txid).expect("transaction").tx_node.tx; + /// let tx = wallet.get_tx(txid).expect("transaction").tx; /// let fee_rate = wallet.calculate_fee_rate(&tx).expect("fee rate"); /// ``` /// @@ -1101,7 +1130,7 @@ impl Wallet { /// # use bdk_wallet::Wallet; /// # let mut wallet: Wallet = todo!(); /// # let txid:Txid = todo!(); - /// let tx = wallet.get_tx(txid).expect("tx exists").tx_node.tx; + /// let tx = wallet.get_tx(txid).expect("tx exists").tx; /// let (sent, received) = wallet.sent_and_received(&tx); /// ``` /// @@ -1135,19 +1164,11 @@ impl Wallet { /// /// let wallet_tx = wallet.get_tx(my_txid).expect("panic if tx does not exist"); /// - /// // get reference to full transaction - /// println!("my tx: {:#?}", wallet_tx.tx_node.tx); - /// - /// // list all transaction anchors - /// for anchor in wallet_tx.tx_node.anchors { - /// println!( - /// "tx is anchored by block of hash {}", - /// anchor.anchor_block().hash - /// ); - /// } + /// // Get reference to full transaction + /// println!("my tx: {:#?}", wallet_tx.tx); /// - /// // get confirmation status of transaction - /// match wallet_tx.chain_position { + /// // Get confirmation status of transaction + /// match wallet_tx.pos { /// ChainPosition::Confirmed { /// anchor, /// transitively: None, @@ -1170,15 +1191,10 @@ impl Wallet { /// ``` /// /// [`Anchor`]: bdk_chain::Anchor - pub fn get_tx(&self, txid: Txid) -> Option> { - let graph = self.indexed_graph.graph(); - graph - .list_canonical_txs( - &self.chain, - self.chain.tip().block_id(), - CanonicalizationParams::default(), - ) - .find(|tx| tx.tx_node.txid == txid) + pub fn get_tx(&self, txid: Txid) -> Option { + self.canonical_view + .txs() + .find(|canon_tx| canon_tx.txid == txid) } /// Iterate over relevant and canonical transactions in the wallet. @@ -1192,16 +1208,10 @@ impl Wallet { /// /// To iterate over all canonical transactions, including those that are irrelevant, use /// [`TxGraph::list_canonical_txs`]. - pub fn transactions<'a>(&'a self) -> impl Iterator> + 'a { - let tx_graph = self.indexed_graph.graph(); - let tx_index = &self.indexed_graph.index; - tx_graph - .list_canonical_txs( - &self.chain, - self.chain.tip().block_id(), - CanonicalizationParams::default(), - ) - .filter(|c_tx| tx_index.is_tx_relevant(&c_tx.tx_node.tx)) + pub fn transactions(&self) -> impl Iterator + '_ { + self.canonical_view + .txs() + .filter(|canon_tx| self.indexed_graph.index.is_tx_relevant(&canon_tx.tx)) } /// Array of relevant and canonical transactions in the wallet sorted with a comparator @@ -1214,13 +1224,12 @@ impl Wallet { /// /// ```rust,no_run /// # use bdk_wallet::{LoadParams, Wallet, WalletTx}; - /// # let mut wallet:Wallet = todo!(); + /// # let mut wallet: Wallet = todo!(); /// // Transactions by chain position: first unconfirmed then descending by confirmed height. - /// let sorted_txs: Vec = - /// wallet.transactions_sort_by(|tx1, tx2| tx2.chain_position.cmp(&tx1.chain_position)); + /// let sorted_txs: Vec = wallet.transactions_sort_by(|tx1, tx2| tx2.pos.cmp(&tx1.pos)); /// # Ok::<(), anyhow::Error>(()) /// ``` - pub fn transactions_sort_by(&self, compare: F) -> Vec> + pub fn transactions_sort_by(&self, compare: F) -> Vec where F: FnMut(&WalletTx, &WalletTx) -> Ordering, { @@ -1232,15 +1241,29 @@ impl Wallet { /// Return the balance, separated into available, trusted-pending, untrusted-pending, and /// immature values. pub fn balance(&self) -> Balance { - self.indexed_graph.graph().balance( - &self.chain, - self.chain.tip().block_id(), - CanonicalizationParams::default(), + self.canonical_view.balance( self.indexed_graph.index.outpoints().iter().cloned(), - |&(k, _), _| k == KeychainKind::Internal, + |_, txo| self.is_tx_trusted(txo.outpoint.txid), + /* min_confirmations: */ 1, ) } + /// Whether the transaction of `txid` is trusted by this wallet. + /// + /// A tx is considered "trusted" if all of the inputs are controlled by this wallet, + /// i.e. the input corresponds to an outpoint that is indexed under a tracked keychain. + fn is_tx_trusted(&self, txid: Txid) -> bool { + let Some(tx) = self.indexed_graph.graph().get_tx(txid) else { + return false; + }; + tx.input.iter().all(|txin| { + self.indexed_graph + .index + .txout(txin.previous_output) + .is_some() + }) + } + /// Add an external signer /// /// See [the `signer` module](signer) for an example. @@ -1713,10 +1736,10 @@ impl Wallet { ) -> Result, BuildFeeBumpError> { let tx_graph = self.indexed_graph.graph(); let txout_index = &self.indexed_graph.index; - let chain_tip = self.chain.tip().block_id(); - let chain_positions: HashMap> = tx_graph - .list_canonical_txs(&self.chain, chain_tip, CanonicalizationParams::default()) - .map(|canon_tx| (canon_tx.tx_node.txid, canon_tx.chain_position)) + let chain_positions: HashMap> = self + .canonical_view + .txs() + .map(|canon_tx| (canon_tx.txid, canon_tx.pos)) .collect(); let mut tx = tx_graph @@ -1960,24 +1983,22 @@ impl Wallet { sign_options: SignOptions, ) -> Result { let tx = &psbt.unsigned_tx; - let chain_tip = self.chain.tip().block_id(); let prev_txids = tx .input .iter() .map(|txin| txin.previous_output.txid) .collect::>(); let confirmation_heights = self - .indexed_graph - .graph() - .list_canonical_txs(&self.chain, chain_tip, CanonicalizationParams::default()) - .filter(|canon_tx| prev_txids.contains(&canon_tx.tx_node.txid)) + .canonical_view + .txs() + .filter(|canon_tx| prev_txids.contains(&canon_tx.txid)) // This is for a small performance gain. Although `.filter` filters out excess txs, it // will still consume the internal `CanonicalIter` entirely. Having a `.take` here // allows us to stop further unnecessary canonicalization. .take(prev_txids.len()) .map(|canon_tx| { - let txid = canon_tx.tx_node.txid; - match canon_tx.chain_position { + let txid = canon_tx.txid; + match canon_tx.pos { ChainPosition::Confirmed { anchor, .. } => (txid, anchor.block_id.height), ChainPosition::Unconfirmed { .. } => (txid, u32::MAX), } @@ -2121,16 +2142,13 @@ impl Wallet { .map(|wutxo| wutxo.utxo.outpoint()) .collect::>(); self.indexed_graph - .graph() - // Get all unspent UTxOs from wallet. - // NOTE: the UTxOs returned by the following method already belong to wallet as the - // call chain uses get_tx_node infallibly. - .filter_chain_unspents( + .canonical_view( &self.chain, self.chain.tip().block_id(), CanonicalizationParams::default(), - self.indexed_graph.index.outpoints().iter().cloned(), ) + // Get all unspent UTXOs from wallet. + .filter_unspent_outpoints(self.indexed_graph.index.outpoints().iter().cloned()) // Only create LocalOutput if UTxO is mature. .filter_map(move |((k, i), full_txo)| { full_txo @@ -2343,8 +2361,15 @@ impl Wallet { /// Usually you create an `update` by interacting with some blockchain data source and inserting /// transactions related to your wallet into it. /// - /// After applying updates you should persist the staged wallet changes. For an example of how - /// to persist staged wallet changes see [`Wallet::reveal_next_address`]. + /// After applying updates the [`canonical_view`](Self::canonical_view) of transactions is + /// updated to reflect changes to the transaction graph. + /// + /// You should persist the staged wallet changes. For an example of how to persist staged + /// wallet changes see [`Wallet::reveal_next_address`]. + /// + /// # Errors + /// + /// If the [`Update::chain`] update fails, a [`CannotConnectError`] will occur. pub fn apply_update(&mut self, update: impl Into) -> Result<(), CannotConnectError> { let update = update.into(); let mut changeset = match update.chain { @@ -2359,6 +2384,7 @@ impl Wallet { changeset.merge(index_changeset.into()); changeset.merge(self.indexed_graph.apply_update(update.tx_update).into()); self.stage.merge(changeset); + self.update_canonical_view(); Ok(()) } @@ -2519,17 +2545,7 @@ impl Wallet { /// [`apply_unconfirmed_txs`]: Wallet::apply_unconfirmed_txs /// [`start_sync_with_revealed_spks`]: Wallet::start_sync_with_revealed_spks pub fn apply_evicted_txs(&mut self, evicted_txs: impl IntoIterator) { - let chain = &self.chain; - let canon_txids: Vec = self - .indexed_graph - .graph() - .list_canonical_txs( - chain, - chain.tip().block_id(), - CanonicalizationParams::default(), - ) - .map(|c| c.tx_node.txid) - .collect(); + let canon_txids: Vec = self.canonical_view.txs().map(|c| c.txid).collect(); let changeset = self.indexed_graph.batch_insert_relevant_evicted_at( evicted_txs @@ -2567,11 +2583,10 @@ impl Wallet { SyncRequest::builder_at(start_time) .chain_tip(self.chain.tip()) .revealed_spks_from_indexer(&self.indexed_graph.index, ..) - .expected_spk_txids(self.indexed_graph.list_expected_spk_txids( - &self.chain, - self.chain.tip().block_id(), - .., - )) + .expected_spk_txids( + self.canonical_view + .list_expected_spk_txids(&self.indexed_graph.index, ..), + ) } /// Create a partial [`SyncRequest`] for this wallet for all revealed spks. @@ -2592,11 +2607,10 @@ impl Wallet { SyncRequest::builder() .chain_tip(self.chain.tip()) .revealed_spks_from_indexer(&self.indexed_graph.index, ..) - .expected_spk_txids(self.indexed_graph.list_expected_spk_txids( - &self.chain, - self.chain.tip().block_id(), - .., - )) + .expected_spk_txids( + self.canonical_view + .list_expected_spk_txids(&self.indexed_graph.index, ..), + ) } /// Create a [`FullScanRequest] for this wallet. diff --git a/src/wallet/tx_builder.rs b/src/wallet/tx_builder.rs index f3bfe3f90..9188ab5e5 100644 --- a/src/wallet/tx_builder.rs +++ b/src/wallet/tx_builder.rs @@ -1344,7 +1344,7 @@ mod test { assert_ne!(txid1, txid2); let utxo1 = wallet1.list_unspent().next().unwrap(); - let tx1 = wallet1.get_tx(txid1).unwrap().tx_node.tx.clone(); + let tx1 = wallet1.get_tx(txid1).unwrap().tx.clone(); let satisfaction_weight = wallet1 .public_descriptor(KeychainKind::External) diff --git a/tests/add_foreign_utxo.rs b/tests/add_foreign_utxo.rs index 1dd0a8c9d..a7feb6ba3 100644 --- a/tests/add_foreign_utxo.rs +++ b/tests/add_foreign_utxo.rs @@ -139,8 +139,8 @@ fn test_add_foreign_utxo_where_outpoint_doesnt_match_psbt_input() { get_funded_wallet_single("wpkh(cVbZ8ovhye9AoAHFsqobCf7LxbXDAECy9Kb8TZdfsDYMZGBUyCnm)"); let utxo2 = wallet2.list_unspent().next().unwrap(); - let tx1 = wallet1.get_tx(txid1).unwrap().tx_node.tx.clone(); - let tx2 = wallet2.get_tx(txid2).unwrap().tx_node.tx.clone(); + let tx1 = wallet1.get_tx(txid1).unwrap().tx.clone(); + let tx2 = wallet2.get_tx(txid2).unwrap().tx.clone(); let satisfaction_weight = wallet2 .public_descriptor(KeychainKind::External) @@ -230,7 +230,7 @@ fn test_add_foreign_utxo_only_witness_utxo() { let mut builder = wallet1.build_tx(); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(60_000)); - let tx2 = wallet2.get_tx(txid2).unwrap().tx_node.tx; + let tx2 = wallet2.get_tx(txid2).unwrap().tx; let psbt_input = psbt::Input { non_witness_utxo: Some(tx2.as_ref().clone()), ..Default::default() diff --git a/tests/build_fee_bump.rs b/tests/build_fee_bump.rs index 4a243dfad..4e700f66a 100644 --- a/tests/build_fee_bump.rs +++ b/tests/build_fee_bump.rs @@ -358,8 +358,7 @@ fn test_bump_fee_remove_output_manually_selected_only() { }], }; - let position: ChainPosition = - wallet.transactions().last().unwrap().chain_position; + let position: ChainPosition = wallet.transactions().last().unwrap().pos; insert_tx(&mut wallet, init_tx.clone()); match position { ChainPosition::Confirmed { anchor, .. } => { @@ -410,8 +409,7 @@ fn test_bump_fee_add_input() { }], }; let txid = init_tx.compute_txid(); - let pos: ChainPosition = - wallet.transactions().last().unwrap().chain_position; + let pos: ChainPosition = wallet.transactions().last().unwrap().pos; insert_tx(&mut wallet, init_tx); match pos { ChainPosition::Confirmed { anchor, .. } => insert_anchor(&mut wallet, txid, anchor), @@ -846,8 +844,7 @@ fn test_legacy_bump_fee_add_input() { }], }; let txid = init_tx.compute_txid(); - let pos: ChainPosition = - wallet.transactions().last().unwrap().chain_position; + let pos: ChainPosition = wallet.transactions().last().unwrap().pos; insert_tx(&mut wallet, init_tx); match pos { ChainPosition::Confirmed { anchor, .. } => insert_anchor(&mut wallet, txid, anchor), @@ -977,7 +974,7 @@ fn test_bump_fee_pay_to_anchor_foreign_utxo() { let tx = psbt.unsigned_tx.clone(); assert!(tx.input.iter().any(|txin| txin.previous_output == outpoint)); let txid1 = tx.compute_txid(); - wallet.apply_unconfirmed_txs([(tx, 123456)]); + insert_tx(&mut wallet, tx); // Now build fee bump. let mut tx_builder = wallet diff --git a/tests/persisted_wallet.rs b/tests/persisted_wallet.rs index 6814f187d..b236e2bee 100644 --- a/tests/persisted_wallet.rs +++ b/tests/persisted_wallet.rs @@ -365,10 +365,7 @@ fn wallet_should_persist_anchors_and_recover() { if let ChainPosition::Confirmed { anchor: obtained_anchor, .. - } = wallet - .get_tx(txid) - .expect("should retrieve stored tx") - .chain_position + } = wallet.get_tx(txid).expect("should retrieve stored tx").pos { assert_eq!(obtained_anchor, expected_anchor) } else { diff --git a/tests/wallet.rs b/tests/wallet.rs index c779c0a4e..dc6260e9f 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -2,7 +2,7 @@ use std::str::FromStr; use std::sync::Arc; use assert_matches::assert_matches; -use bdk_chain::{BlockId, CanonicalizationParams, ConfirmationBlockTime}; +use bdk_chain::{BlockId, ConfirmationBlockTime}; use bdk_wallet::coin_selection; use bdk_wallet::descriptor::{calc_checksum, DescriptorError}; use bdk_wallet::error::CreateTxError; @@ -84,11 +84,11 @@ fn test_get_funded_wallet_sent_and_received() { let mut tx_amounts: Vec<(Txid, (Amount, Amount))> = wallet .transactions() - .map(|ct| (ct.tx_node.txid, wallet.sent_and_received(&ct.tx_node))) + .map(|ct| (ct.txid, wallet.sent_and_received(&ct.tx))) .collect(); tx_amounts.sort_by(|a1, a2| a1.0.cmp(&a2.0)); - let tx = wallet.get_tx(txid).expect("transaction").tx_node.tx; + let tx = wallet.get_tx(txid).expect("transaction").tx; let (sent, received) = wallet.sent_and_received(&tx); // The funded wallet contains a tx with a 76_000 sats input and two outputs, one spending 25_000 @@ -102,7 +102,7 @@ fn test_get_funded_wallet_sent_and_received() { fn test_get_funded_wallet_tx_fees() { let (wallet, txid) = get_funded_wallet_wpkh(); - let tx = wallet.get_tx(txid).expect("transaction").tx_node.tx; + let tx = wallet.get_tx(txid).expect("transaction").tx; let tx_fee = wallet.calculate_fee(&tx).expect("transaction fee"); // The funded wallet contains a tx with a 76_000 sats input and two outputs, one spending 25_000 @@ -115,7 +115,7 @@ fn test_get_funded_wallet_tx_fees() { fn test_get_funded_wallet_tx_fee_rate() { let (wallet, txid) = get_funded_wallet_wpkh(); - let tx = wallet.get_tx(txid).expect("transaction").tx_node.tx; + let tx = wallet.get_tx(txid).expect("transaction").tx; let tx_fee_rate = wallet .calculate_fee_rate(&tx) .expect("transaction fee rate"); @@ -135,7 +135,7 @@ fn test_get_funded_wallet_tx_fee_rate() { fn test_legacy_get_funded_wallet_tx_fee_rate() { let (wallet, txid) = get_funded_wallet_single(get_test_pkh()); - let tx = wallet.get_tx(txid).expect("transaction").tx_node.tx; + let tx = wallet.get_tx(txid).expect("transaction").tx; let tx_fee_rate = wallet .calculate_fee_rate(&tx) .expect("transaction fee rate"); @@ -2139,8 +2139,7 @@ fn test_taproot_sign_using_non_witness_utxo() { let mut psbt = builder.finish().unwrap(); psbt.inputs[0].witness_utxo = None; - psbt.inputs[0].non_witness_utxo = - Some(wallet.get_tx(prev_txid).unwrap().tx_node.as_ref().clone()); + psbt.inputs[0].non_witness_utxo = wallet.get_tx(prev_txid).map(|c| c.tx.as_ref().clone()); assert!( psbt.inputs[0].non_witness_utxo.is_some(), "Previous tx should be present in the database" @@ -2878,11 +2877,10 @@ fn test_transactions_sort_by() { receive_output(&mut wallet, Amount::from_sat(25_000), ReceiveTo::Mempool(0)); // sort by chain position, unconfirmed then confirmed by descending block height - let sorted_txs: Vec = - wallet.transactions_sort_by(|t1, t2| t2.chain_position.cmp(&t1.chain_position)); + let sorted_txs: Vec = wallet.transactions_sort_by(|t1, t2| t2.pos.cmp(&t1.pos)); let conf_heights: Vec> = sorted_txs .iter() - .map(|tx| tx.chain_position.confirmation_height_upper_bound()) + .map(|tx| tx.pos.confirmation_height_upper_bound()) .collect(); assert_eq!([None, Some(2000), Some(1000)], conf_heights.as_slice()); } @@ -2898,15 +2896,7 @@ fn test_wallet_transactions_relevant() { let (mut test_wallet, _txid) = get_funded_wallet_wpkh(); let relevant_tx_count_before = test_wallet.transactions().count(); let full_tx_count_before = test_wallet.tx_graph().full_txs().count(); - let chain_tip = test_wallet.local_chain().tip().block_id(); - let canonical_tx_count_before = test_wallet - .tx_graph() - .list_canonical_txs( - test_wallet.local_chain(), - chain_tip, - CanonicalizationParams::default(), - ) - .count(); + let canonical_tx_count_before = test_wallet.canonical_view().txs().count(); // add not relevant transaction to test wallet let (other_external_desc, other_internal_desc) = get_test_tr_single_sig_xprv_and_change_desc(); @@ -2920,27 +2910,16 @@ fn test_wallet_transactions_relevant() { // verify transaction from other wallet was added but is not in relevant transactions list. let relevant_tx_count_after = test_wallet.transactions().count(); let full_tx_count_after = test_wallet.tx_graph().full_txs().count(); - let canonical_tx_count_after = test_wallet - .tx_graph() - .list_canonical_txs( - test_wallet.local_chain(), - chain_tip, - CanonicalizationParams::default(), - ) - .count(); + let canonical_tx_count_after = test_wallet.canonical_view().txs().count(); assert_eq!(relevant_tx_count_before, relevant_tx_count_after); assert!(!test_wallet .transactions() - .any(|wallet_tx| wallet_tx.tx_node.txid == other_txid)); + .any(|wallet_tx| wallet_tx.txid == other_txid)); assert!(test_wallet - .tx_graph() - .list_canonical_txs( - test_wallet.local_chain(), - chain_tip, - CanonicalizationParams::default() - ) - .any(|wallet_tx| wallet_tx.tx_node.txid == other_txid)); + .canonical_view() + .txs() + .any(|wallet_tx| wallet_tx.txid == other_txid)); assert!(full_tx_count_before < full_tx_count_after); assert!(canonical_tx_count_before < canonical_tx_count_after); }