]> Untitled Git - bdk/commitdiff
fix(chain): add missing `continue` in `CanonicalIter` assumed-tx processing
authorElias Rohrer <dev@tnull.de>
Wed, 8 Apr 2026 09:43:08 +0000 (11:43 +0200)
committervalued mammal <valuedmammal@protonmail.com>
Thu, 16 Apr 2026 16:02:48 +0000 (12:02 -0400)
Without the `continue`, the loop falls through to the subsequent
processing blocks when assumed-canonical transactions are the only
remaining unprocessed source. If the anchored, seen, and leftover
iterators are all exhausted, the loop reaches `return None` and silently
drops the assumed transactions that were just marked canonical.

Co-Authored-By: HAL 9000
crates/chain/src/canonical_iter.rs
crates/chain/tests/test_tx_graph_conflicts.rs

index 7ff04249b5cedf8f69900a20f02223412ee9dc8b..41f17e527e4c8ee4cfca205708725d849b3f2720 100644 (file)
@@ -218,6 +218,7 @@ impl<A: Anchor, C: ChainOracle> Iterator for CanonicalIter<'_, A, C> {
                 if !self.is_canonicalized(txid) {
                     self.mark_canonical(txid, tx, CanonicalReason::assumed());
                 }
+                continue;
             }
 
             if let Some((txid, tx, anchors)) = self.unprocessed_anchored_txs.next() {
index 113a985b4624cb7fc6463cfa3743deee8d756ecb..abfd950c81463863f029b4022f964961a2437062 100644 (file)
@@ -943,6 +943,34 @@ fn test_tx_conflict_handling() {
                 confirmed: Amount::ZERO,
             },
         },
+        Scenario {
+            name: "only assumed-canonical txs are yielded without anchored or seen txs",
+            tx_templates: &[
+                TxTemplate {
+                    tx_name: "assumed_a",
+                    inputs: &[TxInTemplate::Bogus],
+                    outputs: &[TxOutTemplate::new(21_000, Some(0))],
+                    assume_canonical: true,
+                    ..Default::default()
+                },
+                TxTemplate {
+                    tx_name: "assumed_b",
+                    inputs: &[TxInTemplate::Bogus],
+                    outputs: &[TxOutTemplate::new(18_000, Some(1))],
+                    assume_canonical: true,
+                    ..Default::default()
+                },
+            ],
+            exp_chain_txs: HashSet::from(["assumed_a", "assumed_b"]),
+            exp_chain_txouts: HashSet::from([("assumed_a", 0), ("assumed_b", 0)]),
+            exp_unspents: HashSet::from([("assumed_a", 0), ("assumed_b", 0)]),
+            exp_balance: Balance {
+                immature: Amount::ZERO,
+                trusted_pending: Amount::from_sat(21_000 + 18_000),
+                untrusted_pending: Amount::ZERO,
+                confirmed: Amount::ZERO,
+            },
+        },
         Scenario {
             name: "coinbase tx must not become unconfirmed",
             tx_templates: &[