bdk_wallet/wallet/
mod.rs

1// Bitcoin Dev Kit
2// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
3//
4// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
5//
6// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
7// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
8// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
9// You may not use this file except in accordance with one or both of these
10// licenses.
11
12//! Wallet
13//!
14//! This module defines the [`Wallet`].
15
16use alloc::{
17    boxed::Box,
18    string::{String, ToString},
19    sync::Arc,
20    vec::Vec,
21};
22use core::{cmp::Ordering, fmt, mem, ops::Deref};
23
24use bdk_chain::{
25    indexed_tx_graph,
26    indexer::keychain_txout::KeychainTxOutIndex,
27    local_chain::{ApplyHeaderError, CannotConnectError, CheckPoint, CheckPointIter, LocalChain},
28    spk_client::{
29        FullScanRequest, FullScanRequestBuilder, FullScanResponse, SyncRequest, SyncRequestBuilder,
30        SyncResponse,
31    },
32    tx_graph::{CalculateFeeError, CanonicalTx, TxGraph, TxUpdate},
33    BlockId, CanonicalizationParams, ChainPosition, ConfirmationBlockTime, DescriptorExt,
34    FullTxOut, Indexed, IndexedTxGraph, Indexer, Merge,
35};
36use bitcoin::{
37    absolute,
38    consensus::encode::serialize,
39    constants::genesis_block,
40    psbt,
41    secp256k1::Secp256k1,
42    sighash::{EcdsaSighashType, TapSighashType},
43    transaction, Address, Amount, Block, BlockHash, FeeRate, Network, OutPoint, Psbt, ScriptBuf,
44    Sequence, SignedAmount, Transaction, TxOut, Txid, Weight, Witness,
45};
46use miniscript::{
47    descriptor::KeyMap,
48    psbt::{PsbtExt, PsbtInputExt, PsbtInputSatisfier},
49};
50use rand_core::RngCore;
51
52mod changeset;
53pub mod coin_selection;
54pub mod error;
55pub mod event;
56pub mod export;
57mod params;
58mod persisted;
59#[deprecated(
60    since = "2.2.0",
61    note = "PSBT signing was moved to `bitcoin::psbt` module"
62)]
63pub mod signer;
64pub mod tx_builder;
65pub(crate) mod utils;
66
67use crate::collections::{BTreeMap, HashMap, HashSet};
68use crate::descriptor::{
69    check_wallet_descriptor, error::Error as DescriptorError, policy::BuildSatisfaction,
70    DerivedDescriptor, DescriptorMeta, ExtendedDescriptor, ExtractPolicy, IntoWalletDescriptor,
71    Policy, XKeyUtils,
72};
73use crate::psbt::PsbtUtils;
74use crate::types::*;
75use crate::wallet::{
76    coin_selection::{DefaultCoinSelectionAlgorithm, Excess, InsufficientFunds},
77    error::{BuildFeeBumpError, CreateTxError, MiniscriptPsbtError},
78    signer::{SignOptions, SignerError, SignerOrdering, SignersContainer, TransactionSigner},
79    tx_builder::{FeePolicy, TxBuilder, TxParams},
80    utils::{check_nsequence_rbf, After, Older, SecpCtx},
81};
82
83// re-exports
84use crate::event::{wallet_events, WalletEvent};
85pub use bdk_chain::Balance;
86pub use changeset::ChangeSet;
87pub use params::*;
88pub use persisted::*;
89pub use utils::IsDust;
90pub use utils::TxDetails;
91
92/// A Bitcoin wallet
93///
94/// The `Wallet` acts as a way of coherently interfacing with output descriptors and related
95/// transactions. Its main components are:
96///
97/// 1. output *descriptors* from which it can derive addresses.
98/// 2. [`signer`]s that can contribute signatures to addresses instantiated from the descriptors.
99///
100/// The user is responsible for loading and writing wallet changes which are represented as
101/// [`ChangeSet`]s (see [`take_staged`]). Also see individual functions and example for instructions
102/// on when [`Wallet`] state needs to be persisted.
103///
104/// The `Wallet` descriptor (external) and change descriptor (internal) must not derive the same
105/// script pubkeys. See [`KeychainTxOutIndex::insert_descriptor()`] for more details.
106///
107/// [`signer`]: crate::signer
108/// [`take_staged`]: Wallet::take_staged
109#[derive(Debug)]
110pub struct Wallet {
111    signers: Arc<SignersContainer>,
112    change_signers: Arc<SignersContainer>,
113    chain: LocalChain,
114    indexed_graph: IndexedTxGraph<ConfirmationBlockTime, KeychainTxOutIndex<KeychainKind>>,
115    stage: ChangeSet,
116    network: Network,
117    secp: SecpCtx,
118}
119
120/// An update to [`Wallet`].
121///
122/// It updates [`KeychainTxOutIndex`], [`bdk_chain::TxGraph`] and [`LocalChain`] atomically.
123#[derive(Debug, Clone, Default)]
124pub struct Update {
125    /// Contains the last active derivation indices per keychain (`K`), which is used to update the
126    /// [`KeychainTxOutIndex`].
127    pub last_active_indices: BTreeMap<KeychainKind, u32>,
128
129    /// Update for the wallet's internal [`TxGraph`].
130    pub tx_update: TxUpdate<ConfirmationBlockTime>,
131
132    /// Update for the wallet's internal [`LocalChain`].
133    pub chain: Option<CheckPoint>,
134}
135
136impl From<FullScanResponse<KeychainKind>> for Update {
137    fn from(value: FullScanResponse<KeychainKind>) -> Self {
138        Self {
139            last_active_indices: value.last_active_indices,
140            tx_update: value.tx_update,
141            chain: value.chain_update,
142        }
143    }
144}
145
146impl From<SyncResponse> for Update {
147    fn from(value: SyncResponse) -> Self {
148        Self {
149            last_active_indices: BTreeMap::new(),
150            tx_update: value.tx_update,
151            chain: value.chain_update,
152        }
153    }
154}
155
156/// A derived address and the index it was found at.
157/// For convenience this automatically derefs to `Address`
158#[derive(Debug, Clone, PartialEq, Eq)]
159pub struct AddressInfo {
160    /// Child index of this address
161    pub index: u32,
162    /// Address
163    pub address: Address,
164    /// Type of keychain
165    pub keychain: KeychainKind,
166}
167
168impl Deref for AddressInfo {
169    type Target = Address;
170
171    fn deref(&self) -> &Self::Target {
172        &self.address
173    }
174}
175
176impl fmt::Display for AddressInfo {
177    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178        write!(f, "{}", self.address)
179    }
180}
181
182/// The error type when loading a [`Wallet`] from a [`ChangeSet`].
183#[derive(Debug, PartialEq)]
184pub enum LoadError {
185    /// There was a problem with the passed-in descriptor(s).
186    Descriptor(crate::descriptor::DescriptorError),
187    /// Data loaded from persistence is missing network type.
188    MissingNetwork,
189    /// Data loaded from persistence is missing genesis hash.
190    MissingGenesis,
191    /// Data loaded from persistence is missing descriptor.
192    MissingDescriptor(KeychainKind),
193    /// Data loaded is unexpected.
194    Mismatch(LoadMismatch),
195}
196
197impl fmt::Display for LoadError {
198    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199        match self {
200            LoadError::Descriptor(e) => e.fmt(f),
201            LoadError::MissingNetwork => write!(f, "loaded data is missing network type"),
202            LoadError::MissingGenesis => write!(f, "loaded data is missing genesis hash"),
203            LoadError::MissingDescriptor(k) => {
204                write!(f, "loaded data is missing descriptor for {k} keychain")
205            }
206            LoadError::Mismatch(e) => write!(f, "{e}"),
207        }
208    }
209}
210
211#[cfg(feature = "std")]
212impl std::error::Error for LoadError {}
213
214/// Represents a mismatch with what is loaded and what is expected from [`LoadParams`].
215#[derive(Debug, PartialEq)]
216pub enum LoadMismatch {
217    /// Network does not match.
218    Network {
219        /// The network that is loaded.
220        loaded: Network,
221        /// The expected network.
222        expected: Network,
223    },
224    /// Genesis hash does not match.
225    Genesis {
226        /// The genesis hash that is loaded.
227        loaded: BlockHash,
228        /// The expected genesis hash.
229        expected: BlockHash,
230    },
231    /// Descriptor's [`DescriptorId`](bdk_chain::DescriptorId) does not match.
232    Descriptor {
233        /// Keychain identifying the descriptor.
234        keychain: KeychainKind,
235        /// The loaded descriptor.
236        loaded: Option<ExtendedDescriptor>,
237        /// The expected descriptor.
238        expected: Option<ExtendedDescriptor>,
239    },
240}
241
242impl fmt::Display for LoadMismatch {
243    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244        match self {
245            LoadMismatch::Network { loaded, expected } => {
246                write!(f, "Network mismatch: loaded {loaded}, expected {expected}")
247            }
248            LoadMismatch::Genesis { loaded, expected } => {
249                write!(
250                    f,
251                    "Genesis hash mismatch: loaded {loaded}, expected {expected}"
252                )
253            }
254            LoadMismatch::Descriptor {
255                keychain,
256                loaded,
257                expected,
258            } => {
259                write!(
260                    f,
261                    "Descriptor mismatch for {} keychain: loaded {}, expected {}",
262                    keychain,
263                    loaded
264                        .as_ref()
265                        .map_or("None".to_string(), |d| d.to_string()),
266                    expected
267                        .as_ref()
268                        .map_or("None".to_string(), |d| d.to_string())
269                )
270            }
271        }
272    }
273}
274
275impl From<LoadMismatch> for LoadError {
276    fn from(mismatch: LoadMismatch) -> Self {
277        Self::Mismatch(mismatch)
278    }
279}
280
281impl<E> From<LoadMismatch> for LoadWithPersistError<E> {
282    fn from(mismatch: LoadMismatch) -> Self {
283        Self::InvalidChangeSet(LoadError::Mismatch(mismatch))
284    }
285}
286
287/// An error that may occur when applying a block to [`Wallet`].
288#[derive(Debug)]
289pub enum ApplyBlockError {
290    /// Occurs when the update chain cannot connect with original chain.
291    CannotConnect(CannotConnectError),
292    /// Occurs when the `connected_to` hash does not match the hash derived from `block`.
293    UnexpectedConnectedToHash {
294        /// Block hash of `connected_to`.
295        connected_to_hash: BlockHash,
296        /// Expected block hash of `connected_to`, as derived from `block`.
297        expected_hash: BlockHash,
298    },
299}
300
301impl fmt::Display for ApplyBlockError {
302    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303        match self {
304            ApplyBlockError::CannotConnect(err) => err.fmt(f),
305            ApplyBlockError::UnexpectedConnectedToHash {
306                expected_hash: block_hash,
307                connected_to_hash: checkpoint_hash,
308            } => write!(
309                f,
310                "`connected_to` hash {checkpoint_hash} differs from the expected hash {block_hash} (which is derived from `block`)"
311            ),
312        }
313    }
314}
315
316#[cfg(feature = "std")]
317impl std::error::Error for ApplyBlockError {}
318
319/// A `CanonicalTx` managed by a `Wallet`.
320pub type WalletTx<'a> = CanonicalTx<'a, Arc<Transaction>, ConfirmationBlockTime>;
321
322impl Wallet {
323    /// Build a new single descriptor [`Wallet`].
324    ///
325    /// If you have previously created a wallet, use [`load`](Self::load) instead.
326    ///
327    /// # Note
328    ///
329    /// Only use this method when creating a wallet designed to be used with a single
330    /// descriptor and keychain. Otherwise the recommended way to construct a new wallet is
331    /// by using [`Wallet::create`]. It's worth noting that not all features are available
332    /// with single descriptor wallets, for example setting a [`change_policy`] on [`TxBuilder`]
333    /// and related methods such as [`do_not_spend_change`]. This is because all payments are
334    /// received on the external keychain (including change), and without a change keychain
335    /// BDK lacks enough information to distinguish between change and outside payments.
336    ///
337    /// Additionally because this wallet has no internal (change) keychain, all methods that
338    /// require a [`KeychainKind`] as input, e.g. [`reveal_next_address`] should only be called
339    /// using the [`External`] variant. In most cases passing [`Internal`] is treated as the
340    /// equivalent of [`External`] but this behavior must not be relied on.
341    ///
342    /// # Example
343    ///
344    /// ```rust
345    /// # use bdk_wallet::Wallet;
346    /// # use bitcoin::Network;
347    /// # const EXTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
348    /// # let temp_dir = tempfile::tempdir().expect("must create tempdir");
349    /// # let file_path = temp_dir.path().join("store.db");
350    /// // Create a wallet that is persisted to SQLite database.
351    /// use bdk_wallet::rusqlite::Connection;
352    /// let mut conn = Connection::open(file_path)?;
353    /// let wallet = Wallet::create_single(EXTERNAL_DESC)
354    ///     .network(Network::Testnet)
355    ///     .create_wallet(&mut conn)?;
356    /// # Ok::<_, anyhow::Error>(())
357    /// ```
358    /// [`change_policy`]: TxBuilder::change_policy
359    /// [`do_not_spend_change`]: TxBuilder::do_not_spend_change
360    /// [`External`]: KeychainKind::External
361    /// [`Internal`]: KeychainKind::Internal
362    /// [`reveal_next_address`]: Self::reveal_next_address
363    pub fn create_single<D>(descriptor: D) -> CreateParams
364    where
365        D: IntoWalletDescriptor + Send + Clone + 'static,
366    {
367        CreateParams::new_single(descriptor)
368    }
369
370    /// Build a new [`Wallet`].
371    ///
372    /// If you have previously created a wallet, use [`load`](Self::load) instead.
373    ///
374    /// # Synopsis
375    ///
376    /// ```rust
377    /// # use bdk_wallet::Wallet;
378    /// # use bitcoin::Network;
379    /// # fn main() -> anyhow::Result<()> {
380    /// # const EXTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
381    /// # const INTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
382    /// // Create a non-persisted wallet.
383    /// let wallet = Wallet::create(EXTERNAL_DESC, INTERNAL_DESC)
384    ///     .network(Network::Testnet)
385    ///     .create_wallet_no_persist()?;
386    ///
387    /// // Create a wallet that is persisted to SQLite database.
388    /// # let temp_dir = tempfile::tempdir().expect("must create tempdir");
389    /// # let file_path = temp_dir.path().join("store.db");
390    /// use bdk_wallet::rusqlite::Connection;
391    /// let mut conn = Connection::open(file_path)?;
392    /// let wallet = Wallet::create(EXTERNAL_DESC, INTERNAL_DESC)
393    ///     .network(Network::Testnet)
394    ///     .create_wallet(&mut conn)?;
395    /// # Ok(())
396    /// # }
397    /// ```
398    pub fn create<D>(descriptor: D, change_descriptor: D) -> CreateParams
399    where
400        D: IntoWalletDescriptor + Send + Clone + 'static,
401    {
402        CreateParams::new(descriptor, change_descriptor)
403    }
404
405    /// Build a new [`Wallet`] from a two-path descriptor.
406    ///
407    /// This function parses a multipath descriptor with exactly 2 paths and creates a wallet
408    /// using the existing receive and change wallet creation logic. Note that you can only use this
409    /// method with public extended keys (`xpub` prefix) to create watch-only wallets.
410    ///
411    /// Multipath descriptors follow [BIP 389] and allow defining both receive and change
412    /// derivation paths in a single descriptor using the `<0;1>` syntax.
413    ///
414    /// If you have previously created a wallet, use [`load`](Self::load) instead.
415    ///
416    /// # Errors
417    /// Returns an error if the descriptor is invalid, not a 2-path multipath descriptor, or if
418    /// the descriptor provided contains an extended private key (`xprv` prefix).
419    ///
420    /// # Synopsis
421    ///
422    /// ```rust
423    /// # use bdk_wallet::Wallet;
424    /// # use bitcoin::Network;
425    /// # use bdk_wallet::KeychainKind;
426    /// # const TWO_PATH_DESC: &str = "wpkh([9a6a2580/84'/1'/0']tpubDDnGNapGEY6AZAdQbfRJgMg9fvz8pUBrLwvyvUqEgcUfgzM6zc2eVK4vY9x9L5FJWdX8WumXuLEDV5zDZnTfbn87vLe9XceCFwTu9so9Kks/<0;1>/*)";
427    /// let wallet = Wallet::create_from_two_path_descriptor(TWO_PATH_DESC)
428    ///     .network(Network::Testnet)
429    ///     .create_wallet_no_persist()
430    ///     .unwrap();
431    ///
432    /// // The multipath descriptor automatically creates separate receive and change descriptors
433    /// let receive_addr = wallet.peek_address(KeychainKind::External, 0);  // Uses path /0/*
434    /// let change_addr = wallet.peek_address(KeychainKind::Internal, 0);   // Uses path /1/*
435    /// assert_ne!(receive_addr.address, change_addr.address);
436    /// ```
437    ///
438    /// [BIP 389]: https://github.com/bitcoin/bips/blob/master/bip-0389.mediawiki
439    pub fn create_from_two_path_descriptor<D>(two_path_descriptor: D) -> CreateParams
440    where
441        D: IntoWalletDescriptor + Send + Clone + 'static,
442    {
443        CreateParams::new_two_path(two_path_descriptor)
444    }
445
446    /// Create a new [`Wallet`] with given `params`.
447    ///
448    /// Refer to [`Wallet::create`] for more.
449    pub fn create_with_params(params: CreateParams) -> Result<Self, DescriptorError> {
450        let secp = SecpCtx::new();
451        let network = params.network;
452        let genesis_hash = params
453            .genesis_hash
454            .unwrap_or(genesis_block(network).block_hash());
455        let (chain, chain_changeset) = LocalChain::from_genesis_hash(genesis_hash);
456
457        let (descriptor, mut descriptor_keymap) = (params.descriptor)(&secp, network)?;
458        check_wallet_descriptor(&descriptor)?;
459        descriptor_keymap.extend(params.descriptor_keymap);
460
461        let signers = Arc::new(SignersContainer::build(
462            descriptor_keymap,
463            &descriptor,
464            &secp,
465        ));
466
467        let (change_descriptor, change_signers) = match params.change_descriptor {
468            Some(make_desc) => {
469                let (change_descriptor, mut internal_keymap) = make_desc(&secp, network)?;
470                check_wallet_descriptor(&change_descriptor)?;
471                internal_keymap.extend(params.change_descriptor_keymap);
472                let change_signers = Arc::new(SignersContainer::build(
473                    internal_keymap,
474                    &change_descriptor,
475                    &secp,
476                ));
477                (Some(change_descriptor), change_signers)
478            }
479            None => (None, Arc::new(SignersContainer::new())),
480        };
481
482        let mut stage = ChangeSet {
483            descriptor: Some(descriptor.clone()),
484            change_descriptor: change_descriptor.clone(),
485            local_chain: chain_changeset,
486            network: Some(network),
487            ..Default::default()
488        };
489
490        let indexed_graph = make_indexed_graph(
491            &mut stage,
492            Default::default(),
493            Default::default(),
494            descriptor,
495            change_descriptor,
496            params.lookahead,
497            params.use_spk_cache,
498        )?;
499
500        Ok(Wallet {
501            signers,
502            change_signers,
503            network,
504            chain,
505            indexed_graph,
506            stage,
507            secp,
508        })
509    }
510
511    /// Build [`Wallet`] by loading from persistence or [`ChangeSet`].
512    ///
513    /// Note that the descriptor secret keys are not persisted to the db. You can add
514    /// signers after-the-fact with [`Wallet::add_signer`] or [`Wallet::set_keymap`]. You
515    /// can also add keys when building the wallet by using [`LoadParams::keymap`]. Finally
516    /// you can check the wallet's descriptors are what you expect with [`LoadParams::descriptor`]
517    /// which will try to populate signers if [`LoadParams::extract_keys`] is enabled.
518    ///
519    /// # Synopsis
520    ///
521    /// ```rust,no_run
522    /// # use bdk_wallet::{Wallet, ChangeSet, KeychainKind};
523    /// # use bitcoin::{BlockHash, Network, hashes::Hash};
524    /// # fn main() -> anyhow::Result<()> {
525    /// # const EXTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
526    /// # const INTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
527    /// # let changeset = ChangeSet::default();
528    /// // Load a wallet from changeset (no persistence).
529    /// let wallet = Wallet::load()
530    ///     .load_wallet_no_persist(changeset)?
531    ///     .expect("must have data to load wallet");
532    ///
533    /// // Load a wallet that is persisted to SQLite database.
534    /// # let temp_dir = tempfile::tempdir().expect("must create tempdir");
535    /// # let file_path = temp_dir.path().join("store.db");
536    /// # let external_keymap = Default::default();
537    /// # let internal_keymap = Default::default();
538    /// # let genesis_hash = BlockHash::all_zeros();
539    /// let mut conn = bdk_wallet::rusqlite::Connection::open(file_path)?;
540    /// let mut wallet = Wallet::load()
541    ///     // check loaded descriptors matches these values and extract private keys
542    ///     .descriptor(KeychainKind::External, Some(EXTERNAL_DESC))
543    ///     .descriptor(KeychainKind::Internal, Some(INTERNAL_DESC))
544    ///     .extract_keys()
545    ///     // you can also manually add private keys
546    ///     .keymap(KeychainKind::External, external_keymap)
547    ///     .keymap(KeychainKind::Internal, internal_keymap)
548    ///     // ensure loaded wallet's genesis hash matches this value
549    ///     .check_genesis_hash(genesis_hash)
550    ///     // set a lookahead for our indexer
551    ///     .lookahead(101)
552    ///     .load_wallet(&mut conn)?
553    ///     .expect("must have data to load wallet");
554    /// # Ok(())
555    /// # }
556    /// ```
557    pub fn load() -> LoadParams {
558        LoadParams::new()
559    }
560
561    /// Load [`Wallet`] from the given previously persisted [`ChangeSet`] and `params`.
562    ///
563    /// Returns `Ok(None)` if the changeset is empty. Refer to [`Wallet::load`] for more.
564    pub fn load_with_params(
565        changeset: ChangeSet,
566        params: LoadParams,
567    ) -> Result<Option<Self>, LoadError> {
568        if changeset.is_empty() {
569            return Ok(None);
570        }
571        let secp = Secp256k1::new();
572        let network = changeset.network.ok_or(LoadError::MissingNetwork)?;
573        let chain = LocalChain::from_changeset(changeset.local_chain)
574            .map_err(|_| LoadError::MissingGenesis)?;
575
576        if let Some(exp_network) = params.check_network {
577            if network != exp_network {
578                return Err(LoadError::Mismatch(LoadMismatch::Network {
579                    loaded: network,
580                    expected: exp_network,
581                }));
582            }
583        }
584        if let Some(exp_genesis_hash) = params.check_genesis_hash {
585            if chain.genesis_hash() != exp_genesis_hash {
586                return Err(LoadError::Mismatch(LoadMismatch::Genesis {
587                    loaded: chain.genesis_hash(),
588                    expected: exp_genesis_hash,
589                }));
590            }
591        }
592
593        let descriptor = changeset
594            .descriptor
595            .ok_or(LoadError::MissingDescriptor(KeychainKind::External))?;
596        check_wallet_descriptor(&descriptor).map_err(LoadError::Descriptor)?;
597        let mut external_keymap = params.descriptor_keymap;
598
599        if let Some(expected) = params.check_descriptor {
600            if let Some(make_desc) = expected {
601                let (exp_desc, keymap) =
602                    make_desc(&secp, network).map_err(LoadError::Descriptor)?;
603                if descriptor.descriptor_id() != exp_desc.descriptor_id() {
604                    return Err(LoadError::Mismatch(LoadMismatch::Descriptor {
605                        keychain: KeychainKind::External,
606                        loaded: Some(descriptor),
607                        expected: Some(exp_desc),
608                    }));
609                }
610                if params.extract_keys {
611                    external_keymap.extend(keymap);
612                }
613            } else {
614                return Err(LoadError::Mismatch(LoadMismatch::Descriptor {
615                    keychain: KeychainKind::External,
616                    loaded: Some(descriptor),
617                    expected: None,
618                }));
619            }
620        }
621        let signers = Arc::new(SignersContainer::build(external_keymap, &descriptor, &secp));
622
623        let mut change_descriptor = None;
624        let mut internal_keymap = params.change_descriptor_keymap;
625
626        match (changeset.change_descriptor, params.check_change_descriptor) {
627            // empty signer
628            (None, None) => {}
629            (None, Some(expect)) => {
630                // expected desc but none loaded
631                if let Some(make_desc) = expect {
632                    let (exp_desc, _) = make_desc(&secp, network).map_err(LoadError::Descriptor)?;
633                    return Err(LoadError::Mismatch(LoadMismatch::Descriptor {
634                        keychain: KeychainKind::Internal,
635                        loaded: None,
636                        expected: Some(exp_desc),
637                    }));
638                }
639            }
640            // nothing expected
641            (Some(desc), None) => {
642                check_wallet_descriptor(&desc).map_err(LoadError::Descriptor)?;
643                change_descriptor = Some(desc);
644            }
645            (Some(desc), Some(expect)) => match expect {
646                // expected none for existing
647                None => {
648                    return Err(LoadError::Mismatch(LoadMismatch::Descriptor {
649                        keychain: KeychainKind::Internal,
650                        loaded: Some(desc),
651                        expected: None,
652                    }))
653                }
654                // parameters must match
655                Some(make_desc) => {
656                    check_wallet_descriptor(&desc).map_err(LoadError::Descriptor)?;
657                    let (exp_desc, keymap) =
658                        make_desc(&secp, network).map_err(LoadError::Descriptor)?;
659                    if desc.descriptor_id() != exp_desc.descriptor_id() {
660                        return Err(LoadError::Mismatch(LoadMismatch::Descriptor {
661                            keychain: KeychainKind::Internal,
662                            loaded: Some(desc),
663                            expected: Some(exp_desc),
664                        }));
665                    }
666                    if params.extract_keys {
667                        internal_keymap.extend(keymap);
668                    }
669                    change_descriptor = Some(desc);
670                }
671            },
672        }
673
674        let change_signers = match change_descriptor {
675            Some(ref change_descriptor) => Arc::new(SignersContainer::build(
676                internal_keymap,
677                change_descriptor,
678                &secp,
679            )),
680            None => Arc::new(SignersContainer::new()),
681        };
682
683        let mut stage = ChangeSet::default();
684
685        let indexed_graph = make_indexed_graph(
686            &mut stage,
687            changeset.tx_graph,
688            changeset.indexer,
689            descriptor,
690            change_descriptor,
691            params.lookahead,
692            params.use_spk_cache,
693        )
694        .map_err(LoadError::Descriptor)?;
695
696        Ok(Some(Wallet {
697            signers,
698            change_signers,
699            chain,
700            indexed_graph,
701            stage,
702            network,
703            secp,
704        }))
705    }
706
707    /// Get the Bitcoin network the wallet is using.
708    pub fn network(&self) -> Network {
709        self.network
710    }
711
712    /// Iterator over all keychains in this wallet
713    pub fn keychains(&self) -> impl Iterator<Item = (KeychainKind, &ExtendedDescriptor)> {
714        self.indexed_graph.index.keychains()
715    }
716
717    /// Peek an address of the given `keychain` at `index` without revealing it.
718    ///
719    /// For non-wildcard descriptors this returns the same address at every provided index.
720    ///
721    /// # Panics
722    ///
723    /// This panics when the caller requests for an address of derivation index greater than the
724    /// [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) max index.
725    pub fn peek_address(&self, keychain: KeychainKind, mut index: u32) -> AddressInfo {
726        let keychain = self.map_keychain(keychain);
727        let mut spk_iter = self
728            .indexed_graph
729            .index
730            .unbounded_spk_iter(keychain)
731            .expect("keychain must exist");
732        if !spk_iter.descriptor().has_wildcard() {
733            index = 0;
734        }
735        let (index, spk) = spk_iter
736            .nth(index as usize)
737            .expect("derivation index is out of bounds");
738
739        AddressInfo {
740            index,
741            address: Address::from_script(&spk, self.network).expect("must have address form"),
742            keychain,
743        }
744    }
745
746    /// Attempt to reveal the next address of the given `keychain`.
747    ///
748    /// This will increment the keychain's derivation index. If the keychain's descriptor doesn't
749    /// contain a wildcard or every address is already revealed up to the maximum derivation
750    /// index defined in [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki),
751    /// then the last revealed address will be returned.
752    ///
753    /// **WARNING**: To avoid address reuse you must persist the changes resulting from one or more
754    /// calls to this method before closing the wallet. For example:
755    ///
756    /// ```rust,no_run
757    /// # use bdk_wallet::{LoadParams, ChangeSet, KeychainKind};
758    /// use bdk_chain::rusqlite::Connection;
759    /// let mut conn = Connection::open_in_memory().expect("must open connection");
760    /// let mut wallet = LoadParams::new()
761    ///     .load_wallet(&mut conn)
762    ///     .expect("database is okay")
763    ///     .expect("database has data");
764    /// let next_address = wallet.reveal_next_address(KeychainKind::External);
765    /// wallet.persist(&mut conn).expect("write is okay");
766    ///
767    /// // Now it's safe to show the user their next address!
768    /// println!("Next address: {}", next_address.address);
769    /// # Ok::<(), anyhow::Error>(())
770    /// ```
771    pub fn reveal_next_address(&mut self, keychain: KeychainKind) -> AddressInfo {
772        let keychain = self.map_keychain(keychain);
773        let index = &mut self.indexed_graph.index;
774        let stage = &mut self.stage;
775
776        let ((index, spk), index_changeset) = index
777            .reveal_next_spk(keychain)
778            .expect("keychain must exist");
779
780        stage.merge(index_changeset.into());
781
782        AddressInfo {
783            index,
784            address: Address::from_script(spk.as_script(), self.network)
785                .expect("must have address form"),
786            keychain,
787        }
788    }
789
790    /// Reveal addresses up to and including the target `index` and return an iterator
791    /// of newly revealed addresses.
792    ///
793    /// If the target `index` is unreachable, we make a best effort to reveal up to the last
794    /// possible index. If all addresses up to the given `index` are already revealed, then
795    /// no new addresses are returned.
796    ///
797    /// **WARNING**: To avoid address reuse you must persist the changes resulting from one or more
798    /// calls to this method before closing the wallet. See [`Wallet::reveal_next_address`].
799    pub fn reveal_addresses_to(
800        &mut self,
801        keychain: KeychainKind,
802        index: u32,
803    ) -> impl Iterator<Item = AddressInfo> + '_ {
804        let keychain = self.map_keychain(keychain);
805        let (spks, index_changeset) = self
806            .indexed_graph
807            .index
808            .reveal_to_target(keychain, index)
809            .expect("keychain must exist");
810
811        self.stage.merge(index_changeset.into());
812
813        spks.into_iter().map(move |(index, spk)| AddressInfo {
814            index,
815            address: Address::from_script(&spk, self.network).expect("must have address form"),
816            keychain,
817        })
818    }
819
820    /// Get the next unused address for the given `keychain`, i.e. the address with the lowest
821    /// derivation index that hasn't been used in a transaction.
822    ///
823    /// This will attempt to reveal a new address if all previously revealed addresses have
824    /// been used, in which case the returned address will be the same as calling
825    /// [`Wallet::reveal_next_address`].
826    ///
827    /// **WARNING**: To avoid address reuse you must persist the changes resulting from one or more
828    /// calls to this method before closing the wallet. See [`Wallet::reveal_next_address`].
829    pub fn next_unused_address(&mut self, keychain: KeychainKind) -> AddressInfo {
830        let keychain = self.map_keychain(keychain);
831        let index = &mut self.indexed_graph.index;
832
833        let ((index, spk), index_changeset) = index
834            .next_unused_spk(keychain)
835            .expect("keychain must exist");
836
837        self.stage
838            .merge(indexed_tx_graph::ChangeSet::from(index_changeset).into());
839
840        AddressInfo {
841            index,
842            address: Address::from_script(spk.as_script(), self.network)
843                .expect("must have address form"),
844            keychain,
845        }
846    }
847
848    /// Marks an address used of the given `keychain` at `index`.
849    ///
850    /// Returns whether the given index was present and then removed from the unused set.
851    pub fn mark_used(&mut self, keychain: KeychainKind, index: u32) -> bool {
852        self.indexed_graph.index.mark_used(keychain, index)
853    }
854
855    /// Undoes the effect of [`mark_used`] and returns whether the `index` was inserted
856    /// back into the unused set.
857    ///
858    /// Since this is only a superficial marker, it will have no effect if the address at the given
859    /// `index` was actually used, i.e. the wallet has previously indexed a tx output for the
860    /// derived spk.
861    ///
862    /// [`mark_used`]: Self::mark_used
863    pub fn unmark_used(&mut self, keychain: KeychainKind, index: u32) -> bool {
864        self.indexed_graph.index.unmark_used(keychain, index)
865    }
866
867    /// List addresses that are revealed but unused.
868    ///
869    /// Note if the returned iterator is empty you can reveal more addresses
870    /// by using [`reveal_next_address`](Self::reveal_next_address) or
871    /// [`reveal_addresses_to`](Self::reveal_addresses_to).
872    pub fn list_unused_addresses(
873        &self,
874        keychain: KeychainKind,
875    ) -> impl DoubleEndedIterator<Item = AddressInfo> + '_ {
876        self.indexed_graph
877            .index
878            .unused_keychain_spks(self.map_keychain(keychain))
879            .map(move |(index, spk)| AddressInfo {
880                index,
881                address: Address::from_script(spk.as_script(), self.network)
882                    .expect("must have address form"),
883                keychain,
884            })
885    }
886
887    /// Return whether or not a `script` is part of this wallet (either internal or external)
888    pub fn is_mine(&self, script: ScriptBuf) -> bool {
889        self.indexed_graph.index.index_of_spk(script).is_some()
890    }
891
892    /// Finds how the wallet derived the script pubkey `spk`.
893    ///
894    /// Will only return `Some(_)` if the wallet has given out the spk.
895    pub fn derivation_of_spk(&self, spk: ScriptBuf) -> Option<(KeychainKind, u32)> {
896        self.indexed_graph.index.index_of_spk(spk).cloned()
897    }
898
899    /// Return the list of unspent outputs of this wallet
900    pub fn list_unspent(&self) -> impl Iterator<Item = LocalOutput> + '_ {
901        self.indexed_graph
902            .graph()
903            .filter_chain_unspents(
904                &self.chain,
905                self.chain.tip().block_id(),
906                CanonicalizationParams::default(),
907                self.indexed_graph.index.outpoints().iter().cloned(),
908            )
909            .map(|((k, i), full_txo)| new_local_utxo(k, i, full_txo))
910    }
911
912    /// Get the [`TxDetails`] of a wallet transaction.
913    ///
914    /// If the transaction with txid [`Txid`] cannot be found in the wallet's transactions, `None`
915    /// is returned.
916    pub fn tx_details(&self, txid: Txid) -> Option<TxDetails> {
917        let tx: WalletTx = self.transactions().find(|c| c.tx_node.txid == txid)?;
918
919        let (sent, received) = self.sent_and_received(&tx.tx_node.tx);
920        let fee: Option<Amount> = self.calculate_fee(&tx.tx_node.tx).ok();
921        let fee_rate: Option<FeeRate> = self.calculate_fee_rate(&tx.tx_node.tx).ok();
922        let balance_delta: SignedAmount = self.indexed_graph.index.net_value(&tx.tx_node.tx, ..);
923        let chain_position = tx.chain_position;
924
925        let tx_details: TxDetails = TxDetails {
926            txid,
927            received,
928            sent,
929            fee,
930            fee_rate,
931            balance_delta,
932            chain_position,
933            tx: tx.tx_node.tx,
934        };
935
936        Some(tx_details)
937    }
938
939    /// List all relevant outputs (includes both spent and unspent, confirmed and unconfirmed).
940    ///
941    /// To list only unspent outputs (UTXOs), use [`Wallet::list_unspent`] instead.
942    pub fn list_output(&self) -> impl Iterator<Item = LocalOutput> + '_ {
943        self.indexed_graph
944            .graph()
945            .filter_chain_txouts(
946                &self.chain,
947                self.chain.tip().block_id(),
948                CanonicalizationParams::default(),
949                self.indexed_graph.index.outpoints().iter().cloned(),
950            )
951            .map(|((k, i), full_txo)| new_local_utxo(k, i, full_txo))
952    }
953
954    /// Get all the checkpoints the wallet is currently storing indexed by height.
955    pub fn checkpoints(&self) -> CheckPointIter {
956        self.chain.iter_checkpoints()
957    }
958
959    /// Returns the latest checkpoint.
960    pub fn latest_checkpoint(&self) -> CheckPoint {
961        self.chain.tip()
962    }
963
964    /// Get unbounded script pubkey iterators for both `Internal` and `External` keychains.
965    ///
966    /// This is intended to be used when doing a full scan of your addresses (e.g. after restoring
967    /// from seed words). You pass the `BTreeMap` of iterators to a blockchain data source (e.g.
968    /// electrum server) which will go through each address until it reaches a *stop gap*.
969    ///
970    /// Note carefully that iterators go over **all** script pubkeys on the keychains (not what
971    /// script pubkeys the wallet is storing internally).
972    pub fn all_unbounded_spk_iters(
973        &self,
974    ) -> BTreeMap<KeychainKind, impl Iterator<Item = Indexed<ScriptBuf>> + Clone> {
975        self.indexed_graph.index.all_unbounded_spk_iters()
976    }
977
978    /// Get an unbounded script pubkey iterator for the given `keychain`.
979    ///
980    /// See [`all_unbounded_spk_iters`] for more documentation
981    ///
982    /// [`all_unbounded_spk_iters`]: Self::all_unbounded_spk_iters
983    pub fn unbounded_spk_iter(
984        &self,
985        keychain: KeychainKind,
986    ) -> impl Iterator<Item = Indexed<ScriptBuf>> + Clone {
987        self.indexed_graph
988            .index
989            .unbounded_spk_iter(self.map_keychain(keychain))
990            .expect("keychain must exist")
991    }
992
993    /// Returns the utxo owned by this wallet corresponding to `outpoint` if it exists in the
994    /// wallet's database.
995    pub fn get_utxo(&self, op: OutPoint) -> Option<LocalOutput> {
996        let ((keychain, index), _) = self.indexed_graph.index.txout(op)?;
997        self.indexed_graph
998            .graph()
999            .filter_chain_unspents(
1000                &self.chain,
1001                self.chain.tip().block_id(),
1002                CanonicalizationParams::default(),
1003                core::iter::once(((), op)),
1004            )
1005            .map(|(_, full_txo)| new_local_utxo(keychain, index, full_txo))
1006            .next()
1007    }
1008
1009    /// Inserts a [`TxOut`] at [`OutPoint`] into the wallet's transaction graph.
1010    ///
1011    /// This is used for providing a previous output's value so that we can use [`calculate_fee`]
1012    /// or [`calculate_fee_rate`] on a given transaction. Outputs inserted with this method will
1013    /// not be returned in [`list_unspent`] or [`list_output`].
1014    ///
1015    /// **WARNINGS:** This should only be used to add `TxOut`s that the wallet does not own. Only
1016    /// insert `TxOut`s that you trust the values for!
1017    ///
1018    /// You must persist the changes resulting from one or more calls to this method if you need
1019    /// the inserted `TxOut` data to be reloaded after closing the wallet.
1020    /// See [`Wallet::reveal_next_address`].
1021    ///
1022    /// [`calculate_fee`]: Self::calculate_fee
1023    /// [`calculate_fee_rate`]: Self::calculate_fee_rate
1024    /// [`list_unspent`]: Self::list_unspent
1025    /// [`list_output`]: Self::list_output
1026    pub fn insert_txout(&mut self, outpoint: OutPoint, txout: TxOut) {
1027        let additions = self.indexed_graph.insert_txout(outpoint, txout);
1028        self.stage.merge(additions.into());
1029    }
1030
1031    /// Calculates the fee of a given transaction. Returns [`Amount::ZERO`] if `tx` is a coinbase
1032    /// transaction.
1033    ///
1034    /// To calculate the fee for a [`Transaction`] with inputs not owned by this wallet you must
1035    /// manually insert the TxOut(s) into the tx graph using the [`insert_txout`] function.
1036    ///
1037    /// Note `tx` does not have to be in the graph for this to work.
1038    ///
1039    /// # Examples
1040    ///
1041    /// ```rust, no_run
1042    /// # use bitcoin::Txid;
1043    /// # use bdk_wallet::Wallet;
1044    /// # let mut wallet: Wallet = todo!();
1045    /// # let txid:Txid = todo!();
1046    /// let tx = wallet.get_tx(txid).expect("transaction").tx_node.tx;
1047    /// let fee = wallet.calculate_fee(&tx).expect("fee");
1048    /// ```
1049    ///
1050    /// ```rust, no_run
1051    /// # use bitcoin::Psbt;
1052    /// # use bdk_wallet::Wallet;
1053    /// # let mut wallet: Wallet = todo!();
1054    /// # let mut psbt: Psbt = todo!();
1055    /// let tx = &psbt.clone().extract_tx().expect("tx");
1056    /// let fee = wallet.calculate_fee(tx).expect("fee");
1057    /// ```
1058    /// [`insert_txout`]: Self::insert_txout
1059    pub fn calculate_fee(&self, tx: &Transaction) -> Result<Amount, CalculateFeeError> {
1060        self.indexed_graph.graph().calculate_fee(tx)
1061    }
1062
1063    /// Calculate the [`FeeRate`] for a given transaction.
1064    ///
1065    /// To calculate the fee rate for a [`Transaction`] with inputs not owned by this wallet you
1066    /// must manually insert the TxOut(s) into the tx graph using the [`insert_txout`] function.
1067    ///
1068    /// Note `tx` does not have to be in the graph for this to work.
1069    ///
1070    /// # Examples
1071    ///
1072    /// ```rust, no_run
1073    /// # use bitcoin::Txid;
1074    /// # use bdk_wallet::Wallet;
1075    /// # let mut wallet: Wallet = todo!();
1076    /// # let txid:Txid = todo!();
1077    /// let tx = wallet.get_tx(txid).expect("transaction").tx_node.tx;
1078    /// let fee_rate = wallet.calculate_fee_rate(&tx).expect("fee rate");
1079    /// ```
1080    ///
1081    /// ```rust, no_run
1082    /// # use bitcoin::Psbt;
1083    /// # use bdk_wallet::Wallet;
1084    /// # let mut wallet: Wallet = todo!();
1085    /// # let mut psbt: Psbt = todo!();
1086    /// let tx = &psbt.clone().extract_tx().expect("tx");
1087    /// let fee_rate = wallet.calculate_fee_rate(tx).expect("fee rate");
1088    /// ```
1089    /// [`insert_txout`]: Self::insert_txout
1090    pub fn calculate_fee_rate(&self, tx: &Transaction) -> Result<FeeRate, CalculateFeeError> {
1091        self.calculate_fee(tx).map(|fee| fee / tx.weight())
1092    }
1093
1094    /// Compute the `tx`'s sent and received [`Amount`]s.
1095    ///
1096    /// This method returns a tuple `(sent, received)`. Sent is the sum of the txin amounts
1097    /// that spend from previous txouts tracked by this wallet. Received is the summation
1098    /// of this tx's outputs that send to script pubkeys tracked by this wallet.
1099    ///
1100    /// # Examples
1101    ///
1102    /// ```rust, no_run
1103    /// # use bitcoin::Txid;
1104    /// # use bdk_wallet::Wallet;
1105    /// # let mut wallet: Wallet = todo!();
1106    /// # let txid:Txid = todo!();
1107    /// let tx = wallet.get_tx(txid).expect("tx exists").tx_node.tx;
1108    /// let (sent, received) = wallet.sent_and_received(&tx);
1109    /// ```
1110    ///
1111    /// ```rust, no_run
1112    /// # use bitcoin::Psbt;
1113    /// # use bdk_wallet::Wallet;
1114    /// # let mut wallet: Wallet = todo!();
1115    /// # let mut psbt: Psbt = todo!();
1116    /// let tx = &psbt.clone().extract_tx().expect("tx");
1117    /// let (sent, received) = wallet.sent_and_received(tx);
1118    /// ```
1119    pub fn sent_and_received(&self, tx: &Transaction) -> (Amount, Amount) {
1120        self.indexed_graph.index.sent_and_received(tx, ..)
1121    }
1122
1123    /// Get a single transaction from the wallet as a [`WalletTx`] (if the transaction exists).
1124    ///
1125    /// `WalletTx` contains the full transaction alongside meta-data such as:
1126    /// * Blocks that the transaction is [`Anchor`]ed in. These may or may not be blocks that exist
1127    ///   in the best chain.
1128    /// * The [`ChainPosition`] of the transaction in the best chain - whether the transaction is
1129    ///   confirmed or unconfirmed. If the transaction is confirmed, the anchor which proves the
1130    ///   confirmation is provided. If the transaction is unconfirmed, the unix timestamp of when
1131    ///   the transaction was last seen in the mempool is provided.
1132    ///
1133    /// ```rust, no_run
1134    /// use bdk_chain::Anchor;
1135    /// use bdk_wallet::{chain::ChainPosition, Wallet};
1136    /// # let wallet: Wallet = todo!();
1137    /// # let my_txid: bitcoin::Txid = todo!();
1138    ///
1139    /// let wallet_tx = wallet.get_tx(my_txid).expect("panic if tx does not exist");
1140    ///
1141    /// // get reference to full transaction
1142    /// println!("my tx: {:#?}", wallet_tx.tx_node.tx);
1143    ///
1144    /// // list all transaction anchors
1145    /// for anchor in wallet_tx.tx_node.anchors {
1146    ///     println!(
1147    ///         "tx is anchored by block of hash {}",
1148    ///         anchor.anchor_block().hash
1149    ///     );
1150    /// }
1151    ///
1152    /// // get confirmation status of transaction
1153    /// match wallet_tx.chain_position {
1154    ///     ChainPosition::Confirmed {
1155    ///         anchor,
1156    ///         transitively: None,
1157    ///     } => println!(
1158    ///         "tx is confirmed at height {}, we know this since {}:{} is in the best chain",
1159    ///         anchor.block_id.height, anchor.block_id.height, anchor.block_id.hash,
1160    ///     ),
1161    ///     ChainPosition::Confirmed {
1162    ///         anchor,
1163    ///         transitively: Some(_),
1164    ///     } => println!(
1165    ///         "tx is an ancestor of a tx anchored in {}:{}",
1166    ///         anchor.block_id.height, anchor.block_id.hash,
1167    ///     ),
1168    ///     ChainPosition::Unconfirmed { first_seen, last_seen } => println!(
1169    ///         "tx is first seen at {:?}, last seen at {:?}, it is unconfirmed as it is not anchored in the best chain",
1170    ///         first_seen, last_seen
1171    ///     ),
1172    /// }
1173    /// ```
1174    ///
1175    /// [`Anchor`]: bdk_chain::Anchor
1176    pub fn get_tx(&self, txid: Txid) -> Option<WalletTx<'_>> {
1177        let graph = self.indexed_graph.graph();
1178        graph
1179            .list_canonical_txs(
1180                &self.chain,
1181                self.chain.tip().block_id(),
1182                CanonicalizationParams::default(),
1183            )
1184            .find(|tx| tx.tx_node.txid == txid)
1185    }
1186
1187    /// Iterate over relevant and canonical transactions in the wallet.
1188    ///
1189    /// A transaction is relevant when it spends from or spends to at least one tracked output. A
1190    /// transaction is canonical when it is confirmed in the best chain, or does not conflict
1191    /// with any transaction confirmed in the best chain.
1192    ///
1193    /// To iterate over all transactions, including those that are irrelevant and not canonical, use
1194    /// [`TxGraph::full_txs`].
1195    ///
1196    /// To iterate over all canonical transactions, including those that are irrelevant, use
1197    /// [`TxGraph::list_canonical_txs`].
1198    pub fn transactions<'a>(&'a self) -> impl Iterator<Item = WalletTx<'a>> + 'a {
1199        let tx_graph = self.indexed_graph.graph();
1200        let tx_index = &self.indexed_graph.index;
1201        tx_graph
1202            .list_canonical_txs(
1203                &self.chain,
1204                self.chain.tip().block_id(),
1205                CanonicalizationParams::default(),
1206            )
1207            .filter(|c_tx| tx_index.is_tx_relevant(&c_tx.tx_node.tx))
1208    }
1209
1210    /// Array of relevant and canonical transactions in the wallet sorted with a comparator
1211    /// function.
1212    ///
1213    /// This is a helper method equivalent to collecting the result of [`Wallet::transactions`]
1214    /// into a [`Vec`] and then sorting it.
1215    ///
1216    /// # Example
1217    ///
1218    /// ```rust,no_run
1219    /// # use bdk_wallet::{LoadParams, Wallet, WalletTx};
1220    /// # let mut wallet:Wallet = todo!();
1221    /// // Transactions by chain position: first unconfirmed then descending by confirmed height.
1222    /// let sorted_txs: Vec<WalletTx> =
1223    ///     wallet.transactions_sort_by(|tx1, tx2| tx2.chain_position.cmp(&tx1.chain_position));
1224    /// # Ok::<(), anyhow::Error>(())
1225    /// ```
1226    pub fn transactions_sort_by<F>(&self, compare: F) -> Vec<WalletTx<'_>>
1227    where
1228        F: FnMut(&WalletTx, &WalletTx) -> Ordering,
1229    {
1230        let mut txs: Vec<WalletTx> = self.transactions().collect();
1231        txs.sort_unstable_by(compare);
1232        txs
1233    }
1234
1235    /// Return the balance, separated into available, trusted-pending, untrusted-pending, and
1236    /// immature values.
1237    pub fn balance(&self) -> Balance {
1238        self.indexed_graph.graph().balance(
1239            &self.chain,
1240            self.chain.tip().block_id(),
1241            CanonicalizationParams::default(),
1242            self.indexed_graph.index.outpoints().iter().cloned(),
1243            |&(k, _), _| k == KeychainKind::Internal,
1244        )
1245    }
1246
1247    /// Add an external signer
1248    ///
1249    /// See [the `signer` module](signer) for an example.
1250    pub fn add_signer(
1251        &mut self,
1252        keychain: KeychainKind,
1253        ordering: SignerOrdering,
1254        signer: Arc<dyn TransactionSigner>,
1255    ) {
1256        let signers = match keychain {
1257            KeychainKind::External => Arc::make_mut(&mut self.signers),
1258            KeychainKind::Internal => Arc::make_mut(&mut self.change_signers),
1259        };
1260
1261        signers.add_external(signer.id(&self.secp), ordering, signer);
1262    }
1263
1264    /// Set the keymap for a given keychain.
1265    ///
1266    /// Note this does nothing if the given keychain has no descriptor because we won't
1267    /// know the context (segwit, taproot, etc) in which to create signatures.
1268    pub fn set_keymap(&mut self, keychain: KeychainKind, keymap: KeyMap) {
1269        let wallet_signers = match keychain {
1270            KeychainKind::External => Arc::make_mut(&mut self.signers),
1271            KeychainKind::Internal => Arc::make_mut(&mut self.change_signers),
1272        };
1273        if let Some(descriptor) = self.indexed_graph.index.get_descriptor(keychain) {
1274            *wallet_signers = SignersContainer::build(keymap, descriptor, &self.secp)
1275        }
1276    }
1277
1278    /// Set the keymap for each keychain.
1279    pub fn set_keymaps(&mut self, keymaps: impl IntoIterator<Item = (KeychainKind, KeyMap)>) {
1280        for (keychain, keymap) in keymaps {
1281            self.set_keymap(keychain, keymap);
1282        }
1283    }
1284
1285    /// Get the signers
1286    ///
1287    /// ## Example
1288    ///
1289    /// ```
1290    /// # use bdk_wallet::{Wallet, KeychainKind};
1291    /// # use bdk_wallet::bitcoin::Network;
1292    /// let descriptor = "wpkh(tprv8ZgxMBicQKsPe73PBRSmNbTfbcsZnwWhz5eVmhHpi31HW29Z7mc9B4cWGRQzopNUzZUT391DeDJxL2PefNunWyLgqCKRMDkU1s2s8bAfoSk/84'/1'/0'/0/*)";
1293    /// let change_descriptor = "wpkh(tprv8ZgxMBicQKsPe73PBRSmNbTfbcsZnwWhz5eVmhHpi31HW29Z7mc9B4cWGRQzopNUzZUT391DeDJxL2PefNunWyLgqCKRMDkU1s2s8bAfoSk/84'/1'/0'/1/*)";
1294    /// let wallet = Wallet::create(descriptor, change_descriptor)
1295    ///     .network(Network::Testnet)
1296    ///     .create_wallet_no_persist()?;
1297    /// for secret_key in wallet.get_signers(KeychainKind::External).signers().iter().filter_map(|s| s.descriptor_secret_key()) {
1298    ///     // secret_key: tprv8ZgxMBicQKsPe73PBRSmNbTfbcsZnwWhz5eVmhHpi31HW29Z7mc9B4cWGRQzopNUzZUT391DeDJxL2PefNunWyLgqCKRMDkU1s2s8bAfoSk/84'/0'/0'/0/*
1299    ///     println!("secret_key: {}", secret_key);
1300    /// }
1301    ///
1302    /// Ok::<(), Box<dyn std::error::Error>>(())
1303    /// ```
1304    pub fn get_signers(&self, keychain: KeychainKind) -> Arc<SignersContainer> {
1305        match keychain {
1306            KeychainKind::External => Arc::clone(&self.signers),
1307            KeychainKind::Internal => Arc::clone(&self.change_signers),
1308        }
1309    }
1310
1311    /// Start building a transaction.
1312    ///
1313    /// This returns a blank [`TxBuilder`] from which you can specify the parameters for the
1314    /// transaction.
1315    ///
1316    /// ## Example
1317    ///
1318    /// ```
1319    /// # use std::str::FromStr;
1320    /// # use bitcoin::*;
1321    /// # use bdk_wallet::*;
1322    /// # use bdk_wallet::ChangeSet;
1323    /// # use bdk_wallet::error::CreateTxError;
1324    /// # use anyhow::Error;
1325    /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
1326    /// # let mut wallet = doctest_wallet!();
1327    /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
1328    /// let psbt = {
1329    ///    let mut builder =  wallet.build_tx();
1330    ///    builder
1331    ///        .add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000));
1332    ///    builder.finish()?
1333    /// };
1334    ///
1335    /// // sign and broadcast ...
1336    /// # Ok::<(), anyhow::Error>(())
1337    /// ```
1338    ///
1339    /// [`TxBuilder`]: crate::TxBuilder
1340    pub fn build_tx(&mut self) -> TxBuilder<'_, DefaultCoinSelectionAlgorithm> {
1341        TxBuilder {
1342            wallet: self,
1343            params: TxParams::default(),
1344            coin_selection: DefaultCoinSelectionAlgorithm::default(),
1345        }
1346    }
1347
1348    pub(crate) fn create_tx<Cs: coin_selection::CoinSelectionAlgorithm>(
1349        &mut self,
1350        coin_selection: Cs,
1351        params: TxParams,
1352        rng: &mut impl RngCore,
1353    ) -> Result<Psbt, CreateTxError> {
1354        let keychains: BTreeMap<_, _> = self.indexed_graph.index.keychains().collect();
1355        let external_descriptor = keychains.get(&KeychainKind::External).expect("must exist");
1356        let internal_descriptor = keychains.get(&KeychainKind::Internal);
1357
1358        let external_policy = external_descriptor
1359            .extract_policy(&self.signers, BuildSatisfaction::None, &self.secp)?
1360            .unwrap();
1361        let internal_policy = internal_descriptor
1362            .map(|desc| {
1363                Ok::<_, CreateTxError>(
1364                    desc.extract_policy(&self.change_signers, BuildSatisfaction::None, &self.secp)?
1365                        .unwrap(),
1366                )
1367            })
1368            .transpose()?;
1369
1370        // The policy allows spending external outputs, but it requires a policy path that hasn't
1371        // been provided
1372        if params.change_policy != tx_builder::ChangeSpendPolicy::OnlyChange
1373            && external_policy.requires_path()
1374            && params.external_policy_path.is_none()
1375        {
1376            return Err(CreateTxError::SpendingPolicyRequired(
1377                KeychainKind::External,
1378            ));
1379        };
1380        // Same for the internal_policy path
1381        if let Some(internal_policy) = &internal_policy {
1382            if params.change_policy != tx_builder::ChangeSpendPolicy::ChangeForbidden
1383                && internal_policy.requires_path()
1384                && params.internal_policy_path.is_none()
1385            {
1386                return Err(CreateTxError::SpendingPolicyRequired(
1387                    KeychainKind::Internal,
1388                ));
1389            };
1390        }
1391
1392        let external_requirements = external_policy.get_condition(
1393            params
1394                .external_policy_path
1395                .as_ref()
1396                .unwrap_or(&BTreeMap::new()),
1397        )?;
1398        let internal_requirements = internal_policy
1399            .map(|policy| {
1400                Ok::<_, CreateTxError>(
1401                    policy.get_condition(
1402                        params
1403                            .internal_policy_path
1404                            .as_ref()
1405                            .unwrap_or(&BTreeMap::new()),
1406                    )?,
1407                )
1408            })
1409            .transpose()?;
1410
1411        let requirements =
1412            external_requirements.merge(&internal_requirements.unwrap_or_default())?;
1413
1414        let version = match params.version {
1415            Some(transaction::Version(0)) => return Err(CreateTxError::Version0),
1416            Some(transaction::Version::ONE) if requirements.csv.is_some() => {
1417                return Err(CreateTxError::Version1Csv)
1418            }
1419            Some(v) => v,
1420            None => transaction::Version::TWO,
1421        };
1422
1423        // We use a match here instead of a unwrap_or_else as it's way more readable :)
1424        let current_height = match params.current_height {
1425            // If they didn't tell us the current height, we assume it's the latest sync height.
1426            None => {
1427                let tip_height = self.chain.tip().height();
1428                absolute::LockTime::from_height(tip_height).expect("invalid height")
1429            }
1430            Some(h) => h,
1431        };
1432
1433        let lock_time = match params.locktime {
1434            // When no nLockTime is specified, we try to prevent fee sniping, if possible
1435            None => {
1436                // Fee sniping can be partially prevented by setting the timelock
1437                // to current_height. If we don't know the current_height,
1438                // we default to 0.
1439                let fee_sniping_height = current_height;
1440
1441                // We choose the biggest between the required nlocktime and the fee sniping
1442                // height
1443                match requirements.timelock {
1444                    // No requirement, just use the fee_sniping_height
1445                    None => fee_sniping_height,
1446                    // There's a block-based requirement, but the value is lower than the
1447                    // fee_sniping_height
1448                    Some(value @ absolute::LockTime::Blocks(_)) if value < fee_sniping_height => {
1449                        fee_sniping_height
1450                    }
1451                    // There's a time-based requirement or a block-based requirement greater
1452                    // than the fee_sniping_height use that value
1453                    Some(value) => value,
1454                }
1455            }
1456            // Specific nLockTime required and we have no constraints, so just set to that value
1457            Some(x) if requirements.timelock.is_none() => x,
1458            // Specific nLockTime required and it's compatible with the constraints
1459            Some(x)
1460                if requirements.timelock.unwrap().is_same_unit(x)
1461                    && x >= requirements.timelock.unwrap() =>
1462            {
1463                x
1464            }
1465            // Invalid nLockTime required
1466            Some(x) => {
1467                return Err(CreateTxError::LockTime {
1468                    requested: x,
1469                    required: requirements.timelock.unwrap(),
1470                })
1471            }
1472        };
1473
1474        // nSequence value for inputs
1475        // When not explicitly specified, defaults to 0xFFFFFFFD,
1476        // meaning RBF signaling is enabled
1477        let n_sequence = match (params.sequence, requirements.csv) {
1478            // Enable RBF by default
1479            (None, None) => Sequence::ENABLE_RBF_NO_LOCKTIME,
1480            // None requested, use required
1481            (None, Some(csv)) => csv,
1482            // Requested sequence is incompatible with requirements
1483            (Some(sequence), Some(csv)) if !check_nsequence_rbf(sequence, csv) => {
1484                return Err(CreateTxError::RbfSequenceCsv { sequence, csv })
1485            }
1486            // Use requested nSequence value
1487            (Some(sequence), _) => sequence,
1488        };
1489
1490        let (fee_rate, mut fee_amount) = match params.fee_policy.unwrap_or_default() {
1491            //FIXME: see https://github.com/bitcoindevkit/bdk/issues/256
1492            FeePolicy::FeeAmount(fee) => {
1493                if let Some(previous_fee) = params.bumping_fee {
1494                    if fee < previous_fee.absolute {
1495                        return Err(CreateTxError::FeeTooLow {
1496                            required: previous_fee.absolute,
1497                        });
1498                    }
1499                }
1500                (FeeRate::ZERO, fee)
1501            }
1502            FeePolicy::FeeRate(rate) => {
1503                if let Some(previous_fee) = params.bumping_fee {
1504                    let required_feerate = FeeRate::from_sat_per_kwu(
1505                        previous_fee.rate.to_sat_per_kwu()
1506                            + FeeRate::BROADCAST_MIN.to_sat_per_kwu(), // +1 sat/vb
1507                    );
1508                    if rate < required_feerate {
1509                        return Err(CreateTxError::FeeRateTooLow {
1510                            required: required_feerate,
1511                        });
1512                    }
1513                }
1514                (rate, Amount::ZERO)
1515            }
1516        };
1517
1518        let mut tx = Transaction {
1519            version,
1520            lock_time,
1521            input: vec![],
1522            output: vec![],
1523        };
1524
1525        if params.manually_selected_only && params.utxos.is_empty() {
1526            return Err(CreateTxError::NoUtxosSelected);
1527        }
1528
1529        let mut outgoing = Amount::ZERO;
1530        let recipients = params.recipients.iter().map(|(r, v)| (r, *v));
1531
1532        for (index, (script_pubkey, value)) in recipients.enumerate() {
1533            if !params.allow_dust && value.is_dust(script_pubkey) && !script_pubkey.is_op_return() {
1534                return Err(CreateTxError::OutputBelowDustLimit(index));
1535            }
1536
1537            let new_out = TxOut {
1538                script_pubkey: script_pubkey.clone(),
1539                value,
1540            };
1541
1542            tx.output.push(new_out);
1543
1544            outgoing += value;
1545        }
1546
1547        fee_amount += fee_rate * tx.weight();
1548
1549        let (required_utxos, optional_utxos) = {
1550            // NOTE: manual selection overrides unspendable
1551            let mut required: Vec<WeightedUtxo> = params.utxos.clone();
1552            let optional = self.filter_utxos(&params, current_height.to_consensus_u32());
1553
1554            // if drain_wallet is true, all UTxOs are required
1555            if params.drain_wallet {
1556                required.extend(optional);
1557                (required, vec![])
1558            } else {
1559                (required, optional)
1560            }
1561        };
1562
1563        // get drain script
1564        let mut drain_index = Option::<(KeychainKind, u32)>::None;
1565        let drain_script = match params.drain_to {
1566            Some(ref drain_recipient) => drain_recipient.clone(),
1567            None => {
1568                let change_keychain = self.map_keychain(KeychainKind::Internal);
1569                let (index, spk) = self
1570                    .indexed_graph
1571                    .index
1572                    .unused_keychain_spks(change_keychain)
1573                    .next()
1574                    .unwrap_or_else(|| {
1575                        let (next_index, _) = self
1576                            .indexed_graph
1577                            .index
1578                            .next_index(change_keychain)
1579                            .expect("keychain must exist");
1580                        let spk = self
1581                            .peek_address(change_keychain, next_index)
1582                            .script_pubkey();
1583                        (next_index, spk)
1584                    });
1585                drain_index = Some((change_keychain, index));
1586                spk
1587            }
1588        };
1589
1590        let coin_selection = coin_selection
1591            .coin_select(
1592                required_utxos,
1593                optional_utxos,
1594                fee_rate,
1595                outgoing + fee_amount,
1596                &drain_script,
1597                rng,
1598            )
1599            .map_err(CreateTxError::CoinSelection)?;
1600
1601        let excess = &coin_selection.excess;
1602        tx.input = coin_selection
1603            .selected
1604            .iter()
1605            .map(|u| bitcoin::TxIn {
1606                previous_output: u.outpoint(),
1607                script_sig: ScriptBuf::default(),
1608                sequence: u.sequence().unwrap_or(n_sequence),
1609                witness: Witness::new(),
1610            })
1611            .collect();
1612
1613        if tx.output.is_empty() {
1614            // Uh oh, our transaction has no outputs.
1615            // We allow this when:
1616            // - We have a drain_to address and the utxos we must spend (this happens,
1617            // for example, when we RBF)
1618            // - We have a drain_to address and drain_wallet set
1619            // Otherwise, we don't know who we should send the funds to, and how much
1620            // we should send!
1621            if params.drain_to.is_some() && (params.drain_wallet || !params.utxos.is_empty()) {
1622                if let Excess::NoChange {
1623                    dust_threshold,
1624                    remaining_amount,
1625                    change_fee,
1626                } = excess
1627                {
1628                    return Err(CreateTxError::CoinSelection(InsufficientFunds {
1629                        needed: *dust_threshold,
1630                        available: remaining_amount
1631                            .checked_sub(*change_fee)
1632                            .unwrap_or_default(),
1633                    }));
1634                }
1635            } else {
1636                return Err(CreateTxError::NoRecipients);
1637            }
1638        }
1639
1640        // if there's change, create and add a change output
1641        if let Excess::Change { amount, .. } = excess {
1642            // create drain output
1643            let drain_output = TxOut {
1644                value: *amount,
1645                script_pubkey: drain_script,
1646            };
1647
1648            // TODO: We should pay attention when adding a new output: this might increase
1649            // the length of the "number of vouts" parameter by 2 bytes, potentially making
1650            // our feerate too low
1651            tx.output.push(drain_output);
1652        }
1653
1654        // sort input/outputs according to the chosen algorithm
1655        params.ordering.sort_tx_with_aux_rand(&mut tx, rng);
1656
1657        let psbt = self.complete_transaction(tx, coin_selection.selected, params)?;
1658
1659        // recording changes to the change keychain
1660        if let (Excess::Change { .. }, Some((keychain, index))) = (excess, drain_index) {
1661            if let Some((_, index_changeset)) =
1662                self.indexed_graph.index.reveal_to_target(keychain, index)
1663            {
1664                self.stage.merge(index_changeset.into());
1665                self.mark_used(keychain, index);
1666            }
1667        }
1668
1669        Ok(psbt)
1670    }
1671
1672    /// Bump the fee of a transaction previously created with this wallet.
1673    ///
1674    /// Returns an error if the transaction is already confirmed or doesn't explicitly signal
1675    /// *replace by fee* (RBF). If the transaction can be fee bumped then it returns a [`TxBuilder`]
1676    /// pre-populated with the inputs and outputs of the original transaction.
1677    ///
1678    /// ## Example
1679    ///
1680    /// ```no_run
1681    /// # // TODO: remove norun -- bumping fee seems to need the tx in the wallet database first.
1682    /// # use std::str::FromStr;
1683    /// # use bitcoin::*;
1684    /// # use bdk_wallet::*;
1685    /// # use bdk_wallet::ChangeSet;
1686    /// # use bdk_wallet::error::CreateTxError;
1687    /// # use anyhow::Error;
1688    /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
1689    /// # let mut wallet = doctest_wallet!();
1690    /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
1691    /// let mut psbt = {
1692    ///     let mut builder = wallet.build_tx();
1693    ///     builder
1694    ///         .add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000));
1695    ///     builder.finish()?
1696    /// };
1697    /// let _ = wallet.sign(&mut psbt, SignOptions::default())?;
1698    /// let tx = psbt.clone().extract_tx().expect("tx");
1699    /// // broadcast tx but it's taking too long to confirm so we want to bump the fee
1700    /// let mut psbt =  {
1701    ///     let mut builder = wallet.build_fee_bump(tx.compute_txid())?;
1702    ///     builder
1703    ///         .fee_rate(FeeRate::from_sat_per_vb(5).expect("valid feerate"));
1704    ///     builder.finish()?
1705    /// };
1706    ///
1707    /// let _ = wallet.sign(&mut psbt, SignOptions::default())?;
1708    /// let fee_bumped_tx = psbt.extract_tx();
1709    /// // broadcast fee_bumped_tx to replace original
1710    /// # Ok::<(), anyhow::Error>(())
1711    /// ```
1712    // TODO: support for merging multiple transactions while bumping the fees
1713    pub fn build_fee_bump(
1714        &mut self,
1715        txid: Txid,
1716    ) -> Result<TxBuilder<'_, DefaultCoinSelectionAlgorithm>, BuildFeeBumpError> {
1717        let tx_graph = self.indexed_graph.graph();
1718        let txout_index = &self.indexed_graph.index;
1719        let chain_tip = self.chain.tip().block_id();
1720        let chain_positions: HashMap<Txid, ChainPosition<_>> = tx_graph
1721            .list_canonical_txs(&self.chain, chain_tip, CanonicalizationParams::default())
1722            .map(|canon_tx| (canon_tx.tx_node.txid, canon_tx.chain_position))
1723            .collect();
1724
1725        let mut tx = tx_graph
1726            .get_tx(txid)
1727            .ok_or(BuildFeeBumpError::TransactionNotFound(txid))?
1728            .as_ref()
1729            .clone();
1730
1731        if chain_positions
1732            .get(&txid)
1733            .ok_or(BuildFeeBumpError::TransactionNotFound(txid))?
1734            .is_confirmed()
1735        {
1736            return Err(BuildFeeBumpError::TransactionConfirmed(txid));
1737        }
1738
1739        if !tx
1740            .input
1741            .iter()
1742            .any(|txin| txin.sequence.to_consensus_u32() <= 0xFFFFFFFD)
1743        {
1744            return Err(BuildFeeBumpError::IrreplaceableTransaction(
1745                tx.compute_txid(),
1746            ));
1747        }
1748
1749        let fee = self
1750            .calculate_fee(&tx)
1751            .map_err(|_| BuildFeeBumpError::FeeRateUnavailable)?;
1752        let fee_rate = fee / tx.weight();
1753
1754        // Remove the inputs from the tx and process them.
1755        let utxos: Vec<WeightedUtxo> = tx
1756            .input
1757            .drain(..)
1758            .map(|txin| -> Result<_, BuildFeeBumpError> {
1759                let outpoint = txin.previous_output;
1760                let prev_txout = tx_graph
1761                    .get_txout(outpoint)
1762                    .cloned()
1763                    .ok_or(BuildFeeBumpError::UnknownUtxo(outpoint))?;
1764                match txout_index.index_of_spk(prev_txout.script_pubkey.clone()) {
1765                    Some(&(keychain, derivation_index)) => {
1766                        let txout = prev_txout;
1767                        let chain_position = chain_positions
1768                            .get(&outpoint.txid)
1769                            .cloned()
1770                            .ok_or(BuildFeeBumpError::TransactionNotFound(outpoint.txid))?;
1771                        Ok(WeightedUtxo {
1772                            satisfaction_weight: self
1773                                .public_descriptor(keychain)
1774                                .max_weight_to_satisfy()
1775                                .expect("descriptor should be satisfiable"),
1776                            utxo: Utxo::Local(LocalOutput {
1777                                outpoint,
1778                                txout,
1779                                keychain,
1780                                is_spent: true,
1781                                derivation_index,
1782                                chain_position,
1783                            }),
1784                        })
1785                    }
1786                    None => Ok(WeightedUtxo {
1787                        satisfaction_weight: Weight::from_wu_usize(
1788                            serialize(&txin.script_sig).len() * 4 + serialize(&txin.witness).len(),
1789                        ),
1790                        utxo: Utxo::Foreign {
1791                            outpoint,
1792                            sequence: txin.sequence,
1793                            psbt_input: Box::new(psbt::Input {
1794                                witness_utxo: prev_txout
1795                                    .script_pubkey
1796                                    .witness_version()
1797                                    .map(|_| prev_txout),
1798                                non_witness_utxo: tx_graph
1799                                    .get_tx(outpoint.txid)
1800                                    .map(|tx| tx.as_ref().clone()),
1801                                ..Default::default()
1802                            }),
1803                        },
1804                    }),
1805                }
1806            })
1807            .collect::<Result<_, _>>()?;
1808
1809        if tx.output.len() > 1 {
1810            let mut change_index = None;
1811            for (index, txout) in tx.output.iter().enumerate() {
1812                let change_keychain = self.map_keychain(KeychainKind::Internal);
1813                match txout_index.index_of_spk(txout.script_pubkey.clone()) {
1814                    Some((keychain, _)) if *keychain == change_keychain => {
1815                        change_index = Some(index)
1816                    }
1817                    _ => {}
1818                }
1819            }
1820
1821            if let Some(change_index) = change_index {
1822                tx.output.remove(change_index);
1823            }
1824        }
1825
1826        let params = TxParams {
1827            version: Some(tx.version),
1828            recipients: tx
1829                .output
1830                .into_iter()
1831                .map(|txout| (txout.script_pubkey, txout.value))
1832                .collect(),
1833            utxos,
1834            bumping_fee: Some(tx_builder::PreviousFee {
1835                absolute: fee,
1836                rate: fee_rate,
1837            }),
1838            ..Default::default()
1839        };
1840
1841        Ok(TxBuilder {
1842            wallet: self,
1843            params,
1844            coin_selection: DefaultCoinSelectionAlgorithm::default(),
1845        })
1846    }
1847
1848    /// Sign a transaction with all the wallet's signers, in the order specified by every signer's
1849    /// [`SignerOrdering`]. This function returns the `Result` type with an encapsulated `bool` that
1850    /// has the value true if the PSBT was finalized, or false otherwise.
1851    ///
1852    /// The [`SignOptions`] can be used to tweak the behavior of the software signers, and the way
1853    /// the transaction is finalized at the end. Note that it can't be guaranteed that *every*
1854    /// signers will follow the options, but the "software signers" (WIF keys and `xprv`) defined
1855    /// in this library will.
1856    ///
1857    /// ## Example
1858    ///
1859    /// ```
1860    /// # use std::str::FromStr;
1861    /// # use bitcoin::*;
1862    /// # use bdk_wallet::*;
1863    /// # use bdk_wallet::ChangeSet;
1864    /// # use bdk_wallet::error::CreateTxError;
1865    /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
1866    /// # let mut wallet = doctest_wallet!();
1867    /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
1868    /// let mut psbt = {
1869    ///     let mut builder = wallet.build_tx();
1870    ///     builder.add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000));
1871    ///     builder.finish()?
1872    /// };
1873    /// let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
1874    /// assert!(finalized, "we should have signed all the inputs");
1875    /// # Ok::<(),anyhow::Error>(())
1876    pub fn sign(&self, psbt: &mut Psbt, sign_options: SignOptions) -> Result<bool, SignerError> {
1877        // This adds all the PSBT metadata for the inputs, which will help us later figure out how
1878        // to derive our keys
1879        self.update_psbt_with_descriptor(psbt)
1880            .map_err(SignerError::MiniscriptPsbt)?;
1881
1882        // If we aren't allowed to use `witness_utxo`, ensure that every input (except p2tr and
1883        // finalized ones) has the `non_witness_utxo`
1884        if !sign_options.trust_witness_utxo
1885            && psbt
1886                .inputs
1887                .iter()
1888                .filter(|i| i.final_script_witness.is_none() && i.final_script_sig.is_none())
1889                .filter(|i| i.tap_internal_key.is_none() && i.tap_merkle_root.is_none())
1890                .any(|i| i.non_witness_utxo.is_none())
1891        {
1892            return Err(SignerError::MissingNonWitnessUtxo);
1893        }
1894
1895        // If the user hasn't explicitly opted-in, refuse to sign the transaction unless every input
1896        // is using `SIGHASH_ALL` or `SIGHASH_DEFAULT` for taproot
1897        if !sign_options.allow_all_sighashes
1898            && !psbt.inputs.iter().all(|i| {
1899                i.sighash_type.is_none()
1900                    || i.sighash_type == Some(EcdsaSighashType::All.into())
1901                    || i.sighash_type == Some(TapSighashType::All.into())
1902                    || i.sighash_type == Some(TapSighashType::Default.into())
1903            })
1904        {
1905            return Err(SignerError::NonStandardSighash);
1906        }
1907
1908        for signer in self
1909            .signers
1910            .signers()
1911            .iter()
1912            .chain(self.change_signers.signers().iter())
1913        {
1914            signer.sign_transaction(psbt, &sign_options, &self.secp)?;
1915        }
1916
1917        // attempt to finalize
1918        if sign_options.try_finalize {
1919            self.finalize_psbt(psbt, sign_options)
1920        } else {
1921            Ok(false)
1922        }
1923    }
1924
1925    /// Return the spending policies for the wallet's descriptor
1926    pub fn policies(&self, keychain: KeychainKind) -> Result<Option<Policy>, DescriptorError> {
1927        let signers = match keychain {
1928            KeychainKind::External => &self.signers,
1929            KeychainKind::Internal => &self.change_signers,
1930        };
1931
1932        self.public_descriptor(keychain).extract_policy(
1933            signers,
1934            BuildSatisfaction::None,
1935            &self.secp,
1936        )
1937    }
1938
1939    /// Returns the descriptor used to create addresses for a particular `keychain`.
1940    ///
1941    /// It's the "public" version of the wallet's descriptor, meaning a new descriptor that has
1942    /// the same structure but with the all secret keys replaced by their corresponding public key.
1943    /// This can be used to build a watch-only version of a wallet.
1944    pub fn public_descriptor(&self, keychain: KeychainKind) -> &ExtendedDescriptor {
1945        self.indexed_graph
1946            .index
1947            .get_descriptor(self.map_keychain(keychain))
1948            .expect("keychain must exist")
1949    }
1950
1951    /// Finalize a PSBT, i.e., for each input determine if sufficient data is available to pass
1952    /// validation and construct the respective `scriptSig` or `scriptWitness`. Please refer to
1953    /// [BIP174](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#Input_Finalizer),
1954    /// and [BIP371](https://github.com/bitcoin/bips/blob/master/bip-0371.mediawiki)
1955    /// for further information.
1956    ///
1957    /// Returns `true` if the PSBT could be finalized, and `false` otherwise.
1958    ///
1959    /// The [`SignOptions`] can be used to tweak the behavior of the finalizer.
1960    pub fn finalize_psbt(
1961        &self,
1962        psbt: &mut Psbt,
1963        sign_options: SignOptions,
1964    ) -> Result<bool, SignerError> {
1965        let tx = &psbt.unsigned_tx;
1966        let chain_tip = self.chain.tip().block_id();
1967        let prev_txids = tx
1968            .input
1969            .iter()
1970            .map(|txin| txin.previous_output.txid)
1971            .collect::<HashSet<Txid>>();
1972        let confirmation_heights = self
1973            .indexed_graph
1974            .graph()
1975            .list_canonical_txs(&self.chain, chain_tip, CanonicalizationParams::default())
1976            .filter(|canon_tx| prev_txids.contains(&canon_tx.tx_node.txid))
1977            // This is for a small performance gain. Although `.filter` filters out excess txs, it
1978            // will still consume the internal `CanonicalIter` entirely. Having a `.take` here
1979            // allows us to stop further unnecessary canonicalization.
1980            .take(prev_txids.len())
1981            .map(|canon_tx| {
1982                let txid = canon_tx.tx_node.txid;
1983                match canon_tx.chain_position {
1984                    ChainPosition::Confirmed { anchor, .. } => (txid, anchor.block_id.height),
1985                    ChainPosition::Unconfirmed { .. } => (txid, u32::MAX),
1986                }
1987            })
1988            .collect::<HashMap<Txid, u32>>();
1989
1990        let mut finished = true;
1991
1992        for (n, input) in tx.input.iter().enumerate() {
1993            let psbt_input = &psbt
1994                .inputs
1995                .get(n)
1996                .ok_or(SignerError::InputIndexOutOfRange)?;
1997            if psbt_input.final_script_sig.is_some() || psbt_input.final_script_witness.is_some() {
1998                continue;
1999            }
2000            let confirmation_height = confirmation_heights
2001                .get(&input.previous_output.txid)
2002                .copied();
2003            let current_height = sign_options
2004                .assume_height
2005                .unwrap_or_else(|| self.chain.tip().height());
2006
2007            // - Try to derive the descriptor by looking at the txout. If it's in our database, we
2008            //   know exactly which `keychain` to use, and which derivation index it is
2009            // - If that fails, try to derive it by looking at the psbt input: the complete logic is
2010            //   in `src/descriptor/mod.rs`, but it will basically look at `bip32_derivation`,
2011            //   `redeem_script` and `witness_script` to determine the right derivation
2012            // - If that also fails, it will try it on the internal descriptor, if present
2013            let desc = psbt
2014                .get_utxo_for(n)
2015                .and_then(|txout| self.get_descriptor_for_txout(&txout))
2016                .or_else(|| {
2017                    self.indexed_graph.index.keychains().find_map(|(_, desc)| {
2018                        desc.derive_from_psbt_input(psbt_input, psbt.get_utxo_for(n), &self.secp)
2019                    })
2020                });
2021
2022            match desc {
2023                Some(desc) => {
2024                    let mut tmp_input = bitcoin::TxIn::default();
2025                    match desc.satisfy(
2026                        &mut tmp_input,
2027                        (
2028                            PsbtInputSatisfier::new(psbt, n),
2029                            After::new(Some(current_height), false),
2030                            Older::new(Some(current_height), confirmation_height, false),
2031                        ),
2032                    ) {
2033                        Ok(_) => {
2034                            // Set the UTXO fields, final script_sig and witness
2035                            // and clear everything else.
2036                            let psbt_input = psbt
2037                                .inputs
2038                                .get_mut(n)
2039                                .ok_or(SignerError::InputIndexOutOfRange)?;
2040                            let original = mem::take(psbt_input);
2041                            psbt_input.non_witness_utxo = original.non_witness_utxo;
2042                            psbt_input.witness_utxo = original.witness_utxo;
2043                            if !tmp_input.script_sig.is_empty() {
2044                                psbt_input.final_script_sig = Some(tmp_input.script_sig);
2045                            }
2046                            if !tmp_input.witness.is_empty() {
2047                                psbt_input.final_script_witness = Some(tmp_input.witness);
2048                            }
2049                        }
2050                        Err(_) => finished = false,
2051                    }
2052                }
2053                None => finished = false,
2054            }
2055        }
2056
2057        // Clear derivation paths from outputs
2058        if finished {
2059            for output in &mut psbt.outputs {
2060                output.bip32_derivation.clear();
2061                output.tap_key_origins.clear();
2062            }
2063        }
2064
2065        Ok(finished)
2066    }
2067
2068    /// Return the secp256k1 context used for all signing operations
2069    pub fn secp_ctx(&self) -> &SecpCtx {
2070        &self.secp
2071    }
2072
2073    /// The derivation index of this wallet. It will return `None` if it has not derived any
2074    /// addresses. Otherwise, it will return the index of the highest address it has derived.
2075    pub fn derivation_index(&self, keychain: KeychainKind) -> Option<u32> {
2076        self.indexed_graph.index.last_revealed_index(keychain)
2077    }
2078
2079    /// The index of the next address that you would get if you were to ask the wallet for a new
2080    /// address
2081    pub fn next_derivation_index(&self, keychain: KeychainKind) -> u32 {
2082        self.indexed_graph
2083            .index
2084            .next_index(self.map_keychain(keychain))
2085            .expect("keychain must exist")
2086            .0
2087    }
2088
2089    /// Informs the wallet that you no longer intend to broadcast a tx that was built from it.
2090    ///
2091    /// This frees up the change address used when creating the tx for use in future transactions.
2092    // TODO: Make this free up reserved utxos when that's implemented
2093    pub fn cancel_tx(&mut self, tx: &Transaction) {
2094        let txout_index = &mut self.indexed_graph.index;
2095        for txout in &tx.output {
2096            if let Some((keychain, index)) = txout_index.index_of_spk(txout.script_pubkey.clone()) {
2097                // NOTE: unmark_used will **not** make something unused if it has actually been used
2098                // by a tx in the tracker. It only removes the superficial marking.
2099                txout_index.unmark_used(*keychain, *index);
2100            }
2101        }
2102    }
2103
2104    fn get_descriptor_for_txout(&self, txout: &TxOut) -> Option<DerivedDescriptor> {
2105        let &(keychain, child) = self
2106            .indexed_graph
2107            .index
2108            .index_of_spk(txout.script_pubkey.clone())?;
2109        let descriptor = self.public_descriptor(keychain);
2110        descriptor.at_derivation_index(child).ok()
2111    }
2112
2113    /// Given the options returns the list of utxos that must be used to form the
2114    /// transaction and any further that may be used if needed.
2115    fn filter_utxos(&self, params: &TxParams, current_height: u32) -> Vec<WeightedUtxo> {
2116        if params.manually_selected_only {
2117            vec![]
2118        // only process optional UTxOs if manually_selected_only is false
2119        } else {
2120            let manually_selected_outpoints = params
2121                .utxos
2122                .iter()
2123                .map(|wutxo| wutxo.utxo.outpoint())
2124                .collect::<HashSet<OutPoint>>();
2125            self.indexed_graph
2126                .graph()
2127                // get all unspent UTxOs from wallet
2128                // NOTE: the UTxOs returned by the following method already belong to wallet as the
2129                // call chain uses get_tx_node infallibly
2130                .filter_chain_unspents(
2131                    &self.chain,
2132                    self.chain.tip().block_id(),
2133                    CanonicalizationParams::default(),
2134                    self.indexed_graph.index.outpoints().iter().cloned(),
2135                )
2136                // only create LocalOutput if UTxO is mature
2137                .filter_map(move |((k, i), full_txo)| {
2138                    full_txo
2139                        .is_mature(current_height)
2140                        .then(|| new_local_utxo(k, i, full_txo))
2141                })
2142                // only process UTXOs not selected manually, they will be considered later in the
2143                // chain
2144                // NOTE: this avoid UTXOs in both required and optional list
2145                .filter(|may_spend| !manually_selected_outpoints.contains(&may_spend.outpoint))
2146                // only add to optional UTxOs those which satisfy the change policy if we reuse
2147                // change
2148                .filter(|local_output| {
2149                    self.keychains().count() == 1
2150                        || params.change_policy.is_satisfied_by(local_output)
2151                })
2152                // only add to optional UTxOs those marked as spendable
2153                .filter(|local_output| !params.unspendable.contains(&local_output.outpoint))
2154                // if bumping fees only add to optional UTxOs those confirmed
2155                .filter(|local_output| {
2156                    params.bumping_fee.is_none() || local_output.chain_position.is_confirmed()
2157                })
2158                .map(|utxo| WeightedUtxo {
2159                    satisfaction_weight: self
2160                        .public_descriptor(utxo.keychain)
2161                        .max_weight_to_satisfy()
2162                        .unwrap(),
2163                    utxo: Utxo::Local(utxo),
2164                })
2165                .collect()
2166        }
2167    }
2168
2169    fn complete_transaction(
2170        &self,
2171        tx: Transaction,
2172        selected: Vec<Utxo>,
2173        params: TxParams,
2174    ) -> Result<Psbt, CreateTxError> {
2175        let mut psbt = Psbt::from_unsigned_tx(tx)?;
2176
2177        if params.add_global_xpubs {
2178            let all_xpubs = self
2179                .keychains()
2180                .flat_map(|(_, desc)| desc.get_extended_keys())
2181                .collect::<Vec<_>>();
2182
2183            for xpub in all_xpubs {
2184                let origin = match xpub.origin {
2185                    Some(origin) => origin,
2186                    None if xpub.xkey.depth == 0 => {
2187                        (xpub.root_fingerprint(&self.secp), vec![].into())
2188                    }
2189                    _ => return Err(CreateTxError::MissingKeyOrigin(xpub.xkey.to_string())),
2190                };
2191
2192                psbt.xpub.insert(xpub.xkey, origin);
2193            }
2194        }
2195
2196        let mut lookup_output = selected
2197            .into_iter()
2198            .map(|utxo| (utxo.outpoint(), utxo))
2199            .collect::<HashMap<_, _>>();
2200
2201        // add metadata for the inputs
2202        for (psbt_input, input) in psbt.inputs.iter_mut().zip(psbt.unsigned_tx.input.iter()) {
2203            let utxo = match lookup_output.remove(&input.previous_output) {
2204                Some(utxo) => utxo,
2205                None => continue,
2206            };
2207
2208            match utxo {
2209                Utxo::Local(utxo) => {
2210                    *psbt_input =
2211                        match self.get_psbt_input(utxo, params.sighash, params.only_witness_utxo) {
2212                            Ok(psbt_input) => psbt_input,
2213                            Err(e) => match e {
2214                                CreateTxError::UnknownUtxo => psbt::Input {
2215                                    sighash_type: params.sighash,
2216                                    ..psbt::Input::default()
2217                                },
2218                                _ => return Err(e),
2219                            },
2220                        }
2221                }
2222                Utxo::Foreign {
2223                    outpoint,
2224                    psbt_input: foreign_psbt_input,
2225                    ..
2226                } => {
2227                    let is_taproot = foreign_psbt_input
2228                        .witness_utxo
2229                        .as_ref()
2230                        .map(|txout| txout.script_pubkey.is_p2tr())
2231                        .unwrap_or(false);
2232                    if !is_taproot
2233                        && !params.only_witness_utxo
2234                        && foreign_psbt_input.non_witness_utxo.is_none()
2235                    {
2236                        return Err(CreateTxError::MissingNonWitnessUtxo(outpoint));
2237                    }
2238                    *psbt_input = *foreign_psbt_input;
2239                }
2240            }
2241        }
2242
2243        self.update_psbt_with_descriptor(&mut psbt)?;
2244
2245        Ok(psbt)
2246    }
2247
2248    /// get the corresponding PSBT Input for a LocalUtxo
2249    pub fn get_psbt_input(
2250        &self,
2251        utxo: LocalOutput,
2252        sighash_type: Option<psbt::PsbtSighashType>,
2253        only_witness_utxo: bool,
2254    ) -> Result<psbt::Input, CreateTxError> {
2255        // Try to find the prev_script in our db to figure out if this is internal or external,
2256        // and the derivation index
2257        let &(keychain, child) = self
2258            .indexed_graph
2259            .index
2260            .index_of_spk(utxo.txout.script_pubkey)
2261            .ok_or(CreateTxError::UnknownUtxo)?;
2262
2263        let mut psbt_input = psbt::Input {
2264            sighash_type,
2265            ..psbt::Input::default()
2266        };
2267
2268        let desc = self.public_descriptor(keychain);
2269        let derived_descriptor = desc
2270            .at_derivation_index(child)
2271            .expect("child can't be hardened");
2272
2273        psbt_input
2274            .update_with_descriptor_unchecked(&derived_descriptor)
2275            .map_err(MiniscriptPsbtError::Conversion)?;
2276
2277        let prev_output = utxo.outpoint;
2278        if let Some(prev_tx) = self.indexed_graph.graph().get_tx(prev_output.txid) {
2279            // We want to check that the prevout actually exists in the tx before continuing.
2280            let prevout = prev_tx.output.get(prev_output.vout as usize).ok_or(
2281                MiniscriptPsbtError::UtxoUpdate(miniscript::psbt::UtxoUpdateError::UtxoCheck),
2282            )?;
2283            if desc.is_witness() || desc.is_taproot() {
2284                psbt_input.witness_utxo = Some(prevout.clone());
2285            }
2286            if !desc.is_taproot() && (!desc.is_witness() || !only_witness_utxo) {
2287                psbt_input.non_witness_utxo = Some(prev_tx.as_ref().clone());
2288            }
2289        }
2290        Ok(psbt_input)
2291    }
2292
2293    fn update_psbt_with_descriptor(&self, psbt: &mut Psbt) -> Result<(), MiniscriptPsbtError> {
2294        // We need to borrow `psbt` mutably within the loops, so we have to allocate a vec for all
2295        // the input utxos and outputs
2296        let utxos = (0..psbt.inputs.len())
2297            .filter_map(|i| psbt.get_utxo_for(i).map(|utxo| (true, i, utxo)))
2298            .chain(
2299                psbt.unsigned_tx
2300                    .output
2301                    .iter()
2302                    .enumerate()
2303                    .map(|(i, out)| (false, i, out.clone())),
2304            )
2305            .collect::<Vec<_>>();
2306
2307        // Try to figure out the keychain and derivation for every input and output
2308        for (is_input, index, out) in utxos.into_iter() {
2309            if let Some(&(keychain, child)) =
2310                self.indexed_graph.index.index_of_spk(out.script_pubkey)
2311            {
2312                let desc = self.public_descriptor(keychain);
2313                let desc = desc
2314                    .at_derivation_index(child)
2315                    .expect("child can't be hardened");
2316
2317                if is_input {
2318                    psbt.update_input_with_descriptor(index, &desc)
2319                        .map_err(MiniscriptPsbtError::UtxoUpdate)?;
2320                } else {
2321                    psbt.update_output_with_descriptor(index, &desc)
2322                        .map_err(MiniscriptPsbtError::OutputUpdate)?;
2323                }
2324            }
2325        }
2326
2327        Ok(())
2328    }
2329
2330    /// Return the checksum of the public descriptor associated to `keychain`
2331    ///
2332    /// Internally calls [`Self::public_descriptor`] to fetch the right descriptor
2333    pub fn descriptor_checksum(&self, keychain: KeychainKind) -> String {
2334        self.public_descriptor(keychain)
2335            .to_string()
2336            .split_once('#')
2337            .unwrap()
2338            .1
2339            .to_string()
2340    }
2341
2342    /// Applies an update to the wallet and stages the changes (but does not persist them).
2343    ///
2344    /// Usually you create an `update` by interacting with some blockchain data source and inserting
2345    /// transactions related to your wallet into it.
2346    ///
2347    /// After applying updates you should persist the staged wallet changes. For an example of how
2348    /// to persist staged wallet changes see [`Wallet::reveal_next_address`].
2349    pub fn apply_update(&mut self, update: impl Into<Update>) -> Result<(), CannotConnectError> {
2350        let update = update.into();
2351        let mut changeset = match update.chain {
2352            Some(chain_update) => ChangeSet::from(self.chain.apply_update(chain_update)?),
2353            None => ChangeSet::default(),
2354        };
2355
2356        let index_changeset = self
2357            .indexed_graph
2358            .index
2359            .reveal_to_target_multi(&update.last_active_indices);
2360        changeset.merge(index_changeset.into());
2361        changeset.merge(self.indexed_graph.apply_update(update.tx_update).into());
2362        self.stage.merge(changeset);
2363        Ok(())
2364    }
2365
2366    /// Applies an update to the wallet, stages the changes, and returns events.
2367    ///
2368    /// Usually you create an `update` by interacting with some blockchain data source and inserting
2369    /// transactions related to your wallet into it. Staged changes are NOT persisted.
2370    ///
2371    /// After applying updates you should process the events in your app before persisting the
2372    /// staged wallet changes. For an example of how to persist staged wallet changes see
2373    /// [`Wallet::reveal_next_address`].
2374    ///
2375    /// ```rust,no_run
2376    /// # use bitcoin::*;
2377    /// # use bdk_wallet::*;
2378    /// use bdk_wallet::event::WalletEvent;
2379    /// # let wallet_update = Update::default();
2380    /// # let mut wallet = doctest_wallet!();
2381    /// let events = wallet.apply_update_events(wallet_update)?;
2382    /// // Handle wallet relevant events from this update.
2383    /// events.iter().for_each(|event| {
2384    ///     match event {
2385    ///         // The chain tip changed.
2386    ///         WalletEvent::ChainTipChanged { old_tip, new_tip } => {
2387    ///             todo!() // handle event
2388    ///         }
2389    ///         // An unconfirmed tx is now confirmed in a block.
2390    ///         WalletEvent::TxConfirmed {
2391    ///             txid,
2392    ///             tx,
2393    ///             block_time,
2394    ///             old_block_time: None,
2395    ///         } => {
2396    ///             todo!() // handle event
2397    ///         }
2398    ///         // A confirmed tx is now confirmed in a new block (reorg).
2399    ///         WalletEvent::TxConfirmed {
2400    ///             txid,
2401    ///             tx,
2402    ///             block_time,
2403    ///             old_block_time: Some(old_block_time),
2404    ///         } => {
2405    ///             todo!() // handle event
2406    ///         }
2407    ///         // A new unconfirmed tx was seen in the mempool.
2408    ///         WalletEvent::TxUnconfirmed {
2409    ///             txid,
2410    ///             tx,
2411    ///             old_block_time: None,
2412    ///         } => {
2413    ///             todo!() // handle event
2414    ///         }
2415    ///         // A previously confirmed tx in now unconfirmed in the mempool (reorg).
2416    ///         WalletEvent::TxUnconfirmed {
2417    ///             txid,
2418    ///             tx,
2419    ///             old_block_time: Some(old_block_time),
2420    ///         } => {
2421    ///             todo!() // handle event
2422    ///         }
2423    ///         // An unconfirmed tx was replaced in the mempool (RBF or double spent input).
2424    ///         WalletEvent::TxReplaced {
2425    ///             txid,
2426    ///             tx,
2427    ///             conflicts,
2428    ///         } => {
2429    ///             todo!() // handle event
2430    ///         }
2431    ///         // An unconfirmed tx was dropped from the mempool (fee too low).
2432    ///         WalletEvent::TxDropped { txid, tx } => {
2433    ///             todo!() // handle event
2434    ///         }
2435    ///         _ => {
2436    ///             // unexpected event, do nothing
2437    ///         }
2438    ///     }
2439    ///     // take staged wallet changes
2440    ///     let staged = wallet.take_staged();
2441    ///     // persist staged changes
2442    /// });
2443    /// # Ok::<(), anyhow::Error>(())
2444    /// ```
2445    /// [`TxBuilder`]: crate::TxBuilder
2446    pub fn apply_update_events(
2447        &mut self,
2448        update: impl Into<Update>,
2449    ) -> Result<Vec<WalletEvent>, CannotConnectError> {
2450        // snapshot of chain tip and transactions before update
2451        let chain_tip1 = self.chain.tip().block_id();
2452        let wallet_txs1 = self
2453            .transactions()
2454            .map(|wtx| {
2455                (
2456                    wtx.tx_node.txid,
2457                    (wtx.tx_node.tx.clone(), wtx.chain_position),
2458                )
2459            })
2460            .collect::<BTreeMap<Txid, (Arc<Transaction>, ChainPosition<ConfirmationBlockTime>)>>();
2461
2462        // apply update
2463        self.apply_update(update)?;
2464
2465        // chain tip and transactions after update
2466        let chain_tip2 = self.chain.tip().block_id();
2467        let wallet_txs2 = self
2468            .transactions()
2469            .map(|wtx| {
2470                (
2471                    wtx.tx_node.txid,
2472                    (wtx.tx_node.tx.clone(), wtx.chain_position),
2473                )
2474            })
2475            .collect::<BTreeMap<Txid, (Arc<Transaction>, ChainPosition<ConfirmationBlockTime>)>>();
2476
2477        Ok(wallet_events(
2478            self,
2479            chain_tip1,
2480            chain_tip2,
2481            wallet_txs1,
2482            wallet_txs2,
2483        ))
2484    }
2485
2486    /// Get a reference of the staged [`ChangeSet`] that is yet to be committed (if any).
2487    pub fn staged(&self) -> Option<&ChangeSet> {
2488        if self.stage.is_empty() {
2489            None
2490        } else {
2491            Some(&self.stage)
2492        }
2493    }
2494
2495    /// Get a mutable reference of the staged [`ChangeSet`] that is yet to be committed (if any).
2496    pub fn staged_mut(&mut self) -> Option<&mut ChangeSet> {
2497        if self.stage.is_empty() {
2498            None
2499        } else {
2500            Some(&mut self.stage)
2501        }
2502    }
2503
2504    /// Take the staged [`ChangeSet`] to be persisted now (if any).
2505    pub fn take_staged(&mut self) -> Option<ChangeSet> {
2506        self.stage.take()
2507    }
2508
2509    /// Get a reference to the inner [`TxGraph`].
2510    pub fn tx_graph(&self) -> &TxGraph<ConfirmationBlockTime> {
2511        self.indexed_graph.graph()
2512    }
2513
2514    /// Get a reference to the inner [`KeychainTxOutIndex`].
2515    pub fn spk_index(&self) -> &KeychainTxOutIndex<KeychainKind> {
2516        &self.indexed_graph.index
2517    }
2518
2519    /// Get a reference to the inner [`LocalChain`].
2520    pub fn local_chain(&self) -> &LocalChain {
2521        &self.chain
2522    }
2523
2524    /// Introduces a `block` of `height` to the wallet, and tries to connect it to the
2525    /// `prev_blockhash` of the block's header.
2526    ///
2527    /// This is a convenience method that is equivalent to calling [`apply_block_connected_to`]
2528    /// with `prev_blockhash` and `height-1` as the `connected_to` parameter.
2529    ///
2530    /// [`apply_block_connected_to`]: Self::apply_block_connected_to
2531    pub fn apply_block(&mut self, block: &Block, height: u32) -> Result<(), CannotConnectError> {
2532        let connected_to = match height.checked_sub(1) {
2533            Some(prev_height) => BlockId {
2534                height: prev_height,
2535                hash: block.header.prev_blockhash,
2536            },
2537            None => BlockId {
2538                height,
2539                hash: block.block_hash(),
2540            },
2541        };
2542        self.apply_block_connected_to(block, height, connected_to)
2543            .map_err(|err| match err {
2544                ApplyHeaderError::InconsistentBlocks => {
2545                    unreachable!("connected_to is derived from the block so must be consistent")
2546                }
2547                ApplyHeaderError::CannotConnect(err) => err,
2548            })
2549    }
2550
2551    /// Introduces a `block` of `height` to the wallet, and tries to connect it to the
2552    /// `prev_blockhash` of the block's header.
2553    ///
2554    /// This is a convenience method that is equivalent to calling
2555    /// [`apply_block_connected_to_events`] with `prev_blockhash` and `height-1` as the
2556    /// `connected_to` parameter.
2557    ///
2558    /// See [`apply_update_events`] for more information on the returned [`WalletEvent`]s.
2559    ///
2560    /// [`apply_block_connected_to_events`]: Self::apply_block_connected_to_events
2561    /// [`apply_update_events`]: Self::apply_update_events
2562    pub fn apply_block_events(
2563        &mut self,
2564        block: &Block,
2565        height: u32,
2566    ) -> Result<Vec<WalletEvent>, CannotConnectError> {
2567        // snapshot of chain tip and transactions before update
2568        let chain_tip1 = self.chain.tip().block_id();
2569        let wallet_txs1 = self
2570            .transactions()
2571            .map(|wtx| {
2572                (
2573                    wtx.tx_node.txid,
2574                    (wtx.tx_node.tx.clone(), wtx.chain_position),
2575                )
2576            })
2577            .collect::<BTreeMap<Txid, (Arc<Transaction>, ChainPosition<ConfirmationBlockTime>)>>();
2578
2579        self.apply_block(block, height)?;
2580
2581        // chain tip and transactions after update
2582        let chain_tip2 = self.chain.tip().block_id();
2583        let wallet_txs2 = self
2584            .transactions()
2585            .map(|wtx| {
2586                (
2587                    wtx.tx_node.txid,
2588                    (wtx.tx_node.tx.clone(), wtx.chain_position),
2589                )
2590            })
2591            .collect::<BTreeMap<Txid, (Arc<Transaction>, ChainPosition<ConfirmationBlockTime>)>>();
2592
2593        Ok(wallet_events(
2594            self,
2595            chain_tip1,
2596            chain_tip2,
2597            wallet_txs1,
2598            wallet_txs2,
2599        ))
2600    }
2601
2602    /// Applies relevant transactions from `block` of `height` to the wallet, and connects the
2603    /// block to the internal chain.
2604    ///
2605    /// The `connected_to` parameter informs the wallet how this block connects to the internal
2606    /// [`LocalChain`]. Relevant transactions are filtered from the `block` and inserted into the
2607    /// internal [`TxGraph`].
2608    ///
2609    /// **WARNING**: You must persist the changes resulting from one or more calls to this method
2610    /// if you need the inserted block data to be reloaded after closing the wallet.
2611    /// See [`Wallet::reveal_next_address`].
2612    pub fn apply_block_connected_to(
2613        &mut self,
2614        block: &Block,
2615        height: u32,
2616        connected_to: BlockId,
2617    ) -> Result<(), ApplyHeaderError> {
2618        let mut changeset = ChangeSet::default();
2619        changeset.merge(
2620            self.chain
2621                .apply_header_connected_to(&block.header, height, connected_to)?
2622                .into(),
2623        );
2624        changeset.merge(
2625            self.indexed_graph
2626                .apply_block_relevant(block, height)
2627                .into(),
2628        );
2629        self.stage.merge(changeset);
2630        Ok(())
2631    }
2632
2633    /// Applies relevant transactions from `block` of `height` to the wallet, and connects the
2634    /// block to the internal chain.
2635    ///
2636    /// See [`apply_block_connected_to`] for more information.
2637    ///
2638    /// See [`apply_update_events`] for more information on the returned [`WalletEvent`]s.
2639    ///
2640    /// [`apply_block_connected_to`]: Self::apply_block_connected_to
2641    /// [`apply_update_events`]: Self::apply_update_events
2642    pub fn apply_block_connected_to_events(
2643        &mut self,
2644        block: &Block,
2645        height: u32,
2646        connected_to: BlockId,
2647    ) -> Result<Vec<WalletEvent>, ApplyHeaderError> {
2648        // snapshot of chain tip and transactions before update
2649        let chain_tip1 = self.chain.tip().block_id();
2650        let wallet_txs1 = self
2651            .transactions()
2652            .map(|wtx| {
2653                (
2654                    wtx.tx_node.txid,
2655                    (wtx.tx_node.tx.clone(), wtx.chain_position),
2656                )
2657            })
2658            .collect::<BTreeMap<Txid, (Arc<Transaction>, ChainPosition<ConfirmationBlockTime>)>>();
2659
2660        self.apply_block_connected_to(block, height, connected_to)?;
2661
2662        // chain tip and transactions after update
2663        let chain_tip2 = self.chain.tip().block_id();
2664        let wallet_txs2 = self
2665            .transactions()
2666            .map(|wtx| {
2667                (
2668                    wtx.tx_node.txid,
2669                    (wtx.tx_node.tx.clone(), wtx.chain_position),
2670                )
2671            })
2672            .collect::<BTreeMap<Txid, (Arc<Transaction>, ChainPosition<ConfirmationBlockTime>)>>();
2673
2674        Ok(wallet_events(
2675            self,
2676            chain_tip1,
2677            chain_tip2,
2678            wallet_txs1,
2679            wallet_txs2,
2680        ))
2681    }
2682
2683    /// Apply relevant unconfirmed transactions to the wallet.
2684    ///
2685    /// Transactions that are not relevant are filtered out.
2686    ///
2687    /// This method takes in an iterator of `(tx, last_seen)` where `last_seen` is the timestamp of
2688    /// when the transaction was last seen in the mempool. This is used for conflict resolution
2689    /// when there is conflicting unconfirmed transactions. The transaction with the later
2690    /// `last_seen` is prioritized.
2691    ///
2692    /// **WARNING**: You must persist the changes resulting from one or more calls to this method
2693    /// if you need the applied unconfirmed transactions to be reloaded after closing the wallet.
2694    /// See [`Wallet::reveal_next_address`].
2695    pub fn apply_unconfirmed_txs<T: Into<Arc<Transaction>>>(
2696        &mut self,
2697        unconfirmed_txs: impl IntoIterator<Item = (T, u64)>,
2698    ) {
2699        let indexed_graph_changeset = self
2700            .indexed_graph
2701            .batch_insert_relevant_unconfirmed(unconfirmed_txs);
2702        self.stage.merge(indexed_graph_changeset.into());
2703    }
2704
2705    /// Apply evictions of the given transaction IDs with their associated timestamps.
2706    ///
2707    /// This function is used to mark specific unconfirmed transactions as evicted from the mempool.
2708    /// Eviction means that these transactions are not considered canonical by default, and will
2709    /// no longer be part of the wallet's [`transactions`] set. This can happen for example when
2710    /// a transaction is dropped from the mempool due to low fees or conflicts with another
2711    /// transaction.
2712    ///
2713    /// Only transactions that are currently unconfirmed and canonical are considered for eviction.
2714    /// Transactions that are not relevant to the wallet are ignored. Note that an evicted
2715    /// transaction can become canonical again if it is later observed on-chain or seen in the
2716    /// mempool with a higher priority (e.g., due to a fee bump).
2717    ///
2718    /// ## Parameters
2719    ///
2720    /// `evicted_txs`: An iterator of `(Txid, u64)` tuples, where:
2721    /// - `Txid`: The transaction ID of the transaction to be evicted.
2722    /// - `u64`: The timestamp indicating when the transaction was evicted from the mempool. This
2723    ///   will usually correspond to the time of the latest chain sync. See docs for
2724    ///   [`start_sync_with_revealed_spks`].
2725    ///
2726    /// ## Notes
2727    ///
2728    /// - Not all blockchain backends support automatic mempool eviction handling - this method may
2729    ///   be used in such cases. It can also be used to negate the effect of
2730    ///   [`apply_unconfirmed_txs`] for a particular transaction without the need for an additional
2731    ///   sync.
2732    /// - The changes are staged in the wallet's internal state and must be persisted to ensure they
2733    ///   are retained across wallet restarts. Use [`Wallet::take_staged`] to retrieve the staged
2734    ///   changes and persist them to your database of choice.
2735    /// - Evicted transactions are removed from the wallet's canonical transaction set, but the data
2736    ///   remains in the wallet's internal transaction graph for historical purposes.
2737    /// - Ensure that the timestamps provided are accurate and monotonically increasing, as they
2738    ///   influence the wallet's canonicalization logic.
2739    ///
2740    /// [`transactions`]: Wallet::transactions
2741    /// [`apply_unconfirmed_txs`]: Wallet::apply_unconfirmed_txs
2742    /// [`start_sync_with_revealed_spks`]: Wallet::start_sync_with_revealed_spks
2743    pub fn apply_evicted_txs(&mut self, evicted_txs: impl IntoIterator<Item = (Txid, u64)>) {
2744        let chain = &self.chain;
2745        let canon_txids: Vec<Txid> = self
2746            .indexed_graph
2747            .graph()
2748            .list_canonical_txs(
2749                chain,
2750                chain.tip().block_id(),
2751                CanonicalizationParams::default(),
2752            )
2753            .map(|c| c.tx_node.txid)
2754            .collect();
2755
2756        let changeset = self.indexed_graph.batch_insert_relevant_evicted_at(
2757            evicted_txs
2758                .into_iter()
2759                .filter(|(txid, _)| canon_txids.contains(txid)),
2760        );
2761
2762        self.stage.merge(changeset.into());
2763    }
2764
2765    /// Used internally to ensure that all methods requiring a [`KeychainKind`] will use a
2766    /// keychain with an associated descriptor. For example in case the wallet was created
2767    /// with only one keychain, passing [`KeychainKind::Internal`] here will instead return
2768    /// [`KeychainKind::External`].
2769    fn map_keychain(&self, keychain: KeychainKind) -> KeychainKind {
2770        if self.keychains().count() == 1 {
2771            KeychainKind::External
2772        } else {
2773            keychain
2774        }
2775    }
2776}
2777
2778/// Methods to construct sync/full-scan requests for spk-based chain sources.
2779impl Wallet {
2780    /// Create a partial [`SyncRequest`] for all revealed spks at `start_time`.
2781    ///
2782    /// The `start_time` is used to record the time that a mempool transaction was last seen
2783    /// (or evicted). See [`Wallet::start_sync_with_revealed_spks`] for more.
2784    pub fn start_sync_with_revealed_spks_at(
2785        &self,
2786        start_time: u64,
2787    ) -> SyncRequestBuilder<(KeychainKind, u32)> {
2788        use bdk_chain::keychain_txout::SyncRequestBuilderExt;
2789        SyncRequest::builder_at(start_time)
2790            .chain_tip(self.chain.tip())
2791            .revealed_spks_from_indexer(&self.indexed_graph.index, ..)
2792            .expected_spk_txids(self.indexed_graph.list_expected_spk_txids(
2793                &self.chain,
2794                self.chain.tip().block_id(),
2795                ..,
2796            ))
2797    }
2798
2799    /// Create a partial [`SyncRequest`] for this wallet for all revealed spks.
2800    ///
2801    /// This is the first step when performing a spk-based wallet partial sync, the returned
2802    /// [`SyncRequest`] collects all revealed script pubkeys from the wallet keychain needed to
2803    /// start a blockchain sync with a spk based blockchain client.
2804    ///
2805    /// The time of the sync is the current system time and is used to record the
2806    /// tx last-seen for mempool transactions. Or if an expected transaction is missing
2807    /// or evicted, it is the time of the eviction. Note that timestamps may only increase
2808    /// to be counted by the tx graph. To supply your own start time see
2809    /// [`Wallet::start_sync_with_revealed_spks_at`].
2810    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
2811    #[cfg(feature = "std")]
2812    pub fn start_sync_with_revealed_spks(&self) -> SyncRequestBuilder<(KeychainKind, u32)> {
2813        use bdk_chain::keychain_txout::SyncRequestBuilderExt;
2814        SyncRequest::builder()
2815            .chain_tip(self.chain.tip())
2816            .revealed_spks_from_indexer(&self.indexed_graph.index, ..)
2817            .expected_spk_txids(self.indexed_graph.list_expected_spk_txids(
2818                &self.chain,
2819                self.chain.tip().block_id(),
2820                ..,
2821            ))
2822    }
2823
2824    /// Create a [`FullScanRequest] for this wallet.
2825    ///
2826    /// This is the first step when performing a spk-based wallet full scan, the returned
2827    /// [`FullScanRequest] collects iterators for the wallet's keychain script pub keys needed to
2828    /// start a blockchain full scan with a spk based blockchain client.
2829    ///
2830    /// This operation is generally only used when importing or restoring a previously used wallet
2831    /// in which the list of used scripts is not known.
2832    ///
2833    /// The time of the scan is the current system time and is used to record the tx last-seen for
2834    /// mempool transactions. To supply your own start time see [`Wallet::start_full_scan_at`].
2835    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
2836    #[cfg(feature = "std")]
2837    pub fn start_full_scan(&self) -> FullScanRequestBuilder<KeychainKind> {
2838        use bdk_chain::keychain_txout::FullScanRequestBuilderExt;
2839        FullScanRequest::builder()
2840            .chain_tip(self.chain.tip())
2841            .spks_from_indexer(&self.indexed_graph.index)
2842    }
2843
2844    /// Create a [`FullScanRequest`] builder at `start_time`.
2845    pub fn start_full_scan_at(&self, start_time: u64) -> FullScanRequestBuilder<KeychainKind> {
2846        use bdk_chain::keychain_txout::FullScanRequestBuilderExt;
2847        FullScanRequest::builder_at(start_time)
2848            .chain_tip(self.chain.tip())
2849            .spks_from_indexer(&self.indexed_graph.index)
2850    }
2851}
2852
2853impl AsRef<bdk_chain::tx_graph::TxGraph<ConfirmationBlockTime>> for Wallet {
2854    fn as_ref(&self) -> &bdk_chain::tx_graph::TxGraph<ConfirmationBlockTime> {
2855        self.indexed_graph.graph()
2856    }
2857}
2858
2859/// Deterministically generate a unique name given the descriptors defining the wallet
2860///
2861/// Compatible with [`wallet_name_from_descriptor`]
2862pub fn wallet_name_from_descriptor<T>(
2863    descriptor: T,
2864    change_descriptor: Option<T>,
2865    network: Network,
2866    secp: &SecpCtx,
2867) -> Result<String, DescriptorError>
2868where
2869    T: IntoWalletDescriptor,
2870{
2871    //TODO check descriptors contains only public keys
2872    let descriptor = descriptor
2873        .into_wallet_descriptor(secp, network)?
2874        .0
2875        .to_string();
2876    let mut wallet_name = descriptor.split_once('#').unwrap().1.to_string();
2877    if let Some(change_descriptor) = change_descriptor {
2878        let change_descriptor = change_descriptor
2879            .into_wallet_descriptor(secp, network)?
2880            .0
2881            .to_string();
2882        wallet_name.push_str(change_descriptor.split_once('#').unwrap().1);
2883    }
2884
2885    Ok(wallet_name)
2886}
2887
2888fn new_local_utxo(
2889    keychain: KeychainKind,
2890    derivation_index: u32,
2891    full_txo: FullTxOut<ConfirmationBlockTime>,
2892) -> LocalOutput {
2893    LocalOutput {
2894        outpoint: full_txo.outpoint,
2895        txout: full_txo.txout,
2896        is_spent: full_txo.spent_by.is_some(),
2897        chain_position: full_txo.chain_position,
2898        keychain,
2899        derivation_index,
2900    }
2901}
2902
2903fn make_indexed_graph(
2904    stage: &mut ChangeSet,
2905    tx_graph_changeset: chain::tx_graph::ChangeSet<ConfirmationBlockTime>,
2906    indexer_changeset: chain::keychain_txout::ChangeSet,
2907    descriptor: ExtendedDescriptor,
2908    change_descriptor: Option<ExtendedDescriptor>,
2909    lookahead: u32,
2910    use_spk_cache: bool,
2911) -> Result<IndexedTxGraph<ConfirmationBlockTime, KeychainTxOutIndex<KeychainKind>>, DescriptorError>
2912{
2913    let (indexed_graph, changeset) = IndexedTxGraph::from_changeset(
2914        chain::indexed_tx_graph::ChangeSet {
2915            tx_graph: tx_graph_changeset,
2916            indexer: indexer_changeset,
2917        },
2918        |idx_cs| -> Result<KeychainTxOutIndex<KeychainKind>, DescriptorError> {
2919            let mut idx = KeychainTxOutIndex::from_changeset(lookahead, use_spk_cache, idx_cs);
2920
2921            let descriptor_inserted = idx
2922                .insert_descriptor(KeychainKind::External, descriptor)
2923                .expect("already checked to be a unique, wildcard, non-multipath descriptor");
2924            assert!(
2925                descriptor_inserted,
2926                "this must be the first time we are seeing this descriptor"
2927            );
2928
2929            let change_descriptor = match change_descriptor {
2930                Some(change_descriptor) => change_descriptor,
2931                None => return Ok(idx),
2932            };
2933
2934            let change_descriptor_inserted = idx
2935                .insert_descriptor(KeychainKind::Internal, change_descriptor)
2936                .map_err(|e| {
2937                    use bdk_chain::indexer::keychain_txout::InsertDescriptorError;
2938                    match e {
2939                        InsertDescriptorError::DescriptorAlreadyAssigned { .. } => {
2940                            crate::descriptor::error::Error::ExternalAndInternalAreTheSame
2941                        }
2942                        InsertDescriptorError::KeychainAlreadyAssigned { .. } => {
2943                            unreachable!("this is the first time we're assigning internal")
2944                        }
2945                    }
2946                })?;
2947            assert!(
2948                change_descriptor_inserted,
2949                "this must be the first time we are seeing this descriptor"
2950            );
2951
2952            Ok(idx)
2953        },
2954    )?;
2955    stage.tx_graph.merge(changeset.tx_graph);
2956    stage.indexer.merge(changeset.indexer);
2957    Ok(indexed_graph)
2958}
2959
2960/// Transforms a [`FeeRate`] to `f64` with unit as sat/vb.
2961#[macro_export]
2962#[doc(hidden)]
2963macro_rules! floating_rate {
2964    ($rate:expr) => {{
2965        use $crate::bitcoin::constants::WITNESS_SCALE_FACTOR;
2966        // sat_kwu / 250.0 -> sat_vb
2967        $rate.to_sat_per_kwu() as f64 / ((1000 / WITNESS_SCALE_FACTOR) as f64)
2968    }};
2969}
2970
2971#[macro_export]
2972#[doc(hidden)]
2973/// Macro for getting a wallet for use in a doctest
2974macro_rules! doctest_wallet {
2975    () => {{
2976        use $crate::bitcoin::{BlockHash, Transaction, absolute, TxOut, Network, hashes::Hash};
2977        use $crate::chain::{ConfirmationBlockTime, BlockId, TxGraph, tx_graph};
2978        use $crate::{Update, KeychainKind, Wallet};
2979        use $crate::test_utils::*;
2980        let descriptor = "tr([73c5da0a/86'/0'/0']tprv8fMn4hSKPRC1oaCPqxDb1JWtgkpeiQvZhsr8W2xuy3GEMkzoArcAWTfJxYb6Wj8XNNDWEjfYKK4wGQXh3ZUXhDF2NcnsALpWTeSwarJt7Vc/0/*)";
2981        let change_descriptor = "tr([73c5da0a/86'/0'/0']tprv8fMn4hSKPRC1oaCPqxDb1JWtgkpeiQvZhsr8W2xuy3GEMkzoArcAWTfJxYb6Wj8XNNDWEjfYKK4wGQXh3ZUXhDF2NcnsALpWTeSwarJt7Vc/1/*)";
2982
2983        let mut wallet = Wallet::create(descriptor, change_descriptor)
2984            .network(Network::Regtest)
2985            .create_wallet_no_persist()
2986            .unwrap();
2987        let address = wallet.peek_address(KeychainKind::External, 0).address;
2988        let tx = Transaction {
2989            version: transaction::Version::TWO,
2990            lock_time: absolute::LockTime::ZERO,
2991            input: vec![],
2992            output: vec![TxOut {
2993                value: Amount::from_sat(500_000),
2994                script_pubkey: address.script_pubkey(),
2995            }],
2996        };
2997        let txid = tx.compute_txid();
2998        let block_id = BlockId { height: 500, hash: BlockHash::all_zeros() };
2999        insert_checkpoint(&mut wallet, block_id);
3000        insert_checkpoint(&mut wallet, BlockId { height: 1_000, hash: BlockHash::all_zeros() });
3001        insert_tx(&mut wallet, tx);
3002        let anchor = ConfirmationBlockTime {
3003            confirmation_time: 50_000,
3004            block_id,
3005        };
3006        insert_anchor(&mut wallet, txid, anchor);
3007        wallet
3008    }}
3009}
3010
3011#[cfg(test)]
3012mod test {
3013    use super::*;
3014    use crate::miniscript::Error::Unexpected;
3015    use crate::test_utils::get_test_tr_single_sig_xprv_and_change_desc;
3016    use crate::test_utils::insert_tx;
3017
3018    #[test]
3019    fn not_duplicated_utxos_across_optional_and_required() {
3020        let (external_desc, internal_desc) = get_test_tr_single_sig_xprv_and_change_desc();
3021
3022        // create new wallet
3023        let mut wallet = Wallet::create(external_desc, internal_desc)
3024            .network(Network::Testnet)
3025            .create_wallet_no_persist()
3026            .unwrap();
3027
3028        let two_output_tx = Transaction {
3029            input: vec![],
3030            output: vec![
3031                TxOut {
3032                    script_pubkey: wallet
3033                        .next_unused_address(KeychainKind::External)
3034                        .script_pubkey(),
3035                    value: Amount::from_sat(25_000),
3036                },
3037                TxOut {
3038                    script_pubkey: wallet
3039                        .next_unused_address(KeychainKind::External)
3040                        .script_pubkey(),
3041                    value: Amount::from_sat(75_000),
3042                },
3043            ],
3044            version: transaction::Version::non_standard(0),
3045            lock_time: absolute::LockTime::ZERO,
3046        };
3047
3048        let txid = two_output_tx.compute_txid();
3049        insert_tx(&mut wallet, two_output_tx);
3050
3051        let outpoint = OutPoint { txid, vout: 0 };
3052        let mut builder = wallet.build_tx();
3053        builder.add_utxo(outpoint).expect("should add local utxo");
3054        let params = builder.params.clone();
3055        // enforce selection of first output in transaction
3056        let received = wallet.filter_utxos(&params, wallet.latest_checkpoint().block_id().height);
3057        // notice expected doesn't include the first output from two_output_tx as it should be
3058        // filtered out
3059        let expected = vec![wallet
3060            .get_utxo(OutPoint { txid, vout: 1 })
3061            .map(|utxo| WeightedUtxo {
3062                satisfaction_weight: wallet
3063                    .public_descriptor(utxo.keychain)
3064                    .max_weight_to_satisfy()
3065                    .unwrap(),
3066                utxo: Utxo::Local(utxo),
3067            })
3068            .unwrap()];
3069
3070        assert_eq!(expected, received);
3071    }
3072
3073    #[test]
3074    fn test_create_two_path_wallet() {
3075        let two_path_descriptor = "wpkh([9a6a2580/84'/1'/0']tpubDDnGNapGEY6AZAdQbfRJgMg9fvz8pUBrLwvyvUqEgcUfgzM6zc2eVK4vY9x9L5FJWdX8WumXuLEDV5zDZnTfbn87vLe9XceCFwTu9so9Kks/<0;1>/*)";
3076
3077        // Test successful creation of a two-path wallet
3078        let params = Wallet::create_from_two_path_descriptor(two_path_descriptor);
3079        let wallet = params.network(Network::Testnet).create_wallet_no_persist();
3080        assert!(wallet.is_ok());
3081
3082        let wallet = wallet.unwrap();
3083
3084        // Verify that the wallet has both external and internal keychains
3085        let keychains: Vec<_> = wallet.keychains().collect();
3086        assert_eq!(keychains.len(), 2);
3087
3088        // Verify that the descriptors are different (receive vs change)
3089        let external_desc = keychains
3090            .iter()
3091            .find(|(k, _)| *k == KeychainKind::External)
3092            .unwrap()
3093            .1;
3094        let internal_desc = keychains
3095            .iter()
3096            .find(|(k, _)| *k == KeychainKind::Internal)
3097            .unwrap()
3098            .1;
3099        assert_ne!(external_desc.to_string(), internal_desc.to_string());
3100
3101        // Verify that addresses can be generated
3102        let external_addr = wallet.peek_address(KeychainKind::External, 0);
3103        let internal_addr = wallet.peek_address(KeychainKind::Internal, 0);
3104        assert_ne!(external_addr.address, internal_addr.address);
3105    }
3106
3107    #[test]
3108    fn test_create_two_path_wallet_invalid_descriptor() {
3109        // Test with invalid single-path descriptor
3110        let single_path_descriptor = "wpkh([9a6a2580/84'/1'/0']tpubDDnGNapGEY6AZAdQbfRJgMg9fvz8pUBrLwvyvUqEgcUfgzM6zc2eVK4vY9x9L5FJWdX8WumXuLEDV5zDZnTfbn87vLe9XceCFwTu9so9Kks/0/*)";
3111        let params = Wallet::create_from_two_path_descriptor(single_path_descriptor);
3112        let wallet = params.network(Network::Testnet).create_wallet_no_persist();
3113        assert!(matches!(wallet, Err(DescriptorError::MultiPath)));
3114
3115        // Test with a private descriptor
3116        // You get a Miniscript(Unexpected("Can't make an extended private key with multiple paths
3117        // into a public key.")) error.
3118        let private_multipath_descriptor = "wpkh(tprv8ZgxMBicQKsPdWAHbugK2tjtVtRjKGixYVZUdL7xLHMgXZS6BFbFi1UDb1CHT25Z5PU1F9j7wGxwUiRhqz9E3nZRztikGUV6HoRDYcqPhM4/84'/1'/0'/<0;1>/*)";
3119        let params = Wallet::create_from_two_path_descriptor(private_multipath_descriptor);
3120        let wallet = params.network(Network::Testnet).create_wallet_no_persist();
3121        assert!(matches!(
3122            wallet,
3123            Err(DescriptorError::Miniscript(Unexpected(..)))
3124        ));
3125
3126        // Test with invalid 3-path multipath descriptor
3127        let three_path_descriptor = "wpkh([9a6a2580/84'/1'/0']tpubDDnGNapGEY6AZAdQbfRJgMg9fvz8pUBrLwvyvUqEgcUfgzM6zc2eVK4vY9x9L5FJWdX8WumXuLEDV5zDZnTfbn87vLe9XceCFwTu9so9Kks/<0;1;2>/*)";
3128        let params = Wallet::create_from_two_path_descriptor(three_path_descriptor);
3129        let wallet = params.network(Network::Testnet).create_wallet_no_persist();
3130        assert!(matches!(wallet, Err(DescriptorError::MultiPath)));
3131
3132        // Test with completely invalid descriptor
3133        let invalid_descriptor = "invalid_descriptor";
3134        let params = Wallet::create_from_two_path_descriptor(invalid_descriptor);
3135        let wallet = params.network(Network::Testnet).create_wallet_no_persist();
3136        assert!(wallet.is_err());
3137    }
3138}