LCOV - code coverage report
Current view: top level - flamenco/gossip - fd_gossip_message.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 53 0.0 %
Date: 2026-03-19 18:19:27 Functions: 0 44 0.0 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_gossip_fd_gossip_message_h
       2             : #define HEADER_fd_src_flamenco_gossip_fd_gossip_message_h
       3             : 
       4             : #include "../../util/fd_util_base.h"
       5             : #include "../../util/cstr/fd_cstr.h"
       6             : #include "fd_gossip_value.h"
       7             : 
       8             : #include <stddef.h>
       9             : 
      10             : /* The maximum number of contact infos that may be present at any one
      11             :    time.  If new contact infos are added, a removal will be issued first
      12             :    to make space.  This is a hard limit, and the consumer of the contact
      13             :    info messages can assume it is always respected.
      14             : 
      15             :    The contact info messages are designed to be consumed in an
      16             :    incremental way.  In particular, CONTACT_INFO and CONTACT_INFO_REMOVE
      17             :    messages are both sent with an idx field, which is the index of the
      18             :    contact info in an imaginary array of contact infos.  Updates will
      19             :    always have the same idx for the same pubkey, and removes will
      20             :    likewise have the same idx for the pubkey being removed.  A consumer
      21             :    of contact info updates can therefore simply maintain a local array
      22             :    of contact infos, and update it with the idx field.  */
      23             : 
      24           0 : #define FD_CONTACT_INFO_TABLE_SIZE (32768UL)
      25             : 
      26             : /* Tightest bound for a single CrdsValue given network constraints.
      27             : 
      28             :      IPv6 minimum MTU             = 1280
      29             :      IPv6 header                  =   40
      30             :      UDP header                   =    8
      31             :      PACKET_DATA_SIZE             = 1232   (= 1280 - 40 - 8)
      32             : 
      33             :      Maximum CrdsValue size inside PushMessage/PullResponse:
      34             :        PACKET_DATA_SIZE - tag(4) - from(32) - values_len(8)  = 1188  */
      35             : 
      36           0 : #define FD_GOSSIP_VALUE_MAX_SZ (1188UL)
      37             : 
      38             : /* Tightest bound for values[] in a Push / PullResponse given network
      39             :    constraints.
      40             : 
      41             :      IPv6 minimum MTU             = 1280
      42             :      IPv6 header                  =   40
      43             :      UDP header                   =    8
      44             :      PACKET_DATA_SIZE             = 1232   (= 1280 - 40 - 8)
      45             : 
      46             :      Minimum bytes consumed before values loop:
      47             :        Protocol tag(4) + from(32) + values_len(8)             =  44
      48             : 
      49             :      Remaining: 1232 - 44 = 1188
      50             :      Each CrdsValue: signature(64) + CrdsData tag(4) = 68 bytes minimum
      51             :      Max values = floor(1188/68) = 17  */
      52             : 
      53           0 : #define FD_GOSSIP_MESSAGE_MAX_CRDS (17UL)
      54             : 
      55           0 : #define FD_GOSSIP_FAILED_NO_CONTACT_INFO (1)
      56           0 : #define FD_GOSSIP_FAILED_WALLCLOCK       (2)
      57             : 
      58           0 : #define FD_GOSSIP_UPDATE_SZ_CONTACT_INFO        (offsetof(fd_gossip_update_message_t, contact_info)        + sizeof((fd_gossip_update_message_t *)0)->contact_info)
      59           0 : #define FD_GOSSIP_UPDATE_SZ_CONTACT_INFO_REMOVE (offsetof(fd_gossip_update_message_t, contact_info_remove) + sizeof((fd_gossip_update_message_t *)0)->contact_info_remove)
      60           0 : #define FD_GOSSIP_UPDATE_SZ_VOTE                (offsetof(fd_gossip_update_message_t, vote)                + sizeof((fd_gossip_update_message_t *)0)->vote)
      61           0 : #define FD_GOSSIP_UPDATE_SZ_DUPLICATE_SHRED     (offsetof(fd_gossip_update_message_t, duplicate_shred)     + sizeof((fd_gossip_update_message_t *)0)->duplicate_shred)
      62           0 : #define FD_GOSSIP_UPDATE_SZ_SNAPSHOT_HASHES     (offsetof(fd_gossip_update_message_t, snapshot_hashes)     + sizeof((fd_gossip_update_message_t *)0)->snapshot_hashes)
      63             : 
      64             : /* Gossip messages encode wallclock in millis*, while we
      65             :    parse them into nanoseconds for internal use.
      66             : 
      67             :    * exceptions:
      68             :      - Contact Info outset (AKA instance creation wallclock) is encoded
      69             :        in micros */
      70           0 : #define FD_NANOSEC_TO_MILLI(_ts_) ((long)(_ts_/1000000))
      71           0 : #define FD_MILLI_TO_NANOSEC(_ts_) ((long)(_ts_*1000000))
      72           0 : #define FD_NANOSEC_TO_MICRO(_ts_) ((long)(_ts_/1000))
      73           0 : #define FD_MICRO_TO_NANOSEC(_ts_) ((long)(_ts_*1000))
      74             : 
      75           0 : #define FD_GOSSIP_UPDATE_TAG_CONTACT_INFO        (0)
      76           0 : #define FD_GOSSIP_UPDATE_TAG_CONTACT_INFO_REMOVE (1)
      77           0 : #define FD_GOSSIP_UPDATE_TAG_VOTE                (2)
      78           0 : #define FD_GOSSIP_UPDATE_TAG_DUPLICATE_SHRED     (3)
      79           0 : #define FD_GOSSIP_UPDATE_TAG_SNAPSHOT_HASHES     (4)
      80           0 : #define FD_GOSSIP_UPDATE_TAG_WFS_DONE            (5)
      81           0 : #define FD_GOSSIP_UPDATE_TAG_PEER_SATURATED      (6)
      82             : 
      83           0 : #define FD_GOSSIP_CONTACT_INFO_SOCKET_GOSSIP            ( 0)
      84           0 : #define FD_GOSSIP_CONTACT_INFO_SOCKET_SERVE_REPAIR_QUIC ( 1)
      85           0 : #define FD_GOSSIP_CONTACT_INFO_SOCKET_RPC               ( 2)
      86           0 : #define FD_GOSSIP_CONTACT_INFO_SOCKET_RPC_PUBSUB        ( 3)
      87           0 : #define FD_GOSSIP_CONTACT_INFO_SOCKET_SERVE_REPAIR      ( 4)
      88           0 : #define FD_GOSSIP_CONTACT_INFO_SOCKET_TPU               ( 5)
      89           0 : #define FD_GOSSIP_CONTACT_INFO_SOCKET_TPU_FORWARDS      ( 6)
      90           0 : #define FD_GOSSIP_CONTACT_INFO_SOCKET_TPU_FORWARDS_QUIC ( 7)
      91           0 : #define FD_GOSSIP_CONTACT_INFO_SOCKET_TPU_QUIC          ( 8)
      92           0 : #define FD_GOSSIP_CONTACT_INFO_SOCKET_TPU_VOTE          ( 9)
      93           0 : #define FD_GOSSIP_CONTACT_INFO_SOCKET_TVU               (10)
      94           0 : #define FD_GOSSIP_CONTACT_INFO_SOCKET_TVU_QUIC          (11)
      95           0 : #define FD_GOSSIP_CONTACT_INFO_SOCKET_TPU_VOTE_QUIC     (12)
      96           0 : #define FD_GOSSIP_CONTACT_INFO_SOCKET_ALPENGLOW         (13)
      97           0 : #define FD_GOSSIP_CONTACT_INFO_SOCKET_CNT               (14)
      98             : 
      99             : #define FD_GOSSIP_CONTACT_INFO_CLIENT_SOLANA_LABS   (0)
     100             : #define FD_GOSSIP_CONTACT_INFO_CLIENT_JITO_LABS     (1)
     101             : #define FD_GOSSIP_CONTACT_INFO_CLIENT_FRANKENDANCER (2)
     102             : #define FD_GOSSIP_CONTACT_INFO_CLIENT_AGAVE         (3)
     103             : #define FD_GOSSIP_CONTACT_INFO_CLIENT_AGAVE_PALADIN (4)
     104           0 : #define FD_GOSSIP_CONTACT_INFO_CLIENT_FIREDANCER    (5)
     105             : #define FD_GOSSIP_CONTACT_INFO_CLIENT_AGAVE_BAM     (6)
     106             : #define FD_GOSSIP_CONTACT_INFO_CLIENT_SIG           (7)
     107             : 
     108           0 : #define FD_GOSSIP_MESSAGE_PULL_REQUEST  (0)
     109           0 : #define FD_GOSSIP_MESSAGE_PULL_RESPONSE (1)
     110           0 : #define FD_GOSSIP_MESSAGE_PUSH          (2)
     111           0 : #define FD_GOSSIP_MESSAGE_PRUNE         (3)
     112           0 : #define FD_GOSSIP_MESSAGE_PING          (4)
     113           0 : #define FD_GOSSIP_MESSAGE_PONG          (5)
     114             : #define FD_GOSSIP_MESSAGE_CNT           (6)
     115             : 
     116             : struct fd_gossip_vote {
     117             :   uchar index;
     118             :   ulong transaction_len;
     119             :   uchar transaction[ 1232UL ];
     120             : };
     121             : 
     122             : typedef struct fd_gossip_vote fd_gossip_vote_t;
     123             : 
     124             : struct fd_gossip_node_instance {
     125             :   ulong timestamp;
     126             :   ulong token;
     127             : };
     128             : 
     129             : typedef struct fd_gossip_node_instance fd_gossip_node_instance_t;
     130             : 
     131             : /* Tightest bound for chunk[] given network constraints.
     132             : 
     133             :      IPv6 minimum MTU             = 1280
     134             :      IPv6 header                  =   40
     135             :      UDP header                   =    8
     136             :      PACKET_DATA_SIZE             = 1232   (= 1280 - 40 - 8)
     137             : 
     138             :      Maximum CrdsValue size inside PushMessage/PullResponse:
     139             :        PACKET_DATA_SIZE - tag(4) - from(32) - values_len(8) = 1188
     140             : 
     141             :      Minimum bytes consumed before chunk data:
     142             :        signature(64) + CrdsData tag(4) + index(2) + origin(32) +
     143             :        wallclock(8) + slot(8) + unused(4) + shred_type(1) +
     144             :        num_chunks(1) + chunk_index(1) + chunk_len(8)         = 133
     145             : 
     146             :      Remaining: 1188 - 133 = 1055  */
     147             : 
     148             : struct fd_gossip_duplicate_shred {
     149             :   ushort index;
     150             :   ulong  slot;
     151             :   uchar  num_chunks;
     152             :   uchar  chunk_index;
     153             :   ulong  chunk_len;
     154             :   uchar  chunk[ 1055UL ];
     155             : };
     156             : 
     157             : typedef struct fd_gossip_duplicate_shred fd_gossip_duplicate_shred_t;
     158             : 
     159             : /* Tightest bound for incremental[] given network constraints.
     160             : 
     161             :      IPv6 minimum MTU             = 1280
     162             :      IPv6 header                  =   40
     163             :      UDP header                   =    8
     164             :      PACKET_DATA_SIZE             = 1232   (= 1280 - 40 - 8)
     165             : 
     166             :      Maximum CrdsValue size inside PushMessage/PullResponse:
     167             :        PACKET_DATA_SIZE - tag(4) - from(32) - values_len(8) = 1188
     168             : 
     169             :      Bytes consumed before incremental loop:
     170             :        signature(64) + CrdsData tag(4) + origin(32) +
     171             :        full_slot(8) + full_hash(32) + inc_len(8)             = 148
     172             : 
     173             :      Remaining: 1188 - 148 = 1040
     174             :      Each entry: slot(8) + hash(32) = 40 bytes
     175             :      Max entries = floor(1040/40) = 26  */
     176             : 
     177             : struct fd_gossip_snapshot_hashes {
     178             :   ulong full_slot;
     179             :   uchar full_hash[ 32UL ];
     180             : 
     181             :   ulong incremental_len;
     182             :   struct {
     183             :     ulong slot;
     184             :     uchar hash[ 32UL ];
     185             :   } incremental[ 26UL ];
     186             : };
     187             : 
     188             : typedef struct fd_gossip_snapshot_hashes fd_gossip_snapshot_hashes_t;
     189             : 
     190             : struct fd_gossip_socket {
     191             :   ushort port;
     192             :   uint   is_ipv6;
     193             :   union {
     194             :     uint ip4;
     195             :     uchar ip6[ 16UL ];
     196             :   };
     197             : };
     198             : 
     199             : typedef struct fd_gossip_socket fd_gossip_socket_t;
     200             : 
     201             : struct fd_gossip_contact_info {
     202             :   ulong  outset;
     203             :   ushort shred_version;
     204             : 
     205             :   struct {
     206             :     ushort major;
     207             :     ushort minor;
     208             :     ushort patch;
     209             : 
     210             :     uint   commit;
     211             :     uint   feature_set;
     212             : 
     213             :     ushort client;
     214             :   } version;
     215             : 
     216             :   fd_gossip_socket_t sockets[ FD_GOSSIP_CONTACT_INFO_SOCKET_CNT ];
     217             : };
     218             : 
     219             : typedef struct fd_gossip_contact_info fd_gossip_contact_info_t;
     220             : 
     221             : struct fd_gossip_epoch_slots {
     222             :   uchar index;
     223             : };
     224             : 
     225             : typedef struct fd_gossip_epoch_slots fd_gossip_epoch_slots_t;
     226             : 
     227             : struct fd_gossip_value {
     228             :   uint tag;
     229             : 
     230             :   uchar signature[ 64UL ];
     231             :   uchar origin[ 32UL ];
     232             :   ulong wallclock;
     233             : 
     234             :   ulong offset;
     235             :   ulong length;
     236             : 
     237             :   union {
     238             :     // DEPRECATED OR UNUSED
     239             :     // fd_gossip_legacy_contact_info_t           legacy_contact_info[ 1 ];
     240             :     // fd_gossip_lowest_slot_t                   lowest_slot[ 1 ];
     241             :     // fd_gossip_legacy_snapshot_hashes_t        legacy_snapshot_hashes[ 1 ];
     242             :     // fd_gossip_account_hashes_t                account_hashes[ 1 ];
     243             :     // fd_gossip_legacy_version_t                legacy_version[ 1 ];
     244             :     // fd_gossip_version_t                       version[ 1 ];
     245             :     // fd_gossip_restart_last_voted_fork_slots_t restart_last_voted_fork_slots[ 1 ];
     246             :     // fd_gossip_restart_heaviest_fork_t         restart_heaviest_fork[ 1 ];
     247             : 
     248             :     fd_gossip_vote_t            vote[ 1 ];
     249             :     fd_gossip_node_instance_t   node_instance[ 1 ];
     250             :     fd_gossip_duplicate_shred_t duplicate_shred[ 1 ];
     251             :     fd_gossip_snapshot_hashes_t snapshot_hashes[ 1 ];
     252             :     fd_gossip_contact_info_t    contact_info[ 1 ];
     253             :     fd_gossip_epoch_slots_t     epoch_slots[ 1 ];
     254             :   };
     255             : };
     256             : 
     257             : typedef struct fd_gossip_value fd_gossip_value_t;
     258             : 
     259             : /* Tightest bounds for Bloom keys[]/bits[] given network constraints.
     260             : 
     261             :      IPv6 minimum MTU             = 1280
     262             :      IPv6 header                  =   40
     263             :      UDP header                   =    8
     264             :      PACKET_DATA_SIZE             = 1232   (= 1280 - 40 - 8)
     265             : 
     266             :      PullRequest is the only message containing a Bloom filter.
     267             : 
     268             :      Bytes consumed before keys loop:
     269             :        Protocol tag(4) + keys_len(8)                         =  12
     270             : 
     271             :      Remaining: 1232 - 12 = 1220
     272             :      Each key: 8 bytes
     273             :      Max keys = floor(1220/8) = 152
     274             : 
     275             :      Bytes consumed before bits data:
     276             :        Protocol tag(4) + keys_len(8) + has_bits(1) +
     277             :        bits_cap(8)                                           =  21
     278             : 
     279             :      Remaining: 1232 - 21 = 1211
     280             :      Each u64: 8 bytes
     281             :      Max bits = floor(1211/8) = 151  */
     282             : 
     283             : struct fd_gossip_bloom {
     284             :   ulong keys_len;
     285             :   ulong keys[ 152UL ];
     286             :   ulong bits_cap;
     287             :   ulong bits_len;
     288             :   ulong bits[ 151UL ];
     289             :   ulong num_bits_set;
     290             : };
     291             : 
     292             : typedef struct fd_gossip_bloom fd_gossip_bloom_t;
     293             : 
     294             : struct fd_gossip_crds_filter {
     295             :   fd_gossip_bloom_t filter[ 1 ];
     296             :   ulong mask;
     297             :   uint mask_bits;
     298             : };
     299             : 
     300             : typedef struct fd_gossip_crds_filter fd_gossip_crds_filter_t;
     301             : 
     302             : struct fd_gossip_pull_request {
     303             :   fd_gossip_crds_filter_t crds_filter[ 1 ];
     304             : 
     305             :   fd_gossip_value_t contact_info[ 1 ];
     306             : };
     307             : 
     308             : typedef struct fd_gossip_pull_request fd_gossip_pull_request_t;
     309             : 
     310             : struct fd_gossip_pull_response {
     311             :   uchar from[ 32UL ];
     312             :   ulong values_len;
     313             :   fd_gossip_value_t values[ FD_GOSSIP_MESSAGE_MAX_CRDS ];
     314             : };
     315             : 
     316             : typedef struct fd_gossip_pull_response fd_gossip_pull_response_t;
     317             : 
     318             : struct fd_gossip_push {
     319             :   uchar from[ 32UL ];
     320             :   ulong values_len;
     321             :   fd_gossip_value_t values[ FD_GOSSIP_MESSAGE_MAX_CRDS ];
     322             : };
     323             : 
     324             : typedef struct fd_gossip_push fd_gossip_push_t;
     325             : 
     326             : /* Tightest bound for prunes[] given network constraints.
     327             : 
     328             :      IPv6 minimum MTU             = 1280
     329             :      IPv6 header                  =   40
     330             :      UDP header                   =    8
     331             :      PACKET_DATA_SIZE             = 1232   (= 1280 - 40 - 8)
     332             : 
     333             :      Bytes consumed before prunes loop:
     334             :        Protocol tag(4) + sender(32) + pubkey(32) +
     335             :        prunes_len(8)                                         =  76
     336             : 
     337             :      Remaining: 1232 - 76 = 1156
     338             :      Each prune: 32 bytes
     339             :      Max prunes = floor(1156/32) = 36  */
     340             : 
     341             : struct fd_gossip_prune {
     342             :   uchar sender[ 32UL ];
     343             :   uchar pubkey[ 32UL ];
     344             :   ulong prunes_len;
     345             :   uchar prunes[ 36UL ][ 32UL ];
     346             :   uchar signature[ 64UL ];
     347             :   uchar destination[ 32UL ];
     348             :   ulong wallclock;
     349             : };
     350             : 
     351             : typedef struct fd_gossip_prune fd_gossip_prune_t;
     352             : 
     353             : struct fd_gossip_ping {
     354             :   uchar from[ 32UL ];
     355             :   uchar token[ 32UL ];
     356             :   uchar signature[ 64UL ];
     357             : };
     358             : 
     359             : typedef struct fd_gossip_ping fd_gossip_ping_t;
     360             : 
     361             : struct fd_gossip_pong {
     362             :   uchar from[ 32UL ];
     363             :   uchar hash[ 32UL ];
     364             :   uchar signature[ 64UL ];
     365             : };
     366             : 
     367             : typedef struct fd_gossip_pong fd_gossip_pong_t;
     368             : 
     369             : struct fd_gossip_message {
     370             :   uint tag;
     371             : 
     372             :   union {
     373             :     fd_gossip_pull_request_t  pull_request[ 1 ];
     374             :     fd_gossip_pull_response_t pull_response[ 1 ];
     375             :     fd_gossip_push_t          push[ 1 ];
     376             :     fd_gossip_prune_t         prune[ 1 ];
     377             :     fd_gossip_ping_t          ping[ 1 ];
     378             :     fd_gossip_pong_t          pong[ 1 ];
     379             :   };
     380             : };
     381             : 
     382             : typedef struct fd_gossip_message fd_gossip_message_t;
     383             : 
     384             : int
     385             : fd_gossip_message_deserialize( fd_gossip_message_t * message,
     386             :                                uchar const *         payload,
     387             :                                ulong                 payload_sz );
     388             : 
     389             : long
     390             : fd_gossip_value_serialize( fd_gossip_value_t const * value,
     391             :                            uchar *                   out,
     392             :                            ulong                     out_sz );
     393             : 
     394             : struct fd_gossip_update_message {
     395             :   int tag;
     396             : 
     397             :   uchar origin[ 32UL ];
     398             :   ulong wallclock;
     399             : 
     400             :   union {
     401             :     struct {
     402             :       ulong idx;
     403             :       fd_gossip_contact_info_t value[ 1 ];
     404             :     } contact_info[ 1 ];
     405             : 
     406             :     struct {
     407             :       ulong idx;
     408             :     } contact_info_remove[ 1 ];
     409             : 
     410             :     struct {
     411             :       fd_gossip_socket_t socket[ 1 ];
     412             :       fd_gossip_vote_t value[ 1 ];
     413             :     } vote[ 1 ];
     414             : 
     415             :     fd_gossip_duplicate_shred_t duplicate_shred[ 1 ];
     416             :     fd_gossip_snapshot_hashes_t snapshot_hashes[ 1 ];
     417             :   };
     418             : };
     419             : 
     420             : typedef struct fd_gossip_update_message fd_gossip_update_message_t;
     421             : 
     422             : long
     423             : fd_gossip_pull_request_init( uchar *       payload,
     424             :                              ulong         payload_sz,
     425             :                              ulong         num_keys,
     426             :                              ulong         num_bits,
     427             :                              ulong         mask,
     428             :                              uint          mask_bits,
     429             :                              uchar const * contact_info_crds,
     430             :                              ulong         contact_info_crds_sz,
     431             :                              ulong **      out_bloom_keys,
     432             :                              ulong **      out_bloom_bits,
     433             :                              ulong **      out_bits_set );
     434             : 
     435             : /* fd_gossip_version_cstr converts gossip version fields to a null
     436             :    terminated c-string.  Returns 1 on success and 0 on failure (e.g.
     437             :    small out_sz)
     438             : 
     439             :    The 16-bit minor field has a special encoding to support semver
     440             :    prerelease notation.
     441             :     - High 2 bits: prerelease channel (0=stable, 1=rc, 2=beta, 3=alpha)
     442             :     - Low 14 bits: actual minor version number
     443             : 
     444             :     Patch field semantics:
     445             :         - If prerelease_bits==0 (stable), `patch` is rendered as the
     446             :           normal semver patch component:
     447             :           `<major>.<minor_actual>.<patch>`.
     448             :         - If prerelease_bits!=0 (prerelease), the semver patch component
     449             :           is forced to 0 and `patch` is interpreted as the prerelease
     450             :           sequence number, rendered as:
     451             :           `<major>.<minor_actual>.0-<channel>.<patch>`.
     452             : 
     453             :     Note that due to Frankendancer's existing unique versioning hack,
     454             :     future Frankendancer releases will all be stable (i.e.
     455             :     prerelease_bits==0) and based on stable Agave versions.  This is a
     456             :     permissible compromise given Frankendancer is approaching EOL. */
     457             : static inline int
     458             : fd_gossip_version_cstr( ushort major,
     459             :                  ushort minor,
     460             :                  ushort patch,
     461             :                  char * out,
     462           0 :                  ulong  out_sz ) {
     463           0 :   ushort prerelease_bits = (minor >> 14U) & 0x3U;
     464           0 :   ushort minor_actual = minor & 0x3FFFU;
     465             : 
     466           0 :   if( FD_UNLIKELY( prerelease_bits ) ) {
     467           0 :     const char * names[] = { "", "rc", "beta", "alpha" };
     468           0 :     return fd_cstr_printf_check( out, out_sz, NULL, "%hu.%hu.0-%s.%hu", major, minor_actual, names[ prerelease_bits ], patch );
     469           0 :   } else {
     470           0 :     return fd_cstr_printf_check( out, out_sz, NULL, "%hu.%hu.%hu", major, minor_actual, patch );
     471           0 :   }
     472           0 : }
     473             : 
     474             : #endif /* HEADER_fd_src_flamenco_gossip_fd_gossip_message_h */

Generated by: LCOV version 1.14