Implement BIP 54 (Consensus Cleanup) without mainnet activation #35793

pull darosior wants to merge 20 commits into bitcoin:master from darosior:bip54 changing 37 files +6569 −114
  1. darosior commented at 2:18 PM on July 24, 2026: member

    This implements the Consensus Cleanup validation rules proposed in BIP 54. These rules are only enabled on regtest. Mainnet activation, if any, is to be considered separately.

    This patchset is based on the code that was previously reviewed (1, 2) and tested (for instance here) on Bitcoin Inquisition. The tests and documentation have since been improved, but the consensus-critical commits have been carried over with only minor differences (the only behavioural one being the addition of the stripped-size check to PreChecks).

    Roughly 95% of the added lines are tests or test data. The format, contents, and reproduction procedure for the BIP 54 test vectors are documented here. The bip54_tests unit test module exercises each mitigation extensively in isolation. The feature_bip54.py functional test verifies all of them end-to-end after and prior to activation. For the timestamp rules, it simulates timewarp and Murch–Zawy attacks, demonstrating the new timestamp rules prevent these exploits. A fuzz harness for the sigop accounting logic is also included, which can be seeded from the BIP test vectors (implemented here).

    See commit messages for details.

  2. DrahtBot commented at 2:18 PM on July 24, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

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

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/35793.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline and AI policy for information on the review process.

    Type Reviewers
    Concept ACK dergoegge, fanquake, polespinasa, theStack, hsjoberg

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #35657 (refactor: avoid redundant input lookup in CheckTxInputs by arejula27)
    • #35570 (refactor: Change some validation.cpp methods to return BlockValidationState by optout21)
    • #35569 (Encapsulation for CTransaction by purpleKarrot)
    • #35302 (Silent Payments: Sending (take 2) by Eunovo)
    • #35301 (Silent Payments: Implement bip352 (take 2) by Eunovo)
    • #34864 (coins: tighten cache entry state invariants by l0rinc)
    • #32729 (test, refactor: extract script template helpers and expand sigop coverage by l0rinc)
    • #32468 (rpc: generateblock to allow multiple outputs by polespinasa)
    • #28690 (build: Introduce internal kernel library by sedited)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  3. chainparams: add versionbits deployment for BIP 54 4a6b1c6ffb
  4. scripted-diff: rename BIP54-sigops constants to MAX_TX_BIP54_SIGOPS
    BIP54 counts sigops differently from existing sigops-based checks. Since
    we are overloading the sigops term, make clear the constant refers to
    BIP54-sigops, not other kinds of pre-existing sigops.
    
    Also update the functional test framework's constant that has
    "standardness" in its name, since we are about to make it consensus
    critical (func test scripted-diff courtesy of Anthony Towns).
    
    -BEGIN VERIFY SCRIPT-
    sed -i 's/MAX_TX_LEGACY_SIGOPS/MAX_TX_BIP54_SIGOPS/g' $(git grep -l MAX_TX_LEGACY_SIGOPS src/)
    sed -i 's/MAX_STD_LEGACY_SIGOPS/MAX_TX_BIP54_SIGOPS/g' $(git grep -l MAX_STD_LEGACY_SIGOPS)
    sed -i 's/signature operations in validating a transaction./signature operations in a single transaction, per BIP54./' test/functional/test_framework/script_util.py
    -END VERIFY SCRIPT-
    
    Co-Authored-by: Anthony Towns <aj@erisian.com.au>
    9fb74e75d0
  5. moveonly: move CheckSigopsBIP54 from policy to consensus
    Move the function that checks whether a transaction respects the BIP54 sigops rule to the
    consensus folder (along with the accompanying constant), as it will be made consensus-critical
    in the next commit. Can be reviewed with git's --color-moved option.
    9ccf729e75
  6. validation: make BIP54 sigops check consensus-critical
    When BIP54 is active, enforce that block transactions do not violate the BIP54 limit on the
    number of legacy sigops present in Scripts that get executed during block validation.
    39cca6c97e
  7. qa: add to utilities a version of SignSignature for Taproot inputs
    In Taproot the signature commits to the list of spent outputs.
    16d8f7c502
  8. darosior force-pushed on Jul 24, 2026
  9. qa: extensive unit tests for BIP54 legacy sigops limit
    Test the newly introduced limit with various combinations of inputs and outputs types,
    historical transactions, and exercise some implementation-specific edge cases. Record
    each test case and optionally write them to disk as JSON to generate the BIP test vectors.
    d75143d393
  10. fuzz: add a fuzz target for the BIP54 sigops check
    The fuzz target was specifically crafted to support seeding it with the BIP54 test vectors
    generated by the unit test in the previous commit.
    243e7a7623
  11. scripted-diff: rename testnet4 timewarp constant
    We are going to introduce the timewarp fix for mainnet with a greater grace period. Rename
    the MAX_TIMEWARP value for testnet to differentiate them.
    
    -BEGIN VERIFY SCRIPT-
    
    for f in $(git grep -l MAX_TIMEWARP); do sed -i "s/MAX_TIMEWARP/MAX_TIMEWARP_TESTNET4/g" "$f"; done
    
    -END VERIFY SCRIPT-
    43f1b9471b
  12. miner: update a timewarp comment to refer specifically to BIP 54 6a10f77ef5
  13. validation: prevent timewarp attacks with a 2h grace period d96b2c79dc
  14. validation: prevent negative difficulty adjustment intervals 8795625242
  15. qa: BIP54 test vectors for timewarp and Murch-Zawy
    Documentation about the test vectors, including about their structure and content, as well as
    reproduction instructions, is available here: https://github.com/bitcoin/bips/tree/master/bip-0054/test_vectors
    da0b9ecf05
  16. validation: enforce that coinbase transactions are timelocked to block height
    When BIP 54 is active, coinbase transactions must have their nLockTime field set to the block height
    minus 1 (since it encodes the last height at which the transaction is invalid), and their nSequence
    field may be anything but the maximum value (which indicates "final", bypassing timelock
    validation).
    87b003f19d
  17. qa: BIP54 test vectors for restrictions on coinbase transactions
    Documentation about the test vectors' structure and content, as well as instructions for generating
    them is available at https://github.com/bitcoin/bips/tree/master/bip-0054/test_vectors .
    534d4766d1
  18. Avoid creating <= 64-byte transactions in most functional tests. e5c1b4aae9
  19. [test] Separate 64B and 63B tx size tests 32bfb7b6e1
  20. validation: make 64-byte transactions invalid
    64-byte transactions are also now treated as a consensus failure in
    PreChecks, like BIP54-sigops check failures. Note this only changes the
    RPC error, and not the disconnection behaviour in P2P since
    266dd0e10d08c0bfde63205db15d6c210a021b90.
    b1ec5a6f4f
  21. qa: unit tests for BIP54 rule on 64-byte transactions (with JSON test vectors)
    This adds tests exercising the bounds of the checks on the invalid transaction size, for various
    types of transactions (legacy, Segwit, bytes in input/output to get to 64 bytes) as well as
    sanity checking against some known historical violations.
    
    Thanks to Chris Stewart for digging up the historical violations to this rule.
    0719bf5164
  22. qa: end-to-end test all BIP54 mitigations
    The previously introduced unit tests extensively test the specific implementation of each
    mitigation. This functional test complements them by end-to-end testing all mitigations.
    For the added timestamp constraints, it mimicks how they would get exploited (by implementing pseudo
    timewarp and Murch-Zawy attacks) and demonstrates those exploits are not possible anymore after
    BIP54 activates.
    0acde965fa
  23. doc: add a BIP 54 entry to bips.md 9630491bf2
  24. DrahtBot added the label CI failed on Jul 24, 2026
  25. DrahtBot commented at 2:43 PM on July 24, 2026: contributor

    <!--85328a0da195eb286784d51f73fa0af9-->

    🚧 At least one of the CI tasks failed. <sub>Task macOS native: https://github.com/bitcoin/bitcoin/actions/runs/30100472888/job/89504946717</sub> <sub>LLM reason (✨ experimental): CI failed because bip54_tests aborted on an assertion failure in CExtKey::SetSeed (seed.size() was outside the expected 16–64 byte range) during bip54_legacy_sigops.</sub>

    <details><summary>Hints</summary>

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

    </details>

  26. DrahtBot removed the label CI failed on Jul 24, 2026
  27. Christewart commented at 5:49 PM on July 24, 2026: contributor

    Congrats! Excited to see this work make it to this point 🎉

  28. in src/consensus/consensus.h:44 in 9630491bf2
      40 |   */
      41 | -static constexpr int64_t MAX_TIMEWARP = 600;
      42 | +static constexpr int64_t MAX_TIMEWARP_TESTNET4 = 600;
      43 | +
      44 | +/** The maximum number of potentially executed legacy signature operations in a single tx */
      45 | +static constexpr unsigned int MAX_TX_BIP54_SIGOPS{2'500};
    


    ariard commented at 2:38 AM on July 29, 2026:

    there could be a definition of what is understood as a "legacy signature ops" even if it's just echoing the bip doc, it's consensus/consensus.h where one can reasonably expect to find the definition of a "legacy signature" in opposition to signatures included in the witness for SegWit spends.

  29. in src/consensus/tx_verify.cpp:176 in 9630491bf2
     172 | +
     173 | +        // Unlike the existing block wide sigop limit which counts sigops present in the block
     174 | +        // itself (including the scriptPubKey which is not executed until spending later), BIP54
     175 | +        // counts sigops in the block where they are potentially executed (only).
     176 | +        // This means sigops in the spent scriptPubKey count toward the limit.
     177 | +        // `fAccurate` means correctly accounting sigops for CHECKMULTISIGs(VERIFY) with 16 pubkeys
    


    ariard commented at 2:49 AM on July 29, 2026:

    i was reading again the BIP part on the new CheckSigops limit and the computation price for each type of legacy checksig operations, i.e CHECKSIG counts as 1 signature operation, CHECKMULTISIG as 1 to 16 signature operation and (empty) CHECKMULTISIG as 20 signatures operation.

    the asymmetry between OP_1 CHECKMULTISIG and (empty) CHECKMULTISIG sounds striking as the vbyte cost of a single CHECKMULTISIG is going to be 1 vbyte and the fee cost of a OP_1 CHECKMULTISIG, so in any collaborative txn among multi parties, one can force the tx to reach the new 2500 limit at a vbyte cost inferior rather than putting a OP_1 CHECKMULTISIG coming with a higher absolute vbyte cost, whatever the feerate.

    curious if there is any rational somewhere in all the design notes, that's explaining that choice for the asymmetry in the legacy signature accounting for CHECKMULTISIG

  30. ariard commented at 2:50 AM on July 29, 2026: none

    Let's start at least the review for the fix of the long validation block time.

  31. dergoegge commented at 2:25 PM on July 29, 2026: member

    Concept ACK

  32. fanquake commented at 10:20 AM on July 30, 2026: member

    Concept ACK

  33. polespinasa commented at 10:50 AM on July 30, 2026: member

    Concept ACK

  34. theStack commented at 12:41 PM on July 30, 2026: contributor

    Concept ACK

  35. hsjoberg commented at 12:50 PM on July 30, 2026: contributor

    Concept ACK


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-07-31 20:50 UTC

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