LCOV - code coverage report
Current view: top level - flamenco/repair - fd_repair.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 338 0.0 %
Date: 2025-07-13 05:02:02 Functions: 0 28 0.0 %

          Line data    Source code
       1             : #define _GNU_SOURCE 1
       2             : #include "fd_repair.h"
       3             : #include "../../ballet/sha256/fd_sha256.h"
       4             : #include "../../ballet/ed25519/fd_ed25519.h"
       5             : #include "../../ballet/base58/fd_base58.h"
       6             : #include "../../disco/keyguard/fd_keyguard.h"
       7             : #include "../../util/rng/fd_rng.h"
       8             : #include "../../flamenco/fd_flamenco_base.h"
       9             : #include <string.h>
      10             : #include <stdio.h>
      11             : #include <stdlib.h>
      12             : #include <errno.h>
      13             : #include <arpa/inet.h>
      14             : #include <unistd.h>
      15             : #include <sys/socket.h>
      16             : 
      17             : void *
      18           0 : fd_repair_new ( void * shmem, ulong seed ) {
      19           0 :   FD_SCRATCH_ALLOC_INIT(l, shmem);
      20           0 :   fd_repair_t * glob = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_repair_t), sizeof(fd_repair_t) );
      21           0 :   fd_memset(glob, 0, sizeof(fd_repair_t));
      22           0 :   void * shm = FD_SCRATCH_ALLOC_APPEND( l, fd_active_table_align(), fd_active_table_footprint(FD_ACTIVE_KEY_MAX) );
      23           0 :   glob->actives = fd_active_table_join(fd_active_table_new(shm, FD_ACTIVE_KEY_MAX, seed));
      24           0 :   glob->seed = seed;
      25           0 :   shm = FD_SCRATCH_ALLOC_APPEND( l, fd_inflight_table_align(), fd_inflight_table_footprint(FD_NEEDED_KEY_MAX) );
      26           0 :   glob->dupdetect = fd_inflight_table_join(fd_inflight_table_new(shm, FD_NEEDED_KEY_MAX, seed));
      27           0 :   shm = FD_SCRATCH_ALLOC_APPEND( l, fd_pinged_table_align(), fd_pinged_table_footprint(FD_REPAIR_PINGED_MAX) );
      28           0 :   glob->pinged = fd_pinged_table_join(fd_pinged_table_new(shm, FD_REPAIR_PINGED_MAX, seed));
      29           0 :   glob->stake_weights = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_stake_weight_t), FD_STAKE_WEIGHTS_MAX * sizeof(fd_stake_weight_t) );
      30           0 :   glob->stake_weights_temp = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_stake_weight_t), FD_STAKE_WEIGHTS_MAX * sizeof(fd_stake_weight_t) );
      31           0 :   glob->stake_weights_temp_cnt = 0;
      32           0 :   glob->stake_weights_cnt = 0;
      33           0 :   glob->last_decay = 0;
      34           0 :   glob->last_print = 0;
      35           0 :   glob->last_good_peer_cache_file_write = 0;
      36           0 :   glob->oldest_nonce = glob->current_nonce = glob->next_nonce = 0;
      37           0 :   fd_rng_new(glob->rng, (uint)seed, 0UL);
      38             : 
      39           0 :   glob->peer_cnt   = 0;
      40           0 :   glob->peer_idx   = 0;
      41           0 :   glob->actives_random_seed  = 0;
      42             : 
      43           0 :   ulong scratch_top = FD_SCRATCH_ALLOC_FINI(l, 1UL);
      44           0 :   if ( scratch_top > (ulong)shmem + fd_repair_footprint() ) {
      45           0 :     FD_LOG_ERR(("Enough space not allocated for repair"));
      46           0 :   }
      47             : 
      48           0 :   return glob;
      49           0 : }
      50             : 
      51             : fd_repair_t *
      52           0 : fd_repair_join ( void * shmap ) { return (fd_repair_t *)shmap; }
      53             : 
      54             : void *
      55           0 : fd_repair_leave ( fd_repair_t * join ) { return join; }
      56             : 
      57             : void *
      58           0 : fd_repair_delete ( void * shmap ) {
      59           0 :   fd_repair_t * glob = (fd_repair_t *)shmap;
      60           0 :   fd_active_table_delete( fd_active_table_leave( glob->actives ) );
      61           0 :   fd_inflight_table_delete( fd_inflight_table_leave( glob->dupdetect ) );
      62           0 :   fd_pinged_table_delete( fd_pinged_table_leave( glob->pinged ) );
      63           0 :   return glob;
      64           0 : }
      65             : 
      66             : /* Convert an address to a human readable string */
      67           0 : const char * fd_repair_addr_str( char * dst, size_t dstlen, fd_repair_peer_addr_t const * src ) {
      68           0 :   char tmp[INET_ADDRSTRLEN];
      69           0 :   snprintf(dst, dstlen, "%s:%u", inet_ntop(AF_INET, &src->addr, tmp, INET_ADDRSTRLEN), (uint)ntohs(src->port));
      70           0 :   return dst;
      71           0 : }
      72             : 
      73             : /* Set the repair configuration */
      74             : int
      75           0 : fd_repair_set_config( fd_repair_t * glob, const fd_repair_config_t * config ) {
      76           0 :   char tmp[100];
      77           0 :   char keystr[ FD_BASE58_ENCODED_32_SZ ];
      78           0 :   fd_base58_encode_32( config->public_key->uc, NULL, keystr );
      79           0 :   FD_LOG_NOTICE(("configuring address %s key %s", fd_repair_addr_str(tmp, sizeof(tmp), &config->intake_addr), keystr));
      80             : 
      81           0 :   glob->public_key = config->public_key;
      82           0 :   glob->private_key = config->private_key;
      83           0 :   fd_repair_peer_addr_copy(&glob->intake_addr, &config->intake_addr);
      84           0 :   fd_repair_peer_addr_copy(&glob->service_addr, &config->service_addr);
      85           0 :   glob->good_peer_cache_file_fd = config->good_peer_cache_file_fd;
      86           0 :   return 0;
      87           0 : }
      88             : 
      89             : int
      90           0 : fd_repair_update_addr( fd_repair_t * glob, const fd_repair_peer_addr_t * intake_addr, const fd_repair_peer_addr_t * service_addr ) {
      91           0 :   char tmp[100];
      92           0 :   FD_LOG_NOTICE(("updating address %s", fd_repair_addr_str(tmp, sizeof(tmp), intake_addr)));
      93             : 
      94           0 :   fd_repair_peer_addr_copy(&glob->intake_addr, intake_addr);
      95           0 :   fd_repair_peer_addr_copy(&glob->service_addr, service_addr);
      96           0 :   return 0;
      97           0 : }
      98             : 
      99             : /* Initiate connection to a peer */
     100             : int
     101           0 : fd_repair_add_active_peer( fd_repair_t * glob, fd_repair_peer_addr_t const * addr, fd_pubkey_t const * id ) {
     102           0 :   fd_active_elem_t * val = fd_active_table_query(glob->actives, id, NULL);
     103           0 :   if (val == NULL) {
     104           0 :     val = fd_active_table_insert(glob->actives, id);
     105           0 :     fd_repair_peer_addr_copy(&val->addr, addr);
     106           0 :     val->avg_reqs = 0;
     107           0 :     val->avg_reps = 0;
     108           0 :     val->avg_lat = 0;
     109           0 :     val->stake = 0UL;
     110             : 
     111           0 :     glob->peers[ glob->peer_cnt++ ] = (fd_peer_t){
     112           0 :       .key = *id,
     113           0 :       .ip4 = *addr
     114           0 :     };
     115           0 :     return 0;
     116           0 :   }
     117           0 :   return 1;
     118           0 : }
     119             : 
     120             : /* Set the current protocol time in nanosecs */
     121             : void
     122           0 : fd_repair_settime( fd_repair_t * glob, long ts ) {
     123           0 :   glob->now = ts;
     124           0 : }
     125             : 
     126             : /* Get the current protocol time in nanosecs */
     127             : long
     128           0 : fd_repair_gettime( fd_repair_t * glob ) {
     129           0 :   return glob->now;
     130           0 : }
     131             : 
     132             : static void
     133           0 : fd_repair_decay_stats( fd_repair_t * glob ) {
     134           0 :   for( fd_active_table_iter_t iter = fd_active_table_iter_init( glob->actives );
     135           0 :        !fd_active_table_iter_done( glob->actives, iter );
     136           0 :        iter = fd_active_table_iter_next( glob->actives, iter ) ) {
     137           0 :     fd_active_elem_t * ele = fd_active_table_iter_ele( glob->actives, iter );
     138           0 : #define DECAY(_v_) _v_ = _v_ - ((_v_)>>3U) /* Reduce by 12.5% */
     139           0 :     DECAY(ele->avg_reqs);
     140           0 :     DECAY(ele->avg_reps);
     141           0 :     DECAY(ele->avg_lat);
     142           0 : #undef DECAY
     143           0 :   }
     144           0 : }
     145             : 
     146             : /**
     147             :  * read_line() reads characters one by one from 'fd' until:
     148             :  *   - it sees a newline ('\n')
     149             :  *   - it reaches 'max_len - 1' characters
     150             :  *   - or EOF (read returns 0)
     151             :  * It stores the line in 'buf' and null-terminates it.
     152             :  *
     153             :  * Returns the number of characters read (not counting the null terminator),
     154             :  * or -1 on error.
     155             :  */
     156             : static long
     157           0 : read_line( int fd, char * buf ) {
     158           0 :     long i = 0;
     159             : 
     160           0 :     while (i < 255) {
     161           0 :         char c;
     162           0 :         long n = read(fd, &c, 1);
     163             : 
     164           0 :         if (n < 0) {
     165           0 :             if (errno == EINTR) continue;
     166           0 :             return -1;
     167           0 :         } else if (n == 0) {
     168           0 :             break;
     169           0 :         }
     170             : 
     171           0 :         buf[i++] = c;
     172             : 
     173           0 :         if (c == '\n') {
     174           0 :             break;
     175           0 :         }
     176           0 :     }
     177             : 
     178           0 :     buf[i] = '\0';
     179           0 :     return i;
     180           0 : }
     181             : 
     182             : static int
     183           0 : fd_read_in_good_peer_cache_file( fd_repair_t * repair ) {
     184           0 :   if( repair->good_peer_cache_file_fd==-1 ) {
     185           0 :     FD_LOG_NOTICE(( "No repair good_peer_cache_file specified, not loading cached peers" ));
     186           0 :     return 0;
     187           0 :   }
     188             : 
     189           0 :   long seek = lseek( repair->good_peer_cache_file_fd, 0UL, SEEK_SET );
     190           0 :   if( FD_UNLIKELY( seek!=0L ) ) {
     191           0 :     FD_LOG_WARNING(( "Failed to seek to the beginning of the good peer cache file" ));
     192           0 :     return 1;
     193           0 :   }
     194             : 
     195           0 :   int   loaded_peers   = 0;
     196           0 :   char  line[256];
     197           0 :   char  *saveptr      = NULL;
     198             : 
     199           0 :   long len;
     200           0 :   while ((len = read_line(repair->good_peer_cache_file_fd, line)) > 0) {
     201             : 
     202             :     /* Strip newline if present */
     203           0 :     size_t len = strlen( line );
     204           0 :     if( len>0 && line[len-1]=='\n' ) {
     205           0 :       line[len-1] = '\0';
     206           0 :       len--;
     207           0 :     }
     208             : 
     209             :     /* Skip empty or comment lines */
     210           0 :     if( !len || line[0]=='#' ) continue;
     211             : 
     212             :     /* Parse: base58EncodedPubkey/ipAddr/port */
     213           0 :     char * base58_str = strtok_r( line, "/", &saveptr );
     214           0 :     char * ip_str     = strtok_r( NULL, "/", &saveptr );
     215           0 :     char * port_str   = strtok_r( NULL, "/", &saveptr );
     216             : 
     217           0 :     if( FD_UNLIKELY( !base58_str || !ip_str || !port_str ) ) {
     218           0 :       FD_LOG_WARNING(( "Malformed line, skipping" ));
     219           0 :       continue;
     220           0 :     }
     221             : 
     222             :     /* Decode the base58 public key */
     223           0 :     fd_pubkey_t pubkey;
     224           0 :     if( !fd_base58_decode_32( base58_str, pubkey.uc ) ) {
     225           0 :       FD_LOG_WARNING(( "Failed to decode base58 public key '%s', skipping", base58_str ));
     226           0 :       continue;
     227           0 :     }
     228             : 
     229             :     /* Convert IP address */
     230           0 :     struct in_addr addr_parsed;
     231           0 :     if( inet_aton( ip_str, &addr_parsed )==0 ) {
     232           0 :       FD_LOG_WARNING(( "Invalid IPv4 address '%s', skipping", ip_str ));
     233           0 :       continue;
     234           0 :     }
     235             : 
     236             :     /* Convert the port */
     237           0 :     char * endptr = NULL;
     238           0 :     long   port   = strtol( port_str, &endptr, 10 );
     239           0 :     if( (port<=0L) || (port>65535L) || (endptr && *endptr!='\0') ) {
     240           0 :       FD_LOG_WARNING(( "Invalid port '%s', skipping", port_str ));
     241           0 :       continue;
     242           0 :     }
     243             : 
     244             :     /* Create the peer address struct (byte-swap the port to network order). */
     245             :     //fd_repair_peer_addr_t peer_addr;
     246             :     /* already in network byte order from inet_aton */
     247             :     //peer_addr.addr = ip_addr;
     248             :     /* Flip to big-endian for network order */
     249             :     //peer_addr.port = fd_ushort_bswap( (ushort)port );
     250             : 
     251             :     /* Add to active peers in the repair tile. */
     252             :    // fd_repair_add_active_peer( repair, &peer_addr, &pubkey );
     253             : 
     254           0 :     loaded_peers++;
     255           0 :   }
     256             : 
     257           0 :   FD_LOG_INFO(( "Loaded %d peers from good peer cache file", loaded_peers ));
     258           0 :   return 0;
     259           0 : }
     260             : 
     261             : /* Start timed events and other protocol behavior */
     262             : int
     263           0 : fd_repair_start( fd_repair_t * glob ) {
     264           0 :   glob->last_sends = glob->now;
     265           0 :   glob->last_decay = glob->now;
     266           0 :   glob->last_print = glob->now;
     267           0 :   return fd_read_in_good_peer_cache_file( glob );
     268           0 : }
     269             : 
     270             : static void fd_repair_print_all_stats( fd_repair_t * glob );
     271             : static int fd_write_good_peer_cache_file( fd_repair_t * repair );
     272             : 
     273             : /* Dispatch timed events and other protocol behavior. This should be
     274             :  * called inside the main spin loop. */
     275             : int
     276           0 : fd_repair_continue( fd_repair_t * glob ) {
     277           0 :   if ( glob->now - glob->last_print > (long)30e9 ) { /* 30 seconds */
     278           0 :     fd_repair_print_all_stats( glob );
     279           0 :     glob->last_print = glob->now;
     280           0 :     fd_repair_decay_stats( glob );
     281           0 :     glob->last_decay = glob->now;
     282           0 :   } else if ( glob->now - glob->last_decay > (long)15e9 ) { /* 15 seconds */
     283           0 :     fd_repair_decay_stats( glob );
     284           0 :     glob->last_decay = glob->now;
     285           0 :   } else if ( glob->now - glob->last_good_peer_cache_file_write > (long)60e9 ) { /* 1 minute */
     286           0 :     fd_write_good_peer_cache_file( glob );
     287           0 :     glob->last_good_peer_cache_file_write = glob->now;
     288           0 :   }
     289           0 :   return 0;
     290           0 : }
     291             : 
     292             : int
     293             : fd_repair_construct_request_protocol( fd_repair_t          * glob,
     294             :                                       fd_repair_protocol_t * protocol,
     295             :                                       enum fd_needed_elem_type type,
     296             :                                       ulong                  slot,
     297             :                                       uint                   shred_index,
     298             :                                       fd_pubkey_t const    * recipient,
     299             :                                       uint                   nonce,
     300           0 :                                       long                   now ) {
     301           0 :   switch( type ) {
     302           0 :     case fd_needed_window_index: {
     303           0 :       glob->metrics.sent_pkt_types[FD_METRICS_ENUM_REPAIR_SENT_REQUEST_TYPES_V_NEEDED_WINDOW_IDX]++;
     304           0 :       fd_repair_protocol_new_disc(protocol, fd_repair_protocol_enum_window_index);
     305           0 :       fd_repair_window_index_t * wi = &protocol->inner.window_index;
     306           0 :       wi->header.sender = *glob->public_key;
     307           0 :       wi->header.recipient = *recipient;
     308           0 :       wi->header.timestamp = (ulong)now/1000000L;
     309           0 :       wi->header.nonce = nonce;
     310           0 :       wi->slot = slot;
     311           0 :       wi->shred_index = shred_index;
     312             :         //FD_LOG_INFO(( "repair request for %lu, %lu", wi->slot, wi->shred_index ));
     313           0 :       return 1;
     314           0 :     }
     315             : 
     316           0 :     case fd_needed_highest_window_index: {
     317           0 :       glob->metrics.sent_pkt_types[FD_METRICS_ENUM_REPAIR_SENT_REQUEST_TYPES_V_NEEDED_HIGHEST_WINDOW_IDX]++;
     318           0 :       fd_repair_protocol_new_disc( protocol, fd_repair_protocol_enum_highest_window_index );
     319           0 :       fd_repair_highest_window_index_t * wi = &protocol->inner.highest_window_index;
     320           0 :       wi->header.sender = *glob->public_key;
     321           0 :       wi->header.recipient = *recipient;
     322           0 :       wi->header.timestamp = (ulong)now/1000000L;
     323           0 :       wi->header.nonce = nonce;
     324           0 :       wi->slot = slot;
     325           0 :       wi->shred_index = shred_index;
     326             :       //FD_LOG_INFO(( "repair request for %lu, %lu", wi->slot, wi->shred_index ));
     327           0 :       return 1;
     328           0 :     }
     329             : 
     330           0 :     case fd_needed_orphan: {
     331           0 :       glob->metrics.sent_pkt_types[FD_METRICS_ENUM_REPAIR_SENT_REQUEST_TYPES_V_NEEDED_ORPHAN_IDX]++;
     332           0 :       fd_repair_protocol_new_disc( protocol, fd_repair_protocol_enum_orphan );
     333           0 :       fd_repair_orphan_t * wi = &protocol->inner.orphan;
     334           0 :       wi->header.sender = *glob->public_key;
     335           0 :       wi->header.recipient = *recipient;
     336           0 :       wi->header.timestamp = (ulong)now/1000000L;
     337           0 :       wi->header.nonce = nonce;
     338           0 :       wi->slot = slot;
     339             :       //FD_LOG_INFO(( "repair request for %lu", ele->dupkey.slot));
     340           0 :       return 1;
     341           0 :     }
     342           0 :   }
     343           0 :   return 0;
     344           0 : }
     345             : 
     346             : /* Returns 1 if its valid to send a request for the given shred. 0 if
     347             :    it is not, i.e., there is an inflight request for it that was sent
     348             :    within the last x ms. */
     349             : static int
     350           0 : fd_repair_create_inflight_request( fd_repair_t * glob, int type, ulong slot, uint shred_index, long now ) {
     351             : 
     352             :   /* If there are no active sticky peers from which to send requests to, refresh the sticky peers
     353             :      selection. It may be that stake weights were not available before, and now they are. */
     354             : 
     355           0 :   fd_inflight_key_t    dupkey  = { .type = (enum fd_needed_elem_type)type, .slot = slot, .shred_index = shred_index };
     356           0 :   fd_inflight_elem_t * dupelem = fd_inflight_table_query( glob->dupdetect, &dupkey, NULL );
     357             : 
     358           0 :   if( dupelem == NULL ) {
     359           0 :     dupelem = fd_inflight_table_insert( glob->dupdetect, &dupkey );
     360             : 
     361           0 :     if ( FD_UNLIKELY( dupelem == NULL ) ) {
     362           0 :       FD_LOG_ERR(( "Eviction unimplemented. Failed to insert duplicate detection element for slot %lu, shred_index %u", slot, shred_index ));
     363           0 :       return 0;
     364           0 :     }
     365             : 
     366           0 :     dupelem->last_send_time = 0L;
     367           0 :   }
     368             : 
     369           0 :   if( FD_LIKELY( dupelem->last_send_time+(long)40e6  < now ) ) { /* 40ms */
     370           0 :     dupelem->last_send_time = now;
     371           0 :     dupelem->req_cnt        = FD_REPAIR_NUM_NEEDED_PEERS;
     372           0 :     return 1;
     373           0 :   }
     374           0 :   return 0;
     375           0 : }
     376             : 
     377             : int
     378             : fd_repair_inflight_remove( fd_repair_t * glob,
     379             :                            ulong         slot,
     380           0 :                            uint          shred_index ) {
     381             :   /* If we have a shred, we can remove it from the inflight table */
     382             :   // FIXME: might be worth adding eviction logic here for orphan / highest window reqs
     383             : 
     384           0 :   fd_inflight_key_t    dupkey  = { .type = fd_needed_window_index, .slot = slot, .shred_index = shred_index };
     385           0 :   fd_inflight_elem_t * dupelem = fd_inflight_table_query( glob->dupdetect, &dupkey, NULL );
     386           0 :   if( dupelem ) {
     387             :     /* Remove the element from the inflight table */
     388           0 :     fd_inflight_table_remove( glob->dupdetect, &dupkey );
     389           0 :   }
     390           0 :   return 0;
     391           0 : }
     392             : 
     393             : 
     394             : static int
     395           0 : fd_write_good_peer_cache_file( fd_repair_t * repair ) {
     396             :   // return 0;
     397             : 
     398           0 :   if ( repair->good_peer_cache_file_fd == -1 ) {
     399           0 :     return 0;
     400           0 :   }
     401             : 
     402           0 :   if ( repair->actives_sticky_cnt == 0 ) {
     403           0 :     return 0;
     404           0 :   }
     405             : 
     406             :   /* Truncate the file before we write it */
     407           0 :   int err = ftruncate( repair->good_peer_cache_file_fd, 0UL );
     408           0 :   if( FD_UNLIKELY( err==-1 ) ) {
     409           0 :     FD_LOG_WARNING(( "Failed to truncate the good peer cache file (%i-%s)", errno, fd_io_strerror( errno ) ));
     410           0 :     return 1;
     411           0 :   }
     412           0 :   long seek = lseek( repair->good_peer_cache_file_fd, 0UL, SEEK_SET );
     413           0 :   if( FD_UNLIKELY( seek!=0L ) ) {
     414           0 :     FD_LOG_WARNING(( "Failed to seek to the beginning of the good peer cache file" ));
     415           0 :     return 1;
     416           0 :   }
     417             : 
     418             :   /* Write the active sticky peers to file in the format:
     419             :      "base58EncodedPubkey/ipAddr/port"
     420             : 
     421             :      Where ipAddr is in dotted-decimal (e.g. "1.2.3.4")
     422             :      and port is decimal, in host order (e.g. "8001").
     423             :   */
     424           0 :   for( ulong i = 0UL; i < repair->actives_sticky_cnt; i++ ) {
     425           0 :     fd_pubkey_t *      id   = &repair->actives_sticky[ i ];
     426           0 :     fd_active_elem_t * peer = fd_active_table_query( repair->actives, id, NULL );
     427           0 :     if ( peer == NULL ) {
     428           0 :       continue;
     429           0 :     }
     430             : 
     431             :     /* Convert the public key to base58 */
     432           0 :     char base58_str[ FD_BASE58_ENCODED_32_SZ ];
     433           0 :     fd_base58_encode_32( peer->key.uc, NULL, base58_str );
     434             : 
     435             :     /* Convert the IP address to dotted-decimal string.  The address
     436             :        in peer->addr.addr is already in network byte order. */
     437           0 :     struct in_addr addr_parsed;
     438           0 :     addr_parsed.s_addr = peer->addr.addr; /* net-order -> struct in_addr */
     439           0 :     char * ip_str = inet_ntoa( addr_parsed );
     440             : 
     441             :     /* Convert port from network byte order to host byte order. */
     442           0 :     ushort port = fd_ushort_bswap( peer->addr.port );
     443             : 
     444             :     /* Write out line: base58EncodedPubkey/ipAddr/port */
     445           0 :     dprintf( repair->good_peer_cache_file_fd, "%s/%s/%u\n", base58_str, ip_str, (uint)port );
     446           0 :   }
     447             : 
     448           0 :   return 0;
     449           0 : }
     450             : 
     451             : int
     452           0 : fd_repair_need_window_index( fd_repair_t * glob, ulong slot, uint shred_index ) {
     453             :   // FD_LOG_NOTICE(( "[%s] need window %lu, shred_index %u", __func__, slot, shred_index ));
     454           0 :   return fd_repair_create_inflight_request( glob, fd_needed_window_index, slot, shred_index, glob->now );
     455           0 : }
     456             : 
     457             : int
     458           0 : fd_repair_need_highest_window_index( fd_repair_t * glob, ulong slot, uint shred_index ) {
     459             :   //FD_LOG_DEBUG(( "[%s] need highest %lu", __func__, slot ));
     460           0 :   return fd_repair_create_inflight_request( glob, fd_needed_highest_window_index, slot, shred_index, glob->now );
     461           0 : }
     462             : 
     463             : int
     464           0 : fd_repair_need_orphan( fd_repair_t * glob, ulong slot ) {
     465             :   // FD_LOG_NOTICE( ( "[repair] need orphan %lu", slot ) );
     466           0 :   return fd_repair_create_inflight_request( glob, fd_needed_orphan, slot, UINT_MAX, glob->now );
     467           0 : }
     468             : 
     469             : static void
     470           0 : print_stats( fd_active_elem_t * val ) {
     471           0 :   fd_pubkey_t const * id = &val->key;
     472           0 :   if( FD_UNLIKELY( NULL == val ) ) return;
     473           0 :   if( val->avg_reqs == 0 )
     474           0 :     FD_LOG_INFO(( "repair peer %s: no requests sent, stake=%lu", FD_BASE58_ENC_32_ALLOCA( id ), val->stake / (ulong)1e9 ));
     475           0 :   else if( val->avg_reps == 0 )
     476           0 :     FD_LOG_INFO(( "repair peer %s: avg_requests=%lu, no responses received, stake=%lu", FD_BASE58_ENC_32_ALLOCA( id ), val->avg_reqs, val->stake / (ulong)1e9 ));
     477           0 :   else
     478           0 :     FD_LOG_INFO(( "repair peer %s: avg_requests=%lu, response_rate=%f, latency=%f, stake=%lu",
     479           0 :                     FD_BASE58_ENC_32_ALLOCA( id ),
     480           0 :                     val->avg_reqs,
     481           0 :                     ((double)val->avg_reps)/((double)val->avg_reqs),
     482           0 :                     1.0e-9*((double)val->avg_lat)/((double)val->avg_reps),
     483           0 :                     val->stake / (ulong)1e9 ));
     484           0 : }
     485             : 
     486             : static void
     487           0 : fd_repair_print_all_stats( fd_repair_t * glob ) {
     488           0 :   for( fd_active_table_iter_t iter = fd_active_table_iter_init( glob->actives );
     489           0 :        !fd_active_table_iter_done( glob->actives, iter );
     490           0 :        iter = fd_active_table_iter_next( glob->actives, iter ) ) {
     491           0 :     fd_active_elem_t * val = fd_active_table_iter_ele( glob->actives, iter );
     492           0 :     print_stats( val );
     493           0 :   }
     494           0 :   FD_LOG_INFO( ( "peer count: %lu", fd_active_table_key_cnt( glob->actives ) ) );
     495           0 : }
     496             : 
     497           0 : void fd_repair_add_sticky( fd_repair_t * glob, fd_pubkey_t const * id ) {
     498           0 :   glob->actives_sticky[glob->actives_sticky_cnt++] = *id;
     499             : 
     500           0 : }
     501             : 
     502             : void
     503             : fd_repair_set_stake_weights_init( fd_repair_t * repair,
     504             :                                   fd_stake_weight_t const * stake_weights,
     505           0 :                                   ulong stake_weights_cnt ) {
     506           0 :   if( stake_weights == NULL ) {
     507           0 :     FD_LOG_ERR(( "stake weights NULL" ));
     508           0 :   }
     509           0 :   if( stake_weights_cnt > FD_STAKE_WEIGHTS_MAX ) {
     510           0 :     FD_LOG_ERR(( "too many stake weights" ));
     511           0 :   }
     512             : 
     513           0 :   fd_memcpy( repair->stake_weights_temp, stake_weights, stake_weights_cnt * sizeof(fd_stake_weight_t) );
     514           0 :   repair->stake_weights_temp_cnt = stake_weights_cnt;
     515           0 : }
     516             : 
     517             : void
     518           0 : fd_repair_set_stake_weights_fini( fd_repair_t * repair ) {
     519           0 :   fd_swap( repair->stake_weights, repair->stake_weights_temp );
     520           0 :   repair->stake_weights_cnt = repair->stake_weights_temp_cnt;
     521           0 : }
     522             : 
     523             : 
     524             : fd_repair_metrics_t *
     525           0 : fd_repair_get_metrics( fd_repair_t * repair ) {
     526           0 :   return &repair->metrics;
     527           0 : }

Generated by: LCOV version 1.14