{
 "number": 35793,
 "repo": "bitcoin/bitcoin",
 "url": "https://github.com/bitcoin/bitcoin/pull/35793",
 "title": "Implement BIP 54 (Consensus Cleanup) without mainnet activation",
 "author": "darosior",
 "author_association": "MEMBER",
 "created_at": "2026-07-24T14:18:35Z",
 "updated_at": "2026-09-15T11:40:49Z",
 "age_days": 55,
 "draft": false,
 "labels": [],
 "milestone": null,
 "base": "master",
 "head_sha": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
 "head_ref": "bip54",
 "head_repo": "darosior/bitcoin",
 "head_history": [
  {
   "t": "2026-07-24T14:43:18Z",
   "sha": "9630491bf2135d03dac586d3492cfca9939f6fbb"
  },
  {
   "t": "2026-08-24T10:43:16Z",
   "sha": "d4cfdf4214ee6b6170c67c59cad601a0f03ac6ca"
  },
  {
   "t": "2026-09-02T13:52:38Z",
   "sha": "f263592c90d687d57143a11a9671fd53476b79d4"
  },
  {
   "t": "2026-09-13T21:00:28Z",
   "sha": "d6c94c86169d315ef552916387bb8d0066ed7324"
  },
  {
   "t": "2026-09-13T21:03:46Z",
   "sha": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50"
  }
 ],
 "additions": 6584,
 "deletions": 123,
 "changed_files": 39,
 "commit_count": 22,
 "size_bucket": "XL",
 "mergeable_state": "clean",
 "bot": {
  "drahtbot": {
   "present": true,
   "reviews": {
    "concept_ack": [
     {
      "login": "dergoegge",
      "url": "https://github.com/bitcoin/bitcoin/pull/35793#issuecomment-5119091655"
     },
     {
      "login": "fanquake",
      "url": "https://github.com/bitcoin/bitcoin/pull/35793#issuecomment-5129574217"
     },
     {
      "login": "polespinasa",
      "url": "https://github.com/bitcoin/bitcoin/pull/35793#issuecomment-5129880443"
     },
     {
      "login": "theStack",
      "url": "https://github.com/bitcoin/bitcoin/pull/35793#issuecomment-5130931898"
     },
     {
      "login": "hsjoberg",
      "url": "https://github.com/bitcoin/bitcoin/pull/35793#issuecomment-5131035474"
     },
     {
      "login": "fjahr",
      "url": "https://github.com/bitcoin/bitcoin/pull/35793#issuecomment-5153062504"
     },
     {
      "login": "stickies-v",
      "url": "https://github.com/bitcoin/bitcoin/pull/35793#issuecomment-5220002904"
     }
    ]
   },
   "conflicts": [
    {
     "number": 36192,
     "title": "test: cover unsatisfiable mining timestamp",
     "author": "Sjors"
    },
    {
     "number": 35570,
     "title": "refactor: Change some validation.cpp methods to return BlockValidationState",
     "author": "optout21"
    },
    {
     "number": 35569,
     "title": "Encapsulation for CTransaction",
     "author": "purpleKarrot"
    },
    {
     "number": 35511,
     "title": "RFC: consensus: Make `CAmount` a class",
     "author": "hodlinator"
    },
    {
     "number": 35301,
     "title": "Silent Payments: Implement bip352 (take 2)",
     "author": "Eunovo"
    },
    {
     "number": 34864,
     "title": "coins: tighten cache entry state invariants",
     "author": "l0rinc"
    },
    {
     "number": 32468,
     "title": "rpc: generateblock to allow multiple outputs",
     "author": "polespinasa"
    },
    {
     "number": 29491,
     "title": "[EXPERIMENTAL] Schnorr batch verification for blocks",
     "author": "fjahr"
    },
    {
     "number": 28690,
     "title": "build: Introduce internal kernel library",
     "author": "sedited"
    }
   ]
  }
 },
 "acks_parsed": {
  "dergoegge": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-07-29T14:25:55Z",
   "stale": false
  },
  "fanquake": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-07-30T10:20:53Z",
   "stale": false
  },
  "polespinasa": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-07-30T10:50:54Z",
   "stale": false
  },
  "theStack": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-07-30T12:41:23Z",
   "stale": false
  },
  "hsjoberg": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-07-30T12:50:45Z",
   "stale": false
  },
  "fjahr": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-08-01T19:31:35Z",
   "stale": false
  },
  "stickies-v": {
   "kind": "concept_ack",
   "hash": null,
   "t": "2026-08-07T17:16:12Z",
   "stale": false
  }
 },
 "acks_tally": {
  "ack": 0,
  "stale_ack": 0,
  "concept_ack": 7,
  "approach_ack": 0,
  "nack": 0,
  "concept_nack": 0,
  "approach_nack": 0
 },
 "reviews": {
  "approved": 0,
  "changes_requested": 0,
  "distinct_reviewers": [
   "Christewart",
   "ariard",
   "dergoegge",
   "fanquake",
   "fjahr",
   "hsjoberg",
   "l0rinc",
   "polespinasa",
   "stickies-v",
   "theStack"
  ]
 },
 "signals": {
  "needs_rebase": false,
  "ci_failed": false,
  "mergeable_state": "clean",
  "last_author_activity": "2026-09-13T21:05:01Z",
  "last_reviewer_activity": "2026-09-12T06:10:58Z",
  "last_reviewer": "polespinasa",
  "author_silent_days": 3,
  "waiting_on_author_days": 0,
  "days_since_update": 2
 },
 "refs": {
  "mentioned": [
   31376,
   33050,
   35949
  ],
  "depends_on": [],
  "fixes": [],
  "linked_issues": [],
  "references": [
   {
    "number": 31376,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2025-01-23",
    "title": "Miner: never create a template which exploits the timewarp bug"
   },
   {
    "number": 33050,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2025-08-12",
    "title": "net, validation: don't punish peers for consensus-invalid txs"
   },
   {
    "number": 35949,
    "type": "pull",
    "state": "closed",
    "merged": true,
    "merged_at": "2026-09-07",
    "title": "miner: Enforce Murch-Zawy rule (BIP54)"
   }
  ],
  "conflicts": [
   36192,
   35570,
   35569,
   35511,
   35301,
   34864,
   32468,
   29491,
   28690
  ]
 },
 "stack": {
  "shares_commits_with": [],
  "based_on": [],
  "base_for": []
 },
 "review_paths": [
  "src/consensus/consensus.h",
  "src/consensus/tx_verify.cpp",
  "src/kernel/chainparams.cpp",
  "src/node/miner.cpp",
  "src/test/fuzz/bip54.cpp",
  "src/validation.cpp",
  "test/functional/feature_bip54.py"
 ],
 "body": "This implements the Consensus Cleanup validation rules proposed in [BIP 54](https://github.com/bitcoin/bips/blob/master/bip-0054.md). These rules are only enabled on regtest. Mainnet activation, if any, is to be considered separately.\n\nThis patchset is based on the code that was previously reviewed ([1](https://github.com/bitcoin-inquisition/bitcoin/pull/99), [2](https://github.com/bitcoin-inquisition/bitcoin/pull/110)) and tested (for instance [here](https://delvingbitcoin.org/t/consensus-cleanup-demo-of-slow-blocks-on-signet/2367)) 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`).\n\nRoughly 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](https://github.com/bitcoin/bips/tree/master/bip-0054/test_vectors). 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\u2013Zawy 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](https://github.com/darosior/bitcoin/tree/bip54_seed_fuzz_corpus)).\n\nSee commit messages for details.",
 "commits": [
  {
   "sha": "030ca98df23d06b3a43f52aad3199491b3d01719",
   "date": "2026-09-11T22:53:54Z",
   "message": "chainparams: add versionbits deployment for BIP 54"
  },
  {
   "sha": "31e62fcf787610868b1c682cf6bcc760e0e0d58c",
   "date": "2026-09-11T22:53:54Z",
   "message": "scripted-diff: rename BIP54-sigops constants to MAX_TX_BIP54_SIGOPS\n\nBIP54 counts sigops differently from existing sigops-based checks. Since\nwe are overloading the sigops term, make clear the constant refers to\nBIP54-sigops, not other kinds of pre-existing sigops.\n\nAlso update the functional test framework's constant that has\n\"standardness\" in its name, since we are about to make it consensus\ncritical (func test scripted-diff courtesy of Anthony Towns).\n\n-BEGIN VERIFY SCRIPT-\nsed -i 's/MAX_TX_LEGACY_SIGOPS/MAX_TX_BIP54_SIGOPS/g' $(git grep -l MAX_TX_LEGACY_SIGOPS src/)\nsed -i 's/MAX_STD_LEGACY_SIGOPS/MAX_TX_BIP54_SIGOPS/g' $(git grep -l MAX_STD_LEGACY_SIGOPS)\nsed -i 's/signature operations in validating a transaction./signature operations in a single transaction, per BIP54./' test/functional/test_framework/script_util.py\n-END VERIFY SCRIPT-\n\nCo-Authored-by: Anthony Towns <aj@erisian.com.au>"
  },
  {
   "sha": "cf3dfbdb558cdf42c3bd782b7082ddd966c4b341",
   "date": "2026-09-11T22:53:54Z",
   "message": "moveonly: move CheckSigopsBIP54 from policy to consensus\n\nMove the function that checks whether a transaction respects the BIP54 sigops rule to the\nconsensus folder (along with the accompanying constant), as it will be made consensus-critical\nin the next commit. Can be reviewed with git's --color-moved option."
  },
  {
   "sha": "4a72c14bc226206ed54ae9947c6eae9bd5161a6c",
   "date": "2026-09-11T22:53:54Z",
   "message": "consensus: clarify legacy sigops means non-segwit sigops"
  },
  {
   "sha": "730806f8d99bfd609f9b35eb36f203e886a3cdde",
   "date": "2026-09-13T21:05:01Z",
   "message": "qa: use valid BIP 54 blocks to test \"bad-blk-sigops\" in p2p_segwit.py\n\nCommit 6e60c362bc1e373a284911381e2a513f57f5f26b introduced a test using\nBIP54-invalid blocks to test legacy sigops accounting. This commit\nupdates this test to break down the outputs spent in multiple\ntransactions, in order to make the test BIP 54 valid. Failing that, the\nfollowing commit would change the failure reason from \"bad-blk-sigops\"\nto \"bad-txns-legacy-sigops\"."
  },
  {
   "sha": "ed788adeaff9678010e9f23a1bab7e89e5b954a9",
   "date": "2026-09-13T21:05:01Z",
   "message": "validation: make BIP54 sigops check consensus-critical\n\nWhen BIP54 is active, enforce that block transactions do not violate the BIP54 limit on the\nnumber of legacy sigops present in Scripts that get executed during block validation.\n\nNote how the BIP 54 sigops check can't be bypassed anymore in the mempool with -acceptnonstdtxn.\nFurthermore, a BIP 54 failure now always returns `TxValidationResult::TX_CONSENSUS`. It could be\npossible to preserve the `TxValidationResult::TX_INPUTS_NOT_STANDARD` error prior to activation\ninstead. But it would diverge more from the code tested on Bitcoin Inquisition and introduce\ncomplexity for little benefits: the error is not used for disconnection decisions anymore, and is\nnot exposed to users in RPC errors. Hence, we prefer not to."
  },
  {
   "sha": "36e4c649bd7dfe419fa241be2336d161776d2f2f",
   "date": "2026-09-13T21:05:01Z",
   "message": "qa: add to utilities a version of SignSignature for Taproot inputs\n\nIn Taproot the signature commits to the list of spent outputs."
  },
  {
   "sha": "65b2c1d91d0ce65e9f120a3bf07c1017d13ad6bd",
   "date": "2026-09-13T21:05:01Z",
   "message": "qa: extensive unit tests for BIP54 legacy sigops limit\n\nTest the newly introduced limit with various combinations of inputs and outputs types,\nhistorical transactions, and exercise some implementation-specific edge cases. Record\neach test case and optionally write them to disk as JSON to generate the BIP test vectors."
  },
  {
   "sha": "df70771a340ee39c634b06797ec02e2343dab77f",
   "date": "2026-09-13T21:05:01Z",
   "message": "fuzz: add a fuzz target for the BIP54 sigops check\n\nThe fuzz target was specifically crafted to support seeding it with the BIP54 test vectors\ngenerated by the unit test in the previous commit."
  },
  {
   "sha": "8bfc8ed26903ccd7da6e2e1301e4d3f29402c077",
   "date": "2026-09-13T21:05:01Z",
   "message": "scripted-diff: rename testnet4 timewarp constant\n\nWe are going to introduce the timewarp fix for mainnet with a greater grace period. Rename\nthe MAX_TIMEWARP value for testnet to differentiate them.\n\n-BEGIN VERIFY SCRIPT-\n\nfor f in $(git grep -l MAX_TIMEWARP); do sed -i \"s/MAX_TIMEWARP/MAX_TIMEWARP_TESTNET4/g\" \"$f\"; done\n\n-END VERIFY SCRIPT-"
  },
  {
   "sha": "a9485c0dfaeb7b0c96d4d4332a56c8a6c72b3fa6",
   "date": "2026-09-13T21:05:01Z",
   "message": "miner: update a timewarp comment to refer specifically to BIP 54"
  },
  {
   "sha": "8403a89be226d70ddfa1e01d2c8a08b0497ce55d",
   "date": "2026-09-13T21:05:01Z",
   "message": "validation: prevent timewarp attacks with a 2h grace period"
  },
  {
   "sha": "7358a105abacf3195bc19ddc8f3be284df83eefe",
   "date": "2026-09-13T21:05:01Z",
   "message": "validation: prevent negative difficulty adjustment intervals"
  },
  {
   "sha": "9ff7219143ab71e00fd4da432c14870145cca120",
   "date": "2026-09-13T21:05:01Z",
   "message": "qa: BIP54 test vectors for timewarp and Murch-Zawy\n\nDocumentation about the test vectors, including about their structure and content, as well as\nreproduction instructions, is available here: https://github.com/bitcoin/bips/tree/master/bip-0054/test_vectors"
  },
  {
   "sha": "66dfe9e60eeab1dae0ab00e92b176c6e5c395431",
   "date": "2026-09-13T21:05:01Z",
   "message": "validation: enforce that coinbase transactions are timelocked to block height\n\nWhen BIP 54 is active, coinbase transactions must have their nLockTime field set to the block height\nminus 1 (since it encodes the last height at which the transaction is invalid), and their nSequence\nfield may be anything but the maximum value (which indicates \"final\", bypassing timelock\nvalidation)."
  },
  {
   "sha": "0d039290b8e9c1f5e35f5ef28c0a28e999dbb363",
   "date": "2026-09-13T21:05:01Z",
   "message": "qa: BIP54 test vectors for restrictions on coinbase transactions\n\nDocumentation about the test vectors' structure and content, as well as instructions for generating\nthem is available at https://github.com/bitcoin/bips/tree/master/bip-0054/test_vectors ."
  },
  {
   "sha": "a380674f59552742564dcd5d9c1b144814bcfc0c",
   "date": "2026-09-13T21:05:01Z",
   "message": "Avoid creating <= 64-byte transactions in most functional tests."
  },
  {
   "sha": "a3e8a36926f7856b76bd70f3a0733ccce1352506",
   "date": "2026-09-13T21:05:01Z",
   "message": "[test] Separate 64B and 63B tx size tests"
  },
  {
   "sha": "be26f65701cb3563bcbfde04929a402988a6c7e0",
   "date": "2026-09-13T21:05:01Z",
   "message": "validation: make 64-byte transactions invalid\n\n64-byte transactions are also now treated as a consensus failure in\nPreChecks, like BIP54-sigops check failures. Note this only changes the\nRPC error, and not the disconnection behaviour in P2P since\n266dd0e10d08c0bfde63205db15d6c210a021b90."
  },
  {
   "sha": "22b5b4f177a0677e1036bec0fe22a75c0aea64ec",
   "date": "2026-09-13T21:05:01Z",
   "message": "qa: unit tests for BIP54 rule on 64-byte transactions (with JSON test vectors)\n\nThis adds tests exercising the bounds of the checks on the invalid transaction size, for various\ntypes of transactions (legacy, Segwit, bytes in input/output to get to 64 bytes) as well as\nsanity checking against some known historical violations.\n\nThanks to Chris Stewart for digging up the historical violations to this rule."
  },
  {
   "sha": "1c61ceb3d90a434693fa2620af51c2a37a81350b",
   "date": "2026-09-13T21:05:01Z",
   "message": "qa: end-to-end test all BIP54 mitigations\n\nThe previously introduced unit tests extensively test the specific implementation of each\nmitigation. This functional test complements them by end-to-end testing all mitigations.\nFor the added timestamp constraints, it mimicks how they would get exploited (by implementing pseudo\ntimewarp and Murch-Zawy attacks) and demonstrates those exploits are not possible anymore after\nBIP54 activates."
  },
  {
   "sha": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "date": "2026-09-13T21:05:01Z",
   "message": "doc: add a BIP 54 entry to bips.md"
  }
 ],
 "timeline": [
  {
   "t": "2026-07-24T14:43:18Z",
   "kind": "force_push",
   "who": "darosior",
   "commit": "9630491bf2135d03dac586d3492cfca9939f6fbb"
  },
  {
   "t": "2026-07-24T17:49:56Z",
   "kind": "comment",
   "who": "Christewart",
   "assoc": "CONTRIBUTOR",
   "text": "Congrats! Excited to see this work make it to this point \ud83c\udf89"
  },
  {
   "t": "2026-07-29T02:38:02Z",
   "kind": "review_comment",
   "who": "ariard",
   "assoc": "CONTRIBUTOR",
   "path": "src/consensus/consensus.h",
   "commit": "9630491bf2135d03dac586d3492cfca9939f6fbb",
   "in_reply_to": null,
   "text": "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."
  },
  {
   "t": "2026-07-29T02:49:50Z",
   "kind": "review_comment",
   "who": "ariard",
   "assoc": "CONTRIBUTOR",
   "path": "src/consensus/tx_verify.cpp",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": null,
   "text": "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.\n\nthe 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.\n\ncurious 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`"
  },
  {
   "t": "2026-07-29T02:50:48Z",
   "kind": "review",
   "who": "ariard",
   "assoc": "CONTRIBUTOR",
   "state": "COMMENTED",
   "commit": "9630491bf2135d03dac586d3492cfca9939f6fbb",
   "text": "Let's start at least the review for the fix of the long validation block time."
  },
  {
   "t": "2026-07-29T14:25:55Z",
   "kind": "comment",
   "who": "dergoegge",
   "assoc": "MEMBER",
   "text": "Concept ACK"
  },
  {
   "t": "2026-07-30T10:20:53Z",
   "kind": "comment",
   "who": "fanquake",
   "assoc": "MEMBER",
   "text": "Concept ACK"
  },
  {
   "t": "2026-07-30T10:50:54Z",
   "kind": "comment",
   "who": "polespinasa",
   "assoc": "MEMBER",
   "text": "Concept ACK"
  },
  {
   "t": "2026-07-30T12:41:23Z",
   "kind": "comment",
   "who": "theStack",
   "assoc": "MEMBER",
   "text": "Concept ACK"
  },
  {
   "t": "2026-07-30T12:50:45Z",
   "kind": "comment",
   "who": "hsjoberg",
   "assoc": "CONTRIBUTOR",
   "text": "Concept ACK"
  },
  {
   "t": "2026-07-31T20:22:22Z",
   "kind": "review_comment",
   "who": "darosior",
   "assoc": "MEMBER",
   "path": "src/consensus/consensus.h",
   "commit": "9630491bf2135d03dac586d3492cfca9939f6fbb",
   "in_reply_to": 3670568708,
   "text": "Ok, i can replace with \"non-Segwit signature operations\". I've also checked all other instances of \"legacy\" in the diff here, and it's only used in tests, where the term is already present and i think fine to use."
  },
  {
   "t": "2026-08-01T19:31:35Z",
   "kind": "comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "text": "Concept ACK"
  },
  {
   "t": "2026-08-03T08:36:28Z",
   "kind": "review_comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "path": "src/node/miner.cpp",
   "commit": "f263592c90d687d57143a11a9671fd53476b79d4",
   "in_reply_to": null,
   "text": "The miner currently does not enforce the murch-zawy rule but I think it should. Suggested change along with a test: https://github.com/fjahr/bitcoin/commit/edbc841eb546b1c1c41cc6ed16021ddd7adb7b29"
  },
  {
   "t": "2026-08-03T14:28:15Z",
   "kind": "review_comment",
   "who": "darosior",
   "assoc": "MEMBER",
   "path": "src/node/miner.cpp",
   "commit": "f263592c90d687d57143a11a9671fd53476b79d4",
   "in_reply_to": 3702441350,
   "text": "I considered it for #31376 and decided against because it's strictly theoretical. But your patch looks good. Could you PR it to master? This one is already large, and i think that commit can be merged on its own."
  },
  {
   "t": "2026-08-04T21:24:05Z",
   "kind": "review_comment",
   "who": "darosior",
   "assoc": "MEMBER",
   "path": "src/consensus/tx_verify.cpp",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": 3670609391,
   "text": "Absolutely, the rationale is to reuse BIP 16 accounting, instead of introducing another opcode counting method in consensus rules."
  },
  {
   "t": "2026-08-06T21:52:40Z",
   "kind": "review_comment",
   "who": "l0rinc",
   "assoc": "MEMBER",
   "path": "src/kernel/chainparams.cpp",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": null,
   "text": "[quoted text omitted]\n\nI understand that the BIP mentions 2016/2015 because it describes mainnet's adjustment period. Since this PR applies the deployment only to regtest by default, could we adjust the BIP text, or add a note here to clarify that these values are derived from the network's adjustment period rather than fixed constants?"
  },
  {
   "t": "2026-08-07T17:16:12Z",
   "kind": "comment",
   "who": "stickies-v",
   "assoc": "MEMBER",
   "text": "Concept ACK"
  },
  {
   "t": "2026-08-08T01:47:13Z",
   "kind": "review_comment",
   "who": "ariard",
   "assoc": "CONTRIBUTOR",
   "path": "test/functional/feature_bip54.py",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": null,
   "text": "there could be a test for the case where the tx has `2501 sigops` and as such is invalid per BIP54 new rule. to demonstrate the code is **not** doing < 2500 => good ; 2500 => not good ; > 2500 => good.\n\nthere might be a test for it elsewhere for the exact test vector. good to have it in the python framework."
  },
  {
   "t": "2026-08-08T01:57:28Z",
   "kind": "review_comment",
   "who": "ariard",
   "assoc": "CONTRIBUTOR",
   "path": "src/test/fuzz/bip54.cpp",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": null,
   "text": "i would check the test before if it's covered though getting tortuous and valid control flow redeemScript with 10-depth OP_IF then the OP_CHECKSIG, then 10-depth OP_ENDIF, or with OP_ELSE to exerciser the consensus sigops script parser. not guarantee the fuzzer randomness might never yield a structured script for nested control flow."
  },
  {
   "t": "2026-08-08T02:03:37Z",
   "kind": "review_comment",
   "who": "ariard",
   "assoc": "CONTRIBUTOR",
   "path": "src/validation.cpp",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": null,
   "text": "should this check be reflected in `getblocktemplate` given it's already caring about \"sigoplimit\", \"weightlimit\" etc. not infringing tx should be selected in the template and yield back in the template.\n\nnow of course, this check is enforced at tx mempool processing, so it should never appear in the template *already*, though having a sanitization check in `getblocktemplate` might good.\n\nand there is the more transient aspect, than until BIP54 is activated a block is legit to have an infringing tx, even if it has been deployed as policy, though once it's activated, it should not be okay anymore (so don't go to produce an invalid block for the boundary block)."
  },
  {
   "t": "2026-08-08T02:05:02Z",
   "kind": "review_comment",
   "who": "ariard",
   "assoc": "CONTRIBUTOR",
   "path": "src/validation.cpp",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": 3739725399,
   "text": "in fact it's a dumb nuisance attack vector for the few transition blocks during activation if the miners are running \"lax\" mempools. a tx might be okay at mempool reception, is stuck in the mempools, and even after few blocks is selected in a template rendering it invalid."
  },
  {
   "t": "2026-08-08T02:06:01Z",
   "kind": "review",
   "who": "ariard",
   "assoc": "CONTRIBUTOR",
   "state": "COMMENTED",
   "commit": "9630491bf2135d03dac586d3492cfca9939f6fbb",
   "text": "Did a 1st read of the fix for long block validation time, I'll continue after the vacation.\n\nFaut pas deconner c'est le mois d'aout."
  },
  {
   "t": "2026-08-08T02:25:35Z",
   "kind": "review_comment",
   "who": "ariard",
   "assoc": "CONTRIBUTOR",
   "path": "src/consensus/tx_verify.cpp",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": 3670609391,
   "text": "@darosior So I'm saying this because in fact before the fix for this class of vulnerabilities: https://bitcoincore.org/en/2025/10/24/disclose-cve-2025-46598/ one could have abuse the new 2500 sigops rule, at a lower marginal feerate cost.\n\nBefore https://github.com/bitcoin/bitcoin/pull/33050 a tx could have been executed twice, the first with standardness rule, the second with consensus check. An attacker could have done a marginal attack, where the tx would have had a huge OP_SHA256 element to hash and the minimal number of accounted for 20 OP_CHECKMULTISIG.\n\nTherefore the transaction would have failed a first time on the standard check and then a second time on the consensus check with a reduced liquidity cost for the attacker (due to the lower feerate surface). and there was easy way to optimize the attack.\n\nThis one of the attack I did mention [there](https://github.com/bitcoin/bips/pull/1800#issuecomment-2784299171) even if never went to communicate it properly. I might have still have the python test vectors I played with at the time. Somehow the 20 OP_CHECKMULTISIG is a compact trick to render a tx invalid with the minimal of tx surface."
  },
  {
   "t": "2026-08-10T18:38:43Z",
   "kind": "review_comment",
   "who": "darosior",
   "assoc": "MEMBER",
   "path": "src/consensus/tx_verify.cpp",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": 3670609391,
   "text": "I benchmarked the worst case processing time for various types of standard transactions back when i disclosed CVE-2025-46598. As far as i know the worst case for legacy transaction does not involve `OP_SHA256`. It does involve `OP_CHECKMULTISIG`, but not with the minimal amount of sigop accounted for (since you need it to actually do compute).\n\nI am not sure what you are trying to get at. Could your point be related to [this previous one](https://gnusha.org/pi/bitcoindev/e8d7baa0-5d96-4e41-8cb5-083742c61454n@googlegroups.com/) you raised on the list?"
  },
  {
   "t": "2026-08-10T19:01:36Z",
   "kind": "review_comment",
   "who": "darosior",
   "assoc": "MEMBER",
   "path": "src/kernel/chainparams.cpp",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": 3732075425,
   "text": "[quoted text omitted]\n\nI think your comment applies to the difficulty adjustment period values used by the timewarp and Murch-Zawy mitigations, not that commit (which sets a largely inconsequential dummy BIP 9 deployment for regtest), correct?\n\nSo i went and looked for a way to maybe clarify this for the code implementing those checks, but it's already pretty clear these values are derived from the network's adjustment period. [Timewarp](https://github.com/darosior/bitcoin/blob/9630491bf2135d03dac586d3492cfca9939f6fbb/src/validation.cpp#L4117-L4121):\n```cpp\n    // If the block is the first of a difficulty adjustment interval, check its timestamp against the previous\n    // one to prevent timewarp attacks (see BIP 54).\n    const int dai{static_cast<int>(consensusParams.DifficultyAdjustmentInterval())};\n    const bool is_first_block{nHeight % dai == 0};\n    if (is_first_block) {\n```\n[Murch-Zawy](https://github.com/darosior/bitcoin/blob/9630491bf2135d03dac586d3492cfca9939f6fbb/src/validation.cpp#L4134-L4140):\n```cpp\n    // Fix for the Murch-Zawy attack. See https://delvingbitcoin.org/t/zawy-s-alternating-timestamp-attack/1062 .\n    // TL;DR: the duration of a retarget period must not be negative or the difficulty adjustment limit may be exploited to unduly\n    // reduce difficulty similarly to the timewarp vulnerability. Along with the timewarp fix, this effectively makes retarget periods\n    // monotonic (modulo the timewarp fix grace period).\n    const bool is_last_block{nHeight % dai == dai - 1};\n    if (is_last_block && DeploymentActiveAfter(pindexPrev, chainman, Consensus::DEPLOYMENT_CONSENSUSCLEANUP)) {\n        int first_height{nHeight - dai + 1};\n```\n\nHappy to consider any improvement to the comments there."
  },
  {
   "t": "2026-08-10T19:35:02Z",
   "kind": "review_comment",
   "who": "darosior",
   "assoc": "MEMBER",
   "path": "test/functional/feature_bip54.py",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": 3739690020,
   "text": "Bound checking for sigops accounting is tested extensively in unit tests (d75143d39354d723c6a67a290dd03359841f2901). I think it makes more sense for the integration tests to check higher-level boundaries, like for instance activation periods, than duplicate those tests."
  },
  {
   "t": "2026-08-11T13:36:29Z",
   "kind": "review_comment",
   "who": "fjahr",
   "assoc": "MEMBER",
   "path": "src/node/miner.cpp",
   "commit": "f263592c90d687d57143a11a9671fd53476b79d4",
   "in_reply_to": 3702441350,
   "text": "Done now here: #35949"
  },
  {
   "t": "2026-08-11T15:43:26Z",
   "kind": "review_comment",
   "who": "darosior",
   "assoc": "MEMBER",
   "path": "src/validation.cpp",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": 3739725399,
   "text": "Yes, it's already an assumption we make that no invalid transaction make it to our mempool. Note how this commit changes two things in this regard:\n- The BIP 54 sigops check can't be bypassed anymore with `-acceptnonstdtxs`.\n- The mempool sanity checks now assert that it does not contain any transaction that violates the BIP 54 sigops rule."
  },
  {
   "t": "2026-08-12T21:59:37Z",
   "kind": "review_comment",
   "who": "l0rinc",
   "assoc": "MEMBER",
   "path": "src/kernel/chainparams.cpp",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": 3732075425,
   "text": "Yes, added the code comment to that line simply to demonstrate that regtest has a different difficulty adjustment period than what's documented in the BIP itself:\n\n[quoted text omitted]\nThe code looks fine, was just wondering if we could update the BIP to make 2016 and 2015 variables, and in this PR draw attention to the fact that - strictly speaking - we're diverging from the BIP."
  },
  {
   "t": "2026-08-24T10:43:16Z",
   "kind": "force_push",
   "who": "darosior",
   "commit": "d4cfdf4214ee6b6170c67c59cad601a0f03ac6ca"
  },
  {
   "t": "2026-08-24T10:48:49Z",
   "kind": "review_comment",
   "who": "polespinasa",
   "assoc": "MEMBER",
   "path": "src/consensus/tx_verify.cpp",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": null,
   "text": "in 29d1f3fd458acf67830948707c483942dff56778 validation: make BIP54 sigops check consensus-critical\n\nThis signals the state as TX_CONSENSUS even if this is a policy check.\nDoes not affect in debug/log messages or the rejected reason message, but feels weird to miss-categorize it.\n\nIf we care about this, could set a three value struct{consensus, policy, ignore} and set the state according to it."
  },
  {
   "t": "2026-08-24T11:05:55Z",
   "kind": "review",
   "who": "polespinasa",
   "assoc": "MEMBER",
   "state": "COMMENTED",
   "commit": "d4cfdf4214ee6b6170c67c59cad601a0f03ac6ca",
   "text": "Did a swift first read to the code (skipping test code) while preparing for the PR review club.\nThe code looks pretty good, just left a comment. Will re-review again in more detail."
  },
  {
   "t": "2026-08-25T15:32:09Z",
   "kind": "review_comment",
   "who": "polespinasa",
   "assoc": "MEMBER",
   "path": "src/validation.cpp",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": null,
   "text": "in 67ebb0d57d9eaf4e1998733c8d818dafd0422791 validation: prevent timewarp attacks with a 2h grace period\n\nnit: `max_timewarp.has_value()` ?"
  },
  {
   "t": "2026-09-02T13:52:38Z",
   "kind": "force_push",
   "who": "darosior",
   "commit": "f263592c90d687d57143a11a9671fd53476b79d4"
  },
  {
   "t": "2026-09-09T23:52:49Z",
   "kind": "review_comment",
   "who": "ariard",
   "assoc": "CONTRIBUTOR",
   "path": "src/consensus/consensus.h",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": null,
   "text": "I think the description comment can be adjusted above to say it's only applied to testnet4 and not to signet, regtest, testnet3 (I guess from the `enforce_BIP94`)."
  },
  {
   "t": "2026-09-10T00:06:24Z",
   "kind": "review_comment",
   "who": "ariard",
   "assoc": "CONTRIBUTOR",
   "path": "src/consensus/consensus.h",
   "commit": "67ebb0d57d9eaf4e1998733c8d818dafd0422791",
   "in_reply_to": null,
   "text": "the comment could be \"strictly inferior\" which is more defined mathematically than \"must not be more than 2 hours\", where you never know if `=` is included, at least imho"
  },
  {
   "t": "2026-09-10T00:08:57Z",
   "kind": "review_comment",
   "who": "ariard",
   "assoc": "CONTRIBUTOR",
   "path": "src/validation.cpp",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": null,
   "text": "`BLOCK_INVALID_HEADER` comment in `src/consensus/validation.h` could be updated to include \"invalid proof of work or time too old\"."
  },
  {
   "t": "2026-09-10T00:09:45Z",
   "kind": "review",
   "who": "ariard",
   "assoc": "CONTRIBUTOR",
   "state": "COMMENTED",
   "commit": "f263592c90d687d57143a11a9671fd53476b79d4",
   "text": "started to review the timewarp fix."
  },
  {
   "t": "2026-09-10T00:16:20Z",
   "kind": "review_comment",
   "who": "ariard",
   "assoc": "CONTRIBUTOR",
   "path": "src/validation.cpp",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": 3739725399,
   "text": "Okay if `-acceptnonstdtxs` effect starts to kickoff as short as there is a release including this code, I think this is limiting the risk surface for transaction blocks that could violate the rule by accident.\n\nI'll re-check that."
  },
  {
   "t": "2026-09-10T00:25:40Z",
   "kind": "review_comment",
   "who": "ariard",
   "assoc": "CONTRIBUTOR",
   "path": "src/consensus/tx_verify.cpp",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": 3670609391,
   "text": "[quoted text omitted]\n\nNo it's something quite different. What I'm talking about in the present issue, it was relying on crafting small weight unit transaction to provoke the most of `OP_SHA256` (it's less expensive than sigs, but it's still consuming some CPU cycles) during a validation, and therefore the smallest cost.\n\nNote, it was strictly before #33050 that I did the test. It's not only the worst-case in CPU time to consider it's for a minimal mempool min fee, what's the average satoshis liquidity must avails to consume useless CPU cycles. I'll find back my notes on this and come back to you."
  },
  {
   "t": "2026-09-11T22:59:03Z",
   "kind": "review_comment",
   "who": "darosior",
   "assoc": "MEMBER",
   "path": "src/kernel/chainparams.cpp",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": 3732075425,
   "text": "I think the BIP should always optimize to be maximally clear for mainnet. When it does not affect clarity of the mainnet specifications, diverging values for public test networks may be integrated in the BIP (probably in a separate section). I don't think the values for a Bitcoin Core specific local test network should be mentioned in the BIP."
  },
  {
   "t": "2026-09-11T23:05:44Z",
   "kind": "review_comment",
   "who": "darosior",
   "assoc": "MEMBER",
   "path": "src/test/fuzz/bip54.cpp",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": 3739713347,
   "text": "What are you suggesting doing here? I agree code coverage guidance is sometimes lacking when fuzzing stateful logic. I think we can improve things a little with tweaks like Libfuzzer's extra counters. I had briefly looked into it in the past, and may pick it up in the future, but this improvement is largely orthogonal to this PR."
  },
  {
   "t": "2026-09-11T23:21:11Z",
   "kind": "review_comment",
   "who": "darosior",
   "assoc": "MEMBER",
   "path": "src/consensus/tx_verify.cpp",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": 3842747883,
   "text": "I went back and forth on this. I ended up picking the current version because the error type is not used to choose whether to disconnect a peer anymore, nor exposed to the user.\n\nMaking the error depend on the activation status would only change the error string on RPC errors from \"bad-txns-legacy-sigops\"/\"txn-size-64\" to \"bad-txns-nonstandard-inputs\"/\"tx-size-small\" prior to activation. I have implemented this in https://github.com/bitcoin-inquisition/bitcoin/pull/118 before, but ended up discarding it because i don't think it is worth introducing more complexity and divergence from what has been tested on Inquisition just for this.\n\nSee [this comment](https://github.com/bitcoin-inquisition/bitcoin/pull/118#issuecomment-5060191875) and the comments it links to for more details."
  },
  {
   "t": "2026-09-11T23:25:27Z",
   "kind": "review_comment",
   "who": "darosior",
   "assoc": "MEMBER",
   "path": "src/validation.cpp",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": 3854590246,
   "text": "If i did that it would make sense to change the dereference to a `max_timewarp.value()` as well and together it makes the line unnecessarily long, in my opinion.\n\nI did check and in the entire diff of this PR there is no use of `has_value()`/`value()`, so that change also can't be justified on consistency grounds.\n\nFor these reasons and because this is just a style nit, i'll keep it like that and resolve this comment."
  },
  {
   "t": "2026-09-12T06:10:58Z",
   "kind": "review_comment",
   "who": "polespinasa",
   "assoc": "MEMBER",
   "path": "src/consensus/tx_verify.cpp",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": 3842747883,
   "text": "Then a comment in the code could be usefull, to not create confusion with the `consensus` word"
  },
  {
   "t": "2026-09-13T19:39:14Z",
   "kind": "review_comment",
   "who": "darosior",
   "assoc": "MEMBER",
   "path": "src/consensus/consensus.h",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": 3974075397,
   "text": "The constant was renamed with a TESTNET4 a suffix with the purpose of making it clear it's only used for testnet4. I think adding it to the description too would be redundant because it already mentions BIP 94 (which defines BIP 94), and because it's in the name of the constant already."
  },
  {
   "t": "2026-09-13T19:54:10Z",
   "kind": "review_comment",
   "who": "darosior",
   "assoc": "MEMBER",
   "path": "src/consensus/consensus.h",
   "commit": "67ebb0d57d9eaf4e1998733c8d818dafd0422791",
   "in_reply_to": 3974142321,
   "text": "\"No more\" pretty explicitly means it can be equal, just not more. But fair enough, i updated the comment to use \"superior or equal\" language, and took the opportunity to define it positively \"must be superior or equal to\" rather than negatively \"must not be inferior or equal\"."
  },
  {
   "t": "2026-09-13T19:58:56Z",
   "kind": "review_comment",
   "who": "darosior",
   "assoc": "MEMBER",
   "path": "src/validation.cpp",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": 3974157444,
   "text": "This is already what the comment says:\nhttps://github.com/bitcoin/bitcoin/blob/17817818da3cb67c95320b7a5d4d69bd649c1fbf/src/consensus/validation.h#L68"
  },
  {
   "t": "2026-09-13T20:22:09Z",
   "kind": "review_comment",
   "who": "darosior",
   "assoc": "MEMBER",
   "path": "src/consensus/tx_verify.cpp",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
   "in_reply_to": 3842747883,
   "text": "Sure. I gave the rationale for this decision in the commit message though, because i could not find a satisfactory place where to put a comment about it."
  },
  {
   "t": "2026-09-13T20:58:18Z",
   "kind": "review_comment",
   "who": "darosior",
   "assoc": "MEMBER",
   "path": "src/node/miner.cpp",
   "commit": "f263592c90d687d57143a11a9671fd53476b79d4",
   "in_reply_to": 3702441350,
   "text": "Rebased now that #35949 is merged."
  },
  {
   "t": "2026-09-13T21:00:28Z",
   "kind": "force_push",
   "who": "darosior",
   "commit": "d6c94c86169d315ef552916387bb8d0066ed7324"
  },
  {
   "t": "2026-09-13T21:00:35Z",
   "kind": "comment",
   "who": "darosior",
   "assoc": "MEMBER",
   "text": "Addressed all outstanding comments and rebased on master. The most significant change is the modification of the test introduced in 6e60c362bc1e373a284911381e2a513f57f5f26b to use BIP54-valid blocks, prior to enforcing the sigops rule by consensus."
  },
  {
   "t": "2026-09-13T21:03:46Z",
   "kind": "force_push",
   "who": "darosior",
   "commit": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50"
  }
 ],
 "labels_log": [
  {
   "t": "2026-07-24T14:43:46Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-07-24T16:21:13Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-14T17:50:26Z",
   "action": "labeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-24T11:30:10Z",
   "action": "unlabeled",
   "label": "Needs rebase",
   "who": "DrahtBot"
  },
  {
   "t": "2026-08-24T12:21:56Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-09-02T15:37:17Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-09-13T21:04:19Z",
   "action": "labeled",
   "label": "CI failed",
   "who": "DrahtBot"
  },
  {
   "t": "2026-09-13T22:48:04Z",
   "action": "unlabeled",
   "label": "CI failed",
   "who": "DrahtBot"
  }
 ],
 "state_log": [],
 "text_chars": 21428,
 "text_tokens_estimate": 5357,
 "changed_paths": [
  "doc/bips.md",
  "src/CMakeLists.txt",
  "src/consensus/consensus.h",
  "src/consensus/params.h",
  "src/consensus/tx_verify.cpp",
  "src/consensus/tx_verify.h",
  "src/deploymentinfo.cpp",
  "src/kernel/chainparams.cpp",
  "src/node/miner.cpp",
  "src/policy/policy.cpp",
  "src/policy/policy.h",
  "src/rpc/blockchain.cpp",
  "src/test/CMakeLists.txt",
  "src/test/bip54_tests.cpp",
  "src/test/data/bip54_coinbases.json",
  "src/test/data/bip54_timestamps.json",
  "src/test/fuzz/CMakeLists.txt",
  "src/test/fuzz/bip54.cpp",
  "src/test/fuzz/coins_view.cpp",
  "src/test/transaction_tests.cpp",
  "src/test/util/transaction_utils.cpp",
  "src/test/util/transaction_utils.h",
  "src/txmempool.cpp",
  "src/validation.cpp",
  "test/functional/data/invalid_txs.py",
  "test/functional/feature_bip54.py",
  "test/functional/feature_block.py",
  "test/functional/feature_taproot.py",
  "test/functional/mempool_accept.py",
  "test/functional/mempool_sigoplimit.py",
  "test/functional/mining_basic.py",
  "test/functional/p2p_segwit.py",
  "test/functional/rpc_blockchain.py",
  "test/functional/rpc_getblockstats.py",
  "test/functional/test_framework/blocktools.py",
  "test/functional/test_framework/script_util.py",
  "test/functional/test_runner.py",
  "test/functional/wallet_ancient_migration.py",
  "test/functional/wallet_migration.py"
 ],
 "files": [
  {
   "path": "doc/bips.md",
   "add": 1,
   "del": 0
  },
  {
   "path": "src/CMakeLists.txt",
   "add": 1,
   "del": 1
  },
  {
   "path": "src/consensus/consensus.h",
   "add": 16,
   "del": 1
  },
  {
   "path": "src/consensus/params.h",
   "add": 1,
   "del": 0
  },
  {
   "path": "src/consensus/tx_verify.cpp",
   "add": 31,
   "del": 1
  },
  {
   "path": "src/consensus/tx_verify.h",
   "add": 7,
   "del": 1
  },
  {
   "path": "src/deploymentinfo.cpp",
   "add": 4,
   "del": 0
  },
  {
   "path": "src/kernel/chainparams.cpp",
   "add": 28,
   "del": 0
  },
  {
   "path": "src/node/miner.cpp",
   "add": 3,
   "del": 3
  },
  {
   "path": "src/policy/policy.cpp",
   "add": 1,
   "del": 36
  },
  {
   "path": "src/policy/policy.h",
   "add": 2,
   "del": 3
  },
  {
   "path": "src/rpc/blockchain.cpp",
   "add": 1,
   "del": 0
  },
  {
   "path": "src/test/CMakeLists.txt",
   "add": 3,
   "del": 0
  },
  {
   "path": "src/test/bip54_tests.cpp",
   "add": 1608,
   "del": 0
  },
  {
   "path": "src/test/data/bip54_coinbases.json",
   "add": 80,
   "del": 0
  },
  {
   "path": "src/test/data/bip54_timestamps.json",
   "add": 4134,
   "del": 0
  },
  {
   "path": "src/test/fuzz/CMakeLists.txt",
   "add": 1,
   "del": 0
  },
  {
   "path": "src/test/fuzz/bip54.cpp",
   "add": 54,
   "del": 0
  },
  {
   "path": "src/test/fuzz/coins_view.cpp",
   "add": 6,
   "del": 1
  },
  {
   "path": "src/test/transaction_tests.cpp",
   "add": 26,
   "del": 24
  },
  {
   "path": "src/test/util/transaction_utils.cpp",
   "add": 14,
   "del": 0
  },
  {
   "path": "src/test/util/transaction_utils.h",
   "add": 3,
   "del": 0
  },
  {
   "path": "src/txmempool.cpp",
   "add": 1,
   "del": 1
  },
  {
   "path": "src/validation.cpp",
   "add": 54,
   "del": 14
  },
  {
   "path": "test/functional/data/invalid_txs.py",
   "add": 17,
   "del": 3
  },
  {
   "path": "test/functional/feature_bip54.py",
   "add": 417,
   "del": 0
  },
  {
   "path": "test/functional/feature_block.py",
   "add": 9,
   "del": 1
  },
  {
   "path": "test/functional/feature_taproot.py",
   "add": 5,
   "del": 3
  },
  {
   "path": "test/functional/mempool_accept.py",
   "add": 1,
   "del": 1
  },
  {
   "path": "test/functional/mempool_sigoplimit.py",
   "add": 8,
   "del": 9
  },
  {
   "path": "test/functional/mining_basic.py",
   "add": 5,
   "del": 5
  },
  {
   "path": "test/functional/p2p_segwit.py",
   "add": 11,
   "del": 8
  },
  {
   "path": "test/functional/rpc_blockchain.py",
   "add": 13,
   "del": 0
  },
  {
   "path": "test/functional/rpc_getblockstats.py",
   "add": 3,
   "del": 0
  },
  {
   "path": "test/functional/test_framework/blocktools.py",
   "add": 4,
   "del": 2
  },
  {
   "path": "test/functional/test_framework/script_util.py",
   "add": 2,
   "del": 2
  },
  {
   "path": "test/functional/test_runner.py",
   "add": 1,
   "del": 0
  },
  {
   "path": "test/functional/wallet_ancient_migration.py",
   "add": 4,
   "del": 1
  },
  {
   "path": "test/functional/wallet_migration.py",
   "add": 4,
   "del": 2
  }
 ],
 "test_lines": 6495,
 "git": {
  "head": "0f4eb702510783f1fe018f86d2a3bbd81fdf3e50",
  "head_matches_backup": true,
  "base": "f3fec67c3eeb27d5be1bc9d57ca737b74fcd762d",
  "commits": [
   {
    "sha": "030ca98df2",
    "subject": "chainparams: add versionbits deployment for BIP 54",
    "files": 7,
    "add": 49,
    "del": 2
   },
   {
    "sha": "31e62fcf78",
    "subject": "scripted-diff: rename BIP54-sigops constants to MAX_TX_BIP54_SIGOPS",
    "files": 5,
    "add": 11,
    "del": 11
   },
   {
    "sha": "cf3dfbdb55",
    "subject": "moveonly: move CheckSigopsBIP54 from policy to consensus",
    "files": 6,
    "add": 37,
    "del": 33
   },
   {
    "sha": "4a72c14bc2",
    "subject": "consensus: clarify legacy sigops means non-segwit sigops",
    "files": 1,
    "add": 1,
    "del": 1
   },
   {
    "sha": "730806f8d9",
    "subject": "qa: use valid BIP 54 blocks to test \"bad-blk-sigops\" in p2p_segwit.py",
    "files": 1,
    "add": 11,
    "del": 8
   },
   {
    "sha": "ed788adeaf",
    "subject": "validation: make BIP54 sigops check consensus-critical",
    "files": 8,
    "add": 44,
    "del": 39
   },
   {
    "sha": "36e4c649bd",
    "subject": "qa: add to utilities a version of SignSignature for Taproot inputs",
    "files": 2,
    "add": 17,
    "del": 0
   },
   {
    "sha": "65b2c1d91d",
    "subject": "qa: extensive unit tests for BIP54 legacy sigops limit",
    "files": 2,
    "add": 1311,
    "del": 0
   },
   {
    "sha": "df70771a34",
    "subject": "fuzz: add a fuzz target for the BIP54 sigops check",
    "files": 2,
    "add": 55,
    "del": 0
   },
   {
    "sha": "8bfc8ed269",
    "subject": "scripted-diff: rename testnet4 timewarp constant",
    "files": 4,
    "add": 7,
    "del": 7
   },
   {
    "sha": "a9485c0dfa",
    "subject": "miner: update a timewarp comment to refer specifically to BIP 54",
    "files": 1,
    "add": 2,
    "del": 2
   },
   {
    "sha": "8403a89be2",
    "subject": "validation: prevent timewarp attacks with a 2h grace period",
    "files": 2,
    "add": 20,
    "del": 9
   },
   {
    "sha": "7358a105ab",
    "subject": "validation: prevent negative difficulty adjustment intervals",
    "files": 1,
    "add": 14,
    "del": 0
   },
   {
    "sha": "9ff7219143",
    "subject": "qa: BIP54 test vectors for timewarp and Murch-Zawy",
    "files": 3,
    "add": 4218,
    "del": 0
   },
   {
    "sha": "66dfe9e60e",
    "subject": "validation: enforce that coinbase transactions are timelocked to block height",
    "files": 6,
    "add": 35,
    "del": 6
   },
   {
    "sha": "0d039290b8",
    "subject": "qa: BIP54 test vectors for restrictions on coinbase transactions",
    "files": 3,
    "add": 126,
    "del": 0
   },
   {
    "sha": "a380674f59",
    "subject": "Avoid creating <= 64-byte transactions in most functional tests.",
    "files": 1,
    "add": 3,
    "del": 1
   },
   {
    "sha": "a3e8a36926",
    "subject": "[test] Separate 64B and 63B tx size tests",
    "files": 1,
    "add": 14,
    "del": 1
   },
   {
    "sha": "be26f65701",
    "subject": "validation: make 64-byte transactions invalid",
    "files": 6,
    "add": 25,
    "del": 8
   },
   {
    "sha": "22b5b4f177",
    "subject": "qa: unit tests for BIP54 rule on 64-byte transactions (with JSON test vectors)",
    "files": 1,
    "add": 170,
    "del": 0
   },
   {
    "sha": "1c61ceb3d9",
    "subject": "qa: end-to-end test all BIP54 mitigations",
    "files": 2,
    "add": 418,
    "del": 0
   },
   {
    "sha": "0f4eb70251",
    "subject": "doc: add a BIP 54 entry to bips.md",
    "files": 1,
    "add": 1,
    "del": 0
   }
  ],
  "patch_truncated": true
 },
 "input_hash": "65020d3ce0712e2d",
 "extracted_at": "2026-09-17T16:15:31+00:00"
}