5#include <chainparams.h>
26void initialize_p2p_transport_serialization()
30 std::sort(g_all_messages.begin(), g_all_messages.end());
35FUZZ_TARGET(p2p_transport_serialization, .
init = initialize_p2p_transport_serialization)
43 auto checksum_assist = fuzzed_data_provider.
ConsumeBool();
44 auto magic_bytes_assist = fuzzed_data_provider.ConsumeBool();
45 std::vector<uint8_t> mutable_msg_bytes;
48 if (magic_bytes_assist) {
51 mutable_msg_bytes.push_back(msg_start[i]);
56 if (checksum_assist) {
60 auto header_random_bytes = fuzzed_data_provider.ConsumeBytes<uint8_t>(header_bytes_remaining);
61 mutable_msg_bytes.insert(mutable_msg_bytes.end(), header_random_bytes.begin(), header_random_bytes.end());
62 auto payload_bytes = fuzzed_data_provider.ConsumeRemainingBytes<uint8_t>();
66 unsigned char hsh[32];
67 hasher.
Write(payload_bytes);
70 mutable_msg_bytes.push_back(hsh[i]);
74 mutable_msg_bytes.insert(mutable_msg_bytes.end(), payload_bytes.begin(), payload_bytes.end());
76 while (msg_bytes.size() > 0) {
77 if (!recv_transport.ReceivedBytes(msg_bytes)) {
80 if (recv_transport.ReceivedMessageComplete()) {
81 const std::chrono::microseconds m_time{std::numeric_limits<int64_t>::max()};
82 bool reject_message{
false};
83 CNetMessage msg = recv_transport.GetReceivedMessage(m_time, reject_message);
85 assert(
msg.m_raw_message_size <= mutable_msg_bytes.size());
89 std::vector<unsigned char> header;
91 bool queued = send_transport.SetMessageToSend(msg2);
93 std::optional<bool> known_more;
95 const auto& [to_send, more, _msg_type] = send_transport.GetBytesToSend(
false);
96 if (known_more)
assert(!to_send.empty() == *known_more);
97 if (to_send.empty())
break;
98 send_transport.MarkBytesSent(to_send.size());
107template<RandomNumberGenerator R>
116 const std::array<Transport*, 2> transports = {&initiator, &responder};
119 std::array<std::vector<uint8_t>, 2> in_flight;
122 std::array<std::deque<CSerializedNetMsg>, 2> expected;
125 std::array<std::vector<uint8_t>, 2> to_send;
129 std::array<std::optional<bool>, 2> last_more, last_more_next;
133 std::array<std::optional<bool>, 2> expect_more, expect_more_next;
136 auto msg_type_fn = [&]() {
146 if (c < ' ' || c > 0x7E)
break;
152 return g_all_messages[v % g_all_messages.size()];
157 auto make_msg_fn = [&](
bool first) {
161 msg.m_type =
"version";
163 msg.m_type = msg_type_fn();
168 msg.data = rng.randbytes(size);
174 std::array<CSerializedNetMsg, 2> next_msg = {
184 const auto& [bytes, more_nonext, msg_type] = transports[side]->GetBytesToSend(
false);
185 const auto& [bytes_next, more_next, msg_type_next] = transports[side]->GetBytesToSend(
true);
187 if (expect_more[side].has_value())
assert(!bytes.empty() == *expect_more[side]);
189 assert(std::ranges::equal(bytes, bytes_next));
190 assert(msg_type == msg_type_next);
191 if (more_nonext)
assert(more_next);
193 assert(to_send[side].size() <= bytes.size());
194 assert(std::ranges::equal(to_send[side],
Span{bytes}.
first(to_send[side].size())));
195 to_send[side].resize(bytes.size());
196 std::copy(bytes.begin(), bytes.end(), to_send[side].begin());
198 last_more[side] = {more_nonext};
199 last_more_next[side] = {more_next};
201 return {bytes, more_nonext, msg_type};
205 auto new_msg_fn = [&](
int side) {
207 if (expected[side].size() >= 16)
return;
210 bool queued = transports[side]->SetMessageToSend(
msg);
212 expect_more[side] = expect_more_next[side];
213 expect_more_next[side] = std::nullopt;
215 bytes_to_send_fn(side);
218 expected[side].emplace_back(std::move(next_msg[side]));
220 next_msg[side] = make_msg_fn(
false);
225 auto send_fn = [&](
int side,
bool everything =
false) {
226 const auto& [bytes, more, msg_type] = bytes_to_send_fn(side);
228 if (bytes.empty())
return false;
230 if (send_now == 0)
return false;
232 in_flight[side].insert(in_flight[side].end(), bytes.begin(), bytes.begin() + send_now);
233 transports[side]->MarkBytesSent(send_now);
235 if (send_now == bytes.size()) {
236 expect_more[side] = last_more[side];
237 expect_more_next[side] = last_more_next[side];
240 assert(to_send[side].size() >= send_now);
241 to_send[side].erase(to_send[side].begin(), to_send[side].begin() + send_now);
243 bytes_to_send_fn(side);
249 auto recv_fn = [&](
int side,
bool everything =
false) {
251 if (in_flight[side].empty())
return false;
253 size_t to_recv_len = in_flight[side].size();
257 while (!to_recv.empty()) {
258 size_t old_len = to_recv.size();
259 bool ret = transports[!side]->ReceivedBytes(to_recv);
265 if (expect_more[!side] ==
false) expect_more[!side] = std::nullopt;
266 if (expect_more_next[!side] ==
false) expect_more_next[!side] = std::nullopt;
268 bytes_to_send_fn(!side);
269 bool progress = to_recv.size() < old_len;
270 if (transports[!side]->ReceivedMessageComplete()) {
272 auto received = transports[!side]->GetReceivedMessage({}, reject);
276 assert(!expected[side].empty());
278 assert(received.m_message_size == received.m_recv.size());
280 assert(received.m_type == expected[side].front().m_type);
283 expected[side].pop_front();
291 in_flight[side].erase(in_flight[side].begin(), in_flight[side].begin() + to_recv_len);
293 return to_recv_len > 0;
300 [&] { new_msg_fn(0); },
301 [&] { new_msg_fn(1); },
315 if (send_fn(0,
true)) any =
true;
316 if (send_fn(1,
true)) any =
true;
317 if (recv_fn(0,
true)) any =
true;
318 if (recv_fn(1,
true)) any =
true;
323 assert(in_flight[0].empty());
324 assert(in_flight[1].empty());
327 assert(expected[0].empty());
328 assert(expected[1].empty());
334std::unique_ptr<Transport> MakeV1Transport(
NodeId nodeid)
noexcept
336 return std::make_unique<V1Transport>(nodeid);
339template<RandomNumberGenerator RNG>
344 if (!key.IsValid())
return {};
347 std::vector<uint8_t> garb;
348 if (garb_len <= 64) {
351 garb.resize(garb_len);
355 garb = rng.randbytes(garb_len);
367 .
Write(garb.data(), garb.size())
370 return std::make_unique<V2Transport>(nodeid, initiator, key, ent, std::move(garb));
375FUZZ_TARGET(p2p_transport_bidirectional, .
init = initialize_p2p_transport_serialization)
380 auto t1 = MakeV1Transport(
NodeId{0});
381 auto t2 = MakeV1Transport(
NodeId{1});
382 if (!t1 || !t2)
return;
383 SimulationTest(*t1, *t2, rng, provider);
386FUZZ_TARGET(p2p_transport_bidirectional_v2, .
init = initialize_p2p_transport_serialization)
391 auto t1 = MakeV2Transport(
NodeId{0},
true, rng, provider);
392 auto t2 = MakeV2Transport(
NodeId{1},
false, rng, provider);
393 if (!t1 || !t2)
return;
394 SimulationTest(*t1, *t2, rng, provider);
397FUZZ_TARGET(p2p_transport_bidirectional_v1v2, .
init = initialize_p2p_transport_serialization)
402 auto t1 = MakeV1Transport(
NodeId{0});
403 auto t2 = MakeV2Transport(
NodeId{1},
false, rng, provider);
404 if (!t1 || !t2)
return;
405 SimulationTest(*t1, *t2, rng, provider);
void SelectParams(const ChainType chain)
Sets the params returned by Params() to those for the given chain type.
const CChainParams & Params()
Return the currently selected parameters.
const MessageStartChars & MessageStart() const
A hasher class for Bitcoin's 256-bit hash (double SHA-256).
void Finalize(Span< unsigned char > output)
CHash256 & Write(Span< const unsigned char > input)
Transport protocol agnostic message container.
A hasher class for SHA-256.
void Finalize(unsigned char hash[OUTPUT_SIZE])
CSHA256 & Write(const unsigned char *data, size_t len)
RAII class initializing and deinitializing global state for elliptic curve support.
std::vector< T > ConsumeBytes(size_t num_bytes)
T ConsumeIntegralInRange(T min, T max)
A Span is an object that can refer to a contiguous sequence of objects.
CONSTEXPR_IF_NOT_DEBUG Span< C > first(std::size_t count) const noexcept
The Transport converts one connection's sent messages to wire bytes, and received bytes back.
std::tuple< Span< const uint8_t >, bool, const std::string & > BytesToSend
Return type for GetBytesToSend, consisting of:
static constexpr uint32_t MAX_GARBAGE_LEN
#define LIMITED_WHILE(condition, limit)
Can be used to limit a theoretically unbounded loop.
CSerializedNetMsg Make(std::string msg_type, Args &&... args)
FUZZ_TARGET(p2p_transport_serialization,.init=initialize_p2p_transport_serialization)
const std::array ALL_NET_MESSAGE_TYPES
All known message types (see above).
Span< const std::byte > MakeByteSpan(V &&v) noexcept
unsigned char * UCharCast(char *c)
CKey ConsumePrivateKey(FuzzedDataProvider &fuzzed_data_provider, std::optional< bool > compressed) noexcept
size_t CallOneOf(FuzzedDataProvider &fuzzed_data_provider, Callables... callables)
static TxMempoolInfo GetInfo(CTxMemPool::indexed_transaction_set::const_iterator it)