LCOV - code coverage report
Current view: top level - flamenco/gossip - fd_gossip_message.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 710 0.0 %
Date: 2026-03-19 18:19:27 Functions: 0 28 0.0 %

          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 : }

Generated by: LCOV version 1.14