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

bitcoindevkit / bdk / 9984976482

18 Jul 2024 03:21AM UTC coverage: 81.557% (-1.9%) from 83.434%
9984976482

Pull #1514

github

web-flow
Merge 1d7ddfe8d into d99b3ef4b
Pull Request #1514: Flexible sqlite, rework persistence, refactor changeset, refactor wallet construction

801 of 1118 new or added lines in 12 files covered. (71.65%)

35 existing lines in 8 files now uncovered.

10927 of 13398 relevant lines covered (81.56%)

16606.33 hits per line

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

82.85
/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::{FullScanRequest, FullScanResult, SyncRequest, SyncResult},
33
    tx_graph::{CanonicalTx, TxGraph, TxNode},
34
    BlockId, ChainPosition, ConfirmationBlockTime, ConfirmationTime, DescriptorExt, FullTxOut,
35
    Indexed, IndexedTxGraph, Merge,
36
};
37
use bitcoin::sighash::{EcdsaSighashType, TapSighashType};
38
use bitcoin::{
39
    absolute, psbt, Address, Block, FeeRate, Network, OutPoint, Script, ScriptBuf, Sequence,
40
    Transaction, TxOut, Txid, Witness,
41
};
42
use bitcoin::{consensus::encode::serialize, transaction, BlockHash, Psbt};
43
use bitcoin::{constants::genesis_block, Amount};
44
use bitcoin::{secp256k1::Secp256k1, Weight};
45
use core::fmt;
46
use core::mem;
47
use core::ops::Deref;
48
use rand_core::RngCore;
49

50
use descriptor::error::Error as DescriptorError;
51
use miniscript::{
52
    descriptor::KeyMap,
53
    psbt::{PsbtExt, PsbtInputExt, PsbtInputSatisfier},
54
};
55

56
use bdk_chain::tx_graph::CalculateFeeError;
57

58
mod changeset;
59
pub mod coin_selection;
60
pub mod export;
61
mod params;
62
pub mod signer;
63
pub mod tx_builder;
64
pub use changeset::*;
65
pub use params::*;
66
mod persisted;
67
pub use persisted::*;
68
pub(crate) mod utils;
69

70
pub mod error;
71

72
pub use utils::IsDust;
73

74
use coin_selection::DefaultCoinSelectionAlgorithm;
75
use signer::{SignOptions, SignerOrdering, SignersContainer, TransactionSigner};
76
use tx_builder::{FeePolicy, TxBuilder, TxParams};
77
use utils::{check_nsequence_rbf, After, Older, SecpCtx};
78

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

90
use self::coin_selection::Error;
91

92
const COINBASE_MATURITY: u32 = 100;
93

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

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

131
    /// Update for the wallet's internal [`TxGraph`].
132
    pub graph: TxGraph<ConfirmationBlockTime>,
133

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

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

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

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

172
impl Deref for AddressInfo {
173
    type Target = Address;
174

175
    fn deref(&self) -> &Self::Target {
808✔
176
        &self.address
808✔
177
    }
808✔
178
}
179

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

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

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

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

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

246
/// An error that may occur when applying a block to [`Wallet`].
247
#[derive(Debug)]
248
pub enum ApplyBlockError {
249
    /// Occurs when the update chain cannot connect with original chain.
250
    CannotConnect(CannotConnectError),
251
    /// Occurs when the `connected_to` hash does not match the hash derived from `block`.
252
    UnexpectedConnectedToHash {
253
        /// Block hash of `connected_to`.
254
        connected_to_hash: BlockHash,
255
        /// Expected block hash of `connected_to`, as derived from `block`.
256
        expected_hash: BlockHash,
257
    },
258
}
259

260
impl fmt::Display for ApplyBlockError {
261
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
×
262
        match self {
×
263
            ApplyBlockError::CannotConnect(err) => err.fmt(f),
×
264
            ApplyBlockError::UnexpectedConnectedToHash {
265
                expected_hash: block_hash,
×
266
                connected_to_hash: checkpoint_hash,
×
267
            } => write!(
×
268
                f,
×
269
                "`connected_to` hash {} differs from the expected hash {} (which is derived from `block`)",
×
270
                checkpoint_hash, block_hash
×
271
            ),
×
272
        }
273
    }
×
274
}
275

276
#[cfg(feature = "std")]
277
impl std::error::Error for ApplyBlockError {}
278

279
impl Wallet {
280
    /// Build a new [`Wallet`].
281
    ///
282
    /// If you have previously created a wallet, use [`load`](Self::load) instead.
283
    ///
284
    /// # Synopsis
285
    ///
286
    /// ```rust
287
    /// # use bdk_wallet::Wallet;
288
    /// # use bitcoin::Network;
289
    /// # fn main() -> anyhow::Result<()> {
290
    /// # const EXTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
291
    /// # const INTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
292
    /// // Create a non-persisted wallet.
293
    /// let wallet = Wallet::create(EXTERNAL_DESC, INTERNAL_DESC)
294
    ///     .network(Network::Testnet)
295
    ///     .create_wallet_no_persist()?;
296
    ///
297
    /// // Create a wallet that is persisted to SQLite database.
298
    /// # let temp_dir = tempfile::tempdir().expect("must create tempdir");
299
    /// # let file_path = temp_dir.path().join("store.db");
300
    /// use bdk_wallet::rusqlite::Connection;
301
    /// let mut conn = Connection::open(file_path)?;
302
    /// let wallet = Wallet::create(EXTERNAL_DESC, INTERNAL_DESC)
303
    ///     .network(Network::Testnet)
304
    ///     .create_wallet(&mut conn)?;
305
    /// # Ok(())
306
    /// # }
307
    /// ```
308
    pub fn create<D>(descriptor: D, change_descriptor: D) -> CreateParams
152✔
309
    where
152✔
310
        D: IntoWalletDescriptor + Clone + 'static,
152✔
311
    {
152✔
312
        CreateParams::new(descriptor, change_descriptor)
152✔
313
    }
152✔
314

315
    /// Create a new [`Wallet`] with given `params`.
316
    ///
317
    /// Refer to [`Wallet::create`] for more.
318
    pub fn create_with_params(params: CreateParams) -> Result<Self, DescriptorError> {
1,374✔
319
        let secp = SecpCtx::new();
1,374✔
320
        let network = params.network;
1,374✔
321
        let genesis_hash = params
1,374✔
322
            .genesis_hash
1,374✔
323
            .unwrap_or(genesis_block(network).block_hash());
1,374✔
324
        let (chain, chain_changeset) = LocalChain::from_genesis_hash(genesis_hash);
1,374✔
325

326
        let (descriptor, mut descriptor_keymap) = (params.descriptor)(&secp, network)?;
1,374✔
327
        descriptor_keymap.extend(params.descriptor_keymap);
1,374✔
328

329
        let (change_descriptor, mut change_descriptor_keymap) =
1,374✔
330
            (params.change_descriptor)(&secp, network)?;
1,374✔
331
        change_descriptor_keymap.extend(params.change_descriptor_keymap);
1,374✔
332

1,374✔
333
        let signers = Arc::new(SignersContainer::build(
1,374✔
334
            descriptor_keymap,
1,374✔
335
            &descriptor,
1,374✔
336
            &secp,
1,374✔
337
        ));
1,374✔
338
        let change_signers = Arc::new(SignersContainer::build(
1,374✔
339
            change_descriptor_keymap,
1,374✔
340
            &change_descriptor,
1,374✔
341
            &secp,
1,374✔
342
        ));
1,374✔
343
        let index = create_indexer(descriptor, change_descriptor, params.lookahead)?;
1,374✔
344

345
        let descriptor = index.get_descriptor(&KeychainKind::External).cloned();
1,350✔
346
        let change_descriptor = index.get_descriptor(&KeychainKind::Internal).cloned();
1,350✔
347
        let indexed_graph = IndexedTxGraph::new(index);
1,350✔
348
        let indexed_graph_changeset = indexed_graph.initial_changeset();
1,350✔
349

1,350✔
350
        let stage = ChangeSet {
1,350✔
351
            descriptor,
1,350✔
352
            change_descriptor,
1,350✔
353
            local_chain: chain_changeset,
1,350✔
354
            tx_graph: indexed_graph_changeset.tx_graph,
1,350✔
355
            indexer: indexed_graph_changeset.indexer,
1,350✔
356
            network: Some(network),
1,350✔
357
        };
1,350✔
358

1,350✔
359
        Ok(Wallet {
1,350✔
360
            signers,
1,350✔
361
            change_signers,
1,350✔
362
            network,
1,350✔
363
            chain,
1,350✔
364
            indexed_graph,
1,350✔
365
            stage,
1,350✔
366
            secp,
1,350✔
367
        })
1,350✔
368
    }
1,366✔
369

370
    /// Build [`Wallet`] by loading from persistence or [`ChangeSet`].
371
    ///
372
    /// Note that the descriptor secret keys are not persisted to the db. You can either add
373
    /// signers after-the-fact with [`Wallet::add_signer`] or [`Wallet::set_keymap`]. Or you can
374
    /// add keys when building the wallet using [`LoadParams::keymap`] and/or
375
    /// [`LoadParams::descriptors`].
376
    ///
377
    /// # Synopsis
378
    ///
379
    /// ```rust,no_run
380
    /// # use bdk_wallet::{Wallet, ChangeSet, KeychainKind};
381
    /// # use bitcoin::{BlockHash, Network, hashes::Hash};
382
    /// # fn main() -> anyhow::Result<()> {
383
    /// # const EXTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
384
    /// # const INTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
385
    /// # let changeset = ChangeSet::default();
386
    /// // Load a wallet from changeset (no persistence).
387
    /// let wallet = Wallet::load()
388
    ///     .load_wallet_no_persist(changeset)?
389
    ///     .expect("must have data to load wallet");
390
    ///
391
    /// // Load a wallet that is persisted to SQLite database.
392
    /// # let temp_dir = tempfile::tempdir().expect("must create tempdir");
393
    /// # let file_path = temp_dir.path().join("store.db");
394
    /// # let external_keymap = Default::default();
395
    /// # let internal_keymap = Default::default();
396
    /// # let genesis_hash = BlockHash::all_zeros();
397
    /// let mut conn = bdk_wallet::rusqlite::Connection::open(file_path)?;
398
    /// let mut wallet = Wallet::load()
399
    ///     // check loaded descriptors matches these values and extract private keys
400
    ///     .descriptors(EXTERNAL_DESC, INTERNAL_DESC)
401
    ///     // you can also manually add private keys
402
    ///     .keymap(KeychainKind::External, external_keymap)
403
    ///     .keymap(KeychainKind::Internal, internal_keymap)
404
    ///     // ensure loaded wallet's genesis hash matches this value
405
    ///     .genesis_hash(genesis_hash)
406
    ///     // set a lookahead for our indexer
407
    ///     .lookahead(101)
408
    ///     .load_wallet(&mut conn)?
409
    ///     .expect("must have data to load wallet");
410
    /// # Ok(())
411
    /// # }
412
    /// ```
413
    pub fn load() -> LoadParams {
16✔
414
        LoadParams::new()
16✔
415
    }
16✔
416

417
    /// Load [`Wallet`] from the given previously persisted [`ChangeSet`] and `params`.
418
    ///
419
    /// Refer to [`Wallet::load`] for more.
420
    pub fn load_with_params(
16✔
421
        changeset: ChangeSet,
16✔
422
        params: LoadParams,
16✔
423
    ) -> Result<Option<Self>, LoadError> {
16✔
424
        if changeset.is_empty() {
16✔
NEW
425
            return Ok(None);
×
426
        }
16✔
427
        let secp = Secp256k1::new();
16✔
428
        let network = changeset.network.ok_or(LoadError::MissingNetwork)?;
16✔
429
        let chain = LocalChain::from_changeset(changeset.local_chain)
16✔
430
            .map_err(|_| LoadError::MissingGenesis)?;
16✔
431

432
        let mut descriptor_keymap = params.descriptor_keymap;
16✔
433
        let descriptor = changeset
16✔
434
            .descriptor
16✔
435
            .ok_or(LoadError::MissingDescriptor(KeychainKind::External))?;
16✔
436
        check_wallet_descriptor(&descriptor).map_err(LoadError::Descriptor)?;
16✔
437

438
        let mut change_descriptor_keymap = params.change_descriptor_keymap;
16✔
439
        let change_descriptor = changeset
16✔
440
            .change_descriptor
16✔
441
            .ok_or(LoadError::MissingDescriptor(KeychainKind::Internal))?;
16✔
442
        check_wallet_descriptor(&change_descriptor).map_err(LoadError::Descriptor)?;
16✔
443

444
        // checks
445
        if let Some(exp_network) = params.check_network {
16✔
446
            if network != exp_network {
16✔
NEW
447
                return Err(LoadError::Mismatch(LoadMismatch::Network {
×
NEW
448
                    loaded: network,
×
NEW
449
                    expected: exp_network,
×
NEW
450
                }));
×
451
            }
16✔
NEW
452
        }
×
453
        if let Some(exp_genesis_hash) = params.check_genesis_hash {
16✔
NEW
454
            if chain.genesis_hash() != exp_genesis_hash {
×
NEW
455
                return Err(LoadError::Mismatch(LoadMismatch::Genesis {
×
NEW
456
                    loaded: chain.genesis_hash(),
×
NEW
457
                    expected: exp_genesis_hash,
×
NEW
458
                }));
×
NEW
459
            }
×
460
        }
16✔
461
        if let Some(exp_descriptor) = params.check_descriptor {
16✔
462
            let (exp_descriptor, keymap) =
16✔
463
                (exp_descriptor)(&secp, network).map_err(LoadError::Descriptor)?;
16✔
464
            descriptor_keymap.extend(keymap);
16✔
465

16✔
466
            if descriptor.descriptor_id() != exp_descriptor.descriptor_id() {
16✔
NEW
467
                return Err(LoadError::Mismatch(LoadMismatch::Descriptor {
×
NEW
468
                    keychain: KeychainKind::External,
×
NEW
469
                    loaded: descriptor,
×
NEW
470
                    expected: exp_descriptor,
×
NEW
471
                }));
×
472
            }
16✔
NEW
473
        }
×
474
        if let Some(exp_change_descriptor) = params.check_change_descriptor {
16✔
475
            let (exp_change_descriptor, keymap) =
16✔
476
                (exp_change_descriptor)(&secp, network).map_err(LoadError::Descriptor)?;
16✔
477
            change_descriptor_keymap.extend(keymap);
16✔
478

16✔
479
            if change_descriptor.descriptor_id() != exp_change_descriptor.descriptor_id() {
16✔
NEW
480
                return Err(LoadError::Mismatch(LoadMismatch::Descriptor {
×
NEW
481
                    keychain: KeychainKind::External,
×
NEW
482
                    loaded: change_descriptor,
×
NEW
483
                    expected: exp_change_descriptor,
×
NEW
484
                }));
×
485
            }
16✔
NEW
486
        }
×
487

488
        let signers = Arc::new(SignersContainer::build(
16✔
489
            descriptor_keymap,
16✔
490
            &descriptor,
16✔
491
            &secp,
16✔
492
        ));
16✔
493
        let change_signers = Arc::new(SignersContainer::build(
16✔
494
            change_descriptor_keymap,
16✔
495
            &change_descriptor,
16✔
496
            &secp,
16✔
497
        ));
16✔
498
        let index = create_indexer(descriptor, change_descriptor, params.lookahead)
16✔
499
            .map_err(LoadError::Descriptor)?;
16✔
500

501
        let mut indexed_graph = IndexedTxGraph::new(index);
16✔
502
        indexed_graph.apply_changeset(changeset.indexer.into());
16✔
503
        indexed_graph.apply_changeset(changeset.tx_graph.into());
16✔
504

16✔
505
        let stage = ChangeSet::default();
16✔
506

16✔
507
        Ok(Some(Wallet {
16✔
508
            signers,
16✔
509
            change_signers,
16✔
510
            chain,
16✔
511
            indexed_graph,
16✔
512
            stage,
16✔
513
            network,
16✔
514
            secp,
16✔
515
        }))
16✔
516
    }
16✔
517

518
    /// Get the Bitcoin network the wallet is using.
519
    pub fn network(&self) -> Network {
32✔
520
        self.network
32✔
521
    }
32✔
522

523
    /// Iterator over all keychains in this wallet
524
    pub fn keychains(&self) -> impl Iterator<Item = (&KeychainKind, &ExtendedDescriptor)> {
32✔
525
        self.indexed_graph.index.keychains()
32✔
526
    }
32✔
527

528
    /// Peek an address of the given `keychain` at `index` without revealing it.
529
    ///
530
    /// For non-wildcard descriptors this returns the same address at every provided index.
531
    ///
532
    /// # Panics
533
    ///
534
    /// This panics when the caller requests for an address of derivation index greater than the
535
    /// [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) max index.
536
    pub fn peek_address(&self, keychain: KeychainKind, mut index: u32) -> AddressInfo {
1,248✔
537
        let mut spk_iter = self
1,248✔
538
            .indexed_graph
1,248✔
539
            .index
1,248✔
540
            .unbounded_spk_iter(&keychain)
1,248✔
541
            .expect("keychain must exist");
1,248✔
542
        if !spk_iter.descriptor().has_wildcard() {
1,248✔
543
            index = 0;
952✔
544
        }
952✔
545
        let (index, spk) = spk_iter
1,248✔
546
            .nth(index as usize)
1,248✔
547
            .expect("derivation index is out of bounds");
1,248✔
548

1,248✔
549
        AddressInfo {
1,248✔
550
            index,
1,248✔
551
            address: Address::from_script(&spk, self.network).expect("must have address form"),
1,248✔
552
            keychain,
1,248✔
553
        }
1,248✔
554
    }
1,248✔
555

556
    /// Attempt to reveal the next address of the given `keychain`.
557
    ///
558
    /// This will increment the keychain's derivation index. If the keychain's descriptor doesn't
559
    /// contain a wildcard or every address is already revealed up to the maximum derivation
560
    /// index defined in [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki),
561
    /// then the last revealed address will be returned.
562
    ///
563
    /// **WARNING**: To avoid address reuse you must persist the changes resulting from one or more
564
    /// calls to this method before closing the wallet. For example:
565
    ///
566
    /// ```rust,no_run
567
    /// # use bdk_wallet::{LoadParams, ChangeSet, KeychainKind};
568
    /// use bdk_chain::sqlite::Connection;
569
    /// let mut conn = Connection::open_in_memory().expect("must open connection");
570
    /// let mut wallet = LoadParams::new()
571
    ///     .load_wallet(&mut conn)
572
    ///     .expect("database is okay")
573
    ///     .expect("database has data");
574
    /// let next_address = wallet.reveal_next_address(KeychainKind::External);
575
    /// wallet.persist(&mut conn).expect("write is okay");
576
    ///
577
    /// // Now it's safe to show the user their next address!
578
    /// println!("Next address: {}", next_address.address);
579
    /// # Ok::<(), anyhow::Error>(())
580
    /// ```
581
    pub fn reveal_next_address(&mut self, keychain: KeychainKind) -> AddressInfo {
120✔
582
        let index = &mut self.indexed_graph.index;
120✔
583
        let stage = &mut self.stage;
120✔
584

120✔
585
        let ((index, spk), index_changeset) = index
120✔
586
            .reveal_next_spk(&keychain)
120✔
587
            .expect("keychain must exist");
120✔
588

120✔
589
        stage.merge(index_changeset.into());
120✔
590

120✔
591
        AddressInfo {
120✔
592
            index,
120✔
593
            address: Address::from_script(spk.as_script(), self.network)
120✔
594
                .expect("must have address form"),
120✔
595
            keychain,
120✔
596
        }
120✔
597
    }
120✔
598

599
    /// Reveal addresses up to and including the target `index` and return an iterator
600
    /// of newly revealed addresses.
601
    ///
602
    /// If the target `index` is unreachable, we make a best effort to reveal up to the last
603
    /// possible index. If all addresses up to the given `index` are already revealed, then
604
    /// no new addresses are returned.
605
    ///
606
    /// **WARNING**: To avoid address reuse you must persist the changes resulting from one or more
607
    /// calls to this method before closing the wallet. See [`Wallet::reveal_next_address`].
608
    pub fn reveal_addresses_to(
16✔
609
        &mut self,
16✔
610
        keychain: KeychainKind,
16✔
611
        index: u32,
16✔
612
    ) -> impl Iterator<Item = AddressInfo> + '_ {
16✔
613
        let (spks, index_changeset) = self
16✔
614
            .indexed_graph
16✔
615
            .index
16✔
616
            .reveal_to_target(&keychain, index)
16✔
617
            .expect("keychain must exist");
16✔
618

16✔
619
        self.stage.merge(index_changeset.into());
16✔
620

16✔
621
        spks.into_iter().map(move |(index, spk)| AddressInfo {
24✔
622
            index,
10✔
623
            address: Address::from_script(&spk, self.network).expect("must have address form"),
10✔
624
            keychain,
10✔
625
        })
24✔
626
    }
16✔
627

628
    /// Get the next unused address for the given `keychain`, i.e. the address with the lowest
629
    /// derivation index that hasn't been used.
630
    ///
631
    /// This will attempt to derive and reveal a new address if no newly revealed addresses
632
    /// are available. See also [`reveal_next_address`](Self::reveal_next_address).
633
    ///
634
    /// **WARNING**: To avoid address reuse you must persist the changes resulting from one or more
635
    /// calls to this method before closing the wallet. See [`Wallet::reveal_next_address`].
636
    pub fn next_unused_address(&mut self, keychain: KeychainKind) -> AddressInfo {
888✔
637
        let index = &mut self.indexed_graph.index;
888✔
638

888✔
639
        let ((index, spk), index_changeset) = index
888✔
640
            .next_unused_spk(&keychain)
888✔
641
            .expect("keychain must exist");
888✔
642

888✔
643
        self.stage
888✔
644
            .merge(indexed_tx_graph::ChangeSet::from(index_changeset).into());
888✔
645

888✔
646
        AddressInfo {
888✔
647
            index,
888✔
648
            address: Address::from_script(spk.as_script(), self.network)
888✔
649
                .expect("must have address form"),
888✔
650
            keychain,
888✔
651
        }
888✔
652
    }
888✔
653

654
    /// Marks an address used of the given `keychain` at `index`.
655
    ///
656
    /// Returns whether the given index was present and then removed from the unused set.
657
    pub fn mark_used(&mut self, keychain: KeychainKind, index: u32) -> bool {
8✔
658
        self.indexed_graph.index.mark_used(keychain, index)
8✔
659
    }
8✔
660

661
    /// Undoes the effect of [`mark_used`] and returns whether the `index` was inserted
662
    /// back into the unused set.
663
    ///
664
    /// Since this is only a superficial marker, it will have no effect if the address at the given
665
    /// `index` was actually used, i.e. the wallet has previously indexed a tx output for the
666
    /// derived spk.
667
    ///
668
    /// [`mark_used`]: Self::mark_used
669
    pub fn unmark_used(&mut self, keychain: KeychainKind, index: u32) -> bool {
16✔
670
        self.indexed_graph.index.unmark_used(keychain, index)
16✔
671
    }
16✔
672

673
    /// List addresses that are revealed but unused.
674
    ///
675
    /// Note if the returned iterator is empty you can reveal more addresses
676
    /// by using [`reveal_next_address`](Self::reveal_next_address) or
677
    /// [`reveal_addresses_to`](Self::reveal_addresses_to).
678
    pub fn list_unused_addresses(
24✔
679
        &self,
24✔
680
        keychain: KeychainKind,
24✔
681
    ) -> impl DoubleEndedIterator<Item = AddressInfo> + '_ {
24✔
682
        self.indexed_graph
24✔
683
            .index
24✔
684
            .unused_keychain_spks(&keychain)
24✔
685
            .map(move |(index, spk)| AddressInfo {
32✔
686
                index,
11✔
687
                address: Address::from_script(spk, self.network).expect("must have address form"),
11✔
688
                keychain,
11✔
689
            })
32✔
690
    }
24✔
691

692
    /// Return whether or not a `script` is part of this wallet (either internal or external)
693
    pub fn is_mine(&self, script: &Script) -> bool {
1,792✔
694
        self.indexed_graph.index.index_of_spk(script).is_some()
1,792✔
695
    }
1,792✔
696

697
    /// Finds how the wallet derived the script pubkey `spk`.
698
    ///
699
    /// Will only return `Some(_)` if the wallet has given out the spk.
700
    pub fn derivation_of_spk(&self, spk: &Script) -> Option<(KeychainKind, u32)> {
72✔
701
        self.indexed_graph.index.index_of_spk(spk).cloned()
72✔
702
    }
72✔
703

704
    /// Return the list of unspent outputs of this wallet
705
    pub fn list_unspent(&self) -> impl Iterator<Item = LocalOutput> + '_ {
1,248✔
706
        self.indexed_graph
1,248✔
707
            .graph()
1,248✔
708
            .filter_chain_unspents(
1,248✔
709
                &self.chain,
1,248✔
710
                self.chain.tip().block_id(),
1,248✔
711
                self.indexed_graph.index.outpoints().iter().cloned(),
1,248✔
712
            )
1,248✔
713
            .map(|((k, i), full_txo)| new_local_utxo(k, i, full_txo))
1,352✔
714
    }
1,248✔
715

716
    /// List all relevant outputs (includes both spent and unspent, confirmed and unconfirmed).
717
    ///
718
    /// To list only unspent outputs (UTXOs), use [`Wallet::list_unspent`] instead.
719
    pub fn list_output(&self) -> impl Iterator<Item = LocalOutput> + '_ {
8✔
720
        self.indexed_graph
8✔
721
            .graph()
8✔
722
            .filter_chain_txouts(
8✔
723
                &self.chain,
8✔
724
                self.chain.tip().block_id(),
8✔
725
                self.indexed_graph.index.outpoints().iter().cloned(),
8✔
726
            )
8✔
727
            .map(|((k, i), full_txo)| new_local_utxo(k, i, full_txo))
9✔
728
    }
8✔
729

730
    /// Get all the checkpoints the wallet is currently storing indexed by height.
731
    pub fn checkpoints(&self) -> CheckPointIter {
×
732
        self.chain.iter_checkpoints()
×
733
    }
×
734

735
    /// Returns the latest checkpoint.
736
    pub fn latest_checkpoint(&self) -> CheckPoint {
72✔
737
        self.chain.tip()
72✔
738
    }
72✔
739

740
    /// Get unbounded script pubkey iterators for both `Internal` and `External` keychains.
741
    ///
742
    /// This is intended to be used when doing a full scan of your addresses (e.g. after restoring
743
    /// from seed words). You pass the `BTreeMap` of iterators to a blockchain data source (e.g.
744
    /// electrum server) which will go through each address until it reaches a *stop gap*.
745
    ///
746
    /// Note carefully that iterators go over **all** script pubkeys on the keychains (not what
747
    /// script pubkeys the wallet is storing internally).
748
    pub fn all_unbounded_spk_iters(
×
749
        &self,
×
750
    ) -> BTreeMap<KeychainKind, impl Iterator<Item = Indexed<ScriptBuf>> + Clone> {
×
751
        self.indexed_graph.index.all_unbounded_spk_iters()
×
752
    }
×
753

754
    /// Get an unbounded script pubkey iterator for the given `keychain`.
755
    ///
756
    /// See [`all_unbounded_spk_iters`] for more documentation
757
    ///
758
    /// [`all_unbounded_spk_iters`]: Self::all_unbounded_spk_iters
759
    pub fn unbounded_spk_iter(
×
760
        &self,
×
761
        keychain: KeychainKind,
×
762
    ) -> impl Iterator<Item = Indexed<ScriptBuf>> + Clone {
×
763
        self.indexed_graph
×
764
            .index
×
765
            .unbounded_spk_iter(&keychain)
×
766
            .expect("keychain must exist")
×
767
    }
×
768

769
    /// Returns the utxo owned by this wallet corresponding to `outpoint` if it exists in the
770
    /// wallet's database.
771
    pub fn get_utxo(&self, op: OutPoint) -> Option<LocalOutput> {
72✔
772
        let ((keychain, index), _) = self.indexed_graph.index.txout(op)?;
72✔
773
        self.indexed_graph
72✔
774
            .graph()
72✔
775
            .filter_chain_unspents(
72✔
776
                &self.chain,
72✔
777
                self.chain.tip().block_id(),
72✔
778
                core::iter::once(((), op)),
72✔
779
            )
72✔
780
            .map(|(_, full_txo)| new_local_utxo(keychain, index, full_txo))
72✔
781
            .next()
72✔
782
    }
72✔
783

784
    /// Inserts a [`TxOut`] at [`OutPoint`] into the wallet's transaction graph.
785
    ///
786
    /// This is used for providing a previous output's value so that we can use [`calculate_fee`]
787
    /// or [`calculate_fee_rate`] on a given transaction. Outputs inserted with this method will
788
    /// not be returned in [`list_unspent`] or [`list_output`].
789
    ///
790
    /// **WARNINGS:** This should only be used to add `TxOut`s that the wallet does not own. Only
791
    /// insert `TxOut`s that you trust the values for!
792
    ///
793
    /// You must persist the changes resulting from one or more calls to this method if you need
794
    /// the inserted `TxOut` data to be reloaded after closing the wallet.
795
    /// See [`Wallet::reveal_next_address`].
796
    ///
797
    /// [`calculate_fee`]: Self::calculate_fee
798
    /// [`calculate_fee_rate`]: Self::calculate_fee_rate
799
    /// [`list_unspent`]: Self::list_unspent
800
    /// [`list_output`]: Self::list_output
801
    pub fn insert_txout(&mut self, outpoint: OutPoint, txout: TxOut) {
16✔
802
        let additions = self.indexed_graph.insert_txout(outpoint, txout);
16✔
803
        self.stage.merge(additions.into());
16✔
804
    }
16✔
805

806
    /// Calculates the fee of a given transaction. Returns [`Amount::ZERO`] if `tx` is a coinbase transaction.
807
    ///
808
    /// To calculate the fee for a [`Transaction`] with inputs not owned by this wallet you must
809
    /// manually insert the TxOut(s) into the tx graph using the [`insert_txout`] function.
810
    ///
811
    /// Note `tx` does not have to be in the graph for this to work.
812
    ///
813
    /// # Examples
814
    ///
815
    /// ```rust, no_run
816
    /// # use bitcoin::Txid;
817
    /// # use bdk_wallet::Wallet;
818
    /// # let mut wallet: Wallet = todo!();
819
    /// # let txid:Txid = todo!();
820
    /// let tx = wallet.get_tx(txid).expect("transaction").tx_node.tx;
821
    /// let fee = wallet.calculate_fee(&tx).expect("fee");
822
    /// ```
823
    ///
824
    /// ```rust, no_run
825
    /// # use bitcoin::Psbt;
826
    /// # use bdk_wallet::Wallet;
827
    /// # let mut wallet: Wallet = todo!();
828
    /// # let mut psbt: Psbt = todo!();
829
    /// let tx = &psbt.clone().extract_tx().expect("tx");
830
    /// let fee = wallet.calculate_fee(tx).expect("fee");
831
    /// ```
832
    /// [`insert_txout`]: Self::insert_txout
833
    pub fn calculate_fee(&self, tx: &Transaction) -> Result<Amount, CalculateFeeError> {
536✔
834
        self.indexed_graph.graph().calculate_fee(tx)
536✔
835
    }
536✔
836

837
    /// Calculate the [`FeeRate`] for a given transaction.
838
    ///
839
    /// To calculate the fee rate for a [`Transaction`] with inputs not owned by this wallet you must
840
    /// manually insert the TxOut(s) into the tx graph using the [`insert_txout`] function.
841
    ///
842
    /// Note `tx` does not have to be in the graph for this to work.
843
    ///
844
    /// # Examples
845
    ///
846
    /// ```rust, no_run
847
    /// # use bitcoin::Txid;
848
    /// # use bdk_wallet::Wallet;
849
    /// # let mut wallet: Wallet = todo!();
850
    /// # let txid:Txid = todo!();
851
    /// let tx = wallet.get_tx(txid).expect("transaction").tx_node.tx;
852
    /// let fee_rate = wallet.calculate_fee_rate(&tx).expect("fee rate");
853
    /// ```
854
    ///
855
    /// ```rust, no_run
856
    /// # use bitcoin::Psbt;
857
    /// # use bdk_wallet::Wallet;
858
    /// # let mut wallet: Wallet = todo!();
859
    /// # let mut psbt: Psbt = todo!();
860
    /// let tx = &psbt.clone().extract_tx().expect("tx");
861
    /// let fee_rate = wallet.calculate_fee_rate(tx).expect("fee rate");
862
    /// ```
863
    /// [`insert_txout`]: Self::insert_txout
864
    pub fn calculate_fee_rate(&self, tx: &Transaction) -> Result<FeeRate, CalculateFeeError> {
144✔
865
        self.calculate_fee(tx).map(|fee| fee / tx.weight())
144✔
866
    }
144✔
867

868
    /// Compute the `tx`'s sent and received [`Amount`]s.
869
    ///
870
    /// This method returns a tuple `(sent, received)`. Sent is the sum of the txin amounts
871
    /// that spend from previous txouts tracked by this wallet. Received is the summation
872
    /// of this tx's outputs that send to script pubkeys tracked by this wallet.
873
    ///
874
    /// # Examples
875
    ///
876
    /// ```rust, no_run
877
    /// # use bitcoin::Txid;
878
    /// # use bdk_wallet::Wallet;
879
    /// # let mut wallet: Wallet = todo!();
880
    /// # let txid:Txid = todo!();
881
    /// let tx = wallet.get_tx(txid).expect("tx exists").tx_node.tx;
882
    /// let (sent, received) = wallet.sent_and_received(&tx);
883
    /// ```
884
    ///
885
    /// ```rust, no_run
886
    /// # use bitcoin::Psbt;
887
    /// # use bdk_wallet::Wallet;
888
    /// # let mut wallet: Wallet = todo!();
889
    /// # let mut psbt: Psbt = todo!();
890
    /// let tx = &psbt.clone().extract_tx().expect("tx");
891
    /// let (sent, received) = wallet.sent_and_received(tx);
892
    /// ```
893
    pub fn sent_and_received(&self, tx: &Transaction) -> (Amount, Amount) {
224✔
894
        self.indexed_graph.index.sent_and_received(tx, ..)
224✔
895
    }
224✔
896

897
    /// Get a single transaction from the wallet as a [`CanonicalTx`] (if the transaction exists).
898
    ///
899
    /// `CanonicalTx` contains the full transaction alongside meta-data such as:
900
    /// * Blocks that the transaction is [`Anchor`]ed in. These may or may not be blocks that exist
901
    ///   in the best chain.
902
    /// * The [`ChainPosition`] of the transaction in the best chain - whether the transaction is
903
    ///   confirmed or unconfirmed. If the transaction is confirmed, the anchor which proves the
904
    ///   confirmation is provided. If the transaction is unconfirmed, the unix timestamp of when
905
    ///   the transaction was last seen in the mempool is provided.
906
    ///
907
    /// ```rust, no_run
908
    /// use bdk_chain::Anchor;
909
    /// use bdk_wallet::{chain::ChainPosition, Wallet};
910
    /// # let wallet: Wallet = todo!();
911
    /// # let my_txid: bitcoin::Txid = todo!();
912
    ///
913
    /// let canonical_tx = wallet.get_tx(my_txid).expect("panic if tx does not exist");
914
    ///
915
    /// // get reference to full transaction
916
    /// println!("my tx: {:#?}", canonical_tx.tx_node.tx);
917
    ///
918
    /// // list all transaction anchors
919
    /// for anchor in canonical_tx.tx_node.anchors {
920
    ///     println!(
921
    ///         "tx is anchored by block of hash {}",
922
    ///         anchor.anchor_block().hash
923
    ///     );
924
    /// }
925
    ///
926
    /// // get confirmation status of transaction
927
    /// match canonical_tx.chain_position {
928
    ///     ChainPosition::Confirmed(anchor) => println!(
929
    ///         "tx is confirmed at height {}, we know this since {}:{} is in the best chain",
930
    ///         anchor.block_id.height, anchor.block_id.height, anchor.block_id.hash,
931
    ///     ),
932
    ///     ChainPosition::Unconfirmed(last_seen) => println!(
933
    ///         "tx is last seen at {}, it is unconfirmed as it is not anchored in the best chain",
934
    ///         last_seen,
935
    ///     ),
936
    /// }
937
    /// ```
938
    ///
939
    /// [`Anchor`]: bdk_chain::Anchor
940
    pub fn get_tx(
56✔
941
        &self,
56✔
942
        txid: Txid,
56✔
943
    ) -> Option<CanonicalTx<'_, Arc<Transaction>, ConfirmationBlockTime>> {
56✔
944
        let graph = self.indexed_graph.graph();
56✔
945

56✔
946
        Some(CanonicalTx {
56✔
947
            chain_position: graph.get_chain_position(
56✔
948
                &self.chain,
56✔
949
                self.chain.tip().block_id(),
56✔
950
                txid,
56✔
951
            )?,
56✔
952
            tx_node: graph.get_tx_node(txid)?,
56✔
953
        })
954
    }
56✔
955

956
    /// Add a new checkpoint to the wallet's internal view of the chain.
957
    ///
958
    /// Returns whether anything changed with the insertion (e.g. `false` if checkpoint was already
959
    /// there).
960
    ///
961
    /// **WARNING**: You must persist the changes resulting from one or more calls to this method
962
    /// if you need the inserted checkpoint data to be reloaded after closing the wallet.
963
    /// See [`Wallet::reveal_next_address`].
964
    ///
965
    /// [`commit`]: Self::commit
966
    pub fn insert_checkpoint(
3,260✔
967
        &mut self,
3,260✔
968
        block_id: BlockId,
3,260✔
969
    ) -> Result<bool, local_chain::AlterCheckPointError> {
3,260✔
970
        let changeset = self.chain.insert_block(block_id)?;
3,260✔
971
        let changed = !changeset.is_empty();
3,260✔
972
        self.stage.merge(changeset.into());
3,260✔
973
        Ok(changed)
3,260✔
974
    }
3,260✔
975

976
    /// Add a transaction to the wallet's internal view of the chain. This stages the change,
977
    /// you must persist it later.
978
    ///
979
    /// This method inserts the given `tx` and returns whether anything changed after insertion,
980
    /// which will be false if the same transaction already exists in the wallet's transaction
981
    /// graph. Any changes are staged but not committed.
982
    ///
983
    /// # Note
984
    ///
985
    /// By default the inserted `tx` won't be considered "canonical" because it's not known
986
    /// whether the transaction exists in the best chain. To know whether it exists, the tx
987
    /// must be broadcast to the network and the wallet synced via a chain source.
988
    pub fn insert_tx(&mut self, tx: Transaction) -> bool {
2,446✔
989
        let mut changeset = ChangeSet::default();
2,446✔
990
        changeset.merge(self.indexed_graph.insert_tx(tx).into());
2,446✔
991
        let ret = !changeset.is_empty();
2,446✔
992
        self.stage.merge(changeset);
2,446✔
993
        ret
2,446✔
994
    }
2,446✔
995

996
    /// Iterate over the transactions in the wallet.
997
    pub fn transactions(
38✔
998
        &self,
38✔
999
    ) -> impl Iterator<Item = CanonicalTx<'_, Arc<Transaction>, ConfirmationBlockTime>> + '_ {
38✔
1000
        self.indexed_graph
38✔
1001
            .graph()
38✔
1002
            .list_canonical_txs(&self.chain, self.chain.tip().block_id())
38✔
1003
    }
38✔
1004

1005
    /// Return the balance, separated into available, trusted-pending, untrusted-pending and immature
1006
    /// values.
1007
    pub fn balance(&self) -> Balance {
56✔
1008
        self.indexed_graph.graph().balance(
56✔
1009
            &self.chain,
56✔
1010
            self.chain.tip().block_id(),
56✔
1011
            self.indexed_graph.index.outpoints().iter().cloned(),
56✔
1012
            |&(k, _), _| k == KeychainKind::Internal,
56✔
1013
        )
56✔
1014
    }
56✔
1015

1016
    /// Add an external signer
1017
    ///
1018
    /// See [the `signer` module](signer) for an example.
1019
    pub fn add_signer(
16✔
1020
        &mut self,
16✔
1021
        keychain: KeychainKind,
16✔
1022
        ordering: SignerOrdering,
16✔
1023
        signer: Arc<dyn TransactionSigner>,
16✔
1024
    ) {
16✔
1025
        let signers = match keychain {
16✔
1026
            KeychainKind::External => Arc::make_mut(&mut self.signers),
16✔
UNCOV
1027
            KeychainKind::Internal => Arc::make_mut(&mut self.change_signers),
×
1028
        };
1029

1030
        signers.add_external(signer.id(&self.secp), ordering, signer);
16✔
1031
    }
16✔
1032

1033
    /// Set the keymap for a given keychain.
NEW
1034
    pub fn set_keymap(&mut self, keychain: KeychainKind, keymap: KeyMap) {
×
NEW
1035
        let wallet_signers = match keychain {
×
NEW
1036
            KeychainKind::External => Arc::make_mut(&mut self.signers),
×
NEW
1037
            KeychainKind::Internal => Arc::make_mut(&mut self.change_signers),
×
1038
        };
NEW
1039
        let descriptor = self
×
NEW
1040
            .indexed_graph
×
NEW
1041
            .index
×
NEW
1042
            .get_descriptor(&keychain)
×
NEW
1043
            .expect("keychain must exist");
×
NEW
1044
        *wallet_signers = SignersContainer::build(keymap, descriptor, &self.secp);
×
NEW
1045
    }
×
1046

1047
    /// Set the keymap for each keychain.
NEW
1048
    pub fn set_keymaps(&mut self, keymaps: impl IntoIterator<Item = (KeychainKind, KeyMap)>) {
×
NEW
1049
        for (keychain, keymap) in keymaps {
×
NEW
1050
            self.set_keymap(keychain, keymap);
×
NEW
1051
        }
×
NEW
1052
    }
×
1053

1054
    /// Get the signers
1055
    ///
1056
    /// ## Example
1057
    ///
1058
    /// ```
1059
    /// # use bdk_wallet::{Wallet, KeychainKind};
1060
    /// # use bdk_wallet::bitcoin::Network;
1061
    /// let descriptor = "wpkh(tprv8ZgxMBicQKsPe73PBRSmNbTfbcsZnwWhz5eVmhHpi31HW29Z7mc9B4cWGRQzopNUzZUT391DeDJxL2PefNunWyLgqCKRMDkU1s2s8bAfoSk/84'/1'/0'/0/*)";
1062
    /// let change_descriptor = "wpkh(tprv8ZgxMBicQKsPe73PBRSmNbTfbcsZnwWhz5eVmhHpi31HW29Z7mc9B4cWGRQzopNUzZUT391DeDJxL2PefNunWyLgqCKRMDkU1s2s8bAfoSk/84'/1'/0'/1/*)";
1063
    /// let wallet = Wallet::create(descriptor, change_descriptor)
1064
    ///     .network(Network::Testnet)
1065
    ///     .create_wallet_no_persist()?;
1066
    /// for secret_key in wallet.get_signers(KeychainKind::External).signers().iter().filter_map(|s| s.descriptor_secret_key()) {
1067
    ///     // secret_key: tprv8ZgxMBicQKsPe73PBRSmNbTfbcsZnwWhz5eVmhHpi31HW29Z7mc9B4cWGRQzopNUzZUT391DeDJxL2PefNunWyLgqCKRMDkU1s2s8bAfoSk/84'/0'/0'/0/*
1068
    ///     println!("secret_key: {}", secret_key);
1069
    /// }
1070
    ///
1071
    /// Ok::<(), Box<dyn std::error::Error>>(())
1072
    /// ```
1073
    pub fn get_signers(&self, keychain: KeychainKind) -> Arc<SignersContainer> {
36✔
1074
        match keychain {
36✔
1075
            KeychainKind::External => Arc::clone(&self.signers),
22✔
1076
            KeychainKind::Internal => Arc::clone(&self.change_signers),
14✔
1077
        }
1078
    }
36✔
1079

1080
    /// Start building a transaction.
1081
    ///
1082
    /// This returns a blank [`TxBuilder`] from which you can specify the parameters for the transaction.
1083
    ///
1084
    /// ## Example
1085
    ///
1086
    /// ```
1087
    /// # use std::str::FromStr;
1088
    /// # use bitcoin::*;
1089
    /// # use bdk_wallet::*;
1090
    /// # use bdk_wallet::ChangeSet;
1091
    /// # use bdk_wallet::error::CreateTxError;
1092
    /// # use anyhow::Error;
1093
    /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
1094
    /// # let mut wallet = doctest_wallet!();
1095
    /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
1096
    /// let psbt = {
1097
    ///    let mut builder =  wallet.build_tx();
1098
    ///    builder
1099
    ///        .add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000));
1100
    ///    builder.finish()?
1101
    /// };
1102
    ///
1103
    /// // sign and broadcast ...
1104
    /// # Ok::<(), anyhow::Error>(())
1105
    /// ```
1106
    ///
1107
    /// [`TxBuilder`]: crate::TxBuilder
1108
    pub fn build_tx(&mut self) -> TxBuilder<'_, DefaultCoinSelectionAlgorithm> {
1,120✔
1109
        TxBuilder {
1,120✔
1110
            wallet: alloc::rc::Rc::new(core::cell::RefCell::new(self)),
1,120✔
1111
            params: TxParams::default(),
1,120✔
1112
            coin_selection: DefaultCoinSelectionAlgorithm::default(),
1,120✔
1113
        }
1,120✔
1114
    }
1,120✔
1115

1116
    pub(crate) fn create_tx<Cs: coin_selection::CoinSelectionAlgorithm>(
149✔
1117
        &mut self,
149✔
1118
        coin_selection: Cs,
149✔
1119
        params: TxParams,
149✔
1120
        rng: &mut impl RngCore,
149✔
1121
    ) -> Result<Psbt, CreateTxError> {
149✔
1122
        let keychains: BTreeMap<_, _> = self.indexed_graph.index.keychains().collect();
149✔
1123
        let external_descriptor = keychains.get(&KeychainKind::External).expect("must exist");
149✔
1124
        let internal_descriptor = keychains.get(&KeychainKind::Internal).expect("must exist");
149✔
1125

1126
        let external_policy = external_descriptor
149✔
1127
            .extract_policy(&self.signers, BuildSatisfaction::None, &self.secp)?
149✔
1128
            .unwrap();
149✔
1129
        let internal_policy = internal_descriptor
149✔
1130
            .extract_policy(&self.change_signers, BuildSatisfaction::None, &self.secp)?
149✔
1131
            .unwrap();
149✔
1132

149✔
1133
        // The policy allows spending external outputs, but it requires a policy path that hasn't been
149✔
1134
        // provided
149✔
1135
        if params.change_policy != tx_builder::ChangeSpendPolicy::OnlyChange
149✔
1136
            && external_policy.requires_path()
148✔
1137
            && params.external_policy_path.is_none()
4✔
1138
        {
1139
            return Err(CreateTxError::SpendingPolicyRequired(
1✔
1140
                KeychainKind::External,
1✔
1141
            ));
1✔
1142
        };
148✔
1143
        // Same for the internal_policy path
148✔
1144
        if params.change_policy != tx_builder::ChangeSpendPolicy::ChangeForbidden
148✔
1145
            && internal_policy.requires_path()
147✔
1146
            && params.internal_policy_path.is_none()
×
1147
        {
1148
            return Err(CreateTxError::SpendingPolicyRequired(
×
1149
                KeychainKind::Internal,
×
1150
            ));
×
1151
        };
148✔
1152

1153
        let external_requirements = external_policy.get_condition(
148✔
1154
            params
148✔
1155
                .external_policy_path
148✔
1156
                .as_ref()
148✔
1157
                .unwrap_or(&BTreeMap::new()),
148✔
1158
        )?;
148✔
1159
        let internal_requirements = internal_policy.get_condition(
148✔
1160
            params
148✔
1161
                .internal_policy_path
148✔
1162
                .as_ref()
148✔
1163
                .unwrap_or(&BTreeMap::new()),
148✔
1164
        )?;
148✔
1165

1166
        let requirements = external_requirements.merge(&internal_requirements)?;
148✔
1167

1168
        let version = match params.version {
146✔
1169
            Some(tx_builder::Version(0)) => return Err(CreateTxError::Version0),
1✔
1170
            Some(tx_builder::Version(1)) if requirements.csv.is_some() => {
18✔
1171
                return Err(CreateTxError::Version1Csv)
1✔
1172
            }
1173
            Some(tx_builder::Version(x)) => x,
18✔
1174
            None if requirements.csv.is_some() => 2,
128✔
1175
            None => 1,
124✔
1176
        };
1177

1178
        // We use a match here instead of a unwrap_or_else as it's way more readable :)
1179
        let current_height = match params.current_height {
146✔
1180
            // If they didn't tell us the current height, we assume it's the latest sync height.
1181
            None => {
1182
                let tip_height = self.chain.tip().height();
142✔
1183
                absolute::LockTime::from_height(tip_height).expect("invalid height")
142✔
1184
            }
1185
            Some(h) => h,
4✔
1186
        };
1187

1188
        let lock_time = match params.locktime {
145✔
1189
            // When no nLockTime is specified, we try to prevent fee sniping, if possible
1190
            None => {
1191
                // Fee sniping can be partially prevented by setting the timelock
1192
                // to current_height. If we don't know the current_height,
1193
                // we default to 0.
1194
                let fee_sniping_height = current_height;
143✔
1195

1196
                // We choose the biggest between the required nlocktime and the fee sniping
1197
                // height
1198
                match requirements.timelock {
4✔
1199
                    // No requirement, just use the fee_sniping_height
1200
                    None => fee_sniping_height,
139✔
1201
                    // There's a block-based requirement, but the value is lower than the fee_sniping_height
1202
                    Some(value @ absolute::LockTime::Blocks(_)) if value < fee_sniping_height => {
4✔
1203
                        fee_sniping_height
×
1204
                    }
1205
                    // There's a time-based requirement or a block-based requirement greater
1206
                    // than the fee_sniping_height use that value
1207
                    Some(value) => value,
4✔
1208
                }
1209
            }
1210
            // Specific nLockTime required and we have no constraints, so just set to that value
1211
            Some(x) if requirements.timelock.is_none() => x,
3✔
1212
            // Specific nLockTime required and it's compatible with the constraints
1213
            Some(x)
1✔
1214
                if requirements.timelock.unwrap().is_same_unit(x)
2✔
1215
                    && x >= requirements.timelock.unwrap() =>
2✔
1216
            {
1✔
1217
                x
1✔
1218
            }
1219
            // Invalid nLockTime required
1220
            Some(x) => {
1✔
1221
                return Err(CreateTxError::LockTime {
1✔
1222
                    requested: x,
1✔
1223
                    required: requirements.timelock.unwrap(),
1✔
1224
                })
1✔
1225
            }
1226
        };
1227

1228
        // The nSequence to be by default for inputs unless an explicit sequence is specified.
1229
        let n_sequence = match (params.rbf, requirements.csv) {
145✔
1230
            // No RBF or CSV but there's an nLockTime, so the nSequence cannot be final
1231
            (None, None) if lock_time != absolute::LockTime::ZERO => {
120✔
1232
                Sequence::ENABLE_LOCKTIME_NO_RBF
119✔
1233
            }
1234
            // No RBF, CSV or nLockTime, make the transaction final
1235
            (None, None) => Sequence::MAX,
1✔
1236

1237
            // No RBF requested, use the value from CSV. Note that this value is by definition
1238
            // non-final, so even if a timelock is enabled this nSequence is fine, hence why we
1239
            // don't bother checking for it here. The same is true for all the other branches below
1240
            (None, Some(csv)) => csv,
2✔
1241

1242
            // RBF with a specific value but that value is too high
1243
            (Some(tx_builder::RbfValue::Value(rbf)), _) if !rbf.is_rbf() => {
3✔
1244
                return Err(CreateTxError::RbfSequence)
1✔
1245
            }
1246
            // RBF with a specific value requested, but the value is incompatible with CSV
1247
            (Some(tx_builder::RbfValue::Value(rbf)), Some(csv))
1✔
1248
                if !check_nsequence_rbf(rbf, csv) =>
1✔
1249
            {
1✔
1250
                return Err(CreateTxError::RbfSequenceCsv { rbf, csv })
1✔
1251
            }
1252

1253
            // RBF enabled with the default value with CSV also enabled. CSV takes precedence
1254
            (Some(tx_builder::RbfValue::Default), Some(csv)) => csv,
1✔
1255
            // Valid RBF, either default or with a specific value. We ignore the `CSV` value
1256
            // because we've already checked it before
1257
            (Some(rbf), _) => rbf.get_value(),
20✔
1258
        };
1259

1260
        let (fee_rate, mut fee_amount) = match params.fee_policy.unwrap_or_default() {
143✔
1261
            //FIXME: see https://github.com/bitcoindevkit/bdk/issues/256
1262
            FeePolicy::FeeAmount(fee) => {
9✔
1263
                if let Some(previous_fee) = params.bumping_fee {
9✔
1264
                    if fee < previous_fee.absolute {
6✔
1265
                        return Err(CreateTxError::FeeTooLow {
2✔
1266
                            required: Amount::from_sat(previous_fee.absolute),
2✔
1267
                        });
2✔
1268
                    }
4✔
1269
                }
3✔
1270
                (FeeRate::ZERO, fee)
7✔
1271
            }
1272
            FeePolicy::FeeRate(rate) => {
134✔
1273
                if let Some(previous_fee) = params.bumping_fee {
134✔
1274
                    let required_feerate = FeeRate::from_sat_per_kwu(
11✔
1275
                        previous_fee.rate.to_sat_per_kwu()
11✔
1276
                            + FeeRate::BROADCAST_MIN.to_sat_per_kwu(), // +1 sat/vb
11✔
1277
                    );
11✔
1278
                    if rate < required_feerate {
11✔
1279
                        return Err(CreateTxError::FeeRateTooLow {
1✔
1280
                            required: required_feerate,
1✔
1281
                        });
1✔
1282
                    }
10✔
1283
                }
123✔
1284
                (rate, 0)
133✔
1285
            }
1286
        };
1287

1288
        let mut tx = Transaction {
140✔
1289
            version: transaction::Version::non_standard(version),
140✔
1290
            lock_time,
140✔
1291
            input: vec![],
140✔
1292
            output: vec![],
140✔
1293
        };
140✔
1294

140✔
1295
        if params.manually_selected_only && params.utxos.is_empty() {
140✔
1296
            return Err(CreateTxError::NoUtxosSelected);
1✔
1297
        }
139✔
1298

139✔
1299
        let mut outgoing = Amount::ZERO;
139✔
1300
        let mut received = Amount::ZERO;
139✔
1301

139✔
1302
        let recipients = params.recipients.iter().map(|(r, v)| (r, *v));
139✔
1303

1304
        for (index, (script_pubkey, value)) in recipients.enumerate() {
139✔
1305
            if !params.allow_dust && value.is_dust(script_pubkey) && !script_pubkey.is_op_return() {
89✔
1306
                return Err(CreateTxError::OutputBelowDustLimit(index));
1✔
1307
            }
88✔
1308

88✔
1309
            if self.is_mine(script_pubkey) {
88✔
1310
                received += Amount::from_sat(value);
42✔
1311
            }
50✔
1312

1313
            let new_out = TxOut {
88✔
1314
                script_pubkey: script_pubkey.clone(),
88✔
1315
                value: Amount::from_sat(value),
88✔
1316
            };
88✔
1317

88✔
1318
            tx.output.push(new_out);
88✔
1319

88✔
1320
            outgoing += Amount::from_sat(value);
88✔
1321
        }
1322

1323
        fee_amount += (fee_rate * tx.weight()).to_sat();
138✔
1324

138✔
1325
        let (required_utxos, optional_utxos) =
138✔
1326
            self.preselect_utxos(&params, Some(current_height.to_consensus_u32()));
138✔
1327

1328
        // get drain script
1329
        let drain_script = match params.drain_to {
138✔
1330
            Some(ref drain_recipient) => drain_recipient.clone(),
52✔
1331
            None => {
1332
                let change_keychain = KeychainKind::Internal;
86✔
1333
                let ((index, spk), index_changeset) = self
86✔
1334
                    .indexed_graph
86✔
1335
                    .index
86✔
1336
                    .next_unused_spk(&change_keychain)
86✔
1337
                    .expect("keychain must exist");
86✔
1338
                self.indexed_graph.index.mark_used(change_keychain, index);
86✔
1339
                self.stage.merge(index_changeset.into());
86✔
1340
                spk
86✔
1341
            }
1342
        };
1343

1344
        let (required_utxos, optional_utxos) =
138✔
1345
            coin_selection::filter_duplicates(required_utxos, optional_utxos);
138✔
1346

1347
        let coin_selection = match coin_selection.coin_select(
138✔
1348
            required_utxos.clone(),
138✔
1349
            optional_utxos.clone(),
138✔
1350
            fee_rate,
138✔
1351
            outgoing.to_sat() + fee_amount,
138✔
1352
            &drain_script,
138✔
1353
        ) {
138✔
1354
            Ok(res) => res,
62✔
1355
            Err(e) => match e {
76✔
1356
                coin_selection::Error::InsufficientFunds { .. } => {
1357
                    return Err(CreateTxError::CoinSelection(e));
7✔
1358
                }
1359
                coin_selection::Error::BnBNoExactMatch
1360
                | coin_selection::Error::BnBTotalTriesExceeded => {
1361
                    coin_selection::single_random_draw(
69✔
1362
                        required_utxos,
69✔
1363
                        optional_utxos,
69✔
1364
                        outgoing.to_sat() + fee_amount,
69✔
1365
                        &drain_script,
69✔
1366
                        fee_rate,
69✔
1367
                        rng,
69✔
1368
                    )
69✔
1369
                }
1370
            },
1371
        };
1372
        fee_amount += coin_selection.fee_amount;
131✔
1373
        let excess = &coin_selection.excess;
131✔
1374

131✔
1375
        tx.input = coin_selection
131✔
1376
            .selected
131✔
1377
            .iter()
131✔
1378
            .map(|u| bitcoin::TxIn {
147✔
1379
                previous_output: u.outpoint(),
147✔
1380
                script_sig: ScriptBuf::default(),
147✔
1381
                sequence: u.sequence().unwrap_or(n_sequence),
147✔
1382
                witness: Witness::new(),
147✔
1383
            })
147✔
1384
            .collect();
131✔
1385

131✔
1386
        if tx.output.is_empty() {
131✔
1387
            // Uh oh, our transaction has no outputs.
1388
            // We allow this when:
1389
            // - We have a drain_to address and the utxos we must spend (this happens,
1390
            // for example, when we RBF)
1391
            // - We have a drain_to address and drain_wallet set
1392
            // Otherwise, we don't know who we should send the funds to, and how much
1393
            // we should send!
1394
            if params.drain_to.is_some() && (params.drain_wallet || !params.utxos.is_empty()) {
50✔
1395
                if let NoChange {
1396
                    dust_threshold,
1✔
1397
                    remaining_amount,
1✔
1398
                    change_fee,
1✔
1399
                } = excess
48✔
1400
                {
1401
                    return Err(CreateTxError::CoinSelection(Error::InsufficientFunds {
1✔
1402
                        needed: *dust_threshold,
1✔
1403
                        available: remaining_amount.saturating_sub(*change_fee),
1✔
1404
                    }));
1✔
1405
                }
47✔
1406
            } else {
1407
                return Err(CreateTxError::NoRecipients);
2✔
1408
            }
1409
        }
81✔
1410

1411
        match excess {
128✔
1412
            NoChange {
1413
                remaining_amount, ..
7✔
1414
            } => fee_amount += remaining_amount,
7✔
1415
            Change { amount, fee } => {
121✔
1416
                if self.is_mine(&drain_script) {
121✔
1417
                    received += Amount::from_sat(*amount);
111✔
1418
                }
111✔
1419
                fee_amount += fee;
121✔
1420

121✔
1421
                // create drain output
121✔
1422
                let drain_output = TxOut {
121✔
1423
                    value: Amount::from_sat(*amount),
121✔
1424
                    script_pubkey: drain_script,
121✔
1425
                };
121✔
1426

121✔
1427
                // TODO: We should pay attention when adding a new output: this might increase
121✔
1428
                // the length of the "number of vouts" parameter by 2 bytes, potentially making
121✔
1429
                // our feerate too low
121✔
1430
                tx.output.push(drain_output);
121✔
1431
            }
1432
        };
1433

1434
        // sort input/outputs according to the chosen algorithm
1435
        params.ordering.sort_tx_with_aux_rand(&mut tx, rng);
128✔
1436

1437
        let psbt = self.complete_transaction(tx, coin_selection.selected, params)?;
128✔
1438
        Ok(psbt)
126✔
1439
    }
149✔
1440

1441
    /// Bump the fee of a transaction previously created with this wallet.
1442
    ///
1443
    /// Returns an error if the transaction is already confirmed or doesn't explicitly signal
1444
    /// *replace by fee* (RBF). If the transaction can be fee bumped then it returns a [`TxBuilder`]
1445
    /// pre-populated with the inputs and outputs of the original transaction.
1446
    ///
1447
    /// ## Example
1448
    ///
1449
    /// ```no_run
1450
    /// # // TODO: remove norun -- bumping fee seems to need the tx in the wallet database first.
1451
    /// # use std::str::FromStr;
1452
    /// # use bitcoin::*;
1453
    /// # use bdk_wallet::*;
1454
    /// # use bdk_wallet::ChangeSet;
1455
    /// # use bdk_wallet::error::CreateTxError;
1456
    /// # use anyhow::Error;
1457
    /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
1458
    /// # let mut wallet = doctest_wallet!();
1459
    /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
1460
    /// let mut psbt = {
1461
    ///     let mut builder = wallet.build_tx();
1462
    ///     builder
1463
    ///         .add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000))
1464
    ///         .enable_rbf();
1465
    ///     builder.finish()?
1466
    /// };
1467
    /// let _ = wallet.sign(&mut psbt, SignOptions::default())?;
1468
    /// let tx = psbt.clone().extract_tx().expect("tx");
1469
    /// // broadcast tx but it's taking too long to confirm so we want to bump the fee
1470
    /// let mut psbt =  {
1471
    ///     let mut builder = wallet.build_fee_bump(tx.compute_txid())?;
1472
    ///     builder
1473
    ///         .fee_rate(FeeRate::from_sat_per_vb(5).expect("valid feerate"));
1474
    ///     builder.finish()?
1475
    /// };
1476
    ///
1477
    /// let _ = wallet.sign(&mut psbt, SignOptions::default())?;
1478
    /// let fee_bumped_tx = psbt.extract_tx();
1479
    /// // broadcast fee_bumped_tx to replace original
1480
    /// # Ok::<(), anyhow::Error>(())
1481
    /// ```
1482
    // TODO: support for merging multiple transactions while bumping the fees
1483
    pub fn build_fee_bump(
152✔
1484
        &mut self,
152✔
1485
        txid: Txid,
152✔
1486
    ) -> Result<TxBuilder<'_, DefaultCoinSelectionAlgorithm>, BuildFeeBumpError> {
152✔
1487
        let graph = self.indexed_graph.graph();
152✔
1488
        let txout_index = &self.indexed_graph.index;
152✔
1489
        let chain_tip = self.chain.tip().block_id();
152✔
1490

1491
        let mut tx = graph
152✔
1492
            .get_tx(txid)
152✔
1493
            .ok_or(BuildFeeBumpError::TransactionNotFound(txid))?
152✔
1494
            .as_ref()
152✔
1495
            .clone();
152✔
1496

1497
        let pos = graph
152✔
1498
            .get_chain_position(&self.chain, chain_tip, txid)
152✔
1499
            .ok_or(BuildFeeBumpError::TransactionNotFound(txid))?;
152✔
1500
        if let ChainPosition::Confirmed(_) = pos {
152✔
1501
            return Err(BuildFeeBumpError::TransactionConfirmed(txid));
8✔
1502
        }
144✔
1503

144✔
1504
        if !tx
144✔
1505
            .input
144✔
1506
            .iter()
144✔
1507
            .any(|txin| txin.sequence.to_consensus_u32() <= 0xFFFFFFFD)
144✔
1508
        {
1509
            return Err(BuildFeeBumpError::IrreplaceableTransaction(
8✔
1510
                tx.compute_txid(),
8✔
1511
            ));
8✔
1512
        }
136✔
1513

1514
        let fee = self
136✔
1515
            .calculate_fee(&tx)
136✔
1516
            .map_err(|_| BuildFeeBumpError::FeeRateUnavailable)?;
136✔
1517
        let fee_rate = self
136✔
1518
            .calculate_fee_rate(&tx)
136✔
1519
            .map_err(|_| BuildFeeBumpError::FeeRateUnavailable)?;
136✔
1520

1521
        // remove the inputs from the tx and process them
1522
        let original_txin = tx.input.drain(..).collect::<Vec<_>>();
136✔
1523
        let original_utxos = original_txin
136✔
1524
            .iter()
136✔
1525
            .map(|txin| -> Result<_, BuildFeeBumpError> {
144✔
1526
                let prev_tx = graph
144✔
1527
                    .get_tx(txin.previous_output.txid)
144✔
1528
                    .ok_or(BuildFeeBumpError::UnknownUtxo(txin.previous_output))?;
144✔
1529
                let txout = &prev_tx.output[txin.previous_output.vout as usize];
144✔
1530

1531
                let confirmation_time: ConfirmationTime = graph
144✔
1532
                    .get_chain_position(&self.chain, chain_tip, txin.previous_output.txid)
144✔
1533
                    .ok_or(BuildFeeBumpError::UnknownUtxo(txin.previous_output))?
144✔
1534
                    .cloned()
144✔
1535
                    .into();
144✔
1536

1537
                let weighted_utxo = match txout_index.index_of_spk(&txout.script_pubkey) {
144✔
1538
                    Some(&(keychain, derivation_index)) => {
144✔
1539
                        let satisfaction_weight = self
144✔
1540
                            .public_descriptor(keychain)
144✔
1541
                            .max_weight_to_satisfy()
144✔
1542
                            .unwrap();
144✔
1543
                        WeightedUtxo {
144✔
1544
                            utxo: Utxo::Local(LocalOutput {
144✔
1545
                                outpoint: txin.previous_output,
144✔
1546
                                txout: txout.clone(),
144✔
1547
                                keychain,
144✔
1548
                                is_spent: true,
144✔
1549
                                derivation_index,
144✔
1550
                                confirmation_time,
144✔
1551
                            }),
144✔
1552
                            satisfaction_weight,
144✔
1553
                        }
144✔
1554
                    }
1555
                    None => {
1556
                        let satisfaction_weight = Weight::from_wu_usize(
×
1557
                            serialize(&txin.script_sig).len() * 4 + serialize(&txin.witness).len(),
×
1558
                        );
×
1559
                        WeightedUtxo {
×
1560
                            utxo: Utxo::Foreign {
×
1561
                                outpoint: txin.previous_output,
×
1562
                                sequence: Some(txin.sequence),
×
1563
                                psbt_input: Box::new(psbt::Input {
×
1564
                                    witness_utxo: Some(txout.clone()),
×
1565
                                    non_witness_utxo: Some(prev_tx.as_ref().clone()),
×
1566
                                    ..Default::default()
×
1567
                                }),
×
1568
                            },
×
1569
                            satisfaction_weight,
×
1570
                        }
×
1571
                    }
1572
                };
1573

1574
                Ok(weighted_utxo)
144✔
1575
            })
144✔
1576
            .collect::<Result<Vec<_>, _>>()?;
136✔
1577

1578
        if tx.output.len() > 1 {
136✔
1579
            let mut change_index = None;
80✔
1580
            for (index, txout) in tx.output.iter().enumerate() {
160✔
1581
                let change_keychain = KeychainKind::Internal;
160✔
1582
                match txout_index.index_of_spk(&txout.script_pubkey) {
160✔
1583
                    Some((keychain, _)) if *keychain == change_keychain => {
104✔
1584
                        change_index = Some(index)
80✔
1585
                    }
1586
                    _ => {}
80✔
1587
                }
1588
            }
1589

1590
            if let Some(change_index) = change_index {
80✔
1591
                tx.output.remove(change_index);
80✔
1592
            }
80✔
1593
        }
56✔
1594

1595
        let params = TxParams {
136✔
1596
            // TODO: figure out what rbf option should be?
136✔
1597
            version: Some(tx_builder::Version(tx.version.0)),
136✔
1598
            recipients: tx
136✔
1599
                .output
136✔
1600
                .into_iter()
136✔
1601
                .map(|txout| (txout.script_pubkey, txout.value.to_sat()))
136✔
1602
                .collect(),
136✔
1603
            utxos: original_utxos,
136✔
1604
            bumping_fee: Some(tx_builder::PreviousFee {
136✔
1605
                absolute: fee.to_sat(),
136✔
1606
                rate: fee_rate,
136✔
1607
            }),
136✔
1608
            ..Default::default()
136✔
1609
        };
136✔
1610

136✔
1611
        Ok(TxBuilder {
136✔
1612
            wallet: alloc::rc::Rc::new(core::cell::RefCell::new(self)),
136✔
1613
            params,
136✔
1614
            coin_selection: DefaultCoinSelectionAlgorithm::default(),
136✔
1615
        })
136✔
1616
    }
152✔
1617

1618
    /// Sign a transaction with all the wallet's signers, in the order specified by every signer's
1619
    /// [`SignerOrdering`]. This function returns the `Result` type with an encapsulated `bool` that has the value true if the PSBT was finalized, or false otherwise.
1620
    ///
1621
    /// The [`SignOptions`] can be used to tweak the behavior of the software signers, and the way
1622
    /// the transaction is finalized at the end. Note that it can't be guaranteed that *every*
1623
    /// signers will follow the options, but the "software signers" (WIF keys and `xprv`) defined
1624
    /// in this library will.
1625
    ///
1626
    /// ## Example
1627
    ///
1628
    /// ```
1629
    /// # use std::str::FromStr;
1630
    /// # use bitcoin::*;
1631
    /// # use bdk_wallet::*;
1632
    /// # use bdk_wallet::ChangeSet;
1633
    /// # use bdk_wallet::error::CreateTxError;
1634
    /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
1635
    /// # let mut wallet = doctest_wallet!();
1636
    /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
1637
    /// let mut psbt = {
1638
    ///     let mut builder = wallet.build_tx();
1639
    ///     builder.add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000));
1640
    ///     builder.finish()?
1641
    /// };
1642
    /// let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
1643
    /// assert!(finalized, "we should have signed all the inputs");
1644
    /// # Ok::<(),anyhow::Error>(())
1645
    pub fn sign(&self, psbt: &mut Psbt, sign_options: SignOptions) -> Result<bool, SignerError> {
360✔
1646
        // This adds all the PSBT metadata for the inputs, which will help us later figure out how
360✔
1647
        // to derive our keys
360✔
1648
        self.update_psbt_with_descriptor(psbt)
360✔
1649
            .map_err(SignerError::MiniscriptPsbt)?;
360✔
1650

1651
        // If we aren't allowed to use `witness_utxo`, ensure that every input (except p2tr and finalized ones)
1652
        // has the `non_witness_utxo`
1653
        if !sign_options.trust_witness_utxo
360✔
1654
            && psbt
312✔
1655
                .inputs
312✔
1656
                .iter()
312✔
1657
                .filter(|i| i.final_script_witness.is_none() && i.final_script_sig.is_none())
320✔
1658
                .filter(|i| i.tap_internal_key.is_none() && i.tap_merkle_root.is_none())
312✔
1659
                .any(|i| i.non_witness_utxo.is_none())
312✔
1660
        {
1661
            return Err(SignerError::MissingNonWitnessUtxo);
×
1662
        }
360✔
1663

360✔
1664
        // If the user hasn't explicitly opted-in, refuse to sign the transaction unless every input
360✔
1665
        // is using `SIGHASH_ALL` or `SIGHASH_DEFAULT` for taproot
360✔
1666
        if !sign_options.allow_all_sighashes
360✔
1667
            && !psbt.inputs.iter().all(|i| {
368✔
1668
                i.sighash_type.is_none()
368✔
1669
                    || i.sighash_type == Some(EcdsaSighashType::All.into())
24✔
1670
                    || i.sighash_type == Some(TapSighashType::All.into())
16✔
1671
                    || i.sighash_type == Some(TapSighashType::Default.into())
16✔
1672
            })
368✔
1673
        {
1674
            return Err(SignerError::NonStandardSighash);
16✔
1675
        }
344✔
1676

1677
        for signer in self
712✔
1678
            .signers
344✔
1679
            .signers()
344✔
1680
            .iter()
344✔
1681
            .chain(self.change_signers.signers().iter())
344✔
1682
        {
1683
            signer.sign_transaction(psbt, &sign_options, &self.secp)?;
712✔
1684
        }
1685

1686
        // attempt to finalize
1687
        if sign_options.try_finalize {
312✔
1688
            self.finalize_psbt(psbt, sign_options)
280✔
1689
        } else {
1690
            Ok(false)
32✔
1691
        }
1692
    }
360✔
1693

1694
    /// Return the spending policies for the wallet's descriptor
1695
    pub fn policies(&self, keychain: KeychainKind) -> Result<Option<Policy>, DescriptorError> {
24✔
1696
        let signers = match keychain {
24✔
1697
            KeychainKind::External => &self.signers,
24✔
1698
            KeychainKind::Internal => &self.change_signers,
×
1699
        };
1700

1701
        self.public_descriptor(keychain).extract_policy(
24✔
1702
            signers,
24✔
1703
            BuildSatisfaction::None,
24✔
1704
            &self.secp,
24✔
1705
        )
24✔
1706
    }
24✔
1707

1708
    /// Returns the descriptor used to create addresses for a particular `keychain`.
1709
    /// It's the "public" version of the wallet's descriptor, meaning a new descriptor that has
1710
    /// the same structure but with the all secret keys replaced by their corresponding public key.
1711
    ///
1712
    /// This can be used to build a watch-only version of a wallet.
1713
    pub fn public_descriptor(&self, keychain: KeychainKind) -> &ExtendedDescriptor {
6,260✔
1714
        self.indexed_graph
6,260✔
1715
            .index
6,260✔
1716
            .get_descriptor(&keychain)
6,260✔
1717
            .expect("keychain must exist")
6,260✔
1718
    }
6,260✔
1719

1720
    /// Finalize a PSBT, i.e., for each input determine if sufficient data is available to pass
1721
    /// validation and construct the respective `scriptSig` or `scriptWitness`. Please refer to
1722
    /// [BIP174](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#Input_Finalizer),
1723
    /// and [BIP371](https://github.com/bitcoin/bips/blob/master/bip-0371.mediawiki)
1724
    /// for further information.
1725
    ///
1726
    /// Returns `true` if the PSBT could be finalized, and `false` otherwise.
1727
    ///
1728
    /// The [`SignOptions`] can be used to tweak the behavior of the finalizer.
1729
    pub fn finalize_psbt(
280✔
1730
        &self,
280✔
1731
        psbt: &mut Psbt,
280✔
1732
        sign_options: SignOptions,
280✔
1733
    ) -> Result<bool, SignerError> {
280✔
1734
        let chain_tip = self.chain.tip().block_id();
280✔
1735

280✔
1736
        let tx = &psbt.unsigned_tx;
280✔
1737
        let mut finished = true;
280✔
1738

1739
        for (n, input) in tx.input.iter().enumerate() {
320✔
1740
            let psbt_input = &psbt
320✔
1741
                .inputs
320✔
1742
                .get(n)
320✔
1743
                .ok_or(SignerError::InputIndexOutOfRange)?;
320✔
1744
            if psbt_input.final_script_sig.is_some() || psbt_input.final_script_witness.is_some() {
312✔
1745
                continue;
16✔
1746
            }
296✔
1747
            let confirmation_height = self
296✔
1748
                .indexed_graph
296✔
1749
                .graph()
296✔
1750
                .get_chain_position(&self.chain, chain_tip, input.previous_output.txid)
296✔
1751
                .map(|chain_position| match chain_position {
296✔
1752
                    ChainPosition::Confirmed(a) => a.block_id.height,
272✔
1753
                    ChainPosition::Unconfirmed(_) => u32::MAX,
×
1754
                });
296✔
1755
            let current_height = sign_options
296✔
1756
                .assume_height
296✔
1757
                .unwrap_or_else(|| self.chain.tip().height());
296✔
1758

296✔
1759
            // - Try to derive the descriptor by looking at the txout. If it's in our database, we
296✔
1760
            //   know exactly which `keychain` to use, and which derivation index it is
296✔
1761
            // - If that fails, try to derive it by looking at the psbt input: the complete logic
296✔
1762
            //   is in `src/descriptor/mod.rs`, but it will basically look at `bip32_derivation`,
296✔
1763
            //   `redeem_script` and `witness_script` to determine the right derivation
296✔
1764
            // - If that also fails, it will try it on the internal descriptor, if present
296✔
1765
            let desc = psbt
296✔
1766
                .get_utxo_for(n)
296✔
1767
                .and_then(|txout| self.get_descriptor_for_txout(&txout))
296✔
1768
                .or_else(|| {
296✔
1769
                    self.indexed_graph.index.keychains().find_map(|(_, desc)| {
32✔
1770
                        desc.derive_from_psbt_input(psbt_input, psbt.get_utxo_for(n), &self.secp)
32✔
1771
                    })
32✔
1772
                });
296✔
1773

296✔
1774
            match desc {
296✔
1775
                Some(desc) => {
280✔
1776
                    let mut tmp_input = bitcoin::TxIn::default();
280✔
1777
                    match desc.satisfy(
280✔
1778
                        &mut tmp_input,
280✔
1779
                        (
280✔
1780
                            PsbtInputSatisfier::new(psbt, n),
280✔
1781
                            After::new(Some(current_height), false),
280✔
1782
                            Older::new(Some(current_height), confirmation_height, false),
280✔
1783
                        ),
280✔
1784
                    ) {
280✔
1785
                        Ok(_) => {
1786
                            // Set the UTXO fields, final script_sig and witness
1787
                            // and clear everything else.
1788
                            let original = mem::take(&mut psbt.inputs[n]);
272✔
1789
                            let psbt_input = &mut psbt.inputs[n];
272✔
1790
                            psbt_input.non_witness_utxo = original.non_witness_utxo;
272✔
1791
                            psbt_input.witness_utxo = original.witness_utxo;
272✔
1792
                            if !tmp_input.script_sig.is_empty() {
272✔
1793
                                psbt_input.final_script_sig = Some(tmp_input.script_sig);
16✔
1794
                            }
256✔
1795
                            if !tmp_input.witness.is_empty() {
272✔
1796
                                psbt_input.final_script_witness = Some(tmp_input.witness);
264✔
1797
                            }
264✔
1798
                        }
1799
                        Err(_) => finished = false,
8✔
1800
                    }
1801
                }
1802
                None => finished = false,
16✔
1803
            }
1804
        }
1805

1806
        // Clear derivation paths from outputs
1807
        if finished {
272✔
1808
            for output in &mut psbt.outputs {
584✔
1809
                output.bip32_derivation.clear();
336✔
1810
                output.tap_key_origins.clear();
336✔
1811
            }
336✔
1812
        }
24✔
1813

1814
        Ok(finished)
272✔
1815
    }
280✔
1816

1817
    /// Return the secp256k1 context used for all signing operations
1818
    pub fn secp_ctx(&self) -> &SecpCtx {
28✔
1819
        &self.secp
28✔
1820
    }
28✔
1821

1822
    /// The derivation index of this wallet. It will return `None` if it has not derived any addresses.
1823
    /// Otherwise, it will return the index of the highest address it has derived.
1824
    pub fn derivation_index(&self, keychain: KeychainKind) -> Option<u32> {
40✔
1825
        self.indexed_graph.index.last_revealed_index(&keychain)
40✔
1826
    }
40✔
1827

1828
    /// The index of the next address that you would get if you were to ask the wallet for a new address
1829
    pub fn next_derivation_index(&self, keychain: KeychainKind) -> u32 {
×
1830
        self.indexed_graph
×
1831
            .index
×
1832
            .next_index(&keychain)
×
1833
            .expect("keychain must exist")
×
1834
            .0
×
1835
    }
×
1836

1837
    /// Informs the wallet that you no longer intend to broadcast a tx that was built from it.
1838
    ///
1839
    /// This frees up the change address used when creating the tx for use in future transactions.
1840
    // TODO: Make this free up reserved utxos when that's implemented
1841
    pub fn cancel_tx(&mut self, tx: &Transaction) {
16✔
1842
        let txout_index = &mut self.indexed_graph.index;
16✔
1843
        for txout in &tx.output {
48✔
1844
            if let Some((keychain, index)) = txout_index.index_of_spk(&txout.script_pubkey) {
32✔
1845
                // NOTE: unmark_used will **not** make something unused if it has actually been used
16✔
1846
                // by a tx in the tracker. It only removes the superficial marking.
16✔
1847
                txout_index.unmark_used(*keychain, *index);
16✔
1848
            }
16✔
1849
        }
1850
    }
16✔
1851

1852
    fn get_descriptor_for_txout(&self, txout: &TxOut) -> Option<DerivedDescriptor> {
296✔
1853
        let &(keychain, child) = self
296✔
1854
            .indexed_graph
296✔
1855
            .index
296✔
1856
            .index_of_spk(&txout.script_pubkey)?;
296✔
1857
        let descriptor = self.public_descriptor(keychain);
280✔
1858
        descriptor.at_derivation_index(child).ok()
280✔
1859
    }
296✔
1860

1861
    fn get_available_utxos(&self) -> Vec<(LocalOutput, Weight)> {
1,160✔
1862
        self.list_unspent()
1,160✔
1863
            .map(|utxo| {
1,272✔
1864
                let keychain = utxo.keychain;
1,272✔
1865
                (utxo, {
1,272✔
1866
                    self.public_descriptor(keychain)
1,272✔
1867
                        .max_weight_to_satisfy()
1,272✔
1868
                        .unwrap()
1,272✔
1869
                })
1,272✔
1870
            })
1,272✔
1871
            .collect()
1,160✔
1872
    }
1,160✔
1873

1874
    /// Given the options returns the list of utxos that must be used to form the
1875
    /// transaction and any further that may be used if needed.
1876
    fn preselect_utxos(
1,160✔
1877
        &self,
1,160✔
1878
        params: &TxParams,
1,160✔
1879
        current_height: Option<u32>,
1,160✔
1880
    ) -> (Vec<WeightedUtxo>, Vec<WeightedUtxo>) {
1,160✔
1881
        let TxParams {
1,160✔
1882
            change_policy,
1,160✔
1883
            unspendable,
1,160✔
1884
            utxos,
1,160✔
1885
            drain_wallet,
1,160✔
1886
            manually_selected_only,
1,160✔
1887
            bumping_fee,
1,160✔
1888
            ..
1,160✔
1889
        } = params;
1,160✔
1890

1,160✔
1891
        let manually_selected = utxos.clone();
1,160✔
1892
        // we mandate confirmed transactions if we're bumping the fee
1,160✔
1893
        let must_only_use_confirmed_tx = bumping_fee.is_some();
1,160✔
1894
        let must_use_all_available = *drain_wallet;
1,160✔
1895

1,160✔
1896
        let chain_tip = self.chain.tip().block_id();
1,160✔
1897
        //    must_spend <- manually selected utxos
1,160✔
1898
        //    may_spend  <- all other available utxos
1,160✔
1899
        let mut may_spend = self.get_available_utxos();
1,160✔
1900

1,160✔
1901
        may_spend.retain(|may_spend| {
1,272✔
1902
            !manually_selected
1,272✔
1903
                .iter()
1,272✔
1904
                .any(|manually_selected| manually_selected.utxo.outpoint() == may_spend.0.outpoint)
1,272✔
1905
        });
1,272✔
1906
        let mut must_spend = manually_selected;
1,160✔
1907

1,160✔
1908
        // NOTE: we are intentionally ignoring `unspendable` here. i.e manual
1,160✔
1909
        // selection overrides unspendable.
1,160✔
1910
        if *manually_selected_only {
1,160✔
1911
            return (must_spend, vec![]);
40✔
1912
        }
1,120✔
1913

1,120✔
1914
        let satisfies_confirmed = may_spend
1,120✔
1915
            .iter()
1,120✔
1916
            .map(|u| -> bool {
1,160✔
1917
                let txid = u.0.outpoint.txid;
1,160✔
1918
                let tx = match self.indexed_graph.graph().get_tx(txid) {
1,160✔
1919
                    Some(tx) => tx,
1,160✔
1920
                    None => return false,
×
1921
                };
1922
                let confirmation_time: ConfirmationTime = match self
1,160✔
1923
                    .indexed_graph
1,160✔
1924
                    .graph()
1,160✔
1925
                    .get_chain_position(&self.chain, chain_tip, txid)
1,160✔
1926
                {
1927
                    Some(chain_position) => chain_position.cloned().into(),
1,160✔
1928
                    None => return false,
×
1929
                };
1930

1931
                // Whether the UTXO is mature and, if needed, confirmed
1932
                let mut spendable = true;
1,160✔
1933
                if must_only_use_confirmed_tx && !confirmation_time.is_confirmed() {
1,160✔
1934
                    return false;
64✔
1935
                }
1,096✔
1936
                if tx.is_coinbase() {
1,096✔
1937
                    debug_assert!(
24✔
1938
                        confirmation_time.is_confirmed(),
24✔
1939
                        "coinbase must always be confirmed"
×
1940
                    );
1941
                    if let Some(current_height) = current_height {
24✔
1942
                        match confirmation_time {
24✔
1943
                            ConfirmationTime::Confirmed { height, .. } => {
24✔
1944
                                // https://github.com/bitcoin/bitcoin/blob/c5e67be03bb06a5d7885c55db1f016fbf2333fe3/src/validation.cpp#L373-L375
24✔
1945
                                spendable &=
24✔
1946
                                    (current_height.saturating_sub(height)) >= COINBASE_MATURITY;
24✔
1947
                            }
24✔
1948
                            ConfirmationTime::Unconfirmed { .. } => spendable = false,
×
1949
                        }
1950
                    }
×
1951
                }
1,072✔
1952
                spendable
1,096✔
1953
            })
1,160✔
1954
            .collect::<Vec<_>>();
1,120✔
1955

1,120✔
1956
        let mut i = 0;
1,120✔
1957
        may_spend.retain(|u| {
1,160✔
1958
            let retain = change_policy.is_satisfied_by(&u.0)
1,160✔
1959
                && !unspendable.contains(&u.0.outpoint)
1,152✔
1960
                && satisfies_confirmed[i];
1,152✔
1961
            i += 1;
1,160✔
1962
            retain
1,160✔
1963
        });
1,160✔
1964

1,120✔
1965
        let mut may_spend = may_spend
1,120✔
1966
            .into_iter()
1,120✔
1967
            .map(|(local_utxo, satisfaction_weight)| WeightedUtxo {
1,120✔
1968
                satisfaction_weight,
1,072✔
1969
                utxo: Utxo::Local(local_utxo),
1,072✔
1970
            })
1,120✔
1971
            .collect();
1,120✔
1972

1,120✔
1973
        if must_use_all_available {
1,120✔
1974
            must_spend.append(&mut may_spend);
392✔
1975
        }
728✔
1976

1977
        (must_spend, may_spend)
1,120✔
1978
    }
1,160✔
1979

1980
    fn complete_transaction(
1,080✔
1981
        &self,
1,080✔
1982
        tx: Transaction,
1,080✔
1983
        selected: Vec<Utxo>,
1,080✔
1984
        params: TxParams,
1,080✔
1985
    ) -> Result<Psbt, CreateTxError> {
1,080✔
1986
        let mut psbt = Psbt::from_unsigned_tx(tx)?;
1,080✔
1987

1988
        if params.add_global_xpubs {
1,080✔
1989
            let all_xpubs = self
24✔
1990
                .keychains()
24✔
1991
                .flat_map(|(_, desc)| desc.get_extended_keys())
48✔
1992
                .collect::<Vec<_>>();
24✔
1993

1994
            for xpub in all_xpubs {
56✔
1995
                let origin = match xpub.origin {
32✔
1996
                    Some(origin) => origin,
24✔
1997
                    None if xpub.xkey.depth == 0 => {
16✔
1998
                        (xpub.root_fingerprint(&self.secp), vec![].into())
8✔
1999
                    }
2000
                    _ => return Err(CreateTxError::MissingKeyOrigin(xpub.xkey.to_string())),
8✔
2001
                };
2002

2003
                psbt.xpub.insert(xpub.xkey, origin);
32✔
2004
            }
2005
        }
1,056✔
2006

2007
        let mut lookup_output = selected
1,072✔
2008
            .into_iter()
1,072✔
2009
            .map(|utxo| (utxo.outpoint(), utxo))
1,200✔
2010
            .collect::<HashMap<_, _>>();
1,072✔
2011

2012
        // add metadata for the inputs
2013
        for (psbt_input, input) in psbt.inputs.iter_mut().zip(psbt.unsigned_tx.input.iter()) {
1,200✔
2014
            let utxo = match lookup_output.remove(&input.previous_output) {
1,200✔
2015
                Some(utxo) => utxo,
1,200✔
2016
                None => continue,
×
2017
            };
2018

2019
            match utxo {
1,200✔
2020
                Utxo::Local(utxo) => {
1,152✔
2021
                    *psbt_input =
1,152✔
2022
                        match self.get_psbt_input(utxo, params.sighash, params.only_witness_utxo) {
1,152✔
2023
                            Ok(psbt_input) => psbt_input,
1,152✔
2024
                            Err(e) => match e {
×
2025
                                CreateTxError::UnknownUtxo => psbt::Input {
×
2026
                                    sighash_type: params.sighash,
×
2027
                                    ..psbt::Input::default()
×
2028
                                },
×
2029
                                _ => return Err(e),
×
2030
                            },
2031
                        }
2032
                }
2033
                Utxo::Foreign {
2034
                    outpoint,
48✔
2035
                    psbt_input: foreign_psbt_input,
48✔
2036
                    ..
48✔
2037
                } => {
48✔
2038
                    let is_taproot = foreign_psbt_input
48✔
2039
                        .witness_utxo
48✔
2040
                        .as_ref()
48✔
2041
                        .map(|txout| txout.script_pubkey.is_p2tr())
48✔
2042
                        .unwrap_or(false);
48✔
2043
                    if !is_taproot
48✔
2044
                        && !params.only_witness_utxo
40✔
2045
                        && foreign_psbt_input.non_witness_utxo.is_none()
16✔
2046
                    {
2047
                        return Err(CreateTxError::MissingNonWitnessUtxo(outpoint));
8✔
2048
                    }
40✔
2049
                    *psbt_input = *foreign_psbt_input;
40✔
2050
                }
2051
            }
2052
        }
2053

2054
        self.update_psbt_with_descriptor(&mut psbt)?;
1,064✔
2055

2056
        Ok(psbt)
1,064✔
2057
    }
1,080✔
2058

2059
    /// get the corresponding PSBT Input for a LocalUtxo
2060
    pub fn get_psbt_input(
1,168✔
2061
        &self,
1,168✔
2062
        utxo: LocalOutput,
1,168✔
2063
        sighash_type: Option<psbt::PsbtSighashType>,
1,168✔
2064
        only_witness_utxo: bool,
1,168✔
2065
    ) -> Result<psbt::Input, CreateTxError> {
1,168✔
2066
        // Try to find the prev_script in our db to figure out if this is internal or external,
2067
        // and the derivation index
2068
        let &(keychain, child) = self
1,168✔
2069
            .indexed_graph
1,168✔
2070
            .index
1,168✔
2071
            .index_of_spk(&utxo.txout.script_pubkey)
1,168✔
2072
            .ok_or(CreateTxError::UnknownUtxo)?;
1,168✔
2073

2074
        let mut psbt_input = psbt::Input {
1,168✔
2075
            sighash_type,
1,168✔
2076
            ..psbt::Input::default()
1,168✔
2077
        };
1,168✔
2078

1,168✔
2079
        let desc = self.public_descriptor(keychain);
1,168✔
2080
        let derived_descriptor = desc
1,168✔
2081
            .at_derivation_index(child)
1,168✔
2082
            .expect("child can't be hardened");
1,168✔
2083

1,168✔
2084
        psbt_input
1,168✔
2085
            .update_with_descriptor_unchecked(&derived_descriptor)
1,168✔
2086
            .map_err(MiniscriptPsbtError::Conversion)?;
1,168✔
2087

2088
        let prev_output = utxo.outpoint;
1,168✔
2089
        if let Some(prev_tx) = self.indexed_graph.graph().get_tx(prev_output.txid) {
1,168✔
2090
            if desc.is_witness() || desc.is_taproot() {
1,168✔
2091
                psbt_input.witness_utxo = Some(prev_tx.output[prev_output.vout as usize].clone());
1,136✔
2092
            }
1,136✔
2093
            if !desc.is_taproot() && (!desc.is_witness() || !only_witness_utxo) {
1,168✔
2094
                psbt_input.non_witness_utxo = Some(prev_tx.as_ref().clone());
896✔
2095
            }
896✔
2096
        }
×
2097
        Ok(psbt_input)
1,168✔
2098
    }
1,168✔
2099

2100
    fn update_psbt_with_descriptor(&self, psbt: &mut Psbt) -> Result<(), MiniscriptPsbtError> {
1,424✔
2101
        // We need to borrow `psbt` mutably within the loops, so we have to allocate a vec for all
1,424✔
2102
        // the input utxos and outputs
1,424✔
2103
        let utxos = (0..psbt.inputs.len())
1,424✔
2104
            .filter_map(|i| psbt.get_utxo_for(i).map(|utxo| (true, i, utxo)))
1,592✔
2105
            .chain(
1,424✔
2106
                psbt.unsigned_tx
1,424✔
2107
                    .output
1,424✔
2108
                    .iter()
1,424✔
2109
                    .enumerate()
1,424✔
2110
                    .map(|(i, out)| (false, i, out.clone())),
2,216✔
2111
            )
1,424✔
2112
            .collect::<Vec<_>>();
1,424✔
2113

2114
        // Try to figure out the keychain and derivation for every input and output
2115
        for (is_input, index, out) in utxos.into_iter() {
3,768✔
2116
            if let Some(&(keychain, child)) =
3,136✔
2117
                self.indexed_graph.index.index_of_spk(&out.script_pubkey)
3,768✔
2118
            {
2119
                let desc = self.public_descriptor(keychain);
3,136✔
2120
                let desc = desc
3,136✔
2121
                    .at_derivation_index(child)
3,136✔
2122
                    .expect("child can't be hardened");
3,136✔
2123

3,136✔
2124
                if is_input {
3,136✔
2125
                    psbt.update_input_with_descriptor(index, &desc)
1,480✔
2126
                        .map_err(MiniscriptPsbtError::UtxoUpdate)?;
1,480✔
2127
                } else {
2128
                    psbt.update_output_with_descriptor(index, &desc)
1,656✔
2129
                        .map_err(MiniscriptPsbtError::OutputUpdate)?;
1,656✔
2130
                }
2131
            }
632✔
2132
        }
2133

2134
        Ok(())
1,424✔
2135
    }
1,424✔
2136

2137
    /// Return the checksum of the public descriptor associated to `keychain`
2138
    ///
2139
    /// Internally calls [`Self::public_descriptor`] to fetch the right descriptor
2140
    pub fn descriptor_checksum(&self, keychain: KeychainKind) -> String {
8✔
2141
        self.public_descriptor(keychain)
8✔
2142
            .to_string()
8✔
2143
            .split_once('#')
8✔
2144
            .unwrap()
8✔
2145
            .1
8✔
2146
            .to_string()
8✔
2147
    }
8✔
2148

2149
    /// Applies an update to the wallet and stages the changes (but does not persist them).
2150
    ///
2151
    /// Usually you create an `update` by interacting with some blockchain data source and inserting
2152
    /// transactions related to your wallet into it.
2153
    ///
2154
    /// After applying updates you should persist the staged wallet changes. For an example of how
2155
    /// to persist staged wallet changes see [`Wallet::reveal_next_address`]. `
2156
    ///
2157
    /// [`commit`]: Self::commit
2158
    pub fn apply_update(&mut self, update: impl Into<Update>) -> Result<(), CannotConnectError> {
301✔
2159
        let update = update.into();
301✔
2160
        let mut changeset = match update.chain {
301✔
2161
            Some(chain_update) => ChangeSet::from(self.chain.apply_update(chain_update)?),
×
2162
            None => ChangeSet::default(),
301✔
2163
        };
2164

2165
        let index_changeset = self
301✔
2166
            .indexed_graph
301✔
2167
            .index
301✔
2168
            .reveal_to_target_multi(&update.last_active_indices);
301✔
2169
        changeset.merge(index_changeset.into());
301✔
2170
        changeset.merge(self.indexed_graph.apply_update(update.graph).into());
301✔
2171
        self.stage.merge(changeset);
301✔
2172
        Ok(())
301✔
2173
    }
301✔
2174

2175
    /// Get a reference of the staged [`ChangeSet`] that are yet to be committed (if any).
2176
    pub fn staged(&self) -> Option<&ChangeSet> {
×
2177
        if self.stage.is_empty() {
×
2178
            None
×
2179
        } else {
2180
            Some(&self.stage)
×
2181
        }
2182
    }
×
2183

2184
    /// Take the staged [`ChangeSet`] to be persisted now (if any).
2185
    pub fn take_staged(&mut self) -> Option<ChangeSet> {
40✔
2186
        self.stage.take()
40✔
2187
    }
40✔
2188

2189
    /// Get a reference to the inner [`TxGraph`].
2190
    pub fn tx_graph(&self) -> &TxGraph<ConfirmationBlockTime> {
×
2191
        self.indexed_graph.graph()
×
2192
    }
×
2193

2194
    /// Iterate over transactions in the wallet that are unseen and unanchored likely
2195
    /// because they haven't been broadcast.
2196
    pub fn unbroadcast_transactions(
×
2197
        &self,
×
2198
    ) -> impl Iterator<Item = TxNode<'_, Arc<Transaction>, ConfirmationBlockTime>> {
×
2199
        self.tx_graph().txs_with_no_anchor_or_last_seen()
×
2200
    }
×
2201

2202
    /// Get a reference to the inner [`KeychainTxOutIndex`].
2203
    pub fn spk_index(&self) -> &KeychainTxOutIndex<KeychainKind> {
48✔
2204
        &self.indexed_graph.index
48✔
2205
    }
48✔
2206

2207
    /// Get a reference to the inner [`LocalChain`].
2208
    pub fn local_chain(&self) -> &LocalChain {
2,184✔
2209
        &self.chain
2,184✔
2210
    }
2,184✔
2211

2212
    /// Introduces a `block` of `height` to the wallet, and tries to connect it to the
2213
    /// `prev_blockhash` of the block's header.
2214
    ///
2215
    /// This is a convenience method that is equivalent to calling [`apply_block_connected_to`]
2216
    /// with `prev_blockhash` and `height-1` as the `connected_to` parameter.
2217
    ///
2218
    /// [`apply_block_connected_to`]: Self::apply_block_connected_to
2219
    pub fn apply_block(&mut self, block: &Block, height: u32) -> Result<(), CannotConnectError> {
×
2220
        let connected_to = match height.checked_sub(1) {
×
2221
            Some(prev_height) => BlockId {
×
2222
                height: prev_height,
×
2223
                hash: block.header.prev_blockhash,
×
2224
            },
×
2225
            None => BlockId {
×
2226
                height,
×
2227
                hash: block.block_hash(),
×
2228
            },
×
2229
        };
2230
        self.apply_block_connected_to(block, height, connected_to)
×
2231
            .map_err(|err| match err {
×
2232
                ApplyHeaderError::InconsistentBlocks => {
2233
                    unreachable!("connected_to is derived from the block so must be consistent")
×
2234
                }
2235
                ApplyHeaderError::CannotConnect(err) => err,
×
2236
            })
×
2237
    }
×
2238

2239
    /// Applies relevant transactions from `block` of `height` to the wallet, and connects the
2240
    /// block to the internal chain.
2241
    ///
2242
    /// The `connected_to` parameter informs the wallet how this block connects to the internal
2243
    /// [`LocalChain`]. Relevant transactions are filtered from the `block` and inserted into the
2244
    /// internal [`TxGraph`].
2245
    ///
2246
    /// **WARNING**: You must persist the changes resulting from one or more calls to this method
2247
    /// if you need the inserted block data to be reloaded after closing the wallet.
2248
    /// See [`Wallet::reveal_next_address`].
2249
    pub fn apply_block_connected_to(
×
2250
        &mut self,
×
2251
        block: &Block,
×
2252
        height: u32,
×
2253
        connected_to: BlockId,
×
2254
    ) -> Result<(), ApplyHeaderError> {
×
2255
        let mut changeset = ChangeSet::default();
×
2256
        changeset.merge(
×
2257
            self.chain
×
2258
                .apply_header_connected_to(&block.header, height, connected_to)?
×
2259
                .into(),
×
2260
        );
×
2261
        changeset.merge(
×
2262
            self.indexed_graph
×
2263
                .apply_block_relevant(block, height)
×
2264
                .into(),
×
2265
        );
×
2266
        self.stage.merge(changeset);
×
2267
        Ok(())
×
2268
    }
×
2269

2270
    /// Apply relevant unconfirmed transactions to the wallet.
2271
    ///
2272
    /// Transactions that are not relevant are filtered out.
2273
    ///
2274
    /// This method takes in an iterator of `(tx, last_seen)` where `last_seen` is the timestamp of
2275
    /// when the transaction was last seen in the mempool. This is used for conflict resolution
2276
    /// when there is conflicting unconfirmed transactions. The transaction with the later
2277
    /// `last_seen` is prioritized.
2278
    ///
2279
    /// **WARNING**: You must persist the changes resulting from one or more calls to this method
2280
    /// if you need the applied unconfirmed transactions to be reloaded after closing the wallet.
2281
    /// See [`Wallet::reveal_next_address`].
2282
    pub fn apply_unconfirmed_txs<'t>(
×
2283
        &mut self,
×
2284
        unconfirmed_txs: impl IntoIterator<Item = (&'t Transaction, u64)>,
×
2285
    ) {
×
2286
        let indexed_graph_changeset = self
×
2287
            .indexed_graph
×
2288
            .batch_insert_relevant_unconfirmed(unconfirmed_txs);
×
2289
        self.stage.merge(indexed_graph_changeset.into());
×
2290
    }
×
2291
}
2292

2293
/// Methods to construct sync/full-scan requests for spk-based chain sources.
2294
impl Wallet {
2295
    /// Create a partial [`SyncRequest`] for this wallet for all revealed spks.
2296
    ///
2297
    /// This is the first step when performing a spk-based wallet partial sync, the returned
2298
    /// [`SyncRequest`] collects all revealed script pubkeys from the wallet keychain needed to
2299
    /// start a blockchain sync with a spk based blockchain client.
2300
    pub fn start_sync_with_revealed_spks(&self) -> SyncRequest {
×
2301
        SyncRequest::from_chain_tip(self.chain.tip())
×
2302
            .populate_with_revealed_spks(&self.indexed_graph.index, ..)
×
2303
    }
×
2304

2305
    /// Create a [`FullScanRequest] for this wallet.
2306
    ///
2307
    /// This is the first step when performing a spk-based wallet full scan, the returned
2308
    /// [`FullScanRequest] collects iterators for the wallet's keychain script pub keys needed to
2309
    /// start a blockchain full scan with a spk based blockchain client.
2310
    ///
2311
    /// This operation is generally only used when importing or restoring a previously used wallet
2312
    /// in which the list of used scripts is not known.
2313
    pub fn start_full_scan(&self) -> FullScanRequest<KeychainKind> {
×
2314
        FullScanRequest::from_keychain_txout_index(self.chain.tip(), &self.indexed_graph.index)
×
2315
    }
×
2316
}
2317

2318
impl AsRef<bdk_chain::tx_graph::TxGraph<ConfirmationBlockTime>> for Wallet {
2319
    fn as_ref(&self) -> &bdk_chain::tx_graph::TxGraph<ConfirmationBlockTime> {
×
2320
        self.indexed_graph.graph()
×
2321
    }
×
2322
}
2323

2324
/// Deterministically generate a unique name given the descriptors defining the wallet
2325
///
2326
/// Compatible with [`wallet_name_from_descriptor`]
2327
pub fn wallet_name_from_descriptor<T>(
×
2328
    descriptor: T,
×
2329
    change_descriptor: Option<T>,
×
2330
    network: Network,
×
2331
    secp: &SecpCtx,
×
2332
) -> Result<String, DescriptorError>
×
2333
where
×
2334
    T: IntoWalletDescriptor,
×
2335
{
×
2336
    //TODO check descriptors contains only public keys
2337
    let descriptor = descriptor
×
2338
        .into_wallet_descriptor(secp, network)?
×
2339
        .0
2340
        .to_string();
×
2341
    let mut wallet_name = calc_checksum(&descriptor[..descriptor.find('#').unwrap()])?;
×
2342
    if let Some(change_descriptor) = change_descriptor {
×
2343
        let change_descriptor = change_descriptor
×
2344
            .into_wallet_descriptor(secp, network)?
×
2345
            .0
2346
            .to_string();
×
2347
        wallet_name.push_str(
×
2348
            calc_checksum(&change_descriptor[..change_descriptor.find('#').unwrap()])?.as_str(),
×
2349
        );
2350
    }
×
2351

2352
    Ok(wallet_name)
×
2353
}
×
2354

2355
fn new_local_utxo(
1,440✔
2356
    keychain: KeychainKind,
1,440✔
2357
    derivation_index: u32,
1,440✔
2358
    full_txo: FullTxOut<ConfirmationBlockTime>,
1,440✔
2359
) -> LocalOutput {
1,440✔
2360
    LocalOutput {
1,440✔
2361
        outpoint: full_txo.outpoint,
1,440✔
2362
        txout: full_txo.txout,
1,440✔
2363
        is_spent: full_txo.spent_by.is_some(),
1,440✔
2364
        confirmation_time: full_txo.chain_position.into(),
1,440✔
2365
        keychain,
1,440✔
2366
        derivation_index,
1,440✔
2367
    }
1,440✔
2368
}
1,440✔
2369

2370
fn create_indexer(
1,390✔
2371
    descriptor: ExtendedDescriptor,
1,390✔
2372
    change_descriptor: ExtendedDescriptor,
1,390✔
2373
    lookahead: u32,
1,390✔
2374
) -> Result<KeychainTxOutIndex<KeychainKind>, DescriptorError> {
1,390✔
2375
    let mut indexer = KeychainTxOutIndex::<KeychainKind>::new(lookahead);
1,390✔
2376

1,390✔
2377
    // let (descriptor, keymap) = descriptor;
1,390✔
2378
    // let signers = Arc::new(SignersContainer::build(keymap, &descriptor, secp));
1,390✔
2379
    assert!(indexer
1,390✔
2380
        .insert_descriptor(KeychainKind::External, descriptor)
1,390✔
2381
        .expect("first descriptor introduced must succeed"));
1,390✔
2382

2383
    // let (descriptor, keymap) = change_descriptor;
2384
    // let change_signers = Arc::new(SignersContainer::build(keymap, &descriptor, secp));
2385
    assert!(indexer
1,390✔
2386
        .insert_descriptor(KeychainKind::Internal, change_descriptor)
1,390✔
2387
        .map_err(|e| {
1,390✔
2388
            use bdk_chain::indexer::keychain_txout::InsertDescriptorError;
16✔
2389
            match e {
16✔
2390
                InsertDescriptorError::DescriptorAlreadyAssigned { .. } => {
2391
                    crate::descriptor::error::Error::ExternalAndInternalAreTheSame
16✔
2392
                }
2393
                InsertDescriptorError::KeychainAlreadyAssigned { .. } => {
2394
                    unreachable!("this is the first time we're assigning internal")
×
2395
                }
2396
            }
2397
        })?);
1,390✔
2398

2399
    Ok(indexer)
1,366✔
2400
}
1,382✔
2401

2402
/// Transforms a [`FeeRate`] to `f64` with unit as sat/vb.
2403
#[macro_export]
2404
#[doc(hidden)]
2405
macro_rules! floating_rate {
2406
    ($rate:expr) => {{
2407
        use $crate::bitcoin::constants::WITNESS_SCALE_FACTOR;
2408
        // sat_kwu / 250.0 -> sat_vb
2409
        $rate.to_sat_per_kwu() as f64 / ((1000 / WITNESS_SCALE_FACTOR) as f64)
2410
    }};
2411
}
2412

2413
#[macro_export]
2414
#[doc(hidden)]
2415
/// Macro for getting a wallet for use in a doctest
2416
macro_rules! doctest_wallet {
2417
    () => {{
2418
        use $crate::bitcoin::{BlockHash, Transaction, absolute, TxOut, Network, hashes::Hash};
2419
        use $crate::chain::{ConfirmationBlockTime, BlockId, TxGraph};
2420
        use $crate::{Update, KeychainKind, Wallet};
2421
        let descriptor = "tr([73c5da0a/86'/0'/0']tprv8fMn4hSKPRC1oaCPqxDb1JWtgkpeiQvZhsr8W2xuy3GEMkzoArcAWTfJxYb6Wj8XNNDWEjfYKK4wGQXh3ZUXhDF2NcnsALpWTeSwarJt7Vc/0/*)";
2422
        let change_descriptor = "tr([73c5da0a/86'/0'/0']tprv8fMn4hSKPRC1oaCPqxDb1JWtgkpeiQvZhsr8W2xuy3GEMkzoArcAWTfJxYb6Wj8XNNDWEjfYKK4wGQXh3ZUXhDF2NcnsALpWTeSwarJt7Vc/1/*)";
2423

2424
        let mut wallet = Wallet::create(descriptor, change_descriptor)
2425
            .network(Network::Regtest)
2426
            .create_wallet_no_persist()
2427
            .unwrap();
2428
        let address = wallet.peek_address(KeychainKind::External, 0).address;
2429
        let tx = Transaction {
2430
            version: transaction::Version::ONE,
2431
            lock_time: absolute::LockTime::ZERO,
2432
            input: vec![],
2433
            output: vec![TxOut {
2434
                value: Amount::from_sat(500_000),
2435
                script_pubkey: address.script_pubkey(),
2436
            }],
2437
        };
2438
        let txid = tx.txid();
2439
        let block_id = BlockId { height: 500, hash: BlockHash::all_zeros() };
2440
        let _ = wallet.insert_checkpoint(block_id);
2441
        let _ = wallet.insert_checkpoint(BlockId { height: 1_000, hash: BlockHash::all_zeros() });
2442
        let _ = wallet.insert_tx(tx);
2443
        let anchor = ConfirmationBlockTime {
2444
            confirmation_time: 50_000,
2445
            block_id,
2446
        };
2447
        let mut graph = TxGraph::default();
2448
        let _ = graph.insert_anchor(txid, anchor);
2449
        let update = Update { graph, ..Default::default() };
2450
        wallet.apply_update(update).unwrap();
2451
        wallet
2452
    }}
2453
}
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