@@ -5,12 +5,13 @@ use crate::{
55 spk_iter:: BIP32_MAX_INDEX ,
66 SpkIterator , SpkTxOutIndex ,
77} ;
8- use alloc:: vec:: Vec ;
98use bitcoin:: { OutPoint , Script , TxOut } ;
109use core:: { fmt:: Debug , ops:: Deref } ;
1110
1211use crate :: Append ;
1312
13+ const DEFAULT_LOOKAHEAD : u32 = 1_000 ;
14+
1415/// A convenient wrapper around [`SpkTxOutIndex`] that relates script pubkeys to miniscript public
1516/// [`Descriptor`]s.
1617///
@@ -46,7 +47,7 @@ use crate::Append;
4647/// # let secp = bdk_chain::bitcoin::secp256k1::Secp256k1::signing_only();
4748/// # let (external_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/0/*)").unwrap();
4849/// # let (internal_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/1/*)").unwrap();
49- /// # let descriptor_for_user_42 = external_descriptor.clone ();
50+ /// # let ( descriptor_for_user_42, _) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/2/*)").unwrap ();
5051/// txout_index.add_keychain(MyKeychain::External, external_descriptor);
5152/// txout_index.add_keychain(MyKeychain::Internal, internal_descriptor);
5253/// txout_index.add_keychain(MyKeychain::MyAppUser { user_id: 42 }, descriptor_for_user_42);
@@ -65,17 +66,12 @@ pub struct KeychainTxOutIndex<K> {
6566 // last revealed indexes
6667 last_revealed : BTreeMap < K , u32 > ,
6768 // lookahead settings for each keychain
68- lookahead : BTreeMap < K , u32 > ,
69+ lookahead : u32 ,
6970}
7071
7172impl < K > Default for KeychainTxOutIndex < K > {
7273 fn default ( ) -> Self {
73- Self {
74- inner : SpkTxOutIndex :: default ( ) ,
75- keychains : BTreeMap :: default ( ) ,
76- last_revealed : BTreeMap :: default ( ) ,
77- lookahead : BTreeMap :: default ( ) ,
78- }
74+ Self :: new ( DEFAULT_LOOKAHEAD )
7975 }
8076}
8177
@@ -118,6 +114,24 @@ impl<K: Clone + Ord + Debug> Indexer for KeychainTxOutIndex<K> {
118114 }
119115}
120116
117+ impl < K > KeychainTxOutIndex < K > {
118+ /// Construct a [`KeychainTxOutIndex`] with the given `lookahead`.
119+ ///
120+ /// The lookahead is the number of scripts to cache ahead of the last revealed script index.
121+ /// This is useful to find outputs you own when processing block data that lie beyond the last
122+ /// revealed index. In certain situations, such as when performing an initial scan of the
123+ /// blockchain during wallet import, it may be uncertain or unknown what the last revealed index
124+ /// is.
125+ pub fn new ( lookahead : u32 ) -> Self {
126+ Self {
127+ inner : SpkTxOutIndex :: default ( ) ,
128+ keychains : BTreeMap :: new ( ) ,
129+ last_revealed : BTreeMap :: new ( ) ,
130+ lookahead,
131+ }
132+ }
133+ }
134+
121135impl < K : Clone + Ord + Debug > KeychainTxOutIndex < K > {
122136 /// Return a reference to the internal [`SpkTxOutIndex`].
123137 pub fn inner ( & self ) -> & SpkTxOutIndex < ( K , u32 ) > {
@@ -142,57 +156,27 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
142156 /// # Panics
143157 ///
144158 /// This will panic if a different `descriptor` is introduced to the same `keychain`.
159+ ///
160+ /// [`add_keychain_with_lookahead`]: Self::add_keychain_with_lookahead
145161 pub fn add_keychain ( & mut self , keychain : K , descriptor : Descriptor < DescriptorPublicKey > ) {
146162 let old_descriptor = & * self
147163 . keychains
148- . entry ( keychain)
164+ . entry ( keychain. clone ( ) )
149165 . or_insert_with ( || descriptor. clone ( ) ) ;
150166 assert_eq ! (
151167 & descriptor, old_descriptor,
152168 "keychain already contains a different descriptor"
153169 ) ;
170+ self . replenish_lookahead ( & keychain, self . lookahead ) ;
154171 }
155172
156- /// Return the lookahead setting for each keychain.
157- ///
158- /// Refer to [`set_lookahead`] for a deeper explanation of the `lookahead`.
159- ///
160- /// [`set_lookahead`]: Self::set_lookahead
161- pub fn lookaheads ( & self ) -> & BTreeMap < K , u32 > {
162- & self . lookahead
163- }
164-
165- /// Convenience method to call [`set_lookahead`] for all keychains.
166- ///
167- /// [`set_lookahead`]: Self::set_lookahead
168- pub fn set_lookahead_for_all ( & mut self , lookahead : u32 ) {
169- for keychain in & self . keychains . keys ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) {
170- self . set_lookahead ( keychain, lookahead) ;
171- }
172- }
173-
174- /// Set the lookahead count for `keychain`.
175- ///
176- /// The lookahead is the number of scripts to cache ahead of the last revealed script index. This
177- /// is useful to find outputs you own when processing block data that lie beyond the last revealed
178- /// index. In certain situations, such as when performing an initial scan of the blockchain during
179- /// wallet import, it may be uncertain or unknown what the last revealed index is.
173+ /// Get the lookahead setting.
180174 ///
181- /// # Panics
175+ /// Refer to [`new`] for more information on the `lookahead`.
182176 ///
183- /// This will panic if the `keychain` does not exist.
184- pub fn set_lookahead ( & mut self , keychain : & K , lookahead : u32 ) {
185- self . lookahead . insert ( keychain. clone ( ) , lookahead) ;
186- self . replenish_lookahead ( keychain) ;
187- }
188-
189- /// Convenience method to call [`lookahead_to_target`] for multiple keychains.
190- ///
191- /// [`lookahead_to_target`]: Self::lookahead_to_target
192- pub fn lookahead_to_target_multi ( & mut self , target_indexes : BTreeMap < K , u32 > ) {
193- for ( keychain, target_index) in target_indexes {
194- self . lookahead_to_target ( & keychain, target_index)
195- }
177+ /// [`new`]: Self::new
178+ pub fn lookahead ( & self ) -> u32 {
179+ self . lookahead
196180 }
197181
198182 /// Store lookahead scripts until `target_index`.
@@ -201,22 +185,14 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
201185 pub fn lookahead_to_target ( & mut self , keychain : & K , target_index : u32 ) {
202186 let next_index = self . next_store_index ( keychain) ;
203187 if let Some ( temp_lookahead) = target_index. checked_sub ( next_index) . filter ( |& v| v > 0 ) {
204- let old_lookahead = self . lookahead . insert ( keychain. clone ( ) , temp_lookahead) ;
205- self . replenish_lookahead ( keychain) ;
206-
207- // revert
208- match old_lookahead {
209- Some ( lookahead) => self . lookahead . insert ( keychain. clone ( ) , lookahead) ,
210- None => self . lookahead . remove ( keychain) ,
211- } ;
188+ self . replenish_lookahead ( keychain, temp_lookahead) ;
212189 }
213190 }
214191
215- fn replenish_lookahead ( & mut self , keychain : & K ) {
192+ fn replenish_lookahead ( & mut self , keychain : & K , lookahead : u32 ) {
216193 let descriptor = self . keychains . get ( keychain) . expect ( "keychain must exist" ) ;
217194 let next_store_index = self . next_store_index ( keychain) ;
218195 let next_reveal_index = self . last_revealed . get ( keychain) . map_or ( 0 , |v| * v + 1 ) ;
219- let lookahead = self . lookahead . get ( keychain) . map_or ( 0 , |v| * v) ;
220196
221197 for ( new_index, new_spk) in
222198 SpkIterator :: new_with_range ( descriptor, next_store_index..next_reveal_index + lookahead)
@@ -388,25 +364,21 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
388364
389365 let target_index = if has_wildcard { target_index } else { 0 } ;
390366 let next_reveal_index = self . last_revealed . get ( keychain) . map_or ( 0 , |v| * v + 1 ) ;
391- let lookahead = self . lookahead . get ( keychain) . map_or ( 0 , |v| * v) ;
392367
393- debug_assert_eq ! (
394- next_reveal_index + lookahead,
395- self . next_store_index( keychain)
396- ) ;
368+ debug_assert ! ( next_reveal_index + self . lookahead >= self . next_store_index( keychain) ) ;
397369
398370 // if we need to reveal new indices, the latest revealed index goes here
399371 let mut reveal_to_index = None ;
400372
401373 // if the target is not yet revealed, but is already stored (due to lookahead), we need to
402374 // set the `reveal_to_index` as target here (as the `for` loop below only updates
403375 // `reveal_to_index` for indexes that are NOT stored)
404- if next_reveal_index <= target_index && target_index < next_reveal_index + lookahead {
376+ if next_reveal_index <= target_index && target_index < next_reveal_index + self . lookahead {
405377 reveal_to_index = Some ( target_index) ;
406378 }
407379
408380 // we range over indexes that are not stored
409- let range = next_reveal_index + lookahead..=target_index + lookahead;
381+ let range = next_reveal_index + self . lookahead ..=target_index + self . lookahead ;
410382 for ( new_index, new_spk) in SpkIterator :: new_with_range ( descriptor, range) {
411383 let _inserted = self
412384 . inner
0 commit comments