Line data Source code
1 : #include "fd_solfuzz_private.h"
2 : #include "fd_gossip_harness.h"
3 : #include "../../gossip/fd_gossip_message.h"
4 : #include "../../../ballet/txn/fd_compact_u16.h"
5 : #include "../../../disco/fd_disco_base.h"
6 : #include "generated/gossip.pb.h"
7 :
8 : /* alloc_bytes allocates a pb_bytes_array_t on the spad and copies
9 : src[0..len) into it. */
10 :
11 : static pb_bytes_array_t *
12 : alloc_bytes( fd_spad_t * spad,
13 : uchar const * src,
14 17433 : ulong len ) {
15 17433 : pb_bytes_array_t * arr = fd_spad_alloc( spad, alignof(pb_bytes_array_t), PB_BYTES_ARRAY_T_ALLOCSIZE( len ) );
16 17433 : arr->size = (pb_size_t)len;
17 17433 : if( FD_LIKELY( len ) ) memcpy( arr->bytes, src, len );
18 17433 : return arr;
19 17433 : }
20 :
21 : /* Re-parse helpers that walk raw wire bytes to extract fields the
22 : main deserializer does not retain (addrs, sockets, extensions,
23 : compressed slots). */
24 :
25 169 : #define FD_VARINT_U64_MAX_BYTES (10UL) /* ceil(64/7) */
26 :
27 : static inline int
28 : skip_varint_u16( uchar const ** p,
29 96 : ulong * sz ) {
30 96 : ulong n = fd_cu16_dec_sz( *p, *sz );
31 96 : if( FD_UNLIKELY( !n ) ) return 0;
32 96 : *p += n;
33 96 : *sz -= n;
34 96 : return 1;
35 96 : }
36 :
37 : static inline int
38 : read_varint_u16( ushort * dst,
39 : uchar const ** p,
40 92 : ulong * sz ) {
41 92 : ulong n = fd_cu16_dec_sz( *p, *sz );
42 92 : if( FD_UNLIKELY( !n ) ) return 0;
43 92 : *dst = fd_cu16_dec_fixed( *p, n );
44 92 : *p += n;
45 92 : *sz -= n;
46 92 : return 1;
47 92 : }
48 :
49 : static inline int
50 : skip_varint_u64( uchar const ** p,
51 24 : ulong * sz ) {
52 169 : for( ulong i=0UL; i<FD_VARINT_U64_MAX_BYTES; i++ ) {
53 169 : if( FD_UNLIKELY( !*sz ) ) return 0;
54 169 : uchar byte = **p;
55 169 : (*p)++; (*sz)--;
56 169 : if( FD_LIKELY( !(byte & 0x80) ) ) return 1;
57 169 : }
58 0 : return 0;
59 24 : }
60 :
61 836 : #define NEED(n) do { if( FD_UNLIKELY( sz < (n) ) ) return; } while(0)
62 265 : #define SKIP(n) do { NEED(n); p += (n); sz -= (n); } while(0)
63 :
64 : static void
65 : reparse_contact_info_extra( fd_spad_t * spad,
66 : uchar const * value_start,
67 : ulong value_len,
68 24 : fd_exec_test_gossip_contact_info_t * ci ) {
69 24 : uchar const * p = value_start;
70 24 : ulong sz = value_len;
71 :
72 24 : SKIP( 68UL ); /* signature(64) + tag(4) */
73 24 : SKIP( 32UL ); /* origin(32) */
74 24 : if( FD_UNLIKELY( !skip_varint_u64( &p, &sz ) ) ) return; /* wallclock */
75 24 : SKIP( 10UL ); /* outset(8) + shred_version(2) */
76 :
77 24 : if( FD_UNLIKELY( !skip_varint_u16( &p, &sz ) ) ) return; /* major */
78 24 : if( FD_UNLIKELY( !skip_varint_u16( &p, &sz ) ) ) return; /* minor */
79 24 : if( FD_UNLIKELY( !skip_varint_u16( &p, &sz ) ) ) return; /* patch */
80 24 : SKIP( 4UL ); /* commit (u32) */
81 24 : SKIP( 4UL ); /* feature_set (u32) */
82 24 : if( FD_UNLIKELY( !skip_varint_u16( &p, &sz ) ) ) return; /* client */
83 :
84 : /* Addrs */
85 24 : ushort addrs_len = 0;
86 24 : if( FD_UNLIKELY( !read_varint_u16( &addrs_len, &p, &sz ) ) ) return;
87 24 : ci->addrs_count = (pb_size_t)addrs_len;
88 24 : if( addrs_len ) {
89 23 : ci->addrs = fd_spad_alloc( spad, alignof(fd_exec_test_gossip_ip_addr_t),
90 23 : addrs_len * sizeof(fd_exec_test_gossip_ip_addr_t) );
91 67 : for( ushort i=0; i<addrs_len; i++ ) {
92 44 : NEED( 4UL );
93 44 : uint is_ip6 = FD_LOAD( uint, p );
94 44 : p += 4UL; sz -= 4UL;
95 44 : if( !is_ip6 ) {
96 44 : NEED( 4UL );
97 44 : ci->addrs[i].which_addr = FD_EXEC_TEST_GOSSIP_IP_ADDR_IPV4_TAG;
98 44 : ci->addrs[i].addr.ipv4 = fd_uint_bswap( FD_LOAD( uint, p ) );
99 44 : p += 4UL; sz -= 4UL;
100 44 : } else {
101 0 : NEED( 16UL );
102 0 : ci->addrs[i].which_addr = FD_EXEC_TEST_GOSSIP_IP_ADDR_IPV6_TAG;
103 0 : ci->addrs[i].addr.ipv6.hi = fd_ulong_bswap( FD_LOAD( ulong, p ) );
104 0 : ci->addrs[i].addr.ipv6.lo = fd_ulong_bswap( FD_LOAD( ulong, p+8UL ) );
105 0 : p += 16UL; sz -= 16UL;
106 0 : }
107 44 : }
108 23 : }
109 :
110 : /* Sockets */
111 24 : ushort sockets_len = 0;
112 24 : if( FD_UNLIKELY( !read_varint_u16( &sockets_len, &p, &sz ) ) ) return;
113 24 : ci->sockets_count = (pb_size_t)sockets_len;
114 24 : if( sockets_len ) {
115 23 : ci->sockets = fd_spad_alloc( spad, alignof(fd_exec_test_gossip_socket_entry_t),
116 23 : sockets_len * sizeof(fd_exec_test_gossip_socket_entry_t) );
117 67 : for( ushort i=0; i<sockets_len; i++ ) {
118 44 : NEED( 2UL );
119 44 : ci->sockets[i].key = *p; p++; sz--;
120 44 : ci->sockets[i].index = *p; p++; sz--;
121 44 : ushort offset = 0;
122 44 : if( FD_UNLIKELY( !read_varint_u16( &offset, &p, &sz ) ) ) return;
123 44 : ci->sockets[i].offset = offset;
124 44 : }
125 23 : }
126 :
127 : /* Extensions (Agave always sends empty) */
128 24 : ci->extensions = NULL;
129 24 : }
130 :
131 : static void
132 : reparse_epoch_slots_extra( fd_spad_t * spad,
133 : uchar const * value_start,
134 : ulong value_len,
135 51 : fd_exec_test_gossip_epoch_slots_t * es ) {
136 51 : uchar const * p = value_start;
137 51 : ulong sz = value_len;
138 :
139 51 : SKIP( 68UL ); /* signature(64) + tag(4) */
140 51 : SKIP( 33UL ); /* index(1) + origin(32) */
141 :
142 : /* slots_len (u64) */
143 51 : NEED( 8UL );
144 51 : ulong slots_len = FD_LOAD( ulong, p );
145 51 : p += 8UL; sz -= 8UL;
146 :
147 51 : es->slots_count = (pb_size_t)slots_len;
148 51 : if( !slots_len ) {
149 0 : es->slots = NULL;
150 0 : return;
151 0 : }
152 :
153 51 : es->slots = fd_spad_alloc( spad, alignof(fd_exec_test_gossip_compressed_slots_t),
154 51 : slots_len * sizeof(fd_exec_test_gossip_compressed_slots_t) );
155 :
156 126 : for( ulong i=0UL; i<slots_len; i++ ) {
157 75 : fd_exec_test_gossip_compressed_slots_t * slot = &es->slots[i];
158 :
159 75 : NEED( 4UL );
160 75 : uint is_uncompressed = FD_LOAD( uint, p );
161 75 : p += 4UL; sz -= 4UL;
162 :
163 75 : NEED( 8UL );
164 75 : slot->first_slot = FD_LOAD( ulong, p );
165 75 : p += 8UL; sz -= 8UL;
166 :
167 75 : NEED( 8UL );
168 75 : slot->num = FD_LOAD( ulong, p );
169 75 : p += 8UL; sz -= 8UL;
170 :
171 75 : if( is_uncompressed ) {
172 43 : slot->which_data = FD_EXEC_TEST_GOSSIP_COMPRESSED_SLOTS_UNCOMPRESSED_TAG;
173 43 : NEED( 1UL );
174 43 : uchar has_bits = *p; p++; sz--;
175 :
176 43 : if( has_bits ) {
177 28 : NEED( 8UL );
178 28 : ulong bits_cap = FD_LOAD( ulong, p );
179 28 : p += 8UL; sz -= 8UL;
180 28 : NEED( bits_cap );
181 28 : slot->data.uncompressed = alloc_bytes( spad, p, bits_cap );
182 28 : p += bits_cap; sz -= bits_cap;
183 28 : SKIP( 8UL ); /* bits_cnt */
184 28 : } else {
185 15 : slot->data.uncompressed = alloc_bytes( spad, NULL, 0UL );
186 15 : SKIP( 8UL ); /* bits_cnt */
187 15 : }
188 43 : } else {
189 32 : slot->which_data = FD_EXEC_TEST_GOSSIP_COMPRESSED_SLOTS_FLATE2_TAG;
190 32 : NEED( 8UL );
191 32 : ulong compressed_len = FD_LOAD( ulong, p );
192 32 : p += 8UL; sz -= 8UL;
193 32 : NEED( compressed_len );
194 32 : slot->data.flate2 = alloc_bytes( spad, p, compressed_len );
195 32 : p += compressed_len; sz -= compressed_len;
196 32 : }
197 75 : }
198 51 : }
199 :
200 : #undef SKIP
201 : #undef NEED
202 :
203 : static void
204 : convert_crds_data( fd_spad_t * spad,
205 : fd_gossip_value_t const * val,
206 : uchar const * raw_in,
207 392 : fd_exec_test_gossip_crds_data_t * out ) {
208 392 : switch( val->tag ) {
209 24 : case FD_GOSSIP_VALUE_CONTACT_INFO: {
210 24 : out->which_data = FD_EXEC_TEST_GOSSIP_CRDS_DATA_CONTACT_INFO_TAG;
211 24 : fd_exec_test_gossip_contact_info_t * ci = &out->data.contact_info;
212 24 : ci->pubkey = alloc_bytes( spad, val->origin, sizeof(val->origin) );
213 24 : ci->wallclock = val->wallclock;
214 24 : ci->outset = val->contact_info->outset;
215 24 : ci->shred_version = val->contact_info->shred_version;
216 24 : ci->version_major = val->contact_info->version.major;
217 24 : ushort packed_minor = val->contact_info->version.minor;
218 24 : ushort prerelease_bits = (ushort)((packed_minor >> 14U) & 0x3U);
219 24 : ci->version_minor = (uint)(packed_minor & 0x3FFFU);
220 24 : ci->version_patch = prerelease_bits ? 0U : (uint)val->contact_info->version.patch;
221 24 : ci->version_commit = val->contact_info->version.commit;
222 24 : ci->version_feature_set = val->contact_info->version.feature_set;
223 24 : ci->version_client = val->contact_info->version.client;
224 24 : reparse_contact_info_extra( spad, raw_in + val->offset, val->length, ci );
225 24 : break;
226 0 : }
227 52 : case FD_GOSSIP_VALUE_VOTE:
228 52 : out->which_data = FD_EXEC_TEST_GOSSIP_CRDS_DATA_VOTE_TAG;
229 52 : out->data.vote.index = val->vote->index;
230 52 : out->data.vote.from = alloc_bytes( spad, val->origin, sizeof(val->origin) );
231 52 : out->data.vote.wallclock = val->wallclock;
232 52 : out->data.vote.transaction = alloc_bytes( spad, val->vote->transaction, val->vote->transaction_len );
233 52 : break;
234 63 : case FD_GOSSIP_VALUE_LOWEST_SLOT:
235 63 : out->which_data = FD_EXEC_TEST_GOSSIP_CRDS_DATA_LOWEST_SLOT_TAG;
236 63 : out->data.lowest_slot.index = 0;
237 63 : out->data.lowest_slot.from = alloc_bytes( spad, val->origin, sizeof(val->origin) );
238 63 : out->data.lowest_slot.lowest = val->lowest_slot->lowest;
239 63 : out->data.lowest_slot.wallclock = val->wallclock;
240 63 : break;
241 51 : case FD_GOSSIP_VALUE_EPOCH_SLOTS: {
242 51 : out->which_data = FD_EXEC_TEST_GOSSIP_CRDS_DATA_EPOCH_SLOTS_TAG;
243 51 : fd_exec_test_gossip_epoch_slots_t * es = &out->data.epoch_slots;
244 51 : es->index = val->epoch_slots->index;
245 51 : es->from = alloc_bytes( spad, val->origin, sizeof(val->origin) );
246 51 : es->wallclock = val->wallclock;
247 51 : reparse_epoch_slots_extra( spad, raw_in + val->offset, val->length, es );
248 51 : break;
249 0 : }
250 61 : case FD_GOSSIP_VALUE_SNAPSHOT_HASHES: {
251 61 : out->which_data = FD_EXEC_TEST_GOSSIP_CRDS_DATA_SNAPSHOT_HASHES_TAG;
252 61 : fd_exec_test_gossip_snapshot_hashes_t * sh = &out->data.snapshot_hashes;
253 61 : sh->from = alloc_bytes( spad, val->origin, sizeof(val->origin) );
254 61 : sh->full_slot = val->snapshot_hashes->full_slot;
255 61 : sh->full_hash = alloc_bytes( spad, val->snapshot_hashes->full_hash, sizeof(val->snapshot_hashes->full_hash) );
256 61 : sh->wallclock = val->wallclock;
257 61 : sh->incremental_count = (pb_size_t)val->snapshot_hashes->incremental_len;
258 61 : if( sh->incremental_count ) {
259 45 : sh->incremental = fd_spad_alloc( spad, alignof(fd_exec_test_gossip_incremental_hash_t),
260 45 : sh->incremental_count * sizeof(fd_exec_test_gossip_incremental_hash_t) );
261 134 : for( ulong i=0UL; i<sh->incremental_count; i++ ) {
262 89 : sh->incremental[i].slot = val->snapshot_hashes->incremental[i].slot;
263 89 : sh->incremental[i].hash = alloc_bytes( spad, val->snapshot_hashes->incremental[i].hash,
264 89 : sizeof(val->snapshot_hashes->incremental[i].hash) );
265 89 : }
266 45 : }
267 61 : break;
268 0 : }
269 46 : case FD_GOSSIP_VALUE_DUPLICATE_SHRED:
270 46 : out->which_data = FD_EXEC_TEST_GOSSIP_CRDS_DATA_DUPLICATE_SHRED_TAG;
271 46 : out->data.duplicate_shred.index = val->duplicate_shred->index;
272 46 : out->data.duplicate_shred.from = alloc_bytes( spad, val->origin, sizeof(val->origin) );
273 46 : out->data.duplicate_shred.wallclock = val->wallclock;
274 46 : out->data.duplicate_shred.slot = val->duplicate_shred->slot;
275 46 : out->data.duplicate_shred.shred_index = 0;
276 46 : out->data.duplicate_shred.shred_type = 0;
277 46 : out->data.duplicate_shred.num_chunks = val->duplicate_shred->num_chunks;
278 46 : out->data.duplicate_shred.chunk_index = val->duplicate_shred->chunk_index;
279 46 : out->data.duplicate_shred.chunk = val->duplicate_shred->chunk_len
280 46 : ? alloc_bytes( spad, val->duplicate_shred->chunk,
281 46 : val->duplicate_shred->chunk_len )
282 46 : : NULL;
283 46 : break;
284 95 : default:
285 95 : out->which_data = 0;
286 95 : break;
287 392 : }
288 392 : }
289 :
290 : static void
291 : convert_crds_value( fd_spad_t * spad,
292 : fd_gossip_value_t const * val,
293 : uchar const * raw_in,
294 392 : fd_exec_test_gossip_crds_value_t * out ) {
295 392 : out->signature = alloc_bytes( spad, val->signature, sizeof(val->signature) );
296 392 : out->has_data = true;
297 392 : convert_crds_data( spad, val, raw_in, &out->data );
298 392 : }
299 :
300 : static void
301 : convert_crds_values( fd_spad_t * spad,
302 : fd_gossip_value_t const * vals,
303 : ulong vals_len,
304 : uchar const * raw_in,
305 : fd_exec_test_gossip_crds_value_t ** out_vals,
306 386 : pb_size_t * out_count ) {
307 386 : *out_count = (pb_size_t)vals_len;
308 386 : if( !vals_len ) {
309 0 : *out_vals = NULL;
310 0 : return;
311 0 : }
312 386 : *out_vals = fd_spad_alloc( spad, alignof(fd_exec_test_gossip_crds_value_t),
313 386 : vals_len * sizeof(fd_exec_test_gossip_crds_value_t) );
314 772 : for( ulong i=0UL; i<vals_len; i++ ) {
315 386 : convert_crds_value( spad, &vals[i], raw_in, &(*out_vals)[i] );
316 386 : }
317 386 : }
318 :
319 : static void
320 : convert_bloom( fd_spad_t * spad,
321 : fd_gossip_bloom_t const * bloom,
322 6 : fd_exec_test_gossip_bloom_t * out ) {
323 6 : out->keys_count = (pb_size_t)bloom->keys_len;
324 6 : if( bloom->keys_len ) {
325 0 : out->keys = fd_spad_alloc( spad, alignof(uint64_t), bloom->keys_len * sizeof(uint64_t) );
326 0 : memcpy( out->keys, bloom->keys, bloom->keys_len * sizeof(uint64_t) );
327 0 : }
328 : /* Copy only block_len() worth of u64 blocks, not bits_cap.
329 : https://github.com/tov/bv-rs/blob/0.11.1/src/bit_vec/mod.rs#L243-L245 */
330 6 : ulong bits_blocks = (bloom->bits_len + 63UL) / 64UL;
331 6 : ulong bits_byte_len = bits_blocks * sizeof(bloom->bits[0]);
332 6 : out->bits = bits_byte_len ? alloc_bytes( spad, (uchar const *)bloom->bits, bits_byte_len ) : NULL;
333 : /* Mask trailing bits beyond bits_len in the last block of the
334 : protobuf copy. bv::BitVec::get_block() returns get_masked_block()
335 : which zeros bits past bit_len() in the last block.
336 : https://github.com/tov/bv-rs/blob/0.11.1/src/bit_vec/impls.rs#L30-L32
337 : https://github.com/tov/bv-rs/blob/0.11.1/src/traits/bits.rs#L134-L137 */
338 6 : if( bloom->bits_len & 63UL ) {
339 1 : ulong last = bits_blocks - 1UL;
340 1 : ulong mask = ( 2UL << ((bloom->bits_len - 1UL) & 63UL) ) - 1UL;
341 1 : ((ulong *)out->bits->bytes)[ last ] &= mask;
342 1 : }
343 6 : out->num_bits_set = bloom->num_bits_set;
344 6 : }
345 :
346 : static void
347 : convert_gossip_msg( fd_spad_t * spad,
348 : fd_gossip_message_t const * msg,
349 : uchar const * raw_in,
350 2690 : fd_exec_test_gossip_msg_t * out ) {
351 2690 : switch( msg->tag ) {
352 846 : case FD_GOSSIP_MESSAGE_PING:
353 846 : out->which_msg = FD_EXEC_TEST_GOSSIP_MSG_PING_TAG;
354 846 : out->msg.ping.from = alloc_bytes( spad, msg->ping->from, sizeof(msg->ping->from) );
355 846 : out->msg.ping.token = alloc_bytes( spad, msg->ping->token, sizeof(msg->ping->token) );
356 846 : out->msg.ping.signature = alloc_bytes( spad, msg->ping->signature, sizeof(msg->ping->signature) );
357 846 : break;
358 856 : case FD_GOSSIP_MESSAGE_PONG:
359 856 : out->which_msg = FD_EXEC_TEST_GOSSIP_MSG_PONG_TAG;
360 856 : out->msg.pong.from = alloc_bytes( spad, msg->pong->from, sizeof(msg->pong->from) );
361 856 : out->msg.pong.hash = alloc_bytes( spad, msg->pong->hash, sizeof(msg->pong->hash) );
362 856 : out->msg.pong.signature = alloc_bytes( spad, msg->pong->signature, sizeof(msg->pong->signature) );
363 856 : break;
364 6 : case FD_GOSSIP_MESSAGE_PULL_REQUEST: {
365 6 : out->which_msg = FD_EXEC_TEST_GOSSIP_MSG_PULL_REQUEST_TAG;
366 6 : fd_exec_test_gossip_pull_request_t * pr = &out->msg.pull_request;
367 6 : pr->has_filter = true;
368 6 : pr->filter.has_filter = true;
369 6 : convert_bloom( spad, msg->pull_request->crds_filter->filter, &pr->filter.filter );
370 6 : pr->filter.mask_bits = msg->pull_request->crds_filter->mask_bits;
371 : /* Agave canonicalizes the mask by setting all (64-mask_bits) low bits to 1.
372 : https://github.com/anza-xyz/agave/blob/v4.0.0-beta.6/gossip/src/crds_gossip_pull.rs#L152-L155 */
373 6 : ulong lsb_mask = (pr->filter.mask_bits>=64U) ? 0UL : (ULONG_MAX >> pr->filter.mask_bits);
374 6 : pr->filter.mask = msg->pull_request->crds_filter->mask | lsb_mask;
375 6 : pr->has_value = true;
376 6 : convert_crds_value( spad, msg->pull_request->contact_info, raw_in, &pr->value );
377 6 : break;
378 0 : }
379 192 : case FD_GOSSIP_MESSAGE_PULL_RESPONSE: {
380 192 : out->which_msg = FD_EXEC_TEST_GOSSIP_MSG_PULL_RESPONSE_TAG;
381 192 : fd_exec_test_gossip_pull_response_t * pr = &out->msg.pull_response;
382 192 : pr->pubkey = alloc_bytes( spad, msg->pull_response->from, sizeof(msg->pull_response->from) );
383 192 : convert_crds_values( spad, msg->pull_response->values,
384 192 : msg->pull_response->values_len,
385 192 : raw_in,
386 192 : &pr->values, &pr->values_count );
387 192 : break;
388 0 : }
389 194 : case FD_GOSSIP_MESSAGE_PUSH: {
390 194 : out->which_msg = FD_EXEC_TEST_GOSSIP_MSG_PUSH_MESSAGE_TAG;
391 194 : fd_exec_test_gossip_push_message_t * pm = &out->msg.push_message;
392 194 : pm->pubkey = alloc_bytes( spad, msg->push->from, sizeof(msg->push->from) );
393 194 : convert_crds_values( spad, msg->push->values,
394 194 : msg->push->values_len,
395 194 : raw_in,
396 194 : &pm->values, &pm->values_count );
397 194 : break;
398 0 : }
399 599 : case FD_GOSSIP_MESSAGE_PRUNE: {
400 599 : out->which_msg = FD_EXEC_TEST_GOSSIP_MSG_PRUNE_MESSAGE_TAG;
401 599 : fd_exec_test_gossip_prune_message_t * pm = &out->msg.prune_message;
402 599 : pm->pubkey = alloc_bytes( spad, msg->prune->sender, sizeof(msg->prune->sender) );
403 599 : pm->has_data = true;
404 599 : pm->data.pubkey = alloc_bytes( spad, msg->prune->pubkey, sizeof(msg->prune->pubkey) );
405 599 : pm->data.signature = alloc_bytes( spad, msg->prune->signature, sizeof(msg->prune->signature) );
406 599 : pm->data.destination = alloc_bytes( spad, msg->prune->destination, sizeof(msg->prune->destination) );
407 599 : pm->data.wallclock = msg->prune->wallclock;
408 599 : pm->data.prunes_count = (pb_size_t)msg->prune->prunes_len;
409 599 : if( msg->prune->prunes_len ) {
410 586 : pm->data.prunes = fd_spad_alloc( spad, alignof(pb_bytes_array_t *),
411 586 : msg->prune->prunes_len * sizeof(pb_bytes_array_t *) );
412 9157 : for( ulong i=0UL; i<msg->prune->prunes_len; i++ ) {
413 8571 : pm->data.prunes[i] = alloc_bytes( spad, msg->prune->prunes[i], sizeof(msg->prune->prunes[i]) );
414 8571 : }
415 586 : }
416 599 : break;
417 0 : }
418 0 : default:
419 0 : out->which_msg = 0;
420 0 : break;
421 2690 : }
422 2690 : }
423 :
424 : int
425 : fd_solfuzz_gossip_decode( fd_solfuzz_runner_t * runner,
426 : uchar * out,
427 : ulong * out_sz,
428 : uchar const * in,
429 4967 : ulong in_sz ) {
430 4967 : if( FD_UNLIKELY( in_sz>FD_GOSSIP_MTU ) ) FD_LOG_CRIT(( "invariant violation: gossip input %lu bytes exceeds MTU %lu, check fuzzer configuration", in_sz, FD_GOSSIP_MTU ));
431 :
432 4967 : fd_gossip_message_t msg[1] = {0};
433 4967 : fd_exec_test_gossip_effects_t effects = FD_EXEC_TEST_GOSSIP_EFFECTS_INIT_ZERO;
434 :
435 4967 : int ok = fd_gossip_message_deserialize( msg, in, in_sz );
436 4967 : if( ok ) {
437 2690 : effects.valid = true;
438 2690 : effects.has_msg = true;
439 2690 : convert_gossip_msg( runner->spad, msg, in, &effects.msg );
440 2690 : } else {
441 2277 : effects.valid = false;
442 2277 : effects.has_msg = false;
443 2277 : }
444 :
445 4967 : return !!sol_compat_encode( out, out_sz, &effects, &fd_exec_test_gossip_effects_t_msg );
446 4967 : }
|