Repository navigation
Conversation
connect_block_inner checked that header.bits equals the retarget value from the ancestor lookup, but never hashed the header against that target. check_proof_of_work existed and nothing under src/block/ called it. The node hashes headers it ingests, not the header of a full block it connects, so a P2P block after IBD, submitblock, a reorg connect, and parallel IBD all accepted a header whose hash missed the target, as long as its bits were right. Run check_proof_of_work (Core CheckBlockHeader -> CheckProofOfWork) in the same branch as the bits check, which is the context every node connect path builds. Callers that pass no ancestor lookup (library and test paths) are unchanged. It runs after the BIP94 check only so that test keeps its reject reason; both reject. Test: tests/connect_pow_check.rs. Mainnet block 1 rebuilt from its coinbase connects; the same header with nonce 0 has the required bits and a valid merkle root and is rejected; on regtest a nonce grind hits both sides of the target. The two reject cases fail on main.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
connect_block_innerchecks thatheader.bitsequalsnext_required_bitsfrom the ancestor lookup. It never compares the header hash against that target.pow::check_proof_of_workexists, but nothing undersrc/block/calls it.The node hashes headers it ingests through
headersmessages. It does not hash the header of a full block it connects. As a result, these paths all accepted a block whose bits were right and whose hash missed the target:blockafter IBD (handle_block_wire_message, thenprocess_block)submitblock, viaconnect_mined_blockBelow the assume-valid height, scripts were skipped as well.
Fix
This calls
check_proof_of_workinside the samedifficulty_ancestorbranch as the bits check. That matches Core:CheckBlockHeader, thenCheckProofOfWork, run fromCheckBlockinsideConnectBlock. Every node connect path builds this context:block_processor.rs,parallel_ibd/mod.rs,reorg_executor.rs,pruning.rs, andrpc/blockchain.rs. The check costs one double-SHA256 per block.blvm-protocol::validate_and_connect_block, and most unit tests, which use fake headers. Checking unconditionally would match Core more closely, but it would need every fixture in this repo re-mined. A follow-up could make the context carry an explicitcheck_powthat defaults to on.Evidence
The new
tests/connect_pow_check.rsuses mainnet block 1, rebuilt from its coinbase. The test asserts the txid and merkle root0e3e2357…, the hash00000000839a8e68…, and that the block meets its target.mainvector_is_mainnet_block_1connect_accepts_mainnet_block_1connect_rejects_hash_above_target_with_correct_bits(block 1 with nonce 0: right bits, valid merkle root, hash above target)connect_regtest_pow_boundary(nonces 0..63, both sides of the regtest target)cargo test(Rust 1.88): 2207 passed, 0 failed, 7 ignored. That is 2203 onmainplus these 4.cargo clippy --lib --bins -- -D warnings: clean.cargo fmt --check: clean.test_verify_chain_level4_with_undo_logs, has headers with no valid PoW. It is fixed in test(node): mine regtest proof of work for the verifychain level 4 fixture blvm-node#32, which must land before node CI builds against this.Checklist
queue_blockdeque (C2 in the review) is unchanged.submitblockpath is admin-only, so the main exposure was P2P.Review notes: merge order and open decisions (BLVM criticals set)
This PR is one of 7 fixing the four criticals from the BLVM three-lens review:
blvm-consensus#22 (undo log), blvm-consensus#23 (PoW vs target), blvm-node#32 (PoW test fixture), blvm-primitives#2 (min chainwork), blvm-node#31 (assume-valid), blvm-secp256k1#1 (no CUDA by default), blvm#10 (release build + no-CUDA check).
Merge order
consensus_config_default.json, or its test fails.cargo update -p blvm-secp256k1in blvm, then cut a release with blvm#10. v0.1.63 and v0.1.64 stay broken (need libcudart) until then.Decisions for the reviewer
Known, not fixed here:
-assumevalid=<hash>CLI parses the hash in the wrong byte order; the GHCR image ships a different binary (blvm 0.1.0).