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()