From 35bd0c5acc72815eb9116081d5a34a1c3e86b1d9 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sun, 22 Feb 2026 14:30:02 -0500 Subject: [PATCH] Drop fees from validated_bk and change to array, DRY in tx/bk setters. --- .../bitcoin/database/impl/query/validate.ipp | 147 ++++-------------- include/bitcoin/database/query.hpp | 9 +- .../database/tables/caches/validated_bk.hpp | 39 +---- .../database/tables/optionals/filter_bk.hpp | 1 + include/bitcoin/database/tables/schema.hpp | 22 +-- test/query/validate.cpp | 2 +- test/tables/caches/validated_bk.cpp | 57 ++++--- 7 files changed, 89 insertions(+), 188 deletions(-) diff --git a/include/bitcoin/database/impl/query/validate.ipp b/include/bitcoin/database/impl/query/validate.ipp index 65e26af68..5060ed2d1 100644 --- a/include/bitcoin/database/impl/query/validate.ipp +++ b/include/bitcoin/database/impl/query/validate.ipp @@ -118,7 +118,7 @@ bool CLASS::is_unconfirmable(const header_link& link) const NOEXCEPT TEMPLATE code CLASS::get_header_state(const header_link& link) const NOEXCEPT { - table::validated_bk::slab_get_code valid{}; + table::validated_bk::record valid{}; if (!store_.validated_bk.at(to_validated_bk(link), valid)) return error::unvalidated; @@ -133,7 +133,7 @@ code CLASS::get_header_state(const header_link& link) const NOEXCEPT TEMPLATE code CLASS::get_block_state(const header_link& link) const NOEXCEPT { - table::validated_bk::slab_get_code valid{}; + table::validated_bk::record valid{}; if (!store_.validated_bk.at(to_validated_bk(link), valid)) return is_associated(link) ? error::unvalidated : error::unassociated; @@ -305,171 +305,92 @@ bool CLASS::get_context(system::chain::context& ctx, return true; } -// Setters. +// set_block_state // ---------------------------------------------------------------------------- TEMPLATE -bool CLASS::set_block_valid(const header_link& link, uint64_t fees) NOEXCEPT +bool CLASS::set_block_valid(const header_link& link) NOEXCEPT { - // ======================================================================== - const auto scope = store_.get_transactor(); - - // Clean single allocation failure (e.g. disk full). - return store_.validated_bk.put(to_validated_bk(link), - table::validated_bk::slab - { - {}, - schema::block_state::valid, - fees - }); - // ======================================================================== + return set_block_state(link, schema::block_state::valid); } TEMPLATE bool CLASS::set_block_confirmable(const header_link& link) NOEXCEPT { - // ======================================================================== - const auto scope = store_.get_transactor(); - - // Clean single allocation failure (e.g. disk full). - return store_.validated_bk.put(to_validated_bk(link), - table::validated_bk::slab - { - {}, - schema::block_state::confirmable, - 0 // fees - }); - // ======================================================================== + return set_block_state(link, schema::block_state::confirmable); } TEMPLATE bool CLASS::set_block_unconfirmable(const header_link& link) NOEXCEPT { - // ======================================================================== - const auto scope = store_.get_transactor(); - - // Clean single allocation failure (e.g. disk full). - return store_.validated_bk.put(to_validated_bk(link), - table::validated_bk::slab - { - {}, - schema::block_state::unconfirmable, - 0 // fees - }); - // ======================================================================== + return set_block_state(link, schema::block_state::unconfirmable); } TEMPLATE bool CLASS::set_block_unknown(const header_link& link) NOEXCEPT { + return set_block_state(link, schema::block_state::block_unknown); +} + +// private +TEMPLATE +bool CLASS::set_block_state(const header_link& link, + schema::block_state state) NOEXCEPT +{ + const auto record = to_validated_bk(link); + // ======================================================================== const auto scope = store_.get_transactor(); // Clean single allocation failure (e.g. disk full). - return store_.validated_bk.put(to_validated_bk(link), - table::validated_bk::slab - { - {}, - schema::block_state::block_unknown, - 0 // fees - }); + return store_.validated_bk.put(record, + table::validated_bk::record{ {}, state }); // ======================================================================== } +// set_tx_state +// ---------------------------------------------------------------------------- + TEMPLATE bool CLASS::set_tx_unknown(const tx_link& link) NOEXCEPT { - // ======================================================================== - const auto scope = store_.get_transactor(); - - // Clean single allocation failure (e.g. disk full). - return store_.validated_tx.put(link, table::validated_tx::slab - { - {}, - {}, - schema::tx_state::tx_unknown, - 0, // fee - 0 // sigops - }); - // ======================================================================== + return set_tx_state(link, {}, {}, {}, schema::tx_state::tx_unknown); } TEMPLATE bool CLASS::set_tx_disconnected(const tx_link& link, const context& ctx) NOEXCEPT { - // ======================================================================== - const auto scope = store_.get_transactor(); - - // Clean single allocation failure (e.g. disk full). - return store_.validated_tx.put(link, table::validated_tx::slab - { - {}, - ctx, - schema::tx_state::disconnected, - 0, // fee - 0 // sigops - }); - // ======================================================================== + return set_tx_state(link, ctx, {}, {}, schema::tx_state::disconnected); } TEMPLATE bool CLASS::set_tx_connected(const tx_link& link, const context& ctx, uint64_t fee, size_t sigops) NOEXCEPT +{ + return set_tx_state(link, ctx, fee, sigops, schema::tx_state::connected); +} + +// private +TEMPLATE +bool CLASS::set_tx_state(const tx_link& link, const context& ctx, + uint64_t fee, size_t sigops, schema::tx_state state) NOEXCEPT { using sigs = linkage; BC_ASSERT(sigops(to_bits(sigs::size))); // ======================================================================== const auto scope = store_.get_transactor(); + using namespace system; // Clean single allocation failure (e.g. disk full). return store_.validated_tx.put(link, table::validated_tx::slab { - {}, - ctx, - schema::tx_state::connected, - fee, - system::possible_narrow_cast(sigops) + {}, ctx, state, fee, possible_narrow_cast(sigops) }); // ======================================================================== } -////TEMPLATE -////bool CLASS::set_txs_connected(const header_link& link) NOEXCEPT -////{ -//// context ctx{}; -//// if (!get_context(ctx, link)) -//// return false; -//// -//// const auto txs = to_transactions(link); -//// if (txs.empty()) -//// return false; -//// -//// // FOR PERFORMANCE EVALUATION ONLY. -//// constexpr uint64_t fee = 99; -//// constexpr size_t sigops = 42; -//// using sigs = linkage; -//// -//// // ======================================================================== -//// const auto scope = store_.get_transactor(); -//// -//// // Clean single allocation failure (e.g. disk full). -//// return std_all_of(bc::seq, txs.begin(), txs.end(), -//// [&](const tx_link& fk) NOEXCEPT -//// { -//// return store_.validated_tx.put(fk, table::validated_tx::slab -//// { -//// {}, -//// ctx, -//// schema::tx_state::connected, -//// fee, -//// system::possible_narrow_cast(sigops) -//// }); -//// }); -//// // ======================================================================== -////} - } // namespace database } // namespace libbitcoin diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index 525a96bbc..7bac8d4f9 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -502,7 +502,7 @@ class query const header_link& link) const NOEXCEPT; /// Setters. - bool set_block_valid(const header_link& link, uint64_t fees) NOEXCEPT; + bool set_block_valid(const header_link& link) NOEXCEPT; bool set_block_unconfirmable(const header_link& link) NOEXCEPT; bool set_block_confirmable(const header_link& link) NOEXCEPT; bool set_block_unknown(const header_link& link) NOEXCEPT; @@ -654,6 +654,13 @@ class query bool is_block_validated(code& state, const header_link& link, size_t height, size_t checkpoint) const NOEXCEPT; + /// Setters. + /// ----------------------------------------------------------------------- + bool set_block_state(const header_link& link, + schema::block_state state) NOEXCEPT; + bool set_tx_state(const tx_link& link, const context& ctx, + uint64_t fee, size_t sigops, schema::tx_state state) NOEXCEPT; + /// Confirm. /// ----------------------------------------------------------------------- bool is_confirmed_unspent(const output_link& link) const NOEXCEPT; diff --git a/include/bitcoin/database/tables/caches/validated_bk.hpp b/include/bitcoin/database/tables/caches/validated_bk.hpp index a5f7d7d7f..355bc267b 100644 --- a/include/bitcoin/database/tables/caches/validated_bk.hpp +++ b/include/bitcoin/database/tables/caches/validated_bk.hpp @@ -34,57 +34,28 @@ struct validated_bk using coding = linkage; using array_map::arraymap; - struct slab + struct record : public schema::validated_bk { - inline link count() const NOEXCEPT - { - using namespace system; - return possible_narrow_cast(coding::size + - variable_size(fees)); - } - inline bool from_data(reader& source) NOEXCEPT { code = source.read_little_endian(); - fees = source.read_variable(); - BC_ASSERT(!source || source.get_read_position() == count()); + BC_ASSERT(!source || source.get_read_position() == count() * minrow); return source; } inline bool to_data(finalizer& sink) const NOEXCEPT { sink.write_little_endian(code); - sink.write_variable(fees); - BC_ASSERT(!sink || sink.get_write_position() == count()); + BC_ASSERT(!sink || sink.get_write_position() == count() * minrow); return sink; } - inline bool operator==(const slab& other) const NOEXCEPT - { - return code == other.code - && fees == other.fees; - } - - coding::integer code{}; - uint64_t fees{}; - }; - - struct slab_get_code - : public schema::validated_bk - { - inline link count() const NOEXCEPT + inline bool operator==(const record& other) const NOEXCEPT { - BC_ASSERT(false); - return {}; + return code == other.code; } - inline bool from_data(reader& source) NOEXCEPT - { - code = source.read_little_endian(); - return source; - } - coding::integer code{}; }; }; diff --git a/include/bitcoin/database/tables/optionals/filter_bk.hpp b/include/bitcoin/database/tables/optionals/filter_bk.hpp index 4128cf042..1047dc9ad 100644 --- a/include/bitcoin/database/tables/optionals/filter_bk.hpp +++ b/include/bitcoin/database/tables/optionals/filter_bk.hpp @@ -40,6 +40,7 @@ struct filter_bk { hash = source.read_hash(); head = source.read_hash(); + BC_ASSERT(!source || source.get_read_position() == count() * minrow); return source; } diff --git a/include/bitcoin/database/tables/schema.hpp b/include/bitcoin/database/tables/schema.hpp index 92170ef7b..075265275 100644 --- a/include/bitcoin/database/tables/schema.hpp +++ b/include/bitcoin/database/tables/schema.hpp @@ -48,7 +48,6 @@ constexpr size_t prevout_ = 5; // ->prevout slab. constexpr size_t txs_ = 5; // ->txs slab. constexpr size_t tx = 4; // ->tx record. constexpr size_t block = 3; // ->header record. -constexpr size_t bk_slab = 4; // ->validated_bk record. constexpr size_t tx_slab = 5; // ->validated_tx record. constexpr size_t filter_ = 5; // ->filter record. constexpr size_t doubles_ = 4; // doubles bucket (no actual keys). @@ -56,6 +55,10 @@ constexpr size_t doubles_ = 4; // doubles bucket (no actual keys). /// Archive tables. /// ----------------------------------------------------------------------- +// size_t `cell` sets the hashmap bucket size (minimum size of link type). +// bool `align` causes arraymap bucket size to be expanded to nearest word. +// Memory fencing used (vs. mutex) when array/hashmap bucket is word sized. + // record hashmap struct header { @@ -295,20 +298,20 @@ struct prevout static_assert(link::size == 5u); }; -// slab arraymap +// record arraymap struct validated_bk { static constexpr size_t align = false; - static constexpr size_t pk = schema::bk_slab; + static constexpr size_t pk = schema::block; using link = linkage; static constexpr size_t minsize = - schema::code + // TODO: change code to variable. - one; + schema::code; static constexpr size_t minrow = minsize; - static constexpr size_t size = max_size_t; - static_assert(minsize == 2u); - static_assert(minrow == 2u); - static_assert(link::size == 4u); + static constexpr size_t size = minsize; + static constexpr link count() NOEXCEPT { return 1; } + static_assert(minsize == 1u); + static_assert(minrow == 1u); + static_assert(link::size == 3u); }; // slab modest (sk:4) multimap, with low multiple rate. @@ -331,6 +334,7 @@ struct validated_tx static inline link count() NOEXCEPT; static_assert(minsize == 14u); static_assert(minrow == 23u); + static_assert(link::size == 5u); }; /// Optional tables. diff --git a/test/query/validate.cpp b/test/query/validate.cpp index aedaa71f5..83df9d625 100644 --- a/test/query/validate.cpp +++ b/test/query/validate.cpp @@ -234,7 +234,7 @@ BOOST_AUTO_TEST_CASE(query_validate__get_block_state__valid__block_valid) BOOST_REQUIRE(query.initialize(test::genesis)); BOOST_REQUIRE(query.set(test::block1, context{}, false, false)); - BOOST_REQUIRE(query.set_block_valid(1, 42)); + BOOST_REQUIRE(query.set_block_valid(1)); BOOST_REQUIRE_EQUAL(query.get_header_state(1), error::block_valid); BOOST_REQUIRE_EQUAL(query.get_block_state(1), error::block_valid); } diff --git a/test/tables/caches/validated_bk.cpp b/test/tables/caches/validated_bk.cpp index 5c462d8a1..c681a939b 100644 --- a/test/tables/caches/validated_bk.cpp +++ b/test/tables/caches/validated_bk.cpp @@ -22,39 +22,36 @@ BOOST_AUTO_TEST_SUITE(validated_bk_tests) using namespace system; -const table::validated_bk::slab slab1{ {}, 0x42, 0x1122334455667788 }; -const table::validated_bk::slab slab2{ {}, 0xab, 0x0000000000000042 }; +const table::validated_bk::record record1{ {}, 0x42 }; +const table::validated_bk::record record2{ {}, 0xab }; const data_chunk expected_head = base16_chunk ( - "00000000" - "00000000" - "0a000000" - "ffffffff" - "ffffffff" - "ffffffff" - "ffffffff" - "ffffffff" - "ffffffff" + "000000" + "000000" + "010000" + "ffffff" + "ffffff" + "ffffff" + "ffffff" + "ffffff" + "ffffff" ); const data_chunk closed_head = base16_chunk ( - "0c000000" - "00000000" - "0a000000" - "ffffffff" - "ffffffff" - "ffffffff" - "ffffffff" - "ffffffff" - "ffffffff" + "020000" + "000000" + "010000" + "ffffff" + "ffffff" + "ffffff" + "ffffff" + "ffffff" + "ffffff" ); const data_chunk expected_body = base16_chunk ( "42" // code1 - "ff8877665544332211" // fees1 - "ab" // code2 - "42" // fees2 ); BOOST_AUTO_TEST_CASE(validated_bk__put__two__expected) @@ -64,10 +61,10 @@ BOOST_AUTO_TEST_CASE(validated_bk__put__two__expected) table::validated_bk instance{ head_store, body_store, 8 }; BOOST_REQUIRE(instance.create()); - BOOST_REQUIRE(instance.put(0, slab1)); + BOOST_REQUIRE(instance.put(0, record1)); BOOST_REQUIRE_EQUAL(instance.at(0), 0u); - BOOST_REQUIRE(instance.put(1, slab2)); - BOOST_REQUIRE_EQUAL(instance.at(1), 10u); + BOOST_REQUIRE(instance.put(1, record2)); + BOOST_REQUIRE_EQUAL(instance.at(1), 1u); BOOST_REQUIRE_EQUAL(head_store.buffer(), expected_head); BOOST_REQUIRE_EQUAL(body_store.buffer(), expected_body); @@ -85,11 +82,11 @@ BOOST_AUTO_TEST_CASE(validated_bk__get__two__expected) BOOST_REQUIRE_EQUAL(head_store.buffer(), expected_head); BOOST_REQUIRE_EQUAL(body_store.buffer(), expected_body); - table::validated_bk::slab out{}; + table::validated_bk::record out{}; BOOST_REQUIRE(instance.get(0, out)); - BOOST_REQUIRE(out == slab1); - BOOST_REQUIRE(instance.get(10, out)); - BOOST_REQUIRE(out == slab2); + BOOST_REQUIRE(out == record1); + BOOST_REQUIRE(instance.get(1, out)); + BOOST_REQUIRE(out == record2); } BOOST_AUTO_TEST_SUITE_END()