]> Untitled Git - bdk/commitdiff
fix: remove panic from stop gap scan loop
authorMatthew <ramsden@hey.com>
Mon, 29 Sep 2025 21:00:47 +0000 (16:00 -0500)
committerMatthew <ramsden@hey.com>
Fri, 20 Feb 2026 20:26:34 +0000 (14:26 -0600)
crates/esplora/src/async_ext.rs
crates/esplora/src/blocking_ext.rs

index d504a4723fd5e6aace782962dec12c3944d85f83..945bea1226d07dc6390a65fed1f6495d3de3a692 100644 (file)
@@ -184,10 +184,10 @@ async fn fetch_latest_blocks<S: Sleeper>(
     client: &esplora_client::AsyncClient<S>,
 ) -> Result<BTreeMap<u32, BlockHash>, Error> {
     Ok(client
-        .get_blocks(None)
+        .get_block_infos(None)
         .await?
         .into_iter()
-        .map(|b| (b.time.height, b.id))
+        .map(|b| (b.height, b.id))
         .collect())
 }
 
@@ -314,8 +314,11 @@ where
     type TxsOfSpkIndex = (u32, Vec<esplora_client::Tx>, HashSet<Txid>);
 
     let mut update = TxUpdate::<ConfirmationBlockTime>::default();
-    let mut last_index = Option::<u32>::None;
     let mut last_active_index = Option::<u32>::None;
+    // Use consecutive_unused so unused count drives stop gap.
+    let mut consecutive_unused = 0usize;
+    // Treat stop_gap = 0 as 1 while preserving original semantics for other values.
+    let gap_limit = stop_gap.max(1);
 
     loop {
         let handles = keychain_spks
@@ -352,8 +355,10 @@ where
         }
 
         for (index, txs, evicted) in handles.try_collect::<Vec<TxsOfSpkIndex>>().await? {
-            last_index = Some(index);
-            if !txs.is_empty() {
+            if txs.is_empty() {
+                consecutive_unused = consecutive_unused.saturating_add(1);
+            } else {
+                consecutive_unused = 0;
                 last_active_index = Some(index);
             }
             for tx in txs {
@@ -368,13 +373,7 @@ where
                 .extend(evicted.into_iter().map(|txid| (txid, start_time)));
         }
 
-        let last_index = last_index.expect("Must be set since handles wasn't empty.");
-        let gap_limit_reached = if let Some(i) = last_active_index {
-            last_index >= i.saturating_add(stop_gap as u32)
-        } else {
-            last_index + 1 >= stop_gap as u32
-        };
-        if gap_limit_reached {
+        if consecutive_unused >= gap_limit {
             break;
         }
     }
@@ -596,7 +595,10 @@ mod test {
         let res = chain_update(&client, &latest_blocks, &cp, &anchors).await;
         use esplora_client::Error;
         assert!(
-            matches!(*res.unwrap_err(), Error::HeaderHashNotFound(hash) if hash == genesis_hash),
+            matches!(
+                *res.unwrap_err(),
+                Error::HeaderHashNotFound(hash) if hash == genesis_hash
+            ),
             "`chain_update` should error if it can't connect to the local CP",
         );
 
index 9413c14afd148fcacfa64566e9ad706da795a64f..d33723b09939f2f8ecfc5d27e75bec75ca2a570b 100644 (file)
@@ -170,9 +170,9 @@ fn fetch_latest_blocks(
     client: &esplora_client::BlockingClient,
 ) -> Result<BTreeMap<u32, BlockHash>, Error> {
     Ok(client
-        .get_blocks(None)?
+        .get_block_infos(None)?
         .into_iter()
-        .map(|b| (b.time.height, b.id))
+        .map(|b| (b.height, b.id))
         .collect())
 }
 
@@ -282,8 +282,11 @@ fn fetch_txs_with_keychain_spks<I: Iterator<Item = Indexed<SpkWithExpectedTxids>
     type TxsOfSpkIndex = (u32, Vec<esplora_client::Tx>, HashSet<Txid>);
 
     let mut update = TxUpdate::<ConfirmationBlockTime>::default();
-    let mut last_index = Option::<u32>::None;
     let mut last_active_index = Option::<u32>::None;
+    // Use consecutive_unused so unused count drives stop gap.
+    let mut consecutive_unused = 0usize;
+    // Treat stop_gap = 0 as 1 while preserving original semantics for other values.
+    let gap_limit = stop_gap.max(1);
 
     loop {
         let handles = keychain_spks
@@ -321,8 +324,10 @@ fn fetch_txs_with_keychain_spks<I: Iterator<Item = Indexed<SpkWithExpectedTxids>
 
         for handle in handles {
             let (index, txs, evicted) = handle.join().expect("thread must not panic")?;
-            last_index = Some(index);
-            if !txs.is_empty() {
+            if txs.is_empty() {
+                consecutive_unused = consecutive_unused.saturating_add(1);
+            } else {
+                consecutive_unused = 0;
                 last_active_index = Some(index);
             }
             for tx in txs {
@@ -337,13 +342,7 @@ fn fetch_txs_with_keychain_spks<I: Iterator<Item = Indexed<SpkWithExpectedTxids>
                 .extend(evicted.into_iter().map(|txid| (txid, start_time)));
         }
 
-        let last_index = last_index.expect("Must be set since handles wasn't empty.");
-        let gap_limit_reached = if let Some(i) = last_active_index {
-            last_index >= i.saturating_add(stop_gap as u32)
-        } else {
-            last_index + 1 >= stop_gap as u32
-        };
-        if gap_limit_reached {
+        if consecutive_unused >= gap_limit {
             break;
         }
     }