Bitcoin Core 31.99.0
P2P Digital Currency
p2p_private_broadcast.cpp
Go to the documentation of this file.
1// Copyright (c) The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include <banman.h>
6#include <net.h>
7#include <net_processing.h>
8#include <protocol.h>
9#include <sync.h>
11#include <test/fuzz/fuzz.h>
12#include <test/fuzz/util.h>
13#include <test/fuzz/util/net.h>
14#include <test/util/net.h>
16#include <test/util/time.h>
18#include <util/time.h>
19#include <validationinterface.h>
20
21#include <array>
22#include <ios>
23#include <memory>
24#include <vector>
25
26namespace {
28
29void initialize()
30{
31 static const auto testing_setup = MakeNoLogFileContext<TestingSetup>(
32 /*chain_type=*/ChainType::REGTEST);
33 g_setup = testing_setup.get();
34}
35
36// Inbound message types with private broadcast specific handling.
37// Used as the guided path in the CallOneOf() below.
38constexpr std::array INBOUND_MSG_TYPES{
43};
44} // namespace
45
46FUZZ_TARGET(p2p_private_broadcast, .init = ::initialize)
47{
49 FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
50
51 auto& node{g_setup->m_node};
52 auto& connman{static_cast<ConnmanTestMsg&>(*node.connman)};
53 connman.Reset();
54 auto& chainman{static_cast<TestChainstateManager&>(*node.chainman)};
55
56 FakeNodeClock clock_ctx{1610000000s};
57 FakeSteadyClock steady_clock;
58 chainman.ResetIbd();
59 // Sometimes leave IBD: incoming TX processing (the broadcast-abort path)
60 // returns early during IBD.
61 if (fuzzed_data_provider.ConsumeBool()) chainman.JumpOutOfIbd();
62
63 // Reset, so that dangling pointers can be detected by sanitizers.
64 node.banman.reset();
65 node.addrman.reset();
66 node.peerman.reset();
67 node.addrman = std::make_unique<AddrMan>(
68 *node.netgroupman, /*deterministic=*/true, /*consistency_check_ratio=*/0);
69 node.peerman = PeerManager::make(connman, *node.addrman,
70 /*banman=*/nullptr, chainman,
71 *node.mempool, *node.warnings,
73 .reconcile_txs = true,
74 .deterministic_rng = true,
75 });
76 connman.SetMsgProc(node.peerman.get());
77 connman.SetAddrman(*node.addrman);
78
79 // Seed with 0-3 transactions to test multiple pending broadcasts; zero exercises
80 // the connected-in-vain disconnect in PushPrivateBroadcastTx().
81 const int num_txs{fuzzed_data_provider.ConsumeIntegralInRange(0, 3)};
82 std::vector<CTransactionRef> seeded_txs;
83 for (int i = 0; i < num_txs; ++i) {
84 auto tx{MakeTransactionRef(ConsumeTransaction(fuzzed_data_provider, /*prevout_txids=*/std::nullopt))};
85 (void)node.peerman->InitiateTxBroadcastPrivate(tx);
86 seeded_txs.push_back(tx);
87 }
88
90
91 static NodeId node_id{0};
92 // Create at least one PRIVATE_BROADCAST peer, optionally add others of random types.
93 std::vector<CNode*> peers;
94
95 CNode* pb_node = new CNode(
96 /*id=*/node_id++,
97 /*sock=*/std::make_shared<FuzzedSock>(fuzzed_data_provider, steady_clock),
99 /*nKeyedNetGroupIn=*/0,
100 /*nLocalHostNonceIn=*/0,
101 /*addrBindIn=*/CService{},
102 /*addrNameIn=*/"",
103 /*conn_type_in=*/ConnectionType::PRIVATE_BROADCAST,
104 /*inbound_onion=*/false,
105 /*network_key=*/0);
106
107 peers.push_back(pb_node);
108 connman.AddTestNode(*pb_node);
109 // Capture outbound messages to verify if well formed (and to learn the PING
110 // nonce), before SocketSendData drains vSendMsg.
111 connman.SetCaptureMessages(true);
112 const auto CaptureMessageOrig = CaptureMessage;
113 const CAddress pb_addr = pb_node->addr;
114 std::optional<uint64_t> pb_ping_nonce;
115 CaptureMessage = [&](const CAddress& addr, const std::string& msg_type,
116 std::span<const unsigned char> data, bool is_incoming) {
117 if (is_incoming || addr != pb_addr) return;
118 if (msg_type == NetMsgType::PING) {
119 Assert(data.size() == sizeof(uint64_t));
120 uint64_t nonce;
122 pb_ping_nonce = nonce;
123 return;
124 }
125 if (msg_type == NetMsgType::VERSION) {
126 SpanReader ds{data};
127 int32_t version;
128 uint64_t my_services, your_services, my_services_dup, nonce;
129 int64_t my_time;
130 CService your_addr, my_addr;
131 std::string user_agent;
132 int32_t height;
133 bool relay;
134 ds >> version >> my_services >> my_time >>
135 your_services >> CNetAddr::V1(your_addr) >>
136 my_services_dup >> CNetAddr::V1(my_addr) >>
137 nonce >> user_agent >> height >> relay;
138 Assert(version == WTXID_RELAY_VERSION);
139 Assert(my_services == NODE_NONE && my_services_dup == NODE_NONE);
140 Assert(my_time == 0);
141 Assert(your_services == NODE_NONE);
142 Assert(your_addr == CService{});
143 Assert(user_agent == "/pynode:0.0.1/");
144 Assert(height == 0);
145 Assert(!relay);
146 return;
147 }
148 if (msg_type != NetMsgType::INV) return;
149 SpanReader ds{data};
150 std::vector<CInv> invs;
151 ds >> invs;
152 Assert(invs.size() == 1);
153 Assert(invs[0].IsMsgTx());
154 };
155
156 // Complete handshake so PushPrivateBroadcastTx runs.
157 connman.Handshake(
158 /*node=*/*pb_node,
159 /*successfully_connected=*/true,
160 /*remote_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS),
161 /*local_services=*/NODE_NONE,
162 /*version=*/PROTOCOL_VERSION,
163 /*relay_txs=*/true);
164
165 // Optionally add extra peers of random connection types.
166 const int extra_peers{fuzzed_data_provider.ConsumeIntegralInRange(0, 2)};
167 for (int i = 0; i < extra_peers; ++i) {
168 auto extra_peer{ConsumeNodeAsUniquePtr(fuzzed_data_provider, steady_clock, node_id++)};
169 // An address collision would match the capture hook's filter and fail
170 // its assertions on this peer's (legitimate) other-typed messages.
171 if (extra_peer->addr == pb_addr) continue;
172 peers.push_back(extra_peer.release());
173 connman.AddTestNode(*peers.back());
174 node.peerman->InitializeNode(
175 *peers.back(),
176 static_cast<ServiceFlags>(fuzzed_data_provider.ConsumeIntegral<uint64_t>()));
177 }
178
180 {
181 // Pick any random peer to test interleaved message handling.
182 CNode& p2p_node = *PickValue(fuzzed_data_provider, peers);
183 if (p2p_node.fDisconnect) continue;
184
185 clock_ctx += ConsumeDuration<std::chrono::seconds>(fuzzed_data_provider, 0s, 600s);
186
187 std::optional<CSerializedNetMsg> net_msg;
188 CallOneOf(
190 [&] {
191 net_msg.emplace();
192 net_msg->m_type = std::string{PickValue(fuzzed_data_provider, INBOUND_MSG_TYPES)};
193 },
194 [&] {
195 net_msg.emplace();
197 },
198 [&] {
199 (void)node.peerman->InitiateTxBroadcastPrivate(
200 MakeTransactionRef(ConsumeTransaction(fuzzed_data_provider, /*prevout_txids=*/std::nullopt)));
201 },
202 [&] {
203 // Construct a valid GETDATA for a seeded tx to exercise the TX send path.
204 if (p2p_node.IsPrivateBroadcastConn() &&
205 p2p_node.fSuccessfullyConnected &&
206 !seeded_txs.empty()) {
207 const auto& tx{PickValue(fuzzed_data_provider, seeded_txs)};
208 net_msg.emplace(NetMsg::Make(
210 std::vector<CInv>{{MSG_TX, tx->GetHash().ToUint256()}}));
211 }
212 },
213 [&] {
214 // Confirm reception of the pushed TX with a PONG matching the captured PING nonce.
215 if (&p2p_node == pb_node && pb_ping_nonce) {
216 net_msg.emplace(NetMsg::Make(NetMsgType::PONG, *pb_ping_nonce));
217 }
218 },
219 [&] {
220 // Echo a seeded tx back from a non-private-broadcast peer to exercise
221 // the received-from-network broadcast-abort path.
222 if (!p2p_node.IsPrivateBroadcastConn() &&
223 p2p_node.fSuccessfullyConnected &&
224 !seeded_txs.empty()) {
225 const auto& tx{PickValue(fuzzed_data_provider, seeded_txs)};
226 net_msg.emplace(NetMsg::Make(NetMsgType::TX, TX_WITH_WITNESS(*tx)));
227 }
228 });
229
230 if (net_msg) {
231 if (net_msg->data.empty()) {
233 }
234 connman.FlushSendBuffer(p2p_node);
235 (void)connman.ReceiveMsgFrom(p2p_node, std::move(*net_msg));
236
237 bool more_work{true};
238 while (more_work) {
239 p2p_node.fPauseSend = false;
240 try {
241 more_work = connman.ProcessMessagesOnce(p2p_node);
242 } catch (const std::ios_base::failure&) {
243 }
244 node.peerman->SendMessages(p2p_node);
245 }
246 }
247 }
248
249 CaptureMessage = CaptureMessageOrig;
250 connman.SetCaptureMessages(false);
251
252 node.connman->StopNodes();
253}
const TestingSetup * g_setup
#define Assert(val)
Identity function.
Definition: check.h:116
A CService with information about it as peer.
Definition: protocol.h:387
static constexpr size_t MESSAGE_TYPE_SIZE
Definition: protocol.h:31
static constexpr SerParams V1
Definition: netaddress.h:231
Information about a peer.
Definition: net.h:681
std::atomic_bool fSuccessfullyConnected
fSuccessfullyConnected is set to true on receiving VERACK from the peer.
Definition: net.h:740
const CAddress addr
Definition: net.h:720
std::atomic_bool fPauseSend
Definition: net.h:749
bool IsPrivateBroadcastConn() const
Definition: net.h:829
std::atomic_bool fDisconnect
Definition: net.h:743
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:530
Helper to initialize the global NodeClock, let a duration elapse, and reset it after use in a test.
Definition: time.h:54
Helper to initialize the global MockableSteadyClock, let a duration elapse, and reset it after use in...
Definition: time.h:29
std::string ConsumeRandomLengthString(size_t max_length)
T ConsumeIntegralInRange(T min, T max)
static Mutex g_msgproc_mutex
Mutex for anything that is only accessed via the msg processing thread.
Definition: net.h:1042
static std::unique_ptr< PeerManager > make(CConnman &connman, AddrMan &addrman, BanMan *banman, ChainstateManager &chainman, CTxMemPool &pool, node::Warnings &warnings, Options opts)
Minimal stream for reading from an existing byte array by std::span.
Definition: streams.h:83
static const PrecomputedData data
Precomputed COutPoint and CCoins values.
LIMITED_WHILE(provider.remaining_bytes(), 10000)
@ PRIVATE_BROADCAST
Private broadcast connections are short-lived and only opened to privacy networks (Tor,...
static void initialize()
Definition: fuzz.cpp:93
unsigned int nonce
CSerializedNetMsg Make(std::string msg_type, Args &&... args)
constexpr const char * PONG
The pong message replies to a ping message, proving to the pinging node that the ponging node is stil...
Definition: protocol.h:150
constexpr const char * PING
The ping message is sent periodically to help confirm that the receiving peer is still connected.
Definition: protocol.h:144
constexpr const char * VERACK
The verack message acknowledges a previously-received version message, informing the connecting node ...
Definition: protocol.h:70
constexpr const char * GETDATA
The getdata message requests one or more data objects from another node.
Definition: protocol.h:96
constexpr const char * INV
The inv message (inventory message) transmits one or more inventories of objects known to the transmi...
Definition: protocol.h:92
constexpr const char * TX
The tx message transmits a single transaction.
Definition: protocol.h:117
constexpr const char * VERSION
The version message provides information about the transmitting node to the receiving node at the beg...
Definition: protocol.h:65
Definition: basic.cpp:8
Definition: messages.h:21
std::function< void(const CAddress &addr, const std::string &msg_type, std::span< const unsigned char > data, bool is_incoming)> CaptureMessage
Defaults to CaptureMessageToFile(), but can be overridden by unit tests.
Definition: net.cpp:4310
static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH
Maximum length of incoming protocol messages (no message over 4 MB is currently acceptable).
Definition: net.h:65
int64_t NodeId
Definition: net.h:103
FUZZ_TARGET(p2p_private_broadcast,.init=::initialize)
static constexpr TransactionSerParams TX_WITH_WITNESS
Definition: transaction.h:180
static CTransactionRef MakeTransactionRef(Tx &&txIn)
Definition: transaction.h:404
@ MSG_TX
Definition: protocol.h:499
ServiceFlags
nServices flags
Definition: protocol.h:321
@ NODE_NONE
Definition: protocol.h:324
@ NODE_WITNESS
Definition: protocol.h:332
@ NODE_NETWORK
Definition: protocol.h:327
static const int WTXID_RELAY_VERSION
"wtxidrelay" message type for wtxid-based relay starts with this version
static const int PROTOCOL_VERSION
network protocol versioning
node::NodeContext m_node
Definition: setup_common.h:60
void Reset()
Reset the internal state.
Definition: net.cpp:83
Testing setup that configures a complete environment.
Definition: setup_common.h:115
#define LOCK(cs)
Definition: sync.h:268
SeedRandomStateForTest(SeedRand::ZEROS)
CAddress ConsumeAddress(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: net.cpp:88
std::unique_ptr< CNode > ConsumeNodeAsUniquePtr(FuzzedDataProvider &fdp, FakeSteadyClock &clock, const std::optional< NodeId > &node_id_in=std::nullopt)
Definition: net.h:310
CMutableTransaction ConsumeTransaction(FuzzedDataProvider &fuzzed_data_provider, const std::optional< std::vector< Txid > > &prevout_txids, const int max_num_in, const int max_num_out) noexcept
Definition: util.cpp:42
auto & PickValue(FuzzedDataProvider &fuzzed_data_provider, Collection &col)
Definition: util.h:57
size_t CallOneOf(FuzzedDataProvider &fuzzed_data_provider, Callables... callables)
Definition: util.h:37
std::vector< B > ConsumeRandomLengthByteVector(FuzzedDataProvider &fuzzed_data_provider, const std::optional< size_t > &max_length=std::nullopt) noexcept
Definition: util.h:63
@ ZEROS
Seed with a compile time constant of zeros.
FuzzedDataProvider & fuzzed_data_provider
Definition: fees.cpp:39