From aecdb9470d42db5d634a70b20a4305a50f422704 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Thu, 16 Apr 2026 18:13:12 -0400 Subject: [PATCH 1/2] Add get_spenders_history(chain::point) override. --- .../impl/query/address/address_history.ipp | 13 ++++++++++--- include/bitcoin/database/query.hpp | 1 + test/query/address/address_history.cpp | 15 +++++++++++---- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/include/bitcoin/database/impl/query/address/address_history.ipp b/include/bitcoin/database/impl/query/address/address_history.ipp index fc4af689..fa717bd9 100644 --- a/include/bitcoin/database/impl/query/address/address_history.ipp +++ b/include/bitcoin/database/impl/query/address/address_history.ipp @@ -198,10 +198,10 @@ history CLASS::get_tx_history(hash_digest&& key, } TEMPLATE -histories CLASS::get_spenders_history(const hash_digest& key, - uint32_t index) const NOEXCEPT +histories CLASS::get_spenders_history( + const system::chain::point& prevout) const NOEXCEPT { - const auto ins = to_spenders(key, index); + const auto ins = to_spenders(prevout); histories out(ins.size()); for (const auto& in: std::views::reverse(ins)) out.push_back(get_tx_history(to_input_tx(in))); @@ -210,6 +210,13 @@ histories CLASS::get_spenders_history(const hash_digest& key, return out; } +TEMPLATE +histories CLASS::get_spenders_history(const hash_digest& key, + uint32_t index) const NOEXCEPT +{ + return get_spenders_history({ key , index }); +} + // utilities // ---------------------------------------------------------------------------- // private/static diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index 2af953fa..09e95cbd 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -657,6 +657,7 @@ class query /// History queries. history get_tx_history(const tx_link& link) const NOEXCEPT; history get_tx_history(const hash_digest& key) const NOEXCEPT; + histories get_spenders_history(const point& prevout) const NOEXCEPT; histories get_spenders_history(const hash_digest& key, uint32_t index) const NOEXCEPT; diff --git a/test/query/address/address_history.cpp b/test/query/address/address_history.cpp index 3983cbef..89939f1b 100644 --- a/test/query/address/address_history.cpp +++ b/test/query/address/address_history.cpp @@ -347,7 +347,8 @@ BOOST_AUTO_TEST_CASE(query_address__get_tx_history__unrooted__expected) BOOST_REQUIRE_EQUAL(history.tx.hash(), hash); } -// get_spenders_history +// get_spenders_history1 +// get_spenders_history2 BOOST_AUTO_TEST_CASE(query_address__get_spenders_history__bogus__empty) { @@ -358,7 +359,10 @@ BOOST_AUTO_TEST_CASE(query_address__get_spenders_history__bogus__empty) BOOST_REQUIRE(!store.create(test::events_handler)); BOOST_REQUIRE(test::setup_three_block_confirmed_address_store(query)); - const auto histories = query.get_spenders_history({ 0x42 }, 0); + auto histories = query.get_spenders_history({ 0x42 }, 0); + BOOST_REQUIRE(histories.empty()); + + histories = query.get_spenders_history({ { 0x42 }, 0 }); BOOST_REQUIRE(histories.empty()); } @@ -372,8 +376,11 @@ BOOST_AUTO_TEST_CASE(query_address__get_spenders_history__genesis__expected) BOOST_REQUIRE(test::setup_three_block_confirmed_address_store(query)); const auto hash = test::genesis.transactions_ptr()->at(0)->hash(false); - const auto histories = query.get_spenders_history(hash, 0); - BOOST_REQUIRE_EQUAL(histories.size(), 0u); + auto histories = query.get_spenders_history(hash, 0); + BOOST_REQUIRE(histories.empty()); + + histories = query.get_spenders_history({ hash, 0 }); + BOOST_REQUIRE(histories.empty()); } BOOST_AUTO_TEST_CASE(query_address__get_spenders_history__confirmed__expected) From d8d73cf4a00c9673782961fb486ba9f4c6441617 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Thu, 16 Apr 2026 18:16:52 -0400 Subject: [PATCH 2/2] Rename get_[x]_outputs() to get_[x]_outpoints(). --- .../impl/query/address/address_balance.ipp | 3 +- .../impl/query/address/address_outpoints.ipp | 6 +-- include/bitcoin/database/query.hpp | 6 +-- test/query/address/address_outpoints.cpp | 44 +++++++++---------- 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/include/bitcoin/database/impl/query/address/address_balance.ipp b/include/bitcoin/database/impl/query/address/address_balance.ipp index 971ed18c..a328a99f 100644 --- a/include/bitcoin/database/impl/query/address/address_balance.ipp +++ b/include/bitcoin/database/impl/query/address/address_balance.ipp @@ -51,7 +51,8 @@ code CLASS::get_confirmed_balance(const stopper& cancel, uint64_t& out, const hash_digest& key, bool turbo) const NOEXCEPT { outpoints outs{}; - if (const auto ec = get_confirmed_unspent_outputs(cancel, outs, key, turbo)) + if (const auto ec = get_confirmed_unspent_outpoints(cancel, outs, key, + turbo)) { out = zero; return ec; diff --git a/include/bitcoin/database/impl/query/address/address_outpoints.ipp b/include/bitcoin/database/impl/query/address/address_outpoints.ipp index 5013582a..3bb26ee7 100644 --- a/include/bitcoin/database/impl/query/address/address_outpoints.ipp +++ b/include/bitcoin/database/impl/query/address/address_outpoints.ipp @@ -33,7 +33,7 @@ namespace database { // server/native TEMPLATE -code CLASS::get_confirmed_unspent_outputs(const stopper& cancel, +code CLASS::get_confirmed_unspent_outpoints(const stopper& cancel, outpoints& out, const hash_digest& key, bool turbo) const NOEXCEPT { out.clear(); @@ -58,7 +58,7 @@ code CLASS::get_confirmed_unspent_outputs(const stopper& cancel, // unused TEMPLATE -code CLASS::get_minimum_unspent_outputs(const stopper& cancel, +code CLASS::get_minimum_unspent_outpoints(const stopper& cancel, outpoints& out, const hash_digest& key, uint64_t minimum, bool turbo) const NOEXCEPT { @@ -95,7 +95,7 @@ code CLASS::get_minimum_unspent_outputs(const stopper& cancel, // server/native TEMPLATE -code CLASS::get_address_outputs(const stopper& cancel, outpoints& out, +code CLASS::get_address_outpoints(const stopper& cancel, outpoints& out, const hash_digest& key, bool turbo) const NOEXCEPT { out.clear(); diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index 09e95cbd..9c4117cc 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -622,11 +622,11 @@ class query /// Native queries (outpoints, deduped, arbitrary sort). ////code get_unconfirmed_unspent_outputs(const stopper& cancel, outpoints& out, //// const hash_digest& key, bool turbo=false) const NOEXCEPT; - code get_confirmed_unspent_outputs(const stopper& cancel, outpoints& out, + code get_confirmed_unspent_outpoints(const stopper& cancel, outpoints& out, const hash_digest& key, bool turbo=false) const NOEXCEPT; - code get_minimum_unspent_outputs(const stopper& cancel, outpoints& out, + code get_minimum_unspent_outpoints(const stopper& cancel, outpoints& out, const hash_digest& key, uint64_t value, bool turbo=false) const NOEXCEPT; - code get_address_outputs(const stopper& cancel, outpoints& out, + code get_address_outpoints(const stopper& cancel, outpoints& out, const hash_digest& key, bool turbo=false) const NOEXCEPT; /// Electrum queries (histories, deduped, electrum sort). diff --git a/test/query/address/address_outpoints.cpp b/test/query/address/address_outpoints.cpp index 18938b14..c39c2e6d 100644 --- a/test/query/address/address_outpoints.cpp +++ b/test/query/address/address_outpoints.cpp @@ -22,9 +22,9 @@ BOOST_FIXTURE_TEST_SUITE(query_address_tests, test::directory_setup_fixture) -// get_confirmed_unspent_outputs +// get_confirmed_unspent_outpoints -BOOST_AUTO_TEST_CASE(query_address__get_confirmed_unspent_outputs__turbo_genesis__expected) +BOOST_AUTO_TEST_CASE(query_address__get_confirmed_unspent_outpoints__turbo_genesis__expected) { settings settings{}; settings.path = TEST_DIRECTORY; @@ -35,12 +35,12 @@ BOOST_AUTO_TEST_CASE(query_address__get_confirmed_unspent_outputs__turbo_genesis outpoints out{}; const std::atomic_bool cancel{}; - BOOST_REQUIRE(!query.get_confirmed_unspent_outputs(cancel, out, test::genesis_address0, true)); + BOOST_REQUIRE(!query.get_confirmed_unspent_outpoints(cancel, out, test::genesis_address0, true)); BOOST_REQUIRE_EQUAL(out.size(), 1u); BOOST_REQUIRE(*out.begin() == query.get_outpoint(query.to_output(0, 0))); } -BOOST_AUTO_TEST_CASE(query_address__get_confirmed_unspent_outputs__genesis__expected) +BOOST_AUTO_TEST_CASE(query_address__get_confirmed_unspent_outpoints__genesis__expected) { settings settings{}; settings.path = TEST_DIRECTORY; @@ -51,14 +51,14 @@ BOOST_AUTO_TEST_CASE(query_address__get_confirmed_unspent_outputs__genesis__expe outpoints out{}; const std::atomic_bool cancel{}; - BOOST_REQUIRE(!query.get_confirmed_unspent_outputs(cancel, out, test::genesis_address0)); + BOOST_REQUIRE(!query.get_confirmed_unspent_outpoints(cancel, out, test::genesis_address0)); BOOST_REQUIRE_EQUAL(out.size(), 1u); BOOST_REQUIRE(*out.begin() == query.get_outpoint(query.to_output(0, 0))); } -// get_minimum_unspent_outputs +// get_minimum_unspent_outpoints -BOOST_AUTO_TEST_CASE(query_address__get_minimum_unspent_outputs__turbo_above__excluded) +BOOST_AUTO_TEST_CASE(query_address__get_minimum_unspent_outpoints__turbo_above__excluded) { settings settings{}; settings.path = TEST_DIRECTORY; @@ -69,11 +69,11 @@ BOOST_AUTO_TEST_CASE(query_address__get_minimum_unspent_outputs__turbo_above__ex outpoints out{}; const std::atomic_bool cancel{}; - BOOST_REQUIRE(!query.get_minimum_unspent_outputs(cancel, out, test::genesis_address0, 5000000001, true)); + BOOST_REQUIRE(!query.get_minimum_unspent_outpoints(cancel, out, test::genesis_address0, 5000000001, true)); BOOST_REQUIRE(out.empty()); } -BOOST_AUTO_TEST_CASE(query_address__get_minimum_unspent_outputs__above__excluded) +BOOST_AUTO_TEST_CASE(query_address__get_minimum_unspent_outpoints__above__excluded) { settings settings{}; settings.path = TEST_DIRECTORY; @@ -84,11 +84,11 @@ BOOST_AUTO_TEST_CASE(query_address__get_minimum_unspent_outputs__above__excluded outpoints out{}; const std::atomic_bool cancel{}; - BOOST_REQUIRE(!query.get_minimum_unspent_outputs(cancel, out, test::genesis_address0, 5000000001)); + BOOST_REQUIRE(!query.get_minimum_unspent_outpoints(cancel, out, test::genesis_address0, 5000000001)); BOOST_REQUIRE(out.empty()); } -BOOST_AUTO_TEST_CASE(query_address__get_minimum_unspent_outputs__at__included) +BOOST_AUTO_TEST_CASE(query_address__get_minimum_unspent_outpoints__at__included) { settings settings{}; settings.path = TEST_DIRECTORY; @@ -99,12 +99,12 @@ BOOST_AUTO_TEST_CASE(query_address__get_minimum_unspent_outputs__at__included) outpoints out{}; const std::atomic_bool cancel{}; - BOOST_REQUIRE(!query.get_minimum_unspent_outputs(cancel, out, test::genesis_address0, 5000000000)); + BOOST_REQUIRE(!query.get_minimum_unspent_outpoints(cancel, out, test::genesis_address0, 5000000000)); BOOST_REQUIRE_EQUAL(out.size(), 1u); BOOST_REQUIRE(*out.begin() == query.get_outpoint(query.to_output(0, 0))); } -BOOST_AUTO_TEST_CASE(query_address__get_minimum_unspent_outputs__below__included) +BOOST_AUTO_TEST_CASE(query_address__get_minimum_unspent_outpoints__below__included) { settings settings{}; settings.path = TEST_DIRECTORY; @@ -115,18 +115,18 @@ BOOST_AUTO_TEST_CASE(query_address__get_minimum_unspent_outputs__below__included outpoints out{}; const std::atomic_bool cancel{}; - BOOST_REQUIRE(!query.get_minimum_unspent_outputs(cancel, out, test::genesis_address0, 0)); + BOOST_REQUIRE(!query.get_minimum_unspent_outpoints(cancel, out, test::genesis_address0, 0)); BOOST_REQUIRE_EQUAL(out.size(), 1u); BOOST_REQUIRE(*out.begin() == query.get_outpoint(query.to_output(0, 0))); - BOOST_REQUIRE(!query.get_minimum_unspent_outputs(cancel, out, test::genesis_address0, 4999999999)); + BOOST_REQUIRE(!query.get_minimum_unspent_outpoints(cancel, out, test::genesis_address0, 4999999999)); BOOST_REQUIRE_EQUAL(out.size(), 1u); BOOST_REQUIRE(*out.begin() == query.get_outpoint(query.to_output(0, 0))); } -// get_address_outputs +// get_address_outpoints -BOOST_AUTO_TEST_CASE(query_address__get_address_outputs__turbo_genesis__expected) +BOOST_AUTO_TEST_CASE(query_address__get_address_outpoints__turbo_genesis__expected) { settings settings{}; settings.path = TEST_DIRECTORY; @@ -137,12 +137,12 @@ BOOST_AUTO_TEST_CASE(query_address__get_address_outputs__turbo_genesis__expected outpoints out{}; const std::atomic_bool cancel{}; - BOOST_REQUIRE(!query.get_address_outputs(cancel, out, test::genesis_address0, true)); + BOOST_REQUIRE(!query.get_address_outpoints(cancel, out, test::genesis_address0, true)); BOOST_REQUIRE_EQUAL(out.size(), 1u); BOOST_REQUIRE(*out.begin() == query.get_outpoint(query.to_output(0, 0))); } -BOOST_AUTO_TEST_CASE(query_address__get_address_outputs__genesis__expected) +BOOST_AUTO_TEST_CASE(query_address__get_address_outpoints__genesis__expected) { settings settings{}; settings.path = TEST_DIRECTORY; @@ -153,12 +153,12 @@ BOOST_AUTO_TEST_CASE(query_address__get_address_outputs__genesis__expected) outpoints out{}; const std::atomic_bool cancel{}; - BOOST_REQUIRE(!query.get_address_outputs(cancel, out, test::genesis_address0)); + BOOST_REQUIRE(!query.get_address_outpoints(cancel, out, test::genesis_address0)); BOOST_REQUIRE_EQUAL(out.size(), 1u); BOOST_REQUIRE(*out.begin() == query.get_outpoint(query.to_output(0, 0))); } -BOOST_AUTO_TEST_CASE(query_address__get_address_outputs__cancel__canceled_false) +BOOST_AUTO_TEST_CASE(query_address__get_address_outpoints__cancel__canceled_false) { settings settings{}; settings.path = TEST_DIRECTORY; @@ -169,7 +169,7 @@ BOOST_AUTO_TEST_CASE(query_address__get_address_outputs__cancel__canceled_false) outpoints out{}; std::atomic_bool cancel{ true }; - BOOST_REQUIRE_EQUAL(query.get_address_outputs(cancel, out, test::genesis_address0), error::canceled); + BOOST_REQUIRE_EQUAL(query.get_address_outpoints(cancel, out, test::genesis_address0), error::canceled); BOOST_REQUIRE(out.empty()); }