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