LCOV - code coverage report
Current view: top level - flamenco/gossip - fd_gossip_message.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 50 96 52.1 %
Date: 2026-11-12 04:25:03 Functions: 2 162 1.2 %

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

Generated by: LCOV version 1.14