From de0eedf744f6e40160a4975e094cbc0793de38f9 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Wed, 8 Jul 2026 23:37:14 -0400 Subject: [PATCH 1/2] Add/use query::get_transactor(). --- .../impl/query/archive/chain_writer.ipp | 6 ++-- .../impl/query/archive/wire_writer.ipp | 4 +-- .../database/impl/query/batch/ecdsa.ipp | 6 ++-- .../database/impl/query/batch/prevalid.ipp | 4 +-- .../database/impl/query/batch/schnorr.ipp | 6 ++-- .../database/impl/query/batch/silent.ipp | 2 +- .../query/consensus/consensus_prevouts.ipp | 4 +-- .../impl/query/consensus/consensus_states.ipp | 4 +-- .../impl/query/consensus/consensus_strong.ipp | 4 +-- .../bitcoin/database/impl/query/filters.ipp | 4 +-- .../bitcoin/database/impl/query/height.ipp | 8 ++--- .../database/impl/query/initialize.ipp | 2 +- .../bitcoin/database/impl/query/merkle.ipp | 33 +++++++++++++++++++ include/bitcoin/database/impl/query/query.ipp | 29 ++-------------- include/bitcoin/database/query.hpp | 4 +++ 15 files changed, 66 insertions(+), 54 deletions(-) diff --git a/include/bitcoin/database/impl/query/archive/chain_writer.ipp b/include/bitcoin/database/impl/query/archive/chain_writer.ipp index 3957eace2..bb02736cd 100644 --- a/include/bitcoin/database/impl/query/archive/chain_writer.ipp +++ b/include/bitcoin/database/impl/query/archive/chain_writer.ipp @@ -104,7 +104,7 @@ code CLASS::set_code(const tx_link& tx_fk, const transaction& tx, const auto coinbase = tx.is_coinbase(); // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); // Allocate contiguously and store inputs. input_link in_fk{}; @@ -283,7 +283,7 @@ code CLASS::set_code(header_link& out_fk, const header& header, return system::error::orphan_block; // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); // Clean single allocation failure (e.g. disk full). out_fk = store_.header.put_link(key, table::header::put_ref @@ -405,7 +405,7 @@ code CLASS::set_code(const block& block, const header_link& key, (block.serialized_size(true)); // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); constexpr auto positive = true; // Transactor assures cannot be restored without txs, as required to unset. diff --git a/include/bitcoin/database/impl/query/archive/wire_writer.ipp b/include/bitcoin/database/impl/query/archive/wire_writer.ipp index 9a440a48a..156bf3f31 100644 --- a/include/bitcoin/database/impl/query/archive/wire_writer.ipp +++ b/include/bitcoin/database/impl/query/archive/wire_writer.ipp @@ -45,7 +45,7 @@ code CLASS::set_code(const tx_link& tx_fk, const transaction_view& tx, const auto coinbase = tx.is_coinbase(); // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); // Allocate contiguously and store inputs. input_link in_fk{}; @@ -273,7 +273,7 @@ code CLASS::set_code(const block_view& block, const header_link& key, (block.serialized_size(true)); // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); constexpr auto positive = true; // Transactor assures cannot be restored without txs, as required to unset. diff --git a/include/bitcoin/database/impl/query/batch/ecdsa.ipp b/include/bitcoin/database/impl/query/batch/ecdsa.ipp index 2efbb6b79..c7fab8a2a 100644 --- a/include/bitcoin/database/impl/query/batch/ecdsa.ipp +++ b/include/bitcoin/database/impl/query/batch/ecdsa.ipp @@ -67,7 +67,7 @@ TEMPLATE bool CLASS::purge_ecdsa_signatures() NOEXCEPT { // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); return store_.ecdsa.truncate(0); // ======================================================================== } @@ -84,7 +84,7 @@ bool CLASS::set_signature(const hash_digest& digest, // Caller must guard reads, this is writing into hot storage. // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); using namespace system; const auto row = possible_narrow_cast(one); @@ -120,7 +120,7 @@ bool CLASS::set_signatures(const hash_digest& digest, // Caller must guard reads, this is writing into hot storage. // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); using namespace system; const auto rows = possible_narrow_cast(count); diff --git a/include/bitcoin/database/impl/query/batch/prevalid.ipp b/include/bitcoin/database/impl/query/batch/prevalid.ipp index 90b0bbc28..20683656a 100644 --- a/include/bitcoin/database/impl/query/batch/prevalid.ipp +++ b/include/bitcoin/database/impl/query/batch/prevalid.ipp @@ -49,7 +49,7 @@ TEMPLATE bool CLASS::purge_prevalids() NOEXCEPT { // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); return store_.prevalid.truncate(0); // ======================================================================== } @@ -58,7 +58,7 @@ TEMPLATE bool CLASS::set_prevalids(const header_links& links) NOEXCEPT { // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); // Clean single allocation failure (e.g. disk full). const table::prevalid::put_refs prevalids{ {}, links }; diff --git a/include/bitcoin/database/impl/query/batch/schnorr.ipp b/include/bitcoin/database/impl/query/batch/schnorr.ipp index 9b8c174fc..8b3b8a21a 100644 --- a/include/bitcoin/database/impl/query/batch/schnorr.ipp +++ b/include/bitcoin/database/impl/query/batch/schnorr.ipp @@ -67,7 +67,7 @@ TEMPLATE bool CLASS::purge_schnorr_signatures() NOEXCEPT { // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); return store_.schnorr.truncate(0); // ======================================================================== } @@ -83,7 +83,7 @@ bool CLASS::set_signature(const hash_digest& digest, const ec_xonly& point, // Caller must guard reads, this is writing into hot storage. // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); using namespace system; const auto row = possible_narrow_cast(one); @@ -114,7 +114,7 @@ bool CLASS::set_signatures(const threshold& batch, // Caller must guard reads, this is writing into hot storage. // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); using namespace system; const auto& set = batch.tuples; diff --git a/include/bitcoin/database/impl/query/batch/silent.ipp b/include/bitcoin/database/impl/query/batch/silent.ipp index b885a63fc..3813db19e 100644 --- a/include/bitcoin/database/impl/query/batch/silent.ipp +++ b/include/bitcoin/database/impl/query/batch/silent.ipp @@ -119,7 +119,7 @@ bool CLASS::set_silent(const tx_link& link, // TODO: caller must guard reads, this is writing into hot storage. // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); using namespace system; auto rows = possible_narrow_cast(prefixes.size()); diff --git a/include/bitcoin/database/impl/query/consensus/consensus_prevouts.ipp b/include/bitcoin/database/impl/query/consensus/consensus_prevouts.ipp index 2ca50d407..7dfdd383c 100644 --- a/include/bitcoin/database/impl/query/consensus/consensus_prevouts.ipp +++ b/include/bitcoin/database/impl/query/consensus/consensus_prevouts.ipp @@ -46,7 +46,7 @@ code CLASS::get_prevouts(point_sets& sets, size_t points, // Transactor required for prevout read because of pruning. // ======================================================================== { - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); if (!store_.prevout.at(prevout, cache)) return error::integrity_get_prevouts; @@ -90,7 +90,7 @@ bool CLASS::set_prevouts(const header_link& link, const block& block) NOEXCEPT const auto prevout = to_prevout(link); // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); // Clean single allocation failure (e.g. disk full). const table::prevout::slab_put_ref prevouts{ {}, doubles, block }; diff --git a/include/bitcoin/database/impl/query/consensus/consensus_states.ipp b/include/bitcoin/database/impl/query/consensus/consensus_states.ipp index 867b95ac5..61b893b9d 100644 --- a/include/bitcoin/database/impl/query/consensus/consensus_states.ipp +++ b/include/bitcoin/database/impl/query/consensus/consensus_states.ipp @@ -254,7 +254,7 @@ bool CLASS::set_block_state(const header_link& link, const auto record = to_validated_bk(link); // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); // Clean single allocation failure (e.g. disk full). return store_.validated_bk.put(record, @@ -290,7 +290,7 @@ bool CLASS::set_tx_state(const tx_link& link, const context& ctx, using sigs = linkage; // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); using namespace system; // Clean single allocation failure (e.g. disk full). diff --git a/include/bitcoin/database/impl/query/consensus/consensus_strong.ipp b/include/bitcoin/database/impl/query/consensus/consensus_strong.ipp index 4545c3b64..f16848de9 100644 --- a/include/bitcoin/database/impl/query/consensus/consensus_strong.ipp +++ b/include/bitcoin/database/impl/query/consensus/consensus_strong.ipp @@ -141,7 +141,7 @@ bool CLASS::set_strong(const header_link& link) NOEXCEPT BC_ASSERT(!is_zero(txs.number) && txs.coinbase_fk != tx_link::terminal); // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); // Clean allocation failure (e.g. disk full). return set_strong(link, txs.number, txs.coinbase_fk , true); @@ -159,7 +159,7 @@ bool CLASS::set_unstrong(const header_link& link) NOEXCEPT BC_ASSERT(!is_zero(txs.number) && txs.coinbase_fk != tx_link::terminal); // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); // Clean allocation failure (e.g. disk full). return set_strong(link, txs.number, txs.coinbase_fk, false); diff --git a/include/bitcoin/database/impl/query/filters.ipp b/include/bitcoin/database/impl/query/filters.ipp index 09728b246..65c0b6b76 100644 --- a/include/bitcoin/database/impl/query/filters.ipp +++ b/include/bitcoin/database/impl/query/filters.ipp @@ -165,7 +165,7 @@ bool CLASS::set_filter_body(const header_link& link, return true; // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); // Clean single allocation failure (e.g. disk full). return store_.filter_tx.put(to_filter_tx(link), table::filter_tx::put_ref @@ -209,7 +209,7 @@ bool CLASS::set_filter_head(const header_link& link, const hash_digest& head, return true; // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); // Clean single allocation failure (e.g. disk full). return store_.filter_bk.put(to_filter_bk(link), table::filter_bk::put_ref diff --git a/include/bitcoin/database/impl/query/height.ipp b/include/bitcoin/database/impl/query/height.ipp index 33bb03ace..f9c4ac4f4 100644 --- a/include/bitcoin/database/impl/query/height.ipp +++ b/include/bitcoin/database/impl/query/height.ipp @@ -40,7 +40,7 @@ bool CLASS::push_candidate(const header_link& link) NOEXCEPT return false; // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); // Clean single allocation failure (e.g. disk full). const table::height::record candidate{ {}, link }; @@ -58,7 +58,7 @@ bool CLASS::pop_candidate() NOEXCEPT // Clean single allocation failure (e.g. disk full). // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); // Candidate pop implies reorg or disorg, which implies future duplicates. store_.set_dirty(); @@ -82,7 +82,7 @@ bool CLASS::push_confirmed(const header_link& link, bool strong) NOEXCEPT return false; // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); // This reservation guard assumes no concurrent writes to the table. if (strong && !set_strong(link, txs.number, txs.coinbase_fk, true)) @@ -107,7 +107,7 @@ bool CLASS::pop_confirmed() NOEXCEPT return {}; // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); // Clean single allocation failure. if (!set_strong(link, txs.number, txs.coinbase_fk, false)) diff --git a/include/bitcoin/database/impl/query/initialize.ipp b/include/bitcoin/database/impl/query/initialize.ipp index 3ea3748d6..4e02bf202 100644 --- a/include/bitcoin/database/impl/query/initialize.ipp +++ b/include/bitcoin/database/impl/query/initialize.ipp @@ -198,7 +198,7 @@ bool CLASS::initialize(const block& genesis) NOEXCEPT // TODO: add genesis block filter_tx head and body when filter_tx is enabled. // ======================================================================== - const auto scope = store_.get_transactor(); + const auto scope = get_transactor(); if (!set(genesis, context{}, false, false)) return false; diff --git a/include/bitcoin/database/impl/query/merkle.ipp b/include/bitcoin/database/impl/query/merkle.ipp index 1cd5f7448..c68292953 100644 --- a/include/bitcoin/database/impl/query/merkle.ipp +++ b/include/bitcoin/database/impl/query/merkle.ipp @@ -277,6 +277,39 @@ code CLASS::get_merkle_subroots(hashes& roots, size_t waypoint) const NOEXCEPT return error::success; } +// ---------------------------------------------------------------------------- + +TEMPLATE +size_t CLASS::interval_span() const NOEXCEPT +{ + if (const auto span = span_.load(std::memory_order_relaxed); + is_nonzero(span)) + return span; + + // initialize_span() never returns zero. + span_.store(initialize_span(), std::memory_order_relaxed); + return span_; +} + +// protected +TEMPLATE +size_t CLASS::interval_depth() const NOEXCEPT +{ + table::txs::get_genesis_depth txs{}; + return store_.txs.at(to_txs(0), txs) ? txs.depth : store_.interval_depth(); +} + +// protected +TEMPLATE +size_t CLASS::initialize_span() const NOEXCEPT +{ + // span of zero (overflow) is disallowed (division by zero). + // span of one (2^0) caches every block (no optimization, wasted storage). + // span greater than top height eliminates caching (no optimization). + const auto span = system::power2(interval_depth()); + return is_zero(span) ? max_size_t : span; +} + } // namespace database } // namespace libbitcoin diff --git a/include/bitcoin/database/impl/query/query.ipp b/include/bitcoin/database/impl/query/query.ipp index 389feadff..e6a6f5179 100644 --- a/include/bitcoin/database/impl/query/query.ipp +++ b/include/bitcoin/database/impl/query/query.ipp @@ -74,34 +74,9 @@ CLASS::query(Store& store) NOEXCEPT } TEMPLATE -size_t CLASS::interval_span() const NOEXCEPT +const typename CLASS::transactor CLASS::get_transactor() const NOEXCEPT { - if (const auto span = span_.load(std::memory_order_relaxed); - is_nonzero(span)) - return span; - - // initialize_span() never returns zero. - span_.store(initialize_span(), std::memory_order_relaxed); - return span_; -} - -// protected -TEMPLATE -size_t CLASS::interval_depth() const NOEXCEPT -{ - table::txs::get_genesis_depth txs{}; - return store_.txs.at(to_txs(0), txs) ? txs.depth : store_.interval_depth(); -} - -// protected -TEMPLATE -size_t CLASS::initialize_span() const NOEXCEPT -{ - // span of zero (overflow) is disallowed (division by zero). - // span of one (2^0) caches every block (no optimization, wasted storage). - // span greater than top height eliminates caching (no optimization). - const auto span = system::power2(interval_depth()); - return is_zero(span) ? max_size_t : span; + return store_.get_transactor(); } TEMPLATE diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index 9fe8cdf3b..b47ca5c2e 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -33,6 +33,7 @@ class query { public: DELETE_COPY_MOVE_DESTRUCT(query); + using transactor = typename Store::transactor; /// Chain type aliases. using block = system::chain::block; @@ -65,6 +66,9 @@ class query /// Store management from query-holder (not store owner) context. /// ----------------------------------------------------------------------- + /// Get a transactor object. + const transactor get_transactor() const NOEXCEPT; + /// Get first fault code, or disk_full if none and full, or success. code get_code() const NOEXCEPT; From 27aecd064242b77404cae9a3eee89fb449823c80 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Wed, 8 Jul 2026 23:57:20 -0400 Subject: [PATCH 2/2] Make transactor movable (non-const). --- include/bitcoin/database/impl/query/query.ipp | 2 +- include/bitcoin/database/impl/store/store.ipp | 2 +- include/bitcoin/database/query.hpp | 2 +- include/bitcoin/database/store.hpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/bitcoin/database/impl/query/query.ipp b/include/bitcoin/database/impl/query/query.ipp index e6a6f5179..d6ed272f1 100644 --- a/include/bitcoin/database/impl/query/query.ipp +++ b/include/bitcoin/database/impl/query/query.ipp @@ -74,7 +74,7 @@ CLASS::query(Store& store) NOEXCEPT } TEMPLATE -const typename CLASS::transactor CLASS::get_transactor() const NOEXCEPT +typename CLASS::transactor CLASS::get_transactor() const NOEXCEPT { return store_.get_transactor(); } diff --git a/include/bitcoin/database/impl/store/store.ipp b/include/bitcoin/database/impl/store/store.ipp index f1dfdc33b..1440af26d 100644 --- a/include/bitcoin/database/impl/store/store.ipp +++ b/include/bitcoin/database/impl/store/store.ipp @@ -176,7 +176,7 @@ void CLASS::set_dirty() NOEXCEPT } TEMPLATE -const typename CLASS::transactor CLASS::get_transactor() NOEXCEPT +typename CLASS::transactor CLASS::get_transactor() NOEXCEPT { return transactor{ transactor_mutex_ }; } diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index b47ca5c2e..ae503f265 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -67,7 +67,7 @@ class query /// ----------------------------------------------------------------------- /// Get a transactor object. - const transactor get_transactor() const NOEXCEPT; + transactor get_transactor() const NOEXCEPT; /// Get first fault code, or disk_full if none and full, or success. code get_code() const NOEXCEPT; diff --git a/include/bitcoin/database/store.hpp b/include/bitcoin/database/store.hpp index 432df9cf3..69a338ae6 100644 --- a/include/bitcoin/database/store.hpp +++ b/include/bitcoin/database/store.hpp @@ -105,7 +105,7 @@ class store size_t get_space() const NOEXCEPT; /// Get a transactor object. - const transactor get_transactor() NOEXCEPT; + transactor get_transactor() NOEXCEPT; protected: using path = std::filesystem::path;