Skip to content

Commit 679ce3a

Browse files
committed
net_processing: store transactions for private broadcast in PeerManager
Extend `PeerManager` with a transaction storage and a new method `InitiateTxBroadcastPrivate()` which: * adds a transaction to that storage and * calls `CConnman::PrivateBroadcast::NumToOpenAdd()` to open dedicated privacy connections that will pick an entry from the transaction storage and broadcast it.
1 parent a3faa6f commit 679ce3a

File tree

6 files changed

+104
-0
lines changed

6 files changed

+104
-0
lines changed

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ add_library(bitcoin_node STATIC EXCLUDE_FROM_ALL
244244
policy/rbf.cpp
245245
policy/settings.cpp
246246
policy/truc_policy.cpp
247+
private_broadcast.cpp
247248
rest.cpp
248249
rpc/blockchain.cpp
249250
rpc/external_signer.cpp

src/net_processing.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include <policy/policy.h>
4545
#include <primitives/block.h>
4646
#include <primitives/transaction.h>
47+
#include <private_broadcast.h>
4748
#include <protocol.h>
4849
#include <random.h>
4950
#include <scheduler.h>
@@ -196,6 +197,8 @@ static constexpr double MAX_ADDR_RATE_PER_SECOND{0.1};
196197
static constexpr size_t MAX_ADDR_PROCESSING_TOKEN_BUCKET{MAX_ADDR_TO_SEND};
197198
/** The compactblocks version we support. See BIP 152. */
198199
static constexpr uint64_t CMPCTBLOCKS_VERSION{2};
200+
/** For private broadcast, send a transaction to this many peers. */
201+
static constexpr size_t NUM_PRIVATE_BROADCAST_PER_TX{3};
199202

200203
// Internal stuff
201204
namespace {
@@ -538,6 +541,7 @@ class PeerManagerImpl final : public PeerManager
538541
PeerManagerInfo GetInfo() const override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
539542
void SendPings() override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
540543
void InitiateTxBroadcastToAll(const Txid& txid, const Wtxid& wtxid) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
544+
void InitiateTxBroadcastPrivate(const CTransactionRef& tx) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
541545
void SetBestBlock(int height, std::chrono::seconds time) override
542546
{
543547
m_best_height = height;
@@ -1070,6 +1074,9 @@ class PeerManagerImpl final : public PeerManager
10701074
void PushAddress(Peer& peer, const CAddress& addr) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex);
10711075

10721076
void LogBlockHeader(const CBlockIndex& index, const CNode& peer, bool via_compact_block);
1077+
1078+
/// The transactions to be broadcast privately.
1079+
PrivateBroadcast m_tx_for_private_broadcast;
10731080
};
10741081

10751082
const CNodeState* PeerManagerImpl::State(NodeId pnode) const
@@ -2147,6 +2154,17 @@ void PeerManagerImpl::InitiateTxBroadcastToAll(const Txid& txid, const Wtxid& wt
21472154
}
21482155
}
21492156

2157+
void PeerManagerImpl::InitiateTxBroadcastPrivate(const CTransactionRef& tx)
2158+
{
2159+
const auto txstr{strprintf("txid=%s, wtxid=%s", tx->GetHash().ToString(), tx->GetWitnessHash().ToString())};
2160+
if (m_tx_for_private_broadcast.Add(tx)) {
2161+
LogDebug(BCLog::PRIVBROADCAST, "Requesting %d new connections due to %s", NUM_PRIVATE_BROADCAST_PER_TX, txstr);
2162+
m_connman.m_private_broadcast.NumToOpenAdd(NUM_PRIVATE_BROADCAST_PER_TX);
2163+
} else {
2164+
LogDebug(BCLog::PRIVBROADCAST, "Ignoring unnecessary request to schedule an already scheduled transaction: %s", txstr);
2165+
}
2166+
}
2167+
21502168
void PeerManagerImpl::RelayAddress(NodeId originator,
21512169
const CAddress& addr,
21522170
bool fReachable)

src/net_processing.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,12 @@ class PeerManager : public CValidationInterface, public NetEventsInterface
124124
*/
125125
virtual void InitiateTxBroadcastToAll(const Txid& txid, const Wtxid& wtxid) = 0;
126126

127+
/**
128+
* Initiate a private transaction broadcast. This is done
129+
* asynchronously via short-lived connections to peers on privacy networks.
130+
*/
131+
virtual void InitiateTxBroadcastPrivate(const CTransactionRef& tx) = 0;
132+
127133
/** Send ping message to all peers */
128134
virtual void SendPings() = 0;
129135

src/node/transaction.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ TransactionError BroadcastTransaction(NodeContext& node,
139139
node.peerman->InitiateTxBroadcastToAll(txid, wtxid);
140140
break;
141141
case TxBroadcast::NO_MEMPOOL_PRIVATE_BROADCAST:
142+
node.peerman->InitiateTxBroadcastPrivate(tx);
142143
break;
143144
}
144145

src/private_broadcast.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) 2023-present The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or https://opensource.org/license/mit/.
4+
5+
#include <private_broadcast.h>
6+
7+
bool PrivateBroadcast::Add(const CTransactionRef& tx)
8+
EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
9+
{
10+
LOCK(m_mutex);
11+
const bool inserted{m_transactions.try_emplace(tx).second};
12+
return inserted;
13+
}

src/private_broadcast.h

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright (c) 2023-present The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or https://opensource.org/license/mit/.
4+
5+
#ifndef BITCOIN_PRIVATE_BROADCAST_H
6+
#define BITCOIN_PRIVATE_BROADCAST_H
7+
8+
#include <net.h>
9+
#include <primitives/transaction.h>
10+
#include <sync.h>
11+
#include <threadsafety.h>
12+
#include <util/time.h>
13+
14+
#include <optional>
15+
#include <unordered_map>
16+
#include <vector>
17+
18+
/**
19+
* Store a list of transactions to be broadcast privately. Supports the following operations:
20+
* - Add a new transaction
21+
*/
22+
class PrivateBroadcast
23+
{
24+
public:
25+
/**
26+
* Add a transaction to the storage.
27+
* @param[in] tx The transaction to add.
28+
* @retval true The transaction was added.
29+
* @retval false The transaction was already present.
30+
*/
31+
bool Add(const CTransactionRef& tx)
32+
EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
33+
34+
private:
35+
/// Status of a transaction sent to a given node.
36+
struct SendStatus {
37+
const NodeId nodeid; /// Node to which the transaction will be sent (or was sent).
38+
const NodeClock::time_point picked; ///< When was the transaction picked for sending to the node.
39+
std::optional<NodeClock::time_point> confirmed; ///< When was the transaction reception confirmed by the node (by PONG).
40+
41+
SendStatus(const NodeId& nodeid, const NodeClock::time_point& picked) : nodeid{nodeid}, picked{picked} {}
42+
};
43+
44+
// No need for salted hasher because we are going to store just a bunch of locally originating transactions.
45+
46+
struct CTransactionRefHash {
47+
size_t operator()(const CTransactionRef& tx) const
48+
{
49+
return static_cast<size_t>(tx->GetWitnessHash().ToUint256().GetUint64(0));
50+
}
51+
};
52+
53+
struct CTransactionRefComp {
54+
bool operator()(const CTransactionRef& a, const CTransactionRef& b) const
55+
{
56+
return a->GetWitnessHash() == b->GetWitnessHash(); // If wtxid equals, then txid also equals.
57+
}
58+
};
59+
60+
mutable Mutex m_mutex;
61+
std::unordered_map<CTransactionRef, std::vector<SendStatus>, CTransactionRefHash, CTransactionRefComp>
62+
m_transactions GUARDED_BY(m_mutex);
63+
};
64+
65+
#endif // BITCOIN_PRIVATE_BROADCAST_H

0 commit comments

Comments
 (0)