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