]> Untitled Git - bdk/commitdiff
fix(chain): `KeychainTxOutIndex::lookahead_to_target`
author志宇 <hello@evanlinjin.me>
Fri, 16 Feb 2024 18:20:44 +0000 (02:20 +0800)
committer志宇 <hello@evanlinjin.me>
Sat, 17 Feb 2024 15:36:02 +0000 (23:36 +0800)
crates/chain/src/keychain/txout_index.rs
crates/chain/tests/test_keychain_txout_index.rs

index da6a1e25ba5223d8c3c172dbd6e312209300679c..79f98fad23ebb063ddfc5ff7585ef7f78a5c93c4 100644 (file)
@@ -326,12 +326,17 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
         self.lookahead
     }
 
-    /// Store lookahead scripts until `target_index`.
+    /// Store lookahead scripts until `target_index` (inclusive).
     ///
-    /// This does not change the `lookahead` setting.
+    /// This does not change the global `lookahead` setting.
     pub fn lookahead_to_target(&mut self, keychain: &K, target_index: u32) {
-        let next_index = self.next_store_index(keychain);
-        if let Some(temp_lookahead) = target_index.checked_sub(next_index).filter(|&v| v > 0) {
+        let (next_index, _) = self.next_index(keychain);
+
+        let temp_lookahead = (target_index + 1)
+            .checked_sub(next_index)
+            .filter(|&index| index > 0);
+
+        if let Some(temp_lookahead) = temp_lookahead {
             self.replenish_lookahead(keychain, temp_lookahead);
         }
     }
index 0bbc37393c461d04214194b24188a8c8492e4b7c..9ce15f4b4fb1847ddd8b0c68ac290c2ee2873f99 100644 (file)
@@ -386,3 +386,98 @@ fn test_non_wildcard_derivations() {
         1,
     );
 }
+
+/// Check that calling `lookahead_to_target` stores the expected spks.
+#[test]
+fn lookahead_to_target() {
+    #[derive(Default)]
+    struct TestCase {
+        lookahead: u32,                      // Global lookahead value
+        external_last_revealed: Option<u32>, // Last revealed index for external keychain
+        internal_last_revealed: Option<u32>, // Last revealed index for internal keychain
+        external_target: Option<u32>,        // Call `lookahead_to_target(External, u32)`
+        internal_target: Option<u32>,        // Call `lookahead_to_target(Internal, u32)`
+    }
+
+    let test_cases = &[
+        TestCase {
+            lookahead: 0,
+            external_target: Some(100),
+            ..Default::default()
+        },
+        TestCase {
+            lookahead: 10,
+            internal_target: Some(99),
+            ..Default::default()
+        },
+        TestCase {
+            lookahead: 100,
+            internal_target: Some(9),
+            external_target: Some(10),
+            ..Default::default()
+        },
+        TestCase {
+            lookahead: 12,
+            external_last_revealed: Some(2),
+            internal_last_revealed: Some(2),
+            internal_target: Some(15),
+            external_target: Some(13),
+        },
+        TestCase {
+            lookahead: 13,
+            external_last_revealed: Some(100),
+            internal_last_revealed: Some(21),
+            internal_target: Some(120),
+            external_target: Some(130),
+        },
+    ];
+
+    for t in test_cases {
+        let (mut index, _, _) = init_txout_index(t.lookahead);
+
+        if let Some(last_revealed) = t.external_last_revealed {
+            let _ = index.reveal_to_target(&TestKeychain::External, last_revealed);
+        }
+        if let Some(last_revealed) = t.internal_last_revealed {
+            let _ = index.reveal_to_target(&TestKeychain::Internal, last_revealed);
+        }
+
+        let keychain_test_cases = [
+            (
+                TestKeychain::External,
+                t.external_last_revealed,
+                t.external_target,
+            ),
+            (
+                TestKeychain::Internal,
+                t.internal_last_revealed,
+                t.internal_target,
+            ),
+        ];
+        for (keychain, last_revealed, target) in keychain_test_cases {
+            if let Some(target) = target {
+                let original_last_stored_index = match last_revealed {
+                    Some(last_revealed) => Some(last_revealed + t.lookahead),
+                    None => t.lookahead.checked_sub(1),
+                };
+                let exp_last_stored_index = match original_last_stored_index {
+                    Some(original_last_stored_index) => {
+                        Ord::max(target, original_last_stored_index)
+                    }
+                    None => target,
+                };
+                index.lookahead_to_target(&keychain, target);
+                let keys = index
+                    .inner()
+                    .all_spks()
+                    .range((keychain.clone(), 0)..=(keychain.clone(), u32::MAX))
+                    .map(|(k, _)| k.clone())
+                    .collect::<Vec<_>>();
+                let exp_keys = core::iter::repeat(keychain)
+                    .zip(0_u32..=exp_last_stored_index)
+                    .collect::<Vec<_>>();
+                assert_eq!(keys, exp_keys);
+            }
+        }
+    }
+}