• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

bitcoindevkit / bdk / 11232477681

08 Oct 2024 09:22AM UTC coverage: 82.541% (-0.05%) from 82.591%
11232477681

Pull #1643

github

web-flow
Merge a3d4eef77 into ec7342d80
Pull Request #1643: feat(chain,wallet)!: rm `ConfirmationTime`

76 of 78 new or added lines in 4 files covered. (97.44%)

10 existing lines in 2 files now uncovered.

11280 of 13666 relevant lines covered (82.54%)

14796.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.02
/crates/wallet/src/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
use crate::{
16
    collections::{BTreeMap, HashMap},
17
    descriptor::check_wallet_descriptor,
18
};
19
use alloc::{
20
    boxed::Box,
21
    string::{String, ToString},
22
    sync::Arc,
23
    vec::Vec,
24
};
25
pub use bdk_chain::Balance;
26
use bdk_chain::{
27
    indexed_tx_graph,
28
    indexer::keychain_txout::KeychainTxOutIndex,
29
    local_chain::{
30
        self, ApplyHeaderError, CannotConnectError, CheckPoint, CheckPointIter, LocalChain,
31
    },
32
    spk_client::{
33
        FullScanRequest, FullScanRequestBuilder, FullScanResult, SyncRequest, SyncRequestBuilder,
34
        SyncResult,
35
    },
36
    tx_graph::{CanonicalTx, TxGraph, TxNode, TxUpdate},
37
    BlockId, ChainPosition, ConfirmationBlockTime, DescriptorExt, FullTxOut, Indexed,
38
    IndexedTxGraph, Merge,
39
};
40
use bitcoin::sighash::{EcdsaSighashType, TapSighashType};
41
use bitcoin::{
42
    absolute, psbt, Address, Block, FeeRate, Network, OutPoint, ScriptBuf, Sequence, Transaction,
43
    TxOut, Txid, Witness,
44
};
45
use bitcoin::{consensus::encode::serialize, transaction, BlockHash, Psbt};
46
use bitcoin::{constants::genesis_block, Amount};
47
use bitcoin::{secp256k1::Secp256k1, Weight};
48
use core::cmp::Ordering;
49
use core::fmt;
50
use core::mem;
51
use core::ops::Deref;
52
use rand_core::RngCore;
53

54
use descriptor::error::Error as DescriptorError;
55
use miniscript::{
56
    descriptor::KeyMap,
57
    psbt::{PsbtExt, PsbtInputExt, PsbtInputSatisfier},
58
};
59

60
use bdk_chain::tx_graph::CalculateFeeError;
61

62
mod changeset;
63
pub mod coin_selection;
64
pub mod export;
65
mod params;
66
pub mod signer;
67
pub mod tx_builder;
68
pub use changeset::*;
69
pub use params::*;
70
mod persisted;
71
pub use persisted::*;
72
pub(crate) mod utils;
73

74
pub mod error;
75

76
pub use utils::IsDust;
77

78
use coin_selection::{DefaultCoinSelectionAlgorithm, InsufficientFunds};
79
use signer::{SignOptions, SignerOrdering, SignersContainer, TransactionSigner};
80
use tx_builder::{FeePolicy, TxBuilder, TxParams};
81
use utils::{check_nsequence_rbf, After, Older, SecpCtx};
82

83
use crate::descriptor::policy::BuildSatisfaction;
84
use crate::descriptor::{
85
    self, DerivedDescriptor, DescriptorMeta, ExtendedDescriptor, ExtractPolicy,
86
    IntoWalletDescriptor, Policy, XKeyUtils,
87
};
88
use crate::psbt::PsbtUtils;
89
use crate::signer::SignerError;
90
use crate::types::*;
91
use crate::wallet::coin_selection::Excess::{self, Change, NoChange};
92
use crate::wallet::error::{BuildFeeBumpError, CreateTxError, MiniscriptPsbtError};
93

94
const COINBASE_MATURITY: u32 = 100;
95

96
/// A Bitcoin wallet
97
///
98
/// The `Wallet` acts as a way of coherently interfacing with output descriptors and related transactions.
99
/// Its main components are:
100
///
101
/// 1. output *descriptors* from which it can derive addresses.
102
/// 2. [`signer`]s that can contribute signatures to addresses instantiated from the descriptors.
103
///
104
/// The user is responsible for loading and writing wallet changes which are represented as
105
/// [`ChangeSet`]s (see [`take_staged`]). Also see individual functions and example for instructions
106
/// on when [`Wallet`] state needs to be persisted.
107
///
108
/// The `Wallet` descriptor (external) and change descriptor (internal) must not derive the same
109
/// script pubkeys. See [`KeychainTxOutIndex::insert_descriptor()`] for more details.
110
///
111
/// [`signer`]: crate::signer
112
/// [`take_staged`]: Wallet::take_staged
113
#[derive(Debug)]
114
pub struct Wallet {
115
    signers: Arc<SignersContainer>,
116
    change_signers: Arc<SignersContainer>,
117
    chain: LocalChain,
118
    indexed_graph: IndexedTxGraph<ConfirmationBlockTime, KeychainTxOutIndex<KeychainKind>>,
119
    stage: ChangeSet,
120
    network: Network,
121
    secp: SecpCtx,
122
}
123

124
/// An update to [`Wallet`].
125
///
126
/// It updates [`KeychainTxOutIndex`], [`bdk_chain::TxGraph`] and [`local_chain::LocalChain`] atomically.
127
#[derive(Debug, Clone, Default)]
128
pub struct Update {
129
    /// Contains the last active derivation indices per keychain (`K`), which is used to update the
130
    /// [`KeychainTxOutIndex`].
131
    pub last_active_indices: BTreeMap<KeychainKind, u32>,
132

133
    /// Update for the wallet's internal [`TxGraph`].
134
    pub tx_update: TxUpdate<ConfirmationBlockTime>,
135

136
    /// Update for the wallet's internal [`LocalChain`].
137
    ///
138
    /// [`LocalChain`]: local_chain::LocalChain
139
    pub chain: Option<CheckPoint>,
140
}
141

142
impl From<FullScanResult<KeychainKind>> for Update {
143
    fn from(value: FullScanResult<KeychainKind>) -> Self {
×
144
        Self {
×
145
            last_active_indices: value.last_active_indices,
×
146
            tx_update: value.tx_update,
×
147
            chain: value.chain_update,
×
148
        }
×
149
    }
×
150
}
151

152
impl From<SyncResult> for Update {
153
    fn from(value: SyncResult) -> Self {
×
154
        Self {
×
155
            last_active_indices: BTreeMap::new(),
×
156
            tx_update: value.tx_update,
×
157
            chain: value.chain_update,
×
158
        }
×
159
    }
×
160
}
161

162
/// A derived address and the index it was found at.
163
/// For convenience this automatically derefs to `Address`
164
#[derive(Debug, Clone, PartialEq, Eq)]
165
pub struct AddressInfo {
166
    /// Child index of this address
167
    pub index: u32,
168
    /// Address
169
    pub address: Address,
170
    /// Type of keychain
171
    pub keychain: KeychainKind,
172
}
173

174
impl Deref for AddressInfo {
175
    type Target = Address;
176

177
    fn deref(&self) -> &Self::Target {
1,592✔
178
        &self.address
1,592✔
179
    }
1,592✔
180
}
181

182
impl fmt::Display for AddressInfo {
183
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208✔
184
        write!(f, "{}", self.address)
208✔
185
    }
208✔
186
}
187

188
/// The error type when loading a [`Wallet`] from a [`ChangeSet`].
189
#[derive(Debug, PartialEq)]
190
pub enum LoadError {
191
    /// There was a problem with the passed-in descriptor(s).
192
    Descriptor(crate::descriptor::DescriptorError),
193
    /// Data loaded from persistence is missing network type.
194
    MissingNetwork,
195
    /// Data loaded from persistence is missing genesis hash.
196
    MissingGenesis,
197
    /// Data loaded from persistence is missing descriptor.
198
    MissingDescriptor(KeychainKind),
199
    /// Data loaded is unexpected.
200
    Mismatch(LoadMismatch),
201
}
202

203
impl fmt::Display for LoadError {
204
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
×
205
        match self {
×
206
            LoadError::Descriptor(e) => e.fmt(f),
×
207
            LoadError::MissingNetwork => write!(f, "loaded data is missing network type"),
×
208
            LoadError::MissingGenesis => write!(f, "loaded data is missing genesis hash"),
×
209
            LoadError::MissingDescriptor(k) => {
×
210
                write!(f, "loaded data is missing descriptor for keychain {k:?}")
×
211
            }
212
            LoadError::Mismatch(mismatch) => write!(f, "data mismatch: {mismatch:?}"),
×
213
        }
214
    }
×
215
}
216

217
#[cfg(feature = "std")]
218
impl std::error::Error for LoadError {}
219

220
/// Represents a mismatch with what is loaded and what is expected from [`LoadParams`].
221
#[derive(Debug, PartialEq)]
222
pub enum LoadMismatch {
223
    /// Network does not match.
224
    Network {
225
        /// The network that is loaded.
226
        loaded: Network,
227
        /// The expected network.
228
        expected: Network,
229
    },
230
    /// Genesis hash does not match.
231
    Genesis {
232
        /// The genesis hash that is loaded.
233
        loaded: BlockHash,
234
        /// The expected genesis hash.
235
        expected: BlockHash,
236
    },
237
    /// Descriptor's [`DescriptorId`](bdk_chain::DescriptorId) does not match.
238
    Descriptor {
239
        /// Keychain identifying the descriptor.
240
        keychain: KeychainKind,
241
        /// The loaded descriptor.
242
        loaded: Option<ExtendedDescriptor>,
243
        /// The expected descriptor.
244
        expected: Option<ExtendedDescriptor>,
245
    },
246
}
247

248
impl From<LoadMismatch> for LoadError {
249
    fn from(mismatch: LoadMismatch) -> Self {
×
250
        Self::Mismatch(mismatch)
×
251
    }
×
252
}
253

254
impl<E> From<LoadMismatch> for LoadWithPersistError<E> {
255
    fn from(mismatch: LoadMismatch) -> Self {
×
256
        Self::InvalidChangeSet(LoadError::Mismatch(mismatch))
×
257
    }
×
258
}
259

260
/// An error that may occur when applying a block to [`Wallet`].
261
#[derive(Debug)]
262
pub enum ApplyBlockError {
263
    /// Occurs when the update chain cannot connect with original chain.
264
    CannotConnect(CannotConnectError),
265
    /// Occurs when the `connected_to` hash does not match the hash derived from `block`.
266
    UnexpectedConnectedToHash {
267
        /// Block hash of `connected_to`.
268
        connected_to_hash: BlockHash,
269
        /// Expected block hash of `connected_to`, as derived from `block`.
270
        expected_hash: BlockHash,
271
    },
272
}
273

274
impl fmt::Display for ApplyBlockError {
275
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
×
276
        match self {
×
277
            ApplyBlockError::CannotConnect(err) => err.fmt(f),
×
278
            ApplyBlockError::UnexpectedConnectedToHash {
279
                expected_hash: block_hash,
×
280
                connected_to_hash: checkpoint_hash,
×
281
            } => write!(
×
282
                f,
×
283
                "`connected_to` hash {} differs from the expected hash {} (which is derived from `block`)",
×
284
                checkpoint_hash, block_hash
×
285
            ),
×
286
        }
287
    }
×
288
}
289

290
#[cfg(feature = "std")]
291
impl std::error::Error for ApplyBlockError {}
292

293
/// A `CanonicalTx` managed by a `Wallet`.
294
pub type WalletTx<'a> = CanonicalTx<'a, Arc<Transaction>, ConfirmationBlockTime>;
295

296
impl Wallet {
297
    /// Build a new single descriptor [`Wallet`].
298
    ///
299
    /// If you have previously created a wallet, use [`load`](Self::load) instead.
300
    ///
301
    /// # Note
302
    ///
303
    /// Only use this method when creating a wallet designed to be used with a single
304
    /// descriptor and keychain. Otherwise the recommended way to construct a new wallet is
305
    /// by using [`Wallet::create`]. It's worth noting that not all features are available
306
    /// with single descriptor wallets, for example setting a [`change_policy`] on [`TxBuilder`]
307
    /// and related methods such as [`do_not_spend_change`]. This is because all payments are
308
    /// received on the external keychain (including change), and without a change keychain
309
    /// BDK lacks enough information to distinguish between change and outside payments.
310
    ///
311
    /// Additionally because this wallet has no internal (change) keychain, all methods that
312
    /// require a [`KeychainKind`] as input, e.g. [`reveal_next_address`] should only be called
313
    /// using the [`External`] variant. In most cases passing [`Internal`] is treated as the
314
    /// equivalent of [`External`] but this behavior must not be relied on.
315
    ///
316
    /// # Example
317
    ///
318
    /// ```rust
319
    /// # use bdk_wallet::Wallet;
320
    /// # use bitcoin::Network;
321
    /// # const EXTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
322
    /// # let temp_dir = tempfile::tempdir().expect("must create tempdir");
323
    /// # let file_path = temp_dir.path().join("store.db");
324
    /// // Create a wallet that is persisted to SQLite database.
325
    /// use bdk_wallet::rusqlite::Connection;
326
    /// let mut conn = Connection::open(file_path)?;
327
    /// let wallet = Wallet::create_single(EXTERNAL_DESC)
328
    ///     .network(Network::Testnet)
329
    ///     .create_wallet(&mut conn)?;
330
    /// # Ok::<_, anyhow::Error>(())
331
    /// ```
332
    /// [`change_policy`]: TxBuilder::change_policy
333
    /// [`do_not_spend_change`]: TxBuilder::do_not_spend_change
334
    /// [`External`]: KeychainKind::External
335
    /// [`Internal`]: KeychainKind::Internal
336
    /// [`reveal_next_address`]: Self::reveal_next_address
337
    pub fn create_single<D>(descriptor: D) -> CreateParams
6✔
338
    where
6✔
339
        D: IntoWalletDescriptor + Send + Clone + 'static,
6✔
340
    {
6✔
341
        CreateParams::new_single(descriptor)
6✔
342
    }
6✔
343

344
    /// Build a new [`Wallet`].
345
    ///
346
    /// If you have previously created a wallet, use [`load`](Self::load) instead.
347
    ///
348
    /// # Synopsis
349
    ///
350
    /// ```rust
351
    /// # use bdk_wallet::Wallet;
352
    /// # use bitcoin::Network;
353
    /// # fn main() -> anyhow::Result<()> {
354
    /// # const EXTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
355
    /// # const INTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
356
    /// // Create a non-persisted wallet.
357
    /// let wallet = Wallet::create(EXTERNAL_DESC, INTERNAL_DESC)
358
    ///     .network(Network::Testnet)
359
    ///     .create_wallet_no_persist()?;
360
    ///
361
    /// // Create a wallet that is persisted to SQLite database.
362
    /// # let temp_dir = tempfile::tempdir().expect("must create tempdir");
363
    /// # let file_path = temp_dir.path().join("store.db");
364
    /// use bdk_wallet::rusqlite::Connection;
365
    /// let mut conn = Connection::open(file_path)?;
366
    /// let wallet = Wallet::create(EXTERNAL_DESC, INTERNAL_DESC)
367
    ///     .network(Network::Testnet)
368
    ///     .create_wallet(&mut conn)?;
369
    /// # Ok(())
370
    /// # }
371
    /// ```
372
    pub fn create<D>(descriptor: D, change_descriptor: D) -> CreateParams
158✔
373
    where
158✔
374
        D: IntoWalletDescriptor + Send + Clone + 'static,
158✔
375
    {
158✔
376
        CreateParams::new(descriptor, change_descriptor)
158✔
377
    }
158✔
378

379
    /// Create a new [`Wallet`] with given `params`.
380
    ///
381
    /// Refer to [`Wallet::create`] for more.
382
    pub fn create_with_params(params: CreateParams) -> Result<Self, DescriptorError> {
1,478✔
383
        let secp = SecpCtx::new();
1,478✔
384
        let network = params.network;
1,478✔
385
        let genesis_hash = params
1,478✔
386
            .genesis_hash
1,478✔
387
            .unwrap_or(genesis_block(network).block_hash());
1,478✔
388
        let (chain, chain_changeset) = LocalChain::from_genesis_hash(genesis_hash);
1,478✔
389

390
        let (descriptor, mut descriptor_keymap) = (params.descriptor)(&secp, network)?;
1,478✔
391
        check_wallet_descriptor(&descriptor)?;
1,478✔
392
        descriptor_keymap.extend(params.descriptor_keymap);
1,478✔
393

1,478✔
394
        let signers = Arc::new(SignersContainer::build(
1,478✔
395
            descriptor_keymap,
1,478✔
396
            &descriptor,
1,478✔
397
            &secp,
1,478✔
398
        ));
1,478✔
399

400
        let (change_descriptor, change_signers) = match params.change_descriptor {
1,478✔
401
            Some(make_desc) => {
1,422✔
402
                let (change_descriptor, mut internal_keymap) = make_desc(&secp, network)?;
1,422✔
403
                check_wallet_descriptor(&change_descriptor)?;
1,422✔
404
                internal_keymap.extend(params.change_descriptor_keymap);
1,422✔
405
                let change_signers = Arc::new(SignersContainer::build(
1,422✔
406
                    internal_keymap,
1,422✔
407
                    &change_descriptor,
1,422✔
408
                    &secp,
1,422✔
409
                ));
1,422✔
410
                (Some(change_descriptor), change_signers)
1,422✔
411
            }
412
            None => (None, Arc::new(SignersContainer::new())),
56✔
413
        };
414

415
        let index = create_indexer(descriptor, change_descriptor, params.lookahead)?;
1,478✔
416

417
        let descriptor = index.get_descriptor(KeychainKind::External).cloned();
1,454✔
418
        let change_descriptor = index.get_descriptor(KeychainKind::Internal).cloned();
1,454✔
419
        let indexed_graph = IndexedTxGraph::new(index);
1,454✔
420
        let indexed_graph_changeset = indexed_graph.initial_changeset();
1,454✔
421

1,454✔
422
        let stage = ChangeSet {
1,454✔
423
            descriptor,
1,454✔
424
            change_descriptor,
1,454✔
425
            local_chain: chain_changeset,
1,454✔
426
            tx_graph: indexed_graph_changeset.tx_graph,
1,454✔
427
            indexer: indexed_graph_changeset.indexer,
1,454✔
428
            network: Some(network),
1,454✔
429
        };
1,454✔
430

1,454✔
431
        Ok(Wallet {
1,454✔
432
            signers,
1,454✔
433
            change_signers,
1,454✔
434
            network,
1,454✔
435
            chain,
1,454✔
436
            indexed_graph,
1,454✔
437
            stage,
1,454✔
438
            secp,
1,454✔
439
        })
1,454✔
440
    }
1,470✔
441

442
    /// Build [`Wallet`] by loading from persistence or [`ChangeSet`].
443
    ///
444
    /// Note that the descriptor secret keys are not persisted to the db. You can add
445
    /// signers after-the-fact with [`Wallet::add_signer`] or [`Wallet::set_keymap`]. You
446
    /// can also add keys when building the wallet by using [`LoadParams::keymap`]. Finally
447
    /// you can check the wallet's descriptors are what you expect with [`LoadParams::descriptor`]
448
    /// which will try to populate signers if [`LoadParams::extract_keys`] is enabled.
449
    ///
450
    /// # Synopsis
451
    ///
452
    /// ```rust,no_run
453
    /// # use bdk_wallet::{Wallet, ChangeSet, KeychainKind};
454
    /// # use bitcoin::{BlockHash, Network, hashes::Hash};
455
    /// # fn main() -> anyhow::Result<()> {
456
    /// # const EXTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
457
    /// # const INTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
458
    /// # let changeset = ChangeSet::default();
459
    /// // Load a wallet from changeset (no persistence).
460
    /// let wallet = Wallet::load()
461
    ///     .load_wallet_no_persist(changeset)?
462
    ///     .expect("must have data to load wallet");
463
    ///
464
    /// // Load a wallet that is persisted to SQLite database.
465
    /// # let temp_dir = tempfile::tempdir().expect("must create tempdir");
466
    /// # let file_path = temp_dir.path().join("store.db");
467
    /// # let external_keymap = Default::default();
468
    /// # let internal_keymap = Default::default();
469
    /// # let genesis_hash = BlockHash::all_zeros();
470
    /// let mut conn = bdk_wallet::rusqlite::Connection::open(file_path)?;
471
    /// let mut wallet = Wallet::load()
472
    ///     // check loaded descriptors matches these values and extract private keys
473
    ///     .descriptor(KeychainKind::External, Some(EXTERNAL_DESC))
474
    ///     .descriptor(KeychainKind::Internal, Some(INTERNAL_DESC))
475
    ///     .extract_keys()
476
    ///     // you can also manually add private keys
477
    ///     .keymap(KeychainKind::External, external_keymap)
478
    ///     .keymap(KeychainKind::Internal, internal_keymap)
479
    ///     // ensure loaded wallet's genesis hash matches this value
480
    ///     .check_genesis_hash(genesis_hash)
481
    ///     // set a lookahead for our indexer
482
    ///     .lookahead(101)
483
    ///     .load_wallet(&mut conn)?
484
    ///     .expect("must have data to load wallet");
485
    /// # Ok(())
486
    /// # }
487
    /// ```
488
    pub fn load() -> LoadParams {
112✔
489
        LoadParams::new()
112✔
490
    }
112✔
491

492
    /// Load [`Wallet`] from the given previously persisted [`ChangeSet`] and `params`.
493
    ///
494
    /// Refer to [`Wallet::load`] for more.
495
    pub fn load_with_params(
112✔
496
        changeset: ChangeSet,
112✔
497
        params: LoadParams,
112✔
498
    ) -> Result<Option<Self>, LoadError> {
112✔
499
        if changeset.is_empty() {
112✔
500
            return Ok(None);
×
501
        }
112✔
502
        let secp = Secp256k1::new();
112✔
503
        let network = changeset.network.ok_or(LoadError::MissingNetwork)?;
112✔
504
        let chain = LocalChain::from_changeset(changeset.local_chain)
112✔
505
            .map_err(|_| LoadError::MissingGenesis)?;
112✔
506

507
        if let Some(exp_network) = params.check_network {
112✔
508
            if network != exp_network {
48✔
509
                return Err(LoadError::Mismatch(LoadMismatch::Network {
16✔
510
                    loaded: network,
16✔
511
                    expected: exp_network,
16✔
512
                }));
16✔
513
            }
32✔
514
        }
64✔
515
        if let Some(exp_genesis_hash) = params.check_genesis_hash {
96✔
516
            if chain.genesis_hash() != exp_genesis_hash {
16✔
517
                return Err(LoadError::Mismatch(LoadMismatch::Genesis {
16✔
518
                    loaded: chain.genesis_hash(),
16✔
519
                    expected: exp_genesis_hash,
16✔
520
                }));
16✔
521
            }
×
522
        }
80✔
523

524
        let descriptor = changeset
80✔
525
            .descriptor
80✔
526
            .ok_or(LoadError::MissingDescriptor(KeychainKind::External))?;
80✔
527
        check_wallet_descriptor(&descriptor).map_err(LoadError::Descriptor)?;
80✔
528
        let mut external_keymap = params.descriptor_keymap;
80✔
529

530
        if let Some(expected) = params.check_descriptor {
80✔
531
            if let Some(make_desc) = expected {
56✔
532
                let (exp_desc, keymap) =
40✔
533
                    make_desc(&secp, network).map_err(LoadError::Descriptor)?;
40✔
534
                if descriptor.descriptor_id() != exp_desc.descriptor_id() {
40✔
535
                    return Err(LoadError::Mismatch(LoadMismatch::Descriptor {
16✔
536
                        keychain: KeychainKind::External,
16✔
537
                        loaded: Some(descriptor),
16✔
538
                        expected: Some(exp_desc),
16✔
539
                    }));
16✔
540
                }
24✔
541
                if params.extract_keys {
24✔
542
                    external_keymap.extend(keymap);
8✔
543
                }
16✔
544
            } else {
545
                return Err(LoadError::Mismatch(LoadMismatch::Descriptor {
16✔
546
                    keychain: KeychainKind::External,
16✔
547
                    loaded: Some(descriptor),
16✔
548
                    expected: None,
16✔
549
                }));
16✔
550
            }
551
        }
24✔
552
        let signers = Arc::new(SignersContainer::build(external_keymap, &descriptor, &secp));
48✔
553

48✔
554
        let (mut change_descriptor, mut change_signers) = (None, Arc::new(SignersContainer::new()));
48✔
555
        match (changeset.change_descriptor, params.check_change_descriptor) {
48✔
556
            // empty signer
557
            (None, None) => {}
8✔
558
            (None, Some(expect)) => {
8✔
559
                // expected desc but none loaded
560
                if let Some(make_desc) = expect {
8✔
561
                    let (exp_desc, _) = make_desc(&secp, network).map_err(LoadError::Descriptor)?;
8✔
562
                    return Err(LoadError::Mismatch(LoadMismatch::Descriptor {
8✔
563
                        keychain: KeychainKind::Internal,
8✔
564
                        loaded: None,
8✔
565
                        expected: Some(exp_desc),
8✔
566
                    }));
8✔
567
                }
×
568
            }
569
            // nothing expected
570
            (Some(desc), None) => {
16✔
571
                check_wallet_descriptor(&desc).map_err(LoadError::Descriptor)?;
16✔
572
                change_descriptor = Some(desc);
16✔
573
            }
574
            (Some(desc), Some(expect)) => match expect {
16✔
575
                // expected none for existing
576
                None => {
577
                    return Err(LoadError::Mismatch(LoadMismatch::Descriptor {
×
578
                        keychain: KeychainKind::Internal,
×
579
                        loaded: Some(desc),
×
580
                        expected: None,
×
581
                    }))
×
582
                }
583
                // parameters must match
584
                Some(make_desc) => {
16✔
585
                    check_wallet_descriptor(&desc).map_err(LoadError::Descriptor)?;
16✔
586
                    let (exp_desc, keymap) =
16✔
587
                        make_desc(&secp, network).map_err(LoadError::Descriptor)?;
16✔
588
                    if desc.descriptor_id() != exp_desc.descriptor_id() {
16✔
589
                        return Err(LoadError::Mismatch(LoadMismatch::Descriptor {
×
590
                            keychain: KeychainKind::Internal,
×
591
                            loaded: Some(desc),
×
592
                            expected: Some(exp_desc),
×
593
                        }));
×
594
                    }
16✔
595
                    let mut internal_keymap = params.change_descriptor_keymap;
16✔
596
                    if params.extract_keys {
16✔
597
                        internal_keymap.extend(keymap);
×
598
                    }
16✔
599
                    change_signers =
16✔
600
                        Arc::new(SignersContainer::build(internal_keymap, &desc, &secp));
16✔
601
                    change_descriptor = Some(desc);
16✔
602
                }
603
            },
604
        }
605

606
        let index = create_indexer(descriptor, change_descriptor, params.lookahead)
40✔
607
            .map_err(LoadError::Descriptor)?;
40✔
608

609
        let mut indexed_graph = IndexedTxGraph::new(index);
40✔
610
        indexed_graph.apply_changeset(changeset.indexer.into());
40✔
611
        indexed_graph.apply_changeset(changeset.tx_graph.into());
40✔
612

40✔
613
        let stage = ChangeSet::default();
40✔
614

40✔
615
        Ok(Some(Wallet {
40✔
616
            signers,
40✔
617
            change_signers,
40✔
618
            chain,
40✔
619
            indexed_graph,
40✔
620
            stage,
40✔
621
            network,
40✔
622
            secp,
40✔
623
        }))
40✔
624
    }
112✔
625

626
    /// Get the Bitcoin network the wallet is using.
627
    pub fn network(&self) -> Network {
32✔
628
        self.network
32✔
629
    }
32✔
630

631
    /// Iterator over all keychains in this wallet
632
    pub fn keychains(&self) -> impl Iterator<Item = (KeychainKind, &ExtendedDescriptor)> {
11,860✔
633
        self.indexed_graph.index.keychains()
11,860✔
634
    }
11,860✔
635

636
    /// Peek an address of the given `keychain` at `index` without revealing it.
637
    ///
638
    /// For non-wildcard descriptors this returns the same address at every provided index.
639
    ///
640
    /// # Panics
641
    ///
642
    /// This panics when the caller requests for an address of derivation index greater than the
643
    /// [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) max index.
644
    pub fn peek_address(&self, keychain: KeychainKind, mut index: u32) -> AddressInfo {
2,048✔
645
        let keychain = self.map_keychain(keychain);
2,048✔
646
        let mut spk_iter = self
2,048✔
647
            .indexed_graph
2,048✔
648
            .index
2,048✔
649
            .unbounded_spk_iter(keychain)
2,048✔
650
            .expect("keychain must exist");
2,048✔
651
        if !spk_iter.descriptor().has_wildcard() {
2,048✔
652
            index = 0;
1,632✔
653
        }
1,632✔
654
        let (index, spk) = spk_iter
2,048✔
655
            .nth(index as usize)
2,048✔
656
            .expect("derivation index is out of bounds");
2,048✔
657

2,048✔
658
        AddressInfo {
2,048✔
659
            index,
2,048✔
660
            address: Address::from_script(&spk, self.network).expect("must have address form"),
2,048✔
661
            keychain,
2,048✔
662
        }
2,048✔
663
    }
2,048✔
664

665
    /// Attempt to reveal the next address of the given `keychain`.
666
    ///
667
    /// This will increment the keychain's derivation index. If the keychain's descriptor doesn't
668
    /// contain a wildcard or every address is already revealed up to the maximum derivation
669
    /// index defined in [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki),
670
    /// then the last revealed address will be returned.
671
    ///
672
    /// **WARNING**: To avoid address reuse you must persist the changes resulting from one or more
673
    /// calls to this method before closing the wallet. For example:
674
    ///
675
    /// ```rust,no_run
676
    /// # use bdk_wallet::{LoadParams, ChangeSet, KeychainKind};
677
    /// use bdk_chain::rusqlite::Connection;
678
    /// let mut conn = Connection::open_in_memory().expect("must open connection");
679
    /// let mut wallet = LoadParams::new()
680
    ///     .load_wallet(&mut conn)
681
    ///     .expect("database is okay")
682
    ///     .expect("database has data");
683
    /// let next_address = wallet.reveal_next_address(KeychainKind::External);
684
    /// wallet.persist(&mut conn).expect("write is okay");
685
    ///
686
    /// // Now it's safe to show the user their next address!
687
    /// println!("Next address: {}", next_address.address);
688
    /// # Ok::<(), anyhow::Error>(())
689
    /// ```
690
    pub fn reveal_next_address(&mut self, keychain: KeychainKind) -> AddressInfo {
120✔
691
        let keychain = self.map_keychain(keychain);
120✔
692
        let index = &mut self.indexed_graph.index;
120✔
693
        let stage = &mut self.stage;
120✔
694

120✔
695
        let ((index, spk), index_changeset) = index
120✔
696
            .reveal_next_spk(keychain)
120✔
697
            .expect("keychain must exist");
120✔
698

120✔
699
        stage.merge(index_changeset.into());
120✔
700

120✔
701
        AddressInfo {
120✔
702
            index,
120✔
703
            address: Address::from_script(spk.as_script(), self.network)
120✔
704
                .expect("must have address form"),
120✔
705
            keychain,
120✔
706
        }
120✔
707
    }
120✔
708

709
    /// Reveal addresses up to and including the target `index` and return an iterator
710
    /// of newly revealed addresses.
711
    ///
712
    /// If the target `index` is unreachable, we make a best effort to reveal up to the last
713
    /// possible index. If all addresses up to the given `index` are already revealed, then
714
    /// no new addresses are returned.
715
    ///
716
    /// **WARNING**: To avoid address reuse you must persist the changes resulting from one or more
717
    /// calls to this method before closing the wallet. See [`Wallet::reveal_next_address`].
718
    pub fn reveal_addresses_to(
24✔
719
        &mut self,
24✔
720
        keychain: KeychainKind,
24✔
721
        index: u32,
24✔
722
    ) -> impl Iterator<Item = AddressInfo> + '_ {
24✔
723
        let keychain = self.map_keychain(keychain);
24✔
724
        let (spks, index_changeset) = self
24✔
725
            .indexed_graph
24✔
726
            .index
24✔
727
            .reveal_to_target(keychain, index)
24✔
728
            .expect("keychain must exist");
24✔
729

24✔
730
        self.stage.merge(index_changeset.into());
24✔
731

24✔
732
        spks.into_iter().map(move |(index, spk)| AddressInfo {
31✔
733
            index,
10✔
734
            address: Address::from_script(&spk, self.network).expect("must have address form"),
10✔
735
            keychain,
10✔
736
        })
31✔
737
    }
24✔
738

739
    /// Get the next unused address for the given `keychain`, i.e. the address with the lowest
740
    /// derivation index that hasn't been used.
741
    ///
742
    /// This will attempt to derive and reveal a new address if no newly revealed addresses
743
    /// are available. See also [`reveal_next_address`](Self::reveal_next_address).
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. See [`Wallet::reveal_next_address`].
747
    pub fn next_unused_address(&mut self, keychain: KeychainKind) -> AddressInfo {
1,016✔
748
        let keychain = self.map_keychain(keychain);
1,016✔
749
        let index = &mut self.indexed_graph.index;
1,016✔
750

1,016✔
751
        let ((index, spk), index_changeset) = index
1,016✔
752
            .next_unused_spk(keychain)
1,016✔
753
            .expect("keychain must exist");
1,016✔
754

1,016✔
755
        self.stage
1,016✔
756
            .merge(indexed_tx_graph::ChangeSet::from(index_changeset).into());
1,016✔
757

1,016✔
758
        AddressInfo {
1,016✔
759
            index,
1,016✔
760
            address: Address::from_script(spk.as_script(), self.network)
1,016✔
761
                .expect("must have address form"),
1,016✔
762
            keychain,
1,016✔
763
        }
1,016✔
764
    }
1,016✔
765

766
    /// Marks an address used of the given `keychain` at `index`.
767
    ///
768
    /// Returns whether the given index was present and then removed from the unused set.
769
    pub fn mark_used(&mut self, keychain: KeychainKind, index: u32) -> bool {
656✔
770
        self.indexed_graph.index.mark_used(keychain, index)
656✔
771
    }
656✔
772

773
    /// Undoes the effect of [`mark_used`] and returns whether the `index` was inserted
774
    /// back into the unused set.
775
    ///
776
    /// Since this is only a superficial marker, it will have no effect if the address at the given
777
    /// `index` was actually used, i.e. the wallet has previously indexed a tx output for the
778
    /// derived spk.
779
    ///
780
    /// [`mark_used`]: Self::mark_used
781
    pub fn unmark_used(&mut self, keychain: KeychainKind, index: u32) -> bool {
16✔
782
        self.indexed_graph.index.unmark_used(keychain, index)
16✔
783
    }
16✔
784

785
    /// List addresses that are revealed but unused.
786
    ///
787
    /// Note if the returned iterator is empty you can reveal more addresses
788
    /// by using [`reveal_next_address`](Self::reveal_next_address) or
789
    /// [`reveal_addresses_to`](Self::reveal_addresses_to).
790
    pub fn list_unused_addresses(
24✔
791
        &self,
24✔
792
        keychain: KeychainKind,
24✔
793
    ) -> impl DoubleEndedIterator<Item = AddressInfo> + '_ {
24✔
794
        self.indexed_graph
24✔
795
            .index
24✔
796
            .unused_keychain_spks(self.map_keychain(keychain))
24✔
797
            .map(move |(index, spk)| AddressInfo {
32✔
798
                index,
11✔
799
                address: Address::from_script(spk.as_script(), self.network)
11✔
800
                    .expect("must have address form"),
11✔
801
                keychain,
11✔
802
            })
32✔
803
    }
24✔
804

805
    /// Return whether or not a `script` is part of this wallet (either internal or external)
806
    pub fn is_mine(&self, script: ScriptBuf) -> bool {
1,904✔
807
        self.indexed_graph.index.index_of_spk(script).is_some()
1,904✔
808
    }
1,904✔
809

810
    /// Finds how the wallet derived the script pubkey `spk`.
811
    ///
812
    /// Will only return `Some(_)` if the wallet has given out the spk.
813
    pub fn derivation_of_spk(&self, spk: ScriptBuf) -> Option<(KeychainKind, u32)> {
64✔
814
        self.indexed_graph.index.index_of_spk(spk).cloned()
64✔
815
    }
64✔
816

817
    /// Return the list of unspent outputs of this wallet
818
    pub fn list_unspent(&self) -> impl Iterator<Item = LocalOutput> + '_ {
1,328✔
819
        self.indexed_graph
1,328✔
820
            .graph()
1,328✔
821
            .filter_chain_unspents(
1,328✔
822
                &self.chain,
1,328✔
823
                self.chain.tip().block_id(),
1,328✔
824
                self.indexed_graph.index.outpoints().iter().cloned(),
1,328✔
825
            )
1,328✔
826
            .map(|((k, i), full_txo)| new_local_utxo(k, i, full_txo))
1,432✔
827
    }
1,328✔
828

829
    /// List all relevant outputs (includes both spent and unspent, confirmed and unconfirmed).
830
    ///
831
    /// To list only unspent outputs (UTXOs), use [`Wallet::list_unspent`] instead.
832
    pub fn list_output(&self) -> impl Iterator<Item = LocalOutput> + '_ {
8✔
833
        self.indexed_graph
8✔
834
            .graph()
8✔
835
            .filter_chain_txouts(
8✔
836
                &self.chain,
8✔
837
                self.chain.tip().block_id(),
8✔
838
                self.indexed_graph.index.outpoints().iter().cloned(),
8✔
839
            )
8✔
840
            .map(|((k, i), full_txo)| new_local_utxo(k, i, full_txo))
9✔
841
    }
8✔
842

843
    /// Get all the checkpoints the wallet is currently storing indexed by height.
844
    pub fn checkpoints(&self) -> CheckPointIter {
×
845
        self.chain.iter_checkpoints()
×
846
    }
×
847

848
    /// Returns the latest checkpoint.
849
    pub fn latest_checkpoint(&self) -> CheckPoint {
96✔
850
        self.chain.tip()
96✔
851
    }
96✔
852

853
    /// Get unbounded script pubkey iterators for both `Internal` and `External` keychains.
854
    ///
855
    /// This is intended to be used when doing a full scan of your addresses (e.g. after restoring
856
    /// from seed words). You pass the `BTreeMap` of iterators to a blockchain data source (e.g.
857
    /// electrum server) which will go through each address until it reaches a *stop gap*.
858
    ///
859
    /// Note carefully that iterators go over **all** script pubkeys on the keychains (not what
860
    /// script pubkeys the wallet is storing internally).
861
    pub fn all_unbounded_spk_iters(
×
862
        &self,
×
863
    ) -> BTreeMap<KeychainKind, impl Iterator<Item = Indexed<ScriptBuf>> + Clone> {
×
864
        self.indexed_graph.index.all_unbounded_spk_iters()
×
865
    }
×
866

867
    /// Get an unbounded script pubkey iterator for the given `keychain`.
868
    ///
869
    /// See [`all_unbounded_spk_iters`] for more documentation
870
    ///
871
    /// [`all_unbounded_spk_iters`]: Self::all_unbounded_spk_iters
872
    pub fn unbounded_spk_iter(
×
873
        &self,
×
874
        keychain: KeychainKind,
×
875
    ) -> impl Iterator<Item = Indexed<ScriptBuf>> + Clone {
×
876
        self.indexed_graph
×
877
            .index
×
878
            .unbounded_spk_iter(self.map_keychain(keychain))
×
879
            .expect("keychain must exist")
×
880
    }
×
881

882
    /// Returns the utxo owned by this wallet corresponding to `outpoint` if it exists in the
883
    /// wallet's database.
884
    pub fn get_utxo(&self, op: OutPoint) -> Option<LocalOutput> {
72✔
885
        let ((keychain, index), _) = self.indexed_graph.index.txout(op)?;
72✔
886
        self.indexed_graph
72✔
887
            .graph()
72✔
888
            .filter_chain_unspents(
72✔
889
                &self.chain,
72✔
890
                self.chain.tip().block_id(),
72✔
891
                core::iter::once(((), op)),
72✔
892
            )
72✔
893
            .map(|(_, full_txo)| new_local_utxo(keychain, index, full_txo))
72✔
894
            .next()
72✔
895
    }
72✔
896

897
    /// Inserts a [`TxOut`] at [`OutPoint`] into the wallet's transaction graph.
898
    ///
899
    /// This is used for providing a previous output's value so that we can use [`calculate_fee`]
900
    /// or [`calculate_fee_rate`] on a given transaction. Outputs inserted with this method will
901
    /// not be returned in [`list_unspent`] or [`list_output`].
902
    ///
903
    /// **WARNINGS:** This should only be used to add `TxOut`s that the wallet does not own. Only
904
    /// insert `TxOut`s that you trust the values for!
905
    ///
906
    /// You must persist the changes resulting from one or more calls to this method if you need
907
    /// the inserted `TxOut` data to be reloaded after closing the wallet.
908
    /// See [`Wallet::reveal_next_address`].
909
    ///
910
    /// [`calculate_fee`]: Self::calculate_fee
911
    /// [`calculate_fee_rate`]: Self::calculate_fee_rate
912
    /// [`list_unspent`]: Self::list_unspent
913
    /// [`list_output`]: Self::list_output
914
    pub fn insert_txout(&mut self, outpoint: OutPoint, txout: TxOut) {
16✔
915
        let additions = self.indexed_graph.insert_txout(outpoint, txout);
16✔
916
        self.stage.merge(additions.into());
16✔
917
    }
16✔
918

919
    /// Calculates the fee of a given transaction. Returns [`Amount::ZERO`] if `tx` is a coinbase transaction.
920
    ///
921
    /// To calculate the fee for a [`Transaction`] with inputs not owned by this wallet you must
922
    /// manually insert the TxOut(s) into the tx graph using the [`insert_txout`] function.
923
    ///
924
    /// Note `tx` does not have to be in the graph for this to work.
925
    ///
926
    /// # Examples
927
    ///
928
    /// ```rust, no_run
929
    /// # use bitcoin::Txid;
930
    /// # use bdk_wallet::Wallet;
931
    /// # let mut wallet: Wallet = todo!();
932
    /// # let txid:Txid = todo!();
933
    /// let tx = wallet.get_tx(txid).expect("transaction").tx_node.tx;
934
    /// let fee = wallet.calculate_fee(&tx).expect("fee");
935
    /// ```
936
    ///
937
    /// ```rust, no_run
938
    /// # use bitcoin::Psbt;
939
    /// # use bdk_wallet::Wallet;
940
    /// # let mut wallet: Wallet = todo!();
941
    /// # let mut psbt: Psbt = todo!();
942
    /// let tx = &psbt.clone().extract_tx().expect("tx");
943
    /// let fee = wallet.calculate_fee(tx).expect("fee");
944
    /// ```
945
    /// [`insert_txout`]: Self::insert_txout
946
    pub fn calculate_fee(&self, tx: &Transaction) -> Result<Amount, CalculateFeeError> {
536✔
947
        self.indexed_graph.graph().calculate_fee(tx)
536✔
948
    }
536✔
949

950
    /// Calculate the [`FeeRate`] for a given transaction.
951
    ///
952
    /// To calculate the fee rate for a [`Transaction`] with inputs not owned by this wallet you must
953
    /// manually insert the TxOut(s) into the tx graph using the [`insert_txout`] function.
954
    ///
955
    /// Note `tx` does not have to be in the graph for this to work.
956
    ///
957
    /// # Examples
958
    ///
959
    /// ```rust, no_run
960
    /// # use bitcoin::Txid;
961
    /// # use bdk_wallet::Wallet;
962
    /// # let mut wallet: Wallet = todo!();
963
    /// # let txid:Txid = todo!();
964
    /// let tx = wallet.get_tx(txid).expect("transaction").tx_node.tx;
965
    /// let fee_rate = wallet.calculate_fee_rate(&tx).expect("fee rate");
966
    /// ```
967
    ///
968
    /// ```rust, no_run
969
    /// # use bitcoin::Psbt;
970
    /// # use bdk_wallet::Wallet;
971
    /// # let mut wallet: Wallet = todo!();
972
    /// # let mut psbt: Psbt = todo!();
973
    /// let tx = &psbt.clone().extract_tx().expect("tx");
974
    /// let fee_rate = wallet.calculate_fee_rate(tx).expect("fee rate");
975
    /// ```
976
    /// [`insert_txout`]: Self::insert_txout
977
    pub fn calculate_fee_rate(&self, tx: &Transaction) -> Result<FeeRate, CalculateFeeError> {
144✔
978
        self.calculate_fee(tx).map(|fee| fee / tx.weight())
144✔
979
    }
144✔
980

981
    /// Compute the `tx`'s sent and received [`Amount`]s.
982
    ///
983
    /// This method returns a tuple `(sent, received)`. Sent is the sum of the txin amounts
984
    /// that spend from previous txouts tracked by this wallet. Received is the summation
985
    /// of this tx's outputs that send to script pubkeys tracked by this wallet.
986
    ///
987
    /// # Examples
988
    ///
989
    /// ```rust, no_run
990
    /// # use bitcoin::Txid;
991
    /// # use bdk_wallet::Wallet;
992
    /// # let mut wallet: Wallet = todo!();
993
    /// # let txid:Txid = todo!();
994
    /// let tx = wallet.get_tx(txid).expect("tx exists").tx_node.tx;
995
    /// let (sent, received) = wallet.sent_and_received(&tx);
996
    /// ```
997
    ///
998
    /// ```rust, no_run
999
    /// # use bitcoin::Psbt;
1000
    /// # use bdk_wallet::Wallet;
1001
    /// # let mut wallet: Wallet = todo!();
1002
    /// # let mut psbt: Psbt = todo!();
1003
    /// let tx = &psbt.clone().extract_tx().expect("tx");
1004
    /// let (sent, received) = wallet.sent_and_received(tx);
1005
    /// ```
1006
    pub fn sent_and_received(&self, tx: &Transaction) -> (Amount, Amount) {
224✔
1007
        self.indexed_graph.index.sent_and_received(tx, ..)
224✔
1008
    }
224✔
1009

1010
    /// Get a single transaction from the wallet as a [`WalletTx`] (if the transaction exists).
1011
    ///
1012
    /// `WalletTx` contains the full transaction alongside meta-data such as:
1013
    /// * Blocks that the transaction is [`Anchor`]ed in. These may or may not be blocks that exist
1014
    ///   in the best chain.
1015
    /// * The [`ChainPosition`] of the transaction in the best chain - whether the transaction is
1016
    ///   confirmed or unconfirmed. If the transaction is confirmed, the anchor which proves the
1017
    ///   confirmation is provided. If the transaction is unconfirmed, the unix timestamp of when
1018
    ///   the transaction was last seen in the mempool is provided.
1019
    ///
1020
    /// ```rust, no_run
1021
    /// use bdk_chain::Anchor;
1022
    /// use bdk_wallet::{chain::ChainPosition, Wallet};
1023
    /// # let wallet: Wallet = todo!();
1024
    /// # let my_txid: bitcoin::Txid = todo!();
1025
    ///
1026
    /// let wallet_tx = wallet.get_tx(my_txid).expect("panic if tx does not exist");
1027
    ///
1028
    /// // get reference to full transaction
1029
    /// println!("my tx: {:#?}", wallet_tx.tx_node.tx);
1030
    ///
1031
    /// // list all transaction anchors
1032
    /// for anchor in wallet_tx.tx_node.anchors {
1033
    ///     println!(
1034
    ///         "tx is anchored by block of hash {}",
1035
    ///         anchor.anchor_block().hash
1036
    ///     );
1037
    /// }
1038
    ///
1039
    /// // get confirmation status of transaction
1040
    /// match wallet_tx.chain_position {
1041
    ///     ChainPosition::Confirmed(anchor) => println!(
1042
    ///         "tx is confirmed at height {}, we know this since {}:{} is in the best chain",
1043
    ///         anchor.block_id.height, anchor.block_id.height, anchor.block_id.hash,
1044
    ///     ),
1045
    ///     ChainPosition::Unconfirmed(last_seen) => println!(
1046
    ///         "tx is last seen at {}, it is unconfirmed as it is not anchored in the best chain",
1047
    ///         last_seen,
1048
    ///     ),
1049
    /// }
1050
    /// ```
1051
    ///
1052
    /// [`Anchor`]: bdk_chain::Anchor
1053
    pub fn get_tx(&self, txid: Txid) -> Option<WalletTx> {
56✔
1054
        let graph = self.indexed_graph.graph();
56✔
1055

56✔
1056
        Some(WalletTx {
56✔
1057
            chain_position: graph.get_chain_position(
56✔
1058
                &self.chain,
56✔
1059
                self.chain.tip().block_id(),
56✔
1060
                txid,
56✔
1061
            )?,
56✔
1062
            tx_node: graph.get_tx_node(txid)?,
56✔
1063
        })
1064
    }
56✔
1065

1066
    /// Add a new checkpoint to the wallet's internal view of the chain.
1067
    ///
1068
    /// Returns whether anything changed with the insertion (e.g. `false` if checkpoint was already
1069
    /// there).
1070
    ///
1071
    /// **WARNING**: You must persist the changes resulting from one or more calls to this method
1072
    /// if you need the inserted checkpoint data to be reloaded after closing the wallet.
1073
    /// See [`Wallet::reveal_next_address`].
1074
    pub fn insert_checkpoint(
3,284✔
1075
        &mut self,
3,284✔
1076
        block_id: BlockId,
3,284✔
1077
    ) -> Result<bool, local_chain::AlterCheckPointError> {
3,284✔
1078
        let changeset = self.chain.insert_block(block_id)?;
3,284✔
1079
        let changed = !changeset.is_empty();
3,284✔
1080
        self.stage.merge(changeset.into());
3,284✔
1081
        Ok(changed)
3,284✔
1082
    }
3,284✔
1083

1084
    /// Add a transaction to the wallet's internal view of the chain. This stages the change,
1085
    /// you must persist it later.
1086
    ///
1087
    /// This method inserts the given `tx` and returns whether anything changed after insertion,
1088
    /// which will be false if the same transaction already exists in the wallet's transaction
1089
    /// graph. Any changes are staged but not committed.
1090
    ///
1091
    /// # Note
1092
    ///
1093
    /// By default the inserted `tx` won't be considered "canonical" because it's not known
1094
    /// whether the transaction exists in the best chain. To know whether it exists, the tx
1095
    /// must be broadcast to the network and the wallet synced via a chain source.
1096
    pub fn insert_tx<T: Into<Arc<Transaction>>>(&mut self, tx: T) -> bool {
316✔
1097
        let mut changeset = ChangeSet::default();
316✔
1098
        changeset.merge(self.indexed_graph.insert_tx(tx).into());
316✔
1099
        let ret = !changeset.is_empty();
316✔
1100
        self.stage.merge(changeset);
316✔
1101
        ret
316✔
1102
    }
316✔
1103

1104
    /// Iterate over the transactions in the wallet.
1105
    pub fn transactions(&self) -> impl Iterator<Item = WalletTx> + '_ {
46✔
1106
        self.indexed_graph
46✔
1107
            .graph()
46✔
1108
            .list_canonical_txs(&self.chain, self.chain.tip().block_id())
46✔
1109
    }
46✔
1110

1111
    /// Array of transactions in the wallet sorted with a comparator function.
1112
    ///
1113
    /// # Example
1114
    ///
1115
    /// ```rust,no_run
1116
    /// # use bdk_wallet::{LoadParams, Wallet, WalletTx};
1117
    /// # let mut wallet:Wallet = todo!();
1118
    /// // Transactions by chain position: first unconfirmed then descending by confirmed height.
1119
    /// let sorted_txs: Vec<WalletTx> =
1120
    ///     wallet.transactions_sort_by(|tx1, tx2| tx2.chain_position.cmp(&tx1.chain_position));
1121
    /// # Ok::<(), anyhow::Error>(())
1122
    /// ```
1123
    pub fn transactions_sort_by<F>(&self, compare: F) -> Vec<WalletTx>
1✔
1124
    where
1✔
1125
        F: FnMut(&WalletTx, &WalletTx) -> Ordering,
1✔
1126
    {
1✔
1127
        let mut txs: Vec<WalletTx> = self.transactions().collect();
1✔
1128
        txs.sort_unstable_by(compare);
1✔
1129
        txs
1✔
1130
    }
1✔
1131

1132
    /// Return the balance, separated into available, trusted-pending, untrusted-pending and immature
1133
    /// values.
1134
    pub fn balance(&self) -> Balance {
56✔
1135
        self.indexed_graph.graph().balance(
56✔
1136
            &self.chain,
56✔
1137
            self.chain.tip().block_id(),
56✔
1138
            self.indexed_graph.index.outpoints().iter().cloned(),
56✔
1139
            |&(k, _), _| k == KeychainKind::Internal,
56✔
1140
        )
56✔
1141
    }
56✔
1142

1143
    /// Add an external signer
1144
    ///
1145
    /// See [the `signer` module](signer) for an example.
1146
    pub fn add_signer(
16✔
1147
        &mut self,
16✔
1148
        keychain: KeychainKind,
16✔
1149
        ordering: SignerOrdering,
16✔
1150
        signer: Arc<dyn TransactionSigner>,
16✔
1151
    ) {
16✔
1152
        let signers = match keychain {
16✔
1153
            KeychainKind::External => Arc::make_mut(&mut self.signers),
16✔
1154
            KeychainKind::Internal => Arc::make_mut(&mut self.change_signers),
×
1155
        };
1156

1157
        signers.add_external(signer.id(&self.secp), ordering, signer);
16✔
1158
    }
16✔
1159

1160
    /// Set the keymap for a given keychain.
1161
    ///
1162
    /// Note this does nothing if the given keychain has no descriptor because we won't
1163
    /// know the context (segwit, taproot, etc) in which to create signatures.
1164
    pub fn set_keymap(&mut self, keychain: KeychainKind, keymap: KeyMap) {
×
1165
        let wallet_signers = match keychain {
×
1166
            KeychainKind::External => Arc::make_mut(&mut self.signers),
×
1167
            KeychainKind::Internal => Arc::make_mut(&mut self.change_signers),
×
1168
        };
1169
        if let Some(descriptor) = self.indexed_graph.index.get_descriptor(keychain) {
×
1170
            *wallet_signers = SignersContainer::build(keymap, descriptor, &self.secp)
×
1171
        }
×
1172
    }
×
1173

1174
    /// Set the keymap for each keychain.
1175
    pub fn set_keymaps(&mut self, keymaps: impl IntoIterator<Item = (KeychainKind, KeyMap)>) {
×
1176
        for (keychain, keymap) in keymaps {
×
1177
            self.set_keymap(keychain, keymap);
×
1178
        }
×
1179
    }
×
1180

1181
    /// Get the signers
1182
    ///
1183
    /// ## Example
1184
    ///
1185
    /// ```
1186
    /// # use bdk_wallet::{Wallet, KeychainKind};
1187
    /// # use bdk_wallet::bitcoin::Network;
1188
    /// let descriptor = "wpkh(tprv8ZgxMBicQKsPe73PBRSmNbTfbcsZnwWhz5eVmhHpi31HW29Z7mc9B4cWGRQzopNUzZUT391DeDJxL2PefNunWyLgqCKRMDkU1s2s8bAfoSk/84'/1'/0'/0/*)";
1189
    /// let change_descriptor = "wpkh(tprv8ZgxMBicQKsPe73PBRSmNbTfbcsZnwWhz5eVmhHpi31HW29Z7mc9B4cWGRQzopNUzZUT391DeDJxL2PefNunWyLgqCKRMDkU1s2s8bAfoSk/84'/1'/0'/1/*)";
1190
    /// let wallet = Wallet::create(descriptor, change_descriptor)
1191
    ///     .network(Network::Testnet)
1192
    ///     .create_wallet_no_persist()?;
1193
    /// for secret_key in wallet.get_signers(KeychainKind::External).signers().iter().filter_map(|s| s.descriptor_secret_key()) {
1194
    ///     // secret_key: tprv8ZgxMBicQKsPe73PBRSmNbTfbcsZnwWhz5eVmhHpi31HW29Z7mc9B4cWGRQzopNUzZUT391DeDJxL2PefNunWyLgqCKRMDkU1s2s8bAfoSk/84'/0'/0'/0/*
1195
    ///     println!("secret_key: {}", secret_key);
1196
    /// }
1197
    ///
1198
    /// Ok::<(), Box<dyn std::error::Error>>(())
1199
    /// ```
1200
    pub fn get_signers(&self, keychain: KeychainKind) -> Arc<SignersContainer> {
44✔
1201
        match keychain {
44✔
1202
            KeychainKind::External => Arc::clone(&self.signers),
30✔
1203
            KeychainKind::Internal => Arc::clone(&self.change_signers),
14✔
1204
        }
1205
    }
44✔
1206

1207
    /// Start building a transaction.
1208
    ///
1209
    /// This returns a blank [`TxBuilder`] from which you can specify the parameters for the transaction.
1210
    ///
1211
    /// ## Example
1212
    ///
1213
    /// ```
1214
    /// # use std::str::FromStr;
1215
    /// # use bitcoin::*;
1216
    /// # use bdk_wallet::*;
1217
    /// # use bdk_wallet::ChangeSet;
1218
    /// # use bdk_wallet::error::CreateTxError;
1219
    /// # use anyhow::Error;
1220
    /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
1221
    /// # let mut wallet = doctest_wallet!();
1222
    /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
1223
    /// let psbt = {
1224
    ///    let mut builder =  wallet.build_tx();
1225
    ///    builder
1226
    ///        .add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000));
1227
    ///    builder.finish()?
1228
    /// };
1229
    ///
1230
    /// // sign and broadcast ...
1231
    /// # Ok::<(), anyhow::Error>(())
1232
    /// ```
1233
    ///
1234
    /// [`TxBuilder`]: crate::TxBuilder
1235
    pub fn build_tx(&mut self) -> TxBuilder<'_, DefaultCoinSelectionAlgorithm> {
1,184✔
1236
        TxBuilder {
1,184✔
1237
            wallet: alloc::rc::Rc::new(core::cell::RefCell::new(self)),
1,184✔
1238
            params: TxParams::default(),
1,184✔
1239
            coin_selection: DefaultCoinSelectionAlgorithm::default(),
1,184✔
1240
        }
1,184✔
1241
    }
1,184✔
1242

1243
    pub(crate) fn create_tx<Cs: coin_selection::CoinSelectionAlgorithm>(
157✔
1244
        &mut self,
157✔
1245
        coin_selection: Cs,
157✔
1246
        params: TxParams,
157✔
1247
        rng: &mut impl RngCore,
157✔
1248
    ) -> Result<Psbt, CreateTxError> {
157✔
1249
        let keychains: BTreeMap<_, _> = self.indexed_graph.index.keychains().collect();
157✔
1250
        let external_descriptor = keychains.get(&KeychainKind::External).expect("must exist");
157✔
1251
        let internal_descriptor = keychains.get(&KeychainKind::Internal);
157✔
1252

1253
        let external_policy = external_descriptor
157✔
1254
            .extract_policy(&self.signers, BuildSatisfaction::None, &self.secp)?
157✔
1255
            .unwrap();
157✔
1256
        let internal_policy = internal_descriptor
157✔
1257
            .map(|desc| {
157✔
1258
                Ok::<_, CreateTxError>(
152✔
1259
                    desc.extract_policy(&self.change_signers, BuildSatisfaction::None, &self.secp)?
152✔
1260
                        .unwrap(),
152✔
1261
                )
1262
            })
157✔
1263
            .transpose()?;
157✔
1264

1265
        // The policy allows spending external outputs, but it requires a policy path that hasn't been
1266
        // provided
1267
        if params.change_policy != tx_builder::ChangeSpendPolicy::OnlyChange
157✔
1268
            && external_policy.requires_path()
156✔
1269
            && params.external_policy_path.is_none()
4✔
1270
        {
1271
            return Err(CreateTxError::SpendingPolicyRequired(
1✔
1272
                KeychainKind::External,
1✔
1273
            ));
1✔
1274
        };
156✔
1275
        // Same for the internal_policy path
1276
        if let Some(internal_policy) = &internal_policy {
156✔
1277
            if params.change_policy != tx_builder::ChangeSpendPolicy::ChangeForbidden
151✔
1278
                && internal_policy.requires_path()
150✔
1279
                && params.internal_policy_path.is_none()
×
1280
            {
1281
                return Err(CreateTxError::SpendingPolicyRequired(
×
1282
                    KeychainKind::Internal,
×
1283
                ));
×
1284
            };
151✔
1285
        }
5✔
1286

1287
        let external_requirements = external_policy.get_condition(
156✔
1288
            params
156✔
1289
                .external_policy_path
156✔
1290
                .as_ref()
156✔
1291
                .unwrap_or(&BTreeMap::new()),
156✔
1292
        )?;
156✔
1293
        let internal_requirements = internal_policy
156✔
1294
            .map(|policy| {
156✔
1295
                Ok::<_, CreateTxError>(
151✔
1296
                    policy.get_condition(
151✔
1297
                        params
151✔
1298
                            .internal_policy_path
151✔
1299
                            .as_ref()
151✔
1300
                            .unwrap_or(&BTreeMap::new()),
151✔
1301
                    )?,
151✔
1302
                )
1303
            })
156✔
1304
            .transpose()?;
156✔
1305

1306
        let requirements =
156✔
1307
            external_requirements.merge(&internal_requirements.unwrap_or_default())?;
156✔
1308

1309
        let version = match params.version {
154✔
1310
            Some(tx_builder::Version(0)) => return Err(CreateTxError::Version0),
1✔
1311
            Some(tx_builder::Version(1)) if requirements.csv.is_some() => {
18✔
1312
                return Err(CreateTxError::Version1Csv)
1✔
1313
            }
1314
            Some(tx_builder::Version(x)) => x,
18✔
1315
            None if requirements.csv.is_some() => 2,
136✔
1316
            None => 1,
131✔
1317
        };
1318

1319
        // We use a match here instead of a unwrap_or_else as it's way more readable :)
1320
        let current_height = match params.current_height {
154✔
1321
            // If they didn't tell us the current height, we assume it's the latest sync height.
1322
            None => {
1323
                let tip_height = self.chain.tip().height();
150✔
1324
                absolute::LockTime::from_height(tip_height).expect("invalid height")
150✔
1325
            }
1326
            Some(h) => h,
4✔
1327
        };
1328

1329
        let lock_time = match params.locktime {
153✔
1330
            // When no nLockTime is specified, we try to prevent fee sniping, if possible
1331
            None => {
1332
                // Fee sniping can be partially prevented by setting the timelock
1333
                // to current_height. If we don't know the current_height,
1334
                // we default to 0.
1335
                let fee_sniping_height = current_height;
151✔
1336

1337
                // We choose the biggest between the required nlocktime and the fee sniping
1338
                // height
1339
                match requirements.timelock {
4✔
1340
                    // No requirement, just use the fee_sniping_height
1341
                    None => fee_sniping_height,
147✔
1342
                    // There's a block-based requirement, but the value is lower than the fee_sniping_height
1343
                    Some(value @ absolute::LockTime::Blocks(_)) if value < fee_sniping_height => {
4✔
1344
                        fee_sniping_height
×
1345
                    }
1346
                    // There's a time-based requirement or a block-based requirement greater
1347
                    // than the fee_sniping_height use that value
1348
                    Some(value) => value,
4✔
1349
                }
1350
            }
1351
            // Specific nLockTime required and we have no constraints, so just set to that value
1352
            Some(x) if requirements.timelock.is_none() => x,
3✔
1353
            // Specific nLockTime required and it's compatible with the constraints
1354
            Some(x)
1✔
1355
                if requirements.timelock.unwrap().is_same_unit(x)
2✔
1356
                    && x >= requirements.timelock.unwrap() =>
2✔
1357
            {
1✔
1358
                x
1✔
1359
            }
1360
            // Invalid nLockTime required
1361
            Some(x) => {
1✔
1362
                return Err(CreateTxError::LockTime {
1✔
1363
                    requested: x,
1✔
1364
                    required: requirements.timelock.unwrap(),
1✔
1365
                })
1✔
1366
            }
1367
        };
1368

1369
        // nSequence value for inputs
1370
        // When not explicitly specified, defaults to 0xFFFFFFFD,
1371
        // meaning RBF signaling is enabled
1372
        let n_sequence = match (params.sequence, requirements.csv) {
153✔
1373
            // Enable RBF by default
1374
            (None, None) => Sequence::ENABLE_RBF_NO_LOCKTIME,
145✔
1375
            // None requested, use required
1376
            (None, Some(csv)) => csv,
3✔
1377
            // Requested sequence is incompatible with requirements
1378
            (Some(sequence), Some(csv)) if !check_nsequence_rbf(sequence, csv) => {
2✔
1379
                return Err(CreateTxError::RbfSequenceCsv { sequence, csv })
1✔
1380
            }
1381
            // Use requested nSequence value
1382
            (Some(sequence), _) => sequence,
4✔
1383
        };
1384

1385
        let (fee_rate, mut fee_amount) = match params.fee_policy.unwrap_or_default() {
152✔
1386
            //FIXME: see https://github.com/bitcoindevkit/bdk/issues/256
1387
            FeePolicy::FeeAmount(fee) => {
9✔
1388
                if let Some(previous_fee) = params.bumping_fee {
9✔
1389
                    if fee < previous_fee.absolute {
6✔
1390
                        return Err(CreateTxError::FeeTooLow {
2✔
1391
                            required: previous_fee.absolute,
2✔
1392
                        });
2✔
1393
                    }
4✔
1394
                }
3✔
1395
                (FeeRate::ZERO, fee)
7✔
1396
            }
1397
            FeePolicy::FeeRate(rate) => {
143✔
1398
                if let Some(previous_fee) = params.bumping_fee {
143✔
1399
                    let required_feerate = FeeRate::from_sat_per_kwu(
11✔
1400
                        previous_fee.rate.to_sat_per_kwu()
11✔
1401
                            + FeeRate::BROADCAST_MIN.to_sat_per_kwu(), // +1 sat/vb
11✔
1402
                    );
11✔
1403
                    if rate < required_feerate {
11✔
1404
                        return Err(CreateTxError::FeeRateTooLow {
1✔
1405
                            required: required_feerate,
1✔
1406
                        });
1✔
1407
                    }
10✔
1408
                }
132✔
1409
                (rate, Amount::ZERO)
142✔
1410
            }
1411
        };
1412

1413
        let mut tx = Transaction {
149✔
1414
            version: transaction::Version::non_standard(version),
149✔
1415
            lock_time,
149✔
1416
            input: vec![],
149✔
1417
            output: vec![],
149✔
1418
        };
149✔
1419

149✔
1420
        if params.manually_selected_only && params.utxos.is_empty() {
149✔
1421
            return Err(CreateTxError::NoUtxosSelected);
1✔
1422
        }
148✔
1423

148✔
1424
        let mut outgoing = Amount::ZERO;
148✔
1425
        let mut received = Amount::ZERO;
148✔
1426

148✔
1427
        let recipients = params.recipients.iter().map(|(r, v)| (r, *v));
148✔
1428

1429
        for (index, (script_pubkey, value)) in recipients.enumerate() {
148✔
1430
            if !params.allow_dust && value.is_dust(script_pubkey) && !script_pubkey.is_op_return() {
98✔
1431
                return Err(CreateTxError::OutputBelowDustLimit(index));
1✔
1432
            }
97✔
1433

97✔
1434
            if self.is_mine(script_pubkey.clone()) {
97✔
1435
                received += value;
43✔
1436
            }
58✔
1437

1438
            let new_out = TxOut {
97✔
1439
                script_pubkey: script_pubkey.clone(),
97✔
1440
                value,
97✔
1441
            };
97✔
1442

97✔
1443
            tx.output.push(new_out);
97✔
1444

97✔
1445
            outgoing += value;
97✔
1446
        }
1447

1448
        fee_amount += fee_rate * tx.weight();
147✔
1449

147✔
1450
        let (required_utxos, optional_utxos) =
147✔
1451
            self.preselect_utxos(&params, Some(current_height.to_consensus_u32()));
147✔
1452

147✔
1453
        // get drain script
147✔
1454
        let mut drain_index = Option::<(KeychainKind, u32)>::None;
147✔
1455
        let drain_script = match params.drain_to {
147✔
1456
            Some(ref drain_recipient) => drain_recipient.clone(),
52✔
1457
            None => {
1458
                let change_keychain = self.map_keychain(KeychainKind::Internal);
95✔
1459
                let (index, spk) = self
95✔
1460
                    .indexed_graph
95✔
1461
                    .index
95✔
1462
                    .unused_keychain_spks(change_keychain)
95✔
1463
                    .next()
95✔
1464
                    .unwrap_or_else(|| {
95✔
1465
                        let (next_index, _) = self
93✔
1466
                            .indexed_graph
93✔
1467
                            .index
93✔
1468
                            .next_index(change_keychain)
93✔
1469
                            .expect("keychain must exist");
93✔
1470
                        let spk = self
93✔
1471
                            .peek_address(change_keychain, next_index)
93✔
1472
                            .script_pubkey();
93✔
1473
                        (next_index, spk)
93✔
1474
                    });
95✔
1475
                drain_index = Some((change_keychain, index));
95✔
1476
                spk
95✔
1477
            }
1478
        };
1479

1480
        let (required_utxos, optional_utxos) =
147✔
1481
            coin_selection::filter_duplicates(required_utxos, optional_utxos);
147✔
1482

1483
        let coin_selection = coin_selection
147✔
1484
            .coin_select(
147✔
1485
                required_utxos.clone(),
147✔
1486
                optional_utxos.clone(),
147✔
1487
                fee_rate,
147✔
1488
                outgoing.to_sat() + fee_amount.to_sat(),
147✔
1489
                &drain_script,
147✔
1490
                rng,
147✔
1491
            )
147✔
1492
            .map_err(CreateTxError::CoinSelection)?;
147✔
1493
        fee_amount += Amount::from_sat(coin_selection.fee_amount);
139✔
1494
        let excess = &coin_selection.excess;
139✔
1495

139✔
1496
        tx.input = coin_selection
139✔
1497
            .selected
139✔
1498
            .iter()
139✔
1499
            .map(|u| bitcoin::TxIn {
155✔
1500
                previous_output: u.outpoint(),
155✔
1501
                script_sig: ScriptBuf::default(),
155✔
1502
                sequence: u.sequence().unwrap_or(n_sequence),
155✔
1503
                witness: Witness::new(),
155✔
1504
            })
155✔
1505
            .collect();
139✔
1506

139✔
1507
        if tx.output.is_empty() {
139✔
1508
            // Uh oh, our transaction has no outputs.
1509
            // We allow this when:
1510
            // - We have a drain_to address and the utxos we must spend (this happens,
1511
            // for example, when we RBF)
1512
            // - We have a drain_to address and drain_wallet set
1513
            // Otherwise, we don't know who we should send the funds to, and how much
1514
            // we should send!
1515
            if params.drain_to.is_some() && (params.drain_wallet || !params.utxos.is_empty()) {
50✔
1516
                if let NoChange {
1517
                    dust_threshold,
1✔
1518
                    remaining_amount,
1✔
1519
                    change_fee,
1✔
1520
                } = excess
48✔
1521
                {
1522
                    return Err(CreateTxError::CoinSelection(InsufficientFunds {
1✔
1523
                        needed: *dust_threshold,
1✔
1524
                        available: remaining_amount.saturating_sub(*change_fee),
1✔
1525
                    }));
1✔
1526
                }
47✔
1527
            } else {
1528
                return Err(CreateTxError::NoRecipients);
2✔
1529
            }
1530
        }
89✔
1531

1532
        match excess {
136✔
1533
            NoChange {
1534
                remaining_amount, ..
10✔
1535
            } => fee_amount += Amount::from_sat(*remaining_amount),
10✔
1536
            Change { amount, fee } => {
126✔
1537
                if self.is_mine(drain_script.clone()) {
126✔
1538
                    received += Amount::from_sat(*amount);
116✔
1539
                }
116✔
1540
                fee_amount += Amount::from_sat(*fee);
126✔
1541

126✔
1542
                // create drain output
126✔
1543
                let drain_output = TxOut {
126✔
1544
                    value: Amount::from_sat(*amount),
126✔
1545
                    script_pubkey: drain_script,
126✔
1546
                };
126✔
1547

126✔
1548
                // TODO: We should pay attention when adding a new output: this might increase
126✔
1549
                // the length of the "number of vouts" parameter by 2 bytes, potentially making
126✔
1550
                // our feerate too low
126✔
1551
                tx.output.push(drain_output);
126✔
1552
            }
1553
        };
1554

1555
        // sort input/outputs according to the chosen algorithm
1556
        params.ordering.sort_tx_with_aux_rand(&mut tx, rng);
136✔
1557

1558
        let psbt = self.complete_transaction(tx, coin_selection.selected, params)?;
136✔
1559

1560
        // recording changes to the change keychain
1561
        if let (Excess::Change { .. }, Some((keychain, index))) = (excess, drain_index) {
134✔
1562
            let (_, index_changeset) = self
75✔
1563
                .indexed_graph
75✔
1564
                .index
75✔
1565
                .reveal_to_target(keychain, index)
75✔
1566
                .expect("must not be None");
75✔
1567
            self.stage.merge(index_changeset.into());
75✔
1568
            self.mark_used(keychain, index);
75✔
1569
        }
76✔
1570

1571
        Ok(psbt)
134✔
1572
    }
157✔
1573

1574
    /// Bump the fee of a transaction previously created with this wallet.
1575
    ///
1576
    /// Returns an error if the transaction is already confirmed or doesn't explicitly signal
1577
    /// *replace by fee* (RBF). If the transaction can be fee bumped then it returns a [`TxBuilder`]
1578
    /// pre-populated with the inputs and outputs of the original transaction.
1579
    ///
1580
    /// ## Example
1581
    ///
1582
    /// ```no_run
1583
    /// # // TODO: remove norun -- bumping fee seems to need the tx in the wallet database first.
1584
    /// # use std::str::FromStr;
1585
    /// # use bitcoin::*;
1586
    /// # use bdk_wallet::*;
1587
    /// # use bdk_wallet::ChangeSet;
1588
    /// # use bdk_wallet::error::CreateTxError;
1589
    /// # use anyhow::Error;
1590
    /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
1591
    /// # let mut wallet = doctest_wallet!();
1592
    /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
1593
    /// let mut psbt = {
1594
    ///     let mut builder = wallet.build_tx();
1595
    ///     builder
1596
    ///         .add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000));
1597
    ///     builder.finish()?
1598
    /// };
1599
    /// let _ = wallet.sign(&mut psbt, SignOptions::default())?;
1600
    /// let tx = psbt.clone().extract_tx().expect("tx");
1601
    /// // broadcast tx but it's taking too long to confirm so we want to bump the fee
1602
    /// let mut psbt =  {
1603
    ///     let mut builder = wallet.build_fee_bump(tx.compute_txid())?;
1604
    ///     builder
1605
    ///         .fee_rate(FeeRate::from_sat_per_vb(5).expect("valid feerate"));
1606
    ///     builder.finish()?
1607
    /// };
1608
    ///
1609
    /// let _ = wallet.sign(&mut psbt, SignOptions::default())?;
1610
    /// let fee_bumped_tx = psbt.extract_tx();
1611
    /// // broadcast fee_bumped_tx to replace original
1612
    /// # Ok::<(), anyhow::Error>(())
1613
    /// ```
1614
    // TODO: support for merging multiple transactions while bumping the fees
1615
    pub fn build_fee_bump(
152✔
1616
        &mut self,
152✔
1617
        txid: Txid,
152✔
1618
    ) -> Result<TxBuilder<'_, DefaultCoinSelectionAlgorithm>, BuildFeeBumpError> {
152✔
1619
        let graph = self.indexed_graph.graph();
152✔
1620
        let txout_index = &self.indexed_graph.index;
152✔
1621
        let chain_tip = self.chain.tip().block_id();
152✔
1622

1623
        let mut tx = graph
152✔
1624
            .get_tx(txid)
152✔
1625
            .ok_or(BuildFeeBumpError::TransactionNotFound(txid))?
152✔
1626
            .as_ref()
152✔
1627
            .clone();
152✔
1628

1629
        let pos = graph
152✔
1630
            .get_chain_position(&self.chain, chain_tip, txid)
152✔
1631
            .ok_or(BuildFeeBumpError::TransactionNotFound(txid))?;
152✔
1632
        if let ChainPosition::Confirmed(_) = pos {
152✔
1633
            return Err(BuildFeeBumpError::TransactionConfirmed(txid));
8✔
1634
        }
144✔
1635

144✔
1636
        if !tx
144✔
1637
            .input
144✔
1638
            .iter()
144✔
1639
            .any(|txin| txin.sequence.to_consensus_u32() <= 0xFFFFFFFD)
144✔
1640
        {
1641
            return Err(BuildFeeBumpError::IrreplaceableTransaction(
8✔
1642
                tx.compute_txid(),
8✔
1643
            ));
8✔
1644
        }
136✔
1645

1646
        let fee = self
136✔
1647
            .calculate_fee(&tx)
136✔
1648
            .map_err(|_| BuildFeeBumpError::FeeRateUnavailable)?;
136✔
1649
        let fee_rate = self
136✔
1650
            .calculate_fee_rate(&tx)
136✔
1651
            .map_err(|_| BuildFeeBumpError::FeeRateUnavailable)?;
136✔
1652

1653
        // remove the inputs from the tx and process them
1654
        let original_txin = tx.input.drain(..).collect::<Vec<_>>();
136✔
1655
        let original_utxos = original_txin
136✔
1656
            .iter()
136✔
1657
            .map(|txin| -> Result<_, BuildFeeBumpError> {
144✔
1658
                let prev_tx = graph
144✔
1659
                    .get_tx(txin.previous_output.txid)
144✔
1660
                    .ok_or(BuildFeeBumpError::UnknownUtxo(txin.previous_output))?;
144✔
1661
                let txout = &prev_tx.output[txin.previous_output.vout as usize];
144✔
1662

1663
                let chain_position = graph
144✔
1664
                    .get_chain_position(&self.chain, chain_tip, txin.previous_output.txid)
144✔
1665
                    .ok_or(BuildFeeBumpError::UnknownUtxo(txin.previous_output))?
144✔
1666
                    .cloned();
144✔
1667

1668
                let weighted_utxo = match txout_index.index_of_spk(txout.script_pubkey.clone()) {
144✔
1669
                    Some(&(keychain, derivation_index)) => {
144✔
1670
                        let satisfaction_weight = self
144✔
1671
                            .public_descriptor(keychain)
144✔
1672
                            .max_weight_to_satisfy()
144✔
1673
                            .unwrap();
144✔
1674
                        WeightedUtxo {
144✔
1675
                            utxo: Utxo::Local(LocalOutput {
144✔
1676
                                outpoint: txin.previous_output,
144✔
1677
                                txout: txout.clone(),
144✔
1678
                                keychain,
144✔
1679
                                is_spent: true,
144✔
1680
                                derivation_index,
144✔
1681
                                chain_position,
144✔
1682
                            }),
144✔
1683
                            satisfaction_weight,
144✔
1684
                        }
144✔
1685
                    }
1686
                    None => {
1687
                        let satisfaction_weight = Weight::from_wu_usize(
×
1688
                            serialize(&txin.script_sig).len() * 4 + serialize(&txin.witness).len(),
×
1689
                        );
×
1690
                        WeightedUtxo {
×
1691
                            utxo: Utxo::Foreign {
×
1692
                                outpoint: txin.previous_output,
×
1693
                                sequence: Some(txin.sequence),
×
1694
                                psbt_input: Box::new(psbt::Input {
×
1695
                                    witness_utxo: Some(txout.clone()),
×
1696
                                    non_witness_utxo: Some(prev_tx.as_ref().clone()),
×
1697
                                    ..Default::default()
×
1698
                                }),
×
1699
                            },
×
1700
                            satisfaction_weight,
×
1701
                        }
×
1702
                    }
1703
                };
1704

1705
                Ok(weighted_utxo)
144✔
1706
            })
144✔
1707
            .collect::<Result<Vec<_>, _>>()?;
136✔
1708

1709
        if tx.output.len() > 1 {
136✔
1710
            let mut change_index = None;
80✔
1711
            for (index, txout) in tx.output.iter().enumerate() {
160✔
1712
                let change_keychain = KeychainKind::Internal;
160✔
1713
                match txout_index.index_of_spk(txout.script_pubkey.clone()) {
160✔
1714
                    Some((keychain, _)) if *keychain == change_keychain => {
104✔
1715
                        change_index = Some(index)
80✔
1716
                    }
1717
                    _ => {}
80✔
1718
                }
1719
            }
1720

1721
            if let Some(change_index) = change_index {
80✔
1722
                tx.output.remove(change_index);
80✔
1723
            }
80✔
1724
        }
56✔
1725

1726
        let params = TxParams {
136✔
1727
            // TODO: figure out what rbf option should be?
136✔
1728
            version: Some(tx_builder::Version(tx.version.0)),
136✔
1729
            recipients: tx
136✔
1730
                .output
136✔
1731
                .into_iter()
136✔
1732
                .map(|txout| (txout.script_pubkey, txout.value))
136✔
1733
                .collect(),
136✔
1734
            utxos: original_utxos,
136✔
1735
            bumping_fee: Some(tx_builder::PreviousFee {
136✔
1736
                absolute: fee,
136✔
1737
                rate: fee_rate,
136✔
1738
            }),
136✔
1739
            ..Default::default()
136✔
1740
        };
136✔
1741

136✔
1742
        Ok(TxBuilder {
136✔
1743
            wallet: alloc::rc::Rc::new(core::cell::RefCell::new(self)),
136✔
1744
            params,
136✔
1745
            coin_selection: DefaultCoinSelectionAlgorithm::default(),
136✔
1746
        })
136✔
1747
    }
152✔
1748

1749
    /// Sign a transaction with all the wallet's signers, in the order specified by every signer's
1750
    /// [`SignerOrdering`]. This function returns the `Result` type with an encapsulated `bool` that has the value true if the PSBT was finalized, or false otherwise.
1751
    ///
1752
    /// The [`SignOptions`] can be used to tweak the behavior of the software signers, and the way
1753
    /// the transaction is finalized at the end. Note that it can't be guaranteed that *every*
1754
    /// signers will follow the options, but the "software signers" (WIF keys and `xprv`) defined
1755
    /// in this library will.
1756
    ///
1757
    /// ## Example
1758
    ///
1759
    /// ```
1760
    /// # use std::str::FromStr;
1761
    /// # use bitcoin::*;
1762
    /// # use bdk_wallet::*;
1763
    /// # use bdk_wallet::ChangeSet;
1764
    /// # use bdk_wallet::error::CreateTxError;
1765
    /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
1766
    /// # let mut wallet = doctest_wallet!();
1767
    /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
1768
    /// let mut psbt = {
1769
    ///     let mut builder = wallet.build_tx();
1770
    ///     builder.add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000));
1771
    ///     builder.finish()?
1772
    /// };
1773
    /// let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
1774
    /// assert!(finalized, "we should have signed all the inputs");
1775
    /// # Ok::<(),anyhow::Error>(())
1776
    pub fn sign(&self, psbt: &mut Psbt, sign_options: SignOptions) -> Result<bool, SignerError> {
376✔
1777
        // This adds all the PSBT metadata for the inputs, which will help us later figure out how
376✔
1778
        // to derive our keys
376✔
1779
        self.update_psbt_with_descriptor(psbt)
376✔
1780
            .map_err(SignerError::MiniscriptPsbt)?;
376✔
1781

1782
        // If we aren't allowed to use `witness_utxo`, ensure that every input (except p2tr and finalized ones)
1783
        // has the `non_witness_utxo`
1784
        if !sign_options.trust_witness_utxo
376✔
1785
            && psbt
328✔
1786
                .inputs
328✔
1787
                .iter()
328✔
1788
                .filter(|i| i.final_script_witness.is_none() && i.final_script_sig.is_none())
336✔
1789
                .filter(|i| i.tap_internal_key.is_none() && i.tap_merkle_root.is_none())
328✔
1790
                .any(|i| i.non_witness_utxo.is_none())
328✔
1791
        {
1792
            return Err(SignerError::MissingNonWitnessUtxo);
×
1793
        }
376✔
1794

376✔
1795
        // If the user hasn't explicitly opted-in, refuse to sign the transaction unless every input
376✔
1796
        // is using `SIGHASH_ALL` or `SIGHASH_DEFAULT` for taproot
376✔
1797
        if !sign_options.allow_all_sighashes
376✔
1798
            && !psbt.inputs.iter().all(|i| {
384✔
1799
                i.sighash_type.is_none()
384✔
1800
                    || i.sighash_type == Some(EcdsaSighashType::All.into())
24✔
1801
                    || i.sighash_type == Some(TapSighashType::All.into())
16✔
1802
                    || i.sighash_type == Some(TapSighashType::Default.into())
16✔
1803
            })
384✔
1804
        {
1805
            return Err(SignerError::NonStandardSighash);
16✔
1806
        }
360✔
1807

1808
        for signer in self
736✔
1809
            .signers
360✔
1810
            .signers()
360✔
1811
            .iter()
360✔
1812
            .chain(self.change_signers.signers().iter())
360✔
1813
        {
1814
            signer.sign_transaction(psbt, &sign_options, &self.secp)?;
736✔
1815
        }
1816

1817
        // attempt to finalize
1818
        if sign_options.try_finalize {
328✔
1819
            self.finalize_psbt(psbt, sign_options)
288✔
1820
        } else {
1821
            Ok(false)
40✔
1822
        }
1823
    }
376✔
1824

1825
    /// Return the spending policies for the wallet's descriptor
1826
    pub fn policies(&self, keychain: KeychainKind) -> Result<Option<Policy>, DescriptorError> {
24✔
1827
        let signers = match keychain {
24✔
1828
            KeychainKind::External => &self.signers,
24✔
1829
            KeychainKind::Internal => &self.change_signers,
×
1830
        };
1831

1832
        self.public_descriptor(keychain).extract_policy(
24✔
1833
            signers,
24✔
1834
            BuildSatisfaction::None,
24✔
1835
            &self.secp,
24✔
1836
        )
24✔
1837
    }
24✔
1838

1839
    /// Returns the descriptor used to create addresses for a particular `keychain`.
1840
    ///
1841
    /// It's the "public" version of the wallet's descriptor, meaning a new descriptor that has
1842
    /// the same structure but with the all secret keys replaced by their corresponding public key.
1843
    /// This can be used to build a watch-only version of a wallet.
1844
    pub fn public_descriptor(&self, keychain: KeychainKind) -> &ExtendedDescriptor {
6,548✔
1845
        self.indexed_graph
6,548✔
1846
            .index
6,548✔
1847
            .get_descriptor(self.map_keychain(keychain))
6,548✔
1848
            .expect("keychain must exist")
6,548✔
1849
    }
6,548✔
1850

1851
    /// Finalize a PSBT, i.e., for each input determine if sufficient data is available to pass
1852
    /// validation and construct the respective `scriptSig` or `scriptWitness`. Please refer to
1853
    /// [BIP174](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#Input_Finalizer),
1854
    /// and [BIP371](https://github.com/bitcoin/bips/blob/master/bip-0371.mediawiki)
1855
    /// for further information.
1856
    ///
1857
    /// Returns `true` if the PSBT could be finalized, and `false` otherwise.
1858
    ///
1859
    /// The [`SignOptions`] can be used to tweak the behavior of the finalizer.
1860
    pub fn finalize_psbt(
288✔
1861
        &self,
288✔
1862
        psbt: &mut Psbt,
288✔
1863
        sign_options: SignOptions,
288✔
1864
    ) -> Result<bool, SignerError> {
288✔
1865
        let chain_tip = self.chain.tip().block_id();
288✔
1866

288✔
1867
        let tx = &psbt.unsigned_tx;
288✔
1868
        let mut finished = true;
288✔
1869

1870
        for (n, input) in tx.input.iter().enumerate() {
328✔
1871
            let psbt_input = &psbt
328✔
1872
                .inputs
328✔
1873
                .get(n)
328✔
1874
                .ok_or(SignerError::InputIndexOutOfRange)?;
328✔
1875
            if psbt_input.final_script_sig.is_some() || psbt_input.final_script_witness.is_some() {
320✔
1876
                continue;
16✔
1877
            }
304✔
1878
            let confirmation_height = self
304✔
1879
                .indexed_graph
304✔
1880
                .graph()
304✔
1881
                .get_chain_position(&self.chain, chain_tip, input.previous_output.txid)
304✔
1882
                .map(|chain_position| match chain_position {
304✔
1883
                    ChainPosition::Confirmed(a) => a.block_id.height,
272✔
1884
                    ChainPosition::Unconfirmed(_) => u32::MAX,
8✔
1885
                });
304✔
1886
            let current_height = sign_options
304✔
1887
                .assume_height
304✔
1888
                .unwrap_or_else(|| self.chain.tip().height());
304✔
1889

304✔
1890
            // - Try to derive the descriptor by looking at the txout. If it's in our database, we
304✔
1891
            //   know exactly which `keychain` to use, and which derivation index it is
304✔
1892
            // - If that fails, try to derive it by looking at the psbt input: the complete logic
304✔
1893
            //   is in `src/descriptor/mod.rs`, but it will basically look at `bip32_derivation`,
304✔
1894
            //   `redeem_script` and `witness_script` to determine the right derivation
304✔
1895
            // - If that also fails, it will try it on the internal descriptor, if present
304✔
1896
            let desc = psbt
304✔
1897
                .get_utxo_for(n)
304✔
1898
                .and_then(|txout| self.get_descriptor_for_txout(&txout))
304✔
1899
                .or_else(|| {
304✔
1900
                    self.indexed_graph.index.keychains().find_map(|(_, desc)| {
32✔
1901
                        desc.derive_from_psbt_input(psbt_input, psbt.get_utxo_for(n), &self.secp)
32✔
1902
                    })
32✔
1903
                });
304✔
1904

304✔
1905
            match desc {
304✔
1906
                Some(desc) => {
288✔
1907
                    let mut tmp_input = bitcoin::TxIn::default();
288✔
1908
                    match desc.satisfy(
288✔
1909
                        &mut tmp_input,
288✔
1910
                        (
288✔
1911
                            PsbtInputSatisfier::new(psbt, n),
288✔
1912
                            After::new(Some(current_height), false),
288✔
1913
                            Older::new(Some(current_height), confirmation_height, false),
288✔
1914
                        ),
288✔
1915
                    ) {
288✔
1916
                        Ok(_) => {
1917
                            // Set the UTXO fields, final script_sig and witness
1918
                            // and clear everything else.
1919
                            let original = mem::take(&mut psbt.inputs[n]);
280✔
1920
                            let psbt_input = &mut psbt.inputs[n];
280✔
1921
                            psbt_input.non_witness_utxo = original.non_witness_utxo;
280✔
1922
                            psbt_input.witness_utxo = original.witness_utxo;
280✔
1923
                            if !tmp_input.script_sig.is_empty() {
280✔
1924
                                psbt_input.final_script_sig = Some(tmp_input.script_sig);
16✔
1925
                            }
264✔
1926
                            if !tmp_input.witness.is_empty() {
280✔
1927
                                psbt_input.final_script_witness = Some(tmp_input.witness);
272✔
1928
                            }
272✔
1929
                        }
1930
                        Err(_) => finished = false,
8✔
1931
                    }
1932
                }
1933
                None => finished = false,
16✔
1934
            }
1935
        }
1936

1937
        // Clear derivation paths from outputs
1938
        if finished {
280✔
1939
            for output in &mut psbt.outputs {
608✔
1940
                output.bip32_derivation.clear();
352✔
1941
                output.tap_key_origins.clear();
352✔
1942
            }
352✔
1943
        }
24✔
1944

1945
        Ok(finished)
280✔
1946
    }
288✔
1947

1948
    /// Return the secp256k1 context used for all signing operations
1949
    pub fn secp_ctx(&self) -> &SecpCtx {
36✔
1950
        &self.secp
36✔
1951
    }
36✔
1952

1953
    /// The derivation index of this wallet. It will return `None` if it has not derived any addresses.
1954
    /// Otherwise, it will return the index of the highest address it has derived.
1955
    pub fn derivation_index(&self, keychain: KeychainKind) -> Option<u32> {
104✔
1956
        self.indexed_graph.index.last_revealed_index(keychain)
104✔
1957
    }
104✔
1958

1959
    /// The index of the next address that you would get if you were to ask the wallet for a new address
1960
    pub fn next_derivation_index(&self, keychain: KeychainKind) -> u32 {
×
1961
        self.indexed_graph
×
1962
            .index
×
1963
            .next_index(self.map_keychain(keychain))
×
1964
            .expect("keychain must exist")
×
1965
            .0
×
1966
    }
×
1967

1968
    /// Informs the wallet that you no longer intend to broadcast a tx that was built from it.
1969
    ///
1970
    /// This frees up the change address used when creating the tx for use in future transactions.
1971
    // TODO: Make this free up reserved utxos when that's implemented
1972
    pub fn cancel_tx(&mut self, tx: &Transaction) {
16✔
1973
        let txout_index = &mut self.indexed_graph.index;
16✔
1974
        for txout in &tx.output {
48✔
1975
            if let Some((keychain, index)) = txout_index.index_of_spk(txout.script_pubkey.clone()) {
32✔
1976
                // NOTE: unmark_used will **not** make something unused if it has actually been used
16✔
1977
                // by a tx in the tracker. It only removes the superficial marking.
16✔
1978
                txout_index.unmark_used(*keychain, *index);
16✔
1979
            }
16✔
1980
        }
1981
    }
16✔
1982

1983
    fn get_descriptor_for_txout(&self, txout: &TxOut) -> Option<DerivedDescriptor> {
304✔
1984
        let &(keychain, child) = self
304✔
1985
            .indexed_graph
304✔
1986
            .index
304✔
1987
            .index_of_spk(txout.script_pubkey.clone())?;
304✔
1988
        let descriptor = self.public_descriptor(keychain);
288✔
1989
        descriptor.at_derivation_index(child).ok()
288✔
1990
    }
304✔
1991

1992
    fn get_available_utxos(&self) -> Vec<(LocalOutput, Weight)> {
1,232✔
1993
        self.list_unspent()
1,232✔
1994
            .map(|utxo| {
1,344✔
1995
                let keychain = utxo.keychain;
1,344✔
1996
                (utxo, {
1,344✔
1997
                    self.public_descriptor(keychain)
1,344✔
1998
                        .max_weight_to_satisfy()
1,344✔
1999
                        .unwrap()
1,344✔
2000
                })
1,344✔
2001
            })
1,344✔
2002
            .collect()
1,232✔
2003
    }
1,232✔
2004

2005
    /// Given the options returns the list of utxos that must be used to form the
2006
    /// transaction and any further that may be used if needed.
2007
    fn preselect_utxos(
1,232✔
2008
        &self,
1,232✔
2009
        params: &TxParams,
1,232✔
2010
        current_height: Option<u32>,
1,232✔
2011
    ) -> (Vec<WeightedUtxo>, Vec<WeightedUtxo>) {
1,232✔
2012
        let TxParams {
1,232✔
2013
            change_policy,
1,232✔
2014
            unspendable,
1,232✔
2015
            utxos,
1,232✔
2016
            drain_wallet,
1,232✔
2017
            manually_selected_only,
1,232✔
2018
            bumping_fee,
1,232✔
2019
            ..
1,232✔
2020
        } = params;
1,232✔
2021

1,232✔
2022
        let manually_selected = utxos.clone();
1,232✔
2023
        // we mandate confirmed transactions if we're bumping the fee
1,232✔
2024
        let must_only_use_confirmed_tx = bumping_fee.is_some();
1,232✔
2025
        let must_use_all_available = *drain_wallet;
1,232✔
2026

1,232✔
2027
        let chain_tip = self.chain.tip().block_id();
1,232✔
2028
        //    must_spend <- manually selected utxos
1,232✔
2029
        //    may_spend  <- all other available utxos
1,232✔
2030
        let mut may_spend = self.get_available_utxos();
1,232✔
2031

1,232✔
2032
        may_spend.retain(|may_spend| {
1,344✔
2033
            !manually_selected
1,344✔
2034
                .iter()
1,344✔
2035
                .any(|manually_selected| manually_selected.utxo.outpoint() == may_spend.0.outpoint)
1,344✔
2036
        });
1,344✔
2037
        let mut must_spend = manually_selected;
1,232✔
2038

1,232✔
2039
        // NOTE: we are intentionally ignoring `unspendable` here. i.e manual
1,232✔
2040
        // selection overrides unspendable.
1,232✔
2041
        if *manually_selected_only {
1,232✔
2042
            return (must_spend, vec![]);
40✔
2043
        }
1,192✔
2044

1,192✔
2045
        let satisfies_confirmed = may_spend
1,192✔
2046
            .iter()
1,192✔
2047
            .map(|u| -> bool {
1,232✔
2048
                let txid = u.0.outpoint.txid;
1,232✔
2049
                let tx = match self.indexed_graph.graph().get_tx(txid) {
1,232✔
2050
                    Some(tx) => tx,
1,232✔
2051
                    None => return false,
×
2052
                };
2053
                let chain_position = match self.indexed_graph.graph().get_chain_position(
1,232✔
2054
                    &self.chain,
1,232✔
2055
                    chain_tip,
1,232✔
2056
                    txid,
1,232✔
2057
                ) {
1,232✔
2058
                    Some(chain_position) => chain_position.cloned(),
1,232✔
UNCOV
2059
                    None => return false,
×
2060
                };
2061

2062
                // Whether the UTXO is mature and, if needed, confirmed
2063
                let mut spendable = true;
1,232✔
2064
                if must_only_use_confirmed_tx && !chain_position.is_confirmed() {
1,232✔
2065
                    return false;
64✔
2066
                }
1,168✔
2067
                if tx.is_coinbase() {
1,168✔
2068
                    debug_assert!(
24✔
2069
                        chain_position.is_confirmed(),
24✔
2070
                        "coinbase must always be confirmed"
×
2071
                    );
2072
                    if let Some(current_height) = current_height {
24✔
2073
                        match chain_position {
24✔
2074
                            ChainPosition::Confirmed(a) => {
24✔
2075
                                // https://github.com/bitcoin/bitcoin/blob/c5e67be03bb06a5d7885c55db1f016fbf2333fe3/src/validation.cpp#L373-L375
24✔
2076
                                spendable &= (current_height.saturating_sub(a.block_id.height))
24✔
2077
                                    >= COINBASE_MATURITY;
24✔
2078
                            }
24✔
NEW
2079
                            ChainPosition::Unconfirmed { .. } => spendable = false,
×
2080
                        }
2081
                    }
×
2082
                }
1,144✔
2083
                spendable
1,168✔
2084
            })
1,232✔
2085
            .collect::<Vec<_>>();
1,192✔
2086

1,192✔
2087
        let mut i = 0;
1,192✔
2088
        may_spend.retain(|u| {
1,232✔
2089
            let retain = (self.keychains().count() == 1 || change_policy.is_satisfied_by(&u.0))
1,232✔
2090
                && !unspendable.contains(&u.0.outpoint)
1,224✔
2091
                && satisfies_confirmed[i];
1,224✔
2092
            i += 1;
1,232✔
2093
            retain
1,232✔
2094
        });
1,232✔
2095

1,192✔
2096
        let mut may_spend = may_spend
1,192✔
2097
            .into_iter()
1,192✔
2098
            .map(|(local_utxo, satisfaction_weight)| WeightedUtxo {
1,192✔
2099
                satisfaction_weight,
1,144✔
2100
                utxo: Utxo::Local(local_utxo),
1,144✔
2101
            })
1,192✔
2102
            .collect();
1,192✔
2103

1,192✔
2104
        if must_use_all_available {
1,192✔
2105
            must_spend.append(&mut may_spend);
392✔
2106
        }
800✔
2107

2108
        (must_spend, may_spend)
1,192✔
2109
    }
1,232✔
2110

2111
    fn complete_transaction(
1,144✔
2112
        &self,
1,144✔
2113
        tx: Transaction,
1,144✔
2114
        selected: Vec<Utxo>,
1,144✔
2115
        params: TxParams,
1,144✔
2116
    ) -> Result<Psbt, CreateTxError> {
1,144✔
2117
        let mut psbt = Psbt::from_unsigned_tx(tx)?;
1,144✔
2118

2119
        if params.add_global_xpubs {
1,144✔
2120
            let all_xpubs = self
24✔
2121
                .keychains()
24✔
2122
                .flat_map(|(_, desc)| desc.get_extended_keys())
48✔
2123
                .collect::<Vec<_>>();
24✔
2124

2125
            for xpub in all_xpubs {
56✔
2126
                let origin = match xpub.origin {
32✔
2127
                    Some(origin) => origin,
24✔
2128
                    None if xpub.xkey.depth == 0 => {
16✔
2129
                        (xpub.root_fingerprint(&self.secp), vec![].into())
8✔
2130
                    }
2131
                    _ => return Err(CreateTxError::MissingKeyOrigin(xpub.xkey.to_string())),
8✔
2132
                };
2133

2134
                psbt.xpub.insert(xpub.xkey, origin);
32✔
2135
            }
2136
        }
1,120✔
2137

2138
        let mut lookup_output = selected
1,136✔
2139
            .into_iter()
1,136✔
2140
            .map(|utxo| (utxo.outpoint(), utxo))
1,264✔
2141
            .collect::<HashMap<_, _>>();
1,136✔
2142

2143
        // add metadata for the inputs
2144
        for (psbt_input, input) in psbt.inputs.iter_mut().zip(psbt.unsigned_tx.input.iter()) {
1,264✔
2145
            let utxo = match lookup_output.remove(&input.previous_output) {
1,264✔
2146
                Some(utxo) => utxo,
1,264✔
2147
                None => continue,
×
2148
            };
2149

2150
            match utxo {
1,264✔
2151
                Utxo::Local(utxo) => {
1,216✔
2152
                    *psbt_input =
1,216✔
2153
                        match self.get_psbt_input(utxo, params.sighash, params.only_witness_utxo) {
1,216✔
2154
                            Ok(psbt_input) => psbt_input,
1,216✔
2155
                            Err(e) => match e {
×
2156
                                CreateTxError::UnknownUtxo => psbt::Input {
×
2157
                                    sighash_type: params.sighash,
×
2158
                                    ..psbt::Input::default()
×
2159
                                },
×
2160
                                _ => return Err(e),
×
2161
                            },
2162
                        }
2163
                }
2164
                Utxo::Foreign {
2165
                    outpoint,
48✔
2166
                    psbt_input: foreign_psbt_input,
48✔
2167
                    ..
48✔
2168
                } => {
48✔
2169
                    let is_taproot = foreign_psbt_input
48✔
2170
                        .witness_utxo
48✔
2171
                        .as_ref()
48✔
2172
                        .map(|txout| txout.script_pubkey.is_p2tr())
48✔
2173
                        .unwrap_or(false);
48✔
2174
                    if !is_taproot
48✔
2175
                        && !params.only_witness_utxo
40✔
2176
                        && foreign_psbt_input.non_witness_utxo.is_none()
16✔
2177
                    {
2178
                        return Err(CreateTxError::MissingNonWitnessUtxo(outpoint));
8✔
2179
                    }
40✔
2180
                    *psbt_input = *foreign_psbt_input;
40✔
2181
                }
2182
            }
2183
        }
2184

2185
        self.update_psbt_with_descriptor(&mut psbt)?;
1,128✔
2186

2187
        Ok(psbt)
1,128✔
2188
    }
1,144✔
2189

2190
    /// get the corresponding PSBT Input for a LocalUtxo
2191
    pub fn get_psbt_input(
1,232✔
2192
        &self,
1,232✔
2193
        utxo: LocalOutput,
1,232✔
2194
        sighash_type: Option<psbt::PsbtSighashType>,
1,232✔
2195
        only_witness_utxo: bool,
1,232✔
2196
    ) -> Result<psbt::Input, CreateTxError> {
1,232✔
2197
        // Try to find the prev_script in our db to figure out if this is internal or external,
2198
        // and the derivation index
2199
        let &(keychain, child) = self
1,232✔
2200
            .indexed_graph
1,232✔
2201
            .index
1,232✔
2202
            .index_of_spk(utxo.txout.script_pubkey)
1,232✔
2203
            .ok_or(CreateTxError::UnknownUtxo)?;
1,232✔
2204

2205
        let mut psbt_input = psbt::Input {
1,232✔
2206
            sighash_type,
1,232✔
2207
            ..psbt::Input::default()
1,232✔
2208
        };
1,232✔
2209

1,232✔
2210
        let desc = self.public_descriptor(keychain);
1,232✔
2211
        let derived_descriptor = desc
1,232✔
2212
            .at_derivation_index(child)
1,232✔
2213
            .expect("child can't be hardened");
1,232✔
2214

1,232✔
2215
        psbt_input
1,232✔
2216
            .update_with_descriptor_unchecked(&derived_descriptor)
1,232✔
2217
            .map_err(MiniscriptPsbtError::Conversion)?;
1,232✔
2218

2219
        let prev_output = utxo.outpoint;
1,232✔
2220
        if let Some(prev_tx) = self.indexed_graph.graph().get_tx(prev_output.txid) {
1,232✔
2221
            if desc.is_witness() || desc.is_taproot() {
1,232✔
2222
                psbt_input.witness_utxo = Some(prev_tx.output[prev_output.vout as usize].clone());
1,200✔
2223
            }
1,200✔
2224
            if !desc.is_taproot() && (!desc.is_witness() || !only_witness_utxo) {
1,232✔
2225
                psbt_input.non_witness_utxo = Some(prev_tx.as_ref().clone());
904✔
2226
            }
904✔
2227
        }
×
2228
        Ok(psbt_input)
1,232✔
2229
    }
1,232✔
2230

2231
    fn update_psbt_with_descriptor(&self, psbt: &mut Psbt) -> Result<(), MiniscriptPsbtError> {
1,504✔
2232
        // We need to borrow `psbt` mutably within the loops, so we have to allocate a vec for all
1,504✔
2233
        // the input utxos and outputs
1,504✔
2234
        let utxos = (0..psbt.inputs.len())
1,504✔
2235
            .filter_map(|i| psbt.get_utxo_for(i).map(|utxo| (true, i, utxo)))
1,672✔
2236
            .chain(
1,504✔
2237
                psbt.unsigned_tx
1,504✔
2238
                    .output
1,504✔
2239
                    .iter()
1,504✔
2240
                    .enumerate()
1,504✔
2241
                    .map(|(i, out)| (false, i, out.clone())),
2,352✔
2242
            )
1,504✔
2243
            .collect::<Vec<_>>();
1,504✔
2244

2245
        // Try to figure out the keychain and derivation for every input and output
2246
        for (is_input, index, out) in utxos.into_iter() {
3,984✔
2247
            if let Some(&(keychain, child)) =
3,280✔
2248
                self.indexed_graph.index.index_of_spk(out.script_pubkey)
3,984✔
2249
            {
2250
                let desc = self.public_descriptor(keychain);
3,280✔
2251
                let desc = desc
3,280✔
2252
                    .at_derivation_index(child)
3,280✔
2253
                    .expect("child can't be hardened");
3,280✔
2254

3,280✔
2255
                if is_input {
3,280✔
2256
                    psbt.update_input_with_descriptor(index, &desc)
1,560✔
2257
                        .map_err(MiniscriptPsbtError::UtxoUpdate)?;
1,560✔
2258
                } else {
2259
                    psbt.update_output_with_descriptor(index, &desc)
1,720✔
2260
                        .map_err(MiniscriptPsbtError::OutputUpdate)?;
1,720✔
2261
                }
2262
            }
704✔
2263
        }
2264

2265
        Ok(())
1,504✔
2266
    }
1,504✔
2267

2268
    /// Return the checksum of the public descriptor associated to `keychain`
2269
    ///
2270
    /// Internally calls [`Self::public_descriptor`] to fetch the right descriptor
2271
    pub fn descriptor_checksum(&self, keychain: KeychainKind) -> String {
8✔
2272
        self.public_descriptor(keychain)
8✔
2273
            .to_string()
8✔
2274
            .split_once('#')
8✔
2275
            .unwrap()
8✔
2276
            .1
8✔
2277
            .to_string()
8✔
2278
    }
8✔
2279

2280
    /// Applies an update to the wallet and stages the changes (but does not persist them).
2281
    ///
2282
    /// Usually you create an `update` by interacting with some blockchain data source and inserting
2283
    /// transactions related to your wallet into it.
2284
    ///
2285
    /// After applying updates you should persist the staged wallet changes. For an example of how
2286
    /// to persist staged wallet changes see [`Wallet::reveal_next_address`].
2287
    #[cfg(feature = "std")]
2288
    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
2289
    pub fn apply_update(&mut self, update: impl Into<Update>) -> Result<(), CannotConnectError> {
313✔
2290
        use std::time::*;
2291
        let now = SystemTime::now()
313✔
2292
            .duration_since(UNIX_EPOCH)
313✔
2293
            .expect("time now must surpass epoch anchor");
313✔
2294
        self.apply_update_at(update, Some(now.as_secs()))
313✔
2295
    }
313✔
2296

2297
    /// Applies an `update` alongside an optional `seen_at` timestamp and stages the changes.
2298
    ///
2299
    /// `seen_at` represents when the update is seen (in unix seconds). It is used to determine the
2300
    /// `last_seen`s for all transactions in the update which have no corresponding anchor(s). The
2301
    /// `last_seen` value is used internally to determine precedence of conflicting unconfirmed
2302
    /// transactions (where the transaction with the lower `last_seen` value is omitted from the
2303
    /// canonical history).
2304
    ///
2305
    /// Not setting a `seen_at` value means unconfirmed transactions introduced by this update will
2306
    /// not be part of the canonical history of transactions.
2307
    ///
2308
    /// Use [`apply_update`](Wallet::apply_update) to have the `seen_at` value automatically set to
2309
    /// the current time.
2310
    pub fn apply_update_at(
313✔
2311
        &mut self,
313✔
2312
        update: impl Into<Update>,
313✔
2313
        seen_at: Option<u64>,
313✔
2314
    ) -> Result<(), CannotConnectError> {
313✔
2315
        let update = update.into();
313✔
2316
        let mut changeset = match update.chain {
313✔
2317
            Some(chain_update) => ChangeSet::from(self.chain.apply_update(chain_update)?),
×
2318
            None => ChangeSet::default(),
313✔
2319
        };
2320

2321
        let index_changeset = self
313✔
2322
            .indexed_graph
313✔
2323
            .index
313✔
2324
            .reveal_to_target_multi(&update.last_active_indices);
313✔
2325
        changeset.merge(index_changeset.into());
313✔
2326
        changeset.merge(
313✔
2327
            self.indexed_graph
313✔
2328
                .apply_update_at(update.tx_update, seen_at)
313✔
2329
                .into(),
313✔
2330
        );
313✔
2331
        self.stage.merge(changeset);
313✔
2332
        Ok(())
313✔
2333
    }
313✔
2334

2335
    /// Get a reference of the staged [`ChangeSet`] that is yet to be committed (if any).
2336
    pub fn staged(&self) -> Option<&ChangeSet> {
×
2337
        if self.stage.is_empty() {
×
2338
            None
×
2339
        } else {
2340
            Some(&self.stage)
×
2341
        }
2342
    }
×
2343

2344
    /// Get a mutable reference of the staged [`ChangeSet`] that is yet to be committed (if any).
2345
    pub fn staged_mut(&mut self) -> Option<&mut ChangeSet> {
24✔
2346
        if self.stage.is_empty() {
24✔
2347
            None
×
2348
        } else {
2349
            Some(&mut self.stage)
24✔
2350
        }
2351
    }
24✔
2352

2353
    /// Take the staged [`ChangeSet`] to be persisted now (if any).
2354
    pub fn take_staged(&mut self) -> Option<ChangeSet> {
56✔
2355
        self.stage.take()
56✔
2356
    }
56✔
2357

2358
    /// Get a reference to the inner [`TxGraph`].
2359
    pub fn tx_graph(&self) -> &TxGraph<ConfirmationBlockTime> {
×
2360
        self.indexed_graph.graph()
×
2361
    }
×
2362

2363
    /// Iterate over transactions in the wallet that are unseen and unanchored likely
2364
    /// because they haven't been broadcast.
2365
    pub fn unbroadcast_transactions(
×
2366
        &self,
×
2367
    ) -> impl Iterator<Item = TxNode<'_, Arc<Transaction>, ConfirmationBlockTime>> {
×
2368
        self.tx_graph().txs_with_no_anchor_or_last_seen()
×
2369
    }
×
2370

2371
    /// Get a reference to the inner [`KeychainTxOutIndex`].
2372
    pub fn spk_index(&self) -> &KeychainTxOutIndex<KeychainKind> {
48✔
2373
        &self.indexed_graph.index
48✔
2374
    }
48✔
2375

2376
    /// Get a reference to the inner [`LocalChain`].
UNCOV
2377
    pub fn local_chain(&self) -> &LocalChain {
×
UNCOV
2378
        &self.chain
×
UNCOV
2379
    }
×
2380

2381
    /// Introduces a `block` of `height` to the wallet, and tries to connect it to the
2382
    /// `prev_blockhash` of the block's header.
2383
    ///
2384
    /// This is a convenience method that is equivalent to calling [`apply_block_connected_to`]
2385
    /// with `prev_blockhash` and `height-1` as the `connected_to` parameter.
2386
    ///
2387
    /// [`apply_block_connected_to`]: Self::apply_block_connected_to
2388
    pub fn apply_block(&mut self, block: &Block, height: u32) -> Result<(), CannotConnectError> {
×
2389
        let connected_to = match height.checked_sub(1) {
×
2390
            Some(prev_height) => BlockId {
×
2391
                height: prev_height,
×
2392
                hash: block.header.prev_blockhash,
×
2393
            },
×
2394
            None => BlockId {
×
2395
                height,
×
2396
                hash: block.block_hash(),
×
2397
            },
×
2398
        };
2399
        self.apply_block_connected_to(block, height, connected_to)
×
2400
            .map_err(|err| match err {
×
2401
                ApplyHeaderError::InconsistentBlocks => {
2402
                    unreachable!("connected_to is derived from the block so must be consistent")
×
2403
                }
2404
                ApplyHeaderError::CannotConnect(err) => err,
×
2405
            })
×
2406
    }
×
2407

2408
    /// Applies relevant transactions from `block` of `height` to the wallet, and connects the
2409
    /// block to the internal chain.
2410
    ///
2411
    /// The `connected_to` parameter informs the wallet how this block connects to the internal
2412
    /// [`LocalChain`]. Relevant transactions are filtered from the `block` and inserted into the
2413
    /// internal [`TxGraph`].
2414
    ///
2415
    /// **WARNING**: You must persist the changes resulting from one or more calls to this method
2416
    /// if you need the inserted block data to be reloaded after closing the wallet.
2417
    /// See [`Wallet::reveal_next_address`].
2418
    pub fn apply_block_connected_to(
×
2419
        &mut self,
×
2420
        block: &Block,
×
2421
        height: u32,
×
2422
        connected_to: BlockId,
×
2423
    ) -> Result<(), ApplyHeaderError> {
×
2424
        let mut changeset = ChangeSet::default();
×
2425
        changeset.merge(
×
2426
            self.chain
×
2427
                .apply_header_connected_to(&block.header, height, connected_to)?
×
2428
                .into(),
×
2429
        );
×
2430
        changeset.merge(
×
2431
            self.indexed_graph
×
2432
                .apply_block_relevant(block, height)
×
2433
                .into(),
×
2434
        );
×
2435
        self.stage.merge(changeset);
×
2436
        Ok(())
×
2437
    }
×
2438

2439
    /// Apply relevant unconfirmed transactions to the wallet.
2440
    ///
2441
    /// Transactions that are not relevant are filtered out.
2442
    ///
2443
    /// This method takes in an iterator of `(tx, last_seen)` where `last_seen` is the timestamp of
2444
    /// when the transaction was last seen in the mempool. This is used for conflict resolution
2445
    /// when there is conflicting unconfirmed transactions. The transaction with the later
2446
    /// `last_seen` is prioritized.
2447
    ///
2448
    /// **WARNING**: You must persist the changes resulting from one or more calls to this method
2449
    /// if you need the applied unconfirmed transactions to be reloaded after closing the wallet.
2450
    /// See [`Wallet::reveal_next_address`].
2451
    pub fn apply_unconfirmed_txs<T: Into<Arc<Transaction>>>(
×
2452
        &mut self,
×
2453
        unconfirmed_txs: impl IntoIterator<Item = (T, u64)>,
×
2454
    ) {
×
2455
        let indexed_graph_changeset = self
×
2456
            .indexed_graph
×
2457
            .batch_insert_relevant_unconfirmed(unconfirmed_txs);
×
2458
        self.stage.merge(indexed_graph_changeset.into());
×
2459
    }
×
2460

2461
    /// Used internally to ensure that all methods requiring a [`KeychainKind`] will use a
2462
    /// keychain with an associated descriptor. For example in case the wallet was created
2463
    /// with only one keychain, passing [`KeychainKind::Internal`] here will instead return
2464
    /// [`KeychainKind::External`].
2465
    fn map_keychain(&self, keychain: KeychainKind) -> KeychainKind {
10,588✔
2466
        if self.keychains().count() == 1 {
10,588✔
2467
            KeychainKind::External
328✔
2468
        } else {
2469
            keychain
10,260✔
2470
        }
2471
    }
10,588✔
2472
}
2473

2474
/// Methods to construct sync/full-scan requests for spk-based chain sources.
2475
impl Wallet {
2476
    /// Create a partial [`SyncRequest`] for this wallet for all revealed spks.
2477
    ///
2478
    /// This is the first step when performing a spk-based wallet partial sync, the returned
2479
    /// [`SyncRequest`] collects all revealed script pubkeys from the wallet keychain needed to
2480
    /// start a blockchain sync with a spk based blockchain client.
2481
    pub fn start_sync_with_revealed_spks(&self) -> SyncRequestBuilder<(KeychainKind, u32)> {
×
2482
        use bdk_chain::keychain_txout::SyncRequestBuilderExt;
2483
        SyncRequest::builder()
×
2484
            .chain_tip(self.chain.tip())
×
2485
            .revealed_spks_from_indexer(&self.indexed_graph.index, ..)
×
2486
    }
×
2487

2488
    /// Create a [`FullScanRequest] for this wallet.
2489
    ///
2490
    /// This is the first step when performing a spk-based wallet full scan, the returned
2491
    /// [`FullScanRequest] collects iterators for the wallet's keychain script pub keys needed to
2492
    /// start a blockchain full scan with a spk based blockchain client.
2493
    ///
2494
    /// This operation is generally only used when importing or restoring a previously used wallet
2495
    /// in which the list of used scripts is not known.
2496
    pub fn start_full_scan(&self) -> FullScanRequestBuilder<KeychainKind> {
×
2497
        use bdk_chain::keychain_txout::FullScanRequestBuilderExt;
2498
        FullScanRequest::builder()
×
2499
            .chain_tip(self.chain.tip())
×
2500
            .spks_from_indexer(&self.indexed_graph.index)
×
2501
    }
×
2502
}
2503

2504
impl AsRef<bdk_chain::tx_graph::TxGraph<ConfirmationBlockTime>> for Wallet {
2505
    fn as_ref(&self) -> &bdk_chain::tx_graph::TxGraph<ConfirmationBlockTime> {
×
2506
        self.indexed_graph.graph()
×
2507
    }
×
2508
}
2509

2510
/// Deterministically generate a unique name given the descriptors defining the wallet
2511
///
2512
/// Compatible with [`wallet_name_from_descriptor`]
2513
pub fn wallet_name_from_descriptor<T>(
×
2514
    descriptor: T,
×
2515
    change_descriptor: Option<T>,
×
2516
    network: Network,
×
2517
    secp: &SecpCtx,
×
2518
) -> Result<String, DescriptorError>
×
2519
where
×
2520
    T: IntoWalletDescriptor,
×
2521
{
×
2522
    //TODO check descriptors contains only public keys
2523
    let descriptor = descriptor
×
2524
        .into_wallet_descriptor(secp, network)?
×
2525
        .0
2526
        .to_string();
×
2527
    let mut wallet_name = descriptor.split_once('#').unwrap().1.to_string();
×
2528
    if let Some(change_descriptor) = change_descriptor {
×
2529
        let change_descriptor = change_descriptor
×
2530
            .into_wallet_descriptor(secp, network)?
×
2531
            .0
2532
            .to_string();
×
2533
        wallet_name.push_str(change_descriptor.split_once('#').unwrap().1);
×
2534
    }
×
2535

2536
    Ok(wallet_name)
×
2537
}
×
2538

2539
fn new_local_utxo(
1,520✔
2540
    keychain: KeychainKind,
1,520✔
2541
    derivation_index: u32,
1,520✔
2542
    full_txo: FullTxOut<ConfirmationBlockTime>,
1,520✔
2543
) -> LocalOutput {
1,520✔
2544
    LocalOutput {
1,520✔
2545
        outpoint: full_txo.outpoint,
1,520✔
2546
        txout: full_txo.txout,
1,520✔
2547
        is_spent: full_txo.spent_by.is_some(),
1,520✔
2548
        chain_position: full_txo.chain_position,
1,520✔
2549
        keychain,
1,520✔
2550
        derivation_index,
1,520✔
2551
    }
1,520✔
2552
}
1,520✔
2553

2554
fn create_indexer(
1,518✔
2555
    descriptor: ExtendedDescriptor,
1,518✔
2556
    change_descriptor: Option<ExtendedDescriptor>,
1,518✔
2557
    lookahead: u32,
1,518✔
2558
) -> Result<KeychainTxOutIndex<KeychainKind>, DescriptorError> {
1,518✔
2559
    let mut indexer = KeychainTxOutIndex::<KeychainKind>::new(lookahead);
1,518✔
2560

1,518✔
2561
    // let (descriptor, keymap) = descriptor;
1,518✔
2562
    // let signers = Arc::new(SignersContainer::build(keymap, &descriptor, secp));
1,518✔
2563
    assert!(indexer
1,518✔
2564
        .insert_descriptor(KeychainKind::External, descriptor)
1,518✔
2565
        .expect("first descriptor introduced must succeed"));
1,518✔
2566

2567
    // let (descriptor, keymap) = change_descriptor;
2568
    // let change_signers = Arc::new(SignersContainer::build(keymap, &descriptor, secp));
2569
    if let Some(change_descriptor) = change_descriptor {
1,518✔
2570
        assert!(indexer
1,454✔
2571
            .insert_descriptor(KeychainKind::Internal, change_descriptor)
1,454✔
2572
            .map_err(|e| {
1,454✔
2573
                use bdk_chain::indexer::keychain_txout::InsertDescriptorError;
2574
                match e {
16✔
2575
                    InsertDescriptorError::DescriptorAlreadyAssigned { .. } => {
2576
                        crate::descriptor::error::Error::ExternalAndInternalAreTheSame
16✔
2577
                    }
2578
                    InsertDescriptorError::KeychainAlreadyAssigned { .. } => {
2579
                        unreachable!("this is the first time we're assigning internal")
×
2580
                    }
2581
                }
2582
            })?);
1,454✔
2583
    }
64✔
2584

2585
    Ok(indexer)
1,494✔
2586
}
1,510✔
2587

2588
/// Transforms a [`FeeRate`] to `f64` with unit as sat/vb.
2589
#[macro_export]
2590
#[doc(hidden)]
2591
macro_rules! floating_rate {
2592
    ($rate:expr) => {{
2593
        use $crate::bitcoin::constants::WITNESS_SCALE_FACTOR;
2594
        // sat_kwu / 250.0 -> sat_vb
2595
        $rate.to_sat_per_kwu() as f64 / ((1000 / WITNESS_SCALE_FACTOR) as f64)
2596
    }};
2597
}
2598

2599
#[macro_export]
2600
#[doc(hidden)]
2601
/// Macro for getting a wallet for use in a doctest
2602
macro_rules! doctest_wallet {
2603
    () => {{
2604
        use $crate::bitcoin::{BlockHash, Transaction, absolute, TxOut, Network, hashes::Hash};
2605
        use $crate::chain::{ConfirmationBlockTime, BlockId, TxGraph, tx_graph};
2606
        use $crate::{Update, KeychainKind, Wallet};
2607
        let descriptor = "tr([73c5da0a/86'/0'/0']tprv8fMn4hSKPRC1oaCPqxDb1JWtgkpeiQvZhsr8W2xuy3GEMkzoArcAWTfJxYb6Wj8XNNDWEjfYKK4wGQXh3ZUXhDF2NcnsALpWTeSwarJt7Vc/0/*)";
2608
        let change_descriptor = "tr([73c5da0a/86'/0'/0']tprv8fMn4hSKPRC1oaCPqxDb1JWtgkpeiQvZhsr8W2xuy3GEMkzoArcAWTfJxYb6Wj8XNNDWEjfYKK4wGQXh3ZUXhDF2NcnsALpWTeSwarJt7Vc/1/*)";
2609

2610
        let mut wallet = Wallet::create(descriptor, change_descriptor)
2611
            .network(Network::Regtest)
2612
            .create_wallet_no_persist()
2613
            .unwrap();
2614
        let address = wallet.peek_address(KeychainKind::External, 0).address;
2615
        let tx = Transaction {
2616
            version: transaction::Version::ONE,
2617
            lock_time: absolute::LockTime::ZERO,
2618
            input: vec![],
2619
            output: vec![TxOut {
2620
                value: Amount::from_sat(500_000),
2621
                script_pubkey: address.script_pubkey(),
2622
            }],
2623
        };
2624
        let txid = tx.compute_txid();
2625
        let block_id = BlockId { height: 500, hash: BlockHash::all_zeros() };
2626
        let _ = wallet.insert_checkpoint(block_id);
2627
        let _ = wallet.insert_checkpoint(BlockId { height: 1_000, hash: BlockHash::all_zeros() });
2628
        let _ = wallet.insert_tx(tx);
2629
        let anchor = ConfirmationBlockTime {
2630
            confirmation_time: 50_000,
2631
            block_id,
2632
        };
2633
        let update = Update {
2634
            tx_update: tx_graph::TxUpdate {
2635
                anchors: [(anchor, txid)].into_iter().collect(),
2636
                ..Default::default()
2637
            },
2638
            ..Default::default()
2639
        };
2640
        wallet.apply_update(update).unwrap();
2641
        wallet
2642
    }}
2643
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc