From 150b85c977690ae1af9e39878ef41ddfe08da097 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sat, 21 Feb 2026 09:24:20 -0500 Subject: [PATCH 1/4] Rename estimate.ipp to fees.ipp. --- Makefile.am | 4 ++-- builds/cmake/CMakeLists.txt | 2 +- .../libbitcoin-database-test.vcxproj | 2 +- .../libbitcoin-database-test.vcxproj.filters | 4 ++-- .../libbitcoin-database.vcxproj | 2 +- .../libbitcoin-database.vcxproj.filters | 4 ++-- .../impl/query/{estimate.ipp => fees.ipp} | 22 ++++++++++++++++++- .../bitcoin/database/impl/query/validate.ipp | 20 ----------------- include/bitcoin/database/query.hpp | 10 ++++++--- test/query/{estimate.cpp => fees.cpp} | 11 ++++++++-- 10 files changed, 46 insertions(+), 35 deletions(-) rename include/bitcoin/database/impl/query/{estimate.ipp => fees.ipp} (85%) rename test/query/{estimate.cpp => fees.cpp} (83%) diff --git a/Makefile.am b/Makefile.am index 87c4a293..2bd2516d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -91,8 +91,8 @@ test_libbitcoin_database_test_SOURCES = \ test/query/confirm.cpp \ test/query/consensus.cpp \ test/query/context.cpp \ - test/query/estimate.cpp \ test/query/extent.cpp \ + test/query/fees.cpp \ test/query/height.cpp \ test/query/initialize.cpp \ test/query/merkle.cpp \ @@ -182,8 +182,8 @@ include_bitcoin_database_impl_query_HEADERS = \ include/bitcoin/database/impl/query/confirm.ipp \ include/bitcoin/database/impl/query/consensus.ipp \ include/bitcoin/database/impl/query/context.ipp \ - include/bitcoin/database/impl/query/estimate.ipp \ include/bitcoin/database/impl/query/extent.ipp \ + include/bitcoin/database/impl/query/fees.ipp \ include/bitcoin/database/impl/query/height.ipp \ include/bitcoin/database/impl/query/initialize.ipp \ include/bitcoin/database/impl/query/merkle.ipp \ diff --git a/builds/cmake/CMakeLists.txt b/builds/cmake/CMakeLists.txt index 73a8c2eb..7ae2c979 100644 --- a/builds/cmake/CMakeLists.txt +++ b/builds/cmake/CMakeLists.txt @@ -301,8 +301,8 @@ if (with-tests) "../../test/query/confirm.cpp" "../../test/query/consensus.cpp" "../../test/query/context.cpp" - "../../test/query/estimate.cpp" "../../test/query/extent.cpp" + "../../test/query/fees.cpp" "../../test/query/height.cpp" "../../test/query/initialize.cpp" "../../test/query/merkle.cpp" diff --git a/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj b/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj index 144d2090..8eed6eb7 100644 --- a/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj +++ b/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj @@ -152,8 +152,8 @@ - + $(IntDir)test_query_height.obj diff --git a/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj.filters index c42b1fc4..53f11024 100644 --- a/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj.filters +++ b/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj.filters @@ -123,10 +123,10 @@ src\query - + src\query - + src\query diff --git a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj index 1fcd181f..2b3d00b0 100644 --- a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj +++ b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj @@ -219,8 +219,8 @@ - + diff --git a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters index 8eb2eeef..cfbdf8ea 100644 --- a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters +++ b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters @@ -346,10 +346,10 @@ include\bitcoin\database\impl\query - + include\bitcoin\database\impl\query - + include\bitcoin\database\impl\query diff --git a/include/bitcoin/database/impl/query/estimate.ipp b/include/bitcoin/database/impl/query/fees.ipp similarity index 85% rename from include/bitcoin/database/impl/query/estimate.ipp rename to include/bitcoin/database/impl/query/fees.ipp index aabea730..4346f90a 100644 --- a/include/bitcoin/database/impl/query/estimate.ipp +++ b/include/bitcoin/database/impl/query/fees.ipp @@ -29,7 +29,27 @@ namespace libbitcoin { namespace database { - + +// TODO: optimize. + +TEMPLATE +uint64_t CLASS::get_tx_fee(const tx_link& link) const NOEXCEPT +{ + const auto tx = get_transaction(link, false); + if (is_coinbase(link)) + return {}; + + return tx && populate_without_metadata(*tx) ? tx->fee() : max_uint64; +} + +TEMPLATE +uint64_t CLASS::get_block_fee(const header_link& link) const NOEXCEPT +{ + const auto block = get_block(link, false); + return block && populate_without_metadata(*block) ? block->fees() : + max_uint64; +} + TEMPLATE bool CLASS::get_tx_fees(fee_rate& out, const tx_link& link) const NOEXCEPT { diff --git a/include/bitcoin/database/impl/query/validate.ipp b/include/bitcoin/database/impl/query/validate.ipp index dfa1be95..65e26af6 100644 --- a/include/bitcoin/database/impl/query/validate.ipp +++ b/include/bitcoin/database/impl/query/validate.ipp @@ -140,26 +140,6 @@ code CLASS::get_block_state(const header_link& link) const NOEXCEPT return to_block_code(valid.code); } -TEMPLATE -uint64_t CLASS::get_block_fee(const header_link& link) const NOEXCEPT -{ - // TODO: optimize. - const auto block = get_block(link, false); - return block && populate_without_metadata(*block) ? block->fees() : - max_uint64; -} - -TEMPLATE -uint64_t CLASS::get_tx_fee(const tx_link& link) const NOEXCEPT -{ - // TODO: optimize. - const auto tx = get_transaction(link, false); - if (is_coinbase(link)) - return {}; - - return tx && populate_without_metadata(*tx) ? tx->fee() : max_uint64; -} - TEMPLATE inline bool CLASS::is_validated(const header_link& link) const NOEXCEPT { diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index 865ffee4..6d49d4e5 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -398,18 +398,22 @@ class query bool populate_without_metadata(const block& block) const NOEXCEPT; bool populate_without_metadata(const transaction& tx) const NOEXCEPT; - /// Services. + /// Fees. /// ----------------------------------------------------------------------- + /// Total fee value by tx or block. uint64_t get_tx_fee(const tx_link& link) const NOEXCEPT; uint64_t get_block_fee(const header_link& link) const NOEXCEPT; - /// Gether fee rate tuples by tx, block or branch. + /// Fee rate tuples by tx, block or branch. bool get_tx_fees(fee_rate& out, const tx_link& link) const NOEXCEPT; bool get_block_fees(fee_rates& out, const header_link& link) const NOEXCEPT; bool get_branch_fees(std::atomic_bool& cancel, fee_rate_sets& out, size_t top, size_t count) const NOEXCEPT; + /// Merkle. + /// ----------------------------------------------------------------------- + /// Merkle computations over the index of confirmed headers. hash_digest get_merkle_root(size_t height) const NOEXCEPT; code get_merkle_root_and_proof(hash_digest& root, hashes& proof, @@ -786,13 +790,13 @@ BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) #include #include #include +#include #include #include #include #include #include #include -#include #include #include diff --git a/test/query/estimate.cpp b/test/query/fees.cpp similarity index 83% rename from test/query/estimate.cpp rename to test/query/fees.cpp index 74e5365f..95829544 100644 --- a/test/query/estimate.cpp +++ b/test/query/fees.cpp @@ -20,12 +20,19 @@ #include "../mocks/blocks.hpp" #include "../mocks/chunk_store.hpp" -BOOST_FIXTURE_TEST_SUITE(query_estimate_tests, test::directory_setup_fixture) +BOOST_FIXTURE_TEST_SUITE(query_fees__tests, test::directory_setup_fixture) // nop event handler. ////const auto events_handler = [](auto, auto) {}; -BOOST_AUTO_TEST_CASE(query_estimate_test) +// get_tx_fee +// get_block_fee + +// get_tx_fees +// get_block_fees +// get_branch_fees + +BOOST_AUTO_TEST_CASE(query_fee) { BOOST_REQUIRE(true); } From a7344662d6f1a3ecf3e18a320063eedcbf355d2f Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sat, 21 Feb 2026 13:43:37 -0500 Subject: [PATCH 2/4] Change get_branch_fees param from top to start. --- include/bitcoin/database/impl/query/fees.ipp | 8 ++++---- include/bitcoin/database/query.hpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/bitcoin/database/impl/query/fees.ipp b/include/bitcoin/database/impl/query/fees.ipp index 4346f90a..d3550871 100644 --- a/include/bitcoin/database/impl/query/fees.ipp +++ b/include/bitcoin/database/impl/query/fees.ipp @@ -88,17 +88,17 @@ bool CLASS::get_block_fees(fee_rates& out, TEMPLATE bool CLASS::get_branch_fees(std::atomic_bool& cancel, fee_rate_sets& out, - size_t top, size_t count) const NOEXCEPT + size_t start, size_t count) const NOEXCEPT { out.clear(); if (is_zero(count)) return true; - if (top > get_top_confirmed()) + if (system::is_add_overflow(start, sub1(count))) return false; - const auto start = top - sub1(count); - if (system::is_subtract_overflow(top, sub1(count))) + const auto last = start + sub1(count); + if (last > get_top_confirmed()) return false; out.resize(count); diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index 6d49d4e5..525a96bb 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -409,7 +409,7 @@ class query bool get_tx_fees(fee_rate& out, const tx_link& link) const NOEXCEPT; bool get_block_fees(fee_rates& out, const header_link& link) const NOEXCEPT; bool get_branch_fees(std::atomic_bool& cancel, fee_rate_sets& out, - size_t top, size_t count) const NOEXCEPT; + size_t start, size_t count) const NOEXCEPT; /// Merkle. /// ----------------------------------------------------------------------- From 9122791ef5eb1faa6fe441ddb15b0d3056bc2e94 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sat, 21 Feb 2026 13:44:04 -0500 Subject: [PATCH 3/4] Handle coinbase in get_tx_fee/s. --- include/bitcoin/database/impl/query/fees.ipp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/bitcoin/database/impl/query/fees.ipp b/include/bitcoin/database/impl/query/fees.ipp index d3550871..b6edb132 100644 --- a/include/bitcoin/database/impl/query/fees.ipp +++ b/include/bitcoin/database/impl/query/fees.ipp @@ -36,10 +36,13 @@ TEMPLATE uint64_t CLASS::get_tx_fee(const tx_link& link) const NOEXCEPT { const auto tx = get_transaction(link, false); - if (is_coinbase(link)) - return {}; + if (!tx) + return max_uint64; - return tx && populate_without_metadata(*tx) ? tx->fee() : max_uint64; + if (tx->is_coinbase()) + return zero; + + return populate_without_metadata(*tx) ? tx->fee() : max_uint64; } TEMPLATE @@ -54,7 +57,7 @@ TEMPLATE bool CLASS::get_tx_fees(fee_rate& out, const tx_link& link) const NOEXCEPT { const auto tx = get_transaction(link, false); - if (!tx || !populate_without_metadata(*tx)) + if (!tx || tx->is_coinbase() || !populate_without_metadata(*tx)) return false; out.bytes = tx->virtual_size(); From 56be34f3f8febc88629d9e35165da6c515085d59 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Sat, 21 Feb 2026 13:44:37 -0500 Subject: [PATCH 4/4] Add comprehensive fee methods tests. --- test/mocks/blocks.hpp | 109 +++++++++++++ test/query/fees.cpp | 372 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 475 insertions(+), 6 deletions(-) diff --git a/test/mocks/blocks.hpp b/test/mocks/blocks.hpp index 442276db..96b881bb 100644 --- a/test/mocks/blocks.hpp +++ b/test/mocks/blocks.hpp @@ -522,6 +522,115 @@ const block block_spend_internal_2b } } }; +const block block_missing_prevout_2b +{ + header + { + 0x31323334, // version + block1b.hash(), // previous_block_hash + system::one_hash, // merkle_root + 0x41424344, // timestamp + 0x51525354, // bits + 0x61626364 // nonce + }, + transactions + { + tx2b, + transaction + { + 0xb2, + inputs + { + input + { + // missing prevout index. + point{ tx2b.hash(false), 0x01 }, + script{ { { opcode::checkmultisig }, { opcode::size } } }, + witness{}, + 0xb2 + } + }, + outputs + { + output + { + 0xb0, // fee will be 0x01 + script{ { { opcode::pick } } } + } + }, + 0xb2 + } + } +}; +const block block_valid_spend_internal_2b +{ + header + { + 0x31323334, // version + block1b.hash(), // previous_block_hash + system::one_hash, // merkle_root + 0x41424344, // timestamp + 0x51525354, // bits + 0x61626364 // nonce + }, + transactions + { + tx2b, + transaction + { + 0xb2, + inputs + { + input + { + point{ tx2b.hash(false), 0x00 }, + script{ { { opcode::checkmultisig }, { opcode::size } } }, + witness{}, + 0xb2 + } + }, + outputs + { + output + { + 0xb0, // fee will be 0x01 + script{ { { opcode::pick } } } + } + }, + 0xb2 + }, + transaction + { + 0xb2, + inputs + { + input + { + point{ block1b.transactions_ptr()->front()->hash(false), 0x00 }, + script{ { { opcode::checkmultisig }, { opcode::size } } }, + witness{}, + 0xb2 + }, + input + { + point{ block1b.transactions_ptr()->front()->hash(false), 0x01 }, + script{ { { opcode::checkmultisig } } }, + witness{}, + 0xb2 + } + }, + outputs + { + output + { + 0xb2, // fee will be 0xb1 + 0xb1 - 0xb2 = 0xb0 + script{ { { opcode::pick }, { opcode::roll }, { opcode::pick } } } + } + }, + 0xb2 + } + } +}; } // namespace test diff --git a/test/query/fees.cpp b/test/query/fees.cpp index 95829544..bf8aae3d 100644 --- a/test/query/fees.cpp +++ b/test/query/fees.cpp @@ -20,21 +20,381 @@ #include "../mocks/blocks.hpp" #include "../mocks/chunk_store.hpp" -BOOST_FIXTURE_TEST_SUITE(query_fees__tests, test::directory_setup_fixture) +BOOST_FIXTURE_TEST_SUITE(query_fees_tests, test::directory_setup_fixture) // nop event handler. -////const auto events_handler = [](auto, auto) {}; +const auto events_handler = [](auto, auto) {}; // get_tx_fee -// get_block_fee - // get_tx_fees + +BOOST_AUTO_TEST_CASE(query_fees__get_tx_fee__invalid__max_uint64) +{ + settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_CHECK(!store.create(events_handler)); + BOOST_CHECK(query.initialize(test::genesis)); + BOOST_CHECK_EQUAL(query.get_tx_fee(42), max_uint64); + + fee_rate rate{}; + BOOST_CHECK(!query.get_tx_fees(rate, 42)); +} + +BOOST_AUTO_TEST_CASE(query_fees__get_tx_fee__missing_prevouts__max_uint64) +{ + settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_CHECK(!store.create(events_handler)); + BOOST_CHECK(query.initialize(test::genesis)); + BOOST_CHECK_EQUAL(query.get_tx_fee(0), 0u); + BOOST_CHECK(query.set(test::block1a, test::context, false, false)); + BOOST_CHECK(query.set(test::block2a, test::context, false, false)); + BOOST_CHECK_EQUAL(query.get_tx_fee(3), max_uint64); + + fee_rate rate{}; + BOOST_CHECK(!query.get_tx_fees(rate, 3)); +} + +BOOST_AUTO_TEST_CASE(query_fees__get_tx_fee__genesis__zero) +{ + settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_CHECK(!store.create(events_handler)); + BOOST_CHECK(query.initialize(test::genesis)); + BOOST_CHECK_EQUAL(query.get_tx_fee(0), 0u); + + fee_rate rate{}; + BOOST_CHECK(!query.get_tx_fees(rate, 0u)); +} + +BOOST_AUTO_TEST_CASE(query_fees__get_tx_fee__valid_non_coinbase__expected) +{ + settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_CHECK(!store.create(events_handler)); + BOOST_CHECK(query.initialize(test::genesis)); + BOOST_CHECK(query.set(test::block1b, test::context, false, false)); + BOOST_CHECK(query.set(test::tx2b)); + BOOST_CHECK_EQUAL(query.get_tx_fee(2), 0u); + + fee_rate rate{}; + BOOST_CHECK(query.get_tx_fees(rate, 2)); + BOOST_CHECK_EQUAL(rate.bytes, test::tx2b.virtual_size()); + BOOST_CHECK_EQUAL(rate.fee, test::tx2b.fee()); +} + +// get_block_fee // get_block_fees + +BOOST_AUTO_TEST_CASE(query_fees__get_block_fee__invalid__max_uint64) +{ + settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_CHECK(!store.create(events_handler)); + BOOST_CHECK(query.initialize(test::genesis)); + BOOST_CHECK_EQUAL(query.get_block_fee(24), max_uint64); + + fee_rates rates{}; + BOOST_CHECK(!query.get_block_fees(rates, 24)); +} + +BOOST_AUTO_TEST_CASE(query_fees__get_block_fee__block_missing_prevout__max_uint64) +{ + settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_CHECK(!store.create(events_handler)); + BOOST_CHECK(query.initialize(test::genesis)); + BOOST_CHECK(query.set(test::block1b, test::context, false, false)); + BOOST_CHECK(query.set(test::block_missing_prevout_2b, test::context, false, false)); + BOOST_CHECK_EQUAL(query.get_block_fee(2), max_uint64); + + fee_rates rates{}; + BOOST_CHECK(!query.get_block_fees(rates, 2)); +} + +BOOST_AUTO_TEST_CASE(query_fees__get_block_fee__coinbases__zero) +{ + settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_CHECK(!store.create(events_handler)); + BOOST_CHECK(query.initialize(test::genesis)); + BOOST_CHECK(query.set(test::block1, test::context, false, false)); + BOOST_CHECK(query.set(test::block2, test::context, false, false)); + BOOST_CHECK_EQUAL(query.get_block_fee(2), zero); + + fee_rates rates{}; + BOOST_CHECK(query.get_block_fees(rates, 2)); + BOOST_CHECK(rates.empty()); +} + +BOOST_AUTO_TEST_CASE(query_fees__get_block_fee__valid__expected) +{ + settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_CHECK(!store.create(events_handler)); + BOOST_CHECK(query.initialize(test::genesis)); + BOOST_CHECK(query.set(test::block1b, test::context, false, false)); + BOOST_CHECK(query.set(test::block_valid_spend_internal_2b, test::context, false, false)); + BOOST_CHECK_EQUAL(query.get_block_fee(2), 0xb1u); + + // 3 txs - 1 coinbase = 2 rates. + fee_rates rates{}; + BOOST_CHECK(query.get_block_fees(rates, 2)); + BOOST_CHECK_EQUAL(rates.size(), 2u); + BOOST_CHECK_EQUAL(rates.at(0).bytes, 63u); + BOOST_CHECK_EQUAL(rates.at(0).fee, 0x01u); + BOOST_CHECK_EQUAL(rates.at(1).bytes, 107u); + BOOST_CHECK_EQUAL(rates.at(1).fee, 0xb0u); +} + +BOOST_AUTO_TEST_CASE(query_fees__get_block_fee__genesis__zero) +{ + settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_CHECK(!store.create(events_handler)); + BOOST_CHECK(query.initialize(test::genesis)); + BOOST_CHECK_EQUAL(query.get_block_fee(0), 0u); + + fee_rates rates{}; + BOOST_CHECK(query.get_block_fees(rates, 0)); + BOOST_CHECK(rates.empty()); +} + // get_branch_fees -BOOST_AUTO_TEST_CASE(query_fee) +BOOST_AUTO_TEST_CASE(query_fees__get_branch_fees__zero__true_empty) { - BOOST_REQUIRE(true); + settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_CHECK(!store.create(events_handler)); + BOOST_CHECK(query.initialize(test::genesis)); + + std::atomic_bool cancel{}; + fee_rate_sets rates_sets{}; + BOOST_CHECK(query.get_branch_fees(cancel, rates_sets, 0, 0)); + BOOST_CHECK(rates_sets.empty()); +} + +BOOST_AUTO_TEST_CASE(query_fees__get_branch_fees__genesis__true_one_empty) +{ + settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_CHECK(!store.create(events_handler)); + BOOST_CHECK(query.initialize(test::genesis)); + + std::atomic_bool cancel{}; + fee_rate_sets rates_sets{}; + BOOST_CHECK(query.get_branch_fees(cancel, rates_sets, 0, 1)); + BOOST_CHECK_EQUAL(rates_sets.size(), 1u); + BOOST_CHECK(rates_sets.front().empty()); +} + +BOOST_AUTO_TEST_CASE(query_fees__get_branch_fees__unconfirmed_blocks__false) +{ + settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_CHECK(!store.create(events_handler)); + BOOST_CHECK(query.initialize(test::genesis)); + BOOST_CHECK(query.set(test::block1, test::context, false, false)); + BOOST_CHECK(query.set(test::block2, test::context, false, false)); + + std::atomic_bool cancel{}; + fee_rate_sets rates_sets{}; + BOOST_CHECK(!query.get_branch_fees(cancel, rates_sets, 0, 3)); +} + +BOOST_AUTO_TEST_CASE(query_fees__get_branch_fees__confirmed_overflow__false) +{ + settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_CHECK(!store.create(events_handler)); + BOOST_CHECK(query.initialize(test::genesis)); + BOOST_CHECK(query.set(test::block1, test::context, false, false)); + BOOST_CHECK(query.set(test::block2, test::context, false, false)); + BOOST_CHECK(query.push_confirmed(1, true)); + BOOST_CHECK(query.push_confirmed(2, true)); + + std::atomic_bool cancel{}; + fee_rate_sets rates_sets{}; + BOOST_CHECK(!query.get_branch_fees(cancel, rates_sets, 0, 4)); + BOOST_CHECK(!query.get_branch_fees(cancel, rates_sets, 1, 3)); + BOOST_CHECK(!query.get_branch_fees(cancel, rates_sets, 2, 2)); + BOOST_CHECK(!query.get_branch_fees(cancel, rates_sets, 3, 1)); +} + +BOOST_AUTO_TEST_CASE(query_fees__get_branch_fees__zero_over_top__true) +{ + settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_CHECK(!store.create(events_handler)); + BOOST_CHECK(query.initialize(test::genesis)); + + // A start of 1 is over the chain top, but requested count is zero (ok). + std::atomic_bool cancel{}; + fee_rate_sets rates_sets{}; + BOOST_CHECK(query.get_branch_fees(cancel, rates_sets, 1, 0)); +} + +BOOST_AUTO_TEST_CASE(query_fees__get_branch_fees__confirmed_empty_blocks__all_empty) +{ + settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_CHECK(!store.create(events_handler)); + BOOST_CHECK(query.initialize(test::genesis)); + BOOST_CHECK(query.set(test::block1, test::context, false, false)); + BOOST_CHECK(query.set(test::block2, test::context, false, false)); + BOOST_CHECK(query.push_confirmed(1, true)); + BOOST_CHECK(query.push_confirmed(2, true)); + + std::atomic_bool cancel{}; + fee_rate_sets rates_sets{}; + BOOST_CHECK(query.get_branch_fees(cancel, rates_sets, 0, 3)); + BOOST_CHECK_EQUAL(rates_sets.size(), 3u); + BOOST_CHECK(rates_sets.at(0).empty()); + BOOST_CHECK(rates_sets.at(1).empty()); + BOOST_CHECK(rates_sets.at(2).empty()); + + rates_sets.clear(); + BOOST_CHECK(query.get_branch_fees(cancel, rates_sets, 1, 2)); + BOOST_CHECK_EQUAL(rates_sets.size(), 2u); + BOOST_CHECK(rates_sets.at(0).empty()); + BOOST_CHECK(rates_sets.at(1).empty()); + + rates_sets.clear(); + BOOST_CHECK(query.get_branch_fees(cancel, rates_sets, 2, 1)); + BOOST_CHECK_EQUAL(rates_sets.size(), 1u); + BOOST_CHECK(rates_sets.at(0).empty()); + + rates_sets.clear(); + BOOST_CHECK(query.get_branch_fees(cancel, rates_sets, 3, 0)); + BOOST_CHECK(rates_sets.empty()); +} + +BOOST_AUTO_TEST_CASE(query_fees__get_branch_fees__confirmed_non_empty_blocks__all_expected) +{ + settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_CHECK(!store.create(events_handler)); + BOOST_CHECK(query.initialize(test::genesis)); + BOOST_CHECK(query.set(test::block1b, test::context, false, false)); + BOOST_CHECK(query.set(test::block_valid_spend_internal_2b, test::context, false, false)); + BOOST_CHECK(query.push_confirmed(1, true)); + BOOST_CHECK(query.push_confirmed(2, true)); + + std::atomic_bool cancel{}; + fee_rate_sets rates_sets{}; + BOOST_CHECK(query.get_branch_fees(cancel, rates_sets, 0, 3)); + BOOST_CHECK_EQUAL(rates_sets.size(), 3u); + BOOST_CHECK(rates_sets.at(0).empty()); + BOOST_CHECK(rates_sets.at(1).empty()); + BOOST_CHECK_EQUAL(rates_sets.at(2).size(), 2u); + BOOST_CHECK_EQUAL(rates_sets.at(2).at(0).bytes, 63u); + BOOST_CHECK_EQUAL(rates_sets.at(2).at(0).fee, 0x01u); + BOOST_CHECK_EQUAL(rates_sets.at(2).at(1).bytes, 107u); + BOOST_CHECK_EQUAL(rates_sets.at(2).at(1).fee, 0xb0u); + + rates_sets.clear(); + BOOST_CHECK(query.get_branch_fees(cancel, rates_sets, 1, 2)); + BOOST_CHECK_EQUAL(rates_sets.size(), 2u); + BOOST_CHECK(rates_sets.at(0).empty()); + BOOST_CHECK_EQUAL(rates_sets.at(1).size(), 2u); + BOOST_CHECK_EQUAL(rates_sets.at(1).at(0).bytes, 63u); + BOOST_CHECK_EQUAL(rates_sets.at(1).at(0).fee, 0x01u); + BOOST_CHECK_EQUAL(rates_sets.at(1).at(1).bytes, 107u); + BOOST_CHECK_EQUAL(rates_sets.at(1).at(1).fee, 0xb0u); + + rates_sets.clear(); + BOOST_CHECK(query.get_branch_fees(cancel, rates_sets, 2, 1)); + BOOST_CHECK_EQUAL(rates_sets.size(), 1u); + BOOST_CHECK_EQUAL(rates_sets.at(0).size(), 2u); + BOOST_CHECK_EQUAL(rates_sets.at(0).at(0).bytes, 63u); + BOOST_CHECK_EQUAL(rates_sets.at(0).at(0).fee, 0x01u); + BOOST_CHECK_EQUAL(rates_sets.at(0).at(1).bytes, 107u); + BOOST_CHECK_EQUAL(rates_sets.at(0).at(1).fee, 0xb0u); + + rates_sets.clear(); + BOOST_CHECK(query.get_branch_fees(cancel, rates_sets, 3, 0)); + BOOST_CHECK(rates_sets.empty()); +} + + +BOOST_AUTO_TEST_CASE(query_fees__get_branch_fees__cancel_zero__true_empty) +{ + settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_CHECK(!store.create(events_handler)); + BOOST_CHECK(query.initialize(test::genesis)); + + std::atomic_bool cancel{ true }; + fee_rate_sets rates_sets{}; + BOOST_CHECK(query.get_branch_fees(cancel, rates_sets, 0, 0)); + BOOST_CHECK(rates_sets.empty()); +} + +BOOST_AUTO_TEST_CASE(query_fees__get_branch_fees__cancel_genesis__false_empty) +{ + settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_CHECK(!store.create(events_handler)); + BOOST_CHECK(query.initialize(test::genesis)); + + std::atomic_bool cancel{ true }; + fee_rate_sets rates_sets{}; + BOOST_CHECK(!query.get_branch_fees(cancel, rates_sets, 0, 1)); + BOOST_CHECK(rates_sets.empty()); +} + +BOOST_AUTO_TEST_CASE(query_fees__get_branch_fees__cancel_three_blocks__false_empty) +{ + settings settings{}; + settings.path = TEST_DIRECTORY; + test::chunk_store store{ settings }; + test::query_accessor query{ store }; + BOOST_CHECK(!store.create(events_handler)); + BOOST_CHECK(query.initialize(test::genesis)); + BOOST_CHECK(query.set(test::block1, test::context, false, false)); + BOOST_CHECK(query.set(test::block2, test::context, false, false)); + + std::atomic_bool cancel{ true }; + fee_rate_sets rates_sets{}; + BOOST_CHECK(!query.get_branch_fees(cancel, rates_sets, 0, 3)); + BOOST_CHECK(rates_sets.empty()); } BOOST_AUTO_TEST_SUITE_END()