engine/codec/ is vendored into five repos. Seven of the eight consensus files are byte-identical across all of them; blocks.js is not.
b8d482b8 367 lines kernel, browser-node
4c49c625 368 lines health, forks, mempool
The single line of difference is a fix, in witnessCommitmentHash:
const reserved = hexToBytes(block.transactions[0].witness?.[0]?.[0] ?? '00'.repeat(32));
if (reserved.length !== 32) return null; // malformed reserved value can never match the commitment
Without it, a coinbase whose witness reserved value is longer than 32 bytes reaches cat.set(reserved, 32) and throws:
THREW: RangeError: offset is out of bounds
-> uncaught exception instead of a validation failure
Core requires the coinbase witness stack to be exactly one item of exactly 32 bytes and rejects otherwise with bad-witness-nonce-size. The patched version produces the correct verdict (verified: the rule returns false, and the block verdict is false), so the fix is right — it is just in the wrong place.
The problem
It landed in the three downstream copies (all pushed 2026-07-24) and never reached kernel, the canonical source, or browser-node. Consequences:
kernel and browser-node still throw on hostile block data
- anyone importing the library gets the unpatched version
- the published spec and the live test suite are generated from the unpatched version
Since health, forks and mempool consume untrusted blocks from nostr and WebRTC peers, this is the kind of input that arrives unannounced.
The general issue
Nothing checks that the five copies agree. build.js vendors into the site; nothing verifies the copies against the source. This time the drift is a fix travelling downstream-only. Next time it could be a fix in kernel that never reaches the monitors, leaving three tools validating live mainnet data against stale consensus rules — and nothing would report it.
Suggested fix
- Port the one-line guard back into
kernel (and re-vendor to browser-node).
- Add a drift check to CI: hash every
engine/codec/*.js against packages/kernel/codec/*.js and fail on mismatch. A few lines, and it makes this class of divergence impossible to land silently.
Worth deciding explicitly whether the vendored copies are allowed to diverge at all. If they are not, the check should be strict equality. If they are, the exceptions need recording somewhere the next person will find them.
engine/codec/is vendored into five repos. Seven of the eight consensus files are byte-identical across all of them;blocks.jsis not.The single line of difference is a fix, in
witnessCommitmentHash:Without it, a coinbase whose witness reserved value is longer than 32 bytes reaches
cat.set(reserved, 32)and throws:Core requires the coinbase witness stack to be exactly one item of exactly 32 bytes and rejects otherwise with
bad-witness-nonce-size. The patched version produces the correct verdict (verified: the rule returnsfalse, and the block verdict isfalse), so the fix is right — it is just in the wrong place.The problem
It landed in the three downstream copies (all pushed 2026-07-24) and never reached
kernel, the canonical source, orbrowser-node. Consequences:kernelandbrowser-nodestill throw on hostile block dataSince
health,forksandmempoolconsume untrusted blocks from nostr and WebRTC peers, this is the kind of input that arrives unannounced.The general issue
Nothing checks that the five copies agree.
build.jsvendors into the site; nothing verifies the copies against the source. This time the drift is a fix travelling downstream-only. Next time it could be a fix inkernelthat never reaches the monitors, leaving three tools validating live mainnet data against stale consensus rules — and nothing would report it.Suggested fix
kernel(and re-vendor tobrowser-node).engine/codec/*.jsagainstpackages/kernel/codec/*.jsand fail on mismatch. A few lines, and it makes this class of divergence impossible to land silently.Worth deciding explicitly whether the vendored copies are allowed to diverge at all. If they are not, the check should be strict equality. If they are, the exceptions need recording somewhere the next person will find them.