diff --git a/Makefile.am b/Makefile.am index 87c4a2935..2bd2516dd 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 73a8c2ebb..7ae2c9799 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 144d20903..8eed6eb7f 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 c42b1fc49..53f110246 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 1fcd181f2..2b3d00b02 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 8eb2eeef8..cfbdf8ea8 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 78% rename from include/bitcoin/database/impl/query/estimate.ipp rename to include/bitcoin/database/impl/query/fees.ipp index aabea730b..b6edb132b 100644 --- a/include/bitcoin/database/impl/query/estimate.ipp +++ b/include/bitcoin/database/impl/query/fees.ipp @@ -29,12 +29,35 @@ 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 (!tx) + return max_uint64; + + if (tx->is_coinbase()) + return zero; + + return 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 { 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(); @@ -68,17 +91,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/impl/query/validate.ipp b/include/bitcoin/database/impl/query/validate.ipp index dfa1be95d..65e26af68 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 865ffee4d..525a96bbc 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -398,17 +398,21 @@ 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; + size_t start, size_t count) const NOEXCEPT; + + /// Merkle. + /// ----------------------------------------------------------------------- /// Merkle computations over the index of confirmed headers. hash_digest get_merkle_root(size_t height) const NOEXCEPT; @@ -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/mocks/blocks.hpp b/test/mocks/blocks.hpp index 442276db1..96b881bb6 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/estimate.cpp b/test/query/estimate.cpp deleted file mode 100644 index 74e5365fa..000000000 --- a/test/query/estimate.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/** - * 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 . - */ -#include "../test.hpp" -#include "../mocks/blocks.hpp" -#include "../mocks/chunk_store.hpp" - -BOOST_FIXTURE_TEST_SUITE(query_estimate_tests, test::directory_setup_fixture) - -// nop event handler. -////const auto events_handler = [](auto, auto) {}; - -BOOST_AUTO_TEST_CASE(query_estimate_test) -{ - BOOST_REQUIRE(true); -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/query/fees.cpp b/test/query/fees.cpp new file mode 100644 index 000000000..bf8aae3de --- /dev/null +++ b/test/query/fees.cpp @@ -0,0 +1,400 @@ +/** + * 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 . + */ +#include "../test.hpp" +#include "../mocks/blocks.hpp" +#include "../mocks/chunk_store.hpp" + +BOOST_FIXTURE_TEST_SUITE(query_fees_tests, test::directory_setup_fixture) + +// nop event handler. +const auto events_handler = [](auto, auto) {}; + +// get_tx_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_fees__get_branch_fees__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{}; + 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()