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/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/impl/query/objects.ipp b/include/bitcoin/database/impl/query/objects.ipp
index f15a1f138..72b7e0ded 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,34 +339,28 @@ 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())
+ 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
-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& point_fk: to_spenders(point))
+ ins.insert(get_spender(point_fk));
- 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 48b134365..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;
@@ -652,7 +629,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;
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