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 0 : ulong len ) {
15 0 : pb_bytes_array_t * arr = fd_spad_alloc( spad, alignof(pb_bytes_array_t), PB_BYTES_ARRAY_T_ALLOCSIZE( len ) );
16 0 : arr->size = (pb_size_t)len;
17 0 : if( FD_LIKELY( len ) ) memcpy( arr->bytes, src, len );
18 0 : return arr;
19 0 : }
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 0 : #define FD_VARINT_U64_MAX_BYTES (10UL) /* ceil(64/7) */
26 :
27 : static inline int
28 : skip_varint_u16( uchar const ** p,
29 0 : ulong * sz ) {
30 0 : ulong n = fd_cu16_dec_sz( *p, *sz );
31 0 : if( FD_UNLIKELY( !n ) ) return 0;
32 0 : *p += n;
33 0 : *sz -= n;
34 0 : return 1;
35 0 : }
36 :
37 : static inline int
38 : read_varint_u16( ushort * dst,
39 : uchar const ** p,
40 0 : ulong * sz ) {
41 0 : ulong n = fd_cu16_dec_sz( *p, *sz );
42 0 : if( FD_UNLIKELY( !n ) ) return 0;
43 0 : *dst = fd_cu16_dec_fixed( *p, n );
44 0 : *p += n;
45 0 : *sz -= n;
46 0 : return 1;
47 0 : }
48 :
49 : static inline int
50 : skip_varint_u64( uchar const ** p,
51 0 : ulong * sz ) {
52 0 : for( ulong i=0UL; i<FD_VARINT_U64_MAX_BYTES; i++ ) {
53 0 : if( FD_UNLIKELY( !*sz ) ) return 0;
54 0 : uchar byte = **p;
55 0 : (*p)++; (*sz)--;
56 0 : if( FD_LIKELY( !(byte & 0x80) ) ) return 1;
57 0 : }
58 0 : return 0;
59 0 : }
60 :
61 0 : #define NEED(n) do { if( FD_UNLIKELY( sz < (n) ) ) return; } while(0)
62 0 : #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 0 : fd_exec_test_gossip_contact_info_t * ci ) {
69 0 : uchar const * p = value_start;
70 0 : ulong sz = value_len;
71 :
72 0 : SKIP( 68UL ); /* signature(64) + tag(4) */
73 0 : SKIP( 32UL ); /* origin(32) */
74 0 : if( FD_UNLIKELY( !skip_varint_u64( &p, &sz ) ) ) return; /* wallclock */
75 0 : SKIP( 10UL ); /* outset(8) + shred_version(2) */
76 :
77 0 : if( FD_UNLIKELY( !skip_varint_u16( &p, &sz ) ) ) return; /* major */
78 0 : if( FD_UNLIKELY( !skip_varint_u16( &p, &sz ) ) ) return; /* minor */
79 0 : if( FD_UNLIKELY( !skip_varint_u16( &p, &sz ) ) ) return; /* patch */
80 0 : SKIP( 4UL ); /* commit (u32) */
81 0 : SKIP( 4UL ); /* feature_set (u32) */
82 0 : if( FD_UNLIKELY( !skip_varint_u16( &p, &sz ) ) ) return; /* client */
83 :
84 : /* Addrs */
85 0 : ushort addrs_len = 0;
86 0 : if( FD_UNLIKELY( !read_varint_u16( &addrs_len, &p, &sz ) ) ) return;
87 0 : ci->addrs_count = (pb_size_t)addrs_len;
88 0 : if( addrs_len ) {
89 0 : ci->addrs = fd_spad_alloc( spad, alignof(fd_exec_test_gossip_ip_addr_t),
90 0 : addrs_len * sizeof(fd_exec_test_gossip_ip_addr_t) );
91 0 : for( ushort i=0; i<addrs_len; i++ ) {
92 0 : NEED( 4UL );
93 0 : uint is_ip6 = FD_LOAD( uint, p );
94 0 : p += 4UL; sz -= 4UL;
95 0 : if( !is_ip6 ) {
96 0 : NEED( 4UL );
97 0 : ci->addrs[i].which_addr = FD_EXEC_TEST_GOSSIP_IP_ADDR_IPV4_TAG;
98 0 : ci->addrs[i].addr.ipv4 = fd_uint_bswap( FD_LOAD( uint, p ) );
99 0 : p += 4UL; sz -= 4UL;
100 0 : } 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 0 : }
108 0 : }
109 :
110 : /* Sockets */
111 0 : ushort sockets_len = 0;
112 0 : if( FD_UNLIKELY( !read_varint_u16( &sockets_len, &p, &sz ) ) ) return;
113 0 : ci->sockets_count = (pb_size_t)sockets_len;
114 0 : if( sockets_len ) {
115 0 : ci->sockets = fd_spad_alloc( spad, alignof(fd_exec_test_gossip_socket_entry_t),
116 0 : sockets_len * sizeof(fd_exec_test_gossip_socket_entry_t) );
117 0 : for( ushort i=0; i<sockets_len; i++ ) {
118 0 : NEED( 2UL );
119 0 : ci->sockets[i].key = *p; p++; sz--;
120 0 : ci->sockets[i].index = *p; p++; sz--;
121 0 : ushort offset = 0;
122 0 : if( FD_UNLIKELY( !read_varint_u16( &offset, &p, &sz ) ) ) return;
123 0 : ci->sockets[i].offset = offset;
124 0 : }
125 0 : }
126 :
127 : /* Extensions (Agave always sends empty) */
128 0 : ci->extensions = NULL;
129 0 : }
130 :
131 : static void
132 : reparse_epoch_slots_extra( fd_spad_t * spad,
133 : uchar const * value_start,
134 : ulong value_len,
135 0 : fd_exec_test_gossip_epoch_slots_t * es ) {
136 0 : uchar const * p = value_start;
137 0 : ulong sz = value_len;
138 :
139 0 : SKIP( 68UL ); /* signature(64) + tag(4) */
140 0 : SKIP( 33UL ); /* index(1) + origin(32) */
141 :
142 : /* slots_len (u64) */
143 0 : NEED( 8UL );
144 0 : ulong slots_len = FD_LOAD( ulong, p );
145 0 : p += 8UL; sz -= 8UL;
146 :
147 0 : es->slots_count = (pb_size_t)slots_len;
148 0 : if( !slots_len ) {
149 0 : es->slots = NULL;
150 0 : return;
151 0 : }
152 :
153 0 : es->slots = fd_spad_alloc( spad, alignof(fd_exec_test_gossip_compressed_slots_t),
154 0 : slots_len * sizeof(fd_exec_test_gossip_compressed_slots_t) );
155 :
156 0 : for( ulong i=0UL; i<slots_len; i++ ) {
157 0 : fd_exec_test_gossip_compressed_slots_t * slot = &es->slots[i];
158 :
159 0 : NEED( 4UL );
160 0 : uint is_uncompressed = FD_LOAD( uint, p );
161 0 : p += 4UL; sz -= 4UL;
162 :
163 0 : NEED( 8UL );
164 0 : slot->first_slot = FD_LOAD( ulong, p );
165 0 : p += 8UL; sz -= 8UL;
166 :
167 0 : NEED( 8UL );
168 0 : slot->num = FD_LOAD( ulong, p );
169 0 : p += 8UL; sz -= 8UL;
170 :
171 0 : if( is_uncompressed ) {
172 0 : slot->which_data = FD_EXEC_TEST_GOSSIP_COMPRESSED_SLOTS_UNCOMPRESSED_TAG;
173 0 : NEED( 1UL );
174 0 : uchar has_bits = *p; p++; sz--;
175 :
176 0 : if( has_bits ) {
177 0 : NEED( 8UL );
178 0 : ulong bits_cap = FD_LOAD( ulong, p );
179 0 : p += 8UL; sz -= 8UL;
180 0 : NEED( bits_cap );
181 0 : slot->data.uncompressed = alloc_bytes( spad, p, bits_cap );
182 0 : p += bits_cap; sz -= bits_cap;
183 0 : SKIP( 8UL ); /* bits_cnt */
184 0 : } else {
185 0 : slot->data.uncompressed = alloc_bytes( spad, NULL, 0UL );
186 0 : SKIP( 8UL ); /* bits_cnt */
187 0 : }
188 0 : } else {
189 0 : slot->which_data = FD_EXEC_TEST_GOSSIP_COMPRESSED_SLOTS_FLATE2_TAG;
190 0 : NEED( 8UL );
191 0 : ulong compressed_len = FD_LOAD( ulong, p );
192 0 : p += 8UL; sz -= 8UL;
193 0 : NEED( compressed_len );
194 0 : slot->data.flate2 = alloc_bytes( spad, p, compressed_len );
195 0 : p += compressed_len; sz -= compressed_len;
196 0 : }
197 0 : }
198 0 : }
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 0 : fd_exec_test_gossip_crds_data_t * out ) {
208 0 : switch( val->tag ) {
209 0 : case FD_GOSSIP_VALUE_CONTACT_INFO: {
210 0 : out->which_data = FD_EXEC_TEST_GOSSIP_CRDS_DATA_CONTACT_INFO_TAG;
211 0 : fd_exec_test_gossip_contact_info_t * ci = &out->data.contact_info;
212 0 : ci->pubkey = alloc_bytes( spad, val->origin, sizeof(val->origin) );
213 0 : ci->wallclock = val->wallclock;
214 0 : ci->outset = val->contact_info->outset;
215 0 : ci->shred_version = val->contact_info->shred_version;
216 0 : ci->version_major = val->contact_info->version.major;
217 0 : ushort packed_minor = val->contact_info->version.minor;
218 0 : ushort prerelease_bits = (ushort)((packed_minor >> 14U) & 0x3U);
219 0 : ci->version_minor = (uint)(packed_minor & 0x3FFFU);
220 0 : ci->version_patch = prerelease_bits ? 0U : (uint)val->contact_info->version.patch;
221 0 : ci->version_commit = val->contact_info->version.commit;
222 0 : ci->version_feature_set = val->contact_info->version.feature_set;
223 0 : ci->version_client = val->contact_info->version.client;
224 0 : reparse_contact_info_extra( spad, raw_in + val->offset, val->length, ci );
225 0 : break;
226 0 : }
227 0 : case FD_GOSSIP_VALUE_VOTE:
228 0 : out->which_data = FD_EXEC_TEST_GOSSIP_CRDS_DATA_VOTE_TAG;
229 0 : out->data.vote.index = val->vote->index;
230 0 : out->data.vote.from = alloc_bytes( spad, val->origin, sizeof(val->origin) );
231 0 : out->data.vote.wallclock = val->wallclock;
232 0 : out->data.vote.transaction = alloc_bytes( spad, val->vote->transaction, val->vote->transaction_len );
233 0 : break;
234 0 : case FD_GOSSIP_VALUE_LOWEST_SLOT:
235 0 : out->which_data = FD_EXEC_TEST_GOSSIP_CRDS_DATA_LOWEST_SLOT_TAG;
236 0 : out->data.lowest_slot.index = 0;
237 0 : out->data.lowest_slot.from = alloc_bytes( spad, val->origin, sizeof(val->origin) );
238 0 : out->data.lowest_slot.lowest = val->lowest_slot->lowest;
239 0 : out->data.lowest_slot.wallclock = val->wallclock;
240 0 : break;
241 0 : case FD_GOSSIP_VALUE_EPOCH_SLOTS: {
242 0 : out->which_data = FD_EXEC_TEST_GOSSIP_CRDS_DATA_EPOCH_SLOTS_TAG;
243 0 : fd_exec_test_gossip_epoch_slots_t * es = &out->data.epoch_slots;
244 0 : es->index = val->epoch_slots->index;
245 0 : es->from = alloc_bytes( spad, val->origin, sizeof(val->origin) );
246 0 : es->wallclock = val->wallclock;
247 0 : reparse_epoch_slots_extra( spad, raw_in + val->offset, val->length, es );
248 0 : break;
249 0 : }
250 0 : case FD_GOSSIP_VALUE_SNAPSHOT_HASHES: {
251 0 : out->which_data = FD_EXEC_TEST_GOSSIP_CRDS_DATA_SNAPSHOT_HASHES_TAG;
252 0 : fd_exec_test_gossip_snapshot_hashes_t * sh = &out->data.snapshot_hashes;
253 0 : sh->from = alloc_bytes( spad, val->origin, sizeof(val->origin) );
254 0 : sh->full_slot = val->snapshot_hashes->full_slot;
255 0 : sh->full_hash = alloc_bytes( spad, val->snapshot_hashes->full_hash, sizeof(val->snapshot_hashes->full_hash) );
256 0 : sh->wallclock = val->wallclock;
257 0 : sh->incremental_count = (pb_size_t)val->snapshot_hashes->incremental_len;
258 0 : if( sh->incremental_count ) {
259 0 : sh->incremental = fd_spad_alloc( spad, alignof(fd_exec_test_gossip_incremental_hash_t),
260 0 : sh->incremental_count * sizeof(fd_exec_test_gossip_incremental_hash_t) );
261 0 : for( ulong i=0UL; i<sh->incremental_count; i++ ) {
262 0 : sh->incremental[i].slot = val->snapshot_hashes->incremental[i].slot;
263 0 : sh->incremental[i].hash = alloc_bytes( spad, val->snapshot_hashes->incremental[i].hash,
264 0 : sizeof(val->snapshot_hashes->incremental[i].hash) );
265 0 : }
266 0 : }
267 0 : break;
268 0 : }
269 0 : case FD_GOSSIP_VALUE_DUPLICATE_SHRED:
270 0 : out->which_data = FD_EXEC_TEST_GOSSIP_CRDS_DATA_DUPLICATE_SHRED_TAG;
271 0 : out->data.duplicate_shred.index = val->duplicate_shred->index;
272 0 : out->data.duplicate_shred.from = alloc_bytes( spad, val->origin, sizeof(val->origin) );
273 0 : out->data.duplicate_shred.wallclock = val->wallclock;
274 0 : out->data.duplicate_shred.slot = val->duplicate_shred->slot;
275 0 : out->data.duplicate_shred.shred_index = 0;
276 0 : out->data.duplicate_shred.shred_type = 0;
277 0 : out->data.duplicate_shred.num_chunks = val->duplicate_shred->num_chunks;
278 0 : out->data.duplicate_shred.chunk_index = val->duplicate_shred->chunk_index;
279 0 : out->data.duplicate_shred.chunk = val->duplicate_shred->chunk_len
280 0 : ? alloc_bytes( spad, val->duplicate_shred->chunk,
281 0 : val->duplicate_shred->chunk_len )
282 0 : : NULL;
283 0 : break;
284 0 : default:
285 0 : out->which_data = 0;
286 0 : break;
287 0 : }
288 0 : }
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 0 : fd_exec_test_gossip_crds_value_t * out ) {
295 0 : out->signature = alloc_bytes( spad, val->signature, sizeof(val->signature) );
296 0 : out->has_data = true;
297 0 : convert_crds_data( spad, val, raw_in, &out->data );
298 0 : }
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 0 : pb_size_t * out_count ) {
307 0 : *out_count = (pb_size_t)vals_len;
308 0 : if( !vals_len ) {
309 0 : *out_vals = NULL;
310 0 : return;
311 0 : }
312 0 : *out_vals = fd_spad_alloc( spad, alignof(fd_exec_test_gossip_crds_value_t),
313 0 : vals_len * sizeof(fd_exec_test_gossip_crds_value_t) );
314 0 : for( ulong i=0UL; i<vals_len; i++ ) {
315 0 : convert_crds_value( spad, &vals[i], raw_in, &(*out_vals)[i] );
316 0 : }
317 0 : }
318 :
319 : static void
320 : convert_bloom( fd_spad_t * spad,
321 : fd_gossip_bloom_t const * bloom,
322 0 : fd_exec_test_gossip_bloom_t * out ) {
323 0 : out->keys_count = (pb_size_t)bloom->keys_len;
324 0 : 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 0 : ulong bits_blocks = (bloom->bits_len + 63UL) / 64UL;
331 0 : ulong bits_byte_len = bits_blocks * sizeof(bloom->bits[0]);
332 0 : 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 0 : if( bloom->bits_len & 63UL ) {
339 0 : ulong last = bits_blocks - 1UL;
340 0 : ulong mask = ( 2UL << ((bloom->bits_len - 1UL) & 63UL) ) - 1UL;
341 0 : ((ulong *)out->bits->bytes)[ last ] &= mask;
342 0 : }
343 0 : out->num_bits_set = bloom->num_bits_set;
344 0 : }
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 0 : fd_exec_test_gossip_msg_t * out ) {
351 0 : switch( msg->tag ) {
352 0 : case FD_GOSSIP_MESSAGE_PING:
353 0 : out->which_msg = FD_EXEC_TEST_GOSSIP_MSG_PING_TAG;
354 0 : out->msg.ping.from = alloc_bytes( spad, msg->ping->from, sizeof(msg->ping->from) );
355 0 : out->msg.ping.token = alloc_bytes( spad, msg->ping->token, sizeof(msg->ping->token) );
356 0 : out->msg.ping.signature = alloc_bytes( spad, msg->ping->signature, sizeof(msg->ping->signature) );
357 0 : break;
358 0 : case FD_GOSSIP_MESSAGE_PONG:
359 0 : out->which_msg = FD_EXEC_TEST_GOSSIP_MSG_PONG_TAG;
360 0 : out->msg.pong.from = alloc_bytes( spad, msg->pong->from, sizeof(msg->pong->from) );
361 0 : out->msg.pong.hash = alloc_bytes( spad, msg->pong->hash, sizeof(msg->pong->hash) );
362 0 : out->msg.pong.signature = alloc_bytes( spad, msg->pong->signature, sizeof(msg->pong->signature) );
363 0 : break;
364 0 : case FD_GOSSIP_MESSAGE_PULL_REQUEST: {
365 0 : out->which_msg = FD_EXEC_TEST_GOSSIP_MSG_PULL_REQUEST_TAG;
366 0 : fd_exec_test_gossip_pull_request_t * pr = &out->msg.pull_request;
367 0 : pr->has_filter = true;
368 0 : pr->filter.has_filter = true;
369 0 : convert_bloom( spad, msg->pull_request->crds_filter->filter, &pr->filter.filter );
370 0 : 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 0 : ulong lsb_mask = (pr->filter.mask_bits>=64U) ? 0UL : (ULONG_MAX >> pr->filter.mask_bits);
374 0 : pr->filter.mask = msg->pull_request->crds_filter->mask | lsb_mask;
375 0 : pr->has_value = true;
376 0 : convert_crds_value( spad, msg->pull_request->contact_info, raw_in, &pr->value );
377 0 : break;
378 0 : }
379 0 : case FD_GOSSIP_MESSAGE_PULL_RESPONSE: {
380 0 : out->which_msg = FD_EXEC_TEST_GOSSIP_MSG_PULL_RESPONSE_TAG;
381 0 : fd_exec_test_gossip_pull_response_t * pr = &out->msg.pull_response;
382 0 : pr->pubkey = alloc_bytes( spad, msg->pull_response->from, sizeof(msg->pull_response->from) );
383 0 : convert_crds_values( spad, msg->pull_response->values,
384 0 : msg->pull_response->values_len,
385 0 : raw_in,
386 0 : &pr->values, &pr->values_count );
387 0 : break;
388 0 : }
389 0 : case FD_GOSSIP_MESSAGE_PUSH: {
390 0 : out->which_msg = FD_EXEC_TEST_GOSSIP_MSG_PUSH_MESSAGE_TAG;
391 0 : fd_exec_test_gossip_push_message_t * pm = &out->msg.push_message;
392 0 : pm->pubkey = alloc_bytes( spad, msg->push->from, sizeof(msg->push->from) );
393 0 : convert_crds_values( spad, msg->push->values,
394 0 : msg->push->values_len,
395 0 : raw_in,
396 0 : &pm->values, &pm->values_count );
397 0 : break;
398 0 : }
399 0 : case FD_GOSSIP_MESSAGE_PRUNE: {
400 0 : out->which_msg = FD_EXEC_TEST_GOSSIP_MSG_PRUNE_MESSAGE_TAG;
401 0 : fd_exec_test_gossip_prune_message_t * pm = &out->msg.prune_message;
402 0 : pm->pubkey = alloc_bytes( spad, msg->prune->sender, sizeof(msg->prune->sender) );
403 0 : pm->has_data = true;
404 0 : pm->data.pubkey = alloc_bytes( spad, msg->prune->pubkey, sizeof(msg->prune->pubkey) );
405 0 : pm->data.signature = alloc_bytes( spad, msg->prune->signature, sizeof(msg->prune->signature) );
406 0 : pm->data.destination = alloc_bytes( spad, msg->prune->destination, sizeof(msg->prune->destination) );
407 0 : pm->data.wallclock = msg->prune->wallclock;
408 0 : pm->data.prunes_count = (pb_size_t)msg->prune->prunes_len;
409 0 : if( msg->prune->prunes_len ) {
410 0 : pm->data.prunes = fd_spad_alloc( spad, alignof(pb_bytes_array_t *),
411 0 : msg->prune->prunes_len * sizeof(pb_bytes_array_t *) );
412 0 : for( ulong i=0UL; i<msg->prune->prunes_len; i++ ) {
413 0 : pm->data.prunes[i] = alloc_bytes( spad, msg->prune->prunes[i], sizeof(msg->prune->prunes[i]) );
414 0 : }
415 0 : }
416 0 : break;
417 0 : }
418 0 : default:
419 0 : out->which_msg = 0;
420 0 : break;
421 0 : }
422 0 : }
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 0 : ulong in_sz ) {
430 0 : 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 0 : fd_gossip_message_t msg[1] = {0};
433 0 : fd_exec_test_gossip_effects_t effects = FD_EXEC_TEST_GOSSIP_EFFECTS_INIT_ZERO;
434 :
435 0 : int ok = fd_gossip_message_deserialize( msg, in, in_sz );
436 0 : if( ok ) {
437 0 : effects.valid = true;
438 0 : effects.has_msg = true;
439 0 : convert_gossip_msg( runner->spad, msg, in, &effects.msg );
440 0 : } else {
441 0 : effects.valid = false;
442 0 : effects.has_msg = false;
443 0 : }
444 :
445 0 : return !!sol_compat_encode( out, out_sz, &effects, &fd_exec_test_gossip_effects_t_msg );
446 0 : }
|