From 787c66edfee144d5e9fb6fde2ecb6236363b4fe0 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sat, 6 Dec 2025 21:37:27 -0500 Subject: [PATCH 1/3] Make unspendable() return code. --- .../bitcoin/database/impl/query/consensus.ipp | 18 +++++++++--------- include/bitcoin/database/query.hpp | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/bitcoin/database/impl/query/consensus.ipp b/include/bitcoin/database/impl/query/consensus.ipp index 870ed65ed..562b8e125 100644 --- a/include/bitcoin/database/impl/query/consensus.ipp +++ b/include/bitcoin/database/impl/query/consensus.ipp @@ -185,7 +185,7 @@ bool CLASS::is_strong(const tx_link& tx) const NOEXCEPT // protected TEMPLATE -error::error_t CLASS::unspendable(uint32_t sequence, bool coinbase, +code CLASS::unspendable(uint32_t sequence, bool coinbase, const tx_link& tx, uint32_t version, const context& ctx) const NOEXCEPT { // Ensure prevout tx is in a strong block, first try self link. @@ -317,27 +317,27 @@ code CLASS::block_confirmable(const header_link& link) const NOEXCEPT // Get points for each tx, and sum the total number. std::transform(parallel, txs.begin(), txs.end(), sets.begin(), to_set); - if (failure) - return { failure.load() }; + if (failure != error::success) + return failure.load(); // Check double spends strength, populates prevout parent tx/cb/sq links. if ((ec = populate_prevouts(sets, points, link))) return ec; - const auto is_unspendable = [this, &ctx, &failure](const auto& set) NOEXCEPT + const auto is_spendable = [this, &ctx, &failure](const auto& set) NOEXCEPT { - error::error_t ec{}; + code ec{}; for (const auto& point: set.points) if (!point.tx.is_terminal() && ((ec = unspendable(point.sequence, point.coinbase, point.tx, set.version, ctx)))) - failure.store(ec); + failure.store(static_cast(ec.value())); - return failure != error::success; + return failure == error::success; }; // Check all spends for spendability (strong, unlocked and mature). - if (std::any_of(parallel, sets.begin(), sets.end(), is_unspendable)) - return { failure.load() }; + if (!std::all_of(parallel, sets.begin(), sets.end(), is_spendable)) + return failure.load(); return error::success; } diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index 48b134365..a5a23b963 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -652,7 +652,7 @@ class query const context& ctx) const NOEXCEPT; /// Called by block_confirmable (populate and check double spends). - error::error_t unspendable(uint32_t sequence, bool coinbase, + code unspendable(uint32_t sequence, bool coinbase, const tx_link& prevout_tx, uint32_t version, const context& ctx) const NOEXCEPT; From 8586258c4a9680e4bf5d3be37f7511e8c24c6fa6 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sat, 6 Dec 2025 21:55:58 -0500 Subject: [PATCH 2/3] Create separate header for typedefs, add get_spenders(). --- Makefile.am | 1 + .../libbitcoin-database.vcxproj | 1 + .../libbitcoin-database.vcxproj.filters | 3 + include/bitcoin/database.hpp | 1 + .../bitcoin/database/impl/query/objects.ipp | 43 ++++++++----- include/bitcoin/database/query.hpp | 35 ++--------- include/bitcoin/database/types.hpp | 62 +++++++++++++++++++ 7 files changed, 102 insertions(+), 44 deletions(-) create mode 100644 include/bitcoin/database/types.hpp diff --git a/Makefile.am b/Makefile.am index 5ab26cb67..305844e41 100644 --- a/Makefile.am +++ b/Makefile.am @@ -144,6 +144,7 @@ include_bitcoin_database_HEADERS = \ include/bitcoin/database/query.hpp \ include/bitcoin/database/settings.hpp \ include/bitcoin/database/store.hpp \ + include/bitcoin/database/types.hpp \ include/bitcoin/database/version.hpp include_bitcoin_database_filedir = ${includedir}/bitcoin/database/file diff --git a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj index 29e821e99..fa25058ef 100644 --- a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj +++ b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj @@ -197,6 +197,7 @@ + diff --git a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters index 7a2222c06..04231aeed 100644 --- a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters +++ b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters @@ -290,6 +290,9 @@ include\bitcoin\database\tables + + include\bitcoin\database + include\bitcoin\database diff --git a/include/bitcoin/database.hpp b/include/bitcoin/database.hpp index fe1fd8e8d..8412c80d2 100644 --- a/include/bitcoin/database.hpp +++ b/include/bitcoin/database.hpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/include/bitcoin/database/impl/query/objects.ipp b/include/bitcoin/database/impl/query/objects.ipp index f15a1f138..1ef3d4651 100644 --- a/include/bitcoin/database/impl/query/objects.ipp +++ b/include/bitcoin/database/impl/query/objects.ipp @@ -305,8 +305,27 @@ typename CLASS::output::cptr CLASS::get_output( } TEMPLATE -typename CLASS::outpoint CLASS::get_spent( - const output_link& link) const NOEXCEPT +typename CLASS::inputs_ptr CLASS::get_spenders( + const output_link& link, bool witness) const NOEXCEPT +{ + using namespace system; + const auto point_fks = to_spenders(link); + const auto inputs = to_shared(); + inputs->reserve(point_fks.size()); + + // TODO: eliminate shared memory pointer reallocation. + for (const auto& point_fk: point_fks) + if (!push_bool(*inputs, get_input(point_fk, witness))) + return {}; + + return inputs; +} + +// Inpoint and outpoint result sets. +// ---------------------------------------------------------------------------- + +TEMPLATE +outpoint CLASS::get_spent(const output_link& link) const NOEXCEPT { table::output::get_parent_value out{}; if (!store_.output.get(link, out)) @@ -320,7 +339,7 @@ typename CLASS::outpoint CLASS::get_spent( } TEMPLATE -typename CLASS::point CLASS::get_spender(const point_link& link) const NOEXCEPT +inpoint CLASS::get_spender(const point_link& link) const NOEXCEPT { const auto tx = to_spending_tx(link); if (tx.is_terminal()) @@ -334,20 +353,14 @@ typename CLASS::point CLASS::get_spender(const point_link& link) const NOEXCEPT } TEMPLATE -typename CLASS::inputs_ptr CLASS::get_spenders( - const output_link& link, bool witness) const NOEXCEPT +inpoints CLASS::get_spenders(const point& point) const NOEXCEPT { - using namespace system; - const auto point_fks = to_spenders(link); - const auto inputs = to_shared(); - inputs->reserve(point_fks.size()); - - // TODO: eliminate shared memory pointer reallocation. - for (const auto& point_fk: point_fks) - if (!push_bool(*inputs, get_input(point_fk, witness))) - return {}; + inpoints ins{}; + for (const auto& link: to_spenders(point)) + ins.insert(get_spender(link)); - return inputs; + // std::set (lexically sorted/deduped). + return ins; } // Populate prevout objects. diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index a5a23b963..3be2d9df6 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -24,36 +24,11 @@ #include #include #include -#include -#include -#include +#include namespace libbitcoin { namespace database { -/// Database type aliases. -using height_link = table::height::link; -using header_link = table::header::link; -using output_link = table::output::link; -using input_link = table::input::link; -using outs_link = table::outs::link; -using ins_link = table::ins::link; -using point_link = table::point::link; -using tx_link = table::transaction::link; -using filter_link = table::filter_tx::link; -using strong_link = table::strong_tx::link; - -using header_links = std::vector; -using tx_links = std::vector; -using input_links = std::vector; -using output_links = std::vector; -using point_links = std::vector; -using two_counts = std::pair; -using point_key = table::point::key; - -struct header_state{ header_link link; code ec; }; -using header_states = std::vector; - // Writers (non-const) are only: push_, pop_, set_ and initialize. template class query @@ -66,7 +41,6 @@ class query using point = system::chain::point; using input = system::chain::input; using output = system::chain::output; - using outpoint = system::chain::outpoint; using header = system::chain::header; using script = system::chain::script; using witness = system::chain::witness; @@ -396,14 +370,17 @@ class query input::cptr get_input(const tx_link& link, uint32_t index, bool witness) const NOEXCEPT; - point get_spender(const point_link& link) const NOEXCEPT; - outpoint get_spent(const output_link& link) const NOEXCEPT; script::cptr get_output_script(const output_link& link) const NOEXCEPT; output::cptr get_output(const output_link& link) const NOEXCEPT; output::cptr get_output(const tx_link& link, uint32_t index) const NOEXCEPT; inputs_ptr get_spenders(const output_link& link, bool witness) const NOEXCEPT; + /// Inpoint and outpoint result sets. + outpoint get_spent(const output_link& link) const NOEXCEPT; + inpoint get_spender(const point_link& link) const NOEXCEPT; + inpoints get_spenders(const point& point) const NOEXCEPT; + /// False implies missing prevouts, node input.metadata is populated. bool populate_with_metadata(const input& input) const NOEXCEPT; bool populate_with_metadata(const block& block) const NOEXCEPT; diff --git a/include/bitcoin/database/types.hpp b/include/bitcoin/database/types.hpp new file mode 100644 index 000000000..b6141ebe3 --- /dev/null +++ b/include/bitcoin/database/types.hpp @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2011-2025 libbitcoin developers (see AUTHORS) + * + * This file is part of libbitcoin. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +#ifndef LIBBITCOIN_DATABASE_TYPES_HPP +#define LIBBITCOIN_DATABASE_TYPES_HPP + +#include +#include +#include +#include + +namespace libbitcoin { +namespace database { + +/// Database type aliases. +using height_link = table::height::link; +using header_link = table::header::link; +using output_link = table::output::link; +using input_link = table::input::link; +using outs_link = table::outs::link; +using ins_link = table::ins::link; +using point_link = table::point::link; +using tx_link = table::transaction::link; +using filter_link = table::filter_tx::link; +using strong_link = table::strong_tx::link; + +using header_links = std::vector; +using tx_links = std::vector; +using input_links = std::vector; +using output_links = std::vector; +using point_links = std::vector; +using two_counts = std::pair; +using point_key = table::point::key; + +struct header_state{ header_link link; code ec; }; +using header_states = std::vector; + +// TODO: define a system::chain::inpoint with added state. +using inpoint = system::chain::point; +using inpoints = std::set; +using outpoint = system::chain::outpoint; +using outpoints = std::set; + +} // namespace database +} // namespace libbitcoin + +#endif From 509b66bb6cd28fc7d2368316c7abb727570a4e4a Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sat, 6 Dec 2025 22:09:27 -0500 Subject: [PATCH 3/3] Style. --- include/bitcoin/database/impl/query/objects.ipp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/bitcoin/database/impl/query/objects.ipp b/include/bitcoin/database/impl/query/objects.ipp index 1ef3d4651..72b7e0ded 100644 --- a/include/bitcoin/database/impl/query/objects.ipp +++ b/include/bitcoin/database/impl/query/objects.ipp @@ -341,23 +341,23 @@ outpoint CLASS::get_spent(const output_link& link) const NOEXCEPT TEMPLATE inpoint CLASS::get_spender(const point_link& link) const NOEXCEPT { - const auto tx = to_spending_tx(link); - if (tx.is_terminal()) + const auto tx_fk = to_spending_tx(link); + if (tx_fk.is_terminal()) return {}; - const auto index = to_input_index(tx, link); + const auto index = to_input_index(tx_fk, link); if (index == point::null_index) return {}; - return { get_tx_key(tx), index }; + return { get_tx_key(tx_fk), index }; } TEMPLATE inpoints CLASS::get_spenders(const point& point) const NOEXCEPT { inpoints ins{}; - for (const auto& link: to_spenders(point)) - ins.insert(get_spender(link)); + for (const auto& point_fk: to_spenders(point)) + ins.insert(get_spender(point_fk)); // std::set (lexically sorted/deduped). return ins;