Add initial dataset of invalid blocks with schema, notes, and CI - #3
Conversation
|
P.S. I am writing a deeper dive post about these blocks :) |
|
Drafted because I just want to ensure I've got all observations for the merge-mined contributions.. |
dce4851 to
073924c
Compare
f3a0e81 to
25fb3db
Compare
|
The dataset looks Ok. I haven't looked at the CI code in detail. I was wondering if it could be less/simpler, or is needed at all in this capacity, but I also don't mind having it! |
I do think we should have as comprehensive evaluation of any blocks that are added, but yeah the tests can for sure be reduced, and probably we can simplify regardless |
37b1542 to
6842d4e
Compare
|
Switching from stdlib to leveraging python-bitcoinlib, bring LOC down a fair bit |
d000503 to
fd2060c
Compare
fd2060c to
6b8b441
Compare
|
Feel free to merge at any point you think this is ready. I think you should have the permissions to do so. |
Summary
Initial dataset for the invalid-blocks side of the split discussed in bitcoin-data/stale-blocks#128: headers and blocks that carry valid PoW but failed a named consensus check. 46 records spanning heights 74638 to 957780, with full blocks for 74638, 477115, 783426, 784121, and 809478. The records come from entries dropped from stale-blocks (bitcoin-data/stale-blocks#134), the 2023 P2P-observed invalid blocks, archived block explorers, and merge-mined recoveries (headers rescued from child-chain commitments on Namecoin, RSK, and others).
data/invalid-blocks.jsonlcommits one record per block hash, with the 80-byte header pluscore_reject_reasonandrule. A nestedcontextobject carries the extra evidence a rule needs when the header alone is not enough (BIP34 coinbase height, parent MTP, expected nBits); anobservationsarray records each witness with its source channel andprovenanceURL.The admission standard is spelled out in
docs/schema.md: PoW against the header's own nBits, a registered rule/reject-string pair, and evidence checked for that rule. Complete.binfiles must parse and match their transaction merkle roots and applicable witness commitments; CI checks output overflow, transaction ordering and excessive sigop cost directly. These checks establish the named failure; they do not execute scripts or reconstruct historical chain state.docs/notes.mdcovers replay behaviour and incident background (replaying the 2023 full blocks withsubmitblockcannot reproduce their reject strings today, since their violations only surface inConnectBlock).The validator uses
python-bitcoinlib, pinned to 0.12.2 inrequirements.txt, for Bitcoin parsing and serialization. For sigops, CI fetches and verifies previous transactions from public APIs and runs daily after merge to keep the cache warm. Only successful non-PR runs on the default branch save a cache archive when no exact cache exists for that block set; pull requests restore the cache without uploading archives.Testing
python ci/sanity-check.py --fetch-prevoutspasses: 46 records, 46 context objects, 188 observations, 5 block files. It re-derives the header hash, checks PoW against the header's nBits, decodesprev_hashandnTimeback out of the header, and enforces sort order and hash uniqueness. All 28 regression tests (with named subtests for related cases) pass, as do workflow lint and whitespace checks. CI calculates sigop cost 80003 for each F2Pool block against the 80000 limit; a public-API smoke run filled two missing cache entries and reproduced both counts.I verified the rule-to-reject-string table in
docs/schema.mdagainst Core master (CheckTransaction,CheckTxInputs,ContextualCheckBlockHeader,ContextualCheckBlock,ConnectBlock), and replayed the four original.bins (74638, 783426, 784121, and 809478) on two mainnet nodes (v30.2 and a master build): 74638 returnsbad-txns-vout-toolargeon both; the three 2023 blocks returninconclusiveorduplicatedepending on whether the node already stores them, which is exactly the behaviourdocs/notes.mddocuments.All seven entries removed from stale-blocks in bitcoin-data/stale-blocks#134 are covered here.