diff --git a/builds/gnu/Makefile.am b/builds/gnu/Makefile.am
index da9fe3c7..8daa8051 100644
--- a/builds/gnu/Makefile.am
+++ b/builds/gnu/Makefile.am
@@ -73,8 +73,6 @@ src_libbitcoin_node_la_SOURCES = \
${srcdir}/../../src/chasers/chaser_validate_batch.cpp \
${srcdir}/../../src/chasers/chaser_validate_capture.cpp \
${srcdir}/../../src/chasers/chaser_validate_parallel.cpp \
- ${srcdir}/../../src/messages/block.cpp \
- ${srcdir}/../../src/messages/transaction.cpp \
${srcdir}/../../src/protocols/protocol.cpp \
${srcdir}/../../src/protocols/protocol_block_in_106.cpp \
${srcdir}/../../src/protocols/protocol_block_in_31800.cpp \
@@ -156,14 +154,6 @@ include_bitcoin_node_impl_sessionsdir = \
include_bitcoin_node_impl_sessions_HEADERS = \
${srcdir}/../../include/bitcoin/node/impl/sessions/session_peer.ipp
-include_bitcoin_node_messagesdir = \
- ${includedir}/bitcoin/node/messages
-
-include_bitcoin_node_messages_HEADERS = \
- ${srcdir}/../../include/bitcoin/node/messages/block.hpp \
- ${srcdir}/../../include/bitcoin/node/messages/messages.hpp \
- ${srcdir}/../../include/bitcoin/node/messages/transaction.hpp
-
include_bitcoin_node_protocolsdir = \
${includedir}/bitcoin/node/protocols
@@ -240,7 +230,8 @@ test_libbitcoin_node_test_SOURCES = \
${srcdir}/../../test/chasers/chaser_template.cpp \
${srcdir}/../../test/chasers/chaser_transaction.cpp \
${srcdir}/../../test/chasers/chaser_validate.cpp \
- ${srcdir}/../../test/messages/block.cpp \
+ ${srcdir}/../../test/functional/p2p.cpp \
+ ${srcdir}/../../test/functional/p2p_setup_fixture.cpp \
${srcdir}/../../test/protocols/protocol.cpp \
${srcdir}/../../test/sessions/session.cpp
diff --git a/builds/msvc/vs2022/libbitcoin-node-test/libbitcoin-node-test.vcxproj b/builds/msvc/vs2022/libbitcoin-node-test/libbitcoin-node-test.vcxproj
index 5eaccba2..9e8a8fec 100644
--- a/builds/msvc/vs2022/libbitcoin-node-test/libbitcoin-node-test.vcxproj
+++ b/builds/msvc/vs2022/libbitcoin-node-test/libbitcoin-node-test.vcxproj
@@ -134,14 +134,16 @@
+
+
-
+
diff --git a/builds/msvc/vs2022/libbitcoin-node-test/libbitcoin-node-test.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-node-test/libbitcoin-node-test.vcxproj.filters
index 7a4755f8..d1511e0f 100644
--- a/builds/msvc/vs2022/libbitcoin-node-test/libbitcoin-node-test.vcxproj.filters
+++ b/builds/msvc/vs2022/libbitcoin-node-test/libbitcoin-node-test.vcxproj.filters
@@ -13,7 +13,7 @@
{4BD50864-D3BC-4F64-0000-000000000001}
-
+
{4BD50864-D3BC-4F64-0000-000000000002}
@@ -72,12 +72,15 @@
src
+
+ src\functional
+
+
+ src\functional
+
src
-
- src\messages
-
src\protocols
@@ -92,6 +95,9 @@
+
+ src\functional
+
src
diff --git a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj
index c9de9cbf..c355ac35 100644
--- a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj
+++ b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj
@@ -142,8 +142,6 @@
-
-
@@ -194,9 +192,6 @@
-
-
-
diff --git a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters
index ada1ec44..a6dbdb30 100644
--- a/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters
+++ b/builds/msvc/vs2022/libbitcoin-node/libbitcoin-node.vcxproj.filters
@@ -31,35 +31,29 @@
{5FFB5F52-0772-4404-0000-000000000007}
-
- {5FFB5F52-0772-4404-0000-000000000008}
-
- {5FFB5F52-0772-4404-0000-000000000009}
+ {5FFB5F52-0772-4404-0000-000000000008}
- {5FFB5F52-0772-4404-0000-00000000000A}
+ {5FFB5F52-0772-4404-0000-000000000009}
- {5FFB5F52-0772-4404-0000-00000000000B}
+ {5FFB5F52-0772-4404-0000-00000000000A}
- {5FFB5F52-0772-4404-0000-00000000000C}
+ {5FFB5F52-0772-4404-0000-00000000000B}
- {5FFB5F52-0772-4404-0000-00000000000D}
+ {5FFB5F52-0772-4404-0000-00000000000C}
- {5FFB5F52-0772-4404-0000-00000000000E}
-
-
- {5FFB5F52-0772-4404-0000-00000000000F}
+ {5FFB5F52-0772-4404-0000-00000000000D}
- {5FFB5F52-0772-4404-0000-000000000001}
+ {5FFB5F52-0772-4404-0000-00000000000E}
- {5FFB5F52-0772-4404-0000-000000000002}
+ {5FFB5F52-0772-4404-0000-00000000000F}
@@ -126,12 +120,6 @@
src
-
- src\messages
-
-
- src\messages
-
src\protocols
@@ -278,15 +266,6 @@
include\bitcoin\node
-
- include\bitcoin\node\messages
-
-
- include\bitcoin\node\messages
-
-
- include\bitcoin\node\messages
-
include\bitcoin\node\protocols
diff --git a/builds/msvc/vs2026/libbitcoin-node-test/libbitcoin-node-test.vcxproj b/builds/msvc/vs2026/libbitcoin-node-test/libbitcoin-node-test.vcxproj
index aa83f3bf..d52609c3 100644
--- a/builds/msvc/vs2026/libbitcoin-node-test/libbitcoin-node-test.vcxproj
+++ b/builds/msvc/vs2026/libbitcoin-node-test/libbitcoin-node-test.vcxproj
@@ -134,14 +134,16 @@
+
+
-
+
diff --git a/builds/msvc/vs2026/libbitcoin-node-test/libbitcoin-node-test.vcxproj.filters b/builds/msvc/vs2026/libbitcoin-node-test/libbitcoin-node-test.vcxproj.filters
index 7a4755f8..d1511e0f 100644
--- a/builds/msvc/vs2026/libbitcoin-node-test/libbitcoin-node-test.vcxproj.filters
+++ b/builds/msvc/vs2026/libbitcoin-node-test/libbitcoin-node-test.vcxproj.filters
@@ -13,7 +13,7 @@
{4BD50864-D3BC-4F64-0000-000000000001}
-
+
{4BD50864-D3BC-4F64-0000-000000000002}
@@ -72,12 +72,15 @@
src
+
+ src\functional
+
+
+ src\functional
+
src
-
- src\messages
-
src\protocols
@@ -92,6 +95,9 @@
+
+ src\functional
+
src
diff --git a/builds/msvc/vs2026/libbitcoin-node/libbitcoin-node.vcxproj b/builds/msvc/vs2026/libbitcoin-node/libbitcoin-node.vcxproj
index 37eda379..2d05d8d6 100644
--- a/builds/msvc/vs2026/libbitcoin-node/libbitcoin-node.vcxproj
+++ b/builds/msvc/vs2026/libbitcoin-node/libbitcoin-node.vcxproj
@@ -142,8 +142,6 @@
-
-
@@ -194,9 +192,6 @@
-
-
-
diff --git a/builds/msvc/vs2026/libbitcoin-node/libbitcoin-node.vcxproj.filters b/builds/msvc/vs2026/libbitcoin-node/libbitcoin-node.vcxproj.filters
index ada1ec44..a6dbdb30 100644
--- a/builds/msvc/vs2026/libbitcoin-node/libbitcoin-node.vcxproj.filters
+++ b/builds/msvc/vs2026/libbitcoin-node/libbitcoin-node.vcxproj.filters
@@ -31,35 +31,29 @@
{5FFB5F52-0772-4404-0000-000000000007}
-
- {5FFB5F52-0772-4404-0000-000000000008}
-
- {5FFB5F52-0772-4404-0000-000000000009}
+ {5FFB5F52-0772-4404-0000-000000000008}
- {5FFB5F52-0772-4404-0000-00000000000A}
+ {5FFB5F52-0772-4404-0000-000000000009}
- {5FFB5F52-0772-4404-0000-00000000000B}
+ {5FFB5F52-0772-4404-0000-00000000000A}
- {5FFB5F52-0772-4404-0000-00000000000C}
+ {5FFB5F52-0772-4404-0000-00000000000B}
- {5FFB5F52-0772-4404-0000-00000000000D}
+ {5FFB5F52-0772-4404-0000-00000000000C}
- {5FFB5F52-0772-4404-0000-00000000000E}
-
-
- {5FFB5F52-0772-4404-0000-00000000000F}
+ {5FFB5F52-0772-4404-0000-00000000000D}
- {5FFB5F52-0772-4404-0000-000000000001}
+ {5FFB5F52-0772-4404-0000-00000000000E}
- {5FFB5F52-0772-4404-0000-000000000002}
+ {5FFB5F52-0772-4404-0000-00000000000F}
@@ -126,12 +120,6 @@
src
-
- src\messages
-
-
- src\messages
-
src\protocols
@@ -278,15 +266,6 @@
include\bitcoin\node
-
- include\bitcoin\node\messages
-
-
- include\bitcoin\node\messages
-
-
- include\bitcoin\node\messages
-
include\bitcoin\node\protocols
diff --git a/include/bitcoin/node.hpp b/include/bitcoin/node.hpp
index 1b8f31b1..b7d31740 100644
--- a/include/bitcoin/node.hpp
+++ b/include/bitcoin/node.hpp
@@ -44,9 +44,6 @@
#include
#include
#include
-#include
-#include
-#include
#include
#include
#include
diff --git a/include/bitcoin/node/messages/block.hpp b/include/bitcoin/node/messages/block.hpp
deleted file mode 100644
index 0823ed46..00000000
--- a/include/bitcoin/node/messages/block.hpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/**
- * Copyright (c) 2011-2026 libbitcoin developers
- *
- * 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_NODE_MESSAGES_BLOCK_HPP
-#define LIBBITCOIN_NODE_MESSAGES_BLOCK_HPP
-
-#include
-
-namespace libbitcoin {
-namespace node {
-namespace messages {
-
-/// Based on network::messages::peer::block.
-struct BCN_API block
-{
- typedef std::shared_ptr cptr;
-
- static const std::string command;
- static const uint32_t version_minimum;
- static const uint32_t version_maximum;
-
- // TODO: optimized translation direct to store.
- ////static cptr deserialize(uint32_t version, const system::data_chunk& data,
- //// bool witness=true) NOEXCEPT;
- ////static block deserialize(uint32_t version, system::reader& source,
- //// bool witness=true) NOEXCEPT;
-
- /// The held block is serialized in the requested form; a witnessed view
- /// is stripped when serialized without witness.
- /// The bool overload returns false only on a short output buffer.
- bool serialize(uint32_t version, const system::data_slab& data,
- bool witness=true) const NOEXCEPT;
- void serialize(uint32_t version, system::writer& sink,
- bool witness=true) const NOEXCEPT;
- size_t size(uint32_t version, bool witness=true) const NOEXCEPT;
-
- /// The block, serialized on demand as witnessed or stripped.
- system::chain::block_view block;
-};
-
-} // namespace messages
-} // namespace node
-} // namespace libbitcoin
-
-#endif
diff --git a/include/bitcoin/node/messages/messages.hpp b/include/bitcoin/node/messages/messages.hpp
deleted file mode 100644
index a5a5278e..00000000
--- a/include/bitcoin/node/messages/messages.hpp
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * Copyright (c) 2011-2026 libbitcoin developers
- *
- * 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_NODE_MESSAGES_MESSAGES_HPP
-#define LIBBITCOIN_NODE_MESSAGES_MESSAGES_HPP
-
-#include
-#include
-
-#endif
diff --git a/include/bitcoin/node/messages/transaction.hpp b/include/bitcoin/node/messages/transaction.hpp
deleted file mode 100644
index 11c3fa29..00000000
--- a/include/bitcoin/node/messages/transaction.hpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * Copyright (c) 2011-2026 libbitcoin developers
- *
- * 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_NODE_MESSAGES_TRANSACTION_HPP
-#define LIBBITCOIN_NODE_MESSAGES_TRANSACTION_HPP
-
-#include
-#include
-
-namespace libbitcoin {
-namespace node {
-namespace messages {
-
-/// Based on network::messages::peer::transaction.
-struct BCN_API transaction
-{
- typedef std::shared_ptr cptr;
-
- static const std::string command;
- static const uint32_t version_minimum;
- static const uint32_t version_maximum;
-
- // TODO: optimized translation direct to store.
- ////static cptr deserialize(uint32_t version, const system::data_chunk& data,
- //// bool witness=true) NOEXCEPT;
- ////static transaction deserialize(uint32_t version, system::reader& source,
- //// bool witness=true) NOEXCEPT;
-
- /// These return false if witness or version is inconsistent with tx data.
- bool serialize(uint32_t version, const system::data_slab& data,
- bool witness=true) const NOEXCEPT;
- void serialize(uint32_t version, system::writer& sink,
- bool witness=true) const NOEXCEPT;
- size_t size(uint32_t version, bool witness=true) const NOEXCEPT;
-
- /// Wire serialized transaction.
- system::data_chunk tx_data{};
-
- /// Non-witness hash of the transaction (for non-witness send optimize).
- system::hash_digest hash{};
-
- /// Transaction contains witness data (if applicable).
- const bool witnessed_{};
-};
-
-} // namespace messages
-} // namespace node
-} // namespace libbitcoin
-
-#endif
diff --git a/src/messages/block.cpp b/src/messages/block.cpp
deleted file mode 100644
index 196249f7..00000000
--- a/src/messages/block.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * Copyright (c) 2011-2026 libbitcoin developers
- *
- * 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
-
-#include
-
-namespace libbitcoin {
-namespace node {
-namespace messages {
-
-using namespace system;
-using namespace network::messages::peer;
-
-const std::string block::command = "block";
-const uint32_t block::version_minimum = level::minimum_protocol;
-const uint32_t block::version_maximum = level::maximum_protocol;
-
-// data_slab is preallocated after the message header using size().
-bool block::serialize(uint32_t version, const data_slab& data,
- bool witness) const NOEXCEPT
-{
- system::stream::out::fast out{ data };
- system::write::bytes::fast writer{ out };
- serialize(version, writer, witness);
- return writer;
-}
-
-void block::serialize(uint32_t, writer& sink, bool witness) const NOEXCEPT
-{
- block.to_data(sink, witness);
-}
-
-size_t block::size(uint32_t, bool witness) const NOEXCEPT
-{
- return block.is_valid() ? block.serialized_size(witness) : zero;
-}
-
-} // namespace messages
-} // namespace node
-} // namespace libbitcoin
diff --git a/src/messages/transaction.cpp b/src/messages/transaction.cpp
deleted file mode 100644
index 0a0359ff..00000000
--- a/src/messages/transaction.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * Copyright (c) 2011-2026 libbitcoin developers
- *
- * 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
-
-#include
-
-namespace libbitcoin {
-namespace node {
-namespace messages {
-
-using namespace system;
-using namespace network::messages::peer;
-
-const std::string transaction::command = "tx";
-const uint32_t transaction::version_minimum = level::minimum_protocol;
-const uint32_t transaction::version_maximum = level::maximum_protocol;
-
-// data_slab is preallocated after the message header using size().
-bool transaction::serialize(uint32_t version, const data_slab& data,
- bool witness) const NOEXCEPT
-{
- if (witness != witnessed_)
- return false;
-
- system::stream::out::fast out{ data };
- system::write::bytes::fast writer{ out };
- serialize(version, writer, witness);
- return writer;
-}
-
-// Sender must ensure that version/witness are consistent with channel.
-void transaction::serialize(uint32_t, writer& sink,
- bool BC_DEBUG_ONLY(witness)) const NOEXCEPT
-{
- BC_ASSERT(witness == witnessed_);
- sink.write_bytes(tx_data);
-}
-
-// Sender must ensure that version/witness are consistent with channel.
-size_t transaction::size(uint32_t, bool BC_DEBUG_ONLY(witness)) const NOEXCEPT
-{
- BC_ASSERT(witness == witnessed_);
- return tx_data.size();
-}
-
-} // namespace messages
-} // namespace node
-} // namespace libbitcoin
diff --git a/src/protocols/protocol_block_out_106.cpp b/src/protocols/protocol_block_out_106.cpp
index fa928133..51495482 100644
--- a/src/protocols/protocol_block_out_106.cpp
+++ b/src/protocols/protocol_block_out_106.cpp
@@ -20,7 +20,6 @@
#include
#include
-#include
namespace libbitcoin {
namespace node {
@@ -226,7 +225,7 @@ void protocol_block_out_106::send_block(const code& ec) NOEXCEPT
}
const auto start = logger::now();
- node::messages::block out
+ messages::peer::block out
{
{ query.get_wire_block(link, witness), witness }
};
diff --git a/test/functional/p2p.cpp b/test/functional/p2p.cpp
new file mode 100644
index 00000000..0d244a86
--- /dev/null
+++ b/test/functional/p2p.cpp
@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) 2011-2026 libbitcoin developers
+ *
+ * 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 "p2p_setup_fixture.hpp"
+
+BOOST_FIXTURE_TEST_SUITE(functional_p2p_tests, p2p_setup_fixture)
+
+using namespace network::messages::peer;
+
+BOOST_AUTO_TEST_CASE(functional_p2p__handshake__default__provides_network_and_witness)
+{
+ BOOST_REQUIRE(handshake());
+ BOOST_REQUIRE_EQUAL(node_version->value, config_.network.protocol_maximum);
+ BOOST_REQUIRE_EQUAL(node_version->services,
+ service::node_network | service::node_witness);
+}
+
+BOOST_AUTO_TEST_CASE(functional_p2p__ping__nonce__pong_echo)
+{
+ BOOST_REQUIRE(handshake());
+
+ constexpr uint64_t expected = 42;
+ send(ping{ expected }, node_version->value);
+
+ const auto payload = receive(pong::command);
+ const auto message = pong::deserialize(node_version->value, payload);
+ BOOST_REQUIRE(message);
+ BOOST_REQUIRE_EQUAL(message->nonce, expected);
+}
+
+// The block send regression (github.com/libbitcoin/libbitcoin-network/862).
+BOOST_AUTO_TEST_CASE(functional_p2p__get_data__genesis_block__expected_bytes)
+{
+ BOOST_REQUIRE(handshake());
+
+ const system::chain::block& genesis = config_.bitcoin.genesis_block;
+ const auto expected = genesis.to_data(true);
+
+ const get_data get{ { { inventory_item::type_id::block, genesis.hash() } } };
+ send(get, node_version->value);
+
+ const auto payload = receive(block::command);
+ BOOST_REQUIRE_EQUAL(payload.size(), expected.size());
+ BOOST_REQUIRE(payload == expected);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/functional/p2p_setup_fixture.cpp b/test/functional/p2p_setup_fixture.cpp
new file mode 100644
index 00000000..a4acf10d
--- /dev/null
+++ b/test/functional/p2p_setup_fixture.cpp
@@ -0,0 +1,173 @@
+/**
+ * Copyright (c) 2011-2026 libbitcoin developers
+ *
+ * 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 "p2p_setup_fixture.hpp"
+#include
+
+using namespace bc::system;
+using namespace bc::network::messages::peer;
+
+BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
+
+p2p_setup_fixture::p2p_setup_fixture(const initializer& setup,
+ const configurator& configure)
+ : config_{ chain::selection::mainnet },
+ store_
+ {
+ [&]() NOEXCEPT -> const database::settings&
+ {
+ config_.database.path = TEST_DIRECTORY;
+ return config_.database;
+ }()
+ },
+ query_{ store_ },
+ node_{ query_, config_, log_ }
+{
+ test::clear(test::directory);
+
+ auto& network_settings = config_.network;
+ auto& node_settings = config_.node;
+
+ network_settings.path = TEST_DIRECTORY;
+ network_settings.inbound.connections = 1;
+ network_settings.inbound.binds.clear();
+ network_settings.inbound.binds.emplace_back(P2P_FUNCTIONAL_ENDPOINT);
+ network_settings.outbound.connections = 0;
+ network_settings.outbound.seeds.clear();
+ node_settings.delay_inbound = false;
+
+ // Apply test-specific configuration overrides.
+ if (configure)
+ configure(config_);
+
+ // Create and populate the store.
+ auto ec = store_.create([](auto, auto) {});
+ BOOST_REQUIRE_MESSAGE(!ec, ec.message());
+
+ const chain::block& genesis = config_.bitcoin.genesis_block;
+ BOOST_REQUIRE(query_.initialize(genesis));
+
+ if (setup)
+ BOOST_REQUIRE(setup(query_));
+
+ std::promise started{};
+ node_.start([&](const code& ec) NOEXCEPT
+ {
+ started.set_value(ec);
+ });
+
+ // Block until the node is started.
+ ec = started.get_future().get();
+ BOOST_REQUIRE_MESSAGE(!ec, ec.message());
+
+ std::promise running{};
+ node_.run([&](const code& ec) NOEXCEPT
+ {
+ running.set_value(ec);
+ });
+
+ // Block until the node is running.
+ ec = running.get_future().get();
+ BOOST_REQUIRE_MESSAGE(!ec, ec.message());
+ socket_.connect(network_settings.inbound.binds.back().to_endpoint());
+}
+
+p2p_setup_fixture::~p2p_setup_fixture()
+{
+ socket_.close();
+ node_.close();
+ const auto ec = store_.close([](auto, auto) {});
+ BOOST_WARN_MESSAGE(!ec, ec.message());
+ test::clear(test::directory);
+}
+
+void p2p_setup_fixture::send(const std::string& command,
+ const data_chunk& payload)
+{
+ const auto head = heading::factory(config_.network.identifier, command,
+ payload);
+ data_chunk frame(heading::size() + payload.size());
+ BOOST_REQUIRE(head.serialize({ frame.data(),
+ std::next(frame.data(), heading::size()) }));
+
+ std::copy(payload.begin(), payload.end(),
+ std::next(frame.begin(), heading::size()));
+ boost::asio::write(socket_, boost::asio::buffer(frame));
+}
+
+std::pair p2p_setup_fixture::receive()
+{
+ data_array head_data{};
+ boost::asio::read(socket_, boost::asio::buffer(head_data));
+ const auto head = heading::deserialize(head_data);
+ BOOST_REQUIRE(head);
+
+ data_chunk payload(head->payload_size);
+ if (!payload.empty())
+ boost::asio::read(socket_, boost::asio::buffer(payload));
+
+ return { head->command, std::move(payload) };
+}
+
+data_chunk p2p_setup_fixture::receive(const std::string& command)
+{
+ while (true)
+ {
+ auto message = receive();
+ if (message.first == command)
+ return std::move(message.second);
+ }
+}
+
+bool p2p_setup_fixture::handshake(uint64_t services, uint32_t value)
+{
+ version out{};
+ out.value = value;
+ out.services = services;
+ out.timestamp = sign_cast(network::zulu_time());
+ out.nonce = 42424242;
+ out.user_agent = "/test/";
+ out.start_height = 0;
+ out.relay = false;
+ send(out, value);
+
+ // The node sends its version upon attach and verack upon our version.
+ auto got_version = false;
+ auto got_acknowledge = false;
+ while (!got_version || !got_acknowledge)
+ {
+ const auto message = receive();
+ if (message.first == version::command)
+ {
+ node_version = version::deserialize(value, message.second);
+ if (!node_version)
+ return false;
+
+ got_version = true;
+ }
+ else if (message.first == version_acknowledge::command)
+ {
+ got_acknowledge = true;
+ }
+ }
+
+ send(version_acknowledge{}, value);
+ return true;
+}
+
+BC_POP_WARNING()
diff --git a/test/functional/p2p_setup_fixture.hpp b/test/functional/p2p_setup_fixture.hpp
new file mode 100644
index 00000000..b4a7f80c
--- /dev/null
+++ b/test/functional/p2p_setup_fixture.hpp
@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2011-2026 libbitcoin developers
+ *
+ * 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_NODE_TEST_FUNCTIONAL_P2P_SETUP_FIXTURE
+#define LIBBITCOIN_NODE_TEST_FUNCTIONAL_P2P_SETUP_FIXTURE
+
+#include "../test.hpp"
+
+#define P2P_FUNCTIONAL_ENDPOINT "127.0.0.1:65009"
+
+// Runs a real full node accepting on loopback, with the test acting as the
+// remote peer over a raw blocking socket (framing via peer messages).
+struct p2p_setup_fixture
+{
+ DELETE_COPY_MOVE(p2p_setup_fixture);
+
+ using initializer = std::function;
+ using configurator = std::function;
+ explicit p2p_setup_fixture(const initializer& setup={},
+ const configurator& configure={});
+ ~p2p_setup_fixture();
+
+ /// Write a framed message to the node.
+ void send(const std::string& command, const system::data_chunk& payload);
+
+ /// Serialize and write a framed message to the node.
+ template
+ void send(const Message& message, uint32_t version)
+ {
+ system::data_chunk payload(message.size(version));
+ BOOST_REQUIRE(message.serialize(version, payload));
+ send(Message::command, payload);
+ }
+
+ /// Read one framed message from the node.
+ std::pair receive();
+
+ /// Read framed messages from the node until the command matches.
+ system::data_chunk receive(const std::string& command);
+
+ /// Perform the version handshake, retains the node's version message.
+ bool handshake(uint64_t services=0,
+ uint32_t version=network::messages::peer::level::maximum_protocol);
+
+ /// The node's version message (set by handshake).
+ network::messages::peer::version::cptr node_version{};
+
+protected:
+ configuration config_;
+ node::store store_;
+ node::query query_;
+ network::logger log_{};
+ full_node node_;
+
+private:
+ boost::asio::io_context io_{};
+ boost::asio::ip::tcp::socket socket_{ io_ };
+};
+
+#endif
diff --git a/test/messages/block.cpp b/test/messages/block.cpp
deleted file mode 100644
index 4ae27b0e..00000000
--- a/test/messages/block.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * Copyright (c) 2011-2026 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"
-
-BOOST_AUTO_TEST_SUITE(block_tests)
-
-using namespace network::messages;
-
-// The message holds a block_view and serializes in the requested form. Genesis
-// is non-witness (witnessed and stripped forms are identical); the witnessed
-// strip is covered by the libbitcoin-system block_view to_data tests.
-
-BOOST_AUTO_TEST_CASE(block__serialize__witness__expected)
-{
- const system::settings settings{ system::chain::selection::mainnet };
- const node::messages::block instance
- {
- { settings.genesis_block.to_data(true), true }
- };
- system::data_chunk buffer(instance.size(peer::level::canonical, true));
- BOOST_REQUIRE(instance.serialize(peer::level::canonical, { buffer }, true));
- BOOST_REQUIRE_EQUAL(buffer, settings.genesis_block.to_data(true));
-}
-
-BOOST_AUTO_TEST_CASE(block__serialize__non_witness__expected)
-{
- const system::settings settings{ system::chain::selection::mainnet };
- const node::messages::block instance
- {
- { settings.genesis_block.to_data(true), false }
- };
- system::data_chunk buffer(instance.size(peer::level::canonical, false));
- BOOST_REQUIRE(instance.serialize(peer::level::canonical, { buffer }, false));
- BOOST_REQUIRE_EQUAL(buffer, settings.genesis_block.to_data(false));
-}
-
-BOOST_AUTO_TEST_CASE(block__serialize__short_buffer__false)
-{
- const system::settings settings{ system::chain::selection::mainnet };
- const node::messages::block instance
- {
- { settings.genesis_block.to_data(true), true }
- };
- system::data_chunk buffer(sub1(instance.size(peer::level::canonical, true)));
- BOOST_REQUIRE(!instance.serialize(peer::level::canonical, { buffer }, true));
-}
-
-BOOST_AUTO_TEST_SUITE_END()