#35570 refactor: Change some validation.cpp methods to return BlockValidationState
| Reviewability | Reviews | Agreement | Size | ||||
|---|---|---|---|---|---|---|---|
| #35570 refactor: Change some validation.cpp methods to return BlockValidationState | Ready | 0 (+1) | Disputed | 238 + 36 tests | |||
|
|
|
|
| |||
Reviewability: ReadyStalePaused Agreement: StrongPositivePositive w/ caveatsNeutralMildDisputedBlockedCrickets Reviews: current code-review ACKs, then (+stale ACKs) and -NACKs; greener = more ACKs. Size: lines added or modified outside tests, then in tests; greener = smaller. | |||||||
Goal
Refactors block and header validation functions in validation.cpp and validation.h to return BlockValidationState by value instead of using an out-parameter with a bool return value. Introduces MakeInvalid and MakeError static helper methods on BlockValidationState to construct failure states inline. Callers across net_processing, the kernel C API, RPC, tests, and benchmarks are updated accordingly.
Problem: Validation functions returned a bool while writing to a mutable BlockValidationState out-parameter. This allows the boolean return value and the validation state to disagree, creates ambiguity about whether an incoming state is read or overwritten, and risks state pollution across chained calls where an existing error state prevents a new failure reason from being recorded.
Evidence of importance:
- PR description: 'Exclude the potentially inconsistent case when the bool return value and the returned state are inconsistent' and 'Remove the possibility of unintuitive interaction between subsequent calls with the same state.'
- PR description links to review discussion on #33856 where follow-up refactoring of validation return conventions was requested.
Scope: Touches critical validation and consensus-checking logic across 12 granular commits ordered bottom-to-top in the call hierarchy, including kernel C API and fuzz target updates.
Risk of a mistake: medium (validation, consensus). A mistake in handling return state across block or header acceptance could inadvertently treat invalid blocks as valid or reject valid headers, risking consensus divergence or peer banning.
Changed since the previous assessment: Rebased with minor commit refinements; the overall approach and set of 12 commits remain unchanged.
Reviewability
Ready
Nothing known that would invalidate a review now.
Waiting on (from the thread read):
- decision: decision on whether to enforce valid/invalid return types at compile time (via #35646) before proceeding 2026-09-15
- reviewer: hodlinator to evaluate author's responses and break-out PR #36318 2026-09-23
Agreement
Disputed
objection that needs a change, the objector pushed back after a reply (hodlinator)
Thread notes: The author self-commented on factory methods for ValidationState and created break-out PR #36318. Hodlinator's objection regarding runtime asserts versus compile-time type enforcement remains standing.
Objections, suggestions, and questions:
| Reviewer | Type | Harm, request, or question | Status | Must be | Author replied | Quote |
|---|---|---|---|---|---|---|
| w0xlt (contributor) | objection, correctness | setting validation state to Error in fuzz test causes subsequent validation checks to never run | fixed · fix pushed · fixed in push and acknowledged by author · v1, not yet re-checked | answered | yes | 2026-09-11: 'Calling validation_state_pow_and_merkle.Error("") changes the state to Error, making the later if (validation_state_pow_and_merkle.IsValid()) always false so it never runs.' Status from: 2026-09-11: optout21: 'Applied fix to a minor fuzz test bug, found in review' |
| hodlinator (member) | objection, approach | relying on asserts and comments to enforce that methods never return Error risks unexpected runtime aborts and is fragile compared to type-level enforcement | contested · hodlinator prefers type-level enforcement via #35646 before proceeding · v1, not yet re-checked | changed | yes | 2026-09-15: 'It would feel safer if we made the paths which do not return error states instead return a narrower state type which only allowed valid/invalid, instead of having these more imperative checks.' |
Support:
- w0xlt (contributor) (Concept ACK, 2026-06-20): Concept ACK [not substantive]
- purpleKarrot (member) (Concept ACK, 2026-06-22) [read]: Preferring the return value over output parameters is a useful and I would say *necessary* improment.
- stringintech (contributor) (Concept ACK, 2026-06-23): Concept ACK [not substantive]
- yuvicc (contributor) (Concept ACK, 2026-06-30): Concept ACK [not substantive]
- nervana21 (contributor) (Concept ACK, 2026-07-09): Concept ACK [not substantive]
- arejula27 (contributor) (ACK, 2026-09-10) [read]: This PR only changes signatures as the PR description says, no behavioral changes.
- enirox001 (contributor) (Concept ACK, 2026-09-22) [read]: Initial looks at the `validation.cpp` methods use of the `BlockValidationState` was a bit ambiguous to understand, this makes things much clearer since the validation states can be used to replace the
Participants:
- w0xlt (contributor, support, 2 statements 2026-06-20 to 2026-09-11): Concept ACK; spotted fuzz test bug that was fixed
- purpleKarrot (member, support, 1 statements 2026-06-22 to 2026-06-22): Concept ACK; suggested avoiding BlockValidationState as a mutable state machine
- arejula27 (contributor, support, 21 statements 2026-06-23 to 2026-09-18): Concept ACK and ACK; reviewed signatures, suggested minor improvements, and asked about Assume vs Assert usage
- stringintech (contributor, support, 2 statements 2026-06-23 to 2026-06-24): Concept ACK; discussed util::Expected and separation of concerns
- ryanofsky (member, neutral, 1 statements 2026-06-28 to 2026-06-28): suggested splitting out FlushStateToDisk behavior change into a separate PR
- yuvicc (contributor, support, 2 statements 2026-06-30 to 2026-07-03): Concept ACK; opened #35646 for util::Expected follow-up
- nervana21 (contributor, support, 1 statements 2026-07-09 to 2026-07-09): Concept ACK
- hodlinator (member, objection, 19 statements 2026-09-15 to 2026-09-22): objects to relying on runtime asserts/comments rather than narrower types via #35646; withholds Concept ACK
- enirox001 (contributor, support, 1 statements 2026-09-22 to 2026-09-22): Concept ACK; finds replacing boolean return values with validation states much clearer
Files
75 lines under test/bench/ci.
- src/validation.cpp +176/-154
- src/consensus/validation.h +24/-2
- src/net_processing.cpp +13/-12
- src/validation.h +12/-13
- src/test/fuzz/block.cpp +10/-13
- src/kernel/bitcoinkernel.cpp +5/-9
- src/node/blockstorage.cpp +7/-3
- src/test/chainstate_write_tests.cpp +4/-5
- src/test/validation_block_tests.cpp +7/-2
- src/test/validation_chainstate_tests.cpp +4/-5
- src/test/baseindex_tests.cpp +4/-3
- src/test/fuzz/utxo_snapshot.cpp +2/-4
- src/bench/checkblock.cpp +2/-3
- src/bench/duplicate_inputs.cpp +2/-2
- src/rpc/mining.cpp +1/-2
- src/test/util/mining.cpp +1/-2
Card
The short text the ranking pass compares across PRs.
This PR refactors block validation methods including CheckBlock, AcceptBlock, FlushStateToDisk, and ProcessNewBlockHeaders to return BlockValidationState by value rather than taking an out-parameter alongside a boolean return code. It eliminates the risk of divergence between boolean status codes and the inner validation state, preventing state leakage across chained calls. The change was requested during the review of PR 33856 to clean up internal validation semantics and kernel interfaces. It has no external dependencies.
Data
thread read through 2026-09-23 (101 statements), head 9e3c5ba481
Discussion read under schema 1 rules: suggestions and questions may be missing, and an objection may combine several harms (schema history).
labels: Refactoring
Categories
Validation
P3 · cleanup (ranking pass: Moved up: placed directly after its enabling work so the #35646 -> #35570 chain is reviewed in order)
The PR retires an interface hazard where validation functions could return inconsistent boolean values and mutable validation states. By returning BlockValidationState directly, it 'excludes the potentially inconsistent case when the bool return value and the returned state are inconsistent' and avoids state pollution across chained calls. While beneficial for long-term validation safety, it is an internal refactoring without an active bug fix or user impact, making it reasonably deferrable.
Membership: Refactors block and header validation signatures and state return mechanics across src/validation.cpp, src/validation.h, and src/consensus/validation.h.
Factors: security/stability 1, bug 0, performance 0, user value 0, leverage 1