LCOV - code coverage report
Current view: top level - flamenco/gossip - fd_gossip_msg_parse.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 210 471 44.6 %
Date: 2025-12-28 05:17:03 Functions: 14 26 53.8 %

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

Generated by: LCOV version 1.14