LCOV - code coverage report
Current view: top level - flamenco/gossip - fd_gossip_msg_parse.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 473 0.0 %
Date: 2025-10-27 04:40:00 Functions: 0 26 0.0 %

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

Generated by: LCOV version 1.14