From d533366b4e0688657548fa16cc3470251d612d18 Mon Sep 17 00:00:00 2001 From: Eric Voskuil Date: Wed, 26 Aug 2026 15:49:43 -0400 Subject: [PATCH 1/3] Fix chain_state init for lock-free/confirmed walk. --- .../impl/query/consensus/consensus_chain_state.ipp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/bitcoin/database/impl/query/consensus/consensus_chain_state.ipp b/include/bitcoin/database/impl/query/consensus/consensus_chain_state.ipp index 4ebdbd06e..136ba6f96 100644 --- a/include/bitcoin/database/impl/query/consensus/consensus_chain_state.ipp +++ b/include/bitcoin/database/impl/query/consensus/consensus_chain_state.ipp @@ -36,6 +36,10 @@ bool CLASS::populate_bits(chain_state::data& data, if (!get_bits(data.bits.self, link)) return false; + // Navigate from the subject (data.height) to the map's high block. + for (auto height = data.height; height > map.bits.high; --height) + link = to_parent(link); + data.bits.ordered.resize(map.bits.count); for (auto& bit: std::views::reverse(data.bits.ordered)) { @@ -53,6 +57,10 @@ bool CLASS::populate_versions(chain_state::data& data, if (!get_version(data.version.self, link)) return false; + // Navigate from the subject (data.height) to the map's high block. + for (auto height = data.height; height > map.version.high; --height) + link = to_parent(link); + data.version.ordered.resize(map.version.count); for (auto& version: std::views::reverse(data.version.ordered)) { @@ -70,6 +78,10 @@ bool CLASS::populate_timestamps(chain_state::data& data, if (!get_timestamp(data.timestamp.self, link)) return false; + // Navigate from the subject (data.height) to the map's high block. + for (auto height = data.height; height > map.timestamp.high; --height) + link = to_parent(link); + data.timestamp.ordered.resize(map.timestamp.count); for (auto& timestamp: std::views::reverse(data.timestamp.ordered)) { From 7ba0ade0211b47556c22dbbbf8224cf2819c50cd Mon Sep 17 00:00:00 2001 From: Eric Voskuil Date: Wed, 26 Aug 2026 15:50:05 -0400 Subject: [PATCH 2/3] Add to_candidate_child/to_confirmed_child queries. --- .../impl/query/navigate/navigate_reverse.ipp | 22 +++++++++++++++++++ include/bitcoin/database/query.hpp | 2 ++ 2 files changed, 24 insertions(+) diff --git a/include/bitcoin/database/impl/query/navigate/navigate_reverse.ipp b/include/bitcoin/database/impl/query/navigate/navigate_reverse.ipp index b42116020..4edf0f33a 100644 --- a/include/bitcoin/database/impl/query/navigate/navigate_reverse.ipp +++ b/include/bitcoin/database/impl/query/navigate/navigate_reverse.ipp @@ -43,6 +43,28 @@ header_link CLASS::to_parent(const header_link& link) const NOEXCEPT return header.parent_fk; } +TEMPLATE +header_link CLASS::to_candidate_child(const header_link& link) const NOEXCEPT +{ + size_t height{}; + if (!get_height(height, link)) + return {}; + + const auto child = to_candidate(add1(height)); + return (to_parent(child) == link) ? child : header_link{}; +} + +TEMPLATE +header_link CLASS::to_confirmed_child(const header_link& link) const NOEXCEPT +{ + size_t height{}; + if (!get_height(height, link)) + return {}; + + const auto child = to_confirmed(add1(height)); + return (to_parent(child) == link) ? child : header_link{}; +} + // address->outputs[receivers] // ---------------------------------------------------------------------------- // There can be multiple spenders of the same output (due to conflicts) and diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index 3a17b99f9..8d1548bd9 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -287,6 +287,8 @@ class query height_link find_strong_spender_height(const point& point) const NOEXCEPT; header_link to_parent(const header_link& link) const NOEXCEPT; + header_link to_candidate_child(const header_link& link) const NOEXCEPT; + header_link to_confirmed_child(const header_link& link) const NOEXCEPT; tx_links to_duplicates(const hash_digest& tx_hash) const NOEXCEPT; /// find confirmed objects (reverse navigation) From b4a7c08a22dbde2aba23acadb15417a59f6f144c Mon Sep 17 00:00:00 2001 From: Eric Voskuil Date: Wed, 26 Aug 2026 16:13:10 -0400 Subject: [PATCH 3/3] Remove candidate fallback from confirmed chain state. --- .../impl/query/consensus/consensus_chain_state.ipp | 11 ++++++++--- include/bitcoin/database/query.hpp | 4 +++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/include/bitcoin/database/impl/query/consensus/consensus_chain_state.ipp b/include/bitcoin/database/impl/query/consensus/consensus_chain_state.ipp index 136ba6f96..bea6a0cb2 100644 --- a/include/bitcoin/database/impl/query/consensus/consensus_chain_state.ipp +++ b/include/bitcoin/database/impl/query/consensus/consensus_chain_state.ipp @@ -175,7 +175,7 @@ bool CLASS::populate_all(chain_state::data& data, } TEMPLATE -typename CLASS::chain_state_cptr CLASS::get_chain_state( +typename CLASS::chain_state_cptr CLASS::get_confirmed_chain_state( const system::settings& settings, const hash_digest& hash) const NOEXCEPT { const auto link = to_header(hash); @@ -186,9 +186,14 @@ typename CLASS::chain_state_cptr CLASS::get_chain_state( if (!get_height(height, link)) return nullptr; - if (to_candidate(height) == link) - return get_candidate_chain_state(settings, link, height); + return get_confirmed_chain_state(settings, link, height); +} +TEMPLATE +typename CLASS::chain_state_cptr CLASS::get_confirmed_chain_state( + const system::settings& settings, const header_link& link, + size_t height) const NOEXCEPT +{ chain_state::data data{}; if (!populate_all(data, settings, link, height)) return nullptr; diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index 8d1548bd9..4d4d78d82 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -544,8 +544,10 @@ class query /// Context. /// ----------------------------------------------------------------------- - chain_state_cptr get_chain_state(const system::settings& settings, + chain_state_cptr get_confirmed_chain_state(const system::settings& settings, const hash_digest& hash) const NOEXCEPT; + chain_state_cptr get_confirmed_chain_state(const system::settings& settings, + const header_link& link, size_t height) const NOEXCEPT; chain_state_cptr get_candidate_chain_state( const system::settings& settings) const NOEXCEPT; chain_state_cptr get_candidate_chain_state(const system::settings& settings,