LCOV - code coverage report
Current view: top level - discof/gossip - fd_gossip_tile.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 728 0.0 %
Date: 2025-03-20 12:08:36 Functions: 0 23 0.0 %

          Line data    Source code
       1             : /* Gossip tile runs the gossip networking protcol for a Firedancer node. */
       2             : #define _GNU_SOURCE
       3             : 
       4             : #include "../../disco/topo/fd_topo.h"
       5             : #include "generated/fd_gossip_tile_seccomp.h"
       6             : 
       7             : #include "../store/util.h"
       8             : #include "../restart/fd_restart.h"
       9             : 
      10             : #include "../../disco/fd_disco.h"
      11             : #include "../../disco/keyguard/fd_keyload.h"
      12             : #include "../../disco/keyguard/fd_keyguard_client.h"
      13             : #include "../../disco/net/fd_net_tile.h"
      14             : #include "../../flamenco/gossip/fd_gossip.h"
      15             : #include "../../flamenco/runtime/fd_system_ids.h"
      16             : #include "../../util/net/fd_ip4.h"
      17             : #include "../../util/net/fd_udp.h"
      18             : #include "../../util/net/fd_net_headers.h"
      19             : #include "../../disco/plugin/fd_plugin.h"
      20             : 
      21             : #include <unistd.h>
      22             : #include <arpa/inet.h>
      23             : #include <linux/unistd.h>
      24             : #include <sys/random.h>
      25             : #include <netdb.h>
      26             : #include <netinet/in.h>
      27             : #include <sys/socket.h>
      28             : 
      29           0 : #define CONTACT_INFO_PUBLISH_TIME_NS ((long)5e9)
      30             : #define PLUGIN_PUBLISH_TIME_NS ((long)60e9)
      31             : 
      32           0 : #define IN_KIND_NET     (1)
      33           0 : #define IN_KIND_VOTER   (2)
      34           0 : #define IN_KIND_RESTART (3)
      35           0 : #define IN_KIND_SIGN    (4)
      36             : #define MAX_IN_LINKS    (8)
      37             : 
      38             : /* Scratch space is used for deserializing a gossip message.
      39             :    TODO: update */
      40           0 : #define SCRATCH_MAX (1<<16UL)
      41             : /* A minimal number of frames
      42             :    TODO: update */
      43           0 : #define SCRATCH_DEPTH (16UL)
      44             : 
      45             : static volatile ulong * fd_shred_version;
      46             : 
      47             : FD_FN_PURE static int
      48           0 : fd_pubkey_eq( fd_pubkey_t const * key1, fd_pubkey_t const * key2 ) {
      49           0 :   return memcmp( key1->key, key2->key, sizeof(fd_pubkey_t) ) == 0;
      50           0 : }
      51             : 
      52             : static ulong
      53           0 : fd_pubkey_hash( fd_pubkey_t const * key, ulong seed ) {
      54           0 :   return fd_hash( seed, key->key, sizeof(fd_pubkey_t) );
      55           0 : }
      56             : 
      57             : /* Contact info table */
      58             : #define MAP_NAME     fd_contact_info_table
      59             : #define MAP_KEY_T    fd_pubkey_t
      60           0 : #define MAP_KEY_EQ   fd_pubkey_eq
      61           0 : #define MAP_KEY_HASH fd_pubkey_hash
      62           0 : #define MAP_T        fd_contact_info_elem_t
      63             : #include "../../util/tmpl/fd_map_giant.c"
      64             : 
      65             : struct fd_gossip_tile_metrics {
      66             :   ulong last_crds_push_contact_info_publish_ts;
      67             :   ulong mismatched_contact_info_shred_version;
      68             : 
      69             :   /* Below metrics are segmented by TVU, Repair, Voter */
      70             :   ulong ipv6_contact_info[FD_METRICS_COUNTER_GOSSIP_IPV6_CONTACT_INFO_CNT];
      71             :   ulong zero_ipv4_contact_info[FD_METRICS_COUNTER_GOSSIP_ZERO_IPV4_CONTACT_INFO_CNT];
      72             :   ulong peer_counts[FD_METRICS_GAUGE_GOSSIP_PEER_COUNTS_CNT];
      73             : 
      74             :   ulong shred_version_zero;
      75             : };
      76             : typedef struct fd_gossip_tile_metrics fd_gossip_tile_metrics_t;
      77           0 : #define FD_GOSSIP_TILE_METRICS_FOOTPRINT ( sizeof( fd_gossip_tile_metrics_t ) )
      78             : 
      79             : typedef union {
      80             :   struct {
      81             :     fd_wksp_t * mem;
      82             :     ulong       chunk0;
      83             :     ulong       wmark;
      84             :   };
      85             :   fd_net_rx_bounds_t net_rx;
      86             : } fd_gossip_in_ctx_t;
      87             : 
      88             : struct fd_gossip_tile_ctx {
      89             :   fd_gossip_t * gossip;
      90             :   fd_gossip_config_t gossip_config;
      91             :   long last_shred_dest_push_time;
      92             :   long last_plugin_push_time;
      93             : 
      94             :   ulong gossip_seed;
      95             : 
      96             :   uchar              in_kind[ MAX_IN_LINKS ];
      97             :   fd_gossip_in_ctx_t in_links[ MAX_IN_LINKS ];
      98             : 
      99             :   fd_contact_info_elem_t * contact_info_table;
     100             : 
     101             :   fd_frag_meta_t * shred_contact_out_mcache;
     102             :   ulong *          shred_contact_out_sync;
     103             :   ulong            shred_contact_out_depth;
     104             :   ulong            shred_contact_out_seq;
     105             : 
     106             :   fd_wksp_t * shred_contact_out_mem;
     107             :   ulong       shred_contact_out_chunk0;
     108             :   ulong       shred_contact_out_wmark;
     109             :   ulong       shred_contact_out_chunk;
     110             : 
     111             :   fd_frag_meta_t * repair_contact_out_mcache;
     112             :   ulong *          repair_contact_out_sync;
     113             :   ulong            repair_contact_out_depth;
     114             :   ulong            repair_contact_out_seq;
     115             : 
     116             :   fd_wksp_t * repair_contact_out_mem;
     117             :   ulong       repair_contact_out_chunk0;
     118             :   ulong       repair_contact_out_wmark;
     119             :   ulong       repair_contact_out_chunk;
     120             : 
     121             :   fd_frag_meta_t * voter_contact_out_mcache;
     122             :   ulong *          voter_contact_out_sync;
     123             :   ulong            voter_contact_out_depth;
     124             :   ulong            voter_contact_out_seq;
     125             : 
     126             :   fd_wksp_t * voter_contact_out_mem;
     127             :   ulong       voter_contact_out_chunk0;
     128             :   ulong       voter_contact_out_wmark;
     129             :   ulong       voter_contact_out_chunk;
     130             : 
     131             :   fd_frag_meta_t * verify_out_mcache;
     132             :   ulong *          verify_out_sync;
     133             :   ulong            verify_out_depth;
     134             :   ulong            verify_out_seq;
     135             : 
     136             :   fd_wksp_t * verify_out_mem;
     137             :   ulong       verify_out_chunk0;
     138             :   ulong       verify_out_wmark;
     139             :   ulong       verify_out_chunk;
     140             : 
     141             :   fd_frag_meta_t * eqvoc_out_mcache;
     142             :   ulong *          eqvoc_out_sync;
     143             :   ulong            eqvoc_out_depth;
     144             :   ulong            eqvoc_out_seq;
     145             : 
     146             :   fd_wksp_t * eqvoc_out_mem;
     147             :   ulong       eqvoc_out_chunk0;
     148             :   ulong       eqvoc_out_wmark;
     149             :   ulong       eqvoc_out_chunk;
     150             : 
     151             :   fd_frag_meta_t * restart_out_mcache;
     152             :   ulong *          restart_out_sync;
     153             :   ulong            restart_out_depth;
     154             :   ulong            restart_out_seq;
     155             : 
     156             :   fd_wksp_t * restart_out_mem;
     157             :   ulong       restart_out_chunk0;
     158             :   ulong       restart_out_wmark;
     159             :   ulong       restart_out_chunk;
     160             : 
     161             :   fd_wksp_t *     wksp;
     162             :   fd_gossip_peer_addr_t gossip_my_addr;
     163             :   fd_gossip_peer_addr_t tvu_my_addr;
     164             :   fd_gossip_peer_addr_t tpu_my_addr;
     165             :   fd_gossip_peer_addr_t tpu_quic_my_addr;
     166             :   fd_gossip_peer_addr_t tpu_vote_my_addr;
     167             :   fd_gossip_peer_addr_t repair_serve_addr;
     168             :   ushort                gossip_listen_port;
     169             : 
     170             :   fd_frag_meta_t * net_out_mcache;
     171             :   ulong *          net_out_sync;
     172             :   ulong            net_out_depth;
     173             :   ulong            net_out_seq;
     174             : 
     175             :   fd_wksp_t * net_out_mem;
     176             :   ulong       net_out_chunk0;
     177             :   ulong       net_out_wmark;
     178             :   ulong       net_out_chunk;
     179             : 
     180             :   // Inputs to plugin/gui
     181             : 
     182             :   fd_wksp_t * gossip_plugin_out_mem;
     183             :   ulong       gossip_plugin_out_chunk0;
     184             :   ulong       gossip_plugin_out_wmark;
     185             :   ulong       gossip_plugin_out_chunk;
     186             :   ulong       gossip_plugin_out_idx;
     187             : 
     188             :   uchar         identity_private_key[32];
     189             :   fd_pubkey_t   identity_public_key;
     190             : 
     191             :   /* Includes Ethernet, IP, UDP headers */
     192             :   uchar gossip_buffer[ FD_NET_MTU ];
     193             : 
     194             :   ushort net_id;
     195             :   fd_ip4_udp_hdrs_t hdr[1];
     196             : 
     197             :   fd_keyguard_client_t  keyguard_client[1];
     198             : 
     199             :   fd_stem_context_t * stem;
     200             : 
     201             :   ulong replay_vote_txn_sz;
     202             :   uchar replay_vote_txn [ FD_TXN_MTU ];
     203             : 
     204             :   long  restart_last_push_time;
     205             :   ulong restart_last_vote_msg_sz;
     206             :   ulong restart_heaviest_fork_msg_sz;
     207             :   ulong restart_heaviest_fork_msg[ sizeof(fd_gossip_restart_heaviest_fork_t) ];
     208             :   uchar restart_last_vote_msg[ FD_RESTART_LINK_BYTES_MAX+sizeof(uint) ];
     209             : 
     210             :   /* Metrics */
     211             :   fd_gossip_tile_metrics_t metrics;
     212             : };
     213             : typedef struct fd_gossip_tile_ctx fd_gossip_tile_ctx_t;
     214             : 
     215             : FD_FN_CONST static inline ulong
     216           0 : scratch_align( void ) {
     217           0 :   return 128UL;
     218           0 : }
     219             : 
     220             : FD_FN_PURE static inline ulong
     221           0 : loose_footprint( fd_topo_tile_t const * tile FD_PARAM_UNUSED ) {
     222           0 :   return 1UL * FD_SHMEM_GIGANTIC_PAGE_SZ;
     223           0 : }
     224             : 
     225             : FD_FN_PURE static inline ulong
     226           0 : scratch_footprint( fd_topo_tile_t const * tile FD_PARAM_UNUSED ) {
     227           0 :   ulong l = FD_LAYOUT_INIT;
     228           0 :   l = FD_LAYOUT_APPEND( l, alignof(fd_gossip_tile_ctx_t), sizeof(fd_gossip_tile_ctx_t) );
     229           0 :   l = FD_LAYOUT_APPEND( l, fd_gossip_align(), fd_gossip_footprint() );
     230           0 :   l = FD_LAYOUT_APPEND( l, fd_contact_info_table_align(), fd_contact_info_table_footprint( FD_PEER_KEY_MAX ) );
     231           0 :   l = FD_LAYOUT_APPEND( l, fd_scratch_smem_align(), fd_scratch_smem_footprint( SCRATCH_MAX ) );
     232           0 :   l = FD_LAYOUT_APPEND( l, fd_scratch_fmem_align(), fd_scratch_fmem_footprint( SCRATCH_DEPTH ) );
     233           0 :   return FD_LAYOUT_FINI( l, scratch_align() );
     234           0 : }
     235             : 
     236             : static void
     237             : send_packet( fd_gossip_tile_ctx_t * ctx,
     238             :              uint                   dst_ip_addr,
     239             :              ushort                 dst_port,
     240             :              uchar const *          payload,
     241             :              ulong                  payload_sz,
     242           0 :              ulong                  tsorig ) {
     243           0 :   uchar * packet = fd_chunk_to_laddr( ctx->net_out_mem, ctx->net_out_chunk );
     244             : 
     245           0 :   fd_ip4_udp_hdrs_t * hdr = (fd_ip4_udp_hdrs_t *)packet;
     246           0 :   *hdr = *ctx->hdr;
     247             : 
     248           0 :   fd_ip4_hdr_t * ip4 = hdr->ip4;
     249           0 :   ip4->daddr       = dst_ip_addr;
     250           0 :   ip4->net_id      = fd_ushort_bswap( ctx->net_id++ );
     251           0 :   ip4->check       = 0U;
     252           0 :   ip4->net_tot_len = fd_ushort_bswap( (ushort)(payload_sz + sizeof(fd_ip4_hdr_t)+sizeof(fd_udp_hdr_t)) );
     253           0 :   ip4->check       = fd_ip4_hdr_check_fast( ip4 );
     254             : 
     255           0 :   fd_udp_hdr_t * udp = hdr->udp;
     256           0 :   udp->net_dport = dst_port;
     257           0 :   udp->net_len   = fd_ushort_bswap( (ushort)(payload_sz + sizeof(fd_udp_hdr_t)) );
     258           0 :   fd_memcpy( packet+sizeof(fd_ip4_udp_hdrs_t), payload, payload_sz );
     259           0 :   udp->check = 0U;
     260             : 
     261           0 :   ulong tspub     = fd_frag_meta_ts_comp( fd_tickcount() );
     262           0 :   ulong sig       = fd_disco_netmux_sig( dst_ip_addr, dst_port, dst_ip_addr, DST_PROTO_OUTGOING, sizeof(fd_ip4_udp_hdrs_t) );
     263           0 :   ulong packet_sz = payload_sz + sizeof(fd_ip4_udp_hdrs_t);
     264           0 :   fd_stem_publish( ctx->stem, 0UL, sig, ctx->net_out_chunk, packet_sz, 0UL, tsorig, tspub );
     265           0 :   ctx->net_out_chunk = fd_dcache_compact_next( ctx->net_out_chunk, packet_sz, ctx->net_out_chunk0, ctx->net_out_wmark );
     266           0 : }
     267             : 
     268             : static void
     269             : gossip_send_packet( uchar const * msg,
     270             :                     size_t msglen,
     271             :                     fd_gossip_peer_addr_t const * addr,
     272           0 :                     void * arg ) {
     273           0 : ulong tsorig = fd_frag_meta_ts_comp( fd_tickcount() );
     274           0 :   send_packet( arg, addr->addr, addr->port, msg, msglen, tsorig );
     275           0 : }
     276             : 
     277             : static int
     278           0 : is_vote_state_update_instr( uint discriminant ) {
     279           0 :   return discriminant == fd_vote_instruction_enum_vote ||
     280           0 :          discriminant == fd_vote_instruction_enum_vote_switch ||
     281           0 :          discriminant == fd_vote_instruction_enum_update_vote_state ||
     282           0 :          discriminant == fd_vote_instruction_enum_update_vote_state_switch ||
     283           0 :          discriminant == fd_vote_instruction_enum_compact_update_vote_state ||
     284           0 :          discriminant == fd_vote_instruction_enum_compact_update_vote_state_switch;
     285           0 : }
     286             : 
     287             : static int
     288           0 : verify_vote_txn( fd_gossip_vote_t const * vote ) {
     289           0 :   fd_txn_t const * parsed_txn = (fd_txn_t const *)fd_type_pun_const( vote->txn.txn );
     290           0 :   ushort instr_data_sz = parsed_txn->instr[0].data_sz;
     291           0 :   uchar const * instr_data = vote->txn.raw + parsed_txn->instr[0].data_off;
     292             : 
     293           0 :   fd_pubkey_t const * txn_accounts = (fd_pubkey_t const *)(vote->txn.raw + parsed_txn->acct_addr_off);
     294           0 :   uchar program_id = parsed_txn->instr[0].program_id;
     295             : 
     296           0 :   if( memcmp( txn_accounts[program_id].uc, &fd_solana_vote_program_id, sizeof(fd_pubkey_t) ) ) {
     297           0 :     return -1;
     298           0 :   }
     299             : 
     300             :   /* Check that txn only contains one instruction */
     301           0 :   if( parsed_txn->instr_cnt > 1 ) {
     302           0 :     return -1;
     303           0 :   }
     304             : 
     305           0 :   fd_bincode_decode_ctx_t decode = {
     306           0 :     .data    = instr_data,
     307           0 :     .dataend = instr_data + instr_data_sz
     308           0 :   };
     309             : 
     310           0 :   ulong total_sz      = 0UL;
     311           0 :   int   decode_result = fd_vote_instruction_decode_footprint( &decode, &total_sz );
     312           0 :   if( FD_UNLIKELY( decode_result != FD_BINCODE_SUCCESS ) ) {
     313           0 :     return -1;
     314           0 :   }
     315             : 
     316           0 :   uchar * mem = fd_scratch_alloc( fd_vote_instruction_align(), total_sz );
     317           0 :   if( FD_UNLIKELY( !mem ) ) {
     318           0 :     FD_LOG_ERR(( "Unable to allocate memory for vote instruction" ));
     319           0 :   }
     320             : 
     321           0 :   fd_vote_instruction_t * vote_instr = fd_vote_instruction_decode( mem, &decode );
     322             : 
     323           0 :   if( !is_vote_state_update_instr( vote_instr->discriminant ) ) {
     324           0 :     return -1;
     325           0 :   }
     326             : 
     327           0 :   return 0;
     328           0 : }
     329             : 
     330             : static void
     331             : gossip_deliver_fun( fd_crds_data_t * data,
     332           0 :                     void *           arg ) {
     333           0 :   fd_gossip_tile_ctx_t * ctx = (fd_gossip_tile_ctx_t *)arg;
     334             : 
     335           0 :   if( fd_crds_data_is_vote( data ) ) {
     336           0 :     if( FD_UNLIKELY( !ctx->verify_out_mcache ) ) return;
     337             : 
     338           0 :     fd_gossip_vote_t const * gossip_vote = &data->inner.vote;
     339           0 :     if( verify_vote_txn( gossip_vote ) != 0 ) {
     340           0 :       return;
     341           0 :     }
     342             : 
     343           0 :     uchar * vote_txn_msg = fd_chunk_to_laddr( ctx->verify_out_mem, ctx->verify_out_chunk );
     344           0 :     ulong vote_txn_sz    = gossip_vote->txn.raw_sz;
     345           0 :     memcpy( vote_txn_msg, gossip_vote->txn.raw, vote_txn_sz );
     346             : 
     347           0 :     ulong sig = 1UL;
     348           0 :     fd_mcache_publish( ctx->verify_out_mcache, ctx->verify_out_depth, ctx->verify_out_seq, sig, ctx->verify_out_chunk,
     349           0 :       vote_txn_sz, 0UL, 0, 0 );
     350           0 :     ctx->verify_out_seq   = fd_seq_inc( ctx->verify_out_seq, 1UL );
     351           0 :     ctx->verify_out_chunk = fd_dcache_compact_next( ctx->verify_out_chunk, vote_txn_sz, ctx->verify_out_chunk0, ctx->verify_out_wmark );
     352             : 
     353           0 :   } else if( fd_crds_data_is_contact_info_v1( data ) ) {
     354           0 :     fd_gossip_contact_info_v1_t const * contact_info = &data->inner.contact_info_v1;
     355           0 :     FD_LOG_DEBUG(("contact info v1 - ip: " FD_IP4_ADDR_FMT ", port: %u", FD_IP4_ADDR_FMT_ARGS( contact_info->gossip.inner.ip4.addr ), contact_info->gossip.inner.ip4.port ));
     356             : 
     357           0 :     fd_contact_info_elem_t * ele = fd_contact_info_table_query( ctx->contact_info_table, &contact_info->id, NULL );
     358           0 :     if (FD_UNLIKELY(!ele &&
     359           0 :                     !fd_contact_info_table_is_full(ctx->contact_info_table))) {
     360           0 :       ele = fd_contact_info_table_insert(ctx->contact_info_table,
     361           0 :                                          &contact_info->id);
     362           0 :     }
     363           0 :     if (ele) {
     364           0 :       ele->contact_info = *contact_info;
     365           0 :     }
     366           0 :   } else if( fd_crds_data_is_contact_info_v2( data ) ) {
     367           0 :     fd_gossip_contact_info_v2_t const * contact_info_v2 = &data->inner.contact_info_v2;
     368             : 
     369           0 :     fd_gossip_contact_info_v1_t contact_info;
     370           0 :     fd_gossip_contact_info_v2_to_v1( contact_info_v2, &contact_info );
     371           0 :     FD_LOG_DEBUG(("contact info v2 - ip: " FD_IP4_ADDR_FMT ", port: %u", FD_IP4_ADDR_FMT_ARGS( contact_info.gossip.inner.ip4.addr ), contact_info.gossip.inner.ip4.port ));
     372             : 
     373           0 :     fd_contact_info_elem_t * ele = fd_contact_info_table_query( ctx->contact_info_table, &contact_info.id, NULL );
     374           0 :     if (FD_UNLIKELY(!ele &&
     375           0 :                     !fd_contact_info_table_is_full(ctx->contact_info_table))) {
     376           0 :       ele = fd_contact_info_table_insert(ctx->contact_info_table,
     377           0 :                                          &contact_info.id);
     378           0 :     }
     379           0 :     if (ele) {
     380           0 :       ele->contact_info = contact_info;
     381           0 :     }
     382           0 :   } else if( fd_crds_data_is_duplicate_shred( data ) ) {
     383           0 :     if( FD_UNLIKELY( !ctx->eqvoc_out_mcache ) ) return;
     384             : 
     385           0 :     fd_gossip_duplicate_shred_t const * duplicate_shred = &data->inner.duplicate_shred;
     386           0 :     uchar * eqvoc_msg = fd_chunk_to_laddr( ctx->eqvoc_out_mem, ctx->eqvoc_out_chunk );
     387           0 :     memcpy( eqvoc_msg, duplicate_shred, FD_GOSSIP_DUPLICATE_SHRED_FOOTPRINT );
     388           0 :     memcpy( eqvoc_msg + FD_GOSSIP_DUPLICATE_SHRED_FOOTPRINT, duplicate_shred->chunk, duplicate_shred->chunk_len );
     389             : 
     390           0 :     ulong sig = 1UL;
     391           0 :     fd_mcache_publish( ctx->eqvoc_out_mcache,
     392           0 :                        ctx->eqvoc_out_depth,
     393           0 :                        ctx->eqvoc_out_seq,
     394           0 :                        sig,
     395           0 :                        ctx->eqvoc_out_chunk,
     396           0 :                        FD_GOSSIP_DUPLICATE_SHRED_FOOTPRINT,
     397           0 :                        0UL,
     398           0 :                        0,
     399           0 :                        0 );
     400           0 :     ctx->eqvoc_out_seq   = fd_seq_inc( ctx->eqvoc_out_seq, 1UL );
     401           0 :     ctx->eqvoc_out_chunk = fd_dcache_compact_next( ctx->eqvoc_out_chunk, FD_GOSSIP_DUPLICATE_SHRED_FOOTPRINT, ctx->eqvoc_out_chunk0, ctx->eqvoc_out_wmark );
     402           0 :   } else if( fd_crds_data_is_restart_last_voted_fork_slots( data ) ) {
     403           0 :     if( FD_UNLIKELY( !ctx->restart_out_mcache ) ) return;
     404             : 
     405           0 :     ulong struct_len       = sizeof( fd_gossip_restart_last_voted_fork_slots_t );
     406           0 :     uchar * last_vote_msg_ = fd_chunk_to_laddr( ctx->restart_out_mem, ctx->restart_out_chunk );
     407           0 :     FD_STORE( uint, last_vote_msg_, fd_crds_data_enum_restart_last_voted_fork_slots );
     408             : 
     409           0 :     ulong bitmap_len   = 0;
     410           0 :     uchar * bitmap_dst = last_vote_msg_+sizeof(uint)+struct_len;
     411           0 :     if ( FD_LIKELY( data->inner.restart_last_voted_fork_slots.offsets.discriminant==fd_restart_slots_offsets_enum_raw_offsets ) ) {
     412           0 :       uchar * bitmap_src = data->inner.restart_last_voted_fork_slots.offsets.inner.raw_offsets.offsets.bits.bits;
     413           0 :       bitmap_len         = data->inner.restart_last_voted_fork_slots.offsets.inner.raw_offsets.offsets.bits.bits_len;
     414           0 :       memcpy( bitmap_dst, bitmap_src, bitmap_len );
     415           0 :     } else {
     416           0 :       uchar bitmap_src [ FD_RESTART_RAW_BITMAP_BYTES_MAX ];
     417           0 :       fd_restart_convert_runlength_to_raw_bitmap( &data->inner.restart_last_voted_fork_slots, bitmap_src, &bitmap_len );
     418           0 :       if( FD_UNLIKELY( bitmap_len>FD_RESTART_RAW_BITMAP_BYTES_MAX ) ) {
     419           0 :         FD_LOG_WARNING(( "Ignore an invalid gossip message with bitmap length greater than %lu", FD_RESTART_RAW_BITMAP_BYTES_MAX ));
     420           0 :         return;
     421           0 :       }
     422           0 :       memcpy( bitmap_dst, bitmap_src, bitmap_len );
     423           0 :     }
     424             :     /* Copy the struct to the buffer now because it may be modified by fd_restart_convert_runlength_to_raw_bitmap */
     425           0 :     fd_memcpy( last_vote_msg_+sizeof(uint), &data->inner.restart_last_voted_fork_slots, struct_len );
     426             : 
     427           0 :     ulong total_len = sizeof(uint) + struct_len + bitmap_len;
     428           0 :     fd_mcache_publish( ctx->restart_out_mcache, ctx->restart_out_depth, ctx->restart_out_seq, 1UL, ctx->restart_out_chunk,
     429           0 :                        total_len, 0UL, 0, 0 );
     430           0 :     ctx->restart_out_seq   = fd_seq_inc( ctx->restart_out_seq, 1UL );
     431           0 :     ctx->restart_out_chunk = fd_dcache_compact_next( ctx->restart_out_chunk, total_len, ctx->restart_out_chunk0, ctx->restart_out_wmark );
     432           0 :   } else if( fd_crds_data_is_restart_heaviest_fork( data ) ) {
     433           0 :     if( FD_UNLIKELY( !ctx->restart_out_mcache ) ) return;
     434             : 
     435           0 :     uchar * heaviest_fork_msg_ = fd_chunk_to_laddr( ctx->restart_out_mem, ctx->restart_out_chunk );
     436           0 :     FD_STORE( uint, heaviest_fork_msg_, fd_crds_data_enum_restart_heaviest_fork );
     437             : 
     438           0 :     fd_memcpy( heaviest_fork_msg_+sizeof(uint),
     439           0 :                &data->inner.restart_heaviest_fork,
     440           0 :                sizeof(fd_gossip_restart_heaviest_fork_t) );
     441             : 
     442           0 :     ulong total_len = sizeof(uint) + sizeof(fd_gossip_restart_heaviest_fork_t);
     443           0 :     fd_mcache_publish( ctx->restart_out_mcache, ctx->restart_out_depth, ctx->restart_out_seq, 1UL, ctx->restart_out_chunk,
     444           0 :                        total_len, 0UL, 0, 0 );
     445           0 :     ctx->restart_out_seq   = fd_seq_inc( ctx->restart_out_seq, 1UL );
     446           0 :     ctx->restart_out_chunk = fd_dcache_compact_next( ctx->restart_out_chunk, total_len, ctx->restart_out_chunk0, ctx->restart_out_wmark );
     447           0 :   }
     448           0 : }
     449             : 
     450             : void
     451             : gossip_signer( void *        signer_ctx,
     452             :                uchar         signature[ static 64 ],
     453             :                uchar const * buffer,
     454             :                ulong         len,
     455           0 :                int           sign_type ) {
     456           0 :   fd_gossip_tile_ctx_t * ctx = (fd_gossip_tile_ctx_t *)signer_ctx;
     457           0 :   fd_keyguard_client_sign( ctx->keyguard_client, signature, buffer, len, sign_type );
     458           0 : }
     459             : 
     460             : static void
     461           0 : during_housekeeping( fd_gossip_tile_ctx_t * ctx ) {
     462           0 :   fd_gossip_settime( ctx->gossip, fd_log_wallclock() );
     463           0 : }
     464             : 
     465             : static inline int
     466             : before_frag( fd_gossip_tile_ctx_t * ctx,
     467             :              ulong                  in_idx,
     468             :              ulong                  seq FD_PARAM_UNUSED,
     469           0 :              ulong                  sig ) {
     470           0 :   uint in_kind = ctx->in_kind[ in_idx ];
     471           0 :   return in_kind != IN_KIND_VOTER && in_kind != IN_KIND_RESTART && fd_disco_netmux_sig_proto( sig ) != DST_PROTO_GOSSIP;
     472           0 : }
     473             : 
     474             : static inline void
     475             : during_frag( fd_gossip_tile_ctx_t * ctx,
     476             :              ulong                  in_idx,
     477             :              ulong                  seq FD_PARAM_UNUSED,
     478             :              ulong                  sig FD_PARAM_UNUSED,
     479             :              ulong                  chunk,
     480             :              ulong                  sz,
     481           0 :              ulong                  ctl ) {
     482             : 
     483           0 :   uint in_kind = ctx->in_kind[ in_idx ];
     484           0 :   fd_gossip_in_ctx_t const * in_ctx = &ctx->in_links[ in_idx ];
     485           0 :   if( in_kind==IN_KIND_RESTART ) {
     486           0 :     if( FD_UNLIKELY( chunk<in_ctx->chunk0 || chunk>in_ctx->wmark || sz>FD_RESTART_LINK_BYTES_MAX+sizeof(uint) ) ) {
     487           0 :       FD_LOG_ERR(( "chunk %lu %lu corrupt, not in range [%lu,%lu]", chunk, sz, in_ctx->chunk0, in_ctx->wmark ));
     488           0 :     }
     489             : 
     490           0 :     uchar * msg = fd_chunk_to_laddr( in_ctx->mem, chunk );
     491           0 :     uint discriminant = FD_LOAD( uint, msg );
     492           0 :     if( discriminant==fd_crds_data_enum_restart_last_voted_fork_slots ) {
     493           0 :       if( ctx->restart_last_vote_msg_sz!=0 ) {
     494           0 :         FD_LOG_ERR(( "Gossip tile expects fd_gossip_restart_last_voted_fork_slots_t only once." ));
     495           0 :       }
     496             :       /* Copy this message into ctx and after_frag will send it out periodically */
     497           0 :       FD_TEST( sz>=sizeof(uint)+sizeof(fd_gossip_restart_last_voted_fork_slots_t) );
     498           0 :       fd_memcpy( ctx->restart_last_vote_msg, msg+sizeof(uint), sz-sizeof(uint) );
     499           0 :       ctx->restart_last_vote_msg_sz = sz-sizeof(uint);
     500           0 :     } else if( discriminant==fd_crds_data_enum_restart_heaviest_fork ) {
     501           0 :       if( ctx->restart_heaviest_fork_msg_sz!=0 ) {
     502           0 :         FD_LOG_ERR(( "Gossip tile expects fd_gossip_restart_heaviest_fork_t only once." ));
     503           0 :       }
     504             :       /* Copy this message into ctx and after_frag will send it out periodically */
     505           0 :       FD_TEST( sz==sizeof(uint)+sizeof(fd_gossip_restart_heaviest_fork_t) );
     506           0 :       fd_memcpy( ctx->restart_heaviest_fork_msg, msg+sizeof(uint), sz-sizeof(uint) );
     507           0 :       ctx->restart_heaviest_fork_msg_sz = sz-sizeof(uint);
     508           0 :     }
     509           0 :     return;
     510           0 :   }
     511             : 
     512           0 :   if( in_kind == IN_KIND_VOTER ) {
     513           0 :     if( FD_UNLIKELY( chunk<in_ctx->chunk0 || chunk>in_ctx->wmark || sz>USHORT_MAX ) ) {
     514           0 :       FD_LOG_ERR(( "chunk %lu %lu corrupt, not in range [%lu,%lu]", chunk, sz, in_ctx->chunk0, in_ctx->wmark ));
     515           0 :     }
     516             : 
     517           0 :     ctx->replay_vote_txn_sz = sz;
     518           0 :     memcpy( ctx->replay_vote_txn, fd_chunk_to_laddr( in_ctx->mem, chunk ), sz );
     519           0 :     return;
     520           0 :   }
     521             : 
     522           0 :   if( in_kind!=IN_KIND_NET ) return;
     523             : 
     524           0 :   void const * src = fd_net_rx_translate_frag( &ctx->in_links[ in_idx ].net_rx, chunk, ctl, sz );
     525           0 :   fd_memcpy( ctx->gossip_buffer, src, sz );
     526           0 : }
     527             : 
     528             : static void
     529             : after_frag( fd_gossip_tile_ctx_t * ctx,
     530             :             ulong                  in_idx,
     531             :             ulong                  seq    FD_PARAM_UNUSED,
     532             :             ulong                  sig    FD_PARAM_UNUSED,
     533             :             ulong                  sz,
     534             :             ulong                  tsorig FD_PARAM_UNUSED,
     535             :             ulong                  tspub  FD_PARAM_UNUSED,
     536           0 :             fd_stem_context_t *    stem ) {
     537           0 :   uint in_kind = ctx->in_kind[ in_idx ];
     538             : 
     539             :   /* Messages from the replay tile for wen-restart are handled by after_credit periodically */
     540           0 :   if( in_kind==IN_KIND_RESTART ) return;
     541             : 
     542           0 :   if( in_kind==IN_KIND_VOTER ) {
     543           0 :     fd_crds_data_t vote_txn_crds;
     544           0 :     vote_txn_crds.discriminant          = fd_crds_data_enum_vote;
     545           0 :     vote_txn_crds.inner.vote.txn.raw_sz = ctx->replay_vote_txn_sz;
     546           0 :     memcpy( vote_txn_crds.inner.vote.txn.raw, ctx->replay_vote_txn, ctx->replay_vote_txn_sz );
     547           0 :     fd_txn_parse( vote_txn_crds.inner.vote.txn.raw, ctx->replay_vote_txn_sz, vote_txn_crds.inner.vote.txn.txn_buf, NULL );
     548             : 
     549           0 :     fd_gossip_push_value( ctx->gossip, &vote_txn_crds, NULL );
     550             : 
     551           0 :     static ulong sent_vote_cnt = 0;
     552           0 :     if ( ( ++sent_vote_cnt % 50 ) == 0 )
     553           0 :       FD_LOG_NOTICE(( "Gossip tile has sent %lu vote txns", sent_vote_cnt ));
     554             : 
     555           0 :     return;
     556           0 :   }
     557             : 
     558           0 :   if( in_kind!=IN_KIND_NET ) return;
     559             : 
     560           0 :   if( FD_UNLIKELY( sz<42 ) ) return;
     561             : 
     562           0 :   ctx->stem = stem;
     563           0 :   ulong hdr_sz = fd_disco_netmux_sig_hdr_sz( sig );
     564           0 :   fd_eth_hdr_t const * eth = (fd_eth_hdr_t const *)ctx->gossip_buffer;
     565           0 :   fd_ip4_hdr_t const * ip4 = (fd_ip4_hdr_t const *)( eth+1 );
     566           0 :   fd_udp_hdr_t const * udp = (fd_udp_hdr_t const *)( (ulong)ip4 + FD_IP4_GET_LEN( *ip4 ) );
     567           0 :   if( FD_UNLIKELY( (ulong)(udp+1) > (ulong)eth+sz ) ) return;
     568             : 
     569           0 :   fd_gossip_peer_addr_t peer_addr;
     570           0 :   peer_addr.l    = 0;
     571           0 :   peer_addr.addr = ip4->saddr;
     572           0 :   peer_addr.port = udp->net_sport;
     573             : 
     574           0 :   fd_gossip_recv_packet( ctx->gossip, ctx->gossip_buffer + hdr_sz, sz-hdr_sz, &peer_addr );
     575           0 : }
     576             : 
     577             : static void
     578             : publish_peers_to_plugin( fd_gossip_tile_ctx_t * ctx,
     579           0 :                          fd_stem_context_t *    stem ) {
     580           0 :   uchar * dst = (uchar *)fd_chunk_to_laddr( ctx->gossip_plugin_out_mem, ctx->gossip_plugin_out_chunk );
     581             : 
     582           0 :   ulong i = 0;
     583           0 :   for( fd_contact_info_table_iter_t iter = fd_contact_info_table_iter_init( ctx->contact_info_table );
     584           0 :        !fd_contact_info_table_iter_done( ctx->contact_info_table, iter ) && i < FD_CLUSTER_NODE_CNT;
     585           0 :        iter = fd_contact_info_table_iter_next( ctx->contact_info_table, iter ), ++i ) {
     586           0 :     fd_contact_info_elem_t const * ele = fd_contact_info_table_iter_ele_const( ctx->contact_info_table, iter );
     587           0 :     fd_gossip_update_msg_t * msg = (fd_gossip_update_msg_t *)(dst + sizeof(ulong) + i*FD_GOSSIP_LINK_MSG_SIZE);
     588           0 :     memset( msg, 0, FD_GOSSIP_LINK_MSG_SIZE );
     589           0 :     memcpy( msg->pubkey, ele->contact_info.id.key, sizeof(fd_pubkey_t) );
     590           0 :     msg->wallclock = ele->contact_info.wallclock;
     591           0 :     msg->shred_version = ele->contact_info.shred_version;
     592           0 : #define COPY_ADDR( _idx_, _srcname_ )                                                  \
     593           0 :     if( ele->contact_info._srcname_.discriminant == fd_gossip_socket_addr_enum_ip4 ) { \
     594           0 :       msg->addrs[ _idx_ ].ip = ele->contact_info._srcname_.inner.ip4.addr;             \
     595           0 :       msg->addrs[ _idx_ ].port = ele->contact_info._srcname_.inner.ip4.port;           \
     596           0 :     }
     597             :     /*
     598             :       0:  gossip_socket,
     599             :       1:  rpc_socket,
     600             :       2:  rpc_pubsub_socket,
     601             :       3:  serve_repair_socket_udp,
     602             :       4:  serve_repair_socket_quic,
     603             :       5:  tpu_socket_udp,
     604             :       6:  tpu_socket_quic,
     605             :       7:  tvu_socket_udp,
     606             :       8:  tvu_socket_quic,
     607             :       9:  tpu_forwards_socket_udp,
     608             :       10: tpu_forwards_socket_quic,
     609             :       11: tpu_vote_socket,
     610             :     */
     611           0 :     COPY_ADDR(0,  gossip);
     612           0 :     COPY_ADDR(1,  rpc);
     613           0 :     COPY_ADDR(2,  rpc_pubsub);
     614           0 :     COPY_ADDR(3,  serve_repair);
     615           0 :     COPY_ADDR(4,  serve_repair);
     616           0 :     COPY_ADDR(5,  tpu);
     617           0 :     COPY_ADDR(6,  tpu);
     618           0 :     COPY_ADDR(7,  tvu);
     619           0 :     COPY_ADDR(8,  tvu);
     620           0 :     COPY_ADDR(9,  tpu_fwd);
     621           0 :     COPY_ADDR(10, tpu_fwd);
     622           0 :     COPY_ADDR(11, tpu_vote);
     623           0 :   }
     624             : 
     625           0 :   *(ulong *)dst = i;
     626             : 
     627           0 :   ulong tspub = (ulong)fd_frag_meta_ts_comp( fd_tickcount() );
     628           0 :   fd_stem_publish( stem, ctx->gossip_plugin_out_idx, FD_PLUGIN_MSG_GOSSIP_UPDATE, ctx->gossip_plugin_out_chunk, 0, 0UL, 0UL, tspub );
     629           0 :   ctx->gossip_plugin_out_chunk = fd_dcache_compact_next( ctx->gossip_plugin_out_chunk, 8UL + 40200UL*(58UL+12UL*34UL), ctx->gossip_plugin_out_chunk0, ctx->gossip_plugin_out_wmark );
     630           0 : }
     631             : 
     632             : static void
     633             : after_credit( fd_gossip_tile_ctx_t * ctx,
     634             :               fd_stem_context_t *    stem,
     635             :               int *                  opt_poll_in,
     636           0 :               int *                  charge_busy ) {
     637           0 :   (void)opt_poll_in;
     638             : 
     639             :   /* TODO: Don't charge the tile as busy if after_credit isn't actually
     640             :      doing any work. */
     641           0 :   *charge_busy = 1;
     642             : 
     643           0 :   ctx->stem = stem;
     644           0 :   ulong tsorig = fd_frag_meta_ts_comp( fd_tickcount() );
     645             : 
     646           0 :   if( FD_LIKELY( ctx->shred_contact_out_sync  ) ) fd_mcache_seq_update( ctx->shred_contact_out_sync, ctx->shred_contact_out_seq );
     647           0 :   if( FD_LIKELY( ctx->repair_contact_out_sync ) ) fd_mcache_seq_update( ctx->repair_contact_out_sync, ctx->repair_contact_out_seq );
     648             : 
     649           0 :   long now = fd_gossip_gettime( ctx->gossip );
     650           0 :   if( ( now - ctx->last_shred_dest_push_time )>CONTACT_INFO_PUBLISH_TIME_NS &&
     651           0 :       ctx->shred_contact_out_mcache ) {
     652             : 
     653           0 :     ctx->metrics.last_crds_push_contact_info_publish_ts = (ulong)(ctx->last_shred_dest_push_time);
     654             : 
     655           0 :     ctx->last_shred_dest_push_time = now;
     656             : 
     657           0 :     ulong tvu_peer_cnt = 0;
     658           0 :     ulong repair_peers_cnt = 0;
     659           0 :     ulong voter_peers_cnt = 0;
     660             : 
     661           0 :     ulong * shred_dest_msg = fd_chunk_to_laddr( ctx->shred_contact_out_mem, ctx->shred_contact_out_chunk );
     662           0 :     fd_shred_dest_wire_t * tvu_peers = (fd_shred_dest_wire_t *)(shred_dest_msg+1);
     663           0 :     fd_shred_dest_wire_t * repair_peers = fd_chunk_to_laddr( ctx->repair_contact_out_mem, ctx->repair_contact_out_chunk );
     664           0 :     fd_shred_dest_wire_t * voter_peers = fd_chunk_to_laddr( ctx->voter_contact_out_mem, ctx->voter_contact_out_chunk );
     665           0 :     for( fd_contact_info_table_iter_t iter = fd_contact_info_table_iter_init( ctx->contact_info_table );
     666           0 :          !fd_contact_info_table_iter_done( ctx->contact_info_table, iter );
     667           0 :          iter = fd_contact_info_table_iter_next( ctx->contact_info_table, iter ) ) {
     668           0 :       fd_contact_info_elem_t const * ele = fd_contact_info_table_iter_ele_const( ctx->contact_info_table, iter );
     669             : 
     670           0 :       if( ele->contact_info.shred_version!=fd_gossip_get_shred_version( ctx->gossip ) ) {
     671           0 :         ctx->metrics.mismatched_contact_info_shred_version += 1UL;
     672           0 :         continue;
     673           0 :       }
     674             : 
     675           0 :       {
     676           0 :         if( !fd_gossip_socket_addr_is_ip4( &ele->contact_info.tvu ) ){
     677           0 :           ctx->metrics.ipv6_contact_info[ FD_METRICS_ENUM_PEER_TYPES_V_TVU_IDX ] += 1UL;
     678           0 :           continue;
     679           0 :         }
     680             : 
     681             :         // TODO: add a consistency check function for IP addresses
     682           0 :         if( ele->contact_info.tvu.inner.ip4.addr==0 ) {
     683           0 :           ctx->metrics.zero_ipv4_contact_info[ FD_METRICS_ENUM_PEER_TYPES_V_TVU_IDX ] += 1UL;
     684           0 :           continue;
     685           0 :         }
     686             : 
     687           0 :         tvu_peers[tvu_peer_cnt].ip4_addr = ele->contact_info.tvu.inner.ip4.addr;
     688           0 :         tvu_peers[tvu_peer_cnt].udp_port = ele->contact_info.tvu.inner.ip4.port;
     689           0 :         memcpy( tvu_peers[tvu_peer_cnt].pubkey, ele->contact_info.id.key, sizeof(fd_pubkey_t) );
     690             : 
     691           0 :         tvu_peer_cnt++;
     692           0 :       }
     693             : 
     694           0 :       {
     695           0 :         if( !fd_gossip_socket_addr_is_ip4( &ele->contact_info.repair ) ) {
     696           0 :           ctx->metrics.ipv6_contact_info[ FD_METRICS_ENUM_PEER_TYPES_V_REPAIR_IDX ] += 1UL;
     697           0 :           continue;
     698           0 :         }
     699             : 
     700             :         // TODO: add a consistency check function for IP addresses
     701           0 :         if( ele->contact_info.serve_repair.inner.ip4.addr == 0 ) {
     702           0 :           ctx->metrics.zero_ipv4_contact_info[ FD_METRICS_ENUM_PEER_TYPES_V_REPAIR_IDX ] += 1UL;
     703           0 :           continue;
     704           0 :         }
     705             : 
     706           0 :         repair_peers[repair_peers_cnt].ip4_addr = ele->contact_info.serve_repair.inner.ip4.addr;
     707           0 :         repair_peers[repair_peers_cnt].udp_port = ele->contact_info.serve_repair.inner.ip4.port;
     708           0 :         memcpy( repair_peers[repair_peers_cnt].pubkey, ele->contact_info.id.key, sizeof(fd_pubkey_t) );
     709             : 
     710           0 :         repair_peers_cnt++;
     711           0 :       }
     712             : 
     713           0 :       {
     714           0 :         if( !fd_gossip_socket_addr_is_ip4( &ele->contact_info.tpu_vote ) ) {
     715           0 :           ctx->metrics.ipv6_contact_info[ FD_METRICS_ENUM_PEER_TYPES_V_VOTER_IDX ] += 1UL;
     716           0 :           continue;
     717           0 :         }
     718             : 
     719             :         // TODO: add a consistency check function for IP addresses
     720           0 :         if( ele->contact_info.tpu_vote.inner.ip4.addr == 0 ) {
     721           0 :           ctx->metrics.zero_ipv4_contact_info[ FD_METRICS_ENUM_PEER_TYPES_V_VOTER_IDX ] += 1UL;
     722           0 :           continue;
     723           0 :         }
     724             : 
     725           0 :         voter_peers[voter_peers_cnt].ip4_addr = ele->contact_info.tpu_vote.inner.ip4.addr;
     726           0 :         voter_peers[voter_peers_cnt].udp_port = ele->contact_info.tpu_vote.inner.ip4.port;
     727           0 :         memcpy( voter_peers[voter_peers_cnt].pubkey, ele->contact_info.id.key, sizeof(fd_pubkey_t) );
     728             : 
     729           0 :         voter_peers_cnt++;
     730           0 :       }
     731           0 :     }
     732             : 
     733           0 : #define UPDATE_PEER_CNTS( _peer_cnt_, _peer_type_ ) \
     734           0 :   ctx->metrics.peer_counts[ FD_METRICS_ENUM_PEER_TYPES_V_ ##_peer_type_ ##_IDX ] = _peer_cnt_;
     735             : 
     736           0 :     UPDATE_PEER_CNTS( tvu_peer_cnt, TVU );
     737           0 :     UPDATE_PEER_CNTS( repair_peers_cnt, REPAIR );
     738           0 :     UPDATE_PEER_CNTS( voter_peers_cnt, VOTER );
     739             : 
     740           0 : #undef UPDATE_PEER_CNTS
     741             : 
     742           0 :     ulong tspub = fd_frag_meta_ts_comp( fd_tickcount() );
     743             : 
     744           0 :     FD_LOG_INFO(( "publishing peers - tvu: %lu, repair: %lu, tpu_vote: %lu", tvu_peer_cnt, repair_peers_cnt, voter_peers_cnt ));
     745           0 :     if( tvu_peer_cnt>0 && ctx->shred_contact_out_mcache ) {
     746           0 :       *shred_dest_msg         = tvu_peer_cnt;
     747           0 :       ulong shred_contact_sz  = sizeof(ulong) + (tvu_peer_cnt * sizeof(fd_shred_dest_wire_t));
     748           0 :       ulong shred_contact_sig = 2UL;
     749           0 :       fd_mcache_publish( ctx->shred_contact_out_mcache, ctx->shred_contact_out_depth, ctx->shred_contact_out_seq, shred_contact_sig, ctx->shred_contact_out_chunk,
     750           0 :         shred_contact_sz, 0UL, tsorig, tspub );
     751           0 :       ctx->shred_contact_out_seq   = fd_seq_inc( ctx->shred_contact_out_seq, 1UL );
     752           0 :       ctx->shred_contact_out_chunk = fd_dcache_compact_next( ctx->shred_contact_out_chunk, shred_contact_sz, ctx->shred_contact_out_chunk0, ctx->shred_contact_out_wmark );
     753           0 :     }
     754             : 
     755           0 :     if( repair_peers_cnt>0 && ctx->repair_contact_out_mcache ) {
     756           0 :       ulong repair_contact_sz  = (repair_peers_cnt * sizeof(fd_shred_dest_wire_t));
     757           0 :       ulong repair_contact_sig = 3UL;
     758           0 :       fd_mcache_publish( ctx->repair_contact_out_mcache, ctx->repair_contact_out_depth, ctx->repair_contact_out_seq, repair_contact_sig, ctx->repair_contact_out_chunk,
     759           0 :         repair_peers_cnt, 0UL, tsorig, tspub );
     760           0 :       ctx->repair_contact_out_seq   = fd_seq_inc( ctx->repair_contact_out_seq, 1UL );
     761           0 :       ctx->repair_contact_out_chunk = fd_dcache_compact_next( ctx->repair_contact_out_chunk, repair_contact_sz, ctx->repair_contact_out_chunk0, ctx->repair_contact_out_wmark );
     762           0 :     }
     763             : 
     764           0 :     if( voter_peers_cnt>0 && ctx->voter_contact_out_mcache ) {
     765           0 :       ulong voter_contact_sz  = (voter_peers_cnt * sizeof(fd_shred_dest_wire_t));
     766           0 :       ulong voter_contact_sig = 4UL;
     767           0 :       fd_mcache_publish( ctx->voter_contact_out_mcache, ctx->voter_contact_out_depth, ctx->voter_contact_out_seq, voter_contact_sig, ctx->voter_contact_out_chunk,
     768           0 :         voter_peers_cnt, 0UL, tsorig, tspub );
     769           0 :       ctx->voter_contact_out_seq   = fd_seq_inc( ctx->voter_contact_out_seq, 1UL );
     770           0 :       ctx->voter_contact_out_chunk = fd_dcache_compact_next( ctx->voter_contact_out_chunk, voter_contact_sz, ctx->voter_contact_out_chunk0, ctx->voter_contact_out_wmark );
     771           0 :     }
     772           0 :   }
     773             : 
     774           0 :   if( ctx->gossip_plugin_out_mem && FD_UNLIKELY( ( now - ctx->last_plugin_push_time )>PLUGIN_PUBLISH_TIME_NS ) ) {
     775           0 :     ctx->last_plugin_push_time = now;
     776           0 :     publish_peers_to_plugin( ctx, stem );
     777           0 :   }
     778             : 
     779           0 :   if( FD_UNLIKELY(( ctx->restart_last_push_time+FD_RESTART_MSG_PUBLISH_PERIOD_NS<now )) ) {
     780           0 :     ctx->restart_last_push_time = now;
     781             : 
     782           0 :     if( FD_UNLIKELY( ctx->restart_last_vote_msg_sz>0 ) ) {
     783           0 :       fd_crds_data_t restart_last_vote_msg;
     784           0 :       restart_last_vote_msg.discriminant = fd_crds_data_enum_restart_last_voted_fork_slots;
     785           0 :       fd_memcpy( &restart_last_vote_msg.inner.restart_last_voted_fork_slots,
     786           0 :                  ctx->restart_last_vote_msg,
     787           0 :                  sizeof(fd_gossip_restart_last_voted_fork_slots_t) );
     788             : 
     789           0 :       restart_last_vote_msg.inner.restart_last_voted_fork_slots.shred_version = fd_gossip_get_shred_version( ctx->gossip );
     790           0 :       restart_last_vote_msg.inner.restart_last_voted_fork_slots.offsets.inner.raw_offsets.offsets.bits.bits = ctx->restart_last_vote_msg + sizeof(fd_gossip_restart_last_voted_fork_slots_t);
     791             : 
     792             :       /* Convert the raw bitmap into RunLengthEncoding before sending out */
     793           0 :       fd_restart_run_length_encoding_inner_t runlength_encoding[ FD_RESTART_PACKET_BITMAP_BYTES_MAX/sizeof(ushort) ];
     794           0 :       fd_restart_convert_raw_bitmap_to_runlength( &restart_last_vote_msg.inner.restart_last_voted_fork_slots, runlength_encoding );
     795             : 
     796           0 :       FD_TEST( fd_gossip_push_value( ctx->gossip, &restart_last_vote_msg, NULL )==0 );
     797           0 :       FD_LOG_NOTICE(( "Send out restart_last_voted_fork_slots message with bitmap=%luB, vote_slot=%lu, bank_hash=%s, shred_version=%u",
     798           0 :                       restart_last_vote_msg.inner.restart_last_voted_fork_slots.offsets.inner.run_length_encoding.offsets_len*sizeof(ushort),
     799           0 :                       restart_last_vote_msg.inner.restart_last_voted_fork_slots.last_voted_slot,
     800           0 :                       FD_BASE58_ENC_32_ALLOCA( &restart_last_vote_msg.inner.restart_last_voted_fork_slots.last_voted_hash ),
     801           0 :                       restart_last_vote_msg.inner.restart_last_voted_fork_slots.shred_version ));
     802           0 :     }
     803             : 
     804           0 :     if( FD_UNLIKELY( ctx->restart_heaviest_fork_msg_sz>0 ) ) {
     805           0 :       fd_crds_data_t restart_heaviest_fork_msg;
     806           0 :       restart_heaviest_fork_msg.discriminant = fd_crds_data_enum_restart_heaviest_fork;
     807           0 :       fd_memcpy( &restart_heaviest_fork_msg.inner.restart_heaviest_fork,
     808           0 :                  ctx->restart_heaviest_fork_msg,
     809           0 :                  sizeof(fd_gossip_restart_heaviest_fork_t) );
     810           0 :       restart_heaviest_fork_msg.inner.restart_heaviest_fork.shred_version = fd_gossip_get_shred_version( ctx->gossip );
     811             : 
     812           0 :       FD_TEST( fd_gossip_push_value( ctx->gossip, &restart_heaviest_fork_msg, NULL )==0 );
     813           0 :       FD_LOG_NOTICE(( "Send out restart_heaviest_fork gossip message with slot=%lu, hash=%s, shred_version=%u",
     814           0 :                        restart_heaviest_fork_msg.inner.restart_heaviest_fork.last_slot,
     815           0 :                        FD_BASE58_ENC_32_ALLOCA( &restart_heaviest_fork_msg.inner.restart_heaviest_fork.last_slot_hash ),
     816           0 :                        restart_heaviest_fork_msg.inner.restart_heaviest_fork.shred_version ));
     817             : 
     818           0 :     }
     819           0 :   }
     820             : 
     821           0 :   ushort shred_version = fd_gossip_get_shred_version( ctx->gossip );
     822           0 :   if( shred_version!=0U ) {
     823           0 :     *fd_shred_version = shred_version;
     824           0 :   } else {
     825           0 :     ctx->metrics.shred_version_zero += 1UL;
     826           0 :   }
     827           0 :   fd_gossip_continue( ctx->gossip );
     828           0 : }
     829             : 
     830             : static void
     831             : privileged_init( fd_topo_t *      topo,
     832           0 :                  fd_topo_tile_t * tile ) {
     833           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     834             : 
     835           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     836           0 :   fd_gossip_tile_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_gossip_tile_ctx_t), sizeof(fd_gossip_tile_ctx_t) );
     837           0 :   fd_memset( ctx, 0, sizeof(fd_gossip_tile_ctx_t) );
     838             : 
     839           0 :   uchar const * identity_key = fd_keyload_load( tile->gossip.identity_key_path, /* pubkey only: */ 1 );
     840           0 :   fd_memcpy( ctx->identity_public_key.uc, identity_key, sizeof(fd_pubkey_t) );
     841             : 
     842           0 :   FD_TEST( sizeof(ulong) == getrandom( &ctx->gossip_seed, sizeof(ulong), 0 ) );
     843           0 : }
     844             : 
     845             : static void
     846             : unprivileged_init( fd_topo_t *      topo,
     847           0 :                    fd_topo_tile_t * tile ) {
     848           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     849             : 
     850           0 :   if( FD_UNLIKELY( !tile->out_cnt ) ) FD_LOG_ERR(( "gossip tile has no primary output link" ));
     851             : 
     852           0 :   if( FD_UNLIKELY( !tile->gossip.ip_addr ) ) FD_LOG_ERR(( "gossip ip address not set" ));
     853           0 :   if( FD_UNLIKELY( !tile->gossip.gossip_listen_port ) ) FD_LOG_ERR(( "gossip listen port not set" ));
     854             : 
     855             :   /* Scratch mem setup */
     856           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     857           0 :   fd_gossip_tile_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_gossip_tile_ctx_t), sizeof(fd_gossip_tile_ctx_t) );
     858           0 :   ctx->gossip = FD_SCRATCH_ALLOC_APPEND( l, fd_gossip_align(), fd_gossip_footprint() );
     859           0 :   ctx->contact_info_table = fd_contact_info_table_join( fd_contact_info_table_new( FD_SCRATCH_ALLOC_APPEND( l, fd_contact_info_table_align(), fd_contact_info_table_footprint( FD_PEER_KEY_MAX ) ), FD_PEER_KEY_MAX, 0 ) );
     860             : 
     861           0 :   if( FD_UNLIKELY( tile->in_cnt > MAX_IN_LINKS ) ) FD_LOG_ERR(( "gossip tile has too many input links" ));
     862             : 
     863           0 :   uint sign_link_in_idx = UINT_MAX;
     864           0 :   memset( ctx->in_kind, 0, sizeof(ctx->in_kind) );
     865           0 :   for( uint in_idx=0U; in_idx<(tile->in_cnt); in_idx++ ) {
     866           0 :     fd_topo_link_t * link = &topo->links[ tile->in_link_id[ in_idx ] ];
     867           0 :     if( 0==strcmp( link->name, "net_gossip" ) ) {
     868           0 :       ctx->in_kind[ in_idx ] = IN_KIND_NET;
     869           0 :       fd_net_rx_bounds_init( &ctx->in_links[ in_idx ].net_rx, link->dcache );
     870           0 :       continue;
     871           0 :     } else if( 0==strcmp( link->name, "voter_gossip" ) ) {
     872           0 :       ctx->in_kind[ in_idx ] = IN_KIND_VOTER;
     873           0 :     } else if( 0==strcmp( link->name, "rstart_gossi" ) ) {
     874           0 :       ctx->in_kind[ in_idx ] = IN_KIND_RESTART;
     875           0 :     } else if( 0==strcmp( link->name, "sign_gossip" ) ) {
     876           0 :       ctx->in_kind[ in_idx ] = IN_KIND_SIGN;
     877           0 :       sign_link_in_idx = in_idx;
     878           0 :     } else {
     879           0 :       FD_LOG_ERR(( "gossip tile has unexpected input link %s", link->name ));
     880           0 :     }
     881             : 
     882           0 :     ctx->in_links[ in_idx ].mem    = topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ].wksp;
     883           0 :     ctx->in_links[ in_idx ].chunk0 = fd_dcache_compact_chunk0( ctx->in_links[ in_idx ].mem, link->dcache );
     884           0 :     ctx->in_links[ in_idx ].wmark  = fd_dcache_compact_wmark( ctx->in_links[ in_idx ].mem, link->dcache, link->mtu );
     885           0 :   }
     886           0 :   if( FD_UNLIKELY( sign_link_in_idx==UINT_MAX ) ) FD_LOG_ERR(( "Missing sign_gossip link" ));
     887             : 
     888           0 :   uint sign_link_out_idx = UINT_MAX;
     889           0 :   for( uint out_idx=0U; out_idx<(tile->out_cnt); out_idx++ ) {
     890           0 :     fd_topo_link_t * link = &topo->links[ tile->out_link_id[ out_idx ] ];
     891             : 
     892           0 :     if( 0==strcmp( link->name, "gossip_net" ) ) {
     893             : 
     894           0 :       if( FD_UNLIKELY( ctx->net_out_mcache ) ) FD_LOG_ERR(( "gossip tile has multiple gossip_net out links" ));
     895           0 :       ctx->net_out_mcache = link->mcache;
     896           0 :       ctx->net_out_sync   = fd_mcache_seq_laddr( ctx->net_out_mcache );
     897           0 :       ctx->net_out_depth  = fd_mcache_depth( ctx->net_out_mcache );
     898           0 :       ctx->net_out_seq    = fd_mcache_seq_query( ctx->net_out_sync );
     899           0 :       ctx->net_out_chunk0 = fd_dcache_compact_chunk0( fd_wksp_containing( link->dcache ), link->dcache );
     900           0 :       ctx->net_out_mem    = topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ].wksp;
     901           0 :       ctx->net_out_wmark  = fd_dcache_compact_wmark( ctx->net_out_mem, link->dcache, link->mtu );
     902           0 :       ctx->net_out_chunk  = ctx->net_out_chunk0;
     903             : 
     904           0 :     } else if( 0==strcmp( link->name, "crds_shred" ) ) {
     905             : 
     906             : 
     907           0 :       if( FD_UNLIKELY( ctx->shred_contact_out_mcache ) ) FD_LOG_ERR(( "gossip tile has multiple crds_shred out links" ));
     908           0 :       ctx->shred_contact_out_mcache = link->mcache;
     909           0 :       ctx->shred_contact_out_sync   = fd_mcache_seq_laddr( ctx->shred_contact_out_mcache );
     910           0 :       ctx->shred_contact_out_depth  = fd_mcache_depth( ctx->shred_contact_out_mcache );
     911           0 :       ctx->shred_contact_out_seq    = fd_mcache_seq_query( ctx->shred_contact_out_sync );
     912           0 :       ctx->shred_contact_out_mem    = topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ].wksp;
     913           0 :       ctx->shred_contact_out_chunk0 = fd_dcache_compact_chunk0( ctx->shred_contact_out_mem, link->dcache );
     914           0 :       ctx->shred_contact_out_wmark  = fd_dcache_compact_wmark ( ctx->shred_contact_out_mem, link->dcache, link->mtu );
     915           0 :       ctx->shred_contact_out_chunk  = ctx->shred_contact_out_chunk0;
     916             : 
     917           0 :     } else if( 0==strcmp( link->name, "gossip_repai" ) ) {
     918             : 
     919           0 :       if( FD_UNLIKELY( ctx->repair_contact_out_mcache ) ) FD_LOG_ERR(( "gossip tile has multiple gossip_repair out links" ));
     920           0 :       ctx->repair_contact_out_mcache = link->mcache;
     921           0 :       ctx->repair_contact_out_sync   = fd_mcache_seq_laddr( ctx->repair_contact_out_mcache );
     922           0 :       ctx->repair_contact_out_depth  = fd_mcache_depth( ctx->repair_contact_out_mcache );
     923           0 :       ctx->repair_contact_out_seq    = fd_mcache_seq_query( ctx->repair_contact_out_sync );
     924           0 :       ctx->repair_contact_out_mem    = topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ].wksp;
     925           0 :       ctx->repair_contact_out_chunk0 = fd_dcache_compact_chunk0( ctx->repair_contact_out_mem, link->dcache );
     926           0 :       ctx->repair_contact_out_wmark  = fd_dcache_compact_wmark ( ctx->repair_contact_out_mem, link->dcache, link->mtu );
     927           0 :       ctx->repair_contact_out_chunk  = ctx->repair_contact_out_chunk0;
     928             : 
     929           0 :     } else if( 0==strcmp( link->name, "gossip_verif" ) ) {
     930             : 
     931           0 :       if( FD_UNLIKELY( ctx->verify_out_mcache ) ) FD_LOG_ERR(( "gossip tile has multiple gossip_verif out links" ));
     932           0 :       ctx->verify_out_mcache = link->mcache;
     933           0 :       ctx->verify_out_sync   = fd_mcache_seq_laddr( ctx->verify_out_mcache );
     934           0 :       ctx->verify_out_depth  = fd_mcache_depth( ctx->verify_out_mcache );
     935           0 :       ctx->verify_out_seq    = fd_mcache_seq_query( ctx->verify_out_sync );
     936           0 :       ctx->verify_out_mem    = topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ].wksp;
     937           0 :       ctx->verify_out_chunk0 = fd_dcache_compact_chunk0( ctx->verify_out_mem, link->dcache );
     938           0 :       ctx->verify_out_wmark  = fd_dcache_compact_wmark ( ctx->verify_out_mem, link->dcache, link->mtu );
     939           0 :       ctx->verify_out_chunk  = ctx->verify_out_chunk0;
     940             : 
     941           0 :     } else if( 0==strcmp( link->name, "gossip_sign" ) ) {
     942             : 
     943           0 :       sign_link_out_idx = out_idx;
     944             : 
     945           0 :     } else if( 0==strcmp( link->name, "gossip_voter" ) ) {
     946             : 
     947           0 :       if( FD_UNLIKELY( ctx->voter_contact_out_mcache ) ) FD_LOG_ERR(( "gossip tile has multiple gossip_voter out links" ));
     948           0 :       ctx->voter_contact_out_mcache = link->mcache;
     949           0 :       ctx->voter_contact_out_sync   = fd_mcache_seq_laddr( ctx->voter_contact_out_mcache );
     950           0 :       ctx->voter_contact_out_depth  = fd_mcache_depth( ctx->voter_contact_out_mcache );
     951           0 :       ctx->voter_contact_out_seq    = fd_mcache_seq_query( ctx->voter_contact_out_sync );
     952           0 :       ctx->voter_contact_out_mem    = topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ].wksp;
     953           0 :       ctx->voter_contact_out_chunk0 = fd_dcache_compact_chunk0( ctx->voter_contact_out_mem, link->dcache );
     954           0 :       ctx->voter_contact_out_wmark  = fd_dcache_compact_wmark ( ctx->voter_contact_out_mem, link->dcache, link->mtu );
     955           0 :       ctx->voter_contact_out_chunk  = ctx->voter_contact_out_chunk0;
     956             : 
     957           0 :     } else if( 0==strcmp( link->name, "gossip_eqvoc" ) ) {
     958             : 
     959           0 :       if( FD_UNLIKELY( ctx->eqvoc_out_mcache ) ) FD_LOG_ERR(( "gossip tile has multiple gossip_eqvoc out links" ));
     960           0 :       ctx->eqvoc_out_mcache = link->mcache;
     961           0 :       ctx->eqvoc_out_sync   = fd_mcache_seq_laddr( ctx->eqvoc_out_mcache );
     962           0 :       ctx->eqvoc_out_depth  = fd_mcache_depth( ctx->eqvoc_out_mcache );
     963           0 :       ctx->eqvoc_out_seq    = fd_mcache_seq_query( ctx->eqvoc_out_sync );
     964           0 :       ctx->eqvoc_out_mem    = topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ].wksp;
     965           0 :       ctx->eqvoc_out_chunk0 = fd_dcache_compact_chunk0( ctx->eqvoc_out_mem, link->dcache );
     966           0 :       ctx->eqvoc_out_wmark  = fd_dcache_compact_wmark ( ctx->eqvoc_out_mem, link->dcache, link->mtu );
     967           0 :       ctx->eqvoc_out_chunk  = ctx->eqvoc_out_chunk0;
     968             : 
     969           0 :     } else if( 0==strcmp( link->name, "gossi_rstart" ) ) {
     970             : 
     971           0 :       if( FD_UNLIKELY( ctx->restart_out_mcache ) ) FD_LOG_ERR(( "gossip tile has multiple gossi_rstart out links" ));
     972           0 :       ctx->restart_out_mcache = link->mcache;
     973           0 :       ctx->restart_out_sync   = fd_mcache_seq_laddr( ctx->restart_out_mcache );
     974           0 :       ctx->restart_out_depth  = fd_mcache_depth( ctx->restart_out_mcache );
     975           0 :       ctx->restart_out_seq    = fd_mcache_seq_query( ctx->restart_out_sync );
     976           0 :       ctx->restart_out_mem    = topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ].wksp;
     977           0 :       ctx->restart_out_chunk0 = fd_dcache_compact_chunk0( ctx->restart_out_mem, link->dcache );
     978           0 :       ctx->restart_out_wmark  = fd_dcache_compact_wmark ( ctx->restart_out_mem, link->dcache, link->mtu );
     979           0 :       ctx->restart_out_chunk  = ctx->restart_out_chunk0;
     980             : 
     981           0 :     } else if( 0==strcmp( link->name, "gossip_plugi" ) ) {
     982             : 
     983           0 :       if( FD_UNLIKELY( ctx->gossip_plugin_out_mem ) ) FD_LOG_ERR(( "gossip tile has multiple gossip_plugi out links" ));
     984           0 :       ctx->gossip_plugin_out_mem    = topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ].wksp;
     985           0 :       ctx->gossip_plugin_out_chunk0 = fd_dcache_compact_chunk0( ctx->gossip_plugin_out_mem, link->dcache );
     986           0 :       ctx->gossip_plugin_out_wmark  = fd_dcache_compact_wmark ( ctx->gossip_plugin_out_mem, link->dcache, link->mtu );
     987           0 :       ctx->gossip_plugin_out_chunk  = ctx->gossip_plugin_out_chunk0;
     988           0 :       ctx->gossip_plugin_out_idx    = out_idx;
     989             : 
     990           0 :     } else {
     991           0 :       FD_LOG_ERR(( "gossip tile has unexpected output link %s", link->name ));
     992           0 :     }
     993             : 
     994           0 :   }
     995           0 :   if( FD_UNLIKELY( sign_link_out_idx==UINT_MAX ) ) FD_LOG_ERR(( "Missing gossip_sign link" ));
     996             : 
     997           0 :   void * smem = FD_SCRATCH_ALLOC_APPEND( l, fd_scratch_smem_align(), fd_scratch_smem_footprint( SCRATCH_MAX ) );
     998           0 :   void * fmem = FD_SCRATCH_ALLOC_APPEND( l, fd_scratch_fmem_align(), fd_scratch_fmem_footprint( SCRATCH_DEPTH ) );
     999             : 
    1000           0 :   FD_TEST( ( !!smem ) & ( !!fmem ) );
    1001           0 :   fd_scratch_attach( smem, fmem, SCRATCH_MAX, SCRATCH_DEPTH );
    1002             : 
    1003           0 :   ctx->wksp = topo->workspaces[ topo->objs[ tile->tile_obj_id ].wksp_id ].wksp;
    1004             : 
    1005           0 :   ctx->gossip_my_addr.addr = tile->gossip.ip_addr;
    1006           0 :   ctx->gossip_my_addr.port = fd_ushort_bswap( tile->gossip.gossip_listen_port );
    1007             : 
    1008           0 :   ctx->gossip_listen_port = tile->gossip.gossip_listen_port;
    1009             : 
    1010           0 :   FD_TEST( ctx->gossip_listen_port!=0 );
    1011             : 
    1012           0 :   ctx->net_id = (ushort)0;
    1013             : 
    1014           0 :   fd_ip4_udp_hdr_init( ctx->hdr, FD_NET_MTU, ctx->gossip_my_addr.addr, ctx->gossip_listen_port );
    1015             : 
    1016           0 :   ctx->last_shred_dest_push_time    = 0;
    1017           0 :   ctx->restart_last_push_time       = 0;
    1018           0 :   ctx->restart_last_vote_msg_sz     = 0;
    1019           0 :   ctx->restart_heaviest_fork_msg_sz = 0;
    1020             : 
    1021           0 :   fd_topo_link_t * sign_in  = &topo->links[ tile->in_link_id [ sign_link_in_idx  ] ];
    1022           0 :   fd_topo_link_t * sign_out = &topo->links[ tile->out_link_id[ sign_link_out_idx ] ];
    1023           0 :   if ( fd_keyguard_client_join( fd_keyguard_client_new( ctx->keyguard_client,
    1024           0 :                                                             sign_out->mcache,
    1025           0 :                                                             sign_out->dcache,
    1026           0 :                                                             sign_in->mcache,
    1027           0 :                                                             sign_in->dcache ) )==NULL ) {
    1028           0 :     FD_LOG_ERR(( "Keyguard join failed" ));
    1029           0 :   }
    1030             : 
    1031             :   /* Gossip set up */
    1032           0 :   ctx->gossip = fd_gossip_join( fd_gossip_new( ctx->gossip, ctx->gossip_seed ) );
    1033             : 
    1034           0 :   FD_LOG_NOTICE(( "gossip my addr - addr: " FD_IP4_ADDR_FMT ":%u",
    1035           0 :     FD_IP4_ADDR_FMT_ARGS( ctx->gossip_my_addr.addr ), fd_ushort_bswap( ctx->gossip_my_addr.port ) ));
    1036           0 :   ctx->gossip_config.my_addr       = ctx->gossip_my_addr;
    1037           0 :   ctx->gossip_config.my_version = (fd_gossip_version_v3_t){
    1038           0 :     .major = 42U,
    1039           0 :     .minor = 42U,
    1040           0 :     .patch = 42U,
    1041           0 :     .commit = 0U,
    1042           0 :     .feature_set = 0U,
    1043           0 :     .client = 2U
    1044           0 :   };
    1045           0 :   ctx->gossip_config.node_outset   = fd_log_wallclock() / 1000000; /* in ms */
    1046           0 :   ctx->gossip_config.public_key    = &ctx->identity_public_key;
    1047           0 :   ctx->gossip_config.deliver_fun   = gossip_deliver_fun;
    1048           0 :   ctx->gossip_config.deliver_arg   = ctx;
    1049           0 :   ctx->gossip_config.send_fun      = gossip_send_packet;
    1050           0 :   ctx->gossip_config.send_arg      = ctx;
    1051           0 :   ctx->gossip_config.sign_fun      = gossip_signer;
    1052           0 :   ctx->gossip_config.sign_arg      = ctx;
    1053           0 :   ctx->gossip_config.shred_version = (ushort)tile->gossip.expected_shred_version;
    1054             : 
    1055           0 :   if( fd_gossip_set_config( ctx->gossip, &ctx->gossip_config ) ) {
    1056           0 :     FD_LOG_ERR( ( "error setting gossip config" ) );
    1057           0 :   }
    1058             : 
    1059           0 :   fd_gossip_set_entrypoints( ctx->gossip, tile->gossip.entrypoints, tile->gossip.entrypoints_cnt );
    1060             : 
    1061           0 :   fd_gossip_update_addr( ctx->gossip, &ctx->gossip_config.my_addr );
    1062             : 
    1063           0 :   ctx->tvu_my_addr.addr       = tile->gossip.ip_addr;
    1064           0 :   ctx->tvu_my_addr.port       = fd_ushort_bswap( tile->gossip.tvu_port );
    1065           0 :   ctx->tpu_my_addr.addr       = tile->gossip.ip_addr;
    1066           0 :   ctx->tpu_my_addr.port       = fd_ushort_bswap( tile->gossip.tpu_port );
    1067           0 :   ctx->tpu_quic_my_addr.addr  = tile->gossip.ip_addr;
    1068           0 :   ctx->tpu_quic_my_addr.port  = fd_ushort_bswap( tile->gossip.tpu_quic_port );
    1069           0 :   ctx->tpu_vote_my_addr.addr  = tile->gossip.ip_addr;
    1070           0 :   ctx->tpu_vote_my_addr.port  = fd_ushort_bswap( tile->gossip.tpu_vote_port );
    1071           0 :   ctx->repair_serve_addr.addr = tile->gossip.ip_addr;
    1072           0 :   ctx->repair_serve_addr.port = fd_ushort_bswap( tile->gossip.repair_serve_port );
    1073             : 
    1074           0 :   fd_gossip_update_tvu_addr( ctx->gossip, &ctx->tvu_my_addr );
    1075           0 :   fd_gossip_update_tpu_addr( ctx->gossip, &ctx->tpu_my_addr, &ctx->tpu_quic_my_addr );
    1076           0 :   fd_gossip_update_tpu_vote_addr( ctx->gossip, &ctx->tpu_vote_my_addr );
    1077           0 :   fd_gossip_update_repair_addr( ctx->gossip, &ctx->repair_serve_addr );
    1078           0 :   fd_gossip_settime( ctx->gossip, fd_log_wallclock() );
    1079           0 :   fd_gossip_start( ctx->gossip );
    1080             : 
    1081           0 :   FD_LOG_NOTICE(( "gossip listening on port %u", tile->gossip.gossip_listen_port ));
    1082             : 
    1083           0 :   ulong scratch_top = FD_SCRATCH_ALLOC_FINI( l, 1UL );
    1084           0 :   if( FD_UNLIKELY( scratch_top>( (ulong)scratch + scratch_footprint( tile ) ) ) )
    1085           0 :     FD_LOG_ERR(( "scratch overflow %lu %lu %lu", scratch_top - (ulong)scratch - scratch_footprint( tile ), scratch_top, (ulong)scratch + scratch_footprint( tile ) ));
    1086             : 
    1087           0 :   ulong poh_shred_obj_id = fd_pod_query_ulong( topo->props, "poh_shred", ULONG_MAX );
    1088           0 :   FD_TEST( poh_shred_obj_id!=ULONG_MAX );
    1089             : 
    1090           0 :   fd_shred_version = fd_fseq_join( fd_topo_obj_laddr( topo, poh_shred_obj_id ) );
    1091           0 :   FD_TEST( fd_shred_version );
    1092             : 
    1093             :   /* Initialize metrics to zero */
    1094           0 :   memset( &ctx->metrics, 0, FD_GOSSIP_TILE_METRICS_FOOTPRINT );
    1095           0 : }
    1096             : 
    1097             : static ulong
    1098             : populate_allowed_seccomp( fd_topo_t const *      topo,
    1099             :                           fd_topo_tile_t const * tile,
    1100             :                           ulong                  out_cnt,
    1101           0 :                           struct sock_filter *   out ) {
    1102           0 :   (void)topo;
    1103           0 :   (void)tile;
    1104             : 
    1105           0 :   populate_sock_filter_policy_fd_gossip_tile( out_cnt, out, (uint)fd_log_private_logfile_fd() );
    1106           0 :   return sock_filter_policy_fd_gossip_tile_instr_cnt;
    1107           0 : }
    1108             : 
    1109             : static ulong
    1110             : populate_allowed_fds( fd_topo_t const *      topo,
    1111             :                       fd_topo_tile_t const * tile,
    1112             :                       ulong                  out_fds_cnt,
    1113           0 :                       int *                  out_fds ) {
    1114           0 :   (void)topo;
    1115           0 :   (void)tile;
    1116             : 
    1117           0 :   if( FD_UNLIKELY( out_fds_cnt<2UL ) ) FD_LOG_ERR(( "out_fds_cnt %lu", out_fds_cnt ));
    1118             : 
    1119           0 :   ulong out_cnt = 0UL;
    1120           0 :   out_fds[ out_cnt++ ] = 2; /* stderr */
    1121           0 :   if( FD_LIKELY( -1!=fd_log_private_logfile_fd() ) )
    1122           0 :     out_fds[ out_cnt++ ] = fd_log_private_logfile_fd(); /* logfile */
    1123           0 :   return out_cnt;
    1124           0 : }
    1125             : 
    1126             : static inline void
    1127           0 : fd_gossip_update_gossip_metrics( fd_gossip_metrics_t * metrics ) {
    1128           0 :   FD_MCNT_SET( GOSSIP, RECEIVED_PACKETS, metrics->recv_pkt_cnt );
    1129           0 :   FD_MCNT_SET( GOSSIP, CORRUPTED_MESSAGES, metrics->recv_pkt_corrupted_msg );
    1130             : 
    1131           0 :   FD_MCNT_ENUM_COPY( GOSSIP, RECEIVED_GOSSIP_MESSAGES, metrics->recv_message );
    1132           0 :   FD_MCNT_SET( GOSSIP, RECEIVED_UNKNOWN_MESSAGE, metrics->recv_unknown_message );
    1133             : 
    1134           0 :   FD_MCNT_ENUM_COPY( GOSSIP, RECEIVED_CRDS_PUSH, metrics->recv_crds[ FD_GOSSIP_CRDS_ROUTE_PUSH ] );
    1135           0 :   FD_MCNT_ENUM_COPY( GOSSIP, RECEIVED_CRDS_PULL, metrics->recv_crds[ FD_GOSSIP_CRDS_ROUTE_PULL_RESP ] );
    1136           0 :   FD_MCNT_ENUM_COPY( GOSSIP, RECEIVED_CRDS_DUPLICATE_MESSAGE_PUSH, metrics->recv_crds_duplicate_message[ FD_GOSSIP_CRDS_ROUTE_PUSH ] );
    1137           0 :   FD_MCNT_ENUM_COPY( GOSSIP, RECEIVED_CRDS_DUPLICATE_MESSAGE_PULL, metrics->recv_crds_duplicate_message[ FD_GOSSIP_CRDS_ROUTE_PULL_RESP ] );
    1138           0 :   FD_MCNT_ENUM_COPY( GOSSIP, RECEIVED_CRDS_DROP, metrics->recv_crds_drop_reason );
    1139             : 
    1140           0 :   FD_MCNT_ENUM_COPY( GOSSIP, PUSH_CRDS, metrics->push_crds );
    1141           0 :   FD_MCNT_ENUM_COPY( GOSSIP, PUSH_CRDS_DUPLICATE_MESSAGE, metrics->push_crds_duplicate );
    1142           0 :   FD_MCNT_ENUM_COPY( GOSSIP, PUSH_CRDS_DROP, metrics->push_crds_drop_reason );
    1143           0 :   FD_MGAUGE_SET( GOSSIP, PUSH_CRDS_QUEUE_COUNT, metrics->push_crds_queue_cnt );
    1144             : 
    1145           0 :   FD_MGAUGE_SET( GOSSIP, ACTIVE_PUSH_DESTINATIONS, metrics->active_push_destinations );
    1146           0 :   FD_MCNT_SET( GOSSIP, REFRESH_PUSH_STATES_FAIL_COUNT, metrics->refresh_push_states_failcnt );
    1147             : 
    1148           0 :   FD_MCNT_ENUM_COPY( GOSSIP, PULL_REQ_FAIL, metrics->handle_pull_req_fails );
    1149             : 
    1150           0 :   FD_MCNT_ENUM_COPY( GOSSIP, PULL_REQ_BLOOM_FILTER, metrics->handle_pull_req_bloom_filter_result);
    1151           0 :   FD_MGAUGE_SET( GOSSIP, PULL_REQ_RESP_PACKETS, metrics->handle_pull_req_npackets );
    1152             : 
    1153           0 :   FD_MCNT_ENUM_COPY( GOSSIP, PRUNE_FAIL_COUNT, metrics->handle_prune_fails );
    1154             : 
    1155           0 :   FD_MCNT_SET( GOSSIP, MAKE_PRUNE_STALE_ENTRY, metrics->make_prune_stale_entry );
    1156           0 :   FD_MCNT_SET( GOSSIP, MAKE_PRUNE_HIGH_DUPLICATES, metrics->make_prune_high_duplicates );
    1157           0 :   FD_MGAUGE_SET( GOSSIP, MAKE_PRUNE_REQUESTED_ORIGINS, metrics->make_prune_requested_origins );
    1158           0 :   FD_MCNT_SET( GOSSIP, MAKE_PRUNE_SIGN_DATA_ENCODE_FAILED, metrics->make_prune_sign_data_encode_failed );
    1159             : 
    1160           0 :   FD_MCNT_ENUM_COPY( GOSSIP, SENT_GOSSIP_MESSAGES, metrics->send_message );
    1161             : 
    1162           0 :   FD_MCNT_SET( GOSSIP, SENT_PACKETS, metrics->send_packet_cnt );
    1163             : 
    1164           0 :   FD_MCNT_ENUM_COPY( GOSSIP, SEND_PING_EVENT, metrics->send_ping_events );
    1165           0 :   FD_MCNT_SET( GOSSIP, RECV_PING_INVALID_SIGNATURE, metrics->recv_ping_invalid_signature );
    1166             : 
    1167           0 :   FD_MCNT_ENUM_COPY( GOSSIP, RECV_PONG_EVENT, metrics->recv_pong_events );
    1168             : 
    1169           0 :   FD_MGAUGE_ENUM_COPY( GOSSIP, GOSSIP_PEER_COUNTS, metrics->gossip_peer_cnt );
    1170           0 : }
    1171             : 
    1172             : static inline void
    1173           0 : metrics_write( fd_gossip_tile_ctx_t * ctx ) {
    1174             :   /* Tile-specific metrics */
    1175           0 :   FD_MGAUGE_SET( GOSSIP, LAST_CRDS_PUSH_CONTACT_INFO_PUBLISH_TIMESTAMP_NANOS, ctx->metrics.last_crds_push_contact_info_publish_ts );
    1176           0 :   FD_MCNT_SET( GOSSIP, MISMATCHED_CONTACT_INFO_SHRED_VERSION, ctx->metrics.mismatched_contact_info_shred_version );
    1177           0 :   FD_MCNT_ENUM_COPY( GOSSIP, IPV6_CONTACT_INFO, ctx->metrics.ipv6_contact_info );
    1178           0 :   FD_MCNT_ENUM_COPY( GOSSIP, ZERO_IPV4_CONTACT_INFO, ctx->metrics.zero_ipv4_contact_info );
    1179           0 :   FD_MGAUGE_ENUM_COPY( GOSSIP, PEER_COUNTS, ctx->metrics.peer_counts );
    1180           0 :   FD_MCNT_SET( GOSSIP, SHRED_VERSION_ZERO, ctx->metrics.shred_version_zero );
    1181             : 
    1182             :   /* Gossip-protocol-specific metrics */
    1183           0 :   fd_gossip_update_gossip_metrics( fd_gossip_get_metrics( ctx->gossip ) );
    1184           0 : }
    1185             : 
    1186           0 : #define STEM_BURST (1UL)
    1187             : 
    1188           0 : #define STEM_CALLBACK_CONTEXT_TYPE  fd_gossip_tile_ctx_t
    1189           0 : #define STEM_CALLBACK_CONTEXT_ALIGN alignof(fd_gossip_tile_ctx_t)
    1190             : 
    1191           0 : #define STEM_CALLBACK_AFTER_CREDIT        after_credit
    1192           0 : #define STEM_CALLBACK_DURING_HOUSEKEEPING during_housekeeping
    1193           0 : #define STEM_CALLBACK_BEFORE_FRAG         before_frag
    1194           0 : #define STEM_CALLBACK_DURING_FRAG         during_frag
    1195           0 : #define STEM_CALLBACK_AFTER_FRAG          after_frag
    1196           0 : #define STEM_CALLBACK_METRICS_WRITE       metrics_write
    1197             : 
    1198             : #include "../../disco/stem/fd_stem.c"
    1199             : 
    1200             : fd_topo_run_tile_t fd_tile_gossip = {
    1201             :   .name                     = "gossip",
    1202             :   .loose_footprint          = loose_footprint,
    1203             :   .populate_allowed_seccomp = populate_allowed_seccomp,
    1204             :   .populate_allowed_fds     = populate_allowed_fds,
    1205             :   .scratch_align            = scratch_align,
    1206             :   .scratch_footprint        = scratch_footprint,
    1207             :   .privileged_init          = privileged_init,
    1208             :   .unprivileged_init        = unprivileged_init,
    1209             :   .run                      = stem_run,
    1210             : };

Generated by: LCOV version 1.14