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