diff --git a/include/bitcoin/database/impl/query/height.ipp b/include/bitcoin/database/impl/query/height.ipp index b5a81a48..1835d8a8 100644 --- a/include/bitcoin/database/impl/query/height.ipp +++ b/include/bitcoin/database/impl/query/height.ipp @@ -236,6 +236,42 @@ hashes CLASS::get_confirmed_hashes(size_t first, size_t count) const NOEXCEPT return out; } +TEMPLATE +header_links CLASS::get_confirmed_headers(size_t first, + size_t maximum) const NOEXCEPT +{ + // Empty is always a successful/valid result for this method. + if (is_zero(maximum)) + return {}; + + // First requested height is currently above top. + const auto top = get_top_confirmed(); + if (first > top) + return {}; + + // add1(top) cannot overflow, as indexed block maximum cannot exceed size_t. + maximum = system::limit(maximum, add1(top) - first); + auto last = first + sub1(maximum); + + // Due to reorganization it is possible for this height to now be terminal. + auto link = to_confirmed(last); + + // Walk link back to first indexed header (for reorg safety). + while (link.is_terminal() && last > first) + link = to_confirmed(--last); + + // No headers are currently confirmed at/above first. + if (link.is_terminal()) + return {}; + + // Compiler should optimize out last to_parent() call. + header_links out(add1(last - first)); + for (auto& value: std::views::reverse(out)) + link = to_parent(value = link); + + return out; +} + // writers // ---------------------------------------------------------------------------- diff --git a/include/bitcoin/database/impl/query/optional.ipp b/include/bitcoin/database/impl/query/optional.ipp index 6d53dcd1..3f1426a5 100644 --- a/include/bitcoin/database/impl/query/optional.ipp +++ b/include/bitcoin/database/impl/query/optional.ipp @@ -310,7 +310,7 @@ CLASS::hash_option CLASS::get_confirmed_interval(size_t height) const NOEXCEPT return {}; table::txs::get_interval txs{}; - if (!store_.txs.get(to_confirmed(height), txs)) + if (!store_.txs.at(to_confirmed(height), txs)) return {}; return txs.interval; @@ -318,7 +318,7 @@ CLASS::hash_option CLASS::get_confirmed_interval(size_t height) const NOEXCEPT // protected TEMPLATE -void CLASS::push_merkle(hashes& to, hashes&& from, size_t first) NOEXCEPT +void CLASS::push_merkle(hashes& to, hashes&& from, size_t first) const NOEXCEPT { using namespace system; for (const auto& row: block::merkle_branch(first, from.size())) @@ -333,7 +333,7 @@ void CLASS::push_merkle(hashes& to, hashes&& from, size_t first) NOEXCEPT // protected TEMPLATE code CLASS::get_merkle_proof(hashes& proof, hashes roots, size_t target, - size_t waypoint) NOEXCEPT + size_t waypoint) const NOEXCEPT { const auto span = interval_span(); BC_ASSERT(!is_zero(span)); @@ -353,7 +353,7 @@ code CLASS::get_merkle_proof(hashes& proof, hashes roots, size_t target, // protected TEMPLATE -code CLASS::get_merkle_tree(hashes& tree, size_t waypoint) NOEXCEPT +code CLASS::get_merkle_tree(hashes& tree, size_t waypoint) const NOEXCEPT { const auto span = interval_span(); BC_ASSERT(!is_zero(span)); @@ -384,7 +384,7 @@ code CLASS::get_merkle_tree(hashes& tree, size_t waypoint) NOEXCEPT TEMPLATE code CLASS::get_merkle_root_and_proof(hash_digest& root, hashes& proof, - size_t target, size_t waypoint) NOEXCEPT + size_t target, size_t waypoint) const NOEXCEPT { if (target > waypoint) return error::merkle_arguments; diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index 39a24229..68d0d8d7 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -538,6 +538,8 @@ class query hashes get_candidate_hashes(const heights& heights) const NOEXCEPT; hashes get_confirmed_hashes(const heights& heights) const NOEXCEPT; hashes get_confirmed_hashes(size_t first, size_t count) const NOEXCEPT; + header_links get_confirmed_headers(size_t first, + size_t maximum) const NOEXCEPT; header_links get_confirmed_fork(const header_link& fork) const NOEXCEPT; header_links get_candidate_fork(size_t& fork_point) const NOEXCEPT; @@ -573,7 +575,7 @@ class query uint64_t& balance, const hash_digest& key, bool turbo=false) const NOEXCEPT; code get_merkle_root_and_proof(hash_digest& root, hashes& proof, - size_t target, size_t checkpoint) NOEXCEPT; + size_t target, size_t checkpoint) const NOEXCEPT; bool is_filtered_body(const header_link& link) const NOEXCEPT; bool get_filter_body(filter& out, const header_link& link) const NOEXCEPT; @@ -721,10 +723,10 @@ class query size_t interval_span() const NOEXCEPT; hash_option get_confirmed_interval(size_t height) const NOEXCEPT; hash_option create_interval(header_link link, size_t height) const NOEXCEPT; - void push_merkle(hashes& branch, hashes&& hashes, size_t first) NOEXCEPT; - code get_merkle_tree(hashes& roots, size_t waypoint) NOEXCEPT; + void push_merkle(hashes& branch, hashes&& hashes, size_t first) const NOEXCEPT; + code get_merkle_tree(hashes& roots, size_t waypoint) const NOEXCEPT; code get_merkle_proof(hashes& proof, hashes roots, size_t target, - size_t waypoint) NOEXCEPT; + size_t waypoint) const NOEXCEPT; /// tx_fk must be allocated. /// -----------------------------------------------------------------------