miner: CreateNewBlock errors on mempool tx that fails stricter post-fork script flags #39
Labels
No labels
enhancement
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
SubGeniusFinance/Offerings-to-Cthulhu#39
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Goal
Fix a miner-side flaw uncovered while writing the
qa/rpc-tests/cltv_boundary.pyadversarial test for #34. Surfaces only post-fork (h ≥ 1,055,555) when block-validation flags become stricter than mempool flags.Problem
Sequence:
P2SH | STRICTENConly.P2SH | STRICTENC | DERSIG | CHECKLOCKTIMEVERIFY(issues #33 + #34).tx.nLockTime < required_locktime— mempool's script eval treatsOP_NOP2as a no-op and accepts; block-validation evaluates CLTV and rejects.nSequence == 0xFFFFFFFF— same shape (mempool: no-op pass; block-validation: CLTV reject).setgenerate true 1(or anything that runs the miner) causes the daemon to error or exit instead of gracefully excluding the offending tx from the next block.Reproduction: see
qa/rpc-tests/cltv_boundary.py(Phase 3, currently deferred with a comment). Briefly:Observed in regtest with the freshly built
feat/v2.0.x-rc-bipsoftbinary.Impact
Likely cause
CreateNewBlock(or itsCCheckQueue-driven script-check path) almost certainly treats a script-check failure during block assembly as an unexpected state — Bitcoin Core's invariant historically was "if it's in the mempool, it passes block-validation script checks." Once mempool and block-validation flags diverge, that invariant breaks. The miner needs to gracefully skip the tx instead of erroring/asserting.Investigation should look at:
src/miner.cpp—CreateNewBlock, the loop that pulls txs frommempool.mapTxand runsCheckInputssrc/main.cpp—CheckInputsand itsCScriptCheckcallers; whether failure paths trip an assertion or DoS-100 the callersrc/checkqueue.h—CCheckQueueControldestruction semantics if a check returns false mid-flightProposed fix shape
CheckInputsfor a mempool tx duringCreateNewBlockAdvanceTo: tx %s failed block-flag script check, excluding)mempool(it's no longer valid) and skip~30-50 LoC, plus mempool cleanup logic.
Test for the fix
The deferred Phase 3 in
qa/rpc-tests/cltv_boundary.pyis the regression for this. Once fixed:setgenerate true 1succeeds.Same test pattern applies to BIP66 DERSIG (#33) once the block-construction primitives land — a malformed-sig tx that bypasses STRICTENC won't exist via sendrawtransaction (mempool catches it), but if anyone constructs and submits a block via
submitblockwith such a tx, block-validation must reject without crashing.Should it ship in v2.0.x-rc-bipsoft?
Yes — recommend bundling. The bug is introduced by the bundle's stricter post-fork flags. Shipping the bundle without the fix means the bundle's first day of mainnet activation comes with a known DoS surface. Better to fix-and-ship as one release than ship-then-hotfix.
References
qa/rpc-tests/cltv_boundary.py— reproduction in Phase 3 (deferred)Fixed on
feat/v2.0.x-rc-bipsoftas commit1f63d5f.Approach: align the miner's pre-screen flags in
CreateNewBlockwith the flagsConnectBlockwill use at the same height. Pre-fork no behavior change; post-fork the miner now gracefullycontinues past a mempool tx that fails block-validation script flags, instead of adding it to the candidate block and then crashing the finalConnectBlocktest-pass.Regression test:
qa/rpc-tests/cltv_boundary.pyPhase 3 (the original repro from the issue body) now PASSes — bad-CLTV tx accepted to mempool →setgenerate true 1→ miner skips the tx → block lands cleanly → daemon stays up → bad tx confirmed NOT in any block.Not yet on
main— bundled with the rest offeat/v2.0.x-rc-bipsoftfor merge at freeze-end (post h=1,050,667). Closing as "fix shipped on the working branch."