diff --git a/Makefile.am b/Makefile.am
index 4c4228838..c01022a25 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -109,6 +109,7 @@ src_libbitcoin_network_la_SOURCES = \
src/protocols/protocol_version_31402.cpp \
src/protocols/protocol_version_70001.cpp \
src/protocols/protocol_version_70002.cpp \
+ src/protocols/protocol_version_70016.cpp \
src/sessions/session.cpp \
src/sessions/session_inbound.cpp \
src/sessions/session_manual.cpp \
@@ -209,6 +210,7 @@ test_libbitcoin_network_test_SOURCES = \
test/protocols/protocol_version_31402.cpp \
test/protocols/protocol_version_70001.cpp \
test/protocols/protocol_version_70002.cpp \
+ test/protocols/protocol_version_70016.cpp \
test/sessions/session.cpp \
test/sessions/session_inbound.cpp \
test/sessions/session_manual.cpp \
@@ -365,6 +367,7 @@ include_bitcoin_network_protocols_HEADERS = \
include/bitcoin/network/protocols/protocol_version_31402.hpp \
include/bitcoin/network/protocols/protocol_version_70001.hpp \
include/bitcoin/network/protocols/protocol_version_70002.hpp \
+ include/bitcoin/network/protocols/protocol_version_70016.hpp \
include/bitcoin/network/protocols/protocols.hpp
include_bitcoin_network_sessionsdir = ${includedir}/bitcoin/network/sessions
diff --git a/builds/cmake/CMakeLists.txt b/builds/cmake/CMakeLists.txt
index b246788a2..58732e133 100644
--- a/builds/cmake/CMakeLists.txt
+++ b/builds/cmake/CMakeLists.txt
@@ -291,6 +291,7 @@ add_library( ${CANONICAL_LIB_NAME}
"../../src/protocols/protocol_version_31402.cpp"
"../../src/protocols/protocol_version_70001.cpp"
"../../src/protocols/protocol_version_70002.cpp"
+ "../../src/protocols/protocol_version_70016.cpp"
"../../src/sessions/session.cpp"
"../../src/sessions/session_inbound.cpp"
"../../src/sessions/session_manual.cpp"
@@ -415,6 +416,7 @@ if (with-tests)
"../../test/protocols/protocol_version_31402.cpp"
"../../test/protocols/protocol_version_70001.cpp"
"../../test/protocols/protocol_version_70002.cpp"
+ "../../test/protocols/protocol_version_70016.cpp"
"../../test/sessions/session.cpp"
"../../test/sessions/session_inbound.cpp"
"../../test/sessions/session_manual.cpp"
diff --git a/builds/msvc/vs2022/libbitcoin-network-test/libbitcoin-network-test.vcxproj b/builds/msvc/vs2022/libbitcoin-network-test/libbitcoin-network-test.vcxproj
index 0c795067c..98e9bd7a9 100644
--- a/builds/msvc/vs2022/libbitcoin-network-test/libbitcoin-network-test.vcxproj
+++ b/builds/msvc/vs2022/libbitcoin-network-test/libbitcoin-network-test.vcxproj
@@ -203,6 +203,7 @@
+
diff --git a/builds/msvc/vs2022/libbitcoin-network-test/libbitcoin-network-test.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-network-test/libbitcoin-network-test.vcxproj.filters
index c4ae92dbe..31b82f2db 100644
--- a/builds/msvc/vs2022/libbitcoin-network-test/libbitcoin-network-test.vcxproj.filters
+++ b/builds/msvc/vs2022/libbitcoin-network-test/libbitcoin-network-test.vcxproj.filters
@@ -279,6 +279,9 @@
src\protocols
+
+ src\protocols
+
src\sessions
diff --git a/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj b/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj
index 24890a483..5b764ef51 100644
--- a/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj
+++ b/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj
@@ -198,6 +198,7 @@
+
@@ -306,6 +307,7 @@
+
diff --git a/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj.filters
index 7be69461f..628ec805f 100644
--- a/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj.filters
+++ b/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj.filters
@@ -300,6 +300,9 @@
src\protocols
+
+ src\protocols
+
src\sessions
@@ -620,6 +623,9 @@
include\bitcoin\network\protocols
+
+ include\bitcoin\network\protocols
+
include\bitcoin\network\protocols
diff --git a/include/bitcoin/network.hpp b/include/bitcoin/network.hpp
index cf9b11382..16ddeb11d 100644
--- a/include/bitcoin/network.hpp
+++ b/include/bitcoin/network.hpp
@@ -116,6 +116,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/include/bitcoin/network/protocols/protocol_version_70016.hpp b/include/bitcoin/network/protocols/protocol_version_70016.hpp
new file mode 100644
index 000000000..16d99a9d1
--- /dev/null
+++ b/include/bitcoin/network/protocols/protocol_version_70016.hpp
@@ -0,0 +1,71 @@
+/**
+ * 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_NETWORK_PROTOCOL_VERSION_70016_HPP
+#define LIBBITCOIN_NETWORK_PROTOCOL_VERSION_70016_HPP
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace libbitcoin {
+namespace network {
+
+class BCT_API protocol_version_70016
+ : public protocol_version_70002, protected tracker
+{
+public:
+ typedef std::shared_ptr ptr;
+
+ /// Construct a version protocol instance using configured values.
+ protocol_version_70016(const session::ptr& session,
+ const channel::ptr& channel) NOEXCEPT;
+
+ /// Construct a version protocol instance using parameterized services.
+ protocol_version_70016(const session::ptr& session,
+ const channel::ptr& channel, uint64_t minimum_services,
+ uint64_t maximum_services, bool relay, bool reject) NOEXCEPT;
+
+ /// Perform the handshake (strand required), handler invoked on completion.
+ void shake(result_handler&& handle_event) NOEXCEPT override;
+
+protected:
+ void handle_send_version(const code& ec) NOEXCEPT override;
+ bool handle_receive_acknowledge(const code& ec,
+ const messages::version_acknowledge::cptr& message) NOEXCEPT override;
+ virtual bool handle_receive_send_address_v2(const code& ec,
+ const messages::send_address_v2::cptr& message) NOEXCEPT;
+
+private:
+ // This is thread safe.
+ const bool reject_;
+
+ // This is protected by strand.
+ bool complete_{};
+};
+
+} // namespace network
+} // namespace libbitcoin
+
+#endif
diff --git a/include/bitcoin/network/protocols/protocols.hpp b/include/bitcoin/network/protocols/protocols.hpp
index cbeff1f9e..94e0c8515 100644
--- a/include/bitcoin/network/protocols/protocols.hpp
+++ b/include/bitcoin/network/protocols/protocols.hpp
@@ -30,5 +30,6 @@
#include
#include
#include
+#include
#endif
diff --git a/src/protocols/protocol_version_31402.cpp b/src/protocols/protocol_version_31402.cpp
index 026daa5e9..d5d41766e 100644
--- a/src/protocols/protocol_version_31402.cpp
+++ b/src/protocols/protocol_version_31402.cpp
@@ -54,7 +54,8 @@ protocol_version_31402::protocol_version_31402(const session::ptr& session,
// Used for seeding (should probably not override these).
protocol_version_31402::protocol_version_31402(const session::ptr& session,
- const channel::ptr& channel, uint64_t minimum_services,
+ const channel::ptr& channel,
+ uint64_t minimum_services,
uint64_t maximum_services) NOEXCEPT
: protocol(session, channel),
inbound_(channel->inbound()),
@@ -335,7 +336,7 @@ bool protocol_version_31402::handle_receive_version(const code& ec,
if (is_disallowed_deviation(message->timestamp))
{
- LOGP("Timestamp out of range (" << message->value << ") "
+ LOGR("Timestamp out of range (" << message->value << ") "
"for [" << authority() << "].");
rejection(error::peer_timestamp);
diff --git a/src/protocols/protocol_version_70001.cpp b/src/protocols/protocol_version_70001.cpp
index 535335162..eacee49d1 100644
--- a/src/protocols/protocol_version_70001.cpp
+++ b/src/protocols/protocol_version_70001.cpp
@@ -45,10 +45,11 @@ protocol_version_70001::protocol_version_70001(const session::ptr& session,
}
protocol_version_70001::protocol_version_70001(const session::ptr& session,
- const channel::ptr& channel, uint64_t minimum_services,
- uint64_t maximum_services, bool relay) NOEXCEPT
- : protocol_version_31402(session, channel, minimum_services,
- maximum_services),
+ const channel::ptr& channel,
+ uint64_t minimum_services,
+ uint64_t maximum_services,
+ bool relay) NOEXCEPT
+ : protocol_version_31402(session, channel, minimum_services, maximum_services),
relay_(relay),
tracker(session->log)
{
diff --git a/src/protocols/protocol_version_70002.cpp b/src/protocols/protocol_version_70002.cpp
index f652e03f0..e08b62bd1 100644
--- a/src/protocols/protocol_version_70002.cpp
+++ b/src/protocols/protocol_version_70002.cpp
@@ -27,11 +27,6 @@
#include
#include
-// TODO: incorporate "sendaddrv2" into a new protocol_version_70016.
-// TODO: sendaddrv2 is a a broken protocol in that it is a formally unversioned
-// TODO: message, though Satoshi doesn't send until receiving version >= 70016.
-// TODO: must be sent/received before verack (and sent after version receipt).
-
namespace libbitcoin {
namespace network {
@@ -51,10 +46,11 @@ protocol_version_70002::protocol_version_70002(const session::ptr& session,
}
protocol_version_70002::protocol_version_70002(const session::ptr& session,
- const channel::ptr& channel, uint64_t minimum_services,
- uint64_t maximum_services, bool relay) NOEXCEPT
- : protocol_version_70001(session, channel, minimum_services,
- maximum_services, relay),
+ const channel::ptr& channel,
+ uint64_t minimum_services,
+ uint64_t maximum_services,
+ bool relay) NOEXCEPT
+ : protocol_version_70001(session, channel, minimum_services, maximum_services, relay),
tracker(session->log)
{
}
@@ -76,6 +72,7 @@ void protocol_version_70002::shake(result_handler&& handle_event) NOEXCEPT
// Outgoing [(in)sufficient_peer => send_reject].
// ----------------------------------------------------------------------------
+// Reject is the only difference at protocol level 70002.
void protocol_version_70002::rejection(const code& ec) NOEXCEPT
{
@@ -104,7 +101,7 @@ void protocol_version_70002::rejection(const code& ec) NOEXCEPT
"timestamp" }), handle_send, _1);
}
- return protocol_version_70001::rejection(ec);
+ protocol_version_70001::rejection(ec);
}
// Incoming [receive_reject => log].
diff --git a/src/protocols/protocol_version_70016.cpp b/src/protocols/protocol_version_70016.cpp
new file mode 100644
index 000000000..e347b07a2
--- /dev/null
+++ b/src/protocols/protocol_version_70016.cpp
@@ -0,0 +1,129 @@
+/**
+ * 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
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+// sendaddrv2 is a a broken protocol in that it is a formally unversioned
+// message, though Satoshi doesn't send until receiving version >= 70016.
+// It must be sent/received before verack (and sent after version receipt).
+
+namespace libbitcoin {
+namespace network {
+
+#define CLASS protocol_version_70016
+
+using namespace system;
+using namespace bc::network::messages;
+using namespace std::placeholders;
+
+protocol_version_70016::protocol_version_70016(const session::ptr& session,
+ const channel::ptr& channel) NOEXCEPT
+ : protocol_version_70016(session, channel,
+ session->settings().services_minimum,
+ session->settings().services_maximum,
+ session->settings().enable_transaction,
+ session->settings().enable_reject)
+{
+}
+
+protocol_version_70016::protocol_version_70016(const session::ptr& session,
+ const channel::ptr& channel,
+ uint64_t minimum_services,
+ uint64_t maximum_services,
+ bool relay,
+ bool reject) NOEXCEPT
+ : protocol_version_70002(session, channel, minimum_services, maximum_services, relay),
+ reject_(reject),
+ tracker(session->log)
+{
+}
+
+// Start.
+// ----------------------------------------------------------------------------
+
+void protocol_version_70016::shake(result_handler&& handle_event) NOEXCEPT
+{
+ BC_ASSERT_MSG(stranded(), "protocol_version_70016");
+
+ if (started())
+ return;
+
+ // Protocol versions are cumulative, but reject is deprecated.
+ if (reject_)
+ {
+ protocol_version_70002::shake(std::move(handle_event));
+ return;
+ }
+
+ protocol_version_70001::shake(std::move(handle_event));
+}
+
+
+// Incoming [send_address_v2 => negotiated state change].
+// ----------------------------------------------------------------------------
+// send_address_v2 receipt is the only difference at protocol level 70016.
+
+void protocol_version_70016::handle_send_version(const code& ec) NOEXCEPT
+{
+ BC_ASSERT_MSG(stranded(), "protocol_version_70016");
+
+ SUBSCRIBE_CHANNEL(send_address_v2, handle_receive_send_address_v2, _1, _2);
+ protocol_version_70002::handle_send_version(ec);
+}
+
+bool protocol_version_70016::handle_receive_acknowledge(const code& ec,
+ const messages::version_acknowledge::cptr& message) NOEXCEPT
+{
+ complete_ = true;
+
+ // Channel will pause after this and then be restarted as connected.
+ return protocol_version_70002::handle_receive_acknowledge(ec, message);
+}
+
+bool protocol_version_70016::handle_receive_send_address_v2(const code& ec,
+ const send_address_v2::cptr&) NOEXCEPT
+{
+ BC_ASSERT_MSG(stranded(), "protocol_version_70016");
+
+ if (stopped(ec))
+ return false;
+
+ // Late or already received send_address_v2.
+ if (complete_)
+ {
+ rejection(error::protocol_violation);
+ return false;
+ }
+
+ // TODO: set channel addressv2 property and use to attach protocols.
+ // TODO: implement updated protocol_address_in|out_70016.
+ complete_ = true;
+ return true;
+}
+
+} // namespace network
+} // namespace libbitcoin
diff --git a/src/sessions/session.cpp b/src/sessions/session.cpp
index 87a990778..d550c845e 100644
--- a/src/sessions/session.cpp
+++ b/src/sessions/session.cpp
@@ -149,19 +149,24 @@ void session::attach_handshake(const channel::ptr& channel,
BC_ASSERT_MSG(channel->paused(), "channel not paused for handshake attach");
const auto self = shared_from_this();
- const auto maximum_version = settings().protocol_maximum;
- const auto extended_version = maximum_version >= messages::level::bip37;
- const auto enable_reject = settings().enable_reject &&
- maximum_version >= messages::level::bip61;
+ const auto maximum = settings().protocol_maximum;
+ const auto bip37 = maximum >= messages::level::bip37;
+ const auto bip61 = maximum >= messages::level::bip61;
+ const auto bip155 = maximum >= messages::level::bip155;
// Protocol must pause the channel after receiving version and verack.
- // Reject is deprecated.
- if (enable_reject)
+ // Address (in/out) can be disabled, independent of version.
+ if (bip155 && settings().enable_address)
+ channel->attach(self)
+ ->shake(std::move(handler));
+
+ // Protocol versions are cumulative, but reject is deprecated.
+ else if (bip61 && settings().enable_reject)
channel->attach(self)
->shake(std::move(handler));
- else if (extended_version)
+ else if (bip37)
channel->attach(self)
->shake(std::move(handler));
@@ -280,30 +285,38 @@ void session::attach_protocols(const channel::ptr& channel) NOEXCEPT
BC_ASSERT_MSG(channel->paused(), "channel not paused for protocol attach");
const auto self = shared_from_this();
- const auto enable_alert = settings().enable_alert;
- const auto enable_address = settings().enable_address;
- const auto negotiated_version = channel->negotiated_version();
- const auto enable_pong = negotiated_version >= messages::level::bip31;
- const auto enable_reject = settings().enable_reject &&
- negotiated_version >= messages::level::bip61;
-
- if (enable_pong)
- channel->attach(self)->start();
- else
- channel->attach(self)->start();
+ const auto negotiated = channel->negotiated_version();
+ const auto bip31 = negotiated >= messages::level::bip31;
+ const auto bip61 = negotiated >= messages::level::bip61;
+ const auto bip155 = negotiated >= messages::level::bip155;
- // Alert is deprecated.
- if (enable_alert)
+ // Alert is deprecated, independent of version.
+ if (settings().enable_alert)
channel->attach(self)->start();
- // Reject is deprecated.
- if (enable_reject)
+ // Reject is deprecated, independent of version.
+ if (bip61 && settings().enable_reject)
channel->attach(self)->start();
- if (enable_address)
+ if (bip31)
+ channel->attach(self)->start();
+ else
+ channel->attach(self)->start();
+
+ // Address (in/out) can be disabled, independent of version.
+ if (settings().enable_address)
{
- channel->attach(self)->start();
- channel->attach(self)->start();
+ ////// Receive based on config and negotiated version only (sent).
+ ////if (bip155)
+ //// channel->attach(self)->start();
+ ////else
+ channel->attach(self)->start();
+
+ ////// Peer requested (stoopid because version support is negotiated).
+ ////if (bip155 && channel->send_address_v2())
+ //// channel->attach(self)->start();
+ ////else
+ channel->attach(self)->start();
}
}
diff --git a/test/protocols/protocol_version_70016.cpp b/test/protocols/protocol_version_70016.cpp
new file mode 100644
index 000000000..e1e43ac78
--- /dev/null
+++ b/test/protocols/protocol_version_70016.cpp
@@ -0,0 +1,28 @@
+/**
+ * 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"
+
+BOOST_AUTO_TEST_SUITE(protocol_tests)
+
+BOOST_AUTO_TEST_CASE(protocol_version_70016_tests)
+{
+ BOOST_REQUIRE(true);
+}
+
+BOOST_AUTO_TEST_SUITE_END()