Skip to content

fix(chain): skip evicted txs in leftover canonicalization#2240

Open
noahjoeris wants to merge 2 commits into
bitcoindevkit:masterfrom
noahjoeris:fix/leftover-eviction
Open

fix(chain): skip evicted txs in leftover canonicalization#2240
noahjoeris wants to merge 2 commits into
bitcoindevkit:masterfrom
noahjoeris:fix/leftover-eviction

Conversation

@noahjoeris

Copy link
Copy Markdown
Contributor

Description

CanonicalStage::LeftOverTxs doesn't filter evicted txs and can mark them canonical. So a stale-anchored tx that was evicted/replaced could still show as unconfirmed.

Example: a tx confirms, then a reorg leaves only a stale anchor. Leftover treats it as unconfirmed. If it's later RBF'd or missing from the mempool, leftover still marks it unconfirmed.

Changelog notice

  • Fix leftover canonicalization to disregard txs with last_evicted >= last_seen.

Checklists

All Submissions:

Bugfixes:

  • This pull request breaks the existing API
  • I've added tests to reproduce the issue which are now passing
  • I'm linking the issue being fixed by this PR

Seen already filters last_evicted >= last_seen; leftover did not, so
unmatched-anchor txs could reappear as unconfirmed after drop/RBF.
@codecov

codecov Bot commented Jul 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.85714% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 78.68%. Comparing base (6d03fc3) to head (4f99ffc).
⚠️ Report is 4 commits behind head on master.

Files with missing lines Patch % Lines
crates/chain/src/canonical_task.rs 92.85% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2240      +/-   ##
==========================================
+ Coverage   78.65%   78.68%   +0.02%     
==========================================
  Files          30       30              
  Lines        5909     5922      +13     
  Branches      279      281       +2     
==========================================
+ Hits         4648     4660      +12     
- Misses       1185     1186       +1     
  Partials       76       76              
Flag Coverage Δ
rust 78.68% <92.85%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@evanlinjin evanlinjin moved this to Needs Review in BDK Chain Jul 14, 2026
@evanlinjin evanlinjin added the bug Something isn't working label Jul 14, 2026

@evanlinjin evanlinjin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for finding and fixing this. These changes are logically correct. I have some suggestions with two possible directions.

Comment on lines +265 to +275
fn is_evicted_leftover(&self, txid: Txid) -> bool {
let node = self
.tx_graph
.get_tx_node(txid)
.expect("leftover transaction must exist");
match (node.last_seen, node.last_evicted) {
(_, None) => false,
(Some(seen), Some(evicted)) => evicted >= seen,
(None, Some(_)) => true,
}
}

@evanlinjin evanlinjin Jul 21, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two things:

  1. The _leftover suffix is wrong here - the method's logic has no understanding of what is leftover or not.
  2. The last_evicted >= last_seen check is also used by TxGraph::txids_by_descending_anchor_height but the logic there did not consider the last_seen = None, last_evicted = Some case (which is wrong).

Possible directions:

  1. Introduce TxNode::is_evicted -> bool method which would be a pure mempool-observation predicate (does not take anchoring into account - docs need to be clear about this). Thus, getting rid of is_evicted_leftover.
  2. Rename is_evicted_leftover to just is_evicted and create a ticket to introduce TxNode::is_evicted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

Status: Needs Review

Development

Successfully merging this pull request may close these issues.

2 participants