]> Untitled Git - bdk/commitdiff
Simplify `reveal_to_target` logic
author志宇 <hello@evanlinjin.me>
Wed, 15 Mar 2023 07:38:25 +0000 (15:38 +0800)
committer志宇 <hello@evanlinjin.me>
Sat, 18 Mar 2023 01:18:09 +0000 (09:18 +0800)
- Remove unnecessary check
- Better comments
- Better variable names
- Add test for scanning txouts with lookahead

crates/chain/src/keychain/txout_index.rs
crates/chain/tests/test_keychain_txout_index.rs

index 3a82b92fe2f29b640092641f99e227dc7ce1fdc0..feb71edb45abffca489f4276410e31bf31300bcc 100644 (file)
@@ -63,7 +63,7 @@ pub struct KeychainTxOutIndex<K> {
     inner: SpkTxOutIndex<(K, u32)>,
     // descriptors of each keychain
     keychains: BTreeMap<K, Descriptor<DescriptorPublicKey>>,
-    // last stored indexes
+    // last revealed indexes
     last_revealed: BTreeMap<K, u32>,
     // lookahead settings for each keychain
     lookahead: BTreeMap<K, u32>,
@@ -381,40 +381,39 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
         let has_wildcard = descriptor.has_wildcard();
 
         let target_index = if has_wildcard { target_index } else { 0 };
-        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 lookahead = self.lookahead.get(keychain).map_or(0, |v| *v);
 
-        // if we can reveal new indexes, the latest revealed index goes here
-        let mut revealed_index = None;
+        debug_assert_eq!(
+            next_reveal_index + lookahead,
+            self.next_store_index(keychain)
+        );
+
+        // if we need to reveal new indices, the latest revealed index goes here
+        let mut reveal_to_index = None;
 
-        // if the target is already surpassed, we have nothing to reveal
-        if next_reveal_index <= target_index
-            // if the target is already stored (due to lookahead), this can be our newly revealed index
-            && target_index < next_reveal_index + lookahead
-        {
-            revealed_index = Some(target_index);
+        // 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
+        // `reveal_to_index` for indexes that are NOT stored)
+        if next_reveal_index <= target_index && target_index < next_reveal_index + lookahead {
+            reveal_to_index = Some(target_index);
         }
 
         // we range over indexes that are not stored
         let range = next_reveal_index + lookahead..=target_index + lookahead;
-
         for (new_index, new_spk) in range_descriptor_spks(Cow::Borrowed(descriptor), range) {
-            // no need to store if already stored
-            if new_index >= next_store_index {
-                let _inserted = self
-                    .inner
-                    .insert_spk((keychain.clone(), new_index), new_spk);
-                debug_assert!(_inserted, "must not have existing spk",);
-            }
+            let _inserted = self
+                .inner
+                .insert_spk((keychain.clone(), new_index), new_spk);
+            debug_assert!(_inserted, "must not have existing spk",);
 
             // everything after `target_index` is stored for lookahead only
             if new_index <= target_index {
-                revealed_index = Some(new_index);
+                reveal_to_index = Some(new_index);
             }
         }
 
-        match revealed_index {
+        match reveal_to_index {
             Some(index) => {
                 let _old_index = self.last_revealed.insert(keychain.clone(), index);
                 debug_assert!(_old_index < Some(index));
index cfbcd123b57d0b451ac45486ca4b9d6082a55595..07c7f48d4d741dc757602f7cc87b1d33b11e5fb8 100644 (file)
@@ -7,7 +7,7 @@ use bdk_chain::{
     keychain::{DerivationAdditions, KeychainTxOutIndex},
 };
 
-use bitcoin::{secp256k1::Secp256k1, Script, Transaction, TxOut};
+use bitcoin::{secp256k1::Secp256k1, OutPoint, Script, Transaction, TxOut};
 use miniscript::{Descriptor, DescriptorPublicKey};
 
 #[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd)]
@@ -210,13 +210,54 @@ fn test_lookahead() {
             last_internal_index as usize + 1,
         );
     }
+}
 
-    // when:
-    // - scanning txouts with spks above last stored index
-    // expect:
-    // - cached scripts count should increase as expected
-    // - last stored index should increase as expected
-    // TODO!
+// when:
+// - scanning txouts with spks above last stored index
+// expect:
+// - last revealed index should increase as expected
+// - last used index should change as expected
+#[test]
+fn test_scan_with_lookahead() {
+    let (mut txout_index, external_desc, _) = init_txout_index();
+    txout_index.set_lookahead_for_all(10);
+
+    let spks: BTreeMap<u32, Script> = [0, 10, 20, 30]
+        .into_iter()
+        .map(|i| (i, external_desc.at_derivation_index(i).script_pubkey()))
+        .collect();
+
+    for (&spk_i, spk) in &spks {
+        let op = OutPoint::new(h!("fake tx"), spk_i);
+        let txout = TxOut {
+            script_pubkey: spk.clone(),
+            value: 0,
+        };
+
+        let additions = txout_index.scan_txout(op, &txout);
+        assert_eq!(
+            additions.as_inner(),
+            &[(TestKeychain::External, spk_i)].into()
+        );
+        assert_eq!(
+            txout_index.last_revealed_index(&TestKeychain::External),
+            Some(spk_i)
+        );
+        assert_eq!(
+            txout_index.last_used_index(&TestKeychain::External),
+            Some(spk_i)
+        );
+    }
+
+    // now try with index 41 (lookahead surpassed), we expect that the txout to not be indexed
+    let spk_41 = external_desc.at_derivation_index(41).script_pubkey();
+    let op = OutPoint::new(h!("fake tx"), 41);
+    let txout = TxOut {
+        script_pubkey: spk_41,
+        value: 0,
+    };
+    let additions = txout_index.scan_txout(op, &txout);
+    assert!(additions.is_empty());
 }
 
 #[test]