mempool: recalculate stale BIP68 lockpoints with mempool parents in removeForReorg #35026

pull javierpmateos wants to merge 1 commits into bitcoin:master from javierpmateos:fix-bip68-stale-lockpoints-clean changing 3 files +75 −1
  1. javierpmateos commented at 8:13 pm on April 7, 2026: none

    When a transaction with nSequence=0 (BIP68 relative locktime 0) enters the mempool with an unconfirmed parent, CalculatePrevHeights assigns nCoinHeight=tip+1 and the resulting LockPoints are cached with maxInputBlock=genesis. After invalidateblock lowers the tip, TestLockPointValidity returns true for genesis (always on chain), so the stale cached lockpoints are reused. CheckSequenceLocksAtTip then incorrectly determines the lock is not satisfied and removes the transaction along with all its descendants.

    The fix detects the genesis sentinel (maxInputBlock->nHeight==0 with lp.height>0) in filter_final_and_mature, which indicates lockpoints computed with mempool parent inputs, and forces fresh recalculation via CalculateLockPointsAtTip instead of using the stale cache.

    Added mempool_reorg_bip68_stale_lockpoints.py which verifies that both BIP68-disabled and BIP68-enabled children with mempool parents survive a multi-block reorg via invalidateblock.

    Reproducer for unpatched nodes: https://gist.github.com/javierpmateos/c55d365973adbf488a852dc5e0b77dec

    Same class of issue fixed for TRUC in #33504.

    Closes #35007

  2. DrahtBot added the label Mempool on Apr 7, 2026
  3. DrahtBot commented at 8:13 pm on April 7, 2026: contributor

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Reviews

    See the guideline for information on the review process. A summary of reviews will appear here.

    LLM Linter (✨ experimental)

    Possible places where comparison-specific test macros should replace generic comparisons:

    • [test/functional/mempool_reorg_bip68_stale_lockpoints.py] assert node.getblockcount() == H - 1 -> Replace with assert_equal(node.getblockcount(), H - 1)

    2026-04-08 10:17:50

  4. javierpmateos force-pushed on Apr 7, 2026
  5. javierpmateos force-pushed on Apr 7, 2026
  6. javierpmateos force-pushed on Apr 7, 2026
  7. javierpmateos force-pushed on Apr 8, 2026
  8. javierpmateos force-pushed on Apr 8, 2026
  9. mempool: recalculate stale BIP68 lockpoints with mempool parents in removeForReorg
    When a transaction with nSequence=0 (BIP68 relative locktime 0) enters
    the mempool with an unconfirmed parent, CalculatePrevHeights assigns
    nCoinHeight=tip+1 and the resulting LockPoints are cached with
    maxInputBlock=genesis. After invalidateblock lowers the tip,
    TestLockPointValidity returns true for genesis (always on chain),
    so the stale cached lockpoints are reused. CheckSequenceLocksAtTip
    then incorrectly determines the lock is not satisfied and removes
    the transaction along with all its descendants.
    
    Fix: in filter_final_and_mature, detect the genesis sentinel
    (maxInputBlock->nHeight==0 with lp.height>0) which indicates
    lockpoints computed with mempool parent inputs, and force fresh
    recalculation via CalculateLockPointsAtTip.
    
    This is the same class of issue fixed for TRUC in #33504.
    
    Closes #35007
    9dc0642ac5
  10. javierpmateos force-pushed on Apr 8, 2026
  11. instagibbs commented at 1:15 pm on April 8, 2026: member
    thanks for the PR. From my recollection this code is pretty complicated sadly. Will take a look soon hopefully to see if I can grasp it
  12. DrahtBot added the label CI failed on Apr 9, 2026
  13. DrahtBot removed the label CI failed on Apr 9, 2026

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-04-12 09:13 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me