diff --git a/Makefile.am b/Makefile.am index d3b6f61ca..5ab26cb67 100644 --- a/Makefile.am +++ b/Makefile.am @@ -94,6 +94,7 @@ test_libbitcoin_database_test_SOURCES = \ test/query/extent.cpp \ test/query/height.cpp \ test/query/initialize.cpp \ + test/query/network.cpp \ test/query/objects.cpp \ test/query/optional.cpp \ test/query/translate.cpp \ @@ -181,6 +182,7 @@ include_bitcoin_database_impl_query_HEADERS = \ include/bitcoin/database/impl/query/extent.ipp \ include/bitcoin/database/impl/query/height.ipp \ include/bitcoin/database/impl/query/initialize.ipp \ + include/bitcoin/database/impl/query/network.ipp \ include/bitcoin/database/impl/query/objects.ipp \ include/bitcoin/database/impl/query/optional.ipp \ include/bitcoin/database/impl/query/query.ipp \ diff --git a/builds/cmake/CMakeLists.txt b/builds/cmake/CMakeLists.txt index a3728964d..0bbf66263 100644 --- a/builds/cmake/CMakeLists.txt +++ b/builds/cmake/CMakeLists.txt @@ -304,6 +304,7 @@ if (with-tests) "../../test/query/extent.cpp" "../../test/query/height.cpp" "../../test/query/initialize.cpp" + "../../test/query/network.cpp" "../../test/query/objects.cpp" "../../test/query/optional.cpp" "../../test/query/translate.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 f3f34351c..53a4d0f51 100644 --- a/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj +++ b/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj @@ -153,6 +153,7 @@ $(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 1fd2ef764..6c5cc7060 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 @@ -132,6 +132,9 @@ 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 0976a2c53..880400e50 100644 --- a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj +++ b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj @@ -219,6 +219,7 @@ + diff --git a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters index 6910cdbf7..7a2222c06 100644 --- a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters +++ b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters @@ -352,6 +352,9 @@ include\bitcoin\database\impl\query + + include\bitcoin\database\impl\query + include\bitcoin\database\impl\query diff --git a/include/bitcoin/database/impl/query/height.ipp b/include/bitcoin/database/impl/query/height.ipp index 966c9003c..bcc8169cb 100644 --- a/include/bitcoin/database/impl/query/height.ipp +++ b/include/bitcoin/database/impl/query/height.ipp @@ -60,98 +60,6 @@ size_t CLASS::get_confirmed_size(size_t top) const NOEXCEPT return wire; } -// locator readers -// ---------------------------------------------------------------------------- -// These do not require strict consistency. - -TEMPLATE -CLASS::headers CLASS::get_headers(const hashes& locator, - const hash_digest& stop, size_t limit) const NOEXCEPT -{ - headers out{}; - const auto span = get_locator_span(locator, stop, limit); - out.reserve(span.size()); - - for (auto height = span.begin; height < span.end; ++height) - { - // Terminal implies intervening reorganization. - const auto link = to_confirmed(height); - if (link.is_terminal()) - return {}; - - out.push_back(get_header(link)); - BC_ASSERT(!is_null(out.back())); - } - - return out; -} - -TEMPLATE -hashes CLASS::get_blocks(const hashes& locator, - const hash_digest& stop, size_t limit) const NOEXCEPT -{ - hashes out{}; - const auto span = get_locator_span(locator, stop, limit); - out.reserve(span.size()); - - for (auto height = span.begin; height < span.end; ++height) - { - // Terminal implies intervening reorganization. - const auto link = to_confirmed(height); - if (link.is_terminal()) - return {}; - - out.push_back(get_header_key(link)); - BC_ASSERT(out.back() != system::null_hash); - } - - return out; -} - -TEMPLATE -CLASS::span CLASS::get_locator_span(const hashes& locator, - const hash_digest& stop, size_t limit) const NOEXCEPT -{ - using namespace system; - span out{}; - - // Start at fork point, stop at given header (both excluded). - const auto start = add1(get_fork(locator)); - const auto last1 = (stop == null_hash) ? max_uint32 : - get_height(to_header(stop)).value; - - // Determine number of headers requested, limited by max allowed. - const auto request = floored_subtract(last1, start); - const auto allowed = std::min(request, limit); - - // Set end to (start + allowed), limited by (top + 1). - const auto top1 = ceilinged_add(get_top_confirmed(), one); - const auto end = std::min(ceilinged_add(start, allowed), top1); - - // Convert negative range to empty. - out.end = std::max(start, end); - return out; -} - -// protected -TEMPLATE -size_t CLASS::get_fork(const hashes& locator) const NOEXCEPT -{ - // Locator is presumed (by convention) to be in order by height. - for (const auto& hash: locator) - { - const auto link = to_header(hash); - const auto height = get_height(link); - - table::height::record confirmed{}; - if (store_.confirmed.get(height, confirmed) && - confirmed.header_fk == link) - return height; - } - - return zero; -} - // shared_lock readers // ---------------------------------------------------------------------------- // Protected against index pop (low contention) to ensure branch consistency. diff --git a/include/bitcoin/database/impl/query/network.ipp b/include/bitcoin/database/impl/query/network.ipp new file mode 100644 index 000000000..318648b6a --- /dev/null +++ b/include/bitcoin/database/impl/query/network.ipp @@ -0,0 +1,124 @@ +/** + * 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_QUERY_NETWORK_IPP +#define LIBBITCOIN_DATABASE_QUERY_NETWORK_IPP + +#include +#include +#include + +namespace libbitcoin { +namespace database { + +// locator readers +// ---------------------------------------------------------------------------- +// These do not require strict consistency. + +TEMPLATE +CLASS::headers CLASS::get_headers(const hashes& locator, + const hash_digest& stop, size_t limit) const NOEXCEPT +{ + headers out{}; + const auto span = get_locator_span(locator, stop, limit); + out.reserve(span.size()); + + for (auto height = span.begin; height < span.end; ++height) + { + // Terminal implies intervening reorganization. + const auto link = to_confirmed(height); + if (link.is_terminal()) + return {}; + + out.push_back(get_header(link)); + BC_ASSERT(!is_null(out.back())); + } + + return out; +} + +TEMPLATE +hashes CLASS::get_blocks(const hashes& locator, + const hash_digest& stop, size_t limit) const NOEXCEPT +{ + hashes out{}; + const auto span = get_locator_span(locator, stop, limit); + out.reserve(span.size()); + + for (auto height = span.begin; height < span.end; ++height) + { + // Terminal implies intervening reorganization. + const auto link = to_confirmed(height); + if (link.is_terminal()) + return {}; + + out.push_back(get_header_key(link)); + BC_ASSERT(out.back() != system::null_hash); + } + + return out; +} + +TEMPLATE +CLASS::span CLASS::get_locator_span(const hashes& locator, + const hash_digest& stop, size_t limit) const NOEXCEPT +{ + using namespace system; + span out{}; + + // Start at fork point, stop at given header (both excluded). + const auto start = add1(get_fork(locator)); + const auto last1 = (stop == null_hash) ? max_uint32 : + get_height(to_header(stop)).value; + + // Determine number of headers requested, limited by max allowed. + const auto request = floored_subtract(last1, start); + const auto allowed = std::min(request, limit); + + // Set end to (start + allowed), limited by (top + 1). + const auto top1 = ceilinged_add(get_top_confirmed(), one); + const auto end = std::min(ceilinged_add(start, allowed), top1); + + // Convert negative range to empty. + out.end = std::max(start, end); + return out; +} + +// protected +TEMPLATE +size_t CLASS::get_fork(const hashes& locator) const NOEXCEPT +{ + // Locator is presumed (by convention) to be in order by height. + for (const auto& hash: locator) + { + const auto link = to_header(hash); + const auto height = get_height(link); + + table::height::record confirmed{}; + if (store_.confirmed.get(height, confirmed) && + confirmed.header_fk == link) + return height; + } + + return zero; +} + +} // namespace database +} // namespace libbitcoin + +#endif diff --git a/include/bitcoin/database/query.hpp b/include/bitcoin/database/query.hpp index fb6cbfaac..ce52b593b 100644 --- a/include/bitcoin/database/query.hpp +++ b/include/bitcoin/database/query.hpp @@ -711,6 +711,7 @@ BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) #include #include #include +#include #include #include #include diff --git a/test/query/network.cpp b/test/query/network.cpp new file mode 100644 index 000000000..51d9012b4 --- /dev/null +++ b/test/query/network.cpp @@ -0,0 +1,51 @@ +/** + * 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" + +struct query_network_setup_fixture +{ + DELETE_COPY_MOVE(query_network_setup_fixture); + BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) + + query_network_setup_fixture() NOEXCEPT + { + BOOST_REQUIRE(test::clear(test::directory)); + } + + ~query_network_setup_fixture() NOEXCEPT + { + BOOST_REQUIRE(test::clear(test::directory)); + } + + BC_POP_WARNING() +}; + +BOOST_FIXTURE_TEST_SUITE(query_network_tests, query_network_setup_fixture) + +const auto events_handler = [](auto, auto) {}; + + +BOOST_AUTO_TEST_CASE(query_network_test) +{ + BOOST_REQUIRE(true); +} + +BOOST_AUTO_TEST_SUITE_END()