LCOV - code coverage report
Current view: top level - flamenco/gossip - fd_gossip_msg_parse.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 81 470 17.2 %
Date: 2025-11-29 04:46:19 Functions: 5 26 19.2 %

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

Generated by: LCOV version 1.14