From: 志宇 Date: Fri, 13 Jun 2025 03:07:37 +0000 (+1000) Subject: fix(chain): Unconfirmed coinbase txs should never be canonical X-Git-Tag: bitcoind_rpc-0.21.0~11^2~1 X-Git-Url: http://internal-gitweb-vhost/script/%22https:/database/scripts/static/struct.AggregateChangesetsError.html?a=commitdiff_plain;h=e8da007011c3c7e247c26a1c9984319229bb0afa;p=bdk fix(chain): Unconfirmed coinbase txs should never be canonical The logic in `CanonicalIter` will consider txs that are anchored to blocks not in the best chain since they still can appear in the mempool. However, coinbase txs can never be unconfirmed - which the old logic failed to exclude. --- diff --git a/crates/chain/src/canonical_iter.rs b/crates/chain/src/canonical_iter.rs index 58f266f8..204ead45 100644 --- a/crates/chain/src/canonical_iter.rs +++ b/crates/chain/src/canonical_iter.rs @@ -230,6 +230,10 @@ impl Iterator for CanonicalIter<'_, A, C> { } if let Some((txid, tx, last_seen)) = self.unprocessed_seen_txs.next() { + debug_assert!( + !tx.is_coinbase(), + "Coinbase txs must not have `last_seen` (in mempool) value" + ); if !self.is_canonicalized(txid) { let observed_in = ObservedIn::Mempool(last_seen); self.mark_canonical(txid, tx, CanonicalReason::from_observed_in(observed_in)); @@ -238,7 +242,7 @@ impl Iterator for CanonicalIter<'_, A, C> { } if let Some((txid, tx, height)) = self.unprocessed_leftover_txs.pop_front() { - if !self.is_canonicalized(txid) { + if !self.is_canonicalized(txid) && !tx.is_coinbase() { let observed_in = ObservedIn::Block(height); self.mark_canonical(txid, tx, CanonicalReason::from_observed_in(observed_in)); }