From ad1321d48ce56522deae4ed3befcf006a547ffa8 Mon Sep 17 00:00:00 2001 From: Eric Voskuil Date: Sun, 4 Oct 2026 21:27:29 -0400 Subject: [PATCH] Record the peer's compact block signal on the channel in the version protocol. --- .../bitcoin/network/channels/channel_peer.hpp | 7 +++ .../network/protocols/protocol_peer.hpp | 7 +++ .../protocols/protocol_version_70014.hpp | 11 ++++- .../protocols/protocol_version_70016.hpp | 3 -- src/channels/channel_peer.cpp | 16 +++++++ src/protocols/protocol_peer.cpp | 16 +++++++ src/protocols/protocol_version_70014.cpp | 48 +++++++++++++++++-- src/protocols/protocol_version_70016.cpp | 12 +---- test/channels/channel_peer.cpp | 28 +++++++++++ 9 files changed, 131 insertions(+), 17 deletions(-) diff --git a/include/bitcoin/network/channels/channel_peer.hpp b/include/bitcoin/network/channels/channel_peer.hpp index d4c1d1829..da656acf6 100644 --- a/include/bitcoin/network/channels/channel_peer.hpp +++ b/include/bitcoin/network/channels/channel_peer.hpp @@ -103,6 +103,11 @@ class BCT_API channel_peer bool wants_address_v2() const NOEXCEPT; void set_wants_address_v2() NOEXCEPT; + /// Peer signaled compact blocks version 2, and high bandwidth (bip152). + bool accepts_compact_blocks() const NOEXCEPT; + bool wants_compact_blocks() const NOEXCEPT; + void set_compact_blocks(bool high_bandwidth) NOEXCEPT; + /// Chain is current, reduces the read buffer to the configured minimum. bool current() const NOEXCEPT; void set_current(bool value) NOEXCEPT; @@ -205,6 +210,8 @@ class BCT_API channel_peer steady_clock::duration ping_{}; steady_clock::duration minimum_ping_{}; bool wants_address_v2_{}; + bool accepts_compact_blocks_{}; + bool wants_compact_blocks_{}; bool current_{}; bool reading_{}; bool quiet_{}; diff --git a/include/bitcoin/network/protocols/protocol_peer.hpp b/include/bitcoin/network/protocols/protocol_peer.hpp index 1c96f02da..b2c0c0431 100644 --- a/include/bitcoin/network/protocols/protocol_peer.hpp +++ b/include/bitcoin/network/protocols/protocol_peer.hpp @@ -82,6 +82,13 @@ class BCT_API protocol_peer /// Set that the peer accepts address v2 (set only during handshake). virtual void set_wants_address_v2() NOEXCEPT; + /// The peer signaled compact blocks version 2, and high bandwidth. + virtual bool accepts_compact_blocks() const NOEXCEPT; + virtual bool wants_compact_blocks() const NOEXCEPT; + + /// Set the peer's compact blocks signal (version protocol only). + virtual void set_compact_blocks(bool high_bandwidth) NOEXCEPT; + /// Advertised addresses with own services and current timestamp. virtual messages::peer::address selfs() const NOEXCEPT; diff --git a/include/bitcoin/network/protocols/protocol_version_70014.hpp b/include/bitcoin/network/protocols/protocol_version_70014.hpp index 8c4ee29e6..25382e247 100644 --- a/include/bitcoin/network/protocols/protocol_version_70014.hpp +++ b/include/bitcoin/network/protocols/protocol_version_70014.hpp @@ -42,11 +42,20 @@ class BCT_API protocol_version_70014 /// Construct a version protocol instance using parameterized relay. protocol_version_70014(const session::ptr& session, - const channel::ptr& channel, bool relay) NOEXCEPT; + const channel::ptr& channel, bool relay, bool reject) NOEXCEPT; + + /// Perform the handshake (requires strand), handler invoked on completion. + void shake(result_handler&& handle_event) NOEXCEPT override; protected: bool handle_receive_acknowledge(const code& ec, const messages::peer::version_acknowledge::cptr& message) NOEXCEPT override; + virtual bool handle_receive_send_compact(const code& ec, + const messages::peer::send_compact::cptr& message) NOEXCEPT; + +private: + // This is thread safe. + const bool reject_; }; } // namespace network diff --git a/include/bitcoin/network/protocols/protocol_version_70016.hpp b/include/bitcoin/network/protocols/protocol_version_70016.hpp index a29cce69a..7538b9ca8 100644 --- a/include/bitcoin/network/protocols/protocol_version_70016.hpp +++ b/include/bitcoin/network/protocols/protocol_version_70016.hpp @@ -58,9 +58,6 @@ class BCT_API protocol_version_70016 const messages::peer::witness_tx_id_relay::cptr& message) NOEXCEPT; private: - // This is thread safe. - const bool reject_; - // This is protected by strand. bool complete_{}; }; diff --git a/src/channels/channel_peer.cpp b/src/channels/channel_peer.cpp index 374911866..cbbe17d2a 100644 --- a/src/channels/channel_peer.cpp +++ b/src/channels/channel_peer.cpp @@ -86,6 +86,22 @@ void channel_peer::set_wants_address_v2() NOEXCEPT wants_address_v2_ = true; } +bool channel_peer::accepts_compact_blocks() const NOEXCEPT +{ + return accepts_compact_blocks_; +} + +bool channel_peer::wants_compact_blocks() const NOEXCEPT +{ + return wants_compact_blocks_; +} + +void channel_peer::set_compact_blocks(bool high_bandwidth) NOEXCEPT +{ + accepts_compact_blocks_ = true; + wants_compact_blocks_ = high_bandwidth; +} + bool channel_peer::is_negotiated(messages::peer::level level) const NOEXCEPT { return negotiated_version() >= level; diff --git a/src/protocols/protocol_peer.cpp b/src/protocols/protocol_peer.cpp index db6d95e64..c3f5645b8 100644 --- a/src/protocols/protocol_peer.cpp +++ b/src/protocols/protocol_peer.cpp @@ -93,6 +93,22 @@ void protocol_peer::set_wants_address_v2() NOEXCEPT channel_->set_wants_address_v2(); } +bool protocol_peer::accepts_compact_blocks() const NOEXCEPT +{ + return channel_->accepts_compact_blocks(); +} + +bool protocol_peer::wants_compact_blocks() const NOEXCEPT +{ + return channel_->wants_compact_blocks(); +} + +// Call only from the version protocol, for thread safety. +void protocol_peer::set_compact_blocks(bool high_bandwidth) NOEXCEPT +{ + channel_->set_compact_blocks(high_bandwidth); +} + address protocol_peer::selfs() const NOEXCEPT { const auto time_now = unix_time(); diff --git a/src/protocols/protocol_version_70014.cpp b/src/protocols/protocol_version_70014.cpp index 6115bfd8e..0f8655822 100644 --- a/src/protocols/protocol_version_70014.cpp +++ b/src/protocols/protocol_version_70014.cpp @@ -27,7 +27,7 @@ #include // sendcmpct (bip152) is sent after verack, so it cannot inform protocol -// attachment. The peer's sendcmpct is handled by the compact protocols. +// attachment. The peer's signal is recorded on the channel for the protocols. namespace libbitcoin { namespace network { @@ -41,17 +41,41 @@ using namespace std::placeholders; protocol_version_70014::protocol_version_70014(const session::ptr& session, const channel::ptr& channel) NOEXCEPT : protocol_version_70014(session, channel, - session->network_settings().enable_relay) + session->network_settings().enable_relay, + session->network_settings().enable_reject) { } protocol_version_70014::protocol_version_70014(const session::ptr& session, - const channel::ptr& channel, bool relay) NOEXCEPT + const channel::ptr& channel, bool relay, bool reject) NOEXCEPT : protocol_version_70002(session, channel, relay), + reject_(reject), tracker(session->log) { } +// Start. +// ---------------------------------------------------------------------------- + +void protocol_version_70014::shake(result_handler&& handle_event) NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "protocol_version_70014"); + + if (started()) + return; + + SUBSCRIBE_CHANNEL(send_compact, handle_receive_send_compact, _1, _2); + + // Protocol versions are cumulative, but reject is optional. + if (reject_) + { + protocol_version_70002::shake(std::move(handle_event)); + return; + } + + protocol_version_70001::shake(std::move(handle_event)); +} + // Outgoing [signal compact blocks version 2, low bandwidth (bip152)]. // ---------------------------------------------------------------------------- @@ -73,5 +97,23 @@ bool protocol_version_70014::handle_receive_acknowledge(const code& ec, return true; } +// Incoming [send_compact => negotiated state change]. +// ---------------------------------------------------------------------------- + +// The peer may signal more than one version, and may change bandwidth mode. +bool protocol_version_70014::handle_receive_send_compact(const code& ec, + const send_compact::cptr& message) NOEXCEPT +{ + BC_ASSERT_MSG(stranded(), "protocol_version_70014"); + + if (stopped(ec)) + return false; + + if (message->compact_version == send_compact::compact_version_2) + set_compact_blocks(message->high_bandwidth); + + return true; +} + } // namespace network } // namespace libbitcoin diff --git a/src/protocols/protocol_version_70016.cpp b/src/protocols/protocol_version_70016.cpp index 565083edc..48725bba7 100644 --- a/src/protocols/protocol_version_70016.cpp +++ b/src/protocols/protocol_version_70016.cpp @@ -51,8 +51,7 @@ protocol_version_70016::protocol_version_70016(const session::ptr& session, const channel::ptr& channel, bool relay, bool reject) NOEXCEPT - : protocol_version_70014(session, channel, relay), - reject_(reject), + : protocol_version_70014(session, channel, relay, reject), tracker(session->log) { } @@ -70,14 +69,7 @@ void protocol_version_70016::shake(result_handler&& handle_event) NOEXCEPT SUBSCRIBE_CHANNEL(send_address_v2, handle_receive_send_address_v2, _1, _2); SUBSCRIBE_CHANNEL(witness_tx_id_relay, handle_receive_witness_tx_id_relay, _1, _2); - // Protocol versions are cumulative, but reject is optional. - if (reject_) - { - protocol_version_70002::shake(std::move(handle_event)); - return; - } - - protocol_version_70001::shake(std::move(handle_event)); + protocol_version_70014::shake(std::move(handle_event)); } // Outgoing [signal address v2 (bip155)]. diff --git a/test/channels/channel_peer.cpp b/test/channels/channel_peer.cpp index 495bfbeea..49fefc5bc 100644 --- a/test/channels/channel_peer.cpp +++ b/test/channels/channel_peer.cpp @@ -106,6 +106,34 @@ BOOST_AUTO_TEST_CASE(channel_peer__properties__default__expected) channel_ptr->stop(error::invalid_magic); } +BOOST_AUTO_TEST_CASE(channel_peer__set_compact_blocks__high_bandwidth__expected) +{ + const logger log{}; + threadpool pool(1); + asio::strand strand(pool.service().get_executor()); + const settings set(bc::system::chain::selection::mainnet); + network::socket::parameters params + { + .maximum_request = 42, + .maximum_buffer = settings::tcp_server{ "test" }.maximum_buffer + }; + auto socket_ptr = std::make_shared(log, pool.service(), std::move(params)); + auto channel_ptr = std::make_shared(log, socket_ptr, 42, set, options); + + BOOST_REQUIRE(!channel_ptr->accepts_compact_blocks()); + BOOST_REQUIRE(!channel_ptr->wants_compact_blocks()); + + channel_ptr->set_compact_blocks(true); + BOOST_REQUIRE(channel_ptr->accepts_compact_blocks()); + BOOST_REQUIRE(channel_ptr->wants_compact_blocks()); + + channel_ptr->set_compact_blocks(false); + BOOST_REQUIRE(channel_ptr->accepts_compact_blocks()); + BOOST_REQUIRE(!channel_ptr->wants_compact_blocks()); + + channel_ptr->stop(error::invalid_magic); +} + BOOST_AUTO_TEST_CASE(channel_peer__set_wants_address_v2__always__latched) { const logger log{};