LCOV - code coverage report
Current view: top level - flamenco/gossip - fd_gossip_msg_parse.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 414 0.0 %
Date: 2025-09-19 04:41:14 Functions: 0 23 0.0 %

          Line data    Source code
       1             : #include "fd_gossip_private.h"
       2             : #include "../../ballet/txn/fd_compact_u16.h"
       3             : 
       4             : /* Adapted from fd_txn_parse.c */
       5             : #define CHECK_INIT( payload, payload_sz, offset )   \
       6           0 :   uchar const * _payload        = (payload);        \
       7           0 :   ulong const   _payload_sz     = (payload_sz);     \
       8           0 :   ulong const   _offset         = (offset);         \
       9           0 :   ulong         _i              = (offset);         \
      10           0 :   (void)        _payload;                           \
      11           0 :   (void)        _offset;                            \
      12             : 
      13           0 : #define CHECK( cond ) do {              \
      14           0 :   if( FD_UNLIKELY( !(cond) ) ) {        \
      15           0 :     FD_LOG_WARNING(( "Gossip message parse error at offset %lu, size %lu: %s", _i, _payload_sz, #cond )); \
      16           0 :     return 0;                           \
      17           0 :   }                                     \
      18           0 : } while( 0 )
      19             : 
      20           0 : #define CHECK_LEFT( n ) CHECK( (n)<=(_payload_sz-_i) )
      21             : 
      22           0 : #define INC( n ) (_i += (ulong)(n))
      23             : 
      24           0 : #define CHECKED_INC( n ) do { \
      25           0 :   CHECK_LEFT( n );            \
      26           0 :   INC( n );                   \
      27           0 : } while( 0 )
      28             : 
      29             : #define READ_CHECKED_COMPACT_U16( out_sz, var_name, where )                 \
      30           0 :   do {                                                                      \
      31           0 :     ulong _where = (where);                                                 \
      32           0 :     ulong _out_sz = fd_cu16_dec_sz( _payload+_where, _payload_sz-_where );  \
      33           0 :     CHECK( _out_sz );                                                       \
      34           0 :     (var_name) = fd_cu16_dec_fixed( _payload+_where, _out_sz );             \
      35           0 :     (out_sz)   = _out_sz;                                                   \
      36           0 :   } while( 0 )
      37           0 : #define CUR_OFFSET      ((ushort)_i)
      38           0 : #define CURSOR          (_payload+_i)
      39           0 : #define BYTES_CONSUMED  (_i-_offset)
      40             : #define BYTES_REMAINING (_payload_sz-_i)
      41             : 
      42             : static ulong
      43             : decode_u64_varint( uchar const * payload,
      44             :                    ulong         payload_sz,
      45             :                    ulong         start_offset,
      46           0 :                    ulong *       out_value ) {
      47           0 :   CHECK_INIT( payload, payload_sz, start_offset );
      48           0 :   ulong value = 0UL;
      49           0 :   ulong shift = 0U;
      50           0 :   while( FD_LIKELY( _i < _payload_sz ) ) {
      51           0 :     uchar byte = FD_LOAD( uchar, CURSOR ); INC( 1U );
      52           0 :     value |= (ulong)(byte & 0x7F) << shift;
      53           0 :     if( !(byte & 0x80) ) break;
      54           0 :     shift += 7U;
      55           0 :     if( FD_UNLIKELY( shift >= 64U ) ) return 0;
      56           0 :   }
      57           0 :   *out_value = value;
      58           0 :   return BYTES_CONSUMED;
      59           0 : }
      60             : 
      61             : static ulong
      62             : fd_gossip_msg_crds_legacy_contact_info_parse( fd_gossip_view_crds_value_t * crds_val,
      63             :                                               uchar const *                 payload,
      64             :                                               ulong                         payload_sz,
      65           0 :                                               ulong                         start_offset ) {
      66           0 :   CHECK_INIT( payload, payload_sz, start_offset );
      67             :   /* https://github.com/anza-xyz/agave/blob/540d5bc56cd44e3cc61b179bd52e9a782a2c99e4/gossip/src/legacy_contact_info.rs#L13 */
      68           0 :   CHECK_LEFT( 32U ); crds_val->pubkey_off = CUR_OFFSET                                          ; INC( 32U );
      69           0 :   for( ulong i=0UL; i<10; i++ ) {
      70           0 :     CHECK_LEFT( 4U ); uint is_ip6 = FD_LOAD( uint, CURSOR )                                     ; INC(  4U );
      71           0 :     if( !is_ip6 ){
      72           0 :       CHECKED_INC( 4U+2U ); /* ip4 + port */
      73           0 :     } else {
      74           0 :       CHECKED_INC( 16U+2U+4U+4U ); /* ip6 + port + flowinfo + scope_id */
      75           0 :     }
      76           0 :   }
      77           0 :   CHECK_LEFT(  8U ); crds_val->wallclock_nanos = FD_MILLI_TO_NANOSEC( FD_LOAD( ulong, CURSOR ) ); INC(  8U );
      78           0 :   CHECKED_INC( 2U ); /* shred_version */
      79           0 :   return BYTES_CONSUMED;
      80           0 : }
      81             : 
      82             : static ulong
      83             : fd_gossip_msg_crds_vote_parse( fd_gossip_view_crds_value_t * crds_val,
      84             :                                uchar const *                 payload,
      85             :                                ulong                         payload_sz,
      86           0 :                                ulong                         start_offset ) {
      87           0 :   CHECK_INIT( payload, payload_sz, start_offset );
      88           0 :   CHECK_LEFT(  1U ); crds_val->vote->index = FD_LOAD( uchar, CURSOR )                           ; INC(  1U );
      89           0 :   CHECK_LEFT( 32U ); crds_val->pubkey_off  = CUR_OFFSET                                         ; INC( 32U );
      90           0 :   ulong transaction_sz;
      91           0 :   CHECK( fd_txn_parse_core( CURSOR, BYTES_REMAINING, NULL, NULL, &transaction_sz )!=0UL );
      92           0 :   crds_val->vote->txn_off = CUR_OFFSET;
      93           0 :   crds_val->vote->txn_sz  = transaction_sz;
      94           0 :   INC( transaction_sz );
      95           0 :   CHECK_LEFT(  8U ); crds_val->wallclock_nanos = FD_MILLI_TO_NANOSEC( FD_LOAD( ulong, CURSOR ) ); INC(  8U );
      96           0 :   return BYTES_CONSUMED;
      97           0 : }
      98             : 
      99             : static ulong
     100             : fd_gossip_msg_crds_lowest_slot_parse( fd_gossip_view_crds_value_t * crds_val,
     101             :                                       uchar const *                 payload,
     102             :                                       ulong                         payload_sz,
     103           0 :                                       ulong                         start_offset ) {
     104           0 :   CHECK_INIT( payload, payload_sz, start_offset );
     105           0 :   CHECKED_INC( 1U ); /* deprecated */
     106           0 :   CHECK_LEFT( 32U ); crds_val->pubkey_off = CUR_OFFSET                                          ; INC( 32U );
     107             : 
     108           0 :   CHECKED_INC( 8U ); /* root: deprecated */
     109             : 
     110           0 :   CHECK_LEFT(  8U ); crds_val->lowest_slot = FD_LOAD( ulong, CURSOR )                           ; INC(  8U );
     111             : 
     112             :   /* slots set is deprecated, so we skip it. */
     113           0 :   CHECK_LEFT(  8U ); ulong slots_len = FD_LOAD( ulong, CURSOR )                                 ; INC(  8U );
     114           0 :   CHECKED_INC( slots_len*8U ); /* overflowing this currently doesn't matter, but be careful */
     115             : 
     116             :   /* TODO: stash vector<EpochIncompleteSlots> is deprecated, but is hard to skip
     117             :      since EpochIncompleteSlots is a dynamically sized type. So we fail this
     118             :      parse if there are any entries. Might be worth implementing a skip instead,
     119             :      TBD after live testing.
     120             :      Idea: rip out parser from fd_types
     121             :      https://github.com/anza-xyz/agave/blob/540d5bc56cd44e3cc61b179bd52e9a782a2c99e4/gossip/src/deprecated.rs#L19 */
     122           0 :   CHECK_LEFT(  8U ); ulong stash_len = FD_LOAD( ulong, CURSOR )                                 ; INC(  8U );
     123           0 :   CHECK( stash_len==0U );
     124             : 
     125           0 :   CHECK_LEFT(  8U ); crds_val->wallclock_nanos = FD_MILLI_TO_NANOSEC( FD_LOAD( ulong, CURSOR ) ); INC(  8U );
     126           0 :   return BYTES_CONSUMED;
     127           0 : }
     128             : 
     129             : static ulong
     130             : fd_gossip_msg_crds_account_hashes_parse( fd_gossip_view_crds_value_t * crds_val,
     131             :                                          uchar const *                 payload,
     132             :                                          ulong                         payload_sz,
     133           0 :                                          ulong                         start_offset ) {
     134           0 :   CHECK_INIT( payload, payload_sz, start_offset );
     135           0 :   CHECK_LEFT( 32U ); crds_val->pubkey_off = CUR_OFFSET                                           ; INC( 32U );
     136           0 :   CHECK_LEFT(  8U ); ulong hashes_len     = FD_LOAD( ulong, CURSOR )                             ; INC(  8U );
     137           0 :   CHECKED_INC( hashes_len*32U ); /* overflowing this currently doesn't matter, but be careful */
     138             : 
     139           0 :   CHECK_LEFT(  8U );  crds_val->wallclock_nanos = FD_MILLI_TO_NANOSEC( FD_LOAD( ulong, CURSOR ) ); INC(  8U );
     140           0 :   return BYTES_CONSUMED;
     141           0 : }
     142             : 
     143             : static ulong
     144             : fd_gossip_msg_crds_epoch_slots_parse( fd_gossip_view_crds_value_t * crds_val,
     145             :                                       uchar const *                 payload,
     146             :                                       ulong                         payload_sz,
     147           0 :                                       ulong                         start_offset ) {
     148           0 :   CHECK_INIT( payload, payload_sz, start_offset );
     149           0 :   CHECK_LEFT(  1U ); crds_val->epoch_slots->index = FD_LOAD( uchar, CURSOR )                   ; INC(  1U );
     150           0 :   CHECK_LEFT( 32U ); crds_val->pubkey_off         = CUR_OFFSET                                 ; INC( 32U );
     151           0 :   CHECK_LEFT(  8U ); ulong slots_len              = FD_LOAD( ulong, CURSOR )                   ; INC(  8U );
     152             : 
     153           0 :   for( ulong i=0UL; i<slots_len; i++ ) {
     154           0 :     CHECK_LEFT( 4U ); uint is_uncompressed = FD_LOAD( uint, CURSOR )                           ; INC(  4U );
     155           0 :     if( is_uncompressed ) {
     156           0 :       CHECKED_INC( 8U+8U ); /* first_slot + num */
     157           0 :       uchar has_bits = 0;
     158           0 :       CHECK_LEFT( 1U ); has_bits = FD_LOAD( uchar, CURSOR )                                    ; INC(  1U );
     159           0 :       if( has_bits ) {
     160           0 :         CHECK_LEFT( 8U ); ulong bits_len = FD_LOAD( ulong, CURSOR )                            ; INC(  8U );
     161           0 :         CHECKED_INC( bits_len ); /* bitvec<u8> */
     162           0 :         CHECKED_INC( 8U );
     163           0 :       }
     164           0 :     } else {
     165           0 :       CHECKED_INC( 8U+8U ); /* first_slot + num */
     166           0 :       CHECK_LEFT( 8U ); ulong compressed_len = FD_LOAD( ulong, CURSOR )                        ; INC(  8U );
     167           0 :       CHECKED_INC( compressed_len ); /* compressed bitvec */
     168           0 :     }
     169           0 :   }
     170           0 :   CHECK_LEFT( 8U ); crds_val->wallclock_nanos = FD_MILLI_TO_NANOSEC( FD_LOAD( ulong, CURSOR ) ); INC(  8U );
     171             : 
     172           0 :   return BYTES_CONSUMED;
     173           0 : }
     174             : 
     175             : static ulong
     176             : fd_gossip_msg_crds_legacy_version_parse( fd_gossip_view_crds_value_t * crds_val,
     177             :                                          uchar const *                 payload,
     178             :                                          ulong                         payload_sz,
     179           0 :                                          ulong                         start_offset ) {
     180           0 :   CHECK_INIT( payload, payload_sz, start_offset );
     181           0 :   CHECK_LEFT( 32U ); crds_val->pubkey_off      = CUR_OFFSET                                     ; INC( 32U );
     182           0 :   CHECK_LEFT(  8U ); crds_val->wallclock_nanos = FD_MILLI_TO_NANOSEC( FD_LOAD( ulong, CURSOR ) ); INC(  8U );
     183             : 
     184           0 :   CHECKED_INC( 3*2U ); /* major, minor, patch (all u16s)*/
     185           0 :   CHECK_LEFT(    1U ); uchar has_commit = FD_LOAD( uchar, CURSOR )                              ; INC(  1U );
     186           0 :   if( has_commit ) {
     187           0 :     CHECKED_INC( 4U );
     188           0 :   }
     189           0 :   return BYTES_CONSUMED;
     190           0 : }
     191             : 
     192             : static ulong
     193             : fd_gossip_msg_crds_version_parse( fd_gossip_view_crds_value_t * crds_val,
     194             :                                   uchar const *                 payload,
     195             :                                   ulong                         payload_sz,
     196           0 :                                   ulong                         start_offset ) {
     197           0 :   CHECK_INIT( payload, payload_sz, start_offset );
     198           0 :   INC( fd_gossip_msg_crds_legacy_version_parse( crds_val, payload, payload_sz, start_offset ) );
     199           0 :   CHECKED_INC( 4U ); /* feature set */
     200           0 :   return BYTES_CONSUMED;
     201           0 : }
     202             : 
     203             : static ulong
     204             : fd_gossip_msg_crds_node_instance_parse( fd_gossip_view_crds_value_t * crds_val,
     205             :                                         uchar const *                 payload,
     206             :                                         ulong                         payload_sz,
     207           0 :                                         ulong                         start_offset ) {
     208           0 :   CHECK_INIT( payload, payload_sz, start_offset );
     209           0 :   CHECK_LEFT( 32U ); crds_val->pubkey_off           = CUR_OFFSET                                     ; INC( 32U );
     210           0 :   CHECK_LEFT(  8U ); crds_val->wallclock_nanos      = FD_MILLI_TO_NANOSEC( FD_LOAD( ulong, CURSOR ) ); INC(  8U );
     211           0 :   CHECKED_INC( 8U ); /* timestamp (currently unused) */
     212           0 :   CHECK_LEFT(  8U ); crds_val->node_instance->token = FD_LOAD( ulong, CURSOR )                       ; INC(  8U );
     213           0 :   return BYTES_CONSUMED;
     214           0 : }
     215             : 
     216             : static ulong
     217             : fd_gossip_msg_crds_duplicate_shred_parse( fd_gossip_view_crds_value_t * crds_val,
     218             :                                           uchar const *                 payload,
     219             :                                           ulong                         payload_sz,
     220           0 :                                           ulong                         start_offset ) {
     221           0 :   fd_gossip_view_duplicate_shred_t * ds = crds_val->duplicate_shred;
     222             : 
     223           0 :   CHECK_INIT( payload, payload_sz, start_offset );
     224             : 
     225           0 :   CHECK_LEFT(            2U ); ds->index = FD_LOAD( ushort, CURSOR )                                      ; INC(            2U );
     226           0 :   CHECK_LEFT(           32U ); crds_val->pubkey_off = CUR_OFFSET                                          ; INC(           32U );
     227           0 :   CHECK_LEFT(            8U ); crds_val->wallclock_nanos = FD_MILLI_TO_NANOSEC( FD_LOAD( ulong, CURSOR ) ); INC(            8U );
     228           0 :   CHECK_LEFT(            8U ); ds->slot = FD_LOAD( ulong, CURSOR )                                        ; INC(            8U );
     229           0 :   CHECKED_INC(        4U+1U ); /* (unused) + shred type (unused) */
     230           0 :   CHECK_LEFT(            1U ); ds->num_chunks  = FD_LOAD( uchar, CURSOR )                                 ; INC(            1U );
     231           0 :   CHECK_LEFT(            1U ); ds->chunk_index = FD_LOAD( uchar, CURSOR )                                 ; INC(            1U );
     232           0 :   CHECK_LEFT(            8U ); ds->chunk_len   = FD_LOAD( ulong, CURSOR )                                 ; INC(            8U );
     233           0 :   CHECK_LEFT( ds->chunk_len ); ds->chunk_off   = CUR_OFFSET                                               ; INC( ds->chunk_len );
     234           0 :   return BYTES_CONSUMED;
     235           0 : }
     236             : 
     237             : static ulong
     238             : fd_gossip_msg_crds_snapshot_hashes_parse( fd_gossip_view_crds_value_t * crds_val,
     239             :                                           uchar const *                 payload,
     240             :                                           ulong                         payload_sz,
     241           0 :                                           ulong                         start_offset ) {
     242           0 :   CHECK_INIT( payload, payload_sz, start_offset );
     243           0 :   CHECK_LEFT(                 32U ); crds_val->pubkey_off = CUR_OFFSET                                          ; INC(                 32U );
     244           0 :   CHECK_LEFT(                 40U ); crds_val->snapshot_hashes->full_off = CUR_OFFSET                           ; INC(                 40U );
     245           0 :   CHECK_LEFT(                  8U ); ulong incremental_len = FD_LOAD( ulong, CURSOR )                           ; INC(                  8U );
     246           0 :   CHECK_LEFT( incremental_len*40U ); crds_val->snapshot_hashes->inc_off = CUR_OFFSET                            ; INC( incremental_len*40U );
     247           0 :   CHECK_LEFT(                  8U ); crds_val->wallclock_nanos = FD_MILLI_TO_NANOSEC( FD_LOAD( ulong, CURSOR ) ); INC(                  8U );
     248           0 :   crds_val->snapshot_hashes->inc_len = incremental_len;
     249           0 :   return BYTES_CONSUMED;
     250           0 : }
     251             : 
     252             : static ulong
     253             : version_parse( fd_contact_info_t * ci,
     254             :                uchar const *       payload,
     255             :                ulong               payload_sz,
     256           0 :                ulong               start_offset ) {
     257           0 :   CHECK_INIT( payload, payload_sz, start_offset );
     258           0 :   ulong decode_sz;
     259           0 :   READ_CHECKED_COMPACT_U16( decode_sz, ci->version.major, CUR_OFFSET ) ; INC( decode_sz );
     260           0 :   READ_CHECKED_COMPACT_U16( decode_sz, ci->version.minor, CUR_OFFSET ) ; INC( decode_sz );
     261           0 :   READ_CHECKED_COMPACT_U16( decode_sz, ci->version.patch, CUR_OFFSET ) ; INC( decode_sz );
     262           0 :   CHECK_LEFT( 4U ); ci->version.commit      = FD_LOAD( uint, CURSOR )  ; INC( 4U );
     263           0 :   CHECK_LEFT( 4U ); ci->version.feature_set = FD_LOAD( uint, CURSOR )  ; INC( 4U );
     264           0 :   READ_CHECKED_COMPACT_U16( decode_sz, ci->version.client, CUR_OFFSET ); INC( decode_sz );
     265           0 :   return BYTES_CONSUMED;
     266           0 : }
     267             : 
     268             : /* Contact Infos are checked for the following properties
     269             :    - All addresses in addrs are unique
     270             :    - Each socket entry references a unique socket tag
     271             :    - Socket offsets do not cause an overflow
     272             :    - All addresses are referenced at least once across all sockets
     273             :    https://github.com/anza-xyz/agave/blob/540d5bc56cd44e3cc61b179bd52e9a782a2c99e4/gossip/src/contact_info.rs#L599
     274             : 
     275             :    We perform additional checks when populating the
     276             :    contact_info->sockets array:
     277             :    - Address must be ipv4
     278             :    - Socket tag must fall within range of tags defined in
     279             :      fd_gossip_types.c (bounded by FD_CONTACT_INFO_SOCKET_LAST)
     280             : 
     281             :   Note that these additional checks are not parser failure conditions.
     282             :   These sockets are simply skipped when populating
     283             :   contact_info->sockets (marked as null entries). The CRDS value is
     284             :   considered valid and is still processed into the CRDS table. */
     285             : 
     286             : #define SET_NAME ip4_seen_set
     287           0 : #define SET_MAX  (1<<15)
     288             : #include "../../util/tmpl/fd_set.c"
     289             : 
     290             : #define SET_NAME ip6_seen_set
     291           0 : #define SET_MAX  (1<<14)
     292             : #include "../../util/tmpl/fd_set.c"
     293             : 
     294             : struct ipv6_addr {
     295             :   ulong hi;
     296             :   ulong lo;
     297             : };
     298             : 
     299             : typedef struct ipv6_addr ipv6_addr_t;
     300             : 
     301             : static inline ulong
     302           0 : ipv6_hash( ipv6_addr_t const * addr ) {
     303           0 : return fd_ulong_hash( addr->hi ^ fd_ulong_hash( addr->lo ) );
     304           0 : }
     305             : 
     306             : /* Existing sets for socket validation */
     307             : #define SET_NAME addr_idx_set
     308             : #define SET_MAX  FD_GOSSIP_CONTACT_INFO_MAX_ADDRESSES
     309             : #include "../../util/tmpl/fd_set.c"
     310             : 
     311             : #define SET_NAME socket_tag_set
     312             : #define SET_MAX  FD_GOSSIP_CONTACT_INFO_MAX_SOCKETS
     313             : #include "../../util/tmpl/fd_set.c"
     314             : 
     315             : static ulong
     316             : fd_gossip_msg_crds_contact_info_parse( fd_gossip_view_crds_value_t * crds_val,
     317             :                                        uchar const *                 payload,
     318             :                                        ulong                         payload_sz,
     319           0 :                                        ulong                         start_offset ) {
     320           0 :   CHECK_INIT( payload, payload_sz, start_offset );
     321           0 :   CHECK_LEFT( 32U ); crds_val->pubkey_off = CUR_OFFSET                                                     ; INC( 32U );
     322           0 :   ulong wallclock = 0UL;
     323           0 :   INC( decode_u64_varint( payload, payload_sz, CUR_OFFSET, &wallclock ) );
     324           0 :   crds_val->wallclock_nanos = FD_MILLI_TO_NANOSEC( wallclock );
     325             : 
     326           0 :   fd_contact_info_t * ci = crds_val->ci_view->contact_info;
     327           0 :   fd_memcpy( ci->pubkey.uc, payload + crds_val->pubkey_off, 32UL );
     328           0 :   ci->wallclock_nanos = crds_val->wallclock_nanos;
     329             : 
     330           0 :   CHECK_LEFT( 8U ); ci->instance_creation_wallclock_nanos = FD_MICRO_TO_NANOSEC( FD_LOAD( ulong, CURSOR ) ); INC(  8U );
     331           0 :   CHECK_LEFT( 2U ); ci->shred_version = FD_LOAD( ushort, CURSOR )                                          ; INC(  2U );
     332           0 :   INC( version_parse( ci, payload, payload_sz, CUR_OFFSET ) );
     333             : 
     334           0 :   ulong decode_sz, addrs_len;
     335           0 :   READ_CHECKED_COMPACT_U16( decode_sz, addrs_len, CUR_OFFSET )                                             ; INC( decode_sz );
     336           0 :   CHECK( addrs_len<=FD_GOSSIP_CONTACT_INFO_MAX_ADDRESSES );
     337             : 
     338           0 :   ip4_seen_set_t ip4_seen[ ip4_seen_set_word_cnt ];
     339           0 :   ip6_seen_set_t ip6_seen[ ip6_seen_set_word_cnt ];
     340           0 :   ip4_seen_set_new( ip4_seen );
     341           0 :   ip6_seen_set_new( ip6_seen );
     342             : 
     343           0 :   uint ip4_addrs[ FD_GOSSIP_CONTACT_INFO_MAX_ADDRESSES ];
     344             : 
     345           0 :   for( ulong i=0UL; i<addrs_len; i++ ) {
     346           0 :     CHECK_LEFT( 4U ); uchar is_ip6 = FD_LOAD( uchar, CURSOR )                                              ; INC( 4U );
     347           0 :     if( FD_LIKELY( !is_ip6 ) ) {
     348           0 :       CHECK_LEFT( 4U ); ip4_addrs[ i ] = FD_LOAD( uint, CURSOR )                                           ; INC( 4U );
     349           0 :       ulong idx = fd_uint_hash( ip4_addrs[ i ] )&(ip4_seen_set_max( ip4_seen )-1);
     350           0 :       CHECK( !ip4_seen_set_test( ip4_seen, idx ) ); /* Should not be set initially */
     351           0 :       ip4_seen_set_insert( ip4_seen, idx );
     352           0 :     } else {
     353             :       /* TODO: Support IPv6 ... */
     354           0 :       CHECK_LEFT( 16U ); ipv6_addr_t * ip6_addr = (ipv6_addr_t *)CURSOR                                    ; INC( 16U );
     355           0 :       ulong idx = ipv6_hash( ip6_addr )&(ip6_seen_set_max( ip6_seen )-1);
     356           0 :       CHECK( !ip6_seen_set_test( ip6_seen, idx ) );
     357           0 :       ip6_seen_set_insert( ip6_seen, idx );
     358           0 :       ip4_addrs[ i ] = 0U; /* Mark as null entry */
     359           0 :     }
     360           0 :   }
     361           0 :   crds_val->ci_view->ip6_cnt = ip6_seen_set_cnt( ip6_seen );
     362             : 
     363           0 :   addr_idx_set_t ip_addr_hits[ addr_idx_set_word_cnt ];
     364           0 :   socket_tag_set_t socket_tag_hits[ socket_tag_set_word_cnt ];
     365           0 :   addr_idx_set_new( ip_addr_hits );
     366           0 :   socket_tag_set_new( socket_tag_hits );
     367             : 
     368           0 :   ulong sockets_len;
     369           0 :   READ_CHECKED_COMPACT_U16( decode_sz, sockets_len, CUR_OFFSET )                                           ; INC( decode_sz );
     370           0 :   CHECK( sockets_len<=FD_GOSSIP_CONTACT_INFO_MAX_SOCKETS );
     371             : 
     372           0 :   fd_memset( ci->sockets, 0, (FD_CONTACT_INFO_SOCKET_LAST+1UL)*sizeof(fd_ip4_port_t) );
     373           0 :   crds_val->ci_view->unrecognized_socket_tag_cnt = 0UL;
     374             : 
     375           0 :   ushort cur_port = 0U;
     376           0 :   for( ulong i=0UL; i<sockets_len; i++ ) {
     377           0 :     uchar tag, addr_idx;
     378           0 :     CHECK_LEFT( 1U ); tag      = FD_LOAD( uchar, CURSOR )                                                  ; INC( 1U );
     379           0 :     CHECK_LEFT( 1U ); addr_idx = FD_LOAD( uchar, CURSOR )                                                  ; INC( 1U );
     380             : 
     381           0 :     ushort offset;
     382           0 :     READ_CHECKED_COMPACT_U16( decode_sz, offset, CUR_OFFSET )                                              ; INC( decode_sz );
     383           0 :     CHECK( ((uint)cur_port + (uint)offset)<=(uint)USHORT_MAX ); /* overflow check */
     384           0 :     cur_port = (ushort)(cur_port + offset);
     385           0 :     CHECK( !socket_tag_set_test( socket_tag_hits, tag ) ); socket_tag_set_insert( socket_tag_hits, tag );
     386           0 :     CHECK( addr_idx<addrs_len );
     387           0 :     addr_idx_set_insert( ip_addr_hits, addr_idx );
     388             : 
     389           0 :     if( FD_LIKELY( tag<=FD_CONTACT_INFO_SOCKET_LAST ) ) {
     390           0 :       if( FD_UNLIKELY( !!ip4_addrs[ addr_idx ] ) ) {
     391           0 :         ci->sockets[ tag ].addr = ip4_addrs[ addr_idx ];
     392           0 :         ci->sockets[ tag ].port = fd_ushort_bswap( cur_port ); /* TODO: change this to host order */
     393           0 :       }
     394           0 :     } else {
     395           0 :       crds_val->ci_view->unrecognized_socket_tag_cnt++;
     396           0 :     }
     397           0 :   }
     398           0 :   CHECK( addr_idx_set_cnt( ip_addr_hits )==addrs_len );
     399             : 
     400             :   /* extensions are currently unused */
     401           0 :   READ_CHECKED_COMPACT_U16( decode_sz, crds_val->ci_view->ext_len, CUR_OFFSET )                            ; INC( decode_sz );
     402           0 :   CHECKED_INC( 4*crds_val->ci_view->ext_len );
     403             : 
     404           0 :   return BYTES_CONSUMED;
     405           0 : }
     406             : 
     407             : static ulong
     408             : fd_gossip_msg_crds_last_voted_fork_slots_parse( fd_gossip_view_crds_value_t * crds_val,
     409             :                                                 uchar const *                 payload,
     410             :                                                 ulong                         payload_sz,
     411           0 :                                                 ulong                         start_offset ) {
     412           0 :   CHECK_INIT( payload, payload_sz, start_offset );
     413           0 :   CHECK_LEFT( 32U ); crds_val->pubkey_off      = CUR_OFFSET                                     ; INC( 32U );
     414           0 :   CHECK_LEFT(  8U ); crds_val->wallclock_nanos = FD_MILLI_TO_NANOSEC( FD_LOAD( ulong, CURSOR ) ); INC( 8U );
     415           0 :   CHECK_LEFT(  4U ); uint is_rawoffsets        = FD_LOAD( uint, CURSOR )                        ; INC( 4U );
     416           0 :   if( !is_rawoffsets ) {
     417           0 :     CHECK_LEFT( 8U ); ulong slots_len = FD_LOAD( ulong, CURSOR )                                ; INC( 8U );
     418           0 :     CHECKED_INC( slots_len*4U ); /* RunLengthEncoding */
     419           0 :   } else {
     420           0 :     CHECK_LEFT( 1U ); uchar has_bits = FD_LOAD( uchar, CURSOR )                                 ; INC( 1U );
     421           0 :     if( has_bits ) {
     422           0 :       CHECK_LEFT( 8U ); ulong bits_len = FD_LOAD( ulong, CURSOR )                               ; INC( 8U );
     423           0 :       CHECKED_INC( bits_len ); /* bitvec<u8 > */
     424           0 :       CHECKED_INC( 8U ); /* bits num set */
     425           0 :     }
     426           0 :   }
     427           0 :   CHECKED_INC(  8U+32U+2U ); /* last voted slot + last voted hash + shred version */
     428           0 :   return BYTES_CONSUMED;
     429           0 : }
     430             : 
     431             : static ulong
     432             : fd_gossip_msg_crds_restart_heaviest_fork_parse( fd_gossip_view_crds_value_t * crds_val,
     433             :                                                 uchar const *                 payload,
     434             :                                                 ulong                         payload_sz,
     435           0 :                                                 ulong                         start_offset ) {
     436           0 :   CHECK_INIT( payload, payload_sz, start_offset );
     437           0 :   CHECK_LEFT(  32U ); crds_val->pubkey_off      = CUR_OFFSET                                     ; INC( 32U );
     438           0 :   CHECK_LEFT(   8U ); crds_val->wallclock_nanos = FD_MILLI_TO_NANOSEC( FD_LOAD( ulong, CURSOR ) ); INC( 8U );
     439           0 :   CHECKED_INC(  8U+32U+8U+2U ); /* last slot + last slot hash + observed stake + shred version */
     440           0 :   return BYTES_CONSUMED;
     441           0 : }
     442             : 
     443             : 
     444             : static ulong
     445             : fd_gossip_msg_crds_data_parse( fd_gossip_view_crds_value_t * crds_val,
     446             :                                uchar const *                 payload,
     447             :                                ulong                         payload_sz,
     448           0 :                                ulong                         start_offset ) {
     449           0 :   switch( crds_val->tag ) {
     450           0 :     case FD_GOSSIP_VALUE_LEGACY_CONTACT_INFO:
     451           0 :       return fd_gossip_msg_crds_legacy_contact_info_parse( crds_val, payload, payload_sz, start_offset );
     452           0 :     case FD_GOSSIP_VALUE_VOTE:
     453           0 :       return fd_gossip_msg_crds_vote_parse( crds_val, payload, payload_sz, start_offset );
     454           0 :     case FD_GOSSIP_VALUE_LOWEST_SLOT:
     455           0 :       return fd_gossip_msg_crds_lowest_slot_parse( crds_val, payload, payload_sz, start_offset );
     456           0 :     case FD_GOSSIP_VALUE_LEGACY_SNAPSHOT_HASHES:
     457           0 :     case FD_GOSSIP_VALUE_ACCOUNT_HASHES:
     458           0 :       return fd_gossip_msg_crds_account_hashes_parse( crds_val, payload, payload_sz, start_offset );
     459           0 :     case FD_GOSSIP_VALUE_EPOCH_SLOTS:
     460           0 :       return fd_gossip_msg_crds_epoch_slots_parse( crds_val, payload, payload_sz, start_offset );
     461           0 :     case FD_GOSSIP_VALUE_LEGACY_VERSION:
     462           0 :       return fd_gossip_msg_crds_legacy_version_parse( crds_val, payload, payload_sz, start_offset );
     463           0 :     case FD_GOSSIP_VALUE_VERSION:
     464           0 :       return fd_gossip_msg_crds_version_parse( crds_val, payload, payload_sz, start_offset );
     465           0 :     case FD_GOSSIP_VALUE_NODE_INSTANCE:
     466           0 :       return fd_gossip_msg_crds_node_instance_parse( crds_val, payload, payload_sz, start_offset );
     467           0 :     case FD_GOSSIP_VALUE_DUPLICATE_SHRED:
     468           0 :       return fd_gossip_msg_crds_duplicate_shred_parse( crds_val, payload, payload_sz, start_offset );
     469           0 :     case FD_GOSSIP_VALUE_INC_SNAPSHOT_HASHES:
     470           0 :       return fd_gossip_msg_crds_snapshot_hashes_parse( crds_val, payload, payload_sz, start_offset );
     471           0 :     case FD_GOSSIP_VALUE_CONTACT_INFO:
     472           0 :       return fd_gossip_msg_crds_contact_info_parse( crds_val, payload, payload_sz, start_offset );
     473           0 :     case FD_GOSSIP_VALUE_RESTART_LAST_VOTED_FORK_SLOTS:
     474           0 :       return fd_gossip_msg_crds_last_voted_fork_slots_parse( crds_val, payload, payload_sz, start_offset );
     475           0 :     case FD_GOSSIP_VALUE_RESTART_HEAVIEST_FORK:
     476           0 :       return fd_gossip_msg_crds_restart_heaviest_fork_parse( crds_val, payload, payload_sz, start_offset );
     477           0 :     default:
     478           0 :       FD_LOG_WARNING(( "Unknown CRDS value tag %d", crds_val->tag ));
     479           0 :       return 0;
     480           0 :   }
     481           0 : }
     482             : 
     483             : /* start_offset should point to first byte in first crds value. In
     484             :    push/pullresponse messages this would be after the crds len */
     485             : static ulong
     486             : fd_gossip_msg_crds_vals_parse( fd_gossip_view_crds_value_t * crds_values,
     487             :                                ulong                         crds_values_len,
     488             :                                uchar const *                 payload,
     489             :                                ulong                         payload_sz,
     490           0 :                                ulong                         start_offset ) {
     491           0 :   CHECK_INIT( payload, payload_sz, start_offset );
     492             : 
     493           0 :   for( ulong i=0UL; i<crds_values_len; i++ ) {
     494           0 :     fd_gossip_view_crds_value_t * crds_view = &crds_values[i];
     495           0 :     CHECK_LEFT( 64U ); crds_view->signature_off = CUR_OFFSET             ; INC( 64U );
     496           0 :     CHECK_LEFT(  4U ); crds_view->tag           = FD_LOAD(uchar, CURSOR ); INC(  4U );
     497           0 :     ulong crds_data_sz = fd_gossip_msg_crds_data_parse( crds_view, payload, payload_sz, CUR_OFFSET );
     498           0 :     crds_view->length  = (ushort)(crds_data_sz + 64U + 4U); /* signature + tag */
     499           0 :     INC( crds_data_sz );
     500           0 :   }
     501           0 :   return BYTES_CONSUMED;
     502           0 : }
     503             : static ulong
     504             : fd_gossip_msg_ping_pong_parse( fd_gossip_view_t * view,
     505             :                                uchar const *      payload,
     506             :                                ulong              payload_sz,
     507           0 :                                ulong              start_offset ) {
     508           0 :   CHECK_INIT( payload, payload_sz, start_offset );
     509             :   /* Ping/Pong share the same memory layout */
     510           0 :   FD_STATIC_ASSERT( sizeof(fd_gossip_view_ping_t)==sizeof(fd_gossip_view_pong_t), compat );
     511           0 :   CHECK_LEFT( sizeof(fd_gossip_view_ping_t) );
     512           0 :   view->ping_pong_off = CUR_OFFSET;
     513           0 :   INC( sizeof(fd_gossip_view_ping_t) );
     514             : 
     515           0 :   return BYTES_CONSUMED;
     516           0 : }
     517             : 
     518             : static ulong
     519             : fd_gossip_pull_req_parse( fd_gossip_view_t * view,
     520             :                           uchar const *      payload,
     521             :                           ulong              payload_sz,
     522           0 :                           ulong              start_offset ) {
     523           0 :   CHECK_INIT( payload, payload_sz, start_offset );
     524           0 :   fd_gossip_view_pull_request_t * pr = view->pull_request;
     525             : 
     526           0 :   CHECK_LEFT(                    8U ); pr->bloom_keys_len    = FD_LOAD( ulong, CURSOR ) ; INC( 8U );
     527           0 :   CHECK( pr->bloom_keys_len<=((ULONG_MAX-7U)/8U) );
     528           0 :   CHECK_LEFT( pr->bloom_keys_len*8U ); pr->bloom_keys_offset = CUR_OFFSET               ; INC( pr->bloom_keys_len*8U );
     529             : 
     530           0 :   uchar has_bits = 0;
     531           0 :   CHECK_LEFT(                    1U ); has_bits = FD_LOAD( uchar, CURSOR )              ; INC( 1U );
     532           0 :   if( has_bits ) {
     533           0 :     CHECK_LEFT(                  8U ); pr->bloom_len         = FD_LOAD( ulong, CURSOR ) ; INC( 8U );
     534           0 :     CHECK( pr->bloom_len<=((ULONG_MAX-7U)/8U) );
     535           0 :     CHECK_LEFT(    pr->bloom_len*8U ); pr->bloom_bits_offset = CUR_OFFSET               ; INC( pr->bloom_len*8U );
     536           0 :     CHECK_LEFT(                  8U ); pr->bloom_bits_cnt    = FD_LOAD( ulong, CURSOR ) ; INC( 8U );
     537           0 :   } else {
     538           0 :     pr->bloom_len = 0U;
     539           0 :   }
     540           0 :   CHECK_LEFT(                    8U ); pr->bloom_num_bits_set = FD_LOAD( ulong, CURSOR ); INC( 8U );
     541           0 :   CHECK_LEFT(                    8U ); pr->mask      = FD_LOAD( ulong, CURSOR )         ; INC( 8U );
     542           0 :   CHECK_LEFT(                    4U ); pr->mask_bits = FD_LOAD( uint, CURSOR )          ; INC( 4U );
     543             : 
     544           0 :   INC( fd_gossip_msg_crds_vals_parse( pr->pr_ci,
     545           0 :                                       1U, /* pull request holds only one contact info */
     546           0 :                                       payload,
     547           0 :                                       payload_sz,
     548           0 :                                       CUR_OFFSET ) );
     549           0 :   return BYTES_CONSUMED;
     550           0 : }
     551             : 
     552             : static ulong
     553             : fd_gossip_msg_crds_container_parse( fd_gossip_view_t * view,
     554             :                                     uchar const *      payload,
     555             :                                     ulong              payload_sz,
     556           0 :                                     ulong              start_offset ) {
     557             :   /* Push and Pull Responses are CRDS composite types, */
     558           0 :   CHECK_INIT( payload, payload_sz, start_offset );
     559           0 :   fd_gossip_view_crds_container_t * container = view->tag==FD_GOSSIP_MESSAGE_PUSH ? view->push
     560           0 :                                                                                   : view->pull_response;
     561           0 :   CHECK_LEFT( 32U ); container->from_off        = CUR_OFFSET               ; INC( 32U );
     562           0 :   CHECK_LEFT(  8U ); container->crds_values_len = FD_LOAD( ushort, CURSOR ); INC(  8U );
     563           0 :   CHECK( container->crds_values_len<=FD_GOSSIP_MSG_MAX_CRDS );
     564           0 :   INC( fd_gossip_msg_crds_vals_parse( container->crds_values,
     565           0 :                                       container->crds_values_len,
     566           0 :                                       payload,
     567           0 :                                       payload_sz,
     568           0 :                                       CUR_OFFSET ) );
     569           0 :   return BYTES_CONSUMED;
     570           0 : }
     571             : 
     572             : static ulong
     573             : fd_gossip_msg_prune_parse( fd_gossip_view_t * view,
     574             :                            uchar const *      payload,
     575             :                            ulong              payload_sz,
     576           0 :                            ulong              start_offset ) {
     577           0 :   CHECK_INIT( payload, payload_sz, start_offset );
     578           0 :   fd_gossip_view_prune_t * prune = view->prune;
     579           0 :   CHECKED_INC( 32U ); /* pubkey is sent twice */
     580           0 :   CHECK_LEFT(                   32U ); prune->pubkey_off      = CUR_OFFSET               ; INC( 32U );
     581           0 :   CHECK_LEFT(                    8U ); prune->origins_len     = FD_LOAD( ulong, CURSOR ) ; INC(  8U );
     582           0 :   CHECK( prune->origins_len<=((ULONG_MAX-31U)/32U) );
     583           0 :   CHECK_LEFT( prune->origins_len*32U ); prune->origins_off    = CUR_OFFSET               ; INC( prune->origins_len*32U );
     584           0 :   CHECK_LEFT(                   64U ); prune->signature_off   = CUR_OFFSET               ; INC( 64U );
     585           0 :   CHECK_LEFT(                   32U ); prune->destination_off = CUR_OFFSET               ; INC( 32U );
     586           0 :   CHECK_LEFT(                    8U ); prune->wallclock       = FD_LOAD( ulong, CURSOR ) ; INC(  8U );
     587             : 
     588             :   /* Convert wallclock to nanos */
     589           0 :   prune->wallclock_nanos = FD_MILLI_TO_NANOSEC( prune->wallclock );
     590             : 
     591           0 :   return BYTES_CONSUMED;
     592           0 : }
     593             : 
     594             : ulong
     595             : fd_gossip_msg_parse( fd_gossip_view_t * view,
     596             :                      uchar const *      payload,
     597           0 :                      ulong              payload_sz ) {
     598           0 :   CHECK_INIT( payload, payload_sz, 0U );
     599           0 :   CHECK(     payload_sz<=FD_GOSSIP_MTU );
     600             : 
     601             :   /* Extract enum discriminant/tag (4b encoded) */
     602           0 :   uint tag = 0;
     603           0 :   CHECK_LEFT(                      4U );   tag = FD_LOAD( uchar, CURSOR ); INC( 4U );
     604           0 :   CHECK(   tag<=FD_GOSSIP_MESSAGE_LAST );
     605           0 :   view->tag = (uchar)tag;
     606             : 
     607           0 :   switch( view->tag ){
     608           0 :     case FD_GOSSIP_MESSAGE_PULL_REQUEST:
     609           0 :       INC( fd_gossip_pull_req_parse( view, payload, payload_sz, CUR_OFFSET ) );
     610           0 :       break;
     611           0 :     case FD_GOSSIP_MESSAGE_PULL_RESPONSE:
     612           0 :     case FD_GOSSIP_MESSAGE_PUSH:
     613           0 :       INC( fd_gossip_msg_crds_container_parse( view, payload, payload_sz, CUR_OFFSET ) );
     614           0 :       break;
     615           0 :     case FD_GOSSIP_MESSAGE_PRUNE:
     616           0 :       INC( fd_gossip_msg_prune_parse( view, payload, payload_sz, CUR_OFFSET ) );
     617           0 :       break;
     618           0 :     case FD_GOSSIP_MESSAGE_PING:
     619           0 :     case FD_GOSSIP_MESSAGE_PONG:
     620           0 :       INC( fd_gossip_msg_ping_pong_parse( view, payload, payload_sz, CUR_OFFSET ) );
     621           0 :       break;
     622           0 :     default:
     623           0 :       FD_LOG_WARNING(( "Unknown Gossip message type %d", view->tag ));
     624           0 :       return 0;
     625           0 :   }
     626           0 :   CHECK( payload_sz==CUR_OFFSET );
     627           0 :   return BYTES_CONSUMED;
     628           0 : }

Generated by: LCOV version 1.14