From 921c7f301f4e8d9c320cb1a41d5a03d1b7ec5f93 Mon Sep 17 00:00:00 2001 From: josie Date: Wed, 3 Jun 2026 13:14:15 +0200 Subject: [PATCH] relay broadcast transactions to peers subscribe the outbound transaction protocol to locally broadcast transaction messages and announce them through the existing inv path. the handler preserves the existing was_announced/null-hash behavior and avoids echoing a transaction back to the channel that originated the broadcast. added to support broadcast from sparrow wallet; discovered while testing the silent payments index PRs. --- .../protocol_transaction_out_106.hpp | 6 ++++ .../protocol_transaction_out_106.cpp | 28 +++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/include/bitcoin/node/protocols/protocol_transaction_out_106.hpp b/include/bitcoin/node/protocols/protocol_transaction_out_106.hpp index 16113766..c9c25fba 100644 --- a/include/bitcoin/node/protocols/protocol_transaction_out_106.hpp +++ b/include/bitcoin/node/protocols/protocol_transaction_out_106.hpp @@ -54,11 +54,17 @@ class BCN_API protocol_transaction_out_106 /// Process tx announcement. virtual bool do_announce(transaction_t link) NOEXCEPT; + virtual bool handle_broadcast_transaction(const code& ec, + const network::messages::peer::transaction::cptr& message, + uint64_t sender) NOEXCEPT; + virtual bool handle_receive_get_data(const code& ec, const network::messages::peer::get_data::cptr& message) NOEXCEPT; virtual void send_transaction(const code& ec, size_t index, const network::messages::peer::get_data::cptr& message) NOEXCEPT; + virtual bool announce(const system::hash_digest& hash) NOEXCEPT; + private: // These are thread safe. const bool node_witness_; diff --git a/src/protocols/protocol_transaction_out_106.cpp b/src/protocols/protocol_transaction_out_106.cpp index 6ca35a72..67733f7a 100644 --- a/src/protocols/protocol_transaction_out_106.cpp +++ b/src/protocols/protocol_transaction_out_106.cpp @@ -45,6 +45,7 @@ void protocol_transaction_out_106::start() NOEXCEPT // Events subscription is asynchronous, events may be missed. subscribe_chase(BIND(handle_chase, _1, _2, _3)); + SUBSCRIBE_BROADCAST(transaction, handle_broadcast_transaction, _1, _2, _3); SUBSCRIBE_CHANNEL(get_data, handle_receive_get_data, _1, _2); protocol_peer::start(); } @@ -54,6 +55,7 @@ void protocol_transaction_out_106::stopping(const code& ec) NOEXCEPT // Unsubscriber race is ok. BC_ASSERT(stranded()); unsubscribe_chase(); + UNSUBSCRIBE_BROADCAST(); protocol_peer::stopping(ec); } @@ -98,8 +100,30 @@ bool protocol_transaction_out_106::do_announce(transaction_t link) NOEXCEPT if (stopped()) return false; - // Don't announce to peer that announced to us. - const auto hash = query.get_tx_key(link); + return announce(query.get_tx_key(link)); +} + +bool protocol_transaction_out_106::handle_broadcast_transaction(const code& ec, + const transaction::cptr& message, uint64_t sender) NOEXCEPT +{ + BC_ASSERT(stranded()); + + if (stopped(ec)) + return false; + + if (sender == identifier()) + return true; + + if (!message || !message->transaction_ptr) + return true; + + return announce(message->transaction_ptr->hash(false)); +} + +bool protocol_transaction_out_106::announce(const hash_digest& hash) NOEXCEPT +{ + BC_ASSERT(stranded()); + if (was_announced(hash)) return true;