LCOV - code coverage report
Current view: top level - flamenco/gossip - fd_gossip_private.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 1 54 1.9 %
Date: 2025-09-19 04:41:14 Functions: 0 45 0.0 %

          Line data    Source code
       1             : 
       2             : #ifndef HEADER_fd_src_flamenco_gossip_fd_gossip_private_h
       3             : #define HEADER_fd_src_flamenco_gossip_fd_gossip_private_h
       4             : 
       5             : #include "fd_gossip_types.h"
       6             : #include "../../util/fd_util.h"
       7             : #include "../../disco/fd_disco_base.h"
       8             : 
       9             : /* Constants used in deriving size bounds
      10             :    - 1232b (MTU)
      11             :    - 1188b = 1232b-4b(discriminant)-32b(pubkey)-8(crds len) max CRDS sz
      12             :      largest CRDS value seen so far is duplicate shreds at 1187b*/
      13             : 
      14           0 : #define FD_GOSSIP_CRDS_MAX_SZ (1188UL)
      15             : 
      16             : /* Deriving maximum number of CRDS values a message can hold:
      17             :   - Each CRDS value contains a 64b signature and a 4b discriminant.
      18             :     So, each CRDS value is at least 68b.
      19             :   - Smallest CRDS data is technically slot hashes with zero hashes,
      20             :     which is 32b (pubkey) + 8b (wallclock) + 8b (vector len), bringing
      21             :     total to 68b+32b+8b+8b=116b
      22             :   - However, we take a more conservative approach and assume just the
      23             :     signature and discriminant.
      24             :   - So, maximum number of CRDS values is 1188/(68) ~= 18 */
      25           0 : #define FD_GOSSIP_MSG_MAX_CRDS (18UL)
      26             : 
      27           0 : #define FD_GOSSIP_MESSAGE_PULL_REQUEST  (0)
      28           0 : #define FD_GOSSIP_MESSAGE_PULL_RESPONSE (1)
      29           0 : #define FD_GOSSIP_MESSAGE_PUSH          (2)
      30           0 : #define FD_GOSSIP_MESSAGE_PRUNE         (3)
      31           0 : #define FD_GOSSIP_MESSAGE_PING          (4)
      32           0 : #define FD_GOSSIP_MESSAGE_PONG          (5)
      33             : #define FD_GOSSIP_MESSAGE_LAST          (FD_GOSSIP_MESSAGE_PONG)
      34             : 
      35           0 : #define FD_GOSSIP_VALUE_LEGACY_CONTACT_INFO           ( 0)
      36           0 : #define FD_GOSSIP_VALUE_VOTE                          ( 1)
      37           0 : #define FD_GOSSIP_VALUE_LOWEST_SLOT                   ( 2) // SOME FIELDS DEPRECATED
      38           0 : #define FD_GOSSIP_VALUE_LEGACY_SNAPSHOT_HASHES        ( 3) // DEPRECATED
      39           0 : #define FD_GOSSIP_VALUE_ACCOUNT_HASHES                ( 4) // DEPRECATED
      40           0 : #define FD_GOSSIP_VALUE_EPOCH_SLOTS                   ( 5)
      41           0 : #define FD_GOSSIP_VALUE_LEGACY_VERSION                ( 6)
      42           0 : #define FD_GOSSIP_VALUE_VERSION                       ( 7)
      43           0 : #define FD_GOSSIP_VALUE_NODE_INSTANCE                 ( 8)
      44           0 : #define FD_GOSSIP_VALUE_DUPLICATE_SHRED               ( 9)
      45           0 : #define FD_GOSSIP_VALUE_INC_SNAPSHOT_HASHES           (10)
      46         450 : #define FD_GOSSIP_VALUE_CONTACT_INFO                  (11)
      47           0 : #define FD_GOSSIP_VALUE_RESTART_LAST_VOTED_FORK_SLOTS (12)
      48           0 : #define FD_GOSSIP_VALUE_RESTART_HEAVIEST_FORK         (13)
      49             : #define FD_GOSSIP_VALUE_LAST                          (FD_GOSSIP_VALUE_RESTART_HEAVIEST_FORK)
      50             : 
      51             : /* Gossip messages encode wallclock in millis*, while we
      52             :    parse them into nanoseconds for internal use.
      53             : 
      54             :    * exceptions:
      55             :      - Contact Info outset (AKA instance creation wallclock) is encoded
      56             :        in micros */
      57           0 : #define FD_NANOSEC_TO_MILLI(_ts_) ((long)(_ts_/1000000))
      58           0 : #define FD_MILLI_TO_NANOSEC(_ts_) ((long)(_ts_*1000000))
      59           0 : #define FD_NANOSEC_TO_MICRO(_ts_) ((long)(_ts_/1000))
      60           0 : #define FD_MICRO_TO_NANOSEC(_ts_) ((long)(_ts_*1000))
      61             : 
      62             : /* Bound max inc entries by
      63             :     1188b (max CRDS encoded buffer size )
      64             :   - 64b (signature)
      65             :   - 4b  (tag)
      66             :   - 32b (pubkey)
      67             :   - 40b (full pair)
      68             :   - 8b  (inc len)
      69             :   - 8b  (wallclock)
      70             :   = 1032b
      71             : 
      72             :   1032b/40 ~= 25 */
      73             : FD_STATIC_ASSERT( FD_GOSSIP_SNAPSHOT_HASHES_MAX_INCREMENTAL==25UL,
      74             :                  "FD_GOSSIP_SNAPSHOT_HASHES_MAX_INCREMENTAL must be 25" );
      75             : 
      76             : 
      77           0 : #define FD_GOSSIP_UPDATE_SZ_CONTACT_INFO        (49UL + sizeof(ulong) + sizeof(fd_contact_info_t))
      78           0 : #define FD_GOSSIP_UPDATE_SZ_CONTACT_INFO_REMOVE (49UL + sizeof(ulong))
      79           0 : #define FD_GOSSIP_UPDATE_SZ_LOWEST_SLOT         (49UL + sizeof(ulong))
      80           0 : #define FD_GOSSIP_UPDATE_SZ_VOTE                (49UL + sizeof(fd_gossip_vote_t))
      81           0 : #define FD_GOSSIP_UPDATE_SZ_DUPLICATE_SHRED     (49UL + sizeof(fd_gossip_duplicate_shred_t))
      82           0 : #define FD_GOSSIP_UPDATE_SZ_SNAPSHOT_HASHES     (49UL + sizeof(fd_gossip_snapshot_hashes_t))
      83             : 
      84             : struct fd_gossip_view_ipaddr {
      85             :   uchar   is_ip6;
      86             :   union {
      87             :     uint   ip4;
      88             :     ushort ip6_off;
      89             :   };
      90             : };
      91             : 
      92             : typedef struct fd_gossip_view_ipaddr fd_gossip_view_ipaddr_t;
      93             : 
      94             : struct fd_gossip_view_socket {
      95             :   uchar   key;
      96             :   uchar   index;
      97             :   ushort  offset; /* NOTE: this is a varint in encoded form */
      98             : };
      99             : 
     100             : typedef struct fd_gossip_view_socket fd_gossip_view_socket_t;
     101             : 
     102             : /* To get the minimum possible wire size of a Version message, we use
     103             :    version 0.0.0 client 0 (anything less than 128 works):
     104             : 
     105             :      1b (major)
     106             :    + 1b (minor)
     107             :    + 1b (patch)
     108             :    + 4b (commit)
     109             :    + 4b (feature set)
     110             :    + 1b (client)
     111             :    = 12b */
     112             : struct fd_gossip_view_version {
     113             :   ushort major;
     114             :   ushort minor;
     115             :   ushort patch;
     116             :   uint   commit;      /* First 4 bytes of the commit hash */
     117             :   uint   feature_set; /* Feature set encoded as a bitmask */
     118             :   ushort client;
     119             : };
     120             : 
     121             : typedef struct fd_gossip_view_version fd_gossip_view_version_t;
     122             : 
     123             : /* Contact info size bound calculations:
     124             : 
     125             :    The minimal valid contact info would hold 0 addrs, 0 sockets,
     126             :    and an empty extensions array. This ends up taking
     127             : 
     128             :      32b (pubkey)
     129             :    + 8b  (wallclock)
     130             :    + 8b  (outset)
     131             :    + 2b  (shred version)
     132             :    + 12b (minimum version)
     133             :    + 1b  (addrs_len)
     134             :    + 1b  (sockets_len)
     135             :    + 1b  (ext_len)
     136             :    = 65b
     137             : 
     138             :   This leaves us with 1188b - 65b = 1123b to hold addrs, sockets or
     139             :   extensions. Extension is just a byte array, so we can ignore sizing it
     140             :   and instead offset it in the payload.
     141             : 
     142             :   Before analyzing size bounds for addrs and sockets, we establish the
     143             :   minimum size socket entry:
     144             :      1b (key)
     145             :    + 1b (index)
     146             :    + 1b (offset, compact-u16)
     147             :    = 3b
     148             : 
     149             :   According to Agave's ContactInfo verifier (linked below), every IP
     150             :   address must be unique, and must be referenced by at least one socket.
     151             :   This means that the number of addrs must be at most the number of
     152             :   sockets. So to find the maximum n (addr, socket) pairs we can fit in
     153             :   1123b:
     154             :     1123b / (8b (addr) + 3b (socket)) ~= 102 pairs.
     155             : 
     156             :   This bounds the number of addrs to 102. We cannot apply this bound to
     157             :   sockets, because the socket entries can reference the same addr
     158             :   multiple times, so we can have just 1 addr and use the remaining space
     159             :   to hold sockets.
     160             : 
     161             :   Agave's verifier enforces a unique socket tag (key) across all
     162             :   sockets, and since the key is 1b, this bounds us to 256 sockets.
     163             : 
     164             :   https://github.com/anza-xyz/agave/blob/540d5bc56cd44e3cc61b179bd52e9a782a2c99e4/gossip/src/contact_info.rs#L599-L643 */
     165             : 
     166             : #define FD_GOSSIP_CONTACT_INFO_MAX_ADDRESSES (102UL)
     167             : #define FD_GOSSIP_CONTACT_INFO_MAX_SOCKETS   (256UL)
     168             : 
     169             : struct fd_gossip_view_contact_info {
     170             :   fd_contact_info_t contact_info[1];
     171             :   ulong             ip6_cnt;
     172             :   ulong             unrecognized_socket_tag_cnt;
     173             : 
     174             :   ushort            ext_len;
     175             :   ushort            ext_off;
     176             : };
     177             : 
     178             : typedef struct fd_gossip_view_contact_info fd_gossip_view_contact_info_t;
     179             : 
     180             : struct fd_gossip_view_node_instance {
     181             :   ulong token;
     182             : };
     183             : 
     184             : typedef struct fd_gossip_view_node_instance fd_gossip_view_node_instance_t;
     185             : 
     186             : struct fd_gossip_view_vote {
     187             :   uchar  index;
     188             :   ulong  txn_sz;
     189             :   ushort txn_off;
     190             : };
     191             : 
     192             : typedef struct fd_gossip_view_vote fd_gossip_view_vote_t;
     193             : 
     194             : struct fd_gossip_view_epoch_slots {
     195             :   uchar  index;
     196             : };
     197             : 
     198             : typedef struct fd_gossip_view_epoch_slots fd_gossip_view_epoch_slots_t;
     199             : 
     200             : struct fd_gossip_view_duplicate_shred {
     201             :   ushort index;
     202             :   ulong  slot;
     203             :   uchar  num_chunks;
     204             :   uchar  chunk_index;
     205             :   ulong  chunk_len;
     206             :   ushort chunk_off;
     207             : };
     208             : 
     209             : typedef struct fd_gossip_view_duplicate_shred fd_gossip_view_duplicate_shred_t;
     210             : 
     211             : typedef struct fd_gossip_view_snapshot_hash_pair fd_gossip_view_snapshot_hash_pair_t;
     212             : struct fd_gossip_view_snapshot_hashes {
     213             :   ushort full_off; /* Offset to the full snapshot hashes (slot, hash) pair */
     214             :   ulong  inc_len;
     215             :   ushort inc_off;  /* Offset to start of incremental snapshot hashes pair */
     216             : };
     217             : 
     218             : typedef struct fd_gossip_view_snapshot_hashes fd_gossip_view_snapshot_hashes_t;
     219             : 
     220             :  /* Offsets are within full message payload, not the subset where the encoded
     221             :     CRDS value lies. */
     222             : struct fd_gossip_view_crds_value {
     223             :   union {
     224             :     ushort value_off; /* Start of CRDS value data in payload */
     225             :     ushort signature_off;
     226             :   };
     227             :   ushort pubkey_off;
     228             :   long   wallclock_nanos;
     229             :   ushort length; /* Length of the value in bytes (incl. signature) */
     230             : 
     231             :   uchar tag;
     232             :   union{
     233             :     fd_gossip_view_contact_info_t    ci_view[ 1 ];
     234             :     fd_gossip_view_node_instance_t   node_instance[ 1 ];
     235             :     fd_gossip_view_vote_t            vote[ 1 ];
     236             :     fd_gossip_view_epoch_slots_t     epoch_slots[ 1 ];
     237             :     fd_gossip_view_duplicate_shred_t duplicate_shred[ 1 ];
     238             :     ulong                            lowest_slot;
     239             :     fd_gossip_view_snapshot_hashes_t snapshot_hashes[ 1 ];
     240             :   };
     241             : };
     242             : 
     243             : typedef struct fd_gossip_view_crds_value fd_gossip_view_crds_value_t;
     244             : 
     245             : struct fd_gossip_view_crds_container {
     246             :   ushort from_off;
     247             :   ushort crds_values_len;
     248             : 
     249             :   fd_gossip_view_crds_value_t crds_values[ FD_GOSSIP_MSG_MAX_CRDS ];
     250             : };
     251             : 
     252             : typedef struct fd_gossip_view_crds_container fd_gossip_view_crds_container_t;
     253             : typedef struct fd_gossip_view_crds_container fd_gossip_view_pull_response_t;
     254             : typedef struct fd_gossip_view_crds_container fd_gossip_view_push_t;
     255             : struct fd_gossip_view_pull_request {
     256             :   ulong bloom_keys_len;
     257             :   ulong bloom_keys_offset;
     258             : 
     259             :   ulong bloom_len;
     260             :   ulong bloom_bits_offset;
     261             :   ulong bloom_bits_cnt;
     262             : 
     263             :   ulong bloom_num_bits_set;
     264             :   ulong mask;
     265             :   uint  mask_bits;
     266             : 
     267             :   fd_gossip_view_crds_value_t pr_ci[ 1 ];
     268             : };
     269             : 
     270             : typedef struct fd_gossip_view_pull_request fd_gossip_view_pull_request_t;
     271             : 
     272             : struct fd_gossip_view_prune {
     273             :   ushort pubkey_off;
     274             :   ulong  origins_len;
     275             :   ushort origins_off;
     276             :   ushort destination_off;
     277             :   ulong  wallclock;
     278             :   ushort signature_off;
     279             : 
     280             :   long   wallclock_nanos;
     281             : };
     282             : 
     283             : typedef struct fd_gossip_view_prune fd_gossip_view_prune_t;
     284             : 
     285             : /* Ping/Pong can be casted on to the payload bytes
     286             :    directly */
     287             : struct __attribute__((__packed__)) fd_gossip_view_ping {
     288             :   uchar pubkey[ 32UL ];
     289             :   uchar ping_token[ 32UL ];
     290             :   uchar signature[ 64UL ];
     291             : };
     292             : 
     293             : typedef struct fd_gossip_view_ping fd_gossip_view_ping_t;
     294             : 
     295             : struct __attribute__((__packed__)) fd_gossip_view_pong {
     296             :   uchar pubkey[ 32UL ];
     297             :   uchar ping_hash[ 32UL ];
     298             :   uchar signature[ 64UL ];
     299             : };
     300             : 
     301             : typedef struct fd_gossip_view_pong fd_gossip_view_pong_t;
     302             : 
     303             : struct fd_gossip_view {
     304             :   uchar tag; // uint in rust bincode
     305             :   union {
     306             :     fd_gossip_view_pull_request_t  pull_request[ 1 ];
     307             :     fd_gossip_view_pull_response_t pull_response[ 1 ];
     308             :     fd_gossip_view_push_t          push[ 1 ];
     309             :     fd_gossip_view_prune_t         prune[ 1 ];
     310             :     ushort                         ping_pong_off;
     311             :   };
     312             : };
     313             : 
     314             : typedef struct fd_gossip_view fd_gossip_view_t;
     315             : 
     316             : static inline fd_ip4_port_t
     317             : fd_contact_info_get_socket( fd_contact_info_t const * ci,
     318           0 :                             uchar                     tag ) {
     319           0 :   if( FD_UNLIKELY( tag>FD_CONTACT_INFO_SOCKET_LAST ) ) {
     320           0 :     FD_LOG_ERR(( "Invalid socket tag %u", tag ));
     321           0 :   }
     322           0 :   return ci->sockets[ tag ];
     323           0 : }
     324             : 
     325             : static inline fd_ip4_port_t
     326           0 : fd_contact_info_gossip_socket( fd_contact_info_t const * ci ) {
     327           0 :   return fd_contact_info_get_socket( ci, FD_CONTACT_INFO_SOCKET_GOSSIP );
     328           0 : }
     329             : 
     330             : ulong
     331             : fd_gossip_msg_parse( fd_gossip_view_t * view,
     332             :                      uchar const *      payload,
     333             :                      ulong              payload_sz );
     334             : 
     335             : FD_FN_CONST static inline ulong
     336             : fd_gossip_pull_request_max_filter_bits( ulong num_keys,
     337             :                                         ulong contact_info_crds_sz,
     338           0 :                                         ulong payload_sz ) {
     339           0 :   return 8UL*( payload_sz
     340           0 :              - 4UL          /* discriminant */
     341           0 :              - 8UL          /* keys len */
     342           0 :              - 8UL*num_keys /* keys */
     343           0 :              - 1UL          /* has_bits */
     344           0 :              - 8UL          /* bloom vec len */
     345           0 :              - 8UL          /* bloom bits count */
     346           0 :              - 8UL          /* bloom num bits set */
     347           0 :              - 8UL          /* mask */
     348           0 :              - 4UL          /* mask bits */
     349           0 :              - contact_info_crds_sz ); /* contact info CRDS val */
     350           0 : }
     351             : 
     352             : int
     353             : fd_gossip_pull_request_init( uchar *       payload,
     354             :                              ulong         payload_sz,
     355             :                              ulong         num_keys,
     356             :                              ulong         num_bits,
     357             :                              ulong         mask,
     358             :                              uint          mask_bits,
     359             :                              uchar const * contact_info_crds,
     360             :                              ulong         contact_info_crds_sz,
     361             :                              ulong **      out_bloom_keys,
     362             :                              ulong **      out_bloom_bits,
     363             :                              ulong **      out_bits_set,
     364             :                              ulong *       out_payload_sz );
     365             : 
     366             : int
     367             : fd_gossip_contact_info_encode( fd_contact_info_t const * contact_info,
     368             :                                uchar *                   out_buf,
     369             :                                ulong                     out_buf_cap,
     370             :                                ulong *                   opt_encoded_sz );
     371             : 
     372             : int
     373             : fd_gossip_crds_vote_encode( uchar *       out_buf,
     374             :                             ulong         out_buf_sz,
     375             :                             uchar const * txn,
     376             :                             ulong         txn_sz,
     377             :                             uchar const * identity_pubkey,
     378             :                             long          now,
     379             :                             ulong *       opt_encoded_sz );
     380             : #endif /* HEADER_fd_src_flamenco_gossip_fd_gossip_private_h */

Generated by: LCOV version 1.14