{
 "number": 36521,
 "input_hash": "6494f632f7699f80",
 "model": "ledger",
 "prompt_hash": null,
 "created": "2026-10-30T01:14:11+00:00",
 "result": {
  "summary": "Replaces the internal storage of CScriptWitness from a vector of byte vectors with a single allocation storing its serialized wire format, decoding elements on the fly as spans and making witness stacks immutable after creation. Transaction deserialization is updated to immediately reject transactions claiming more inputs or outputs than could fit in a block before allocating vector storage. For P2P streams, deserialization also decrements a weight budget to reject blocks and transactions exceeding the maximum block weight limit and drops transactions with zero inputs or outputs.",
  "problem": "Holding witness stacks as nested vectors adds 24 bytes of object overhead and a distinct heap allocation for each element, allowing attackers to craft 4 MB blocks with millions of small elements that consume over 100 MiB of RAM and hundreds of milliseconds to deserialize. Furthermore, deserializing malformed transactions or blocks without pre-allocation limits permits peers to induce large memory allocations before validation rejects them.",
  "card": "CScriptWitness currently stores stack items as a vector of byte vectors, adding a 24-byte header and a separate heap allocation for each item. This allows peers to send 4 MB blocks that take over 100 MiB of memory and nearly 300 ms to deserialize. This PR changes CScriptWitness to store its serialized representation in a single allocation, decoding elements on the fly, and introduces early size and weight budget bounds during transaction and P2P block deserialization. Benchmarks show worst-case block memory dropping from 106.8 MiB to 3.8 MiB and deserialization times dropping by up to 93%.",
  "evidence": [
   "Description benchmarks show worst-case valid block deserialization time drops from 279 ms to 19 ms, with persisted block memory usage dropping from 106.8 MiB to 3.8 MiB and peak memory dropping from 182 MiB to 7.8 MiB.",
   "PR description notes the underlying vulnerability was reported by furszy and 0xB10C."
  ],
  "scope_notes": "Touches 76 files, but a substantial fraction is a scripted-diff refactor migrating direct .stack accesses to CScriptWitness accessor methods across tests and validation code, accompanied by dedicated deserialization benchmarks and fuzz targets.",
  "changed_since_previous": "Added deserialization pre-checks that reject transactions with more inputs or outputs than can physically fit in a block across all decoders, and introduced a 4M weight budget check during P2P message deserialization.",
  "thread": {
   "last_event_at": "2026-10-29T17:13:16Z",
   "events": 11,
   "head_sha": "bd512269956afe1baa692d9893e68500356a859e",
   "schema_floor": 2,
   "schema": 2
  },
  "waiting_on": [
   {
    "at": "2026-10-25",
    "id": "c:6395031310",
    "on": "author",
    "url": "https://github.com/bitcoin/bitcoin/pull/36521#issuecomment-6395031310",
    "what": "response or fix for fametrano's allocation regression concern in VerifyWitnessProgram"
   },
   {
    "at": "2026-10-29",
    "id": "c:6503407615",
    "on": "author",
    "url": "https://github.com/bitcoin/bitcoin/pull/36521#issuecomment-6503407615",
    "what": "response to purpleKarrot's approach objection and NACK"
   }
  ],
  "risk": {
   "level": "high",
   "touches": [
    "consensus",
    "validation",
    "p2p"
   ],
   "why": "Altering witness serialization and adding early deserialization rejection could cause nodes to reject valid transactions or blocks, leading to chain splits or network partitions."
  },
  "discussion": {
   "author_status": "last statement processed 2026-10-29",
   "open_concerns": [
    "fametrano: VerifyWitnessProgram calls witness.ToVectors() before checking the witness version, causing a 91 MiB allocation and verification slowdown for unknown witness versions",
    "purpleKarrot: Touching 76 files with 1000+ lines for an interim data layout before localizing transaction access introduces unnecessary churn instead of first abstracting data access"
   ],
   "resolved_concerns": [
    "Yudis-bit: Avoid heap allocations in IsWitnessStandard for Taproot inputs by checking witness size and the last element before calling ToSpans (accepted by Yudis-bit 2026-10-20)",
    "Yudis-bit: Iterate directly over scriptWitness with a counter in the P2WSH check to avoid allocating a vector of spans (accepted by Yudis-bit 2026-10-20)"
   ]
  },
  "reviewability": {
   "state": "Ready",
   "label": "Needs rebase",
   "reason": "Conflicts with master; review the logic now, the rebase is mechanical."
  },
  "agreement": {
   "state": "Blocked",
   "summary": "Blocked: objection that needs a change, nobody has replied (fametrano, purpleKarrot)",
   "reason": "Added purpleKarrot's approach objection/NACK questioning widespread code changes across 76 files prior to completing transaction abstraction work.",
   "evidence": [
    "fametrano (objection, approach, must be changed, open): VerifyWitnessProgram calls witness.ToVectors() before checking the witness version, causing a 91 MiB allocation and verification slowdown for unknown witness versions",
    "purpleKarrot (objection, approach, must be changed, open): Touching 76 files with 1000+ lines for an interim data layout before localizing transaction access introduces unnecessary churn instead of first abstracting data access",
    "furszy: Concept ACK \u2014 Obvious concept ACK",
    "0xB10C: Concept ACK \u2014 Concept ACK",
    "instagibbs: Concept ACK \u2014 this issue with exceptional tx types shows up in a lot of places, like #36015",
    "w0xlt: Concept ACK \u2014 Concept ACK",
    "rkrux: Concept ACK \u2014 Concept ACK",
    "Yudis-bit: Tested ACK \u2014 Tested ACK d3fb8e8 on Windows."
   ],
   "objections": [
    {
     "reviewer": "Yudis-bit",
     "association": "NONE",
     "type": "suggestion",
     "kind": "approach",
     "harm": "",
     "request": "Avoid heap allocations in IsWitnessStandard for Taproot inputs by checking witness size and the last element before calling ToSpans",
     "question": "",
     "text": "Avoid heap allocations in IsWitnessStandard for Taproot inputs by checking witness size and the last element before calling ToSpans",
     "clears_with": "answer",
     "blocking": false,
     "status": "accepted",
     "status_note": "author addressed in a separate commit and Yudis-bit tested ACKed",
     "cleared": true,
     "author_replied": true,
     "others_replied": false,
     "fix_pushed": true,
     "replies": [
      "c:6280847772"
     ],
     "evidence": "2026-10-17: 'checking witness.size() >= 2 and witness.back() upfront before calling ToSpans() avoids that allocation.'",
     "url": "https://github.com/bitcoin/bitcoin/pull/36521#issuecomment-6234391822",
     "id": "c:6234391822",
     "at": "2026-10-17",
     "status_at": "2026-10-20",
     "status_by": "Yudis-bit",
     "resolution_evidence": "2026-10-20: Yudis-bit: 'Tested ACK d3fb8e8 on Windows.'",
     "pin": null,
     "from_schema": 2
    },
    {
     "reviewer": "Yudis-bit",
     "association": "NONE",
     "type": "suggestion",
     "kind": "approach",
     "harm": "",
     "request": "Iterate directly over scriptWitness with a counter in the P2WSH check to avoid allocating a vector of spans",
     "question": "",
     "text": "Iterate directly over scriptWitness with a counter in the P2WSH check to avoid allocating a vector of spans",
     "clears_with": "answer",
     "blocking": false,
     "status": "accepted",
     "status_note": "author addressed in a separate commit and Yudis-bit tested ACKed",
     "cleared": true,
     "author_replied": true,
     "others_replied": false,
     "fix_pushed": true,
     "replies": [
      "c:6280847772"
     ],
     "evidence": "2026-10-17: 'Iterating directly over scriptWitness with a counter avoids allocating the vector of spans without doing O(n^2) indexing.'",
     "url": "https://github.com/bitcoin/bitcoin/pull/36521#issuecomment-6234391822",
     "id": "c:6234391822#2",
     "at": "2026-10-17",
     "status_at": "2026-10-20",
     "status_by": "Yudis-bit",
     "resolution_evidence": "2026-10-20: Yudis-bit: 'Tested ACK d3fb8e8 on Windows.'",
     "pin": null,
     "from_schema": 2
    },
    {
     "reviewer": "fametrano",
     "association": "NONE",
     "type": "objection",
     "kind": "approach",
     "harm": "VerifyWitnessProgram calls witness.ToVectors() before checking the witness version, causing a 91 MiB allocation and verification slowdown for unknown witness versions",
     "request": "",
     "question": "",
     "text": "VerifyWitnessProgram calls witness.ToVectors() before checking the witness version, causing a 91 MiB allocation and verification slowdown for unknown witness versions",
     "clears_with": "change",
     "blocking": true,
     "status": "open",
     "status_note": "",
     "cleared": false,
     "author_replied": false,
     "others_replied": false,
     "fix_pushed": false,
     "replies": [],
     "evidence": "2026-10-25: 'VerifyWitnessProgram calls witness.ToVectors() before it looks at the witness version, so the valid \"1 tx, max empty wit elems\" block from the description still allocates about 91 MiB, now during scri'",
     "url": "https://github.com/bitcoin/bitcoin/pull/36521#issuecomment-6395031310",
     "id": "c:6395031310",
     "at": "2026-10-25",
     "status_at": null,
     "status_by": null,
     "resolution_evidence": "",
     "pin": null,
     "from_schema": 2
    },
    {
     "reviewer": "purpleKarrot",
     "association": "MEMBER",
     "type": "objection",
     "kind": "approach",
     "harm": "Touching 76 files with 1000+ lines for an interim data layout before localizing transaction access introduces unnecessary churn instead of first abstracting data access",
     "request": "",
     "question": "",
     "text": "Touching 76 files with 1000+ lines for an interim data layout before localizing transaction access introduces unnecessary churn instead of first abstracting data access",
     "clears_with": "change",
     "blocking": true,
     "status": "open",
     "status_note": "",
     "cleared": false,
     "author_replied": false,
     "others_replied": false,
     "fix_pushed": false,
     "replies": [],
     "evidence": "2026-10-29: 'Instead pushing 17 commits touching over 1000 lines in 76 files, just to establish an implementation that is proven better but not proven best, should we maybe concentrate on the task that would allow us to make such a change localized in a single place?'",
     "url": "https://github.com/bitcoin/bitcoin/pull/36521#issuecomment-6503407615",
     "id": "c:6503407615",
     "at": "2026-10-29",
     "status_at": null,
     "status_by": null,
     "resolution_evidence": "",
     "pin": null,
     "from_schema": 2
    }
   ],
   "support": [
    {
     "reviewer": "furszy",
     "reason": "Obvious concept ACK",
     "substantive": false,
     "verdict": "Concept ACK",
     "id": "c:6162446479",
     "url": "https://github.com/bitcoin/bitcoin/pull/36521#issuecomment-6162446479",
     "at": "2026-10-14",
     "association": "MEMBER",
     "evidence": "none",
     "areas": []
    },
    {
     "reviewer": "0xB10C",
     "reason": "Concept ACK",
     "substantive": false,
     "verdict": "Concept ACK",
     "id": "c:6162449198",
     "url": "https://github.com/bitcoin/bitcoin/pull/36521#issuecomment-6162449198",
     "at": "2026-10-14",
     "association": "MEMBER",
     "evidence": "none",
     "areas": []
    },
    {
     "reviewer": "instagibbs",
     "reason": "this issue with exceptional tx types shows up in a lot of places, like #36015",
     "substantive": true,
     "verdict": "Concept ACK",
     "id": "c:6181345136",
     "url": "https://github.com/bitcoin/bitcoin/pull/36521#issuecomment-6181345136",
     "at": "2026-10-15",
     "association": "MEMBER",
     "evidence": "read",
     "areas": []
    },
    {
     "reviewer": "w0xlt",
     "reason": "Concept ACK",
     "substantive": false,
     "verdict": "Concept ACK",
     "id": "c:6185721229",
     "url": "https://github.com/bitcoin/bitcoin/pull/36521#issuecomment-6185721229",
     "at": "2026-10-15",
     "association": "CONTRIBUTOR",
     "evidence": "none",
     "areas": []
    },
    {
     "reviewer": "rkrux",
     "reason": "Concept ACK",
     "substantive": false,
     "verdict": "Concept ACK",
     "id": "c:6192784207",
     "url": "https://github.com/bitcoin/bitcoin/pull/36521#issuecomment-6192784207",
     "at": "2026-10-15",
     "association": "MEMBER",
     "evidence": "none",
     "areas": []
    },
    {
     "reviewer": "Yudis-bit",
     "reason": "Tested ACK d3fb8e8 on Windows.",
     "substantive": false,
     "verdict": "Tested ACK",
     "id": "c:6282408300",
     "url": "https://github.com/bitcoin/bitcoin/pull/36521#issuecomment-6282408300",
     "at": "2026-10-20",
     "association": "NONE",
     "evidence": "tested",
     "areas": []
    }
   ],
   "participants": [
    {
     "login": "0xB10C",
     "stance": "support",
     "note": "concept ACK",
     "association": "MEMBER",
     "comments": 1,
     "first": "2026-10-14",
     "last": "2026-10-14"
    },
    {
     "login": "furszy",
     "stance": "support",
     "note": "concept ACK",
     "association": "MEMBER",
     "comments": 1,
     "first": "2026-10-14",
     "last": "2026-10-14"
    },
    {
     "login": "instagibbs",
     "stance": "support",
     "note": "concept ACK citing recurring issues with exceptional transaction types",
     "association": "MEMBER",
     "comments": 1,
     "first": "2026-10-15",
     "last": "2026-10-15"
    },
    {
     "login": "rkrux",
     "stance": "support",
     "note": "concept ACK",
     "association": "MEMBER",
     "comments": 1,
     "first": "2026-10-15",
     "last": "2026-10-15"
    },
    {
     "login": "w0xlt",
     "stance": "support",
     "note": "concept ACK",
     "association": "CONTRIBUTOR",
     "comments": 1,
     "first": "2026-10-15",
     "last": "2026-10-15"
    },
    {
     "login": "Yudis-bit",
     "stance": "support",
     "note": "tested ACK after suggestions were addressed",
     "association": "NONE",
     "comments": 2,
     "first": "2026-10-17",
     "last": "2026-10-20"
    },
    {
     "login": "fametrano",
     "stance": "objection",
     "note": "objected to 91 MiB allocation in VerifyWitnessProgram for unknown witness versions",
     "association": "NONE",
     "comments": 1,
     "first": "2026-10-25",
     "last": "2026-10-25"
    },
    {
     "login": "purpleKarrot",
     "stance": "objection",
     "note": "NACKed, arguing against touching 76 files before localizing transaction data access",
     "association": "MEMBER",
     "comments": 1,
     "first": "2026-10-29",
     "last": "2026-10-29"
    }
   ],
   "derivation": "objection that needs a change, nobody has replied (fametrano, purpleKarrot)",
   "model_state": null,
   "corrections": [],
   "notes": "Added purpleKarrot's approach objection/NACK questioning widespread code changes across 76 files prior to completing transaction abstraction work."
  },
  "dependencies": {
   "depends_on": [],
   "enables": []
  },
  "categories": [
   {
    "name": "build",
    "member": false,
    "evidence": "Matched build keywords due to compiler references, but contains no changes to CMake, CI, or build configurations.",
    "band": "Unranked",
    "reason_tag": "cleanup",
    "score": 0.0,
    "factors": {
     "bug_severity": 0,
     "leverage": 1,
     "performance": 2,
     "security_stability": 2,
     "user_value": 0
    },
    "rationale": "Not a build change."
   },
   {
    "name": "kernel",
    "member": false,
    "evidence": "Touches src/kernel/bitcoinkernel.cpp only for mechanical updates to CScriptWitness accessors.",
    "band": "Unranked",
    "reason_tag": "cleanup",
    "score": 0.0,
    "factors": {
     "bug_severity": 0,
     "leverage": 1,
     "performance": 3,
     "security_stability": 3,
     "user_value": 0
    },
    "rationale": "Does not alter the kernel API or boundary."
   },
   {
    "name": "mempool",
    "member": false,
    "evidence": "Touches policy and mempool files mechanically to adapt to CScriptWitness method changes.",
    "band": "Unranked",
    "reason_tag": "cleanup",
    "score": 0.0,
    "factors": {
     "bug_severity": 0,
     "leverage": 1,
     "performance": 3,
     "security_stability": 3,
     "user_value": 0
    },
    "rationale": "Does not change mempool data structures, acceptance policy, or eviction logic."
   },
   {
    "name": "mining",
    "member": false,
    "evidence": "Touches src/node/miner.cpp mechanically for witness accessor methods.",
    "band": "Unranked",
    "reason_tag": "cleanup",
    "score": 0.0,
    "factors": {
     "bug_severity": 0,
     "leverage": 1,
     "performance": 3,
     "security_stability": 3,
     "user_value": 0
    },
    "rationale": "Does not change block template creation or mining interfaces."
   },
   {
    "name": "p2p",
    "member": true,
    "evidence": "Modifies net_processing.cpp to enforce weight budgets during P2P stream deserialization, dropping invalid transactions immediately.",
    "band": "P1",
    "reason_tag": "DoS protection",
    "score": 0.85,
    "factors": {
     "bug_severity": 0,
     "leverage": 1,
     "performance": 3,
     "security_stability": 3,
     "user_value": 0
    },
    "rationale": "Mitigates a P2P DoS vector where peers can induce large memory allocations before validation rejects messages. Stream deserialization is updated to track weight budgets to prevent memory exhaustion from crafted P2P payloads."
   },
   {
    "name": "rpc",
    "member": false,
    "evidence": "Touches src/rpc/rawtransaction.cpp mechanically to update witness stack accessors.",
    "band": "Unranked",
    "reason_tag": "cleanup",
    "score": 0.0,
    "factors": {
     "bug_severity": 0,
     "leverage": 1,
     "performance": 3,
     "security_stability": 3,
     "user_value": 0
    },
    "rationale": "Does not alter RPC interfaces, commands, or behaviors."
   },
   {
    "name": "tests",
    "member": false,
    "evidence": "Adds benchmarks and fuzz harnesses specific to script witness deserialization rather than test framework infrastructure.",
    "band": "Unranked",
    "reason_tag": "test coverage",
    "score": 0.0,
    "factors": {
     "bug_severity": 0,
     "leverage": 1,
     "performance": 3,
     "security_stability": 3,
     "user_value": 0
    },
    "rationale": "Test modifications directly support the witness refactoring rather than testing infrastructure."
   },
   {
    "name": "tools",
    "member": false,
    "evidence": "Mechanical edit in src/bitcoin-tx.cpp adapting to CScriptWitness API.",
    "band": "Unranked",
    "reason_tag": "cleanup",
    "score": 0.0,
    "factors": {
     "bug_severity": 0,
     "leverage": 1,
     "performance": 3,
     "security_stability": 3,
     "user_value": 0
    },
    "rationale": "Does not change tool behavior or functionality."
   },
   {
    "name": "utils",
    "member": false,
    "evidence": "Adds deserialization helpers in src/serialize.h strictly in service of transaction primitives.",
    "band": "Unranked",
    "reason_tag": "cleanup",
    "score": 0.0,
    "factors": {
     "bug_severity": 0,
     "leverage": 1,
     "performance": 3,
     "security_stability": 3,
     "user_value": 0
    },
    "rationale": "Serialization adjustments follow directly from transaction wire-format handling rather than general utility changes."
   },
   {
    "name": "validation",
    "member": true,
    "evidence": "Changes transaction and witness primitives in src/script/ and src/primitives/transaction.h, dramatically cutting memory and CPU overhead in block deserialization.",
    "band": "P1",
    "reason_tag": "DoS protection",
    "score": 0.9,
    "factors": {
     "bug_severity": 0,
     "leverage": 1,
     "performance": 3,
     "security_stability": 3,
     "user_value": 0
    },
    "rationale": "Eliminates a severe validation-time memory bloat and deserialization DoS vector reported by researchers. Description benchmarks show worst-case block deserialization time drops from 279 ms to 19 ms, persisted block memory from 106.8 MiB to 3.8 MiB, and peak memory from 182 MiB to 7.8 MiB."
   },
   {
    "name": "wallet",
    "member": false,
    "evidence": "Touches PSBT and wallet files mechanically for CScriptWitness method changes.",
    "band": "Unranked",
    "reason_tag": "cleanup",
    "score": 0.0,
    "factors": {
     "bug_severity": 0,
     "leverage": 1,
     "performance": 3,
     "security_stability": 3,
     "user_value": 0
    },
    "rationale": "Does not affect wallet functionality, key management, or coin selection."
   }
  ],
  "confidence": "high",
  "uncertainties": [],
  "needs": []
 },
 "cost_usd": 0.0,
 "source": {
  "record": "2026-10-30T01:14:11+00:00",
  "code": "2026-10-24T01:21:40+00:00",
  "judgments": 11
 }
}