Merge bitcoindevkit/bdk#1229: Use a universal lookahead value for KeychainTxOutIndex and have a reasonable default
				
					
				
			1def76f1f17fc876534c798883099c58de57c0fd chore: make clippy happy and bump clippy msrv (志宇) c9467dcbb27bd497006846dcfcefb0c2cf8823c4 chore: improve documentation of lookahead (LLFourn) bc796f412acdc3d2cd96f7aec0f24fa47c1fe889 fix(example): bitcoind_rpc_polling now initializes local_chain properly (志宇) 4fd539b6470f7f771e3b5e09e3287952fa7a1825 feat(chain)!: `KeychainTxOutIndex` uses a universal lookahead (Antoine Poinsot) Pull request description: ### Description The `bdk::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. To fix this, we have also decided to change `KeychainTxOutIndex` to have a default lookahead. Additionally, we have simplified the `KeychainTxOutIndex` API to have a single `lookahead` that is ONLY set at construction `KeychainTxOutIndex::new(lookahead: u32) -> Self`. This avoids the footguns of having methods which allows the caller to decrease the `lookahead` (which will panic). ### Notes to the reviewers ~A way to set this value externally is introduced in #1172. This PR only aims to use a saner default than 0. `1_000` is the value used by the Bitcoin Core wallet, and that seems reasonable to me.~ Edit: we should NOT allow setting the `lookahead` value after-the-fact. Instead, the `lookahead` should be provided to the wallet's constructor. @evanlinjin: I don't think additional tests are necessary as no additional features are added, and the surface area of the API is decreased. The original tests already thoroughly test the `lookahead` concept. ### Checklists #### All Submissions: *(This section was updated as this PR changed from being a simple setting to introducing a new method.)* * [x] I've signed all my commits * [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md) * [x] I ran `cargo fmt` and `cargo clippy` before committing ~* [ ] I've added tests~ * [x] I've added docs ACKs for top commit: LLFourn: ACK 1def76f1f17fc876534c798883099c58de57c0fd Tree-SHA512: b4c3be8a4f2ac4877cf3f05852147e7dd1daeb02d3bc40895f02fd2a58e584f1dc0735b524153ff0875380ac93c0b4c31e516873d7a9b0027fdbbb5fe7970ff2
This commit is contained in:
		
						commit
						7eff024213
					
				
							
								
								
									
										2
									
								
								.github/workflows/cont_integration.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/cont_integration.yml
									
									
									
									
										vendored
									
									
								
							@ -118,7 +118,7 @@ jobs:
 | 
				
			|||||||
      - uses: actions/checkout@v1
 | 
					      - uses: actions/checkout@v1
 | 
				
			||||||
      - uses: actions-rs/toolchain@v1
 | 
					      - uses: actions-rs/toolchain@v1
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
            toolchain: "stable"
 | 
					            toolchain: stable
 | 
				
			||||||
            components: clippy
 | 
					            components: clippy
 | 
				
			||||||
            override: true
 | 
					            override: true
 | 
				
			||||||
      - name: Rust Cache
 | 
					      - name: Rust Cache
 | 
				
			||||||
 | 
				
			|||||||
@ -1 +1 @@
 | 
				
			|||||||
msrv="1.57.0"
 | 
					msrv="1.63.0"
 | 
				
			||||||
 | 
				
			|||||||
@ -575,7 +575,7 @@ mod test {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if let ExtendedDescriptor::Pkh(pkh) = xdesc.0 {
 | 
					        if let ExtendedDescriptor::Pkh(pkh) = xdesc.0 {
 | 
				
			||||||
            let path: Vec<ChildNumber> = pkh.into_inner().full_derivation_path().unwrap().into();
 | 
					            let path: Vec<ChildNumber> = pkh.into_inner().full_derivation_path().unwrap().into();
 | 
				
			||||||
            let purpose = path.get(0).unwrap();
 | 
					            let purpose = path.first().unwrap();
 | 
				
			||||||
            assert_matches!(purpose, Hardened { index: 44 });
 | 
					            assert_matches!(purpose, Hardened { index: 44 });
 | 
				
			||||||
            let coin_type = path.get(1).unwrap();
 | 
					            let coin_type = path.get(1).unwrap();
 | 
				
			||||||
            assert_matches!(coin_type, Hardened { index: 0 });
 | 
					            assert_matches!(coin_type, Hardened { index: 0 });
 | 
				
			||||||
@ -589,7 +589,7 @@ mod test {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if let ExtendedDescriptor::Pkh(pkh) = tdesc.0 {
 | 
					        if let ExtendedDescriptor::Pkh(pkh) = tdesc.0 {
 | 
				
			||||||
            let path: Vec<ChildNumber> = pkh.into_inner().full_derivation_path().unwrap().into();
 | 
					            let path: Vec<ChildNumber> = pkh.into_inner().full_derivation_path().unwrap().into();
 | 
				
			||||||
            let purpose = path.get(0).unwrap();
 | 
					            let purpose = path.first().unwrap();
 | 
				
			||||||
            assert_matches!(purpose, Hardened { index: 44 });
 | 
					            assert_matches!(purpose, Hardened { index: 44 });
 | 
				
			||||||
            let coin_type = path.get(1).unwrap();
 | 
					            let coin_type = path.get(1).unwrap();
 | 
				
			||||||
            assert_matches!(coin_type, Hardened { index: 1 });
 | 
					            assert_matches!(coin_type, Hardened { index: 1 });
 | 
				
			||||||
 | 
				
			|||||||
@ -812,9 +812,10 @@ pub struct SignOptions {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Customize which taproot script-path leaves the signer should sign.
 | 
					/// Customize which taproot script-path leaves the signer should sign.
 | 
				
			||||||
#[derive(Debug, Clone, PartialEq, Eq)]
 | 
					#[derive(Default, Debug, Clone, PartialEq, Eq)]
 | 
				
			||||||
pub enum TapLeavesOptions {
 | 
					pub enum TapLeavesOptions {
 | 
				
			||||||
    /// The signer will sign all the leaves it has a key for.
 | 
					    /// The signer will sign all the leaves it has a key for.
 | 
				
			||||||
 | 
					    #[default]
 | 
				
			||||||
    All,
 | 
					    All,
 | 
				
			||||||
    /// The signer won't sign leaves other than the ones specified. Note that it could still ignore
 | 
					    /// The signer won't sign leaves other than the ones specified. Note that it could still ignore
 | 
				
			||||||
    /// some of the specified leaves, if it doesn't have the right key to sign them.
 | 
					    /// some of the specified leaves, if it doesn't have the right key to sign them.
 | 
				
			||||||
@ -825,12 +826,6 @@ pub enum TapLeavesOptions {
 | 
				
			|||||||
    None,
 | 
					    None,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Default for TapLeavesOptions {
 | 
					 | 
				
			||||||
    fn default() -> Self {
 | 
					 | 
				
			||||||
        TapLeavesOptions::All
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[allow(clippy::derivable_impls)]
 | 
					#[allow(clippy::derivable_impls)]
 | 
				
			||||||
impl Default for SignOptions {
 | 
					impl Default for SignOptions {
 | 
				
			||||||
    fn default() -> Self {
 | 
					    fn default() -> Self {
 | 
				
			||||||
 | 
				
			|||||||
@ -811,9 +811,10 @@ impl<'a, D> TxBuilder<'a, D, DefaultCoinSelectionAlgorithm, BumpFee> {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Ordering of the transaction's inputs and outputs
 | 
					/// Ordering of the transaction's inputs and outputs
 | 
				
			||||||
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)]
 | 
					#[derive(Default, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)]
 | 
				
			||||||
pub enum TxOrdering {
 | 
					pub enum TxOrdering {
 | 
				
			||||||
    /// Randomized (default)
 | 
					    /// Randomized (default)
 | 
				
			||||||
 | 
					    #[default]
 | 
				
			||||||
    Shuffle,
 | 
					    Shuffle,
 | 
				
			||||||
    /// Unchanged
 | 
					    /// Unchanged
 | 
				
			||||||
    Untouched,
 | 
					    Untouched,
 | 
				
			||||||
@ -821,12 +822,6 @@ pub enum TxOrdering {
 | 
				
			|||||||
    Bip69Lexicographic,
 | 
					    Bip69Lexicographic,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Default for TxOrdering {
 | 
					 | 
				
			||||||
    fn default() -> Self {
 | 
					 | 
				
			||||||
        TxOrdering::Shuffle
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl TxOrdering {
 | 
					impl TxOrdering {
 | 
				
			||||||
    /// Sort transaction inputs and outputs by [`TxOrdering`] variant
 | 
					    /// Sort transaction inputs and outputs by [`TxOrdering`] variant
 | 
				
			||||||
    pub fn sort_tx(&self, tx: &mut Transaction) {
 | 
					    pub fn sort_tx(&self, tx: &mut Transaction) {
 | 
				
			||||||
@ -880,9 +875,10 @@ impl RbfValue {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Policy regarding the use of change outputs when creating a transaction
 | 
					/// Policy regarding the use of change outputs when creating a transaction
 | 
				
			||||||
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)]
 | 
					#[derive(Default, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)]
 | 
				
			||||||
pub enum ChangeSpendPolicy {
 | 
					pub enum ChangeSpendPolicy {
 | 
				
			||||||
    /// Use both change and non-change outputs (default)
 | 
					    /// Use both change and non-change outputs (default)
 | 
				
			||||||
 | 
					    #[default]
 | 
				
			||||||
    ChangeAllowed,
 | 
					    ChangeAllowed,
 | 
				
			||||||
    /// Only use change outputs (see [`TxBuilder::only_spend_change`])
 | 
					    /// Only use change outputs (see [`TxBuilder::only_spend_change`])
 | 
				
			||||||
    OnlyChange,
 | 
					    OnlyChange,
 | 
				
			||||||
@ -890,12 +886,6 @@ pub enum ChangeSpendPolicy {
 | 
				
			|||||||
    ChangeForbidden,
 | 
					    ChangeForbidden,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Default for ChangeSpendPolicy {
 | 
					 | 
				
			||||||
    fn default() -> Self {
 | 
					 | 
				
			||||||
        ChangeSpendPolicy::ChangeAllowed
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl ChangeSpendPolicy {
 | 
					impl ChangeSpendPolicy {
 | 
				
			||||||
    pub(crate) fn is_satisfied_by(&self, utxo: &LocalOutput) -> bool {
 | 
					    pub(crate) fn is_satisfied_by(&self, utxo: &LocalOutput) -> bool {
 | 
				
			||||||
        match self {
 | 
					        match self {
 | 
				
			||||||
 | 
				
			|||||||
@ -5,12 +5,13 @@ use crate::{
 | 
				
			|||||||
    spk_iter::BIP32_MAX_INDEX,
 | 
					    spk_iter::BIP32_MAX_INDEX,
 | 
				
			||||||
    SpkIterator, SpkTxOutIndex,
 | 
					    SpkIterator, SpkTxOutIndex,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use alloc::vec::Vec;
 | 
					 | 
				
			||||||
use bitcoin::{OutPoint, Script, TxOut};
 | 
					use bitcoin::{OutPoint, Script, TxOut};
 | 
				
			||||||
use core::{fmt::Debug, ops::Deref};
 | 
					use core::{fmt::Debug, ops::Deref};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::Append;
 | 
					use crate::Append;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const DEFAULT_LOOKAHEAD: u32 = 1_000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A convenient wrapper around [`SpkTxOutIndex`] that relates script pubkeys to miniscript public
 | 
					/// A convenient wrapper around [`SpkTxOutIndex`] that relates script pubkeys to miniscript public
 | 
				
			||||||
/// [`Descriptor`]s.
 | 
					/// [`Descriptor`]s.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
@ -46,7 +47,7 @@ use crate::Append;
 | 
				
			|||||||
/// # let secp = bdk_chain::bitcoin::secp256k1::Secp256k1::signing_only();
 | 
					/// # let secp = bdk_chain::bitcoin::secp256k1::Secp256k1::signing_only();
 | 
				
			||||||
/// # let (external_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/0/*)").unwrap();
 | 
					/// # let (external_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/0/*)").unwrap();
 | 
				
			||||||
/// # let (internal_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/1/*)").unwrap();
 | 
					/// # let (internal_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/1/*)").unwrap();
 | 
				
			||||||
/// # let descriptor_for_user_42 = external_descriptor.clone();
 | 
					/// # let (descriptor_for_user_42, _) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/2/*)").unwrap();
 | 
				
			||||||
/// txout_index.add_keychain(MyKeychain::External, external_descriptor);
 | 
					/// txout_index.add_keychain(MyKeychain::External, external_descriptor);
 | 
				
			||||||
/// txout_index.add_keychain(MyKeychain::Internal, internal_descriptor);
 | 
					/// txout_index.add_keychain(MyKeychain::Internal, internal_descriptor);
 | 
				
			||||||
/// txout_index.add_keychain(MyKeychain::MyAppUser { user_id: 42 }, descriptor_for_user_42);
 | 
					/// txout_index.add_keychain(MyKeychain::MyAppUser { user_id: 42 }, descriptor_for_user_42);
 | 
				
			||||||
@ -65,17 +66,12 @@ pub struct KeychainTxOutIndex<K> {
 | 
				
			|||||||
    // last revealed indexes
 | 
					    // last revealed indexes
 | 
				
			||||||
    last_revealed: BTreeMap<K, u32>,
 | 
					    last_revealed: BTreeMap<K, u32>,
 | 
				
			||||||
    // lookahead settings for each keychain
 | 
					    // lookahead settings for each keychain
 | 
				
			||||||
    lookahead: BTreeMap<K, u32>,
 | 
					    lookahead: u32,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<K> Default for KeychainTxOutIndex<K> {
 | 
					impl<K> Default for KeychainTxOutIndex<K> {
 | 
				
			||||||
    fn default() -> Self {
 | 
					    fn default() -> Self {
 | 
				
			||||||
        Self {
 | 
					        Self::new(DEFAULT_LOOKAHEAD)
 | 
				
			||||||
            inner: SpkTxOutIndex::default(),
 | 
					 | 
				
			||||||
            keychains: BTreeMap::default(),
 | 
					 | 
				
			||||||
            last_revealed: BTreeMap::default(),
 | 
					 | 
				
			||||||
            lookahead: BTreeMap::default(),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -118,6 +114,25 @@ impl<K: Clone + Ord + Debug> Indexer for KeychainTxOutIndex<K> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<K> KeychainTxOutIndex<K> {
 | 
				
			||||||
 | 
					    /// Construct a [`KeychainTxOutIndex`] with the given `lookahead`.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// The `lookahead` is the number of script pubkeys to derive and cache from the internal
 | 
				
			||||||
 | 
					    /// descriptors over and above the last revealed script index. Without a lookahead the index
 | 
				
			||||||
 | 
					    /// will miss outputs you own when processing transactions whose output script pubkeys lie
 | 
				
			||||||
 | 
					    /// beyond the last revealed index. In certain situations, such as when performing an initial
 | 
				
			||||||
 | 
					    /// scan of the blockchain during wallet import, it may be uncertain or unknown what the index
 | 
				
			||||||
 | 
					    /// of the last revealed script pubkey actually is.
 | 
				
			||||||
 | 
					    pub fn new(lookahead: u32) -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            inner: SpkTxOutIndex::default(),
 | 
				
			||||||
 | 
					            keychains: BTreeMap::new(),
 | 
				
			||||||
 | 
					            last_revealed: BTreeMap::new(),
 | 
				
			||||||
 | 
					            lookahead,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
 | 
					impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
 | 
				
			||||||
    /// Return a reference to the internal [`SpkTxOutIndex`].
 | 
					    /// Return a reference to the internal [`SpkTxOutIndex`].
 | 
				
			||||||
    pub fn inner(&self) -> &SpkTxOutIndex<(K, u32)> {
 | 
					    pub fn inner(&self) -> &SpkTxOutIndex<(K, u32)> {
 | 
				
			||||||
@ -145,54 +160,22 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
 | 
				
			|||||||
    pub fn add_keychain(&mut self, keychain: K, descriptor: Descriptor<DescriptorPublicKey>) {
 | 
					    pub fn add_keychain(&mut self, keychain: K, descriptor: Descriptor<DescriptorPublicKey>) {
 | 
				
			||||||
        let old_descriptor = &*self
 | 
					        let old_descriptor = &*self
 | 
				
			||||||
            .keychains
 | 
					            .keychains
 | 
				
			||||||
            .entry(keychain)
 | 
					            .entry(keychain.clone())
 | 
				
			||||||
            .or_insert_with(|| descriptor.clone());
 | 
					            .or_insert_with(|| descriptor.clone());
 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
            &descriptor, old_descriptor,
 | 
					            &descriptor, old_descriptor,
 | 
				
			||||||
            "keychain already contains a different descriptor"
 | 
					            "keychain already contains a different descriptor"
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					        self.replenish_lookahead(&keychain, self.lookahead);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Return the lookahead setting for each keychain.
 | 
					    /// Get the lookahead setting.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// Refer to [`set_lookahead`] for a deeper explanation of the `lookahead`.
 | 
					    /// Refer to [`new`] for more information on the `lookahead`.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// [`set_lookahead`]: Self::set_lookahead
 | 
					    /// [`new`]: Self::new
 | 
				
			||||||
    pub fn lookaheads(&self) -> &BTreeMap<K, u32> {
 | 
					    pub fn lookahead(&self) -> u32 {
 | 
				
			||||||
        &self.lookahead
 | 
					        self.lookahead
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Convenience method to call [`set_lookahead`] for all keychains.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// [`set_lookahead`]: Self::set_lookahead
 | 
					 | 
				
			||||||
    pub fn set_lookahead_for_all(&mut self, lookahead: u32) {
 | 
					 | 
				
			||||||
        for keychain in &self.keychains.keys().cloned().collect::<Vec<_>>() {
 | 
					 | 
				
			||||||
            self.set_lookahead(keychain, lookahead);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Set the lookahead count for `keychain`.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// The lookahead is the number of scripts to cache ahead of the last revealed script index. This
 | 
					 | 
				
			||||||
    /// is useful to find outputs you own when processing block data that lie beyond the last revealed
 | 
					 | 
				
			||||||
    /// index. In certain situations, such as when performing an initial scan of the blockchain during
 | 
					 | 
				
			||||||
    /// wallet import, it may be uncertain or unknown what the last revealed index is.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// # Panics
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// This will panic if the `keychain` does not exist.
 | 
					 | 
				
			||||||
    pub fn set_lookahead(&mut self, keychain: &K, lookahead: u32) {
 | 
					 | 
				
			||||||
        self.lookahead.insert(keychain.clone(), lookahead);
 | 
					 | 
				
			||||||
        self.replenish_lookahead(keychain);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Convenience method to call [`lookahead_to_target`] for multiple keychains.
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// [`lookahead_to_target`]: Self::lookahead_to_target
 | 
					 | 
				
			||||||
    pub fn lookahead_to_target_multi(&mut self, target_indexes: BTreeMap<K, u32>) {
 | 
					 | 
				
			||||||
        for (keychain, target_index) in target_indexes {
 | 
					 | 
				
			||||||
            self.lookahead_to_target(&keychain, target_index)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Store lookahead scripts until `target_index`.
 | 
					    /// Store lookahead scripts until `target_index`.
 | 
				
			||||||
@ -201,22 +184,14 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
 | 
				
			|||||||
    pub fn lookahead_to_target(&mut self, keychain: &K, target_index: u32) {
 | 
					    pub fn lookahead_to_target(&mut self, keychain: &K, target_index: u32) {
 | 
				
			||||||
        let next_index = self.next_store_index(keychain);
 | 
					        let next_index = self.next_store_index(keychain);
 | 
				
			||||||
        if let Some(temp_lookahead) = target_index.checked_sub(next_index).filter(|&v| v > 0) {
 | 
					        if let Some(temp_lookahead) = target_index.checked_sub(next_index).filter(|&v| v > 0) {
 | 
				
			||||||
            let old_lookahead = self.lookahead.insert(keychain.clone(), temp_lookahead);
 | 
					            self.replenish_lookahead(keychain, temp_lookahead);
 | 
				
			||||||
            self.replenish_lookahead(keychain);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // revert
 | 
					 | 
				
			||||||
            match old_lookahead {
 | 
					 | 
				
			||||||
                Some(lookahead) => self.lookahead.insert(keychain.clone(), lookahead),
 | 
					 | 
				
			||||||
                None => self.lookahead.remove(keychain),
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn replenish_lookahead(&mut self, keychain: &K) {
 | 
					    fn replenish_lookahead(&mut self, keychain: &K, lookahead: u32) {
 | 
				
			||||||
        let descriptor = self.keychains.get(keychain).expect("keychain must exist");
 | 
					        let descriptor = self.keychains.get(keychain).expect("keychain must exist");
 | 
				
			||||||
        let next_store_index = self.next_store_index(keychain);
 | 
					        let next_store_index = self.next_store_index(keychain);
 | 
				
			||||||
        let next_reveal_index = self.last_revealed.get(keychain).map_or(0, |v| *v + 1);
 | 
					        let next_reveal_index = self.last_revealed.get(keychain).map_or(0, |v| *v + 1);
 | 
				
			||||||
        let lookahead = self.lookahead.get(keychain).map_or(0, |v| *v);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (new_index, new_spk) in
 | 
					        for (new_index, new_spk) in
 | 
				
			||||||
            SpkIterator::new_with_range(descriptor, next_store_index..next_reveal_index + lookahead)
 | 
					            SpkIterator::new_with_range(descriptor, next_store_index..next_reveal_index + lookahead)
 | 
				
			||||||
@ -388,12 +363,8 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        let target_index = if has_wildcard { target_index } else { 0 };
 | 
					        let target_index = if has_wildcard { target_index } else { 0 };
 | 
				
			||||||
        let next_reveal_index = self.last_revealed.get(keychain).map_or(0, |v| *v + 1);
 | 
					        let next_reveal_index = self.last_revealed.get(keychain).map_or(0, |v| *v + 1);
 | 
				
			||||||
        let lookahead = self.lookahead.get(keychain).map_or(0, |v| *v);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        debug_assert_eq!(
 | 
					        debug_assert!(next_reveal_index + self.lookahead >= self.next_store_index(keychain));
 | 
				
			||||||
            next_reveal_index + lookahead,
 | 
					 | 
				
			||||||
            self.next_store_index(keychain)
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // if we need to reveal new indices, the latest revealed index goes here
 | 
					        // if we need to reveal new indices, the latest revealed index goes here
 | 
				
			||||||
        let mut reveal_to_index = None;
 | 
					        let mut reveal_to_index = None;
 | 
				
			||||||
@ -401,12 +372,12 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
 | 
				
			|||||||
        // if the target is not yet revealed, but is already stored (due to lookahead), we need to
 | 
					        // if the target is not yet revealed, but is already stored (due to lookahead), we need to
 | 
				
			||||||
        // set the `reveal_to_index` as target here (as the `for` loop below only updates
 | 
					        // set the `reveal_to_index` as target here (as the `for` loop below only updates
 | 
				
			||||||
        // `reveal_to_index` for indexes that are NOT stored)
 | 
					        // `reveal_to_index` for indexes that are NOT stored)
 | 
				
			||||||
        if next_reveal_index <= target_index && target_index < next_reveal_index + lookahead {
 | 
					        if next_reveal_index <= target_index && target_index < next_reveal_index + self.lookahead {
 | 
				
			||||||
            reveal_to_index = Some(target_index);
 | 
					            reveal_to_index = Some(target_index);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // we range over indexes that are not stored
 | 
					        // we range over indexes that are not stored
 | 
				
			||||||
        let range = next_reveal_index + lookahead..=target_index + lookahead;
 | 
					        let range = next_reveal_index + self.lookahead..=target_index + self.lookahead;
 | 
				
			||||||
        for (new_index, new_spk) in SpkIterator::new_with_range(descriptor, range) {
 | 
					        for (new_index, new_spk) in SpkIterator::new_with_range(descriptor, range) {
 | 
				
			||||||
            let _inserted = self
 | 
					            let _inserted = self
 | 
				
			||||||
                .inner
 | 
					                .inner
 | 
				
			||||||
 | 
				
			|||||||
@ -148,7 +148,7 @@ mod test {
 | 
				
			|||||||
        Descriptor<DescriptorPublicKey>,
 | 
					        Descriptor<DescriptorPublicKey>,
 | 
				
			||||||
        Descriptor<DescriptorPublicKey>,
 | 
					        Descriptor<DescriptorPublicKey>,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        let mut txout_index = KeychainTxOutIndex::<TestKeychain>::default();
 | 
					        let mut txout_index = KeychainTxOutIndex::<TestKeychain>::new(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let secp = Secp256k1::signing_only();
 | 
					        let secp = Secp256k1::signing_only();
 | 
				
			||||||
        let (external_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/0/*)").unwrap();
 | 
					        let (external_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/0/*)").unwrap();
 | 
				
			||||||
 | 
				
			|||||||
@ -168,9 +168,7 @@ impl<I: Clone + Ord> SpkTxOutIndex<I> {
 | 
				
			|||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// Returns `None` if the `TxOut` hasn't been scanned or if nothing matching was found there.
 | 
					    /// Returns `None` if the `TxOut` hasn't been scanned or if nothing matching was found there.
 | 
				
			||||||
    pub fn txout(&self, outpoint: OutPoint) -> Option<(&I, &TxOut)> {
 | 
					    pub fn txout(&self, outpoint: OutPoint) -> Option<(&I, &TxOut)> {
 | 
				
			||||||
        self.txouts
 | 
					        self.txouts.get(&outpoint).map(|v| (&v.0, &v.1))
 | 
				
			||||||
            .get(&outpoint)
 | 
					 | 
				
			||||||
            .map(|(spk_i, txout)| (spk_i, txout))
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Returns the script that has been inserted at the `index`.
 | 
					    /// Returns the script that has been inserted at the `index`.
 | 
				
			||||||
 | 
				
			|||||||
@ -581,10 +581,7 @@ impl<A: Clone + Ord> TxGraph<A> {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (outpoint, txout) in changeset.txouts {
 | 
					        for (outpoint, txout) in changeset.txouts {
 | 
				
			||||||
            let tx_entry = self
 | 
					            let tx_entry = self.txs.entry(outpoint.txid).or_default();
 | 
				
			||||||
                .txs
 | 
					 | 
				
			||||||
                .entry(outpoint.txid)
 | 
					 | 
				
			||||||
                .or_insert_with(Default::default);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            match tx_entry {
 | 
					            match tx_entry {
 | 
				
			||||||
                (TxNodeInternal::Whole(_), _, _) => { /* do nothing since we already have full tx */
 | 
					                (TxNodeInternal::Whole(_), _, _) => { /* do nothing since we already have full tx */
 | 
				
			||||||
@ -597,13 +594,13 @@ impl<A: Clone + Ord> TxGraph<A> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        for (anchor, txid) in changeset.anchors {
 | 
					        for (anchor, txid) in changeset.anchors {
 | 
				
			||||||
            if self.anchors.insert((anchor.clone(), txid)) {
 | 
					            if self.anchors.insert((anchor.clone(), txid)) {
 | 
				
			||||||
                let (_, anchors, _) = self.txs.entry(txid).or_insert_with(Default::default);
 | 
					                let (_, anchors, _) = self.txs.entry(txid).or_default();
 | 
				
			||||||
                anchors.insert(anchor);
 | 
					                anchors.insert(anchor);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (txid, new_last_seen) in changeset.last_seen {
 | 
					        for (txid, new_last_seen) in changeset.last_seen {
 | 
				
			||||||
            let (_, _, last_seen) = self.txs.entry(txid).or_insert_with(Default::default);
 | 
					            let (_, _, last_seen) = self.txs.entry(txid).or_default();
 | 
				
			||||||
            if new_last_seen > *last_seen {
 | 
					            if new_last_seen > *last_seen {
 | 
				
			||||||
                *last_seen = new_last_seen;
 | 
					                *last_seen = new_last_seen;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,5 @@
 | 
				
			|||||||
mod tx_template;
 | 
					mod tx_template;
 | 
				
			||||||
 | 
					#[allow(unused_imports)]
 | 
				
			||||||
pub use tx_template::*;
 | 
					pub use tx_template::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[allow(unused_macros)]
 | 
					#[allow(unused_macros)]
 | 
				
			||||||
 | 
				
			|||||||
@ -27,9 +27,10 @@ fn insert_relevant_txs() {
 | 
				
			|||||||
    let spk_0 = descriptor.at_derivation_index(0).unwrap().script_pubkey();
 | 
					    let spk_0 = descriptor.at_derivation_index(0).unwrap().script_pubkey();
 | 
				
			||||||
    let spk_1 = descriptor.at_derivation_index(9).unwrap().script_pubkey();
 | 
					    let spk_1 = descriptor.at_derivation_index(9).unwrap().script_pubkey();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut graph = IndexedTxGraph::<ConfirmationHeightAnchor, KeychainTxOutIndex<()>>::default();
 | 
					    let mut graph = IndexedTxGraph::<ConfirmationHeightAnchor, KeychainTxOutIndex<()>>::new(
 | 
				
			||||||
 | 
					        KeychainTxOutIndex::new(10),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
    graph.index.add_keychain((), descriptor);
 | 
					    graph.index.add_keychain((), descriptor);
 | 
				
			||||||
    graph.index.set_lookahead(&(), 10);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let tx_a = Transaction {
 | 
					    let tx_a = Transaction {
 | 
				
			||||||
        output: vec![
 | 
					        output: vec![
 | 
				
			||||||
@ -118,12 +119,12 @@ fn test_list_owned_txouts() {
 | 
				
			|||||||
    let (desc_1, _) = Descriptor::parse_descriptor(&Secp256k1::signing_only(), "tr(tprv8ZgxMBicQKsPd3krDUsBAmtnRsK3rb8u5yi1zhQgMhF1tR8MW7xfE4rnrbbsrbPR52e7rKapu6ztw1jXveJSCGHEriUGZV7mCe88duLp5pj/86'/1'/0'/0/*)").unwrap();
 | 
					    let (desc_1, _) = Descriptor::parse_descriptor(&Secp256k1::signing_only(), "tr(tprv8ZgxMBicQKsPd3krDUsBAmtnRsK3rb8u5yi1zhQgMhF1tR8MW7xfE4rnrbbsrbPR52e7rKapu6ztw1jXveJSCGHEriUGZV7mCe88duLp5pj/86'/1'/0'/0/*)").unwrap();
 | 
				
			||||||
    let (desc_2, _) = Descriptor::parse_descriptor(&Secp256k1::signing_only(), "tr(tprv8ZgxMBicQKsPd3krDUsBAmtnRsK3rb8u5yi1zhQgMhF1tR8MW7xfE4rnrbbsrbPR52e7rKapu6ztw1jXveJSCGHEriUGZV7mCe88duLp5pj/86'/1'/0'/1/*)").unwrap();
 | 
					    let (desc_2, _) = Descriptor::parse_descriptor(&Secp256k1::signing_only(), "tr(tprv8ZgxMBicQKsPd3krDUsBAmtnRsK3rb8u5yi1zhQgMhF1tR8MW7xfE4rnrbbsrbPR52e7rKapu6ztw1jXveJSCGHEriUGZV7mCe88duLp5pj/86'/1'/0'/1/*)").unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut graph =
 | 
					    let mut graph = IndexedTxGraph::<ConfirmationHeightAnchor, KeychainTxOutIndex<String>>::new(
 | 
				
			||||||
        IndexedTxGraph::<ConfirmationHeightAnchor, KeychainTxOutIndex<String>>::default();
 | 
					        KeychainTxOutIndex::new(10),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    graph.index.add_keychain("keychain_1".into(), desc_1);
 | 
					    graph.index.add_keychain("keychain_1".into(), desc_1);
 | 
				
			||||||
    graph.index.add_keychain("keychain_2".into(), desc_2);
 | 
					    graph.index.add_keychain("keychain_2".into(), desc_2);
 | 
				
			||||||
    graph.index.set_lookahead_for_all(10);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Get trusted and untrusted addresses
 | 
					    // Get trusted and untrusted addresses
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -18,12 +18,14 @@ enum TestKeychain {
 | 
				
			|||||||
    Internal,
 | 
					    Internal,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn init_txout_index() -> (
 | 
					fn init_txout_index(
 | 
				
			||||||
 | 
					    lookahead: u32,
 | 
				
			||||||
 | 
					) -> (
 | 
				
			||||||
    bdk_chain::keychain::KeychainTxOutIndex<TestKeychain>,
 | 
					    bdk_chain::keychain::KeychainTxOutIndex<TestKeychain>,
 | 
				
			||||||
    Descriptor<DescriptorPublicKey>,
 | 
					    Descriptor<DescriptorPublicKey>,
 | 
				
			||||||
    Descriptor<DescriptorPublicKey>,
 | 
					    Descriptor<DescriptorPublicKey>,
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    let mut txout_index = bdk_chain::keychain::KeychainTxOutIndex::<TestKeychain>::default();
 | 
					    let mut txout_index = bdk_chain::keychain::KeychainTxOutIndex::<TestKeychain>::new(lookahead);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let secp = bdk_chain::bitcoin::secp256k1::Secp256k1::signing_only();
 | 
					    let secp = bdk_chain::bitcoin::secp256k1::Secp256k1::signing_only();
 | 
				
			||||||
    let (external_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/0/*)").unwrap();
 | 
					    let (external_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/0/*)").unwrap();
 | 
				
			||||||
@ -46,7 +48,7 @@ fn spk_at_index(descriptor: &Descriptor<DescriptorPublicKey>, index: u32) -> Scr
 | 
				
			|||||||
fn test_set_all_derivation_indices() {
 | 
					fn test_set_all_derivation_indices() {
 | 
				
			||||||
    use bdk_chain::indexed_tx_graph::Indexer;
 | 
					    use bdk_chain::indexed_tx_graph::Indexer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let (mut txout_index, _, _) = init_txout_index();
 | 
					    let (mut txout_index, _, _) = init_txout_index(0);
 | 
				
			||||||
    let derive_to: BTreeMap<_, _> =
 | 
					    let derive_to: BTreeMap<_, _> =
 | 
				
			||||||
        [(TestKeychain::External, 12), (TestKeychain::Internal, 24)].into();
 | 
					        [(TestKeychain::External, 12), (TestKeychain::Internal, 24)].into();
 | 
				
			||||||
    assert_eq!(
 | 
					    assert_eq!(
 | 
				
			||||||
@ -64,19 +66,10 @@ fn test_set_all_derivation_indices() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[test]
 | 
					#[test]
 | 
				
			||||||
fn test_lookahead() {
 | 
					fn test_lookahead() {
 | 
				
			||||||
    let (mut txout_index, external_desc, internal_desc) = init_txout_index();
 | 
					    let (mut txout_index, external_desc, internal_desc) = init_txout_index(10);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    // ensure it does not break anything if lookahead is set multiple times
 | 
					 | 
				
			||||||
    (0..=10).for_each(|lookahead| txout_index.set_lookahead(&TestKeychain::External, lookahead));
 | 
					 | 
				
			||||||
    (0..=20)
 | 
					 | 
				
			||||||
        .filter(|v| v % 2 == 0)
 | 
					 | 
				
			||||||
        .for_each(|lookahead| txout_index.set_lookahead(&TestKeychain::Internal, lookahead));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    assert_eq!(txout_index.inner().all_spks().len(), 30);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // given:
 | 
					    // given:
 | 
				
			||||||
    // - external lookahead set to 10
 | 
					    // - external lookahead set to 10
 | 
				
			||||||
    // - internal lookahead set to 20
 | 
					 | 
				
			||||||
    // when:
 | 
					    // when:
 | 
				
			||||||
    // - set external derivation index to value higher than last, but within the lookahead value
 | 
					    // - set external derivation index to value higher than last, but within the lookahead value
 | 
				
			||||||
    // expect:
 | 
					    // expect:
 | 
				
			||||||
@ -97,7 +90,7 @@ fn test_lookahead() {
 | 
				
			|||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
            txout_index.inner().all_spks().len(),
 | 
					            txout_index.inner().all_spks().len(),
 | 
				
			||||||
            10 /* external lookahead */ +
 | 
					            10 /* external lookahead */ +
 | 
				
			||||||
            20 /* internal lookahead */ +
 | 
					            10 /* internal lookahead */ +
 | 
				
			||||||
            index as usize + 1 /* `derived` count */
 | 
					            index as usize + 1 /* `derived` count */
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
@ -127,7 +120,7 @@ fn test_lookahead() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // given:
 | 
					    // given:
 | 
				
			||||||
    // - internal lookahead is 20
 | 
					    // - internal lookahead is 10
 | 
				
			||||||
    // - internal derivation index is `None`
 | 
					    // - internal derivation index is `None`
 | 
				
			||||||
    // when:
 | 
					    // when:
 | 
				
			||||||
    // - derivation index is set ahead of current derivation index + lookahead
 | 
					    // - derivation index is set ahead of current derivation index + lookahead
 | 
				
			||||||
@ -148,7 +141,7 @@ fn test_lookahead() {
 | 
				
			|||||||
    assert_eq!(
 | 
					    assert_eq!(
 | 
				
			||||||
        txout_index.inner().all_spks().len(),
 | 
					        txout_index.inner().all_spks().len(),
 | 
				
			||||||
        10 /* external lookahead */ +
 | 
					        10 /* external lookahead */ +
 | 
				
			||||||
        20 /* internal lookahead */ +
 | 
					        10 /* internal lookahead */ +
 | 
				
			||||||
        20 /* external stored index count */ +
 | 
					        20 /* external stored index count */ +
 | 
				
			||||||
        25 /* internal stored index count */
 | 
					        25 /* internal stored index count */
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
@ -226,8 +219,7 @@ fn test_lookahead() {
 | 
				
			|||||||
// - last used index should change as expected
 | 
					// - last used index should change as expected
 | 
				
			||||||
#[test]
 | 
					#[test]
 | 
				
			||||||
fn test_scan_with_lookahead() {
 | 
					fn test_scan_with_lookahead() {
 | 
				
			||||||
    let (mut txout_index, external_desc, _) = init_txout_index();
 | 
					    let (mut txout_index, external_desc, _) = init_txout_index(10);
 | 
				
			||||||
    txout_index.set_lookahead_for_all(10);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let spks: BTreeMap<u32, ScriptBuf> = [0, 10, 20, 30]
 | 
					    let spks: BTreeMap<u32, ScriptBuf> = [0, 10, 20, 30]
 | 
				
			||||||
        .into_iter()
 | 
					        .into_iter()
 | 
				
			||||||
@ -281,7 +273,7 @@ fn test_scan_with_lookahead() {
 | 
				
			|||||||
#[test]
 | 
					#[test]
 | 
				
			||||||
#[rustfmt::skip]
 | 
					#[rustfmt::skip]
 | 
				
			||||||
fn test_wildcard_derivations() {
 | 
					fn test_wildcard_derivations() {
 | 
				
			||||||
    let (mut txout_index, external_desc, _) = init_txout_index();
 | 
					    let (mut txout_index, external_desc, _) = init_txout_index(0);
 | 
				
			||||||
    let external_spk_0 = external_desc.at_derivation_index(0).unwrap().script_pubkey();
 | 
					    let external_spk_0 = external_desc.at_derivation_index(0).unwrap().script_pubkey();
 | 
				
			||||||
    let external_spk_16 = external_desc.at_derivation_index(16).unwrap().script_pubkey();
 | 
					    let external_spk_16 = external_desc.at_derivation_index(16).unwrap().script_pubkey();
 | 
				
			||||||
    let external_spk_26 = external_desc.at_derivation_index(26).unwrap().script_pubkey();
 | 
					    let external_spk_26 = external_desc.at_derivation_index(26).unwrap().script_pubkey();
 | 
				
			||||||
@ -339,7 +331,7 @@ fn test_wildcard_derivations() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[test]
 | 
					#[test]
 | 
				
			||||||
fn test_non_wildcard_derivations() {
 | 
					fn test_non_wildcard_derivations() {
 | 
				
			||||||
    let mut txout_index = KeychainTxOutIndex::<TestKeychain>::default();
 | 
					    let mut txout_index = KeychainTxOutIndex::<TestKeychain>::new(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let secp = bitcoin::secp256k1::Secp256k1::signing_only();
 | 
					    let secp = bitcoin::secp256k1::Secp256k1::signing_only();
 | 
				
			||||||
    let (no_wildcard_descriptor, _) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "wpkh([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/1/0)").unwrap();
 | 
					    let (no_wildcard_descriptor, _) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "wpkh([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/1/0)").unwrap();
 | 
				
			||||||
 | 
				
			|||||||
@ -477,7 +477,7 @@ fn populate_with_txids(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        let spk = tx
 | 
					        let spk = tx
 | 
				
			||||||
            .output
 | 
					            .output
 | 
				
			||||||
            .get(0)
 | 
					            .first()
 | 
				
			||||||
            .map(|txo| &txo.script_pubkey)
 | 
					            .map(|txo| &txo.script_pubkey)
 | 
				
			||||||
            .expect("tx must have an output");
 | 
					            .expect("tx must have an output");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -12,7 +12,7 @@ use bdk_bitcoind_rpc::{
 | 
				
			|||||||
    Emitter,
 | 
					    Emitter,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use bdk_chain::{
 | 
					use bdk_chain::{
 | 
				
			||||||
    bitcoin::{Block, Transaction},
 | 
					    bitcoin::{constants::genesis_block, Block, Transaction},
 | 
				
			||||||
    indexed_tx_graph, keychain,
 | 
					    indexed_tx_graph, keychain,
 | 
				
			||||||
    local_chain::{self, CheckPoint, LocalChain},
 | 
					    local_chain::{self, CheckPoint, LocalChain},
 | 
				
			||||||
    ConfirmationTimeHeightAnchor, IndexedTxGraph,
 | 
					    ConfirmationTimeHeightAnchor, IndexedTxGraph,
 | 
				
			||||||
@ -64,9 +64,6 @@ struct RpcArgs {
 | 
				
			|||||||
    /// Starting block height to fallback to if no point of agreement if found
 | 
					    /// Starting block height to fallback to if no point of agreement if found
 | 
				
			||||||
    #[clap(env = "FALLBACK_HEIGHT", long, default_value = "0")]
 | 
					    #[clap(env = "FALLBACK_HEIGHT", long, default_value = "0")]
 | 
				
			||||||
    fallback_height: u32,
 | 
					    fallback_height: u32,
 | 
				
			||||||
    /// The unused-scripts lookahead will be kept at this size
 | 
					 | 
				
			||||||
    #[clap(long, default_value = "10")]
 | 
					 | 
				
			||||||
    lookahead: u32,
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl From<RpcArgs> for Auth {
 | 
					impl From<RpcArgs> for Auth {
 | 
				
			||||||
@ -120,10 +117,11 @@ fn main() -> anyhow::Result<()> {
 | 
				
			|||||||
        "[{:>10}s] loaded initial changeset from db",
 | 
					        "[{:>10}s] loaded initial changeset from db",
 | 
				
			||||||
        start.elapsed().as_secs_f32()
 | 
					        start.elapsed().as_secs_f32()
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					    let (init_chain_changeset, init_graph_changeset) = init_changeset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let graph = Mutex::new({
 | 
					    let graph = Mutex::new({
 | 
				
			||||||
        let mut graph = IndexedTxGraph::new(index);
 | 
					        let mut graph = IndexedTxGraph::new(index);
 | 
				
			||||||
        graph.apply_changeset(init_changeset.1);
 | 
					        graph.apply_changeset(init_graph_changeset);
 | 
				
			||||||
        graph
 | 
					        graph
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    println!(
 | 
					    println!(
 | 
				
			||||||
@ -131,7 +129,16 @@ fn main() -> anyhow::Result<()> {
 | 
				
			|||||||
        start.elapsed().as_secs_f32()
 | 
					        start.elapsed().as_secs_f32()
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let chain = Mutex::new(LocalChain::from_changeset(init_changeset.0)?);
 | 
					    let chain = Mutex::new(if init_chain_changeset.is_empty() {
 | 
				
			||||||
 | 
					        let genesis_hash = genesis_block(args.network).block_hash();
 | 
				
			||||||
 | 
					        let (chain, chain_changeset) = LocalChain::from_genesis_hash(genesis_hash);
 | 
				
			||||||
 | 
					        let mut db = db.lock().unwrap();
 | 
				
			||||||
 | 
					        db.stage((chain_changeset, Default::default()));
 | 
				
			||||||
 | 
					        db.commit()?;
 | 
				
			||||||
 | 
					        chain
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        LocalChain::from_changeset(init_chain_changeset)?
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
    println!(
 | 
					    println!(
 | 
				
			||||||
        "[{:>10}s] loaded local chain from changeset",
 | 
					        "[{:>10}s] loaded local chain from changeset",
 | 
				
			||||||
        start.elapsed().as_secs_f32()
 | 
					        start.elapsed().as_secs_f32()
 | 
				
			||||||
@ -161,13 +168,9 @@ fn main() -> anyhow::Result<()> {
 | 
				
			|||||||
    match rpc_cmd {
 | 
					    match rpc_cmd {
 | 
				
			||||||
        RpcCommands::Sync { rpc_args } => {
 | 
					        RpcCommands::Sync { rpc_args } => {
 | 
				
			||||||
            let RpcArgs {
 | 
					            let RpcArgs {
 | 
				
			||||||
                fallback_height,
 | 
					                fallback_height, ..
 | 
				
			||||||
                lookahead,
 | 
					 | 
				
			||||||
                ..
 | 
					 | 
				
			||||||
            } = rpc_args;
 | 
					            } = rpc_args;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            graph.lock().unwrap().index.set_lookahead_for_all(lookahead);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            let chain_tip = chain.lock().unwrap().tip();
 | 
					            let chain_tip = chain.lock().unwrap().tip();
 | 
				
			||||||
            let rpc_client = rpc_args.new_client()?;
 | 
					            let rpc_client = rpc_args.new_client()?;
 | 
				
			||||||
            let mut emitter = Emitter::new(&rpc_client, chain_tip, fallback_height);
 | 
					            let mut emitter = Emitter::new(&rpc_client, chain_tip, fallback_height);
 | 
				
			||||||
@ -233,13 +236,10 @@ fn main() -> anyhow::Result<()> {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        RpcCommands::Live { rpc_args } => {
 | 
					        RpcCommands::Live { rpc_args } => {
 | 
				
			||||||
            let RpcArgs {
 | 
					            let RpcArgs {
 | 
				
			||||||
                fallback_height,
 | 
					                fallback_height, ..
 | 
				
			||||||
                lookahead,
 | 
					 | 
				
			||||||
                ..
 | 
					 | 
				
			||||||
            } = rpc_args;
 | 
					            } = rpc_args;
 | 
				
			||||||
            let sigterm_flag = start_ctrlc_handler();
 | 
					            let sigterm_flag = start_ctrlc_handler();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            graph.lock().unwrap().index.set_lookahead_for_all(lookahead);
 | 
					 | 
				
			||||||
            let last_cp = chain.lock().unwrap().tip();
 | 
					            let last_cp = chain.lock().unwrap().tip();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            println!(
 | 
					            println!(
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user