#29700 kernel, refactor: return error status on all fatal errors
https://github.com/bitcoin/bitcoin/pull/29700 · · +1754/-675 in 55 files, 22 commits · labels: none · draft
Goal
- Return fatal error details programmatically instead of aborting the node process during validation
- Let libbitcoinkernel users handle critical failures directly without relying on notification callbacks
This PR refactors validation and blockstorage routines to return util::Result objects with error and flush status instead of aborting the process via AbortNode. It extends util::Result with failure value support, an InfoType field, and an Update method to merge messages, then threads these results through block connection, package processing, and chainstate flushes.
Problem: Currently, many validation routines handle fatal conditions by calling AbortNode and initiating node shutdown without returning error context to the caller. This forces libbitcoinkernel consumers to rely on asynchronous notification callbacks to detect failures instead of handling them programmatically via return values.
Category: Kernel (libbitcoinkernel) (#3 of 18)
P2 · new feature
- P2 because external applications embedding the kernel need structured errors instead of process shutdowns
- Avoids requiring consumers to register asynchronous notification callbacks to detect fatal failures
P2 because replacing global AbortNode shutdowns with structured return values is essential for external applications embedding libbitcoinkernel. As stated in the description, 'This makes error handling in libbitcoinkernel application code difficult, because the only way to handle these errors is to register for notification callbacks.'
Membership: Directly targets libbitcoinkernel error handling across validation and block storage boundaries.
Factors: security/stability 1, bug 0, performance 0, user value 2, leverage 2
Category: Utilities (logging, arguments, libraries) (#25 of 66)
P3 · cleanup
- P3 because expanding result framework capabilities is mostly auxiliary to the kernel work
- General utility improvements provide limited independent benefit on their own
P3 because it improves the utility result framework to support multiple messages and distinct success/failure/info types, but is largely motivated by the needs of the kernel refactoring.
Membership: Adds InfoType and message updating utilities to src/util/result.h and src/util/messages.cpp.
Factors: security/stability 1, bug 0, performance 0, user value 1, leverage 1
Category: Validation (#31 of 48)
P3 · cleanup
- P3 because changes across validation routines are purely refactoring without changing runtime behavior
- Updates function signatures to thread return values through without altering core validation logic
P3 because while it modifies dozens of core validation call sites and method signatures, it is described by the author as 'a pure refactoring that returns extra result information from functions without changing their behavior'.
Membership: Extensively updates validation entry points (ConnectBlock, ActivateBestChain, FlushStateToDisk, VerifyDB) to return results.
Factors: security/stability 1, bug 0, performance 0, user value 1, leverage 2
Reviewability: Ready: Review #25665 first
- Review #25665 first
The code is clean, CI passes, and the branch is regularly maintained, but it depends on the unmerged base PR #25665 which provides the underlying util::Result machinery.
Author status: active, regularly rebasing on master and tracking conflict fixes
Open concerns:
- purpleKarrot objects to adopting Result-style error handling, arguing it is an unnecessary rustism contrary to C++ performance idioms.
- maflcko pointed out that wrapping InterruptResult within util::Result makes call sites prone to missing interruption.
Resolved concerns:
- optout21 noted an inconsistency where FlushStateToDisk modifies state while its return value is ignored; this was documented in comments and the fix split out to #35621 (merged).
Agreement: Blocked
- Blocked by an unaddressed approach objection
- Unaddressed objection: Result-style error handling is unidiomatic and harms performance (purpleKarrot)
- Nonblocking objection: nesting interrupt results inside error results invites unhandled stops (maflcko)
- Approval without detailed technical analysis (Graysonbarton)
Blocked by an unaddressed approach objection against util::Result error handling (purpleKarrot)
purpleKarrot posted an explicit objection arguing against Result-style error handling in C++, which the author has not directly addressed in discussion. Additionally, maflcko's earlier feedback on InterruptResult remains unimplemented.
- purpleKarrot (2026-04-01): 'Introducing util::Result is a development in the wrong direction.'
- maflcko (2024-07-26): 'Seems fragile to use util::Result<InterruptResult>.'
- optout21 (2026-06-29): 'Addressing this single case has been split off into #35621.'
Objections:
| Reviewer | Kind | Harm | Status | Blocking | Author replied | Quote |
|---|---|---|---|---|---|---|
| purpleKarrot | approach | Argues introducing util::Result error handling is contrary to C++ idioms and runtime performance requirements | open | yes | no | 2026-04-01: 'I see Result-style error handling as a rustism that should be kept out of the C++ codebase of Bitcoin core... Introducing util::Result is a development in the wrong direction.' |
| maflcko | approach | Wrapping results inside results makes it easy for callers to miss interruptions | open | no | yes | 2024-07-26: 'Seems fragile to use util::Result<InterruptResult>. Wrapping one result into another is fragile, because call-sites may easily forget to unwrap the inner result...' |
| optout21 | correctness | Ignored return values from FlushStateToDisk could inadvertently mutate validation state | resolved | no | yes | 2026-06-20: 'While working on #35570 , I have also found a potential inconsistency here: the return value from FlushStateToDisk is ignored, but it can cause change in state' Settled: 2026-06-29: optout21 noted 'Addressing this single case has been split off into #35621.' |
Participants: Graysonbarton (support), maflcko (objection), sedited (neutral), purpleKarrot (objection), optout21 (question)
State derived from the lists: blocking objection open with no author reply (purpleKarrot)
Review verdicts (DrahtBot): 0
Dependencies
Depends on: #25665
Enables:
- libbitcoinkernel standalone fatal error handling without callbacks
Based on (shares commits with): #25665
Files
592 lines under test/bench/ci.
- src/validation.cpp +368/-193
- src/util/result.h +394/-62
- src/test/result_tests.cpp +195/-11
- src/node/blockstorage.cpp +119/-67
- src/node/chainstate.cpp +85/-53
- src/test/txpackage_tests.cpp +83/-52
- src/validation.h +44/-36
- src/kernel/result.h +67/-0
- src/util/messages.h +60/-0
- src/init.cpp +27/-25
- src/node/mempool_persist.cpp +23/-9
- src/util/messages.cpp +30/-0
- src/node/chainstate.h +6/-22
- src/kernel/bitcoinkernel.cpp +16/-11
- src/test/validation_chainstatemanager_tests.cpp +17/-10
- src/node/blockstorage.h +13/-10
- src/rpc/blockchain.cpp +12/-11
- src/test/validation_block_tests.cpp +17/-5
- src/test/validation_chainstate_tests.cpp +14/-7
- src/test/util/setup_common.cpp +13/-7
- src/rpc/mining.cpp +14/-5
- src/net_processing.cpp +9/-6
- src/bench/readwriteblock.cpp +9/-5
- src/test/baseindex_tests.cpp +10/-4
- src/test/chainstate_write_tests.cpp +7/-7
- src/test/fuzz/connect_block.cpp +7/-7
- src/test/fuzz/package_eval.cpp +8/-6
- src/test/fuzz/tx_pool.cpp +9/-5
- src/rpc/mempool.cpp +7/-4
- src/test/blockfilter_index_tests.cpp +8/-3
- src/node/miner.cpp +5/-3
- src/test/blockmanager_tests.cpp +4/-4
- src/test/peerman_tests.cpp +7/-1
- test/functional/feature_assumeutxo.py +5/-3
- src/node/interfaces.cpp +6/-1
- src/test/util/mining.cpp +5/-1
- src/test/util/chainstate.h +3/-2
- src/bench/block_assemble.cpp +3/-1
- src/node/mempool_persist.h +3/-1
- src/node/transaction.cpp +2/-2
- src/test/fuzz/load_external_block_file.cpp +2/-2
- src/wallet/wallet.cpp +2/-2
- src/bench/load_external.cpp +2/-1
- src/test/txvalidation_tests.cpp +2/-1
- src/test/txvalidationcache_tests.cpp +2/-1
- ci/test/00_setup_env_native_previous_releases.sh +1/-1
- src/test/blockchain_tests.cpp +1/-1
- src/test/fuzz/utxo_snapshot.cpp +1/-1
- src/test/fuzz/utxo_total_supply.cpp +1/-1
- src/test/interfaces_tests.cpp +1/-1
- src/test/txdownload_tests.cpp +1/-1
- src/bench/connectblock.cpp +1/-0
- src/kernel/CMakeLists.txt +1/-0
- src/test/miner_tests.cpp +1/-0
- src/util/CMakeLists.txt +1/-0
Card
This PR refactors validation and block storage functions to return error status via util::Result rather than aborting the process via AbortNode. The goal is to allow libbitcoinkernel consumers to handle errors programmatically without having to register global notification callbacks. It depends on base PR #25665, which provides the underlying Result error types. While the author continues to actively rebase the branch, progress is currently stalled by an unresolved objection from purpleKarrot against Result-style error handling in Core.