From 2194abb5411bde125bf6de595446b1f220a24828 Mon Sep 17 00:00:00 2001 From: Antoine Poinsot Date: Mon, 27 Nov 2023 21:41:25 +0100 Subject: [PATCH 1/2] bdk: set a reasonable default lookahead when creating a wallet The wallet is currently created without setting any lookahead value for the keychain. This implicitly makes it a lookahead of 0. As this is a high-level interface we should avoid footguns and aim for a reasonable default. --- crates/bdk/src/wallet/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/bdk/src/wallet/mod.rs b/crates/bdk/src/wallet/mod.rs index 4f06876900..0dc1080938 100644 --- a/crates/bdk/src/wallet/mod.rs +++ b/crates/bdk/src/wallet/mod.rs @@ -75,6 +75,9 @@ use crate::wallet::error::{BuildFeeBumpError, CreateTxError, MiniscriptPsbtError const COINBASE_MATURITY: u32 = 100; +// The default "gap limit" for a wallet. +const DEFAULT_LOOKAHEAD: u32 = 1_000; + /// A Bitcoin wallet /// /// The `Wallet` struct acts as a way of coherently interfacing with output descriptors and related transactions. @@ -456,6 +459,7 @@ impl Wallet { let secp = Secp256k1::new(); let (chain, chain_changeset) = LocalChain::from_genesis_hash(genesis_hash); let mut index = KeychainTxOutIndex::::default(); + index.set_lookahead_for_all(DEFAULT_LOOKAHEAD); let (signers, change_signers) = create_signers(&mut index, &secp, descriptor, change_descriptor, network) From 9d3cb2b3e2907a9fefa5e5389d524daaa752aa99 Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Mon, 27 Nov 2023 21:02:39 -0800 Subject: [PATCH 2/2] fix(bdk): set a reasonable default lookahead when creating a wallet Added wallet test "test_get_funded_wallet_balance_for_nonzero_index" to test new DEFAULT_LOOKAHEAD. WIP: other tests still failing and need to be investigated. --- crates/bdk/src/wallet/mod.rs | 18 +++++++++++-- crates/bdk/tests/common.rs | 49 ++++++++++++++++++++++++++++++++++++ crates/bdk/tests/wallet.rs | 8 ++++++ 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/crates/bdk/src/wallet/mod.rs b/crates/bdk/src/wallet/mod.rs index 0dc1080938..89dc7f624a 100644 --- a/crates/bdk/src/wallet/mod.rs +++ b/crates/bdk/src/wallet/mod.rs @@ -459,13 +459,13 @@ impl Wallet { let secp = Secp256k1::new(); let (chain, chain_changeset) = LocalChain::from_genesis_hash(genesis_hash); let mut index = KeychainTxOutIndex::::default(); - index.set_lookahead_for_all(DEFAULT_LOOKAHEAD); let (signers, change_signers) = create_signers(&mut index, &secp, descriptor, change_descriptor, network) .map_err(NewError::Descriptor)?; - let indexed_graph = IndexedTxGraph::new(index); + let mut indexed_graph = IndexedTxGraph::new(index); + indexed_graph.index.set_lookahead_for_all(DEFAULT_LOOKAHEAD); let mut persist = Persist::new(db); persist.stage(ChangeSet { @@ -2312,6 +2312,20 @@ impl Wallet { &self.indexed_graph.index } + // /// Set's inner [`KeychainTxOutIndex`] look ahead count for all keychains. + // /// + // /// See [`KeychainTxOutIndex::set_lookahead_for_all`] for more details. + // pub fn set_spk_lookahead_for_all(&mut self, lookahead: u32) { + // self.indexed_graph.index.set_lookahead_for_all(lookahead); + // } + // + // /// Set's inner [`KeychainTxOutIndex`] look ahead count for the specified keychain. + // /// + // /// See [`KeychainTxOutIndex::set_lookahead`] for more details. + // pub fn set_lookahead(&mut self, keychain: &KeychainKind, lookahead: u32) { + // self.indexed_graph.index.set_lookahead(keychain, lookahead); + // } + /// Get a reference to the inner [`LocalChain`]. pub fn local_chain(&self) -> &LocalChain { &self.chain diff --git a/crates/bdk/tests/common.rs b/crates/bdk/tests/common.rs index 3e0292a299..9b48d07ef3 100644 --- a/crates/bdk/tests/common.rs +++ b/crates/bdk/tests/common.rs @@ -108,10 +108,59 @@ pub fn get_funded_wallet(descriptor: &str) -> (Wallet, bitcoin::Txid) { get_funded_wallet_with_change(descriptor, None) } +// Return a fake wallet that appears to have one UTXO sent at a specific address index. +// +// The funded wallet containing a tx with one 76_000 sats input. +pub fn get_funded_wallet_at_index(descriptor: &str, address_index: AddressIndex) -> (Wallet, Txid) { + let mut wallet = Wallet::new_no_persist(descriptor, None, Network::Regtest).unwrap(); + let utxo_address = wallet.get_address(address_index).address; + + let tx0 = Transaction { + version: 1, + lock_time: bitcoin::absolute::LockTime::ZERO, + input: vec![TxIn { + previous_output: OutPoint { + txid: Txid::all_zeros(), + vout: 0, + }, + script_sig: Default::default(), + sequence: Default::default(), + witness: Default::default(), + }], + output: vec![TxOut { + value: 76_000, + script_pubkey: utxo_address.script_pubkey(), + }], + }; + + wallet + .insert_checkpoint(BlockId { + height: 1_000, + hash: BlockHash::all_zeros(), + }) + .unwrap(); + + wallet + .insert_tx( + tx0.clone(), + ConfirmationTime::Confirmed { + height: 1_000, + time: 100, + }, + ) + .unwrap(); + + (wallet, tx0.txid()) +} + pub fn get_test_wpkh() -> &'static str { "wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)" } +pub fn get_test_wpkh_xprv() -> &'static str { + "wpkh(tprv8ZgxMBicQKsPdDArR4xSAECuVxeX1jwwSXR4ApKbkYgZiziDc4LdBy2WvJeGDfUSE4UT4hHhbgEwbdq8ajjUHiKDegkwrNU6V55CxcxonVN/*)" +} + pub fn get_test_single_sig_csv() -> &'static str { // and(pk(Alice),older(6)) "wsh(and_v(v:pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW),older(6)))" diff --git a/crates/bdk/tests/wallet.rs b/crates/bdk/tests/wallet.rs index 4fa399d862..a43b9781a9 100644 --- a/crates/bdk/tests/wallet.rs +++ b/crates/bdk/tests/wallet.rs @@ -188,6 +188,14 @@ fn test_get_funded_wallet_balance() { assert_eq!(wallet.get_balance().confirmed, 50_000); } +#[test] +fn test_get_funded_wallet_balance_for_nonzero_index() { + // The funded wallet contains a tx with a 76_000 sats outputs to spk at index 1 that is found + // with the default look ahead. + let (wallet, _) = get_funded_wallet_at_index(get_test_wpkh_xprv(), Peek(1)); + assert_eq!(wallet.get_balance().confirmed, 76_000); +} + #[test] fn test_get_funded_wallet_sent_and_received() { let (wallet, txid) = get_funded_wallet(get_test_wpkh());