#35570 refactor: Change some validation.cpp methods to return BlockValidationState

ReviewabilityReviewsAgreementSize
#35570 optout21 refactor: Change some validation.cpp methods to return BlockValidationStateReady0 (+1)Disputed238 + 36 tests
  • Stop block and header validation checks from returning conflicting status flags and error states
  • Prevent chained validation steps from inheriting or overwriting unrelated failure reasons
  • Ready to review
  • Broad concept support for removing mutable validation out-parameters
  • Contested objection that relying on asserts over compile-time types risks runtime aborts (hodlinator)
  • Verified that updates change signatures without altering behavior (arejula27)
  • Support because returning values directly instead of using out-parameters is cleaner (purpleKarrot)
  • 238 lines added or modified outside tests
  • 36 lines added or modified in tests
  • 234 lines removed in total
  • 16 files, 12 commits
Validation#37 of 53
P3 · cleanup
  • P3 because it eliminates an interface hazard where validation results and error states can disagree
  • It improves long-term validation safety but fixes no active bug and carries no direct user impact
  • Ranking pass: Moved up: placed directly after its enabling work so the #35646 -> #35570 chain is reviewed in order
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:

ReviewerTypeHarm, request, or questionStatusMust beAuthor repliedQuote
w0xlt (contributor)objection, correctnesssetting validation state to Error in fuzz test causes subsequent validation checks to never runfixed · fix pushed · fixed in push and acknowledged by author · v1, not yet re-checkedansweredyes2026-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, approachrelying on asserts and comments to enforce that methods never return Error risks unexpected runtime aborts and is fragile compared to type-level enforcementcontested · hodlinator prefers type-level enforcement via #35646 before proceeding · v1, not yet re-checkedchangedyes2026-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

dossier JSON · extract JSON · model ledger, generated 2026-09-24T01:19, confidence high, input hash e0bc3936aa1b9996
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