LCOV - code coverage report
Current view: top level - disco/repair - fd_rserve_tile.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 621 0.0 %
Date: 2026-11-12 04:25:03 Functions: 0 32 0.0 %

          Line data    Source code
       1             : /* fd_rserve_tile serves incoming repair requests from other nodes */
       2             : 
       3             : #define _GNU_SOURCE
       4             : #include <errno.h>
       5             : #include <fcntl.h>
       6             : 
       7             : #include "fd_rserve.h"
       8             : #include "fd_repair_tile.h"
       9             : #include "fd_repair_serde.h"
      10             : #include "../../disco/fd_disco_base.h"
      11             : #include "../../disco/keyguard/fd_keyguard_client.h"
      12             : #include "../../disco/keyguard/fd_keyguard.h"
      13             : #include "../../disco/keyguard/fd_keyload.h"
      14             : #include "../../disco/keyguard/fd_keyswitch.h"
      15             : #include "../../disco/metrics/fd_metrics.h"
      16             : #include "../../disco/net/fd_net_tile.h"
      17             : #include "../../disco/shred/fd_shred_tile.h"
      18             : #include "../../disco/store/fd_store.h"
      19             : #include "../../disco/topo/fd_topo.h"
      20             : #include "../../util/pod/fd_pod_format.h"
      21             : #include "../../flamenco/gossip/fd_gossip_message.h"
      22             : #include "../../util/net/fd_net_headers.h"
      23             : 
      24             : #include <linux/futex.h>
      25             : #include "generated/fd_rserve_tile_seccomp.h"
      26             : 
      27           0 : #define IN_KIND_NET    (0)
      28           0 : #define IN_KIND_SIGN   (1)
      29           0 : #define IN_KIND_SHRED  (2)
      30           0 : #define IN_KIND_REPAIR (3)
      31             : 
      32             : #define MAX_IN_LINKS FD_TOPO_MAX_TILE_IN_LINKS
      33             : 
      34           0 : #define FD_RSERVE_MAX_PACKET_SIZE 1232
      35             : 
      36             : /* The maximum number of parent slots to look for. */
      37           0 : #define FD_RSERVE_MAX_ORPHAN_SLOTS 11
      38             : 
      39             : /* 10 minutes in milliseconds. */
      40             : #define FD_RSERVE_SIGNED_REPAIR_WINDOW (60L*10L*1000L)
      41             : 
      42             : /* static map from request type to response metric array index */
      43             : static uint response_metric_index[FD_REPAIR_SERDE_TAG_WINDOW_INDEX_FOR_BLOCK_ID + 1] = {
      44             :   [FD_REPAIR_SERDE_TAG_PING]                      = FD_METRICS_ENUM_REPAIR_RESPONSE_TYPE_V_PING_IDX,
      45             :   [FD_REPAIR_SERDE_TAG_WINDOW_INDEX]              = FD_METRICS_ENUM_REPAIR_RESPONSE_TYPE_V_WINDOW_INDEX_IDX,
      46             :   [FD_REPAIR_SERDE_TAG_HIGHEST_WINDOW_INDEX]      = FD_METRICS_ENUM_REPAIR_RESPONSE_TYPE_V_HIGHEST_WINDOW_INDEX_IDX,
      47             :   [FD_REPAIR_SERDE_TAG_ORPHAN]                    = FD_METRICS_ENUM_REPAIR_RESPONSE_TYPE_V_ORPHAN_IDX,
      48             :   [FD_REPAIR_SERDE_TAG_PARENT_AND_FEC_SET_COUNT]  = FD_METRICS_ENUM_REPAIR_RESPONSE_TYPE_V_PARENT_FEC_SET_COUNT_IDX,
      49             :   [FD_REPAIR_SERDE_TAG_FEC_SET_ROOT]              = FD_METRICS_ENUM_REPAIR_RESPONSE_TYPE_V_FEC_SET_ROOT_IDX,
      50             :   [FD_REPAIR_SERDE_TAG_WINDOW_INDEX_FOR_BLOCK_ID] = FD_METRICS_ENUM_REPAIR_RESPONSE_TYPE_V_WINDOW_INDEX_FOR_BLOCK_ID_IDX,
      51             : };
      52             : 
      53             : /* static map from request type to received request metric array index */
      54             : static uint request_metric_index[FD_REPAIR_SERDE_TAG_WINDOW_INDEX_FOR_BLOCK_ID + 1] = {
      55             :   [FD_REPAIR_SERDE_TAG_PONG]                      = FD_METRICS_ENUM_REPAIR_REQUEST_TYPE_V_PONG_IDX,
      56             :   [FD_REPAIR_SERDE_TAG_WINDOW_INDEX]              = FD_METRICS_ENUM_REPAIR_REQUEST_TYPE_V_WINDOW_INDEX_IDX,
      57             :   [FD_REPAIR_SERDE_TAG_HIGHEST_WINDOW_INDEX]      = FD_METRICS_ENUM_REPAIR_REQUEST_TYPE_V_HIGHEST_WINDOW_INDEX_IDX,
      58             :   [FD_REPAIR_SERDE_TAG_ORPHAN]                    = FD_METRICS_ENUM_REPAIR_REQUEST_TYPE_V_ORPHAN_IDX,
      59             :   [FD_REPAIR_SERDE_TAG_PARENT_AND_FEC_SET_COUNT]  = FD_METRICS_ENUM_REPAIR_REQUEST_TYPE_V_PARENT_FEC_SET_COUNT_IDX,
      60             :   [FD_REPAIR_SERDE_TAG_FEC_SET_ROOT]              = FD_METRICS_ENUM_REPAIR_REQUEST_TYPE_V_FEC_SET_ROOT_IDX,
      61             :   [FD_REPAIR_SERDE_TAG_WINDOW_INDEX_FOR_BLOCK_ID] = FD_METRICS_ENUM_REPAIR_REQUEST_TYPE_V_WINDOW_INDEX_FOR_BLOCK_ID_IDX,
      62             : };
      63             : 
      64             : 
      65             : typedef union {
      66             :   struct {
      67             :     fd_wksp_t * mem;
      68             :     ulong       chunk0;
      69             :     ulong       wmark;
      70             :     ulong       mtu;
      71             :   };
      72             :   fd_net_rx_bounds_t net_rx;
      73             : } in_ctx_t;
      74             : 
      75             : typedef struct ctx {
      76             :   fd_net_rx_bounds_t net_rx;
      77             : 
      78             :   uint     in_kind [ MAX_IN_LINKS ];
      79             :   in_ctx_t in_links[ MAX_IN_LINKS ];
      80             : 
      81             :   uint        net_out_idx;
      82             :   fd_wksp_t * net_out_mem;
      83             :   ulong       net_out_chunk0;
      84             :   ulong       net_out_wmark;
      85             :   ulong       net_out_chunk;
      86             : 
      87             :   ulong           seed;
      88             :   uchar           rserve_secret[ 32 ];
      89             :   fd_rserve_t *   rserve;
      90             :   fd_blockdb_t *  blockdb; /* NULL if disabled */
      91             :   fd_store_t *    store;
      92             :   int             disk_fd;
      93             :   ulong           max_shreds_per_block;
      94             : 
      95             :   /* Used for verifying incoming requests, and signing outgoing responses. */
      96             :   fd_sha512_t sha512[1];
      97             :   fd_keyguard_client_t keyguard_client[1];
      98             :   fd_keyswitch_t * keyswitch;
      99             :   fd_pubkey_t identity_public_key;
     100             :   int halt_signing;
     101             : 
     102             :   fd_ip4_udp_hdrs_t   serve_hdr[1];
     103             :   ushort              net_id;
     104             : 
     105             :   uchar               net_buf[ FD_NET_MTU ];
     106             :   fd_repair_out_blk_t repair_buf[1];
     107             : 
     108             :   struct {
     109             :     ulong received_request_count[FD_METRICS_ENUM_REPAIR_REQUEST_TYPE_CNT];
     110             :     ulong received_request_bytes;
     111             :     ulong received_malformed_count[FD_METRICS_ENUM_REQUEST_MALFORMED_REASON_CNT];
     112             : 
     113             :     ulong send_pkt_cnt;
     114             :     ulong sent_pkt_types  [FD_METRICS_ENUM_REPAIR_RESPONSE_TYPE_CNT];
     115             :     ulong sent_response_bytes;
     116             : 
     117             :     ulong unanswered      [FD_METRICS_ENUM_REPAIR_REQUEST_TYPE_CNT];
     118             :     ulong dropped  [FD_METRICS_ENUM_REQUEST_DROP_REASON_CNT];
     119             :     ulong disk_read[FD_METRICS_ENUM_DISK_READ_RESULT_CNT];
     120             :     ulong disk_read_bytes;
     121             :     ulong shreds_current;
     122             :     ulong disk_current_bytes;
     123             :     ulong disk_allocated_bytes;
     124             :     fd_histf_t disk_write_timing[1];
     125             :     ulong      disk_inserted;
     126             :     ulong      disk_write_failed;
     127             :     ulong      disk_write_bytes;
     128             :     fd_histf_t fec_preevict_timing[1];
     129             :     ulong      fec_preevict_write_cnt;
     130             :     ulong      fec_preevict_write_bytes;
     131             : 
     132             :     ulong ping_cache_entries;
     133             :     ulong ping_cache_capacity;
     134             :     ulong ping_cache_evictions;
     135             :   } metrics[ 1 ];
     136             : } ctx_t;
     137             : 
     138             : FD_FN_CONST static inline ulong
     139           0 : scratch_align( void ) {
     140           0 :   return 128UL;
     141           0 : }
     142             : 
     143             : FD_FN_PURE static inline ulong
     144           0 : scratch_footprint( fd_topo_tile_t const * tile FD_PARAM_UNUSED ) {
     145           0 :   ulong l = FD_LAYOUT_INIT;
     146           0 :   l = FD_LAYOUT_APPEND( l, alignof(ctx_t),    sizeof(ctx_t) );
     147           0 :   l = FD_LAYOUT_APPEND( l, fd_rserve_align(), fd_rserve_footprint( tile->rserve.ping_cache_entries) );
     148           0 :   if( FD_LIKELY( tile->rserve.blockdb_max ) ) {
     149           0 :     l = FD_LAYOUT_APPEND( l, fd_blockdb_align(), fd_blockdb_footprint( tile->rserve.blockdb_max ) );
     150           0 :   }
     151           0 :   return FD_LAYOUT_FINI( l, scratch_align() );
     152           0 : }
     153             : 
     154             : static void
     155             : send_packet( ctx_t               * ctx,
     156             :             fd_stem_context_t    * stem,
     157             :             uint                   dst_ip_addr,
     158             :             ushort                 dst_port,
     159             :             uint                   src_ip_addr,
     160             :             uchar const          * payload,
     161             :             ulong                  payload_sz,
     162           0 :             ulong                  tsorig ) {
     163           0 :   ctx->metrics->send_pkt_cnt++;
     164           0 :   ctx->metrics->sent_response_bytes += payload_sz;
     165           0 :   uchar * packet = fd_chunk_to_laddr( ctx->net_out_mem, ctx->net_out_chunk );
     166           0 :   fd_ip4_udp_hdrs_t * hdr = (fd_ip4_udp_hdrs_t *)packet;
     167           0 :   *hdr = *ctx->serve_hdr;
     168             : 
     169           0 :   fd_ip4_hdr_t * ip4 = hdr->ip4;
     170           0 :   ip4->saddr       = src_ip_addr;
     171           0 :   ip4->daddr       = dst_ip_addr;
     172           0 :   ip4->net_id      = fd_ushort_bswap( ctx->net_id++ );
     173           0 :   ip4->check       = 0U;
     174           0 :   ip4->net_tot_len = fd_ushort_bswap( (ushort)(payload_sz + sizeof(fd_ip4_hdr_t)+sizeof(fd_udp_hdr_t)) );
     175           0 :   ip4->check       = fd_ip4_hdr_check_fast( ip4 );
     176             : 
     177           0 :   fd_udp_hdr_t * udp = hdr->udp;
     178           0 :   udp->net_dport = dst_port;
     179           0 :   udp->net_len   = fd_ushort_bswap( (ushort)(payload_sz + sizeof(fd_udp_hdr_t)) );
     180           0 :   fd_memcpy( packet+sizeof(fd_ip4_udp_hdrs_t), payload, payload_sz );
     181           0 :   hdr->udp->check = 0U;
     182             : 
     183           0 :   ulong tspub     = fd_frag_meta_ts_comp( fd_tickcount() );
     184           0 :   ulong sig       = fd_disco_netmux_sig( dst_ip_addr, dst_port, dst_ip_addr, DST_PROTO_OUTGOING, sizeof(fd_ip4_udp_hdrs_t) );
     185           0 :   ulong packet_sz = payload_sz + sizeof(fd_ip4_udp_hdrs_t);
     186           0 :   ulong chunk     = ctx->net_out_chunk;
     187           0 :   fd_stem_publish( stem, ctx->net_out_idx, sig, chunk, packet_sz, 0UL, tsorig, tspub );
     188           0 :   ctx->net_out_chunk = fd_dcache_compact_next( chunk, packet_sz, ctx->net_out_chunk0, ctx->net_out_wmark );
     189           0 : }
     190             : 
     191             : static inline void
     192             : handle_pong( ctx_t              * ctx,
     193             :              uchar const        * payload,
     194             :              ulong                payload_sz,
     195             :              uint                 saddr,
     196           0 :              ushort               sport ) {
     197           0 :   fd_repair_pong_t pong;
     198           0 :   fd_ed25519_sig_t signature;
     199           0 :   fd_pubkey_t      from;
     200           0 :   if( FD_UNLIKELY( fd_repair_pong_de( payload, payload_sz, &pong, signature, &from )!=payload_sz ) ) return;
     201             : 
     202           0 :   if( FD_UNLIKELY( fd_pubkey_eq( &ctx->identity_public_key, &from ) ) ) {
     203             :     /* We've received our own repair request, ignore. */
     204           0 :     ctx->metrics->dropped[ FD_METRICS_ENUM_REQUEST_DROP_REASON_V_FROM_SELF_IDX ]++;
     205           0 :     return;
     206           0 :   }
     207             : 
     208           0 :   if( FD_UNLIKELY( FD_ED25519_SUCCESS!=fd_ed25519_verify( pong.hash.uc, 32UL, signature, from.uc, ctx->sha512 ) ) ) {
     209             :     /* Invalid signature, ignore. */
     210           0 :     ctx->metrics->dropped[ FD_METRICS_ENUM_REQUEST_DROP_REASON_V_SIGNATURE_FAILED_IDX ]++;
     211           0 :     return;
     212           0 :   }
     213             : 
     214             :   /* Verify that the pong hash corresponds to the token we would have issued
     215             :      to this (pubkey, address) under either the current or previous rotating
     216             :      secret. */
     217           0 :   if( FD_UNLIKELY( !fd_rserve_pong_token_verify( ctx->rserve, pong.hash.uc, &from, saddr, sport ) ) ) {
     218           0 :     ctx->metrics->dropped[ FD_METRICS_ENUM_REQUEST_DROP_REASON_V_PONG_TOKEN_INVALID_IDX ]++;
     219           0 :     return;
     220           0 :   }
     221             : 
     222           0 :   fd_rserve_t * rserve = ctx->rserve;
     223           0 :   ping_cache_key_t key[1];
     224           0 :   memset( key, 0, sizeof(ping_cache_key_t) );
     225           0 :   key->pubkey = from;
     226           0 :   key->ip4    = saddr;
     227           0 :   key->port   = sport;
     228             : 
     229           0 :   ping_cache_entry_t * entry = ping_map_ele_query( rserve->ping_map, key, NULL, rserve->ping_pool );
     230             : 
     231           0 :   if( FD_LIKELY( !entry ) ) {
     232             :     /* New entry, evict LRU if pool is full. */
     233           0 :     if( FD_UNLIKELY( !ping_pool_free( rserve->ping_pool ) ) ) {
     234           0 :       ping_cache_entry_t * victim = ping_dlist_ele_pop_head( rserve->ping_dlist, rserve->ping_pool );
     235           0 :       ping_map_ele_remove_fast( rserve->ping_map, victim, rserve->ping_pool );
     236           0 :       ping_pool_ele_release( rserve->ping_pool, victim );
     237           0 :       ctx->metrics->ping_cache_entries--;
     238           0 :       ctx->metrics->ping_cache_evictions++;
     239           0 :     }
     240           0 :     entry = ping_pool_ele_acquire( rserve->ping_pool );
     241           0 :     entry->key                = *key;
     242           0 :     ping_map_ele_insert( rserve->ping_map, entry, rserve->ping_pool );
     243           0 :     ctx->metrics->ping_cache_entries++;
     244           0 :   } else {
     245             :     /* Existing entry, move to tail. */
     246           0 :     ping_dlist_ele_remove( rserve->ping_dlist, entry, rserve->ping_pool );
     247           0 :   }
     248             : 
     249           0 :   entry->timestamp = (ulong)fd_log_wallclock();
     250           0 :   ping_dlist_ele_push_tail( rserve->ping_dlist, entry, rserve->ping_pool );
     251           0 :   return;
     252           0 : }
     253             : 
     254             : static inline void
     255             : handle_net_request( ctx_t             * ctx,
     256             :                     fd_stem_context_t * stem,
     257             :                     uchar const       * payload,
     258             :                     ulong               payload_sz,
     259             :                     fd_udp_hdr_t      * udp,
     260           0 :                     fd_ip4_hdr_t      * ip4 ) {
     261           0 :   if( FD_UNLIKELY( payload_sz<4UL ) ) {
     262           0 :     ctx->metrics->received_malformed_count[ FD_METRICS_ENUM_REQUEST_MALFORMED_REASON_V_TOO_SMALL_IDX ]++;
     263           0 :     return;
     264           0 :   }
     265           0 :   uint tag = FD_LOAD( uint, payload );
     266             : 
     267           0 :   if( FD_UNLIKELY( tag==FD_REPAIR_SERDE_TAG_PONG ) ) {
     268           0 :     ctx->metrics->received_request_count[ request_metric_index[tag] ]++;
     269           0 :     ctx->metrics->received_request_bytes += payload_sz;
     270           0 :     handle_pong( ctx, payload, payload_sz, ip4->saddr, udp->net_sport );
     271           0 :     return;
     272           0 :   }
     273             :   /* Block id requests need the blockdb, which only exists when
     274             :      alpenglow is enabled. */
     275           0 :   int is_bid = tag==FD_REPAIR_SERDE_TAG_PARENT_AND_FEC_SET_COUNT || tag==FD_REPAIR_SERDE_TAG_FEC_SET_ROOT || tag==FD_REPAIR_SERDE_TAG_WINDOW_INDEX_FOR_BLOCK_ID;
     276           0 :   if( FD_UNLIKELY( tag!=FD_REPAIR_SERDE_TAG_WINDOW_INDEX &&
     277           0 :                    tag!=FD_REPAIR_SERDE_TAG_HIGHEST_WINDOW_INDEX &&
     278           0 :                    tag!=FD_REPAIR_SERDE_TAG_ORPHAN &&
     279           0 :                    !( is_bid && ctx->blockdb ) ) ) {
     280           0 :     if(      tag==FD_REPAIR_SERDE_TAG_PING            ) ctx->metrics->received_malformed_count[ FD_METRICS_ENUM_REQUEST_MALFORMED_REASON_V_UNSUPPORTED_PING_IDX ]++;
     281           0 :     else if( tag==FD_REPAIR_SERDE_TAG_ANCESTOR_HASHES ) ctx->metrics->received_malformed_count[ FD_METRICS_ENUM_REQUEST_MALFORMED_REASON_V_UNSUPPORTED_ANCESTOR_HASHES_IDX ]++;
     282           0 :     else                                                ctx->metrics->received_malformed_count[ FD_METRICS_ENUM_REQUEST_MALFORMED_REASON_V_UNKNOWN_TAG_IDX ]++;
     283           0 :     return;
     284           0 :   }
     285             : 
     286             :   /* The request must be exactly its kind's size, checked before
     287             :      constructing the signable payload to avoid OOB reads. */
     288           0 :   fd_ed25519_sig_t signature;
     289           0 :   fd_pubkey_t      sender;
     290           0 :   fd_pubkey_t      recipient;
     291           0 :   ulong            timestamp;
     292           0 :   uint             nonce;
     293           0 :   union {
     294           0 :     fd_repair_shred_t                shred;
     295           0 :     fd_repair_highest_shred_t        highest_shred;
     296           0 :     fd_repair_orphan_t               orphan;
     297           0 :     fd_repair_parent_fec_set_count_t parent_fec_set_count;
     298           0 :     fd_repair_fec_set_root_t         fec_set_root;
     299           0 :     fd_repair_shred_for_block_id_t   shred_for_block_id;
     300           0 :   } req;
     301           0 :   ulong req_sz = 0UL;
     302           0 :   switch( tag ) {
     303           0 :     case FD_REPAIR_SERDE_TAG_WINDOW_INDEX:              req_sz = fd_repair_req_window_index_de             ( payload, payload_sz, &req.shred,                signature, &sender, &recipient, &timestamp, &nonce ); break;
     304           0 :     case FD_REPAIR_SERDE_TAG_HIGHEST_WINDOW_INDEX:      req_sz = fd_repair_req_highest_window_index_de     ( payload, payload_sz, &req.highest_shred,        signature, &sender, &recipient, &timestamp, &nonce ); break;
     305           0 :     case FD_REPAIR_SERDE_TAG_ORPHAN:                    req_sz = fd_repair_req_orphan_de                   ( payload, payload_sz, &req.orphan,               signature, &sender, &recipient, &timestamp, &nonce ); break;
     306           0 :     case FD_REPAIR_SERDE_TAG_PARENT_AND_FEC_SET_COUNT:  req_sz = fd_repair_req_parent_and_fec_set_count_de ( payload, payload_sz, &req.parent_fec_set_count, signature, &sender, &recipient, &timestamp, &nonce ); break;
     307           0 :     case FD_REPAIR_SERDE_TAG_FEC_SET_ROOT:              req_sz = fd_repair_req_fec_set_root_de             ( payload, payload_sz, &req.fec_set_root,         signature, &sender, &recipient, &timestamp, &nonce ); break;
     308           0 :     case FD_REPAIR_SERDE_TAG_WINDOW_INDEX_FOR_BLOCK_ID: req_sz = fd_repair_req_window_index_for_block_id_de( payload, payload_sz, &req.shred_for_block_id,   signature, &sender, &recipient, &timestamp, &nonce ); break;
     309           0 :   }
     310           0 :   if( FD_UNLIKELY( req_sz!=payload_sz ) ) {
     311           0 :     ctx->metrics->received_malformed_count[ FD_METRICS_ENUM_REQUEST_MALFORMED_REASON_V_WRONG_SIZE_IDX ]++;
     312           0 :     return;
     313           0 :   }
     314             : 
     315           0 :   ctx->metrics->received_request_count[ request_metric_index[tag] ]++;
     316           0 :   ctx->metrics->received_request_bytes += payload_sz;
     317             : 
     318           0 :   if( FD_UNLIKELY( !fd_pubkey_eq( &ctx->identity_public_key, &recipient ) ) ) {
     319           0 :     ctx->metrics->dropped[ FD_METRICS_ENUM_REQUEST_DROP_REASON_V_WRONG_RECIPIENT_IDX ]++;
     320           0 :     return;
     321           0 :   }
     322           0 :   if( FD_UNLIKELY( fd_pubkey_eq( &ctx->identity_public_key, &sender ) ) ) {
     323           0 :     ctx->metrics->dropped[ FD_METRICS_ENUM_REQUEST_DROP_REASON_V_FROM_SELF_IDX ]++;
     324           0 :     return;
     325           0 :   }
     326             : 
     327           0 :   long current = FD_NANOSEC_TO_MILLI( fd_log_wallclock() );
     328           0 :   long ts_diff = current - (long)timestamp;
     329           0 :   if( FD_UNLIKELY( ts_diff < 0L ) ) ts_diff = -ts_diff;
     330           0 :   if( FD_UNLIKELY( ts_diff > FD_RSERVE_SIGNED_REPAIR_WINDOW ) ) {
     331           0 :     ctx->metrics->dropped[ FD_METRICS_ENUM_REQUEST_DROP_REASON_V_TIMESTAMP_SKEW_IDX ]++;
     332           0 :     return;
     333           0 :   }
     334             : 
     335             :   /* Most requests are for shreds we never stored, probe before doing
     336             :      a full ed25519 verify. */
     337           0 :   if( FD_LIKELY( tag==FD_REPAIR_SERDE_TAG_WINDOW_INDEX || tag==FD_REPAIR_SERDE_TAG_HIGHEST_WINDOW_INDEX ) ) {
     338           0 :     fd_repair_shred_t const * msg = &req.shred; /* highest_shred shares its layout */
     339           0 :     if( FD_UNLIKELY( msg->shred_idx>=ctx->max_shreds_per_block ) ) {
     340           0 :       ctx->metrics->dropped[ FD_METRICS_ENUM_REQUEST_DROP_REASON_V_SHRED_INDEX_INVALID_IDX ]++;
     341           0 :       return;
     342           0 :     }
     343           0 :     if( FD_LIKELY( !fd_store_disk_probe( ctx->store, msg->slot, tag==FD_REPAIR_SERDE_TAG_WINDOW_INDEX ? (uint)msg->shred_idx : UINT_MAX ) ) ) {
     344           0 :       ctx->metrics->disk_read[ FD_METRICS_ENUM_DISK_READ_RESULT_V_MISS_IDX ]++;
     345           0 :       ctx->metrics->unanswered[ request_metric_index[tag] ]++;
     346           0 :       return;
     347           0 :     }
     348           0 :   }
     349             : 
     350             :   /* Verify the signature. */
     351             : 
     352             :   /* The signed bytes are the tag followed by everything after the
     353             :      signature. */
     354           0 :   uchar signable[ FD_REPAIR_SIG_SER_MAX ];
     355           0 :   ulong signable_sz = fd_repair_req_sig_ser( payload, payload_sz, signable );
     356             : 
     357           0 :   if( FD_UNLIKELY( FD_ED25519_SUCCESS!=fd_ed25519_verify( signable, signable_sz, signature, sender.uc, ctx->sha512 ) ) ) {
     358           0 :     ctx->metrics->dropped[ FD_METRICS_ENUM_REQUEST_DROP_REASON_V_SIGNATURE_FAILED_IDX ]++;
     359           0 :     return;
     360           0 :   }
     361             : 
     362             :   /* Check whether we've heard a pong response from this peer at this
     363             :      exact source address. Keying on (pubkey, address) means a peer that
     364             :      ponged from one address cannot have repair responses redirected to
     365             :      a spoofed source address. */
     366           0 :   ping_cache_key_t key[1];
     367           0 :   memset( key, 0, sizeof(ping_cache_key_t) );
     368           0 :   key->pubkey = sender;
     369           0 :   key->ip4    = ip4->saddr;
     370           0 :   key->port   = udp->net_sport;
     371           0 :   ping_cache_entry_t * entry = ping_map_ele_query( ctx->rserve->ping_map, key, NULL, ctx->rserve->ping_pool );
     372           0 :   if( FD_LIKELY( entry ) ) {
     373           0 :     switch( tag ) {
     374           0 :       case FD_REPAIR_SERDE_TAG_WINDOW_INDEX:
     375           0 :       case FD_REPAIR_SERDE_TAG_HIGHEST_WINDOW_INDEX: {
     376           0 :         fd_repair_shred_t const * msg = &req.shred; /* highest_shred shares its layout */
     377             : 
     378           0 :         ulong slot = msg->slot;
     379           0 :         ulong shred_idx = msg->shred_idx;
     380             : 
     381           0 :         if( FD_UNLIKELY( shred_idx>=ctx->max_shreds_per_block ) ) {
     382           0 :           ctx->metrics->dropped[ FD_METRICS_ENUM_REQUEST_DROP_REASON_V_SHRED_INDEX_INVALID_IDX ]++;
     383           0 :           return;
     384           0 :         }
     385             : 
     386           0 :         uchar payload[ FD_SHRED_MAX_SZ+sizeof(uint) ];
     387           0 :         int len;
     388           0 :         for( ulong retry=0UL;; retry++ ) {
     389           0 :           if( tag==FD_REPAIR_SERDE_TAG_WINDOW_INDEX ) {
     390           0 :             len = fd_store_disk_query( ctx->store, ctx->disk_fd, slot, (uint)shred_idx, payload );
     391           0 :           } else {
     392           0 :             len = fd_store_disk_query_highest( ctx->store, ctx->disk_fd, slot, (uint)shred_idx, payload );
     393           0 :           }
     394           0 :           if( FD_LIKELY( len!=FD_STORE_DISK_QUERY_BUSY || retry==7UL ) ) break;
     395           0 :           for( ulong pause=0UL; pause<(1UL<<retry); pause++ ) FD_SPIN_PAUSE();
     396           0 :         }
     397           0 :         if( FD_UNLIKELY( len<0 ) ) {
     398           0 :           if(      len==FD_STORE_DISK_QUERY_BUSY      ) ctx->metrics->disk_read[ FD_METRICS_ENUM_DISK_READ_RESULT_V_BUSY_IDX ]++;
     399           0 :           else if( len==FD_STORE_DISK_QUERY_SCAN_LIMIT) ctx->metrics->disk_read[ FD_METRICS_ENUM_DISK_READ_RESULT_V_SCAN_LIMIT_IDX ]++;
     400           0 :           else                                          ctx->metrics->disk_read[ FD_METRICS_ENUM_DISK_READ_RESULT_V_MISS_IDX ]++;
     401           0 :           ctx->metrics->unanswered[ request_metric_index[tag] ]++;
     402           0 :           return;
     403           0 :         }
     404           0 :         ctx->metrics->disk_read[ FD_METRICS_ENUM_DISK_READ_RESULT_V_SUCCESS_IDX ]++;
     405           0 :         ctx->metrics->disk_read_bytes += (ulong)len;
     406             : 
     407           0 :         fd_memcpy( payload+len, &nonce, sizeof(uint) );
     408           0 :         send_packet( ctx, stem, ip4->saddr, udp->net_sport, ip4->daddr, payload, (ulong)len+sizeof(uint), fd_frag_meta_ts_comp( fd_tickcount() ) );
     409           0 :         ctx->metrics->sent_pkt_types[ response_metric_index[tag] ]++;
     410           0 :         return;
     411           0 :       }
     412           0 :       case FD_REPAIR_SERDE_TAG_ORPHAN: {
     413             :         /* Orphan repair works by giving us a "root" slot to start at,
     414             :            and has us walk back through the parent slots sending the
     415             :            highest shred of each slot.
     416             :            We may send up to FD_RSERVE_MAX_ORPHAN_SLOTS of these shreds
     417             :            (including the root one). */
     418           0 :         fd_repair_orphan_t const * msg = &req.orphan;
     419             : 
     420           0 :         ulong current = msg->slot;
     421           0 :         for( uint i=0; i<FD_RSERVE_MAX_ORPHAN_SLOTS; i++ ) {
     422           0 :           uchar payload[ FD_SHRED_MAX_SZ+sizeof(uint) ];
     423           0 :           int len;
     424           0 :           for( ulong retry=0UL;; retry++ ) {
     425           0 :             len = fd_store_disk_query_highest( ctx->store, ctx->disk_fd, current, 0, payload );
     426           0 :             if( FD_LIKELY( len!=FD_STORE_DISK_QUERY_BUSY || retry==7UL ) ) break;
     427           0 :             for( ulong pause=0UL; pause<(1UL<<retry); pause++ ) FD_SPIN_PAUSE();
     428           0 :           }
     429           0 :           if( FD_UNLIKELY( len<0 ) ) {
     430           0 :             if(      len==FD_STORE_DISK_QUERY_BUSY      ) ctx->metrics->disk_read[ FD_METRICS_ENUM_DISK_READ_RESULT_V_BUSY_IDX ]++;
     431           0 :             else if( len==FD_STORE_DISK_QUERY_SCAN_LIMIT) ctx->metrics->disk_read[ FD_METRICS_ENUM_DISK_READ_RESULT_V_SCAN_LIMIT_IDX ]++;
     432           0 :             else                                          ctx->metrics->disk_read[ FD_METRICS_ENUM_DISK_READ_RESULT_V_MISS_IDX ]++;
     433           0 :             ctx->metrics->unanswered[ FD_METRICS_ENUM_REPAIR_REQUEST_TYPE_V_ORPHAN_IDX ]++;
     434           0 :             return;
     435           0 :           }
     436           0 :           ctx->metrics->disk_read[ FD_METRICS_ENUM_DISK_READ_RESULT_V_SUCCESS_IDX ]++;
     437           0 :           ctx->metrics->disk_read_bytes += (ulong)len;
     438           0 :           fd_shred_t const * shred = (fd_shred_t const *)fd_type_pun_const( payload );
     439           0 :           memcpy( payload+len, &nonce, sizeof(uint) );
     440           0 :           send_packet( ctx, stem, ip4->saddr, udp->net_sport, ip4->daddr, payload, (ulong)len+sizeof(uint), fd_frag_meta_ts_comp( fd_tickcount() ) );
     441           0 :           ctx->metrics->sent_pkt_types[ FD_METRICS_ENUM_REPAIR_RESPONSE_TYPE_V_ORPHAN_IDX ]++;
     442           0 :           ushort parent_off = shred->data.parent_off;
     443             :           /* fd_shred_parse ensures that parent_off will be 0 if and only if slot is 0 */
     444           0 :           if( FD_UNLIKELY( parent_off==0 ) ) break;
     445           0 :           current = current - parent_off;
     446           0 :         }
     447           0 :         break;
     448           0 :       }
     449           0 :       case FD_REPAIR_SERDE_TAG_PARENT_AND_FEC_SET_COUNT: {
     450             :         /* Serves the block's parent, FEC set count, and the proof of its
     451             :            parent-info leaf, which follows the fec_set_cnt FEC root leaves. */
     452           0 :         fd_repair_parent_fec_set_count_t const * msg = &req.parent_fec_set_count;
     453             : 
     454           0 :         fd_blockdb_blk_t const * blk = fd_blockdb_query( ctx->blockdb, msg->slot, &msg->block_id );
     455           0 :         if( FD_UNLIKELY( !blk ) ) {
     456           0 :           ctx->metrics->unanswered[ request_metric_index[tag] ]++;
     457           0 :           return;
     458           0 :         }
     459             : 
     460           0 :         uchar proof[ FD_BLOCKDB_PROOF_NODE_MAX*FD_SHRED_MERKLE_NODE_SZ ];
     461           0 :         int proof_len = fd_blockdb_proof( ctx->blockdb, blk, blk->fec_set_cnt, proof );
     462           0 :         FD_TEST( proof_len>=0 );
     463             : 
     464           0 :         uchar buf[ FD_REPAIR_RES_DE_MAX ];
     465           0 :         ulong sz = fd_repair_res_parent_fec_set_count_ser( blk->fec_set_cnt, blk->parent_slot, &blk->parent_block_id,
     466           0 :                                                            proof, (ulong)proof_len*FD_SHRED_MERKLE_NODE_SZ, nonce, buf, sizeof(buf) );
     467           0 :         FD_TEST( sz );
     468             : 
     469           0 :         send_packet( ctx, stem, ip4->saddr, udp->net_sport, ip4->daddr, buf, sz, fd_frag_meta_ts_comp( fd_tickcount() ) );
     470           0 :         ctx->metrics->sent_pkt_types[ response_metric_index[tag] ]++;
     471           0 :         return;
     472           0 :       }
     473           0 :       case FD_REPAIR_SERDE_TAG_FEC_SET_ROOT: {
     474             :         /* Serves the merkle root prefix of FEC set fec_set_idx and the
     475             :            proof of its leaf. */
     476           0 :         fd_repair_fec_set_root_t const * msg = &req.fec_set_root;
     477             : 
     478           0 :         fd_blockdb_blk_t const * blk = fd_blockdb_query( ctx->blockdb, msg->slot, &msg->block_id );
     479           0 :         if( FD_UNLIKELY( !blk ) ) {
     480           0 :           ctx->metrics->unanswered[ request_metric_index[tag] ]++;
     481           0 :           return;
     482           0 :         }
     483           0 :         if( FD_UNLIKELY( msg->fec_set_idx%FD_FEC_SHRED_CNT || msg->fec_set_idx/FD_FEC_SHRED_CNT>=blk->fec_set_cnt ) ) {
     484           0 :           ctx->metrics->dropped[ FD_METRICS_ENUM_REQUEST_DROP_REASON_V_FEC_SET_INDEX_INVALID_IDX ]++;
     485           0 :           return;
     486           0 :         }
     487           0 :         ulong leaf_idx = msg->fec_set_idx/FD_FEC_SHRED_CNT;
     488             : 
     489           0 :         uchar proof[ FD_BLOCKDB_PROOF_NODE_MAX*FD_SHRED_MERKLE_NODE_SZ ];
     490           0 :         int proof_len = fd_blockdb_proof( ctx->blockdb, blk, leaf_idx, proof );
     491           0 :         FD_TEST( proof_len>=0 );
     492             : 
     493           0 :         uchar buf[ FD_REPAIR_RES_DE_MAX ];
     494           0 :         ulong sz = fd_repair_res_fec_set_root_ser( blk->merkle_roots[ leaf_idx ], proof, (ulong)proof_len*FD_SHRED_MERKLE_NODE_SZ, nonce, buf, sizeof(buf) );
     495           0 :         FD_TEST( sz );
     496             : 
     497           0 :         send_packet( ctx, stem, ip4->saddr, udp->net_sport, ip4->daddr, buf, sz, fd_frag_meta_ts_comp( fd_tickcount() ) );
     498           0 :         ctx->metrics->sent_pkt_types[ response_metric_index[tag] ]++;
     499           0 :         return;
     500           0 :       }
     501           0 :       case FD_REPAIR_SERDE_TAG_WINDOW_INDEX_FOR_BLOCK_ID: {
     502             :         /* Serves the data shred at shred_idx of block (slot, block_id),
     503             :            found by its FEC set's merkle root. */
     504           0 :         fd_repair_shred_for_block_id_t const * msg = &req.shred_for_block_id;
     505             : 
     506           0 :         fd_blockdb_blk_t const * blk = fd_blockdb_query( ctx->blockdb, msg->slot, &msg->block_id );
     507           0 :         if( FD_UNLIKELY( !blk ) ) {
     508           0 :           ctx->metrics->unanswered[ request_metric_index[tag] ]++;
     509           0 :           return;
     510           0 :         }
     511           0 :         if( FD_UNLIKELY( (ulong)msg->shred_idx>=(ulong)blk->fec_set_cnt*FD_FEC_SHRED_CNT ) ) {
     512           0 :           ctx->metrics->dropped[ FD_METRICS_ENUM_REQUEST_DROP_REASON_V_SHRED_INDEX_INVALID_IDX ]++;
     513           0 :           return;
     514           0 :         }
     515             : 
     516           0 :         uchar const * root = blk->merkle_roots[ msg->shred_idx/FD_FEC_SHRED_CNT ];
     517           0 :         uchar payload[ FD_SHRED_MAX_SZ+sizeof(uint) ];
     518           0 :         int len;
     519           0 :         for( ulong retry=0UL;; retry++ ) {
     520           0 :           len = fd_store_disk_query_root( ctx->store, ctx->disk_fd, root, msg->shred_idx, payload );
     521           0 :           if( FD_LIKELY( len!=FD_STORE_DISK_QUERY_BUSY || retry==7UL ) ) break;
     522           0 :           for( ulong pause=0UL; pause<(1UL<<retry); pause++ ) FD_SPIN_PAUSE();
     523           0 :         }
     524           0 :         if( FD_UNLIKELY( len<0 ) ) {
     525           0 :           if( len==FD_STORE_DISK_QUERY_BUSY ) ctx->metrics->disk_read[ FD_METRICS_ENUM_DISK_READ_RESULT_V_BUSY_IDX ]++;
     526           0 :           else                                ctx->metrics->disk_read[ FD_METRICS_ENUM_DISK_READ_RESULT_V_MISS_IDX ]++;
     527           0 :           ctx->metrics->unanswered[ request_metric_index[tag] ]++;
     528           0 :           return;
     529           0 :         }
     530           0 :         ctx->metrics->disk_read[ FD_METRICS_ENUM_DISK_READ_RESULT_V_SUCCESS_IDX ]++;
     531           0 :         ctx->metrics->disk_read_bytes += (ulong)len;
     532             : 
     533           0 :         memcpy( payload+len, &nonce, sizeof(uint) );
     534           0 :         send_packet( ctx, stem, ip4->saddr, udp->net_sport, ip4->daddr, payload, (ulong)len+sizeof(uint), fd_frag_meta_ts_comp( fd_tickcount() ) );
     535           0 :         ctx->metrics->sent_pkt_types[ response_metric_index[tag] ]++;
     536           0 :         return;
     537           0 :       }
     538           0 :     }
     539           0 :   } else {
     540             :         /* Derive a ping token bound to this peer's pubkey and the source
     541             :        address the request arrived from.  The peer can only produce a
     542             :        valid pong if it actually receives this ping at that address. */
     543           0 :     uchar token[ 32UL ];
     544           0 :     fd_rserve_ping_token( ctx->rserve, token, &sender, ip4->saddr, udp->net_sport );
     545             : 
     546             :     /* Sign the token. */
     547           0 :     fd_ed25519_sig_t ping_sig;
     548           0 :     fd_keyguard_client_sign( ctx->keyguard_client, ping_sig, token, 32UL, FD_KEYGUARD_SIGN_TYPE_ED25519 );
     549             : 
     550             :     /* Like Agave, block id metadata requests are answered with the
     551             :        BlockIdRepairResponse ping variant, and ShredForBlockId, like the
     552             :        legacy requests, with the RepairResponse one. */
     553           0 :     uchar buf[ FD_REPAIR_PING_DE_SZ ];
     554           0 :     ulong sz;
     555           0 :     if( tag==FD_REPAIR_SERDE_TAG_PARENT_AND_FEC_SET_COUNT || tag==FD_REPAIR_SERDE_TAG_FEC_SET_ROOT ) sz = fd_repair_block_id_ping_ser( &ctx->identity_public_key, (fd_hash_t const *)token, ping_sig, buf );
     556           0 :     else                                                                                            sz = fd_repair_ping_ser         ( &ctx->identity_public_key, (fd_hash_t const *)token, ping_sig, buf );
     557             : 
     558             :     /* Send the ping packet back to the source. */
     559           0 :     send_packet( ctx, stem, ip4->saddr, udp->net_sport, ip4->daddr, buf, sz, fd_frag_meta_ts_comp( fd_tickcount() ) );
     560           0 :     ctx->metrics->sent_pkt_types[ FD_METRICS_ENUM_REPAIR_RESPONSE_TYPE_V_PING_IDX ]++;
     561           0 :   }
     562           0 : }
     563             : 
     564             : 
     565             : static inline int
     566             : before_frag( ctx_t * ctx,
     567             :              ulong   in_idx,
     568             :              ulong   seq FD_PARAM_UNUSED,
     569           0 :              ulong   sig ) {
     570           0 :   if( FD_LIKELY( ctx->in_kind[ in_idx ]==IN_KIND_NET ) ) return fd_disco_netmux_sig_proto( sig )!=DST_PROTO_RSERVE;
     571           0 :   return 0;
     572           0 : }
     573             : 
     574             : static inline void
     575             : during_frag( ctx_t * ctx,
     576             :              ulong   in_idx,
     577             :              ulong   seq FD_PARAM_UNUSED,
     578             :              ulong   sig,
     579             :              ulong   chunk,
     580             :              ulong   sz,
     581           0 :              ulong   ctl ) {
     582           0 :   in_ctx_t const * in_ctx = &ctx->in_links[ in_idx ];
     583           0 :   switch( ctx->in_kind[ in_idx ] ) {
     584           0 :   case IN_KIND_NET: {
     585           0 :     uchar const * buffer = fd_net_rx_translate_frag( &in_ctx->net_rx, chunk, ctl, sz );
     586           0 :     fd_memcpy( ctx->net_buf, buffer, sz );
     587           0 :     break;
     588           0 :   }
     589           0 :   case IN_KIND_REPAIR: {
     590           0 :     if( FD_UNLIKELY( sig!=REPAIR_SIG_BLK ) ) break;
     591           0 :     if( FD_UNLIKELY( sz<offsetof(fd_repair_out_blk_t, merkle_roots) || sz>sizeof(fd_repair_out_blk_t) || chunk<in_ctx->chunk0 || chunk>in_ctx->wmark ) )
     592           0 :       FD_LOG_ERR(( "repair_rserve chunk %lu %lu corrupt, not in range [%lu,%lu]", chunk, sz, in_ctx->chunk0, in_ctx->wmark ));
     593           0 :     fd_memcpy( ctx->repair_buf, fd_chunk_to_laddr_const( in_ctx->mem, chunk ), sz );
     594           0 :     break;
     595           0 :   }
     596           0 :   default: break;
     597           0 :   }
     598           0 : }
     599             : 
     600             : static inline void
     601             : after_frag( ctx_t *             ctx,
     602             :             ulong               in_idx,
     603             :             ulong               seq    FD_PARAM_UNUSED,
     604             :             ulong               sig,
     605             :             ulong               sz,
     606             :             ulong               tsorig FD_PARAM_UNUSED,
     607             :             ulong               tspub  FD_PARAM_UNUSED,
     608           0 :             fd_stem_context_t * stem ) {
     609           0 :   uint in_kind = ctx->in_kind[ in_idx ];
     610           0 :   if( FD_UNLIKELY( in_kind==IN_KIND_REPAIR ) ) {
     611           0 :     if( FD_UNLIKELY( sig!=REPAIR_SIG_BLK ) ) return;
     612           0 :     fd_repair_out_blk_t const * msg = ctx->repair_buf;
     613           0 :     if( FD_UNLIKELY( sz!=offsetof(fd_repair_out_blk_t, merkle_roots) + (ulong)msg->fec_set_cnt*FD_SHRED_MERKLE_NODE_SZ ) )
     614           0 :       FD_LOG_ERR(( "repair_rserve frag sz %lu does not match fec_set_cnt %u", sz, msg->fec_set_cnt ));
     615           0 :     FD_TEST( fd_blockdb_insert( ctx->blockdb, msg->slot, &msg->block_id, msg->parent_slot, &msg->parent_block_id,
     616           0 :                                 msg->fec_set_cnt, (uchar const *)msg->merkle_roots ) );
     617           0 :     return;
     618           0 :   }
     619           0 :   if( FD_LIKELY( in_kind!=IN_KIND_NET ) ) return; /* returnable_frag */
     620             : 
     621           0 :   uchar * payload; ulong payload_sz;
     622           0 :   fd_udp_hdr_t * udp;
     623           0 :   fd_ip4_hdr_t * ip4;
     624           0 :   if( FD_UNLIKELY( !fd_ip4_udp_hdr_strip( ctx->net_buf, sz, &payload, &payload_sz, NULL, &ip4, &udp ) ) ) {
     625           0 :     FD_LOG_WARNING(( "rserve: malformed packet (sz=%lu)", sz ));
     626           0 :     return;
     627           0 :   }
     628           0 :   handle_net_request( ctx, stem, payload, payload_sz, udp, ip4 );
     629           0 : }
     630             : 
     631             : static inline int
     632             : returnable_frag( ctx_t             * ctx,
     633             :                  ulong               in_idx,
     634             :                  ulong               seq FD_PARAM_UNUSED,
     635             :                  ulong               sig,
     636             :                  ulong               chunk,
     637             :                  ulong               sz,
     638             :                  ulong               ctl FD_PARAM_UNUSED,
     639             :                  ulong               tsorig FD_PARAM_UNUSED,
     640             :                  ulong               tspub FD_PARAM_UNUSED,
     641           0 :                  fd_stem_context_t * stem FD_PARAM_UNUSED ) {
     642           0 :   uint in_kind = ctx->in_kind[ in_idx ];
     643           0 :   in_ctx_t const * in_ctx = &ctx->in_links[ in_idx ];
     644             : 
     645           0 :   switch( in_kind ) {
     646           0 :   case IN_KIND_NET:
     647           0 :     return ctx->halt_signing; /* after_frag */
     648           0 :   case IN_KIND_SIGN: return 0; /* handled internally by keyguard_client */
     649           0 :   case IN_KIND_SHRED: {
     650           0 :     int shred_result = fd_shred_sig_res( sig );
     651           0 :     if( FD_UNLIKELY( fd_shred_sig_src( sig )>SHRED_SIG_SRC_BAD_REPAIR ||
     652           0 :                      (shred_result!=SHRED_SIG_RESULT_OKAY && shred_result!=SHRED_SIG_RESULT_COMPLETES) ) ) return 0;
     653           0 :     if( FD_UNLIKELY( sz!=sizeof(fd_shred_base_t) || chunk<in_ctx->chunk0 || chunk>in_ctx->wmark ) )
     654           0 :       FD_LOG_ERR(( "shred_out chunk %lu %lu corrupt, not in range [%lu,%lu]", chunk, sz, in_ctx->chunk0, in_ctx->wmark ));
     655             : 
     656           0 :     fd_shred_base_t const * msg   = fd_chunk_to_laddr_const( in_ctx->mem, chunk );
     657           0 :     fd_shred_t const *      shred = &msg->shred;
     658           0 :     if( FD_UNLIKELY( !fd_shred_is_data( fd_shred_type( shred->variant ) ) ) ) return 0;
     659             : 
     660           0 :     long dt = -fd_tickcount();
     661           0 :     int result = fd_store_disk_insert( ctx->store, ctx->disk_fd, shred, &msg->merkle_root );
     662           0 :     dt += fd_tickcount();
     663           0 :     fd_histf_sample( ctx->metrics->disk_write_timing, (ulong)dt );
     664           0 :     if( FD_LIKELY( result==FD_STORE_DISK_INSERT_SUCCESS ) ) {
     665           0 :       ctx->metrics->disk_inserted++;
     666           0 :       ctx->metrics->disk_write_bytes += sizeof(fd_shredb_entry_t);
     667           0 :     } else if( FD_UNLIKELY( result==FD_STORE_DISK_INSERT_ERR ) ) ctx->metrics->disk_write_failed++;
     668           0 :     return 0;
     669           0 :   }
     670           0 :   case IN_KIND_REPAIR: return 0; /* after_frag */
     671           0 :   default: FD_LOG_ERR(( "unexpected input kind (%u)", in_kind ));
     672           0 :   }
     673           0 : }
     674             : 
     675             : static inline void
     676             : before_credit( ctx_t             * ctx,
     677             :                fd_stem_context_t * stem FD_PARAM_UNUSED,
     678           0 :                int               * charge_busy ) {
     679           0 :   fd_store_fec_spill_stats_t spill[1];
     680           0 :   if( FD_UNLIKELY( fd_store_fec_data_preevict( ctx->store, ctx->disk_fd, spill ) ) ) {
     681           0 :     fd_histf_sample( ctx->metrics->fec_preevict_timing, spill->write_ticks );
     682           0 :     ctx->metrics->fec_preevict_write_cnt   += spill->write_cnt;
     683           0 :     ctx->metrics->fec_preevict_write_bytes += spill->write_bytes;
     684           0 :     *charge_busy = 1;
     685           0 :   }
     686           0 : }
     687             : 
     688             : static inline void
     689           0 : during_housekeeping( ctx_t * ctx ) {
     690           0 :   if( FD_UNLIKELY( fd_keyswitch_state_query( ctx->keyswitch )==FD_KEYSWITCH_STATE_UNHALT_PENDING ) ) {
     691           0 :     FD_LOG_DEBUG(( "keyswitch: unhalting" ));
     692           0 :     FD_DCHECK_CRIT( ctx->halt_signing, "state machine corruption" );
     693           0 :     fd_memcpy( ctx->identity_public_key.uc, ctx->keyswitch->bytes, sizeof(fd_pubkey_t) );
     694           0 :     ctx->halt_signing = 0;
     695           0 :     fd_keyswitch_state( ctx->keyswitch, FD_KEYSWITCH_STATE_COMPLETED );
     696           0 :   }
     697             : 
     698           0 :   if( FD_UNLIKELY( fd_keyswitch_state_query( ctx->keyswitch )==FD_KEYSWITCH_STATE_SWITCH_PENDING ) ) {
     699           0 :     ctx->halt_signing = 1;
     700           0 :     fd_keyswitch_state( ctx->keyswitch, FD_KEYSWITCH_STATE_COMPLETED );
     701           0 :   }
     702             : 
     703           0 :   fd_rserve_t * rserve = ctx->rserve;
     704           0 :   ulong now_ns = (ulong)fd_log_wallclock();
     705           0 :   fd_rserve_maybe_rotate( rserve, now_ns );
     706             : 
     707             :   /* Evict expired entries from the head (oldest) of the LRU list. */
     708           0 :   while( !ping_dlist_is_empty( rserve->ping_dlist, rserve->ping_pool ) ) {
     709           0 :     ping_cache_entry_t * head = ping_dlist_ele_peek_head( rserve->ping_dlist, rserve->ping_pool );
     710           0 :     if( FD_LIKELY( now_ns-head->timestamp <= FD_RSERVE_PING_CACHE_TTL_NS ) ) break;
     711           0 :     ping_dlist_ele_pop_head( rserve->ping_dlist, rserve->ping_pool );
     712           0 :     ping_map_ele_remove_fast( rserve->ping_map, head, rserve->ping_pool );
     713           0 :     ping_pool_ele_release( rserve->ping_pool, head );
     714           0 :     ctx->metrics->ping_cache_entries--;
     715           0 :   }
     716           0 : }
     717             : 
     718             : static inline void
     719           0 : metrics_write( ctx_t * ctx ) {
     720           0 :   fd_store_fec_cache_stats_t cache_stats[1] = {{0}};
     721           0 :   if( FD_LIKELY( ctx->store ) ) {
     722           0 :     fd_store_disk_stats_t stats[1];
     723           0 :     if( FD_LIKELY( !fd_store_disk_stats_query( ctx->store, stats ) ) ) {
     724           0 :       ctx->metrics->shreds_current           = stats->shred_cnt;
     725           0 :       ctx->metrics->disk_current_bytes       = stats->current_bytes;
     726           0 :       ctx->metrics->disk_allocated_bytes     = stats->allocated_bytes;
     727           0 :     }
     728           0 :     fd_store_fec_cache_stats_query( ctx->store, cache_stats );
     729           0 :   }
     730             : 
     731           0 :   FD_MCNT_ENUM_COPY( RSERVE, REQUEST_RX,                         ctx->metrics->received_request_count   );
     732           0 :   FD_MCNT_SET      ( RSERVE, REQUEST_RX_BYTES,                   ctx->metrics->received_request_bytes   );
     733           0 :   FD_MCNT_ENUM_COPY( RSERVE, REQUEST_MALFORMED,                  ctx->metrics->received_malformed_count );
     734           0 :   FD_MCNT_ENUM_COPY( RSERVE, REQUEST_DROPPED,                    ctx->metrics->dropped                  );
     735           0 :   FD_MCNT_ENUM_COPY( RSERVE, REQUEST_UNANSWERED,                 ctx->metrics->unanswered               );
     736             : 
     737           0 :   FD_MCNT_SET      ( RSERVE, PKT_TX,                             ctx->metrics->send_pkt_cnt             );
     738           0 :   FD_MCNT_ENUM_COPY( RSERVE, RESPONSE_TX,                        ctx->metrics->sent_pkt_types           );
     739           0 :   FD_MCNT_SET      ( RSERVE, RESPONSE_TX_BYTES,                  ctx->metrics->sent_response_bytes      );
     740             : 
     741           0 :   FD_MCNT_ENUM_COPY( RSERVE, DISK_READ_ATTEMPTED,                ctx->metrics->disk_read                );
     742           0 :   FD_MCNT_SET      ( RSERVE, DISK_READ_BYTES,                    ctx->metrics->disk_read_bytes          );
     743           0 :   FD_MGAUGE_SET    ( RSERVE, SHRED_USED,                         ctx->metrics->shreds_current           );
     744           0 :   FD_MGAUGE_SET    ( RSERVE, DISK_USED_BYTES,                    ctx->metrics->disk_current_bytes       );
     745           0 :   FD_MGAUGE_SET    ( RSERVE, DISK_PEAK_BYTES,                    ctx->metrics->disk_allocated_bytes     );
     746           0 :   FD_MHIST_COPY    ( RSERVE, DISK_WRITE_DURATION_NANOS,          ctx->metrics->disk_write_timing        );
     747           0 :   FD_MCNT_SET      ( RSERVE, DISK_SHRED_WRITTEN,                 ctx->metrics->disk_inserted            );
     748           0 :   FD_MCNT_SET      ( RSERVE, DISK_SHRED_WRITE_FAILED,            ctx->metrics->disk_write_failed        );
     749           0 :   FD_MCNT_SET      ( RSERVE, DISK_SHRED_WRITTEN_BYTES,           ctx->metrics->disk_write_bytes         );
     750           0 :   FD_MHIST_COPY    ( RSERVE, STORE_FEC_PREEVICT_DURATION_NANOS,  ctx->metrics->fec_preevict_timing      );
     751           0 :   FD_MCNT_SET      ( RSERVE, STORE_FEC_PREEVICTED,               ctx->metrics->fec_preevict_write_cnt   );
     752           0 :   FD_MCNT_SET      ( RSERVE, STORE_FEC_PREEVICTED_BYTES,         ctx->metrics->fec_preevict_write_bytes );
     753           0 :   FD_MGAUGE_SET    ( RSERVE, STORE_FEC_CACHE_FREE,               cache_stats->free_cnt                  );
     754           0 :   FD_MGAUGE_SET    ( RSERVE, STORE_FEC_CACHE_CAPACITY,           cache_stats->max                       );
     755           0 :   FD_MGAUGE_SET    ( RSERVE, STORE_FEC_CACHE_FREE_TARGET,        cache_stats->target                    );
     756           0 :   FD_MGAUGE_SET    ( RSERVE, STORE_FEC_CACHE_FREE_LOW_WATER,     cache_stats->low_water                 );
     757             : 
     758           0 :   FD_MGAUGE_SET    ( RSERVE, PING_CACHE_USED,                    ctx->metrics->ping_cache_entries       );
     759           0 :   FD_MGAUGE_SET    ( RSERVE, PING_CACHE_CAPACITY,                ctx->metrics->ping_cache_capacity      );
     760           0 :   FD_MCNT_SET      ( RSERVE, PING_CACHE_EVICTED,                 ctx->metrics->ping_cache_evictions     );
     761           0 : }
     762             : 
     763             : static void
     764             : privileged_init( fd_topo_t      const * topo,
     765           0 :                  fd_topo_tile_t const * tile ) {
     766           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     767             : 
     768           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     769           0 :   ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(ctx_t), sizeof(ctx_t) );
     770             : 
     771           0 :   FD_TEST( fd_rng_secure( &ctx->seed, sizeof(ulong) ) );
     772           0 :   FD_TEST( fd_rng_secure( ctx->rserve_secret, sizeof(ctx->rserve_secret) ) );
     773             : 
     774           0 :   ctx->disk_fd = -1;
     775           0 :   ulong store_obj_id = fd_pod_queryf_ulong( topo->props, ULONG_MAX, "store" );
     776           0 :   if( FD_LIKELY( store_obj_id!=ULONG_MAX ) ) {
     777           0 :     fd_store_t * store = fd_store_join( fd_topo_obj_laddr( topo, store_obj_id ) );
     778           0 :     FD_TEST( store );
     779           0 :     ctx->disk_fd = FD_STORE_FD_RW;
     780           0 :     if( FD_UNLIKELY( fcntl( ctx->disk_fd, F_GETFD )<0 ) )
     781           0 :       FD_LOG_ERR(( "store file descriptor was not inherited (%i-%s)", errno, fd_io_strerror( errno ) ));
     782           0 :   }
     783             : 
     784           0 :   uchar const * identity_public_key = fd_keyload_load( tile->rserve.identity_key_path, /* pubkey only: */ 1 );
     785           0 :   fd_memcpy( ctx->identity_public_key.uc, identity_public_key, sizeof(fd_pubkey_t) );
     786           0 : }
     787             : 
     788             : static void
     789             : unprivileged_init( fd_topo_t      const * topo,
     790           0 :                    fd_topo_tile_t const * tile ) {
     791           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     792             : 
     793           0 :   ulong ping_cache_entries = tile->rserve.ping_cache_entries;
     794             : 
     795           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     796           0 :   ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(ctx_t), sizeof(ctx_t) );
     797           0 :   ctx->rserve = FD_SCRATCH_ALLOC_APPEND( l, fd_rserve_align(), fd_rserve_footprint( ping_cache_entries ) );
     798           0 :   void * blockdb_mem = NULL;
     799           0 :   if( FD_LIKELY( tile->rserve.blockdb_max ) ) {
     800           0 :     blockdb_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_blockdb_align(), fd_blockdb_footprint( tile->rserve.blockdb_max ) );
     801           0 :   }
     802           0 :   FD_TEST( FD_SCRATCH_ALLOC_FINI( l, scratch_align() )==(ulong)scratch + scratch_footprint( tile ) );
     803             : 
     804           0 :   ctx->blockdb = NULL;
     805           0 :   if( FD_LIKELY( blockdb_mem ) ) {
     806           0 :     ctx->blockdb = fd_blockdb_join( fd_blockdb_new( blockdb_mem, tile->rserve.blockdb_max, ctx->seed ) );
     807           0 :     FD_TEST( ctx->blockdb );
     808           0 :   }
     809             : 
     810           0 :   ctx->store = NULL;
     811           0 :   ulong store_obj_id = fd_pod_queryf_ulong( topo->props, ULONG_MAX, "store" );
     812           0 :   if( FD_LIKELY( store_obj_id!=ULONG_MAX ) ) {
     813           0 :     ctx->store = fd_store_join( fd_topo_obj_laddr( topo, store_obj_id ) );
     814           0 :     FD_TEST( ctx->store );
     815           0 :   }
     816           0 :   if( FD_UNLIKELY( !ctx->store || !fd_store_has_disk( ctx->store ) ) ) {
     817           0 :     FD_LOG_ERR(( "rserve requires an enabled store disk layer" ));
     818           0 :   }
     819           0 :   if( FD_UNLIKELY( ctx->disk_fd<0 ) ) {
     820           0 :     FD_LOG_ERR(( "rserve could not open the store disk file" ));
     821           0 :   }
     822             : 
     823           0 :   ctx->max_shreds_per_block = tile->rserve.max_shreds_per_block;
     824           0 :   ctx->rserve    = fd_rserve_join   ( fd_rserve_new( ctx->rserve, ping_cache_entries, ctx->seed, ctx->rserve_secret ) );
     825           0 :   ctx->keyswitch = fd_keyswitch_join( fd_topo_obj_laddr( topo, tile->id_keyswitch_obj_id ) );
     826           0 :   FD_TEST( ctx->keyswitch );
     827             : 
     828           0 :   fd_memset( ctx->metrics, 0, sizeof(ctx->metrics) );
     829           0 :   ctx->metrics->ping_cache_capacity = fd_ulong_pow2_up( ping_cache_entries );
     830           0 :   fd_histf_join( fd_metrics_histf_new_ns( ctx->metrics->disk_write_timing, FD_MHIST_EDGES_NS( RSERVE, DISK_WRITE_DURATION_NANOS ) ) );
     831           0 :   fd_histf_join( fd_metrics_histf_new_ns( ctx->metrics->fec_preevict_timing, FD_MHIST_EDGES_NS( RSERVE, STORE_FEC_PREEVICT_DURATION_NANOS ) ) );
     832           0 :   FD_MGAUGE_SET( RSERVE, SHRED_CAPACITY, ctx->store ? ctx->store->disk_max_shreds : 0UL );
     833             : 
     834           0 :   ctx->halt_signing = 0;
     835           0 :   ctx->net_id = (ushort)0;
     836           0 :   fd_ip4_udp_hdr_init( ctx->serve_hdr, FD_RSERVE_MAX_PACKET_SIZE, 0, tile->rserve.repair_serve_listen_port );
     837           0 :   fd_sha512_new( ctx->sha512 );
     838             : 
     839           0 :   ulong sign_in_idx  = fd_topo_find_tile_in_link ( topo, tile, "sign_rserve", tile->kind_id );
     840           0 :   ulong sign_out_idx = fd_topo_find_tile_out_link( topo, tile, "rserve_sign", tile->kind_id );
     841           0 :   FD_TEST( sign_in_idx!=ULONG_MAX );
     842           0 :   fd_topo_link_t const * sign_in = &topo->links[ tile->in_link_id[ sign_in_idx ] ];
     843           0 :   fd_topo_link_t const * sign_out = &topo->links[ tile->out_link_id[ sign_out_idx ] ];
     844             : 
     845           0 :   fd_sleep_t * sleep = NULL;
     846           0 :   if( FD_UNLIKELY( topo->sleep_obj_id!=ULONG_MAX ) ) {
     847           0 :     sleep = fd_sleep_join( fd_topo_obj_laddr( topo, topo->sleep_obj_id ) );
     848           0 :     FD_TEST( sleep );
     849           0 :   }
     850             : 
     851           0 :   if( FD_UNLIKELY( !fd_keyguard_client_join( fd_keyguard_client_new( ctx->keyguard_client,
     852           0 :           sign_out->mcache,
     853           0 :           sign_out->dcache,
     854           0 :           sign_in->mcache,
     855           0 :           sign_in->dcache,
     856           0 :           sign_out->mtu,
     857           0 :           sign_in->mtu,
     858           0 :           sleep,
     859           0 :           sign_out->id,
     860           0 :           fd_topo_find_link_consumer( topo, sign_out ) ) ) ) ) {
     861           0 :     FD_LOG_ERR(( "failed to construct keyguard" ));
     862           0 :   }
     863             : 
     864           0 :   FD_TEST( tile->in_cnt>=1UL );
     865           0 :   FD_CHECK_ERR( tile->in_cnt<=MAX_IN_LINKS, "too many input links" );
     866           0 :   for( ulong in_idx=0UL; in_idx<tile->in_cnt; in_idx++ ) {
     867           0 :     fd_topo_link_t const * link = &topo->links[ tile->in_link_id[ in_idx ] ];
     868           0 :     if( 0==strcmp( link->name, "net_rserve" ) ) {
     869           0 :       ctx->in_kind[ in_idx ] = IN_KIND_NET;
     870           0 :       fd_net_rx_bounds_init( &ctx->in_links[ in_idx ].net_rx, link->dcache );
     871           0 :       continue;
     872           0 :     }
     873           0 :     else if( 0==strcmp( link->name, "sign_rserve" ) ) ctx->in_kind[ in_idx ] = IN_KIND_SIGN;
     874           0 :     else if( 0==strcmp( link->name, "shred_out" ) )   ctx->in_kind[ in_idx ] = IN_KIND_SHRED;
     875           0 :     else if( 0==strcmp( link->name, "repair_rserve" ) ) {
     876           0 :       if( FD_UNLIKELY( !ctx->blockdb ) ) FD_LOG_ERR(( "rserve has a repair_rserve link but blockdb_max is 0" ));
     877           0 :       ctx->in_kind[ in_idx ] = IN_KIND_REPAIR;
     878           0 :     }
     879           0 :     else FD_LOG_ERR(( "rserve tile has unexpected input link: %s", link->name ));
     880             : 
     881           0 :     ctx->in_links[ in_idx ].mem    = topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ].wksp;
     882           0 :     ctx->in_links[ in_idx ].chunk0 = fd_dcache_compact_chunk0( ctx->in_links[ in_idx ].mem, link->dcache );
     883           0 :     ctx->in_links[ in_idx ].wmark  = fd_dcache_compact_wmark ( ctx->in_links[ in_idx ].mem, link->dcache, link->mtu );
     884           0 :     ctx->in_links[ in_idx ].mtu    = link->mtu;
     885           0 :   }
     886             : 
     887           0 :   ctx->net_out_idx = UINT_MAX;
     888           0 :   for( uint out_idx=0U; out_idx<tile->out_cnt; out_idx++ ) {
     889           0 :     fd_topo_link_t const * link = &topo->links[ tile->out_link_id[ out_idx ] ];
     890           0 :     if( 0==strcmp( link->name, "rserve_net" ) ) {
     891           0 :       if( ctx->net_out_idx!=UINT_MAX ) continue; /* only use the first net link */
     892           0 :       ctx->net_out_idx    = out_idx;
     893           0 :       ctx->net_out_mem    = topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ].wksp;
     894           0 :       ctx->net_out_chunk0 = fd_dcache_compact_chunk0( ctx->net_out_mem, link->dcache );
     895           0 :       ctx->net_out_wmark  = fd_dcache_compact_wmark( ctx->net_out_mem, link->dcache, link->mtu );
     896           0 :       ctx->net_out_chunk  = ctx->net_out_chunk0;
     897           0 :     }
     898           0 :     else if( 0==strcmp( link->name, "rserve_sign" ) ) { /* Handled above for keyguard. */ }
     899           0 :     else FD_LOG_ERR(( "rserve tile has unexpected output link: %s", link->name ));
     900           0 :   }
     901           0 :   if( FD_UNLIKELY( ctx->net_out_idx==UINT_MAX ) ) FD_LOG_ERR(( "Missing rserve_net output link" ));
     902           0 : }
     903             : 
     904             : static ulong
     905             : populate_allowed_seccomp( fd_topo_t const *      topo FD_PARAM_UNUSED,
     906             :                           fd_topo_tile_t const * tile FD_PARAM_UNUSED,
     907             :                           ulong                  out_cnt,
     908           0 :                           struct sock_filter *   out ) {
     909           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     910           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     911           0 :   ctx_t * ctx     = FD_SCRATCH_ALLOC_APPEND( l, alignof(ctx_t), sizeof(ctx_t) );
     912           0 :   populate_sock_filter_policy_fd_rserve_tile( out_cnt, out, (uint)fd_log_private_logfile_fd(), (uint)ctx->disk_fd );
     913           0 :   return sock_filter_policy_fd_rserve_tile_instr_cnt;
     914           0 : }
     915             : 
     916             : static ulong
     917             : populate_allowed_fds( fd_topo_t const *      topo FD_PARAM_UNUSED,
     918             :                       fd_topo_tile_t const * tile FD_PARAM_UNUSED,
     919             :                       ulong                  out_fds_cnt,
     920           0 :                       int *                  out_fds ) {
     921           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     922           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     923           0 :   ctx_t * ctx     = FD_SCRATCH_ALLOC_APPEND( l, alignof(ctx_t), sizeof(ctx_t) );
     924             : 
     925           0 :   if( FD_UNLIKELY( out_fds_cnt<3UL ) ) FD_LOG_ERR(( "out_fds_cnt %lu", out_fds_cnt ));
     926             : 
     927           0 :   ulong out_cnt = 0UL;
     928           0 :   out_fds[ out_cnt++ ] = 2; /* stderr */
     929           0 :   if( FD_LIKELY( -1!=fd_log_private_logfile_fd() ) )
     930           0 :     out_fds[ out_cnt++ ] = fd_log_private_logfile_fd(); /* logfile */
     931           0 :   if( FD_LIKELY( ctx->disk_fd>=0 ) )
     932           0 :     out_fds[ out_cnt++ ] = ctx->disk_fd;
     933           0 :   return out_cnt;
     934           0 : }
     935             : 
     936             : /* For orphan responses, we may send up to 11 net packets out.
     937             :    All other implemented codepaths will send at most 1. */
     938           0 : #define STEM_BURST FD_RSERVE_MAX_ORPHAN_SLOTS
     939           0 : #define STEM_LAZY (64000UL)
     940             : 
     941           0 : #define STEM_CALLBACK_CONTEXT_TYPE  ctx_t
     942           0 : #define STEM_CALLBACK_CONTEXT_ALIGN alignof(ctx_t)
     943           0 : #define STEM_CALLBACK_DURING_HOUSEKEEPING during_housekeeping
     944           0 : #define STEM_CALLBACK_METRICS_WRITE       metrics_write
     945           0 : #define STEM_CALLBACK_BEFORE_CREDIT       before_credit
     946           0 : #define STEM_CALLBACK_BEFORE_FRAG         before_frag
     947           0 : #define STEM_CALLBACK_DURING_FRAG         during_frag
     948           0 : #define STEM_CALLBACK_RETURNABLE_FRAG     returnable_frag
     949           0 : #define STEM_CALLBACK_AFTER_FRAG          after_frag
     950             : 
     951             : #include "../../disco/stem/fd_stem.c"
     952             : 
     953             : fd_topo_run_tile_t fd_tile_rserve = {
     954             :   .name                     = "rserve",
     955             :   .populate_allowed_seccomp = populate_allowed_seccomp,
     956             :   .populate_allowed_fds     = populate_allowed_fds,
     957             :   .scratch_align            = scratch_align,
     958             :   .scratch_footprint        = scratch_footprint,
     959             :   .privileged_init          = privileged_init,
     960             :   .unprivileged_init        = unprivileged_init,
     961             :   .run                      = stem_run,
     962             : };

Generated by: LCOV version 1.14