diff --git a/include/bitcoin/database/impl/query/optional.ipp b/include/bitcoin/database/impl/query/optional.ipp index 44e12cf9..30eeea9d 100644 --- a/include/bitcoin/database/impl/query/optional.ipp +++ b/include/bitcoin/database/impl/query/optional.ipp @@ -36,7 +36,7 @@ namespace database { // Pushing into vectors is more efficient than precomputation of size. TEMPLATE -code CLASS::to_address_outputs(const std::atomic_bool& cancel, +code CLASS::get_address_outputs(const std::atomic_bool& cancel, outpoints& out, const hash_digest& key) const NOEXCEPT { out.clear(); @@ -56,7 +56,7 @@ code CLASS::to_address_outputs(const std::atomic_bool& cancel, } TEMPLATE -code CLASS::to_confirmed_unspent_outputs(const std::atomic_bool& cancel, +code CLASS::get_confirmed_unspent_outputs(const std::atomic_bool& cancel, outpoints& out, const hash_digest& key) const NOEXCEPT { out.clear(); @@ -77,7 +77,7 @@ code CLASS::to_confirmed_unspent_outputs(const std::atomic_bool& cancel, } TEMPLATE -code CLASS::to_minimum_unspent_outputs(const std::atomic_bool& cancel, +code CLASS::get_minimum_unspent_outputs(const std::atomic_bool& cancel, outpoints& out, const hash_digest& key, uint64_t minimum) const NOEXCEPT { out.clear(); @@ -106,27 +106,21 @@ code CLASS::to_minimum_unspent_outputs(const std::atomic_bool& cancel, TEMPLATE code CLASS::get_confirmed_balance(const std::atomic_bool& cancel, - uint64_t& out, const hash_digest& key) const NOEXCEPT + uint64_t& balance, const hash_digest& key) const NOEXCEPT { - out = zero; - for (auto it = store_.address.it(key); it; ++it) + outpoints outs{}; + if (code ec = get_confirmed_unspent_outputs(cancel, outs, key)) { - if (cancel) - return error::canceled; - - table::address::record address{}; - if (!store_.address.get(it, address)) - return error::integrity; + balance = zero; + return ec; + } - if (is_confirmed_unspent(address.output_fk)) + // Use of to_confirmed_unspent_outputs() provides necessary deduplication. + balance = std::accumulate(outs.begin(), outs.end(), zero, + [](size_t total, const outpoint& out) NOEXCEPT { - uint64_t value{}; - if (!get_value(value, address.output_fk)) - return error::integrity; - - out = system::ceilinged_add(value, out); - } - } + return system::ceilinged_add(total, out.value()); + }); return error::success; } diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index 6eec21c4..5e2c1fb5 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -549,14 +549,14 @@ class query /// Optional Tables. /// ----------------------------------------------------------------------- - code to_address_outputs(const std::atomic_bool& cancel, + code get_address_outputs(const std::atomic_bool& cancel, outpoints& out, const hash_digest& key) const NOEXCEPT; - code to_confirmed_unspent_outputs(const std::atomic_bool& cancel, + code get_confirmed_unspent_outputs(const std::atomic_bool& cancel, outpoints& out, const hash_digest& key) const NOEXCEPT; - code to_minimum_unspent_outputs(const std::atomic_bool& cancel, + code get_minimum_unspent_outputs(const std::atomic_bool& cancel, outpoints& out, const hash_digest& key, uint64_t value) const NOEXCEPT; code get_confirmed_balance(const std::atomic_bool& cancel, - uint64_t& out, const hash_digest& key) const NOEXCEPT; + uint64_t& balance, const hash_digest& key) const NOEXCEPT; bool is_filtered_body(const header_link& link) const NOEXCEPT; bool get_filter_body(filter& out, const header_link& link) const NOEXCEPT; diff --git a/test/query/optional.cpp b/test/query/optional.cpp index 052f82ec..b4d1b92e 100644 --- a/test/query/optional.cpp +++ b/test/query/optional.cpp @@ -27,7 +27,7 @@ const auto events_handler = [](auto, auto) {}; const auto genesis_address = test::genesis.transactions_ptr()->front()->outputs_ptr()->front()->script().hash(); -BOOST_AUTO_TEST_CASE(query_optional__to_address_outputs__genesis__expected) +BOOST_AUTO_TEST_CASE(query_optional__get_address_outputs__genesis__expected) { settings settings{}; settings.path = TEST_DIRECTORY; @@ -38,12 +38,12 @@ BOOST_AUTO_TEST_CASE(query_optional__to_address_outputs__genesis__expected) outpoints out{}; const std::atomic_bool cancel{}; - BOOST_REQUIRE(!query.to_address_outputs(cancel, out, genesis_address)); + BOOST_REQUIRE(!query.get_address_outputs(cancel, out, genesis_address)); BOOST_REQUIRE_EQUAL(out.size(), 1u); ////BOOST_REQUIRE_EQUAL(out.front(), query.to_output(0, 0)); } -BOOST_AUTO_TEST_CASE(query_optional__to_address_outputs__cancel__canceled_false) +BOOST_AUTO_TEST_CASE(query_optional__get_address_outputs__cancel__canceled_false) { settings settings{}; settings.path = TEST_DIRECTORY; @@ -54,11 +54,11 @@ BOOST_AUTO_TEST_CASE(query_optional__to_address_outputs__cancel__canceled_false) outpoints out{}; const std::atomic_bool cancel{ true }; - BOOST_REQUIRE_EQUAL(query.to_address_outputs(cancel, out, genesis_address), error::canceled); + BOOST_REQUIRE_EQUAL(query.get_address_outputs(cancel, out, genesis_address), error::canceled); BOOST_REQUIRE(out.empty()); } -BOOST_AUTO_TEST_CASE(query_optional__to_confirmed_unspent_outputs__genesis__expected) +BOOST_AUTO_TEST_CASE(query_optional__get_confirmed_unspent_outputs__genesis__expected) { settings settings{}; settings.path = TEST_DIRECTORY; @@ -69,12 +69,12 @@ BOOST_AUTO_TEST_CASE(query_optional__to_confirmed_unspent_outputs__genesis__expe outpoints out{}; const std::atomic_bool cancel{}; - BOOST_REQUIRE(!query.to_confirmed_unspent_outputs(cancel, out, genesis_address)); + BOOST_REQUIRE(!query.get_confirmed_unspent_outputs(cancel, out, genesis_address)); BOOST_REQUIRE_EQUAL(out.size(), 1u); ////BOOST_REQUIRE_EQUAL(out.front(), 0); } -BOOST_AUTO_TEST_CASE(query_optional__to_minimum_unspent_outputs__above__excluded) +BOOST_AUTO_TEST_CASE(query_optional__get_minimum_unspent_outputs__above__excluded) { settings settings{}; settings.path = TEST_DIRECTORY; @@ -85,11 +85,11 @@ BOOST_AUTO_TEST_CASE(query_optional__to_minimum_unspent_outputs__above__excluded outpoints out{}; const std::atomic_bool cancel{}; - BOOST_REQUIRE(!query.to_minimum_unspent_outputs(cancel, out, genesis_address, 5000000001)); + BOOST_REQUIRE(!query.get_minimum_unspent_outputs(cancel, out, genesis_address, 5000000001)); BOOST_REQUIRE(out.empty()); } -BOOST_AUTO_TEST_CASE(query_optional__to_minimum_unspent_outputs__at__included) +BOOST_AUTO_TEST_CASE(query_optional__get_minimum_unspent_outputs__at__included) { settings settings{}; settings.path = TEST_DIRECTORY; @@ -100,12 +100,12 @@ BOOST_AUTO_TEST_CASE(query_optional__to_minimum_unspent_outputs__at__included) outpoints out{}; const std::atomic_bool cancel{}; - BOOST_REQUIRE(!query.to_minimum_unspent_outputs(cancel, out, genesis_address, 5000000000)); + BOOST_REQUIRE(!query.get_minimum_unspent_outputs(cancel, out, genesis_address, 5000000000)); BOOST_REQUIRE_EQUAL(out.size(), 1u); ////BOOST_REQUIRE_EQUAL(out.front(), 0); } -BOOST_AUTO_TEST_CASE(query_optional__to_minimum_unspent_outputs__below__included) +BOOST_AUTO_TEST_CASE(query_optional__get_minimum_unspent_outputs__below__included) { settings settings{}; settings.path = TEST_DIRECTORY; @@ -116,10 +116,10 @@ BOOST_AUTO_TEST_CASE(query_optional__to_minimum_unspent_outputs__below__included outpoints out{}; const std::atomic_bool cancel{}; - BOOST_REQUIRE(!query.to_minimum_unspent_outputs(cancel, out, genesis_address, 0)); + BOOST_REQUIRE(!query.get_minimum_unspent_outputs(cancel, out, genesis_address, 0)); BOOST_REQUIRE_EQUAL(out.size(), 1u); ////BOOST_REQUIRE_EQUAL(out.front(), 0); - BOOST_REQUIRE(!query.to_minimum_unspent_outputs(cancel, out, genesis_address, 4999999999)); + BOOST_REQUIRE(!query.get_minimum_unspent_outputs(cancel, out, genesis_address, 4999999999)); BOOST_REQUIRE_EQUAL(out.size(), 1u); ////BOOST_REQUIRE_EQUAL(out.front(), 0); }