LCOV - code coverage report
Current view: top level - discof/gossip - fd_gossip_tile.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 520 0.0 %
Date: 2025-07-01 05:00:49 Functions: 0 20 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 "../../disco/fd_disco.h"
       8             : #include "../../disco/keyguard/fd_keyload.h"
       9             : #include "../../disco/keyguard/fd_keyguard_client.h"
      10             : #include "../../disco/net/fd_net_tile.h"
      11             : #include "../../flamenco/gossip/fd_gossip.h"
      12             : #include "../../util/pod/fd_pod.h"
      13             : #include "../../util/net/fd_ip4.h"
      14             : #include "../../util/net/fd_udp.h"
      15             : #include "../../util/net/fd_net_headers.h"
      16             : 
      17             : #include "../store/util.h"
      18             : 
      19             : #include <unistd.h>
      20             : #include <arpa/inet.h>
      21             : #include <linux/unistd.h>
      22             : #include <sys/random.h>
      23             : #include <netdb.h>
      24             : #include <netinet/in.h>
      25             : #include <sys/socket.h>
      26             : 
      27           0 : #define CONTACT_INFO_PUBLISH_TIME_NS ((long)5e9)
      28             : #define PLUGIN_PUBLISH_TIME_NS ((long)30e9)
      29             : 
      30           0 : #define IN_KIND_NET     (1)
      31           0 : #define IN_KIND_SEND    (2)
      32           0 : #define IN_KIND_SIGN    (4)
      33             : #define MAX_IN_LINKS    (8)
      34             : 
      35             : static volatile ulong * fd_shred_version;
      36             : 
      37             : static ulong
      38           0 : fd_pubkey_hash( fd_pubkey_t const * key, ulong seed ) {
      39           0 :   return fd_hash( seed, key->key, sizeof(fd_pubkey_t) );
      40           0 : }
      41             : 
      42             : /* Contact info table */
      43             : #define MAP_NAME     fd_contact_info_table
      44             : #define MAP_KEY_T    fd_pubkey_t
      45           0 : #define MAP_KEY_EQ   fd_pubkey_eq
      46           0 : #define MAP_KEY_HASH fd_pubkey_hash
      47           0 : #define MAP_T        fd_contact_info_elem_t
      48             : #include "../../util/tmpl/fd_map_giant.c"
      49             : 
      50             : struct fd_gossip_tile_metrics {
      51             :   ulong last_crds_push_contact_info_publish_ts;
      52             :   ulong mismatched_contact_info_shred_version;
      53             : 
      54             :   /* Below metrics are segmented by TVU, Repair, Send */
      55             :   ulong ipv6_contact_info[FD_METRICS_COUNTER_GOSSIP_IPV6_CONTACT_INFO_CNT];
      56             :   ulong zero_ipv4_contact_info[FD_METRICS_COUNTER_GOSSIP_ZERO_IPV4_CONTACT_INFO_CNT];
      57             :   ulong peer_counts[FD_METRICS_GAUGE_GOSSIP_PEER_COUNTS_CNT];
      58             : 
      59             :   ulong shred_version_zero;
      60             : };
      61             : typedef struct fd_gossip_tile_metrics fd_gossip_tile_metrics_t;
      62           0 : #define FD_GOSSIP_TILE_METRICS_FOOTPRINT ( sizeof( fd_gossip_tile_metrics_t ) )
      63             : 
      64             : typedef union {
      65             :   struct {
      66             :     fd_wksp_t * mem;
      67             :     ulong       chunk0;
      68             :     ulong       wmark;
      69             :   };
      70             :   fd_net_rx_bounds_t net_rx;
      71             : } fd_gossip_in_ctx_t;
      72             : 
      73             : struct fd_gossip_tile_ctx {
      74             :   fd_gossip_t * gossip;
      75             :   fd_gossip_config_t gossip_config;
      76             :   long last_shred_dest_push_time;
      77             :   long last_plugin_push_time;
      78             : 
      79             :   ulong gossip_seed;
      80             : 
      81             :   uchar              in_kind[ MAX_IN_LINKS ];
      82             :   fd_gossip_in_ctx_t in_links[ MAX_IN_LINKS ];
      83             : 
      84             :   fd_contact_info_elem_t * contact_info_table;
      85             : 
      86             :   fd_frag_meta_t * shred_contact_out_mcache;
      87             :   ulong *          shred_contact_out_sync;
      88             :   ulong            shred_contact_out_depth;
      89             :   ulong            shred_contact_out_seq;
      90             : 
      91             :   fd_wksp_t * shred_contact_out_mem;
      92             :   ulong       shred_contact_out_chunk0;
      93             :   ulong       shred_contact_out_wmark;
      94             :   ulong       shred_contact_out_chunk;
      95             : 
      96             :   fd_frag_meta_t * repair_contact_out_mcache;
      97             :   ulong *          repair_contact_out_sync;
      98             :   ulong            repair_contact_out_depth;
      99             :   ulong            repair_contact_out_seq;
     100             : 
     101             :   fd_wksp_t * repair_contact_out_mem;
     102             :   ulong       repair_contact_out_chunk0;
     103             :   ulong       repair_contact_out_wmark;
     104             :   ulong       repair_contact_out_chunk;
     105             : 
     106             :   fd_frag_meta_t * send_contact_out_mcache;
     107             :   ulong *          send_contact_out_sync;
     108             :   ulong            send_contact_out_depth;
     109             :   ulong            send_contact_out_seq;
     110             : 
     111             :   fd_wksp_t * send_contact_out_mem;
     112             :   ulong       send_contact_out_chunk0;
     113             :   ulong       send_contact_out_wmark;
     114             :   ulong       send_contact_out_chunk;
     115             : 
     116             :   fd_frag_meta_t * verify_out_mcache;
     117             :   ulong *          verify_out_sync;
     118             :   ulong            verify_out_depth;
     119             :   ulong            verify_out_seq;
     120             : 
     121             :   fd_wksp_t * verify_out_mem;
     122             :   ulong       verify_out_chunk0;
     123             :   ulong       verify_out_wmark;
     124             :   ulong       verify_out_chunk;
     125             : 
     126             :   ulong       tower_out_idx;
     127             :   fd_wksp_t * tower_out_mem;
     128             :   ulong       tower_out_chunk0;
     129             :   ulong       tower_out_wmark;
     130             :   ulong       tower_out_chunk;
     131             : 
     132             :   fd_wksp_t *           wksp;
     133             :   fd_gossip_peer_addr_t gossip_my_addr;
     134             :   fd_gossip_peer_addr_t tvu_my_addr;
     135             :   fd_gossip_peer_addr_t tpu_my_addr;
     136             :   fd_gossip_peer_addr_t tpu_quic_my_addr;
     137             :   fd_gossip_peer_addr_t tpu_vote_my_addr;
     138             :   fd_gossip_peer_addr_t repair_serve_addr;
     139             :   ushort                gossip_listen_port;
     140             : 
     141             :   fd_frag_meta_t * net_out_mcache;
     142             :   ulong *          net_out_sync;
     143             :   ulong            net_out_depth;
     144             :   ulong            net_out_seq;
     145             : 
     146             :   fd_wksp_t * net_out_mem;
     147             :   ulong       net_out_chunk0;
     148             :   ulong       net_out_wmark;
     149             :   ulong       net_out_chunk;
     150             : 
     151             :   // Inputs to plugin/gui
     152             : 
     153             :   fd_wksp_t * gossip_plugin_out_mem;
     154             :   ulong       gossip_plugin_out_chunk0;
     155             :   ulong       gossip_plugin_out_wmark;
     156             :   ulong       gossip_plugin_out_chunk;
     157             :   ulong       gossip_plugin_out_idx;
     158             : 
     159             :   uchar         identity_private_key[32];
     160             :   fd_pubkey_t   identity_public_key;
     161             : 
     162             :   /* Includes Ethernet, IP, UDP headers */
     163             :   uchar gossip_buffer[ FD_NET_MTU ];
     164             : 
     165             :   ushort net_id;
     166             :   fd_ip4_udp_hdrs_t hdr[1];
     167             : 
     168             :   fd_keyguard_client_t  keyguard_client[1];
     169             : 
     170             :   fd_stem_context_t * stem;
     171             : 
     172             :   ulong replay_vote_txn_sz;
     173             :   uchar replay_vote_txn [ FD_TXN_MTU ];
     174             : 
     175             :   /* Metrics */
     176             :   fd_gossip_tile_metrics_t metrics;
     177             : };
     178             : typedef struct fd_gossip_tile_ctx fd_gossip_tile_ctx_t;
     179             : 
     180             : FD_FN_CONST static inline ulong
     181           0 : scratch_align( void ) {
     182           0 :   return 128UL;
     183           0 : }
     184             : 
     185             : FD_FN_PURE static inline ulong
     186           0 : loose_footprint( fd_topo_tile_t const * tile FD_PARAM_UNUSED ) {
     187           0 :   return 1UL * FD_SHMEM_GIGANTIC_PAGE_SZ;
     188           0 : }
     189             : 
     190             : FD_FN_PURE static inline ulong
     191           0 : scratch_footprint( fd_topo_tile_t const * tile FD_PARAM_UNUSED ) {
     192           0 :   ulong l = FD_LAYOUT_INIT;
     193           0 :   l = FD_LAYOUT_APPEND( l, alignof(fd_gossip_tile_ctx_t), sizeof(fd_gossip_tile_ctx_t) );
     194           0 :   l = FD_LAYOUT_APPEND( l, fd_gossip_align(), fd_gossip_footprint() );
     195           0 :   l = FD_LAYOUT_APPEND( l, fd_contact_info_table_align(), fd_contact_info_table_footprint( FD_PEER_KEY_MAX ) );
     196           0 :   return FD_LAYOUT_FINI( l, scratch_align() );
     197           0 : }
     198             : 
     199             : static void
     200             : send_packet( fd_gossip_tile_ctx_t * ctx,
     201             :              uint                   dst_ip_addr,
     202             :              ushort                 dst_port,
     203             :              uchar const *          payload,
     204             :              ulong                  payload_sz,
     205           0 :              ulong                  tsorig ) {
     206           0 :   uchar * packet = fd_chunk_to_laddr( ctx->net_out_mem, ctx->net_out_chunk );
     207             : 
     208           0 :   fd_ip4_udp_hdrs_t * hdr = (fd_ip4_udp_hdrs_t *)packet;
     209           0 :   *hdr = *ctx->hdr;
     210             : 
     211           0 :   fd_ip4_hdr_t * ip4 = hdr->ip4;
     212           0 :   ip4->daddr       = dst_ip_addr;
     213           0 :   ip4->net_id      = fd_ushort_bswap( ctx->net_id++ );
     214           0 :   ip4->check       = 0U;
     215           0 :   ip4->net_tot_len = fd_ushort_bswap( (ushort)(payload_sz + sizeof(fd_ip4_hdr_t)+sizeof(fd_udp_hdr_t)) );
     216           0 :   ip4->check       = fd_ip4_hdr_check_fast( ip4 );
     217             : 
     218           0 :   fd_udp_hdr_t * udp = hdr->udp;
     219           0 :   udp->net_dport = dst_port;
     220           0 :   udp->net_len   = fd_ushort_bswap( (ushort)(payload_sz + sizeof(fd_udp_hdr_t)) );
     221           0 :   fd_memcpy( packet+sizeof(fd_ip4_udp_hdrs_t), payload, payload_sz );
     222           0 :   udp->check = 0U;
     223             : 
     224           0 :   ulong tspub     = fd_frag_meta_ts_comp( fd_tickcount() );
     225           0 :   ulong sig       = fd_disco_netmux_sig( dst_ip_addr, dst_port, dst_ip_addr, DST_PROTO_OUTGOING, sizeof(fd_ip4_udp_hdrs_t) );
     226           0 :   ulong packet_sz = payload_sz + sizeof(fd_ip4_udp_hdrs_t);
     227           0 :   fd_stem_publish( ctx->stem, 0UL, sig, ctx->net_out_chunk, packet_sz, 0UL, tsorig, tspub );
     228           0 :   ctx->net_out_chunk = fd_dcache_compact_next( ctx->net_out_chunk, packet_sz, ctx->net_out_chunk0, ctx->net_out_wmark );
     229           0 : }
     230             : 
     231             : static void
     232             : gossip_send_packet( uchar const * msg,
     233             :                     size_t msglen,
     234             :                     fd_gossip_peer_addr_t const * addr,
     235           0 :                     void * arg ) {
     236           0 :   ulong tsorig = fd_frag_meta_ts_comp( fd_tickcount() );
     237           0 :   send_packet( arg, addr->addr, addr->port, msg, msglen, tsorig );
     238           0 : }
     239             : 
     240             : static void
     241             : gossip_deliver_fun( fd_crds_data_t * data,
     242           0 :                     void *           arg ) {
     243           0 :   fd_gossip_tile_ctx_t * ctx = (fd_gossip_tile_ctx_t *)arg;
     244             : 
     245           0 :   if( fd_crds_data_is_vote( data ) ) {
     246           0 :     if( FD_UNLIKELY( !ctx->verify_out_mcache ) ) return;
     247             : 
     248           0 :     fd_gossip_vote_t const * gossip_vote = &data->inner.vote;
     249             : 
     250           0 :     uchar * vote_txn_msg = fd_chunk_to_laddr( ctx->verify_out_mem, ctx->verify_out_chunk );
     251           0 :     ulong vote_txn_sz    = gossip_vote->txn.raw_sz;
     252           0 :     memcpy( vote_txn_msg, gossip_vote->txn.raw, vote_txn_sz );
     253             : 
     254           0 :     ulong sig = 1UL;
     255           0 :     fd_mcache_publish( ctx->verify_out_mcache, ctx->verify_out_depth, ctx->verify_out_seq, sig, ctx->verify_out_chunk,
     256           0 :       vote_txn_sz, 0UL, 0, 0 );
     257           0 :     ctx->verify_out_seq   = fd_seq_inc( ctx->verify_out_seq, 1UL );
     258           0 :     ctx->verify_out_chunk = fd_dcache_compact_next( ctx->verify_out_chunk, vote_txn_sz, ctx->verify_out_chunk0, ctx->verify_out_wmark );
     259             : 
     260           0 :   } else if( fd_crds_data_is_contact_info_v2( data ) ) {
     261           0 :     fd_gossip_contact_info_v2_t const * contact_info_v2 = &data->inner.contact_info_v2;
     262             : 
     263           0 :     fd_contact_info_elem_t * ele = fd_contact_info_table_query( ctx->contact_info_table, &contact_info_v2->from, NULL );
     264             : 
     265           0 :     if( FD_UNLIKELY( !ele &&
     266           0 :                      !fd_contact_info_table_is_full( ctx->contact_info_table ) ) ) {
     267           0 :       ele = fd_contact_info_table_insert( ctx->contact_info_table, &contact_info_v2->from);
     268           0 :       fd_contact_info_init( &ele->contact_info );
     269           0 :     }
     270             : 
     271           0 :     if( FD_LIKELY( ele ) ) {
     272           0 :       fd_contact_info_from_ci_v2( contact_info_v2, &ele->contact_info );
     273           0 :     }
     274             : 
     275           0 :   } else if( fd_crds_data_is_duplicate_shred( data ) ) {
     276             : 
     277           0 :     fd_gossip_duplicate_shred_t const * duplicate_shred = &data->inner.duplicate_shred;
     278           0 :     uchar * chunk_laddr = fd_chunk_to_laddr( ctx->tower_out_mem, ctx->tower_out_chunk );
     279           0 :     memcpy( chunk_laddr, duplicate_shred, sizeof(fd_gossip_duplicate_shred_t) );
     280           0 :     memcpy( chunk_laddr + sizeof(fd_gossip_duplicate_shred_t), duplicate_shred->chunk, duplicate_shred->chunk_len );
     281           0 :     fd_stem_publish( ctx->stem, ctx->tower_out_idx, data->discriminant, ctx->tower_out_chunk, sizeof(fd_gossip_duplicate_shred_t) + duplicate_shred->chunk_len, 0UL, 0, 0 /* FIXME gossip tile needs to plumb through ts. this callback API is not ideal. */ );
     282             : 
     283           0 :   }
     284           0 : }
     285             : 
     286             : static void
     287             : gossip_signer( void *        signer_ctx,
     288             :                uchar         signature[ static 64 ],
     289             :                uchar const * buffer,
     290             :                ulong         len,
     291           0 :                int           sign_type ) {
     292           0 :   fd_gossip_tile_ctx_t * ctx = (fd_gossip_tile_ctx_t *)signer_ctx;
     293           0 :   fd_keyguard_client_sign( ctx->keyguard_client, signature, buffer, len, sign_type );
     294           0 : }
     295             : 
     296             : static void
     297           0 : during_housekeeping( fd_gossip_tile_ctx_t * ctx ) {
     298           0 :   fd_gossip_settime( ctx->gossip, fd_log_wallclock() );
     299           0 : }
     300             : 
     301             : static inline int
     302             : before_frag( fd_gossip_tile_ctx_t * ctx,
     303             :              ulong                  in_idx,
     304             :              ulong                  seq FD_PARAM_UNUSED,
     305           0 :              ulong                  sig ) {
     306           0 :   uint in_kind = ctx->in_kind[ in_idx ];
     307           0 :   return in_kind != IN_KIND_SEND && fd_disco_netmux_sig_proto( sig ) != DST_PROTO_GOSSIP;
     308           0 : }
     309             : 
     310             : static inline void
     311             : during_frag( fd_gossip_tile_ctx_t * ctx,
     312             :              ulong                  in_idx,
     313             :              ulong                  seq FD_PARAM_UNUSED,
     314             :              ulong                  sig FD_PARAM_UNUSED,
     315             :              ulong                  chunk,
     316             :              ulong                  sz,
     317           0 :              ulong                  ctl ) {
     318             : 
     319           0 :   uint in_kind = ctx->in_kind[ in_idx ];
     320           0 :   fd_gossip_in_ctx_t const * in_ctx = &ctx->in_links[ in_idx ];
     321             : 
     322           0 :   if( in_kind == IN_KIND_SEND ) {
     323           0 :     if( FD_UNLIKELY( chunk<in_ctx->chunk0 || chunk>in_ctx->wmark || sz>FD_TXN_MTU ) ) {
     324           0 :       FD_LOG_ERR(( "chunk %lu %lu corrupt, not in range [%lu,%lu]", chunk, sz, in_ctx->chunk0, in_ctx->wmark ));
     325           0 :     }
     326             : 
     327           0 :     ctx->replay_vote_txn_sz = sz;
     328           0 :     memcpy( ctx->replay_vote_txn, fd_chunk_to_laddr( in_ctx->mem, chunk ), sz );
     329           0 :     return;
     330           0 :   }
     331             : 
     332           0 :   if( in_kind!=IN_KIND_NET ) return;
     333             : 
     334           0 :   void const * src = fd_net_rx_translate_frag( &ctx->in_links[ in_idx ].net_rx, chunk, ctl, sz );
     335           0 :   fd_memcpy( ctx->gossip_buffer, src, sz );
     336           0 : }
     337             : 
     338             : static void
     339             : after_frag( fd_gossip_tile_ctx_t * ctx,
     340             :             ulong                  in_idx,
     341             :             ulong                  seq    FD_PARAM_UNUSED,
     342             :             ulong                  sig    FD_PARAM_UNUSED,
     343             :             ulong                  sz,
     344             :             ulong                  tsorig FD_PARAM_UNUSED,
     345             :             ulong                  tspub  FD_PARAM_UNUSED,
     346           0 :             fd_stem_context_t *    stem ) {
     347           0 :   uint in_kind = ctx->in_kind[ in_idx ];
     348             : 
     349           0 :   if( in_kind==IN_KIND_SEND ) {
     350           0 :     fd_crds_data_t vote_txn_crds;
     351           0 :     vote_txn_crds.discriminant          = fd_crds_data_enum_vote;
     352           0 :     vote_txn_crds.inner.vote.txn.raw_sz = ctx->replay_vote_txn_sz;
     353           0 :     memcpy( vote_txn_crds.inner.vote.txn.raw, ctx->replay_vote_txn, ctx->replay_vote_txn_sz );
     354           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 );
     355             : 
     356           0 :     fd_gossip_push_value( ctx->gossip, &vote_txn_crds, NULL );
     357             : 
     358           0 :     static ulong sent_vote_cnt = 0;
     359           0 :     if ( ( ++sent_vote_cnt % 50 ) == 0 )
     360           0 :       FD_LOG_NOTICE(( "Gossip tile has sent %lu vote txns", sent_vote_cnt ));
     361             : 
     362           0 :     return;
     363           0 :   }
     364             : 
     365           0 :   if( in_kind!=IN_KIND_NET ) return;
     366             : 
     367           0 :   if( FD_UNLIKELY( sz<42 ) ) return;
     368             : 
     369           0 :   ctx->stem = stem;
     370           0 :   fd_eth_hdr_t const * eth  = (fd_eth_hdr_t const *)ctx->gossip_buffer;
     371           0 :   fd_ip4_hdr_t const * ip4  = (fd_ip4_hdr_t const *)( (ulong)eth + sizeof(fd_eth_hdr_t) );
     372           0 :   fd_udp_hdr_t const * udp  = (fd_udp_hdr_t const *)( (ulong)ip4 + FD_IP4_GET_LEN( *ip4 ) );
     373           0 :   uchar const *        data = (uchar        const *)( (ulong)udp + sizeof(fd_udp_hdr_t) );
     374           0 :   if( FD_UNLIKELY( (ulong)udp+sizeof(fd_udp_hdr_t) > (ulong)eth+sz ) ) return;
     375           0 :   ulong udp_sz = fd_ushort_bswap( udp->net_len );
     376           0 :   if( FD_UNLIKELY( udp_sz<sizeof(fd_udp_hdr_t) ) ) return;
     377           0 :   ulong data_sz = udp_sz-sizeof(fd_udp_hdr_t);
     378           0 :   if( FD_UNLIKELY( (ulong)data+data_sz > (ulong)eth+sz ) ) return;
     379             : 
     380           0 :   fd_gossip_peer_addr_t peer_addr = { .addr=ip4->saddr, .port=udp->net_sport };
     381           0 :   fd_gossip_recv_packet( ctx->gossip, data, data_sz, &peer_addr );
     382           0 : }
     383             : 
     384             : static void
     385             : publish_peers_to_plugin( fd_gossip_tile_ctx_t * ctx,
     386           0 :                          fd_stem_context_t *    stem ) {
     387           0 :   uchar * dst = (uchar *)fd_chunk_to_laddr( ctx->gossip_plugin_out_mem, ctx->gossip_plugin_out_chunk );
     388             : 
     389           0 :   ulong i = 0;
     390           0 :   for( fd_contact_info_table_iter_t iter = fd_contact_info_table_iter_init( ctx->contact_info_table );
     391           0 :        !fd_contact_info_table_iter_done( ctx->contact_info_table, iter ) && i < FD_CLUSTER_NODE_CNT;
     392           0 :        iter = fd_contact_info_table_iter_next( ctx->contact_info_table, iter ), ++i ) {
     393           0 :     fd_contact_info_elem_t const * ele = fd_contact_info_table_iter_ele_const( ctx->contact_info_table, iter );
     394           0 :     fd_gossip_update_msg_t * msg = (fd_gossip_update_msg_t *)(dst + sizeof(ulong) + i*FD_GOSSIP_LINK_MSG_SIZE);
     395           0 :     fd_contact_info_to_update_msg( &ele->contact_info, msg );
     396           0 :   }
     397             : 
     398           0 :   *(ulong *)dst = i;
     399             : 
     400           0 :   ulong tspub = (ulong)fd_frag_meta_ts_comp( fd_tickcount() );
     401           0 :   fd_stem_publish( stem, ctx->gossip_plugin_out_idx, FD_PLUGIN_MSG_GOSSIP_UPDATE, ctx->gossip_plugin_out_chunk, 0, 0UL, 0UL, tspub );
     402           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 );
     403           0 : }
     404             : 
     405             : static void
     406             : after_credit( fd_gossip_tile_ctx_t * ctx,
     407             :               fd_stem_context_t *    stem,
     408             :               int *                  opt_poll_in,
     409           0 :               int *                  charge_busy ) {
     410           0 :   (void)opt_poll_in;
     411             : 
     412             :   /* TODO: Don't charge the tile as busy if after_credit isn't actually
     413             :      doing any work. */
     414           0 :   *charge_busy = 1;
     415             : 
     416           0 :   ctx->stem = stem;
     417           0 :   ulong tsorig = fd_frag_meta_ts_comp( fd_tickcount() );
     418             : 
     419           0 :   if( FD_LIKELY( ctx->shred_contact_out_sync  ) ) fd_mcache_seq_update( ctx->shred_contact_out_sync, ctx->shred_contact_out_seq );
     420           0 :   if( FD_LIKELY( ctx->repair_contact_out_sync ) ) fd_mcache_seq_update( ctx->repair_contact_out_sync, ctx->repair_contact_out_seq );
     421             : 
     422           0 :   long now = fd_gossip_gettime( ctx->gossip );
     423           0 :   if( ( now - ctx->last_shred_dest_push_time )>CONTACT_INFO_PUBLISH_TIME_NS &&
     424           0 :       ctx->shred_contact_out_mcache ) {
     425             : 
     426           0 :     ctx->metrics.last_crds_push_contact_info_publish_ts = (ulong)(ctx->last_shred_dest_push_time);
     427             : 
     428           0 :     ctx->last_shred_dest_push_time = now;
     429             : 
     430           0 :     ulong tvu_peer_cnt = 0;
     431           0 :     ulong repair_peers_cnt = 0;
     432           0 :     ulong send_peers_cnt = 0;
     433             : 
     434           0 :     ulong * shred_dest_msg = fd_chunk_to_laddr( ctx->shred_contact_out_mem, ctx->shred_contact_out_chunk );
     435           0 :     fd_shred_dest_wire_t * tvu_peers = (fd_shred_dest_wire_t *)(shred_dest_msg+1);
     436           0 :     fd_shred_dest_wire_t * repair_peers = fd_chunk_to_laddr( ctx->repair_contact_out_mem, ctx->repair_contact_out_chunk );
     437           0 :     fd_shred_dest_wire_t * send_peers = fd_chunk_to_laddr( ctx->send_contact_out_mem, ctx->send_contact_out_chunk );
     438           0 :     for( fd_contact_info_table_iter_t iter = fd_contact_info_table_iter_init( ctx->contact_info_table );
     439           0 :          !fd_contact_info_table_iter_done( ctx->contact_info_table, iter );
     440           0 :          iter = fd_contact_info_table_iter_next( ctx->contact_info_table, iter ) ) {
     441           0 :       fd_contact_info_elem_t const * ele = fd_contact_info_table_iter_ele_const( ctx->contact_info_table, iter );
     442           0 :       fd_contact_info_t const * ci = &ele->contact_info;
     443             : 
     444           0 :       if( fd_contact_info_get_shred_version( ci )!=fd_gossip_get_shred_version( ctx->gossip ) ) {
     445           0 :         ctx->metrics.mismatched_contact_info_shred_version += 1UL;
     446           0 :         continue;
     447           0 :       }
     448             : 
     449           0 :       {
     450           0 :         ushort tvu_socket_idx = ci->socket_tag_idx[ FD_GOSSIP_SOCKET_TAG_TVU ];
     451           0 :         if( tvu_socket_idx == FD_CONTACT_INFO_SOCKET_TAG_NULL ) {
     452           0 :           ctx->metrics.zero_ipv4_contact_info[ FD_METRICS_ENUM_PEER_TYPES_V_TVU_IDX ] += 1UL;
     453           0 :           continue;
     454           0 :         }
     455           0 :         if( !fd_gossip_ip_addr_is_ip4( &ci->addrs[ ci->sockets[ tvu_socket_idx].index ] )) {
     456           0 :           continue;
     457           0 :         }
     458             : 
     459             : 
     460           0 :         tvu_peers[tvu_peer_cnt].ip4_addr = ci->addrs[ ci->sockets[ tvu_socket_idx].index ].inner.ip4;
     461           0 :         tvu_peers[tvu_peer_cnt].udp_port = ci->ports[ tvu_socket_idx ]; /* NOT converted to net order */
     462           0 :         memcpy( tvu_peers[tvu_peer_cnt].pubkey, &ci->ci_crd.from, sizeof(fd_pubkey_t) );
     463             : 
     464           0 :         tvu_peer_cnt++;
     465           0 :       }
     466             : 
     467           0 :       {
     468           0 :         ushort repair_socket_idx = ci->socket_tag_idx[ FD_GOSSIP_SOCKET_TAG_SERVE_REPAIR ];
     469           0 :         if( repair_socket_idx == FD_CONTACT_INFO_SOCKET_TAG_NULL ) {
     470           0 :           ctx->metrics.zero_ipv4_contact_info[ FD_METRICS_ENUM_PEER_TYPES_V_REPAIR_IDX ] += 1UL;
     471           0 :           continue;
     472           0 :         }
     473           0 :         if( !fd_gossip_ip_addr_is_ip4( &ci->addrs[ ci->sockets[ repair_socket_idx].index ] )) {
     474           0 :           continue;
     475           0 :         }
     476             : 
     477           0 :         repair_peers[repair_peers_cnt].ip4_addr = ci->addrs[ ci->sockets[ repair_socket_idx].index ].inner.ip4;
     478           0 :         repair_peers[repair_peers_cnt].udp_port = ci->ports[ repair_socket_idx ]; /* NOT converted to net order */
     479           0 :         memcpy( repair_peers[repair_peers_cnt].pubkey, &ci->ci_crd.from, sizeof(fd_pubkey_t) );
     480             : 
     481           0 :         repair_peers_cnt++;
     482           0 :       }
     483             : 
     484           0 :       {
     485           0 :         ushort sender_socket_idx = ci->socket_tag_idx[ FD_GOSSIP_SOCKET_TAG_TPU_QUIC ];
     486           0 :         if( sender_socket_idx == FD_CONTACT_INFO_SOCKET_TAG_NULL ) {
     487           0 :           ctx->metrics.zero_ipv4_contact_info[ FD_METRICS_ENUM_PEER_TYPES_V_SEND_IDX ] += 1UL;
     488           0 :           continue;
     489           0 :         }
     490           0 :         if( !fd_gossip_ip_addr_is_ip4( &ci->addrs[ ci->sockets[ sender_socket_idx].index ] )) {
     491           0 :           continue;
     492           0 :         }
     493             : 
     494           0 :         send_peers[send_peers_cnt].ip4_addr = ci->addrs[ ci->sockets[ sender_socket_idx ].index ].inner.ip4;
     495           0 :         send_peers[send_peers_cnt].udp_port = ci->ports[ sender_socket_idx ]; /* NOT converted to net order */
     496           0 :         memcpy( send_peers[send_peers_cnt].pubkey, &ci->ci_crd.from, sizeof(fd_pubkey_t) );
     497             : 
     498           0 :         send_peers_cnt++;
     499           0 :       }
     500           0 :     }
     501             : 
     502           0 : #define UPDATE_PEER_CNTS( _peer_cnt_, _peer_type_ ) \
     503           0 :   ctx->metrics.peer_counts[ FD_METRICS_ENUM_PEER_TYPES_V_ ##_peer_type_ ##_IDX ] = _peer_cnt_;
     504             : 
     505           0 :     UPDATE_PEER_CNTS( tvu_peer_cnt, TVU );
     506           0 :     UPDATE_PEER_CNTS( repair_peers_cnt, REPAIR );
     507           0 :     UPDATE_PEER_CNTS( send_peers_cnt, SEND );
     508             : 
     509           0 : #undef UPDATE_PEER_CNTS
     510             : 
     511           0 :     ulong tspub = fd_frag_meta_ts_comp( fd_tickcount() );
     512             : 
     513           0 :     FD_LOG_INFO(( "publishing peers - tvu: %lu, repair: %lu, tpu_vote: %lu", tvu_peer_cnt, repair_peers_cnt, send_peers_cnt ));
     514           0 :     if( tvu_peer_cnt>0 && ctx->shred_contact_out_mcache ) {
     515           0 :       *shred_dest_msg         = tvu_peer_cnt;
     516           0 :       ulong shred_contact_sz  = sizeof(ulong) + (tvu_peer_cnt * sizeof(fd_shred_dest_wire_t));
     517           0 :       ulong shred_contact_sig = 2UL;
     518           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,
     519           0 :         shred_contact_sz, 0UL, tsorig, tspub );
     520           0 :       ctx->shred_contact_out_seq   = fd_seq_inc( ctx->shred_contact_out_seq, 1UL );
     521           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 );
     522           0 :     }
     523             : 
     524           0 :     if( repair_peers_cnt>0 && ctx->repair_contact_out_mcache ) {
     525           0 :       ulong repair_contact_sz  = (repair_peers_cnt * sizeof(fd_shred_dest_wire_t));
     526           0 :       ulong repair_contact_sig = 3UL;
     527           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,
     528           0 :         repair_peers_cnt, 0UL, tsorig, tspub );
     529           0 :       ctx->repair_contact_out_seq   = fd_seq_inc( ctx->repair_contact_out_seq, 1UL );
     530           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 );
     531           0 :     }
     532             : 
     533           0 :     if( send_peers_cnt>0 && ctx->send_contact_out_mcache ) {
     534           0 :       ulong send_contact_sz  = (send_peers_cnt * sizeof(fd_shred_dest_wire_t));
     535           0 :       ulong send_contact_sig = 4UL;
     536           0 :       fd_mcache_publish( ctx->send_contact_out_mcache, ctx->send_contact_out_depth, ctx->send_contact_out_seq, send_contact_sig, ctx->send_contact_out_chunk,
     537           0 :         send_contact_sz, 0UL, tsorig, tspub );
     538           0 :       ctx->send_contact_out_seq   = fd_seq_inc( ctx->send_contact_out_seq, 1UL );
     539           0 :       ctx->send_contact_out_chunk = fd_dcache_compact_next( ctx->send_contact_out_chunk, send_contact_sz, ctx->send_contact_out_chunk0, ctx->send_contact_out_wmark );
     540           0 :     }
     541           0 :   }
     542             : 
     543           0 :   if( ctx->gossip_plugin_out_mem && FD_UNLIKELY( ( now - ctx->last_plugin_push_time )>PLUGIN_PUBLISH_TIME_NS ) ) {
     544           0 :     ctx->last_plugin_push_time = now;
     545           0 :     publish_peers_to_plugin( ctx, stem );
     546           0 :   }
     547             : 
     548           0 :   ushort shred_version = fd_gossip_get_shred_version( ctx->gossip );
     549           0 :   if( shred_version!=0U ) {
     550           0 :     *fd_shred_version = shred_version;
     551           0 :   } else {
     552           0 :     ctx->metrics.shred_version_zero += 1UL;
     553           0 :   }
     554           0 :   fd_gossip_continue( ctx->gossip );
     555           0 : }
     556             : 
     557             : static void
     558             : privileged_init( fd_topo_t *      topo,
     559           0 :                  fd_topo_tile_t * tile ) {
     560           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     561             : 
     562           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     563           0 :   fd_gossip_tile_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_gossip_tile_ctx_t), sizeof(fd_gossip_tile_ctx_t) );
     564           0 :   fd_memset( ctx, 0, sizeof(fd_gossip_tile_ctx_t) );
     565             : 
     566           0 :   uchar const * identity_key = fd_keyload_load( tile->gossip.identity_key_path, /* pubkey only: */ 1 );
     567           0 :   fd_memcpy( ctx->identity_public_key.uc, identity_key, sizeof(fd_pubkey_t) );
     568             : 
     569           0 :   FD_TEST( sizeof(ulong) == getrandom( &ctx->gossip_seed, sizeof(ulong), 0 ) );
     570           0 : }
     571             : 
     572             : static void
     573             : unprivileged_init( fd_topo_t *      topo,
     574           0 :                    fd_topo_tile_t * tile ) {
     575           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     576             : 
     577           0 :   if( FD_UNLIKELY( !tile->out_cnt ) ) FD_LOG_ERR(( "gossip tile has no primary output link" ));
     578             : 
     579           0 :   if( FD_UNLIKELY( !tile->gossip.ip_addr ) ) FD_LOG_ERR(( "gossip ip address not set" ));
     580           0 :   if( FD_UNLIKELY( !tile->gossip.gossip_listen_port ) ) FD_LOG_ERR(( "gossip listen port not set" ));
     581             : 
     582             :   /* Scratch mem setup */
     583           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     584           0 :   fd_gossip_tile_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_gossip_tile_ctx_t), sizeof(fd_gossip_tile_ctx_t) );
     585           0 :   ctx->gossip = FD_SCRATCH_ALLOC_APPEND( l, fd_gossip_align(), fd_gossip_footprint() );
     586           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 ) );
     587             : 
     588           0 :   if( FD_UNLIKELY( tile->in_cnt > MAX_IN_LINKS ) ) FD_LOG_ERR(( "gossip tile has too many input links" ));
     589             : 
     590           0 :   uint sign_link_in_idx = UINT_MAX;
     591           0 :   memset( ctx->in_kind, 0, sizeof(ctx->in_kind) );
     592           0 :   for( uint in_idx=0U; in_idx<(tile->in_cnt); in_idx++ ) {
     593           0 :     fd_topo_link_t * link = &topo->links[ tile->in_link_id[ in_idx ] ];
     594           0 :     if( 0==strcmp( link->name, "net_gossip" ) ) {
     595           0 :       ctx->in_kind[ in_idx ] = IN_KIND_NET;
     596           0 :       fd_net_rx_bounds_init( &ctx->in_links[ in_idx ].net_rx, link->dcache );
     597           0 :       continue;
     598           0 :     } else if( 0==strcmp( link->name, "send_txns" ) ) {
     599           0 :       ctx->in_kind[ in_idx ] = IN_KIND_SEND;
     600           0 :     } else if( 0==strcmp( link->name, "sign_gossip" ) ) {
     601           0 :       ctx->in_kind[ in_idx ] = IN_KIND_SIGN;
     602           0 :       sign_link_in_idx = in_idx;
     603           0 :     } else {
     604           0 :       FD_LOG_ERR(( "gossip tile has unexpected input link %s", link->name ));
     605           0 :     }
     606             : 
     607           0 :     ctx->in_links[ in_idx ].mem    = topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ].wksp;
     608           0 :     ctx->in_links[ in_idx ].chunk0 = fd_dcache_compact_chunk0( ctx->in_links[ in_idx ].mem, link->dcache );
     609           0 :     ctx->in_links[ in_idx ].wmark  = fd_dcache_compact_wmark( ctx->in_links[ in_idx ].mem, link->dcache, link->mtu );
     610           0 :   }
     611           0 :   if( FD_UNLIKELY( sign_link_in_idx==UINT_MAX ) ) FD_LOG_ERR(( "Missing sign_gossip link" ));
     612             : 
     613           0 :   uint sign_link_out_idx = UINT_MAX;
     614           0 :   for( uint out_idx=0U; out_idx<(tile->out_cnt); out_idx++ ) {
     615           0 :     fd_topo_link_t * link = &topo->links[ tile->out_link_id[ out_idx ] ];
     616             : 
     617           0 :     if( 0==strcmp( link->name, "gossip_net" ) ) {
     618             : 
     619           0 :       if( FD_UNLIKELY( ctx->net_out_mcache ) ) FD_LOG_ERR(( "gossip tile has multiple gossip_net out links" ));
     620           0 :       ctx->net_out_mcache = link->mcache;
     621           0 :       ctx->net_out_sync   = fd_mcache_seq_laddr( ctx->net_out_mcache );
     622           0 :       ctx->net_out_depth  = fd_mcache_depth( ctx->net_out_mcache );
     623           0 :       ctx->net_out_seq    = fd_mcache_seq_query( ctx->net_out_sync );
     624           0 :       ctx->net_out_chunk0 = fd_dcache_compact_chunk0( fd_wksp_containing( link->dcache ), link->dcache );
     625           0 :       ctx->net_out_mem    = topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ].wksp;
     626           0 :       ctx->net_out_wmark  = fd_dcache_compact_wmark( ctx->net_out_mem, link->dcache, link->mtu );
     627           0 :       ctx->net_out_chunk  = ctx->net_out_chunk0;
     628             : 
     629           0 :     } else if( 0==strcmp( link->name, "crds_shred" ) ) {
     630             : 
     631             : 
     632           0 :       if( FD_UNLIKELY( ctx->shred_contact_out_mcache ) ) FD_LOG_ERR(( "gossip tile has multiple crds_shred out links" ));
     633           0 :       ctx->shred_contact_out_mcache = link->mcache;
     634           0 :       ctx->shred_contact_out_sync   = fd_mcache_seq_laddr( ctx->shred_contact_out_mcache );
     635           0 :       ctx->shred_contact_out_depth  = fd_mcache_depth( ctx->shred_contact_out_mcache );
     636           0 :       ctx->shred_contact_out_seq    = fd_mcache_seq_query( ctx->shred_contact_out_sync );
     637           0 :       ctx->shred_contact_out_mem    = topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ].wksp;
     638           0 :       ctx->shred_contact_out_chunk0 = fd_dcache_compact_chunk0( ctx->shred_contact_out_mem, link->dcache );
     639           0 :       ctx->shred_contact_out_wmark  = fd_dcache_compact_wmark ( ctx->shred_contact_out_mem, link->dcache, link->mtu );
     640           0 :       ctx->shred_contact_out_chunk  = ctx->shred_contact_out_chunk0;
     641             : 
     642           0 :     } else if( 0==strcmp( link->name, "gossip_repai" ) ) {
     643             : 
     644           0 :       if( FD_UNLIKELY( ctx->repair_contact_out_mcache ) ) FD_LOG_ERR(( "gossip tile has multiple gossip_repair out links" ));
     645           0 :       ctx->repair_contact_out_mcache = link->mcache;
     646           0 :       ctx->repair_contact_out_sync   = fd_mcache_seq_laddr( ctx->repair_contact_out_mcache );
     647           0 :       ctx->repair_contact_out_depth  = fd_mcache_depth( ctx->repair_contact_out_mcache );
     648           0 :       ctx->repair_contact_out_seq    = fd_mcache_seq_query( ctx->repair_contact_out_sync );
     649           0 :       ctx->repair_contact_out_mem    = topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ].wksp;
     650           0 :       ctx->repair_contact_out_chunk0 = fd_dcache_compact_chunk0( ctx->repair_contact_out_mem, link->dcache );
     651           0 :       ctx->repair_contact_out_wmark  = fd_dcache_compact_wmark ( ctx->repair_contact_out_mem, link->dcache, link->mtu );
     652           0 :       ctx->repair_contact_out_chunk  = ctx->repair_contact_out_chunk0;
     653             : 
     654           0 :     } else if( 0==strcmp( link->name, "gossip_verif" ) ) {
     655             : 
     656           0 :       if( FD_UNLIKELY( ctx->verify_out_mcache ) ) FD_LOG_ERR(( "gossip tile has multiple gossip_verif out links" ));
     657           0 :       ctx->verify_out_mcache = link->mcache;
     658           0 :       ctx->verify_out_sync   = fd_mcache_seq_laddr( ctx->verify_out_mcache );
     659           0 :       ctx->verify_out_depth  = fd_mcache_depth( ctx->verify_out_mcache );
     660           0 :       ctx->verify_out_seq    = fd_mcache_seq_query( ctx->verify_out_sync );
     661           0 :       ctx->verify_out_mem    = topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ].wksp;
     662           0 :       ctx->verify_out_chunk0 = fd_dcache_compact_chunk0( ctx->verify_out_mem, link->dcache );
     663           0 :       ctx->verify_out_wmark  = fd_dcache_compact_wmark ( ctx->verify_out_mem, link->dcache, link->mtu );
     664           0 :       ctx->verify_out_chunk  = ctx->verify_out_chunk0;
     665             : 
     666           0 :     } else if( 0==strcmp( link->name, "gossip_sign" ) ) {
     667             : 
     668           0 :       sign_link_out_idx = out_idx;
     669             : 
     670           0 :     } else if( 0==strcmp( link->name, "gossip_send" ) ) {
     671             : 
     672           0 :       if( FD_UNLIKELY( ctx->send_contact_out_mcache ) ) FD_LOG_ERR(( "gossip tile has multiple gossip_send out links" ));
     673           0 :       ctx->send_contact_out_mcache = link->mcache;
     674           0 :       ctx->send_contact_out_sync   = fd_mcache_seq_laddr( ctx->send_contact_out_mcache );
     675           0 :       ctx->send_contact_out_depth  = fd_mcache_depth( ctx->send_contact_out_mcache );
     676           0 :       ctx->send_contact_out_seq    = fd_mcache_seq_query( ctx->send_contact_out_sync );
     677           0 :       ctx->send_contact_out_mem    = topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ].wksp;
     678           0 :       ctx->send_contact_out_chunk0 = fd_dcache_compact_chunk0( ctx->send_contact_out_mem, link->dcache );
     679           0 :       ctx->send_contact_out_wmark  = fd_dcache_compact_wmark ( ctx->send_contact_out_mem, link->dcache, link->mtu );
     680           0 :       ctx->send_contact_out_chunk  = ctx->send_contact_out_chunk0;
     681             : 
     682           0 :     } else if( 0==strcmp( link->name, "gossip_tower" ) ) {
     683             : 
     684           0 :       ctx->tower_out_idx         = fd_topo_find_tile_out_link( topo, tile, "gossip_tower", 0 );
     685           0 :       ctx->tower_out_mem         = topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ].wksp;
     686           0 :       ctx->tower_out_chunk0      = fd_dcache_compact_chunk0( ctx->tower_out_mem, link->dcache );
     687           0 :       ctx->tower_out_wmark       = fd_dcache_compact_wmark ( ctx->tower_out_mem, link->dcache, link->mtu );
     688           0 :       ctx->tower_out_chunk       = ctx->tower_out_chunk0;
     689             : 
     690           0 :       FD_TEST( ctx->tower_out_idx!=ULONG_MAX );
     691           0 :       FD_TEST( ctx->tower_out_mem );
     692           0 :       FD_TEST( fd_dcache_compact_is_safe( ctx->tower_out_mem, link->dcache, link->mtu, link->depth ) );
     693             : 
     694           0 :     } else if( 0==strcmp( link->name, "gossip_plugi" ) ) {
     695             : 
     696           0 :       if( FD_UNLIKELY( ctx->gossip_plugin_out_mem ) ) FD_LOG_ERR(( "gossip tile has multiple gossip_plugi out links" ));
     697           0 :       ctx->gossip_plugin_out_mem    = topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ].wksp;
     698           0 :       ctx->gossip_plugin_out_chunk0 = fd_dcache_compact_chunk0( ctx->gossip_plugin_out_mem, link->dcache );
     699           0 :       ctx->gossip_plugin_out_wmark  = fd_dcache_compact_wmark ( ctx->gossip_plugin_out_mem, link->dcache, link->mtu );
     700           0 :       ctx->gossip_plugin_out_chunk  = ctx->gossip_plugin_out_chunk0;
     701           0 :       ctx->gossip_plugin_out_idx    = out_idx;
     702             : 
     703           0 :     } else {
     704           0 :       FD_LOG_ERR(( "gossip tile has unexpected output link %s", link->name ));
     705           0 :     }
     706             : 
     707           0 :   }
     708           0 :   if( FD_UNLIKELY( sign_link_out_idx==UINT_MAX ) ) FD_LOG_ERR(( "Missing gossip_sign link" ));
     709             : 
     710           0 :   ctx->wksp = topo->workspaces[ topo->objs[ tile->tile_obj_id ].wksp_id ].wksp;
     711             : 
     712           0 :   ctx->gossip_my_addr.addr = tile->gossip.ip_addr;
     713           0 :   ctx->gossip_my_addr.port = fd_ushort_bswap( tile->gossip.gossip_listen_port );
     714             : 
     715           0 :   ctx->gossip_listen_port = tile->gossip.gossip_listen_port;
     716             : 
     717           0 :   FD_TEST( ctx->gossip_listen_port!=0 );
     718             : 
     719           0 :   ctx->net_id = (ushort)0;
     720             : 
     721           0 :   fd_ip4_udp_hdr_init( ctx->hdr, FD_NET_MTU, ctx->gossip_my_addr.addr, ctx->gossip_listen_port );
     722             : 
     723           0 :   ctx->last_shred_dest_push_time = 0;
     724             : 
     725           0 :   fd_topo_link_t * sign_in  = &topo->links[ tile->in_link_id [ sign_link_in_idx  ] ];
     726           0 :   fd_topo_link_t * sign_out = &topo->links[ tile->out_link_id[ sign_link_out_idx ] ];
     727           0 :   if ( fd_keyguard_client_join( fd_keyguard_client_new( ctx->keyguard_client,
     728           0 :                                                             sign_out->mcache,
     729           0 :                                                             sign_out->dcache,
     730           0 :                                                             sign_in->mcache,
     731           0 :                                                             sign_in->dcache ) )==NULL ) {
     732           0 :     FD_LOG_ERR(( "Keyguard join failed" ));
     733           0 :   }
     734             : 
     735             :   /* Gossip set up */
     736           0 :   ctx->gossip = fd_gossip_join( fd_gossip_new( ctx->gossip, ctx->gossip_seed ) );
     737             : 
     738           0 :   FD_LOG_NOTICE(( "gossip my addr - addr: " FD_IP4_ADDR_FMT ":%u",
     739           0 :     FD_IP4_ADDR_FMT_ARGS( ctx->gossip_my_addr.addr ), fd_ushort_bswap( ctx->gossip_my_addr.port ) ));
     740           0 :   ctx->gossip_config.my_addr    = ctx->gossip_my_addr;
     741           0 :   ctx->gossip_config.my_version = (fd_gossip_version_v3_t){
     742           0 :     .major = 42U,
     743           0 :     .minor = 42U,
     744           0 :     .patch = 42U,
     745           0 :     .commit = 0U,
     746           0 :     .feature_set = 0U,
     747           0 :     .client = 2U
     748           0 :   };
     749           0 :   ctx->gossip_config.node_outset   = fd_log_wallclock() / 1000000; /* in ms */
     750           0 :   ctx->gossip_config.public_key    = &ctx->identity_public_key;
     751           0 :   ctx->gossip_config.deliver_fun   = gossip_deliver_fun;
     752           0 :   ctx->gossip_config.deliver_arg   = ctx;
     753           0 :   ctx->gossip_config.send_fun      = gossip_send_packet;
     754           0 :   ctx->gossip_config.send_arg      = ctx;
     755           0 :   ctx->gossip_config.sign_fun      = gossip_signer;
     756           0 :   ctx->gossip_config.sign_arg      = ctx;
     757           0 :   ctx->gossip_config.shred_version = (ushort)tile->gossip.expected_shred_version;
     758             : 
     759           0 :   if( fd_gossip_set_config( ctx->gossip, &ctx->gossip_config ) ) {
     760           0 :     FD_LOG_ERR( ( "error setting gossip config" ) );
     761           0 :   }
     762             : 
     763           0 :   fd_gossip_set_entrypoints( ctx->gossip, tile->gossip.entrypoints, tile->gossip.entrypoints_cnt );
     764             : 
     765           0 :   fd_gossip_update_addr( ctx->gossip, &ctx->gossip_config.my_addr );
     766             : 
     767           0 :   ctx->tvu_my_addr.addr       = tile->gossip.ip_addr;
     768           0 :   ctx->tvu_my_addr.port       = fd_ushort_bswap( tile->gossip.tvu_port );
     769           0 :   ctx->tpu_my_addr.addr       = tile->gossip.ip_addr;
     770           0 :   ctx->tpu_my_addr.port       = fd_ushort_bswap( tile->gossip.tpu_port );
     771           0 :   ctx->tpu_quic_my_addr.addr  = tile->gossip.ip_addr;
     772           0 :   ctx->tpu_quic_my_addr.port  = fd_ushort_bswap( tile->gossip.tpu_quic_port );
     773           0 :   ctx->tpu_vote_my_addr.addr  = tile->gossip.ip_addr;
     774           0 :   ctx->tpu_vote_my_addr.port  = fd_ushort_bswap( tile->gossip.tpu_vote_port );
     775           0 :   ctx->repair_serve_addr.addr = tile->gossip.ip_addr;
     776           0 :   ctx->repair_serve_addr.port = fd_ushort_bswap( tile->gossip.repair_serve_port );
     777             : 
     778           0 :   fd_gossip_update_tvu_addr( ctx->gossip, &ctx->tvu_my_addr );
     779           0 :   fd_gossip_update_tpu_addr( ctx->gossip, &ctx->tpu_my_addr, &ctx->tpu_quic_my_addr );
     780           0 :   fd_gossip_update_tpu_vote_addr( ctx->gossip, &ctx->tpu_vote_my_addr );
     781           0 :   fd_gossip_update_repair_addr( ctx->gossip, &ctx->repair_serve_addr );
     782           0 :   fd_gossip_settime( ctx->gossip, fd_log_wallclock() );
     783           0 :   fd_gossip_start( ctx->gossip );
     784             : 
     785           0 :   FD_LOG_NOTICE(( "gossip listening on port %u", tile->gossip.gossip_listen_port ));
     786             : 
     787           0 :   ulong scratch_top = FD_SCRATCH_ALLOC_FINI( l, 1UL );
     788           0 :   if( FD_UNLIKELY( scratch_top>( (ulong)scratch + scratch_footprint( tile ) ) ) )
     789           0 :     FD_LOG_ERR(( "scratch overflow %lu %lu %lu", scratch_top - (ulong)scratch - scratch_footprint( tile ), scratch_top, (ulong)scratch + scratch_footprint( tile ) ));
     790             : 
     791           0 :   ulong poh_shred_obj_id = fd_pod_query_ulong( topo->props, "poh_shred", ULONG_MAX );
     792           0 :   FD_TEST( poh_shred_obj_id!=ULONG_MAX );
     793             : 
     794           0 :   fd_shred_version = fd_fseq_join( fd_topo_obj_laddr( topo, poh_shred_obj_id ) );
     795           0 :   FD_TEST( fd_shred_version );
     796             : 
     797             :   /* Initialize metrics to zero */
     798           0 :   memset( &ctx->metrics, 0, FD_GOSSIP_TILE_METRICS_FOOTPRINT );
     799           0 : }
     800             : 
     801             : static ulong
     802             : populate_allowed_seccomp( fd_topo_t const *      topo,
     803             :                           fd_topo_tile_t const * tile,
     804             :                           ulong                  out_cnt,
     805           0 :                           struct sock_filter *   out ) {
     806           0 :   (void)topo;
     807           0 :   (void)tile;
     808             : 
     809           0 :   populate_sock_filter_policy_fd_gossip_tile( out_cnt, out, (uint)fd_log_private_logfile_fd() );
     810           0 :   return sock_filter_policy_fd_gossip_tile_instr_cnt;
     811           0 : }
     812             : 
     813             : static ulong
     814             : populate_allowed_fds( fd_topo_t const *      topo,
     815             :                       fd_topo_tile_t const * tile,
     816             :                       ulong                  out_fds_cnt,
     817           0 :                       int *                  out_fds ) {
     818           0 :   (void)topo;
     819           0 :   (void)tile;
     820             : 
     821           0 :   if( FD_UNLIKELY( out_fds_cnt<2UL ) ) FD_LOG_ERR(( "out_fds_cnt %lu", out_fds_cnt ));
     822             : 
     823           0 :   ulong out_cnt = 0UL;
     824           0 :   out_fds[ out_cnt++ ] = 2; /* stderr */
     825           0 :   if( FD_LIKELY( -1!=fd_log_private_logfile_fd() ) )
     826           0 :     out_fds[ out_cnt++ ] = fd_log_private_logfile_fd(); /* logfile */
     827           0 :   return out_cnt;
     828           0 : }
     829             : 
     830             : static inline void
     831           0 : fd_gossip_update_gossip_metrics( fd_gossip_metrics_t * metrics ) {
     832           0 :   FD_MCNT_SET( GOSSIP, RECEIVED_PACKETS, metrics->recv_pkt_cnt );
     833           0 :   FD_MCNT_SET( GOSSIP, CORRUPTED_MESSAGES, metrics->recv_pkt_corrupted_msg );
     834             : 
     835           0 :   FD_MCNT_ENUM_COPY( GOSSIP, RECEIVED_GOSSIP_MESSAGES, metrics->recv_message );
     836           0 :   FD_MCNT_SET( GOSSIP, RECEIVED_UNKNOWN_MESSAGE, metrics->recv_unknown_message );
     837             : 
     838           0 :   FD_MCNT_ENUM_COPY( GOSSIP, RECEIVED_CRDS_PUSH, metrics->recv_crds[ FD_GOSSIP_CRDS_ROUTE_PUSH ] );
     839           0 :   FD_MCNT_ENUM_COPY( GOSSIP, RECEIVED_CRDS_PULL, metrics->recv_crds[ FD_GOSSIP_CRDS_ROUTE_PULL_RESP ] );
     840           0 :   FD_MCNT_ENUM_COPY( GOSSIP, RECEIVED_CRDS_DUPLICATE_MESSAGE_PUSH, metrics->recv_crds_duplicate_message[ FD_GOSSIP_CRDS_ROUTE_PUSH ] );
     841           0 :   FD_MCNT_ENUM_COPY( GOSSIP, RECEIVED_CRDS_DUPLICATE_MESSAGE_PULL, metrics->recv_crds_duplicate_message[ FD_GOSSIP_CRDS_ROUTE_PULL_RESP ] );
     842           0 :   FD_MCNT_ENUM_COPY( GOSSIP, RECEIVED_CRDS_DROP, metrics->recv_crds_drop_reason );
     843             : 
     844           0 :   FD_MCNT_ENUM_COPY( GOSSIP, PUSH_CRDS, metrics->push_crds );
     845           0 :   FD_MCNT_ENUM_COPY( GOSSIP, PUSH_CRDS_DUPLICATE_MESSAGE, metrics->push_crds_duplicate );
     846           0 :   FD_MCNT_ENUM_COPY( GOSSIP, PUSH_CRDS_DROP, metrics->push_crds_drop_reason );
     847           0 :   FD_MGAUGE_SET( GOSSIP, PUSH_CRDS_QUEUE_COUNT, metrics->push_crds_queue_cnt );
     848             : 
     849           0 :   FD_MGAUGE_SET( GOSSIP, VALUE_META_SIZE, metrics->value_meta_cnt );
     850           0 :   FD_MGAUGE_SET( GOSSIP, VALUE_VEC_SIZE, metrics->value_vec_cnt );
     851             : 
     852           0 :   FD_MGAUGE_SET( GOSSIP, ACTIVE_PUSH_DESTINATIONS, metrics->active_push_destinations );
     853           0 :   FD_MCNT_SET( GOSSIP, REFRESH_PUSH_STATES_FAIL_COUNT, metrics->refresh_push_states_failcnt );
     854             : 
     855           0 :   FD_MCNT_ENUM_COPY( GOSSIP, PULL_REQ_FAIL, metrics->handle_pull_req_fails );
     856             : 
     857           0 :   FD_MCNT_ENUM_COPY( GOSSIP, PULL_REQ_BLOOM_FILTER, metrics->handle_pull_req_bloom_filter_result);
     858           0 :   FD_MGAUGE_SET( GOSSIP, PULL_REQ_RESP_PACKETS, metrics->handle_pull_req_npackets );
     859             : 
     860           0 :   FD_MCNT_ENUM_COPY( GOSSIP, PRUNE_FAIL_COUNT, metrics->handle_prune_fails );
     861             : 
     862           0 :   FD_MCNT_SET( GOSSIP, MAKE_PRUNE_STALE_ENTRY, metrics->make_prune_stale_entry );
     863           0 :   FD_MCNT_SET( GOSSIP, MAKE_PRUNE_HIGH_DUPLICATES, metrics->make_prune_high_duplicates );
     864           0 :   FD_MGAUGE_SET( GOSSIP, MAKE_PRUNE_REQUESTED_ORIGINS, metrics->make_prune_requested_origins );
     865           0 :   FD_MCNT_SET( GOSSIP, MAKE_PRUNE_SIGN_DATA_ENCODE_FAILED, metrics->make_prune_sign_data_encode_failed );
     866             : 
     867           0 :   FD_MCNT_ENUM_COPY( GOSSIP, SENT_GOSSIP_MESSAGES, metrics->send_message );
     868             : 
     869           0 :   FD_MCNT_SET( GOSSIP, SENT_PACKETS, metrics->send_packet_cnt );
     870             : 
     871           0 :   FD_MCNT_ENUM_COPY( GOSSIP, SEND_PING_EVENT, metrics->send_ping_events );
     872           0 :   FD_MCNT_SET( GOSSIP, RECV_PING_INVALID_SIGNATURE, metrics->recv_ping_invalid_signature );
     873             : 
     874           0 :   FD_MCNT_ENUM_COPY( GOSSIP, RECV_PONG_EVENT, metrics->recv_pong_events );
     875             : 
     876           0 :   FD_MGAUGE_ENUM_COPY( GOSSIP, GOSSIP_PEER_COUNTS, metrics->gossip_peer_cnt );
     877           0 : }
     878             : 
     879             : static inline void
     880           0 : metrics_write( fd_gossip_tile_ctx_t * ctx ) {
     881             :   /* Tile-specific metrics */
     882           0 :   FD_MGAUGE_SET( GOSSIP, LAST_CRDS_PUSH_CONTACT_INFO_PUBLISH_TIMESTAMP_NANOS, ctx->metrics.last_crds_push_contact_info_publish_ts );
     883           0 :   FD_MCNT_SET( GOSSIP, MISMATCHED_CONTACT_INFO_SHRED_VERSION, ctx->metrics.mismatched_contact_info_shred_version );
     884           0 :   FD_MCNT_ENUM_COPY( GOSSIP, IPV6_CONTACT_INFO, ctx->metrics.ipv6_contact_info );
     885           0 :   FD_MCNT_ENUM_COPY( GOSSIP, ZERO_IPV4_CONTACT_INFO, ctx->metrics.zero_ipv4_contact_info );
     886           0 :   FD_MGAUGE_ENUM_COPY( GOSSIP, PEER_COUNTS, ctx->metrics.peer_counts );
     887           0 :   FD_MCNT_SET( GOSSIP, SHRED_VERSION_ZERO, ctx->metrics.shred_version_zero );
     888             : 
     889             :   /* Gossip-protocol-specific metrics */
     890           0 :   fd_gossip_update_gossip_metrics( fd_gossip_get_metrics( ctx->gossip ) );
     891           0 : }
     892             : 
     893           0 : #define STEM_BURST (1UL)
     894             : 
     895           0 : #define STEM_CALLBACK_CONTEXT_TYPE  fd_gossip_tile_ctx_t
     896           0 : #define STEM_CALLBACK_CONTEXT_ALIGN alignof(fd_gossip_tile_ctx_t)
     897             : 
     898           0 : #define STEM_CALLBACK_AFTER_CREDIT        after_credit
     899           0 : #define STEM_CALLBACK_DURING_HOUSEKEEPING during_housekeeping
     900           0 : #define STEM_CALLBACK_BEFORE_FRAG         before_frag
     901           0 : #define STEM_CALLBACK_DURING_FRAG         during_frag
     902           0 : #define STEM_CALLBACK_AFTER_FRAG          after_frag
     903           0 : #define STEM_CALLBACK_METRICS_WRITE       metrics_write
     904             : 
     905             : #include "../../disco/stem/fd_stem.c"
     906             : 
     907             : fd_topo_run_tile_t fd_tile_gossip = {
     908             :   .name                     = "gossip",
     909             :   .loose_footprint          = loose_footprint,
     910             :   .populate_allowed_seccomp = populate_allowed_seccomp,
     911             :   .populate_allowed_fds     = populate_allowed_fds,
     912             :   .scratch_align            = scratch_align,
     913             :   .scratch_footprint        = scratch_footprint,
     914             :   .privileged_init          = privileged_init,
     915             :   .unprivileged_init        = unprivileged_init,
     916             :   .run                      = stem_run,
     917             : };

Generated by: LCOV version 1.14