Line data Source code
1 : #include "fd_gossip_message.h"
2 :
3 : #include <string.h>
4 :
5 : #include "../../ballet/txn/fd_compact_u16.h"
6 : #include "../runtime/fd_system_ids.h"
7 : #include "../types/fd_types.h"
8 :
9 : /* https://github.com/anza-xyz/agave/blob/bff4df9cf6f41520a26c9838ee3d4d8c024a96a1/gossip/src/crds_data.rs#L22-L23 */
10 : #define WALLCLOCK_MAX_MILLIS (1000000000000000UL)
11 : #define MAX_SLOT (1000000000000000UL)
12 :
13 : /* https://github.com/anza-xyz/agave/blob/master/gossip/src/epoch_slots.rs#L15 */
14 : #define MAX_SLOTS_PER_EPOCH_SLOT (2048UL*8UL)
15 :
16 : #define FD_GOSSIP_VOTE_IDX_MAX (32)
17 : #define FD_GOSSIP_EPOCH_SLOTS_IDX_MAX (255U)
18 : #define FD_GOSSIP_DUPLICATE_SHRED_IDX_MAX (512U)
19 :
20 0 : #define CHECK( cond ) do { \
21 0 : if( FD_UNLIKELY( !(cond) ) ) return 0; \
22 0 : } while( 0 )
23 :
24 0 : #define READ_BYTES( dst, n, payload, payload_sz ) do { \
25 0 : CHECK( (n)<=(*(payload_sz)) ); \
26 0 : fd_memcpy( (dst), *(payload), (n) ); \
27 0 : *(payload) += (n); \
28 0 : *(payload_sz) -= (n); \
29 0 : } while( 0 )
30 :
31 0 : #define SKIP_BYTES( n, payload, payload_sz ) do { \
32 0 : CHECK( (n)<=(*(payload_sz)) ); \
33 0 : *(payload) += (n); \
34 0 : *(payload_sz) -= (n); \
35 0 : } while( 0 )
36 :
37 0 : #define READ_OPTION( dst, payload, payload_sz ) do { \
38 0 : READ_U8( dst, payload, payload_sz ); \
39 0 : CHECK( (dst)==0 || (dst)==1 ); \
40 0 : } while( 0 )
41 :
42 0 : #define READ_ENUM( dst, n, payload, payload_sz ) do { \
43 0 : CHECK( 4UL<=(*(payload_sz)) ); \
44 0 : (dst) = FD_LOAD( uint, *(payload) ); \
45 0 : CHECK( (dst)<n ); \
46 0 : *(payload) += 4UL; \
47 0 : *(payload_sz) -= 4UL; \
48 0 : } while( 0 )
49 :
50 0 : #define READ_U8( dst, payload, payload_sz ) do { \
51 0 : CHECK( 1UL<=(*(payload_sz)) ); \
52 0 : (dst) = FD_LOAD( uchar, *(payload) ); \
53 0 : *(payload) += 1UL; \
54 0 : *(payload_sz) -= 1UL; \
55 0 : } while( 0 )
56 :
57 0 : #define READ_U16( dst, payload, payload_sz ) do { \
58 0 : CHECK( 2UL<=(*(payload_sz)) ); \
59 0 : (dst) = FD_LOAD( ushort, *(payload) ); \
60 0 : *(payload) += 2UL; \
61 0 : *(payload_sz) -= 2UL; \
62 0 : } while( 0 )
63 :
64 0 : #define READ_U32( dst, payload, payload_sz ) do { \
65 0 : CHECK( 4UL<=(*(payload_sz)) ); \
66 0 : (dst) = FD_LOAD( uint, *(payload) ); \
67 0 : *(payload) += 4UL; \
68 0 : *(payload_sz) -= 4UL; \
69 0 : } while( 0 )
70 :
71 0 : #define READ_U64( dst, payload, payload_sz ) do { \
72 0 : CHECK( 8UL<=(*(payload_sz)) ); \
73 0 : (dst) = FD_LOAD( ulong, *(payload) ); \
74 0 : *(payload) += 8UL; \
75 0 : *(payload_sz) -= 8UL; \
76 0 : } while( 0 )
77 :
78 0 : #define READ_U16_VARINT( dst, payload, payload_sz ) do { \
79 0 : ulong _sz = fd_cu16_dec_sz( *(payload), *(payload_sz) ); \
80 0 : CHECK( _sz ); \
81 0 : (dst) = fd_cu16_dec_fixed( *(payload), _sz ); \
82 0 : *(payload) += _sz; \
83 0 : *(payload_sz) -= _sz; \
84 0 : } while( 0 )
85 :
86 0 : #define READ_U64_VARINT( dst, payload, payload_sz ) do { \
87 0 : ulong _val = 0UL; \
88 0 : uint _shift = 0U; \
89 0 : for(;;) { \
90 0 : CHECK( 1UL<=(*(payload_sz)) ); \
91 0 : uchar _byte = FD_LOAD( uchar, *(payload) ); \
92 0 : *(payload) += 1UL; \
93 0 : *(payload_sz) -= 1UL; \
94 0 : _val |= (ulong)(_byte & 0x7F) << _shift; \
95 0 : if( FD_LIKELY( !(_byte & 0x80) ) ) { \
96 0 : CHECK( (_val>>_shift)==(ulong)_byte ); /* last byte not truncated */ \
97 0 : CHECK( _byte || !_shift ); /* no trailing zero bytes */ \
98 0 : (dst) = _val; \
99 0 : break; \
100 0 : } \
101 0 : _shift += 7U; \
102 0 : CHECK( _shift<64U ); \
103 0 : } \
104 0 : } while( 0 )
105 :
106 0 : #define READ_WALLCLOCK( dst, payload, payload_sz ) do { \
107 0 : ulong wallclock_millis; \
108 0 : READ_U64( wallclock_millis, payload, payload_sz ); \
109 0 : CHECK( wallclock_millis<WALLCLOCK_MAX_MILLIS ); \
110 0 : (dst) = wallclock_millis; \
111 0 : } while( 0 )
112 :
113 : static int
114 : deser_legacy_contact_info( fd_gossip_value_t * value,
115 : uchar const ** payload,
116 0 : ulong * payload_sz ) {
117 0 : READ_BYTES( value->origin, 32UL, payload, payload_sz );
118 0 : for( ulong i=0UL; i<10UL; i++ ) {
119 0 : uint is_ip6 = 0U;
120 0 : READ_ENUM( is_ip6, 2UL, payload, payload_sz );
121 0 : SKIP_BYTES( is_ip6 ? 16UL+2UL : 4UL+2UL, payload, payload_sz );
122 0 : }
123 0 : READ_WALLCLOCK( value->wallclock, payload, payload_sz );
124 0 : SKIP_BYTES( 2UL, payload, payload_sz );
125 0 : return 1;
126 0 : }
127 :
128 : static int
129 : deser_vote_instruction( uchar const * data,
130 0 : ulong data_len ) {
131 : // TODO: NO FD TYPES
132 0 : fd_bincode_decode_ctx_t ctx = { .data = data, .dataend = data+data_len };
133 0 : ulong total_sz = 0UL;
134 0 : CHECK( !fd_vote_instruction_decode_footprint( &ctx, &total_sz ) );
135 0 : uchar * buf = fd_alloca_check( alignof(fd_vote_instruction_t), total_sz );
136 0 : fd_vote_instruction_t * vote_instruction = fd_vote_instruction_decode( buf, &ctx );
137 0 : CHECK( vote_instruction );
138 0 : CHECK(
139 0 : vote_instruction->discriminant==fd_vote_instruction_enum_vote ||
140 0 : vote_instruction->discriminant==fd_vote_instruction_enum_vote_switch ||
141 0 : vote_instruction->discriminant==fd_vote_instruction_enum_update_vote_state ||
142 0 : vote_instruction->discriminant==fd_vote_instruction_enum_update_vote_state_switch ||
143 0 : vote_instruction->discriminant==fd_vote_instruction_enum_compact_update_vote_state ||
144 0 : vote_instruction->discriminant==fd_vote_instruction_enum_compact_update_vote_state_switch ||
145 0 : vote_instruction->discriminant==fd_vote_instruction_enum_tower_sync ||
146 0 : vote_instruction->discriminant==fd_vote_instruction_enum_tower_sync_switch );
147 : // Oddly, trailing garbage is allowed here at the end of the instruction
148 0 : return 1;
149 0 : }
150 :
151 : static int
152 : deser_vote_txn( fd_gossip_vote_t * vote,
153 : uchar const ** payload,
154 0 : ulong * payload_sz ) {
155 0 : uchar const * payload_start = *payload;
156 :
157 0 : ushort signatures_len;
158 0 : READ_U16_VARINT( signatures_len, payload, payload_sz );
159 0 : SKIP_BYTES( signatures_len*64UL, payload, payload_sz );
160 0 : uchar num_required_signatures, num_readonly_signed_accounts, num_readonly_unsigned_accounts;
161 0 : READ_U8( num_required_signatures, payload, payload_sz );
162 0 : READ_U8( num_readonly_signed_accounts, payload, payload_sz );
163 0 : READ_U8( num_readonly_unsigned_accounts, payload, payload_sz );
164 0 : ushort account_keys_len;
165 0 : READ_U16_VARINT( account_keys_len, payload, payload_sz );
166 0 : uchar const * account_keys = *payload;
167 0 : SKIP_BYTES( account_keys_len*32UL, payload, payload_sz );
168 0 : SKIP_BYTES( 32UL, payload, payload_sz ); /* recent blockhash */
169 0 : ushort instructions_len;
170 0 : READ_U16_VARINT( instructions_len, payload, payload_sz );
171 0 : for( ulong i=0UL; i<instructions_len; i++ ) {
172 0 : uchar program_id_index;
173 0 : READ_U8( program_id_index, payload, payload_sz );
174 0 : CHECK( program_id_index<account_keys_len );
175 0 : CHECK( program_id_index );
176 0 : ushort accounts_len;
177 0 : READ_U16_VARINT( accounts_len, payload, payload_sz );
178 0 : for( ulong j=0UL; j<accounts_len; j++ ) {
179 0 : uchar account_index;
180 0 : READ_U8( account_index, payload, payload_sz );
181 0 : CHECK( account_index<account_keys_len );
182 0 : }
183 0 : ushort data_len;
184 0 : READ_U16_VARINT( data_len, payload, payload_sz );
185 0 : uchar data[ 1232UL ];
186 0 : READ_BYTES( data, data_len, payload, payload_sz );
187 0 : if( FD_LIKELY( i==0UL ) ) {
188 0 : CHECK( accounts_len );
189 0 : uchar const * account_key = account_keys+32UL*program_id_index;
190 0 : CHECK( !memcmp( account_key, fd_solana_vote_program_id.uc, 32UL ) );
191 0 : CHECK( deser_vote_instruction( data, data_len ) );
192 0 : }
193 0 : }
194 :
195 0 : CHECK( num_required_signatures<=signatures_len );
196 0 : CHECK( signatures_len<=account_keys_len );
197 0 : CHECK( num_required_signatures+num_readonly_unsigned_accounts<=account_keys_len );
198 0 : CHECK( num_readonly_signed_accounts<num_required_signatures );
199 0 : CHECK( instructions_len );
200 :
201 0 : vote->transaction_len = (ulong)(*payload-payload_start);
202 0 : fd_memcpy( vote->transaction, payload_start, vote->transaction_len );
203 0 : return 1;
204 0 : }
205 :
206 : static int
207 : deser_vote( fd_gossip_value_t * value,
208 : uchar const ** payload,
209 0 : ulong * payload_sz ) {
210 0 : READ_U8( value->vote->index, payload, payload_sz );
211 0 : CHECK( value->vote->index<FD_GOSSIP_VOTE_IDX_MAX );
212 0 : READ_BYTES( value->origin, 32UL, payload, payload_sz );
213 :
214 0 : CHECK( deser_vote_txn( value->vote, payload, payload_sz ) );
215 0 : READ_WALLCLOCK( value->wallclock, payload, payload_sz );
216 0 : return 1;
217 0 : }
218 :
219 : static int
220 : deser_lowest_slot( fd_gossip_value_t * value,
221 : uchar const ** payload,
222 0 : ulong * payload_sz ) {
223 0 : uchar ix;
224 0 : READ_U8( ix, payload, payload_sz );
225 0 : CHECK( !ix );
226 0 : READ_BYTES( value->origin, 32UL, payload, payload_sz );
227 0 : ulong root;
228 0 : READ_U64( root, payload, payload_sz );
229 0 : CHECK( !root );
230 0 : ulong lowest;
231 0 : READ_U64( lowest, payload, payload_sz );
232 0 : CHECK( lowest<MAX_SLOT );
233 0 : ulong slots_len;
234 0 : READ_U64( slots_len, payload, payload_sz );
235 0 : CHECK( !slots_len );
236 0 : ulong stash_len;
237 0 : READ_U64( stash_len, payload, payload_sz );
238 0 : CHECK( !stash_len );
239 0 : READ_WALLCLOCK( value->wallclock, payload, payload_sz );
240 0 : return 1;
241 0 : }
242 :
243 : static int
244 : deser_bitvec_u8_epoch_slots( uchar const ** payload,
245 0 : ulong * payload_sz ) {
246 0 : uchar has_bits;
247 0 : READ_OPTION( has_bits, payload, payload_sz );
248 0 : if( FD_UNLIKELY( !has_bits ) ) {
249 0 : ulong bits_cnt;
250 0 : READ_U64( bits_cnt, payload, payload_sz );
251 0 : CHECK( !bits_cnt );
252 0 : return 1;
253 0 : }
254 :
255 0 : ulong bits_cap;
256 0 : READ_U64( bits_cap, payload, payload_sz );
257 0 : CHECK( bits_cap );
258 0 : SKIP_BYTES( bits_cap, payload, payload_sz );
259 0 : ulong bits_cnt;
260 0 : READ_U64( bits_cnt, payload, payload_sz );
261 0 : CHECK( bits_cnt==bits_cap*8UL );
262 0 : return 1;
263 0 : }
264 :
265 : static int
266 : deser_epoch_slots( fd_gossip_value_t * value,
267 : uchar const ** payload,
268 0 : ulong * payload_sz ) {
269 0 : READ_U8( value->epoch_slots->index, payload, payload_sz );
270 0 : CHECK( value->epoch_slots->index<FD_GOSSIP_EPOCH_SLOTS_IDX_MAX );
271 0 : READ_BYTES( value->origin, 32UL, payload, payload_sz );
272 0 : ulong slots_len;
273 0 : READ_U64( slots_len, payload, payload_sz );
274 0 : for( ulong i=0UL; i<slots_len; i++ ) {
275 0 : uint is_uncompressed;
276 0 : READ_ENUM( is_uncompressed, 2UL, payload, payload_sz );
277 0 : ulong first_slot;
278 0 : READ_U64( first_slot, payload, payload_sz );
279 0 : CHECK( first_slot<MAX_SLOT );
280 0 : ulong num;
281 0 : READ_U64( num, payload, payload_sz );
282 0 : CHECK( num<MAX_SLOTS_PER_EPOCH_SLOT );
283 0 : if( FD_UNLIKELY( is_uncompressed ) ) {
284 0 : CHECK( deser_bitvec_u8_epoch_slots( payload, payload_sz ) );
285 0 : } else {
286 0 : ulong compressed_len;
287 0 : READ_U64( compressed_len, payload, payload_sz );
288 0 : SKIP_BYTES( compressed_len, payload, payload_sz );
289 0 : }
290 0 : }
291 0 : READ_WALLCLOCK( value->wallclock, payload, payload_sz );
292 0 : return 1;
293 0 : }
294 :
295 : static int
296 : deser_duplicate_shred( fd_gossip_value_t * value,
297 : uchar const ** payload,
298 0 : ulong * payload_sz ) {
299 0 : READ_U16( value->duplicate_shred->index, payload, payload_sz );
300 0 : CHECK( value->duplicate_shred->index<FD_GOSSIP_DUPLICATE_SHRED_IDX_MAX );
301 0 : READ_BYTES( value->origin, 32UL, payload, payload_sz );
302 0 : READ_WALLCLOCK( value->wallclock, payload, payload_sz );
303 0 : READ_U64( value->duplicate_shred->slot, payload, payload_sz );
304 0 : SKIP_BYTES( 5UL, payload, payload_sz ); /* (unused) + shred type (unused) */
305 0 : READ_U8( value->duplicate_shred->num_chunks, payload, payload_sz );
306 0 : READ_U8( value->duplicate_shred->chunk_index, payload, payload_sz );
307 0 : CHECK( value->duplicate_shred->chunk_index<value->duplicate_shred->num_chunks );
308 0 : READ_U64( value->duplicate_shred->chunk_len, payload, payload_sz );
309 0 : READ_BYTES( value->duplicate_shred->chunk, value->duplicate_shred->chunk_len, payload, payload_sz );
310 0 : return 1;
311 0 : }
312 :
313 : static int
314 : deser_snapshot_hashes( fd_gossip_value_t * value,
315 : uchar const ** payload,
316 0 : ulong * payload_sz ) {
317 0 : READ_BYTES( value->origin, 32UL, payload, payload_sz );
318 0 : READ_U64( value->snapshot_hashes->full_slot, payload, payload_sz );
319 0 : CHECK( value->snapshot_hashes->full_slot<MAX_SLOT );
320 0 : READ_BYTES( value->snapshot_hashes->full_hash, 32UL, payload, payload_sz );
321 0 : READ_U64( value->snapshot_hashes->incremental_len, payload, payload_sz );
322 0 : for( ulong i=0UL; i<value->snapshot_hashes->incremental_len; i++ ) {
323 0 : READ_U64( value->snapshot_hashes->incremental[ i ].slot, payload, payload_sz );
324 0 : CHECK( value->snapshot_hashes->incremental[ i ].slot<MAX_SLOT );
325 0 : CHECK( value->snapshot_hashes->incremental[ i ].slot>value->snapshot_hashes->full_slot );
326 0 : READ_BYTES( value->snapshot_hashes->incremental[ i ].hash, 32UL, payload, payload_sz );
327 0 : }
328 0 : READ_WALLCLOCK( value->wallclock, payload, payload_sz );
329 0 : return 1;
330 0 : }
331 :
332 : static int
333 : deser_contact_info( fd_gossip_value_t * value,
334 : uchar const ** payload,
335 0 : ulong * payload_sz ) {
336 0 : READ_BYTES( value->origin, 32UL, payload, payload_sz );
337 0 : READ_U64_VARINT( value->wallclock, payload, payload_sz );
338 0 : CHECK( value->wallclock<WALLCLOCK_MAX_MILLIS );
339 0 : READ_U64( value->contact_info->outset, payload, payload_sz );
340 0 : READ_U16( value->contact_info->shred_version, payload, payload_sz );
341 0 : READ_U16_VARINT( value->contact_info->version.major, payload, payload_sz );
342 0 : READ_U16_VARINT( value->contact_info->version.minor, payload, payload_sz );
343 0 : READ_U16_VARINT( value->contact_info->version.patch, payload, payload_sz );
344 0 : READ_U32( value->contact_info->version.commit, payload, payload_sz );
345 0 : READ_U32( value->contact_info->version.feature_set, payload, payload_sz );
346 0 : READ_U16_VARINT( value->contact_info->version.client, payload, payload_sz );
347 :
348 : /* Tightest bounds for array sizes given network constraints.
349 :
350 : IPv6 minimum MTU = 1280
351 : IPv6 header = 40
352 : UDP header = 8
353 : PACKET_DATA_SIZE = 1232 (= 1280 - 40 - 8)
354 :
355 : Bytes consumed before addrs loop:
356 : Protocol tag(4) + from(32) + values_len(8) + signature(64) +
357 : CrdsData tag(4) + origin(32) + wallclock_varint(1) + outset(8) +
358 : shred_version(2) + major(1) + minor(1) + patch(1) + commit(4) +
359 : feature_set(4) + client(1) + addrs_len_varint(1) = 168
360 :
361 : Remaining: 1232 - 168 = 1064
362 : Each addr: READ_ENUM(4) + READ_U32(4) = 8 bytes minimum
363 : Max addrs = floor(1064/8) = 133
364 :
365 : Bytes consumed before sockets loop:
366 : (same as above) + sockets_len_varint(1) = 169
367 :
368 : Remaining: 1232 - 169 = 1063
369 : Each socket: READ_U8(1) + READ_U8(1) + READ_U16_VARINT(1) = 3 bytes minimum
370 : Max sockets = floor(1063/3) = 354 */
371 :
372 0 : #define FD_GOSSIP_CONTACT_INFO_MAX_ADDRESSES (133UL)
373 0 : #define FD_GOSSIP_CONTACT_INFO_MAX_SOCKETS (354UL)
374 :
375 0 : uint is_ip6[ FD_GOSSIP_CONTACT_INFO_MAX_ADDRESSES ];
376 0 : union {
377 0 : uint ip4;
378 0 : uchar ip6[ 16UL ];
379 0 : } ips[ FD_GOSSIP_CONTACT_INFO_MAX_ADDRESSES ];
380 :
381 0 : ulong addrs_len;
382 0 : READ_U16_VARINT( addrs_len, payload, payload_sz );
383 0 : for( ulong i=0UL; i<addrs_len; i++ ) {
384 0 : READ_ENUM( is_ip6[ i ], 2UL, payload, payload_sz );
385 0 : if( !is_ip6[ i ] ) READ_U32( ips[ i ].ip4, payload, payload_sz );
386 0 : else READ_BYTES( ips[ i ].ip6, 16UL, payload, payload_sz );
387 0 : }
388 :
389 0 : struct {
390 0 : uchar key;
391 0 : uchar index;
392 0 : ushort offset;
393 0 : } sockets[ FD_GOSSIP_CONTACT_INFO_MAX_SOCKETS ];
394 :
395 0 : ulong sockets_len;
396 0 : READ_U16_VARINT( sockets_len, payload, payload_sz );
397 0 : for( ulong i=0UL; i<sockets_len; i++ ) {
398 0 : READ_U8( sockets[ i ].key, payload, payload_sz );
399 0 : READ_U8( sockets[ i ].index, payload, payload_sz );
400 0 : READ_U16_VARINT( sockets[ i ].offset, payload, payload_sz );
401 0 : }
402 :
403 0 : ulong extensions_len;
404 0 : READ_U16_VARINT( extensions_len, payload, payload_sz );
405 0 : for( ulong i=0UL; i<extensions_len; i++ ) {
406 0 : SKIP_BYTES( 1UL, payload, payload_sz ); /* type */
407 0 : ushort bytes_len;
408 0 : READ_U16_VARINT( bytes_len, payload, payload_sz );
409 0 : SKIP_BYTES( bytes_len, payload, payload_sz );
410 0 : }
411 :
412 : /* Duplicate IPs are not allowed */
413 0 : for( ulong i=0UL; i<addrs_len; i++ ) {
414 0 : for( ulong j=0UL; j<addrs_len; j++ ) {
415 0 : if( i==j ) continue;
416 0 : if( is_ip6[ i ] != is_ip6[ j ] ) continue;
417 0 : if( FD_LIKELY( !is_ip6[ i ] ) ) CHECK( ips[ i ].ip4!=ips[ j ].ip4 );
418 0 : else CHECK( memcmp( ips[ i ].ip6, ips[ j ].ip6, 16UL ) );
419 0 : }
420 0 : }
421 :
422 : /* Each socket must reference unique key */
423 0 : int seen_socket_key[ 256UL ] = {0};
424 0 : for( ulong i=0UL; i<sockets_len; i++ ) {
425 0 : CHECK( !seen_socket_key[ sockets[ i ].key ] );
426 0 : seen_socket_key[ sockets[ i ].key ] = 1;
427 0 : }
428 :
429 : /* Each IP address must be referenced by at least one socket */
430 0 : int seen_ip_addr[ FD_GOSSIP_CONTACT_INFO_MAX_ADDRESSES ] = {0};
431 0 : for( ulong i=0UL; i<sockets_len; i++ ) {
432 0 : CHECK( sockets[ i ].index<addrs_len );
433 0 : seen_ip_addr[ sockets[ i ].index ] = 1;
434 0 : }
435 0 : for( ulong i=0UL; i<addrs_len; i++ ) CHECK( seen_ip_addr[ i ] );
436 :
437 : /* Port offsets don't overflow */
438 0 : ushort cur_port = 0U;
439 0 : for( ulong i=0UL; i<sockets_len; i++ ) {
440 0 : ushort result;
441 0 : CHECK( !__builtin_add_overflow( cur_port, sockets[ i ].offset, &result ) );
442 0 : cur_port = result;
443 0 : }
444 :
445 0 : memset( value->contact_info->sockets, 0, sizeof( value->contact_info->sockets ) );
446 :
447 0 : cur_port = 0U;
448 0 : for( ulong i=0UL; i<sockets_len; i++ ) {
449 0 : if( FD_LIKELY( sockets[ i ].key<FD_GOSSIP_CONTACT_INFO_SOCKET_CNT ) ) {
450 0 : value->contact_info->sockets[ sockets[ i ].key ].is_ipv6 = is_ip6[ sockets[ i ].index ];
451 0 : if( FD_LIKELY( !is_ip6[ sockets[ i ].index ] ) ) value->contact_info->sockets[ sockets[ i ].key ].ip4 = ips[ sockets[ i ].index ].ip4;
452 0 : else fd_memcpy( value->contact_info->sockets[ sockets[ i ].key ].ip6, ips[ sockets[ i ].index ].ip6, 16UL );
453 :
454 0 : cur_port = (ushort)(cur_port + sockets[ i ].offset);
455 0 : value->contact_info->sockets[ sockets[ i ].key ].port = fd_ushort_bswap( cur_port );
456 0 : }
457 0 : }
458 0 : return 1;
459 0 : }
460 :
461 : static int
462 : deser_bitvec_u8_restart_last_voted_fork_slots( uchar const ** payload,
463 0 : ulong * payload_sz ) {
464 0 : uchar has_bits;
465 0 : READ_OPTION( has_bits, payload, payload_sz );
466 0 : if( FD_UNLIKELY( !has_bits ) ) {
467 0 : ulong bits_cnt;
468 0 : READ_U64( bits_cnt, payload, payload_sz );
469 0 : CHECK( !bits_cnt );
470 0 : return 1;
471 0 : }
472 :
473 0 : ulong bits_cap;
474 0 : READ_U64( bits_cap, payload, payload_sz );
475 0 : CHECK( bits_cap );
476 0 : SKIP_BYTES( bits_cap, payload, payload_sz );
477 0 : ulong bits_cnt;
478 0 : READ_U64( bits_cnt, payload, payload_sz );
479 0 : CHECK( bits_cnt<=bits_cap*8UL );
480 0 : return 1;
481 0 : }
482 :
483 : static int
484 : deser_restart_last_voted_fork_slots( fd_gossip_value_t * value,
485 : uchar const ** payload,
486 0 : ulong * payload_sz ) {
487 0 : READ_BYTES( value->origin, 32UL, payload, payload_sz );
488 0 : READ_WALLCLOCK( value->wallclock, payload, payload_sz );
489 0 : uint is_raw_offsets;
490 0 : READ_ENUM( is_raw_offsets, 2UL, payload, payload_sz );
491 0 : if( FD_LIKELY( is_raw_offsets ) ) {
492 0 : CHECK( deser_bitvec_u8_restart_last_voted_fork_slots( payload, payload_sz ) );
493 0 : } else {
494 0 : ulong slots_len;
495 0 : READ_U64( slots_len, payload, payload_sz );
496 0 : for( ulong i=0UL; i<slots_len; i++ ) {
497 0 : ushort _slot;
498 0 : READ_U16_VARINT( _slot, payload, payload_sz );
499 0 : (void)_slot;
500 0 : }
501 0 : }
502 0 : SKIP_BYTES( 8UL+32UL+2UL, payload, payload_sz ); /* last voted slot + last voted hash + shred version */
503 0 : return 1;
504 0 : }
505 :
506 : static int
507 : deser_restart_heaviest_fork( fd_gossip_value_t * value,
508 : uchar const ** payload,
509 0 : ulong * payload_sz ) {
510 0 : READ_BYTES( value->origin, 32UL, payload, payload_sz );
511 0 : READ_WALLCLOCK( value->wallclock, payload, payload_sz );
512 0 : SKIP_BYTES( 8UL+32UL+8UL+2UL, payload, payload_sz ); /* last slot + last slot hash + observed stake + shred version */
513 0 : return 1;
514 0 : }
515 :
516 : static int
517 : deser_value( fd_gossip_value_t * value,
518 : uchar const ** payload,
519 0 : ulong * payload_sz ) {
520 0 : READ_BYTES( value->signature, 64UL, payload, payload_sz );
521 0 : READ_ENUM( value->tag, FD_GOSSIP_VALUE_CNT, payload, payload_sz );
522 :
523 0 : switch( value->tag ) {
524 0 : case FD_GOSSIP_VALUE_LEGACY_CONTACT_INFO: return deser_legacy_contact_info( value, payload, payload_sz );
525 0 : case FD_GOSSIP_VALUE_VOTE: return deser_vote( value, payload, payload_sz );
526 0 : case FD_GOSSIP_VALUE_LOWEST_SLOT: return deser_lowest_slot( value, payload, payload_sz );
527 0 : case FD_GOSSIP_VALUE_LEGACY_SNAPSHOT_HASHES: return 0; /* https://github.com/anza-xyz/agave/blob/9bf0e79eeebfafd72ee68660cffcaec51ea7a66a/gossip/src/crds_data.rs#L225 */
528 0 : case FD_GOSSIP_VALUE_ACCOUNT_HASHES: return 0; /* https://github.com/anza-xyz/agave/blob/9bf0e79eeebfafd72ee68660cffcaec51ea7a66a/gossip/src/crds_data.rs#L225 */
529 0 : case FD_GOSSIP_VALUE_EPOCH_SLOTS: return deser_epoch_slots( value, payload, payload_sz );
530 0 : case FD_GOSSIP_VALUE_LEGACY_VERSION: return 0; /* https://github.com/anza-xyz/agave/blob/9bf0e79eeebfafd72ee68660cffcaec51ea7a66a/gossip/src/crds_data.rs#L432 */
531 0 : case FD_GOSSIP_VALUE_VERSION: return 0; /* https://github.com/anza-xyz/agave/blob/9bf0e79eeebfafd72ee68660cffcaec51ea7a66a/gossip/src/crds_data.rs#L449 */
532 0 : case FD_GOSSIP_VALUE_NODE_INSTANCE: return 0; /* https://github.com/anza-xyz/agave/blob/9bf0e79eeebfafd72ee68660cffcaec51ea7a66a/gossip/src/crds_data.rs#L467 */
533 0 : case FD_GOSSIP_VALUE_DUPLICATE_SHRED: return deser_duplicate_shred( value, payload, payload_sz );
534 0 : case FD_GOSSIP_VALUE_SNAPSHOT_HASHES: return deser_snapshot_hashes( value, payload, payload_sz );
535 0 : case FD_GOSSIP_VALUE_CONTACT_INFO: return deser_contact_info( value, payload, payload_sz );
536 0 : case FD_GOSSIP_VALUE_RESTART_LAST_VOTED_FORK_SLOTS: return deser_restart_last_voted_fork_slots( value, payload, payload_sz );
537 0 : case FD_GOSSIP_VALUE_RESTART_HEAVIEST_FORK: return deser_restart_heaviest_fork( value, payload, payload_sz );
538 0 : default: FD_LOG_CRIT(( "impossible" ));
539 0 : }
540 0 : }
541 :
542 : static int
543 : deser_bitvec_u64( fd_gossip_bloom_t * bloom,
544 : uchar const ** payload,
545 0 : ulong * payload_sz ) {
546 0 : uchar has_bits;
547 0 : READ_OPTION( has_bits, payload, payload_sz );
548 0 : if( FD_UNLIKELY( !has_bits ) ) {
549 0 : bloom->bits_cap = 0UL;
550 0 : READ_U64( bloom->bits_len, payload, payload_sz );
551 0 : return 0; /* Bloom sanitize rejects empty bits */
552 0 : }
553 :
554 0 : READ_U64( bloom->bits_cap, payload, payload_sz );
555 0 : CHECK( bloom->bits_cap );
556 0 : ulong dummy;
557 0 : CHECK( !__builtin_mul_overflow( bloom->bits_cap, 8UL, &dummy ) );
558 0 : READ_BYTES( bloom->bits, bloom->bits_cap*8UL, payload, payload_sz );
559 0 : READ_U64( bloom->bits_len, payload, payload_sz );
560 0 : CHECK( bloom->bits_len<=bloom->bits_cap*64UL );
561 0 : CHECK( bloom->bits_len ); /* Bloom sanitize rejects empty bits */
562 0 : return 1;
563 0 : }
564 :
565 : static int
566 : deser_pull_request( fd_gossip_message_t * message,
567 : uchar const ** payload,
568 : ulong * payload_sz,
569 0 : ulong original_sz ) {
570 0 : READ_U64( message->pull_request->crds_filter->filter->keys_len, payload, payload_sz );
571 0 : for( ulong i=0UL; i<message->pull_request->crds_filter->filter->keys_len; i++ ) {
572 0 : READ_U64( message->pull_request->crds_filter->filter->keys[ i ], payload, payload_sz );
573 0 : }
574 :
575 0 : CHECK( deser_bitvec_u64( message->pull_request->crds_filter->filter, payload, payload_sz ) );
576 :
577 0 : READ_U64( message->pull_request->crds_filter->filter->num_bits_set, payload, payload_sz );
578 0 : READ_U64( message->pull_request->crds_filter->mask, payload, payload_sz );
579 0 : READ_U32( message->pull_request->crds_filter->mask_bits, payload, payload_sz );
580 :
581 0 : message->pull_request->contact_info->offset = original_sz-*payload_sz;
582 0 : CHECK( deser_value( message->pull_request->contact_info, payload, payload_sz ) );
583 0 : message->pull_request->contact_info->length = original_sz-*payload_sz-message->pull_request->contact_info->offset;
584 0 : CHECK( message->pull_request->contact_info->tag==FD_GOSSIP_VALUE_LEGACY_CONTACT_INFO ||
585 0 : message->pull_request->contact_info->tag==FD_GOSSIP_VALUE_CONTACT_INFO );
586 0 : return 1;
587 0 : }
588 :
589 : static int
590 : deser_pull_response( fd_gossip_message_t * message,
591 : uchar const ** payload,
592 : ulong * payload_sz,
593 0 : ulong original_sz ) {
594 0 : READ_BYTES( message->pull_response->from, 32UL, payload, payload_sz );
595 0 : READ_U64( message->pull_response->values_len, payload, payload_sz );
596 0 : for( ulong i=0UL; i<message->pull_response->values_len; i++ ) {
597 0 : message->pull_response->values[ i ].offset = original_sz-*payload_sz;
598 0 : CHECK( deser_value( &message->pull_response->values[ i ], payload, payload_sz ) );
599 0 : message->pull_response->values[ i ].length = original_sz-*payload_sz-message->pull_response->values[ i ].offset;
600 0 : }
601 0 : return 1;
602 0 : }
603 :
604 : static int
605 : deser_push( fd_gossip_message_t * message,
606 : uchar const ** payload,
607 : ulong * payload_sz,
608 0 : ulong original_sz ) {
609 0 : READ_BYTES( message->push->from, 32UL, payload, payload_sz );
610 0 : READ_U64( message->push->values_len, payload, payload_sz );
611 0 : for( ulong i=0UL; i<message->push->values_len; i++ ) {
612 0 : message->push->values[ i ].offset = original_sz-*payload_sz;
613 0 : CHECK( deser_value( &message->push->values[ i ], payload, payload_sz ) );
614 0 : message->push->values[ i ].length = original_sz-*payload_sz-message->push->values[ i ].offset;
615 0 : }
616 0 : return 1;
617 0 : }
618 :
619 : static int
620 : deser_prune( fd_gossip_message_t * message,
621 : uchar const ** payload,
622 0 : ulong * payload_sz ) {
623 0 : READ_BYTES( message->prune->sender, 32UL, payload, payload_sz );
624 0 : READ_BYTES( message->prune->pubkey, 32UL, payload, payload_sz );
625 0 : CHECK( !memcmp( message->prune->sender, message->prune->pubkey, 32UL ) );
626 0 : READ_U64( message->prune->prunes_len, payload, payload_sz );
627 0 : for( ulong i=0UL; i<message->prune->prunes_len; i++ ) {
628 0 : READ_BYTES( message->prune->prunes[ i ], 32UL, payload, payload_sz );
629 0 : }
630 0 : READ_BYTES( message->prune->signature, 64UL, payload, payload_sz );
631 0 : READ_BYTES( message->prune->destination, 32UL, payload, payload_sz );
632 0 : READ_WALLCLOCK( message->prune->wallclock, payload, payload_sz );
633 0 : return 1;
634 0 : }
635 :
636 : static int
637 : deser_ping( fd_gossip_message_t * message,
638 : uchar const ** payload,
639 0 : ulong * payload_sz ) {
640 0 : READ_BYTES( message->ping->from, 32UL, payload, payload_sz );
641 0 : READ_BYTES( message->ping->token, 32UL, payload, payload_sz );
642 0 : READ_BYTES( message->ping->signature, 64UL, payload, payload_sz );
643 0 : return 1;
644 0 : }
645 :
646 : static int
647 : deser_pong( fd_gossip_message_t * message,
648 : uchar const ** payload,
649 0 : ulong * payload_sz ) {
650 0 : READ_BYTES( message->pong->from, 32UL, payload, payload_sz );
651 0 : READ_BYTES( message->pong->hash, 32UL, payload, payload_sz );
652 0 : READ_BYTES( message->pong->signature, 64UL, payload, payload_sz );
653 0 : return 1;
654 0 : }
655 :
656 : int
657 : fd_gossip_message_deserialize( fd_gossip_message_t * message,
658 : uchar const * _payload,
659 0 : ulong _payload_sz ) {
660 0 : uchar const ** payload = &_payload;
661 0 : ulong * payload_sz = &_payload_sz;
662 0 : ulong original_sz = _payload_sz;
663 :
664 0 : CHECK( _payload_sz<=1232UL );
665 0 : READ_ENUM( message->tag, FD_GOSSIP_MESSAGE_CNT, payload, payload_sz );
666 :
667 0 : switch( message->tag ){
668 0 : case FD_GOSSIP_MESSAGE_PULL_REQUEST: CHECK( deser_pull_request( message, payload, payload_sz, original_sz ) ); break;
669 0 : case FD_GOSSIP_MESSAGE_PULL_RESPONSE: CHECK( deser_pull_response( message, payload, payload_sz, original_sz ) ); break;
670 0 : case FD_GOSSIP_MESSAGE_PUSH: CHECK( deser_push( message, payload, payload_sz, original_sz ) ); break;
671 0 : case FD_GOSSIP_MESSAGE_PRUNE: CHECK( deser_prune( message, payload, payload_sz ) ); break;
672 0 : case FD_GOSSIP_MESSAGE_PING: CHECK( deser_ping( message, payload, payload_sz ) ); break;
673 0 : case FD_GOSSIP_MESSAGE_PONG: CHECK( deser_pong( message, payload, payload_sz ) ); break;
674 0 : default: FD_LOG_CRIT(( "invalid message tag" ));
675 0 : }
676 :
677 0 : return !*payload_sz;
678 0 : }
679 :
680 0 : #define CHECK1( cond ) do { \
681 0 : if( FD_UNLIKELY( !(cond) ) ) return -1; \
682 0 : } while( 0 )
683 :
684 0 : #define WRITE_BYTES( src, src_sz, out, out_sz ) do { \
685 0 : CHECK1( *out_sz>=src_sz ); \
686 0 : fd_memcpy( *out, src, src_sz ); \
687 0 : (*out) += src_sz; \
688 0 : (*out_sz) -= src_sz; \
689 0 : } while( 0 )
690 :
691 0 : #define WRITE_SKIP_BYTES( skip_sz, out, out_sz ) do { \
692 0 : CHECK1( *out_sz>=skip_sz ); \
693 0 : (*out) += skip_sz; \
694 0 : (*out_sz) -= skip_sz; \
695 0 : } while( 0 )
696 :
697 0 : #define WRITE_U8( val, out, out_sz ) do { \
698 0 : CHECK1( *out_sz>=1UL ); \
699 0 : FD_STORE( uchar, *out, val ); \
700 0 : (*out) += 1UL; \
701 0 : (*out_sz) -= 1UL; \
702 0 : } while( 0 )
703 :
704 0 : #define WRITE_U16( val, out, out_sz ) do { \
705 0 : CHECK1( *out_sz>=2UL ); \
706 0 : FD_STORE( ushort, *out, val ); \
707 0 : (*out) += 2UL; \
708 0 : (*out_sz) -= 2UL; \
709 0 : } while( 0 )
710 :
711 0 : #define WRITE_U32( val, out, out_sz ) do { \
712 0 : CHECK1( *out_sz>=4UL ); \
713 0 : FD_STORE( uint, *out, val ); \
714 0 : (*out) += 4UL; \
715 0 : (*out_sz) -= 4UL; \
716 0 : } while( 0 )
717 :
718 0 : #define WRITE_U64( val, out, out_sz ) do { \
719 0 : CHECK1( *out_sz>=8UL ); \
720 0 : FD_STORE( ulong, *out, val ); \
721 0 : (*out) += 8UL; \
722 0 : (*out_sz) -= 8UL; \
723 0 : } while( 0 )
724 :
725 0 : #define WRITE_U16_VARINT( val, out, out_sz ) do { \
726 0 : ushort _val = (val); \
727 0 : if( FD_LIKELY( _val<128U ) ) { \
728 0 : CHECK1( *(out_sz)>=1UL ); \
729 0 : FD_STORE( uchar, *out, (uchar)_val ); \
730 0 : (*out) += 1UL; \
731 0 : (*out_sz) -= 1UL; \
732 0 : } else if( FD_LIKELY( _val<16384U ) ) { \
733 0 : CHECK1( *out_sz>=2UL ); \
734 0 : FD_STORE( uchar, (*out), (uchar)((_val&0x7FU)|0x80U) ); \
735 0 : FD_STORE( uchar, (*out)+1, (uchar)(_val>>7U) ); \
736 0 : (*out) += 2UL; \
737 0 : (*out_sz) -= 2UL; \
738 0 : } else { \
739 0 : CHECK1( *out_sz>=3UL ); \
740 0 : FD_STORE( uchar, (*out), (uchar)((_val&0x7FU)|0x80U) ); \
741 0 : FD_STORE( uchar, (*out)+1, (uchar)(((_val>>7U)&0x7FU)|0x80U) ); \
742 0 : FD_STORE( uchar, (*out)+2, (uchar)(_val>>14U) ); \
743 0 : (*out) += 3UL; \
744 0 : (*out_sz) -= 3UL; \
745 0 : } \
746 0 : } while( 0 )
747 :
748 0 : #define WRITE_U64_VARINT( val, out, out_sz ) do { \
749 0 : ulong _val = (val); \
750 0 : while( _val>=0x80UL ) { \
751 0 : CHECK1( *(out_sz)>=1UL ); \
752 0 : FD_STORE( uchar, *out, (uchar)((_val&0x7FUL)|0x80UL) ); \
753 0 : (*out) += 1UL; \
754 0 : (*out_sz) -= 1UL; \
755 0 : _val >>= 7; \
756 0 : } \
757 0 : CHECK1( *(out_sz)>=1UL ); \
758 0 : FD_STORE( uchar, *out, (uchar)_val ); \
759 0 : (*out) += 1UL; \
760 0 : (*out_sz) -= 1UL; \
761 0 : } while( 0 )
762 :
763 : static int
764 : ser_vote( fd_gossip_value_t const * value,
765 : uchar ** out,
766 0 : ulong * out_sz ) {
767 0 : WRITE_U8( value->vote->index, out, out_sz );
768 0 : WRITE_BYTES( value->origin, 32UL, out, out_sz );
769 0 : WRITE_BYTES( value->vote->transaction, value->vote->transaction_len, out, out_sz );
770 0 : WRITE_U64( value->wallclock, out, out_sz );
771 0 : return 1;
772 0 : }
773 :
774 : static int
775 : ser_duplicate_shred( fd_gossip_value_t const * value,
776 : uchar ** out,
777 0 : ulong * out_sz ) {
778 0 : WRITE_U16( value->duplicate_shred->index, out, out_sz );
779 0 : WRITE_BYTES( value->origin, 32UL, out, out_sz );
780 0 : WRITE_U64( value->wallclock, out, out_sz );
781 0 : WRITE_U64( value->duplicate_shred->slot, out, out_sz );
782 0 : WRITE_BYTES( "\0\0\0\0\0", 5UL, out, out_sz ); /* (unused) + shred type (unused) */
783 0 : WRITE_U8( value->duplicate_shred->num_chunks, out, out_sz );
784 0 : WRITE_U8( value->duplicate_shred->chunk_index, out, out_sz );
785 0 : WRITE_U64( value->duplicate_shred->chunk_len, out, out_sz );
786 0 : WRITE_BYTES( value->duplicate_shred->chunk, value->duplicate_shred->chunk_len, out, out_sz );
787 0 : return 1;
788 0 : }
789 :
790 : static int
791 : ser_snapshot_hashes( fd_gossip_value_t const * value,
792 : uchar ** out,
793 0 : ulong * out_sz ) {
794 0 : WRITE_BYTES( value->origin, 32UL, out, out_sz );
795 0 : WRITE_U64( value->snapshot_hashes->full_slot, out, out_sz );
796 0 : WRITE_BYTES( value->snapshot_hashes->full_hash, 32UL, out, out_sz );
797 0 : WRITE_U64( value->snapshot_hashes->incremental_len, out, out_sz );
798 0 : for( ulong i=0UL; i<value->snapshot_hashes->incremental_len; i++ ) {
799 0 : WRITE_U64( value->snapshot_hashes->incremental[ i ].slot, out, out_sz );
800 0 : WRITE_BYTES( value->snapshot_hashes->incremental[ i ].hash, 32UL, out, out_sz );
801 0 : }
802 0 : WRITE_U64( value->wallclock, out, out_sz );
803 0 : return 1;
804 0 : }
805 :
806 : static int
807 : ser_contact_info( fd_gossip_value_t const * value,
808 : uchar ** out,
809 0 : ulong * out_sz ) {
810 0 : WRITE_BYTES( value->origin, 32UL, out, out_sz );
811 0 : WRITE_U64_VARINT( value->wallclock, out, out_sz );
812 0 : WRITE_U64( value->contact_info->outset, out, out_sz );
813 0 : WRITE_U16( value->contact_info->shred_version, out, out_sz );
814 0 : WRITE_U16_VARINT( value->contact_info->version.major, out, out_sz );
815 0 : WRITE_U16_VARINT( value->contact_info->version.minor, out, out_sz );
816 0 : WRITE_U16_VARINT( value->contact_info->version.patch, out, out_sz );
817 0 : WRITE_U32( value->contact_info->version.commit, out, out_sz );
818 0 : WRITE_U32( value->contact_info->version.feature_set, out, out_sz );
819 0 : WRITE_U16_VARINT( value->contact_info->version.client, out, out_sz );
820 :
821 0 : ulong num_sockets = 0UL;
822 0 : ulong num_unique_addrs = 0UL;
823 0 : int duplicate[ FD_GOSSIP_CONTACT_INFO_SOCKET_CNT ] = {0};
824 0 : ulong address_map[ FD_GOSSIP_CONTACT_INFO_SOCKET_CNT ];
825 0 : for( ulong i=0UL; i<FD_GOSSIP_CONTACT_INFO_SOCKET_CNT; i++ ) {
826 0 : if( FD_UNLIKELY( !value->contact_info->sockets[ i ].port ) ) continue;
827 0 : num_sockets++;
828 :
829 0 : if( FD_UNLIKELY( duplicate[ i ] ) ) continue;
830 :
831 0 : address_map[ i ] = num_unique_addrs;
832 0 : num_unique_addrs++;
833 :
834 0 : for( ulong j=i+1UL; j<FD_GOSSIP_CONTACT_INFO_SOCKET_CNT; j++ ) {
835 0 : if( FD_UNLIKELY( value->contact_info->sockets[ i ].is_ipv6!=value->contact_info->sockets[ j ].is_ipv6 ) ) continue;
836 0 : if( FD_LIKELY( !value->contact_info->sockets[ i ].is_ipv6 ) ) {
837 0 : if( FD_LIKELY( value->contact_info->sockets[ i ].ip4!=value->contact_info->sockets[ j ].ip4 ) ) continue;
838 0 : } else {
839 0 : if( FD_LIKELY( memcmp( value->contact_info->sockets[ i ].ip6, value->contact_info->sockets[ j ].ip6, 16UL ) ) ) continue;
840 0 : }
841 :
842 0 : duplicate[ j ] = 1;
843 0 : address_map[ j ] = address_map[ i ];
844 0 : }
845 0 : }
846 :
847 0 : WRITE_U16_VARINT( (ushort)num_unique_addrs, out, out_sz );
848 0 : for( ulong i=0UL; i<FD_GOSSIP_CONTACT_INFO_SOCKET_CNT; i++ ) {
849 0 : if( FD_UNLIKELY( !value->contact_info->sockets[ i ].port ) ) continue;
850 0 : if( FD_UNLIKELY( duplicate[ i ] ) ) continue;
851 :
852 0 : WRITE_U32( value->contact_info->sockets[ i ].is_ipv6, out, out_sz );
853 0 : if( FD_LIKELY( !value->contact_info->sockets[ i ].is_ipv6 ) ) WRITE_U32( value->contact_info->sockets[ i ].ip4, out, out_sz );
854 0 : else WRITE_BYTES( value->contact_info->sockets[ i ].ip6, 16UL, out, out_sz );
855 0 : }
856 :
857 0 : WRITE_U16_VARINT( (ushort)num_sockets, out, out_sz );
858 :
859 0 : int already_written[ FD_GOSSIP_CONTACT_INFO_SOCKET_CNT ] = {0};
860 0 : ushort prev_port = 0U;
861 0 : for( ulong i=0UL; i<num_sockets; i++ ) {
862 0 : ulong lowest_port_index = ULONG_MAX;
863 0 : for( ulong j=0UL; j<FD_GOSSIP_CONTACT_INFO_SOCKET_CNT; j++ ) {
864 0 : if( FD_UNLIKELY( !value->contact_info->sockets[ j ].port ) ) continue;
865 0 : if( FD_UNLIKELY( already_written[ j ] ) ) continue;
866 0 : if( FD_UNLIKELY( lowest_port_index==ULONG_MAX || fd_ushort_bswap( value->contact_info->sockets[ j ].port )<fd_ushort_bswap( value->contact_info->sockets[ lowest_port_index ].port ) ) ) lowest_port_index = j;
867 0 : }
868 0 : if( FD_UNLIKELY( lowest_port_index==ULONG_MAX ) ) break;
869 0 : already_written[ lowest_port_index ] = 1;
870 :
871 0 : WRITE_U8( (uchar)lowest_port_index, out, out_sz );
872 0 : WRITE_U8( (uchar)address_map[ lowest_port_index ], out, out_sz );
873 :
874 0 : ushort port_offset = (ushort)(fd_ushort_bswap( value->contact_info->sockets[ lowest_port_index ].port )-prev_port);
875 0 : WRITE_U16_VARINT( port_offset, out, out_sz );
876 0 : prev_port = fd_ushort_bswap( value->contact_info->sockets[ lowest_port_index ].port );
877 0 : }
878 :
879 0 : WRITE_U16_VARINT( 0UL, out, out_sz ); /* extensions_len */
880 0 : return 1;
881 0 : }
882 :
883 : long
884 : fd_gossip_value_serialize( fd_gossip_value_t const * value,
885 : uchar * _out,
886 0 : ulong _out_sz ) {
887 :
888 0 : uchar ** out = &_out;
889 0 : ulong original_size = _out_sz;
890 0 : ulong * out_sz = &_out_sz;
891 :
892 0 : WRITE_BYTES( value->signature, 64UL, out, out_sz );
893 0 : WRITE_U32( value->tag, out, out_sz );
894 :
895 0 : switch( value->tag ) {
896 0 : case FD_GOSSIP_VALUE_VOTE: if( FD_UNLIKELY( -1==ser_vote( value, out, out_sz ) ) ) return -1; break;
897 0 : case FD_GOSSIP_VALUE_DUPLICATE_SHRED: if( FD_UNLIKELY( -1==ser_duplicate_shred( value, out, out_sz ) ) ) return -1; break;
898 0 : case FD_GOSSIP_VALUE_SNAPSHOT_HASHES: if( FD_UNLIKELY( -1==ser_snapshot_hashes( value, out, out_sz ) ) ) return -1; break;
899 0 : case FD_GOSSIP_VALUE_CONTACT_INFO: if( FD_UNLIKELY( -1==ser_contact_info( value, out, out_sz ) ) ) return -1; break;
900 :
901 : // UNUSED VALUES, WE DO NOT SERIALIZE THESE
902 : // case FD_GOSSIP_VALUE_LEGACY_CONTACT_INFO: return ser_legacy_contact_info( value, out, out_sz );
903 : // case FD_GOSSIP_VALUE_LOWEST_SLOT: return ser_lowest_slot( value, out, out_sz );
904 : // case FD_GOSSIP_VALUE_LEGACY_SNAPSHOT_HASHES: return ser_legacy_snapshot_hashes( value, out, out_sz );
905 : // case FD_GOSSIP_VALUE_ACCOUNT_HASHES: return ser_account_hashes( value, out, out_sz );
906 : // case FD_GOSSIP_VALUE_EPOCH_SLOTS: return ser_epoch_slots( value, out, out_sz );
907 : // case FD_GOSSIP_VALUE_LEGACY_VERSION: return ser_legacy_version( value, out, out_sz );
908 : // case FD_GOSSIP_VALUE_VERSION: return ser_version( value, out, out_sz );
909 : // case FD_GOSSIP_VALUE_RESTART_LAST_VOTED_FORK_SLOTS: return ser_restart_last_voted_fork_slots( value, out, out_sz );
910 : // case FD_GOSSIP_VALUE_RESTART_HEAVIEST_FORK: return ser_restart_heaviest_fork( value, out, out_sz );
911 0 : default: FD_LOG_CRIT(( "impossible" ));
912 0 : }
913 :
914 0 : return (long)(original_size-_out_sz);
915 0 : }
916 :
917 : long
918 : fd_gossip_pull_request_init( uchar * payload,
919 : ulong payload_sz,
920 : ulong num_keys,
921 : ulong num_bits,
922 : ulong mask,
923 : uint mask_bits,
924 : uchar const * contact_info_crds,
925 : ulong contact_info_crds_sz,
926 : ulong ** out_bloom_keys,
927 : ulong ** out_bloom_bits,
928 0 : ulong ** out_bits_set ) {
929 0 : uchar ** out = &payload;
930 0 : ulong original_size = payload_sz;
931 0 : ulong * out_sz = &payload_sz;
932 :
933 0 : WRITE_U32( FD_GOSSIP_MESSAGE_PULL_REQUEST, out, out_sz );
934 0 : WRITE_U64( num_keys, out, out_sz );
935 0 : *out_bloom_keys = fd_type_pun( payload+(payload_sz-*out_sz) );
936 0 : WRITE_SKIP_BYTES( num_keys*8UL, out, out_sz );
937 :
938 0 : if( FD_LIKELY( !!num_bits ) ) {
939 : /* Bloom bits is a bitvec<u64>, so we need to be careful about converting bloom bits count to vector lengths */
940 0 : ulong bloom_vec_len = (num_bits+63UL)/64UL;
941 0 : WRITE_U8( 1, out, out_sz ); /* has_bits */
942 0 : WRITE_U64( bloom_vec_len, out, out_sz );
943 0 : *out_bloom_bits = fd_type_pun( payload+(payload_sz-*out_sz) );
944 0 : WRITE_SKIP_BYTES( bloom_vec_len*8UL, out, out_sz );
945 0 : } else {
946 0 : WRITE_U8( 0, out, out_sz ); /* has_bits */
947 0 : *out_bloom_bits = NULL;
948 0 : }
949 0 : WRITE_U64( num_bits, out, out_sz );
950 0 : *out_bits_set = fd_type_pun( payload+(payload_sz-*out_sz) );
951 0 : WRITE_SKIP_BYTES( 8UL, out, out_sz );
952 0 : WRITE_U64( mask, out, out_sz );
953 0 : WRITE_U32( mask_bits, out, out_sz );
954 0 : WRITE_BYTES( contact_info_crds, contact_info_crds_sz, out, out_sz );
955 :
956 0 : return (long)(original_size-*out_sz);
957 0 : }
|