LCOV - code coverage report
Current view: top level - flamenco/gossip - fd_ping_tracker.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 241 320 75.3 %
Date: 2025-09-19 04:41:14 Functions: 11 12 91.7 %

          Line data    Source code
       1             : #include "fd_ping_tracker.h"
       2             : 
       3             : #include "../../ballet/sha256/fd_sha256.h"
       4             : #include "../../util/log/fd_log.h"
       5             : 
       6          15 : #define FD_PING_TRACKER_STATE_UNPINGED         (0)
       7          30 : #define FD_PING_TRACKER_STATE_INVALID          (1)
       8          18 : #define FD_PING_TRACKER_STATE_VALID            (2)
       9           6 : #define FD_PING_TRACKER_STATE_VALID_REFRESHING (3)
      10             : 
      11             : struct pubkey_private {
      12             :   uchar b[ 32UL ];
      13             : };
      14             : 
      15             : typedef struct pubkey_private pubkey_private_t;
      16             : 
      17             : struct fd_ping_peer {
      18             :   fd_ip4_port_t    address;
      19             :   pubkey_private_t identity_pubkey;
      20             :   uchar            ping_token[ 32UL ];
      21             :   uchar            expected_pong_hash[ 32UL ];
      22             : 
      23             :   uchar state;
      24             : 
      25             :   long  next_ping_nanos;
      26             :   long  valid_until_nanos;
      27             :   long  last_rx_nanos;
      28             : 
      29             :   ulong pool_next;
      30             : 
      31             :   ulong lru_prev;
      32             :   ulong lru_next;
      33             : 
      34             :   ulong map_next;
      35             :   ulong map_prev;
      36             : 
      37             :   union {
      38             :     struct {
      39             :       ulong unpinged_next;
      40             :       ulong unpinged_prev;
      41             :     };
      42             : 
      43             :     struct {
      44             :       ulong waiting_next;
      45             :       ulong waiting_prev;
      46             :     };
      47             : 
      48             :     struct {
      49             :       ulong refreshing_next;
      50             :       ulong refreshing_prev;
      51             :     };
      52             :   };
      53             : };
      54             : 
      55             : typedef struct fd_ping_peer fd_ping_peer_t;
      56             : 
      57             : #define POOL_NAME pool
      58      983058 : #define POOL_NEXT pool_next
      59          30 : #define POOL_T    fd_ping_peer_t
      60             : #include "../../util/tmpl/fd_pool.c"
      61             : 
      62             : #define DLIST_NAME  lru_list
      63             : #define DLIST_ELE_T fd_ping_peer_t
      64          66 : #define DLIST_PREV  lru_prev
      65          66 : #define DLIST_NEXT  lru_next
      66             : #include "../../util/tmpl/fd_dlist.c"
      67             : 
      68             : #define DLIST_NAME  unpinged_list
      69             : #define DLIST_ELE_T fd_ping_peer_t
      70          15 : #define DLIST_PREV  unpinged_prev
      71          27 : #define DLIST_NEXT  unpinged_next
      72             : #include "../../util/tmpl/fd_dlist.c"
      73             : 
      74             : #define DLIST_NAME  waiting_list
      75             : #define DLIST_ELE_T fd_ping_peer_t
      76          18 : #define DLIST_PREV  waiting_prev
      77          21 : #define DLIST_NEXT  waiting_next
      78             : #include "../../util/tmpl/fd_dlist.c"
      79             : 
      80             : #define DLIST_NAME  refreshing_list
      81             : #define DLIST_ELE_T fd_ping_peer_t
      82          48 : #define DLIST_PREV  refreshing_prev
      83          66 : #define DLIST_NEXT  refreshing_next
      84             : #include "../../util/tmpl/fd_dlist.c"
      85             : 
      86             : #define MAP_NAME  peer_map
      87           6 : #define MAP_ELE_T fd_ping_peer_t
      88             : #define MAP_KEY_T pubkey_private_t
      89          18 : #define MAP_KEY   identity_pubkey
      90      149577 : #define MAP_IDX_T ulong
      91          18 : #define MAP_NEXT  map_next
      92          12 : #define MAP_PREV  map_prev
      93       74793 : #define MAP_KEY_HASH(k,s) ((s) ^ fd_ulong_load_8( (k)->b ))
      94          30 : #define MAP_KEY_EQ(k0,k1) (!memcmp((k0)->b, (k1)->b, 32UL))
      95             : #define MAP_OPTIMIZE_RANDOM_ACCESS_REMOVAL 1
      96             : #include "../../util/tmpl/fd_map_chain.c"
      97             : 
      98             : struct __attribute__((aligned(FD_PING_TRACKER_ALIGN))) fd_ping_tracker_private {
      99             :   fd_rng_t * rng;
     100             :   fd_sha256_t sha[1];
     101             : 
     102             :   ulong           entrypoints_cnt;
     103             :   fd_ip4_port_t * entrypoints;
     104             : 
     105             :   fd_ping_tracker_metrics_t metrics[1];
     106             : 
     107             :   fd_ping_peer_t *    pool;
     108             :   lru_list_t *        lru;
     109             : 
     110             :   unpinged_list_t *   unpinged;
     111             :   waiting_list_t *    waiting;
     112             :   refreshing_list_t * refreshing;
     113             : 
     114             :   peer_map_t *        peers;
     115             : 
     116             :   fd_ping_tracker_change_fn change_fn;
     117             :   void *                    change_fn_ctx;
     118             : 
     119             :   ulong magic; /* ==FD_PING_TRACKER_MAGIC */
     120             : };
     121             : 
     122             : FD_FN_CONST ulong
     123          45 : fd_ping_tracker_align( void ) {
     124          45 :   return FD_PING_TRACKER_ALIGN;
     125          45 : }
     126             : 
     127             : FD_FN_CONST ulong
     128          15 : fd_ping_tracker_footprint( ulong entrypoints_len ) {
     129          15 :   ulong l;
     130          15 :   l = FD_LAYOUT_INIT;
     131          15 :   l = FD_LAYOUT_APPEND( l, FD_PING_TRACKER_ALIGN,   sizeof(fd_ping_tracker_t)             );
     132          15 :   l = FD_LAYOUT_APPEND( l, alignof(fd_ip4_port_t),  entrypoints_len*sizeof(fd_ip4_port_t) );
     133          15 :   l = FD_LAYOUT_APPEND( l, pool_align(),            pool_footprint( FD_PING_TRACKER_MAX ) );
     134          15 :   l = FD_LAYOUT_APPEND( l, lru_list_align(),        lru_list_footprint()                  );
     135          15 :   l = FD_LAYOUT_APPEND( l, unpinged_list_align(),   unpinged_list_footprint()             );
     136          15 :   l = FD_LAYOUT_APPEND( l, waiting_list_align(),    waiting_list_footprint()              );
     137          15 :   l = FD_LAYOUT_APPEND( l, refreshing_list_align(), refreshing_list_footprint()           );
     138          15 :   l = FD_LAYOUT_APPEND( l, peer_map_align(),        peer_map_footprint( 8192UL )          );
     139          15 :   return FD_LAYOUT_FINI( l, FD_PING_TRACKER_ALIGN );
     140          15 : }
     141             : 
     142             : void *
     143             : fd_ping_tracker_new( void *                    shmem,
     144             :                      fd_rng_t *                rng,
     145             :                      ulong                     entrypoints_len,
     146             :                      fd_ip4_port_t const *     entrypoints,
     147             :                      fd_ping_tracker_change_fn change_fn,
     148          15 :                      void *                    change_fn_ctx ) {
     149          15 :   if( FD_UNLIKELY( !shmem ) ) {
     150           0 :     FD_LOG_WARNING(( "NULL shmem" ));
     151           0 :     return NULL;
     152           0 :   }
     153             : 
     154          15 :   if( FD_UNLIKELY( !rng ) ) {
     155           0 :     FD_LOG_WARNING(( "NULL rng" ));
     156           0 :     return NULL;
     157           0 :   }
     158             : 
     159          15 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_ping_tracker_align() ) ) ) {
     160           0 :     FD_LOG_WARNING(( "misaligned shmem" ));
     161           0 :     return NULL;
     162           0 :   }
     163             : 
     164          15 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
     165          15 :   fd_ping_tracker_t * ping_tracker = FD_SCRATCH_ALLOC_APPEND( l, FD_PING_TRACKER_ALIGN,   sizeof(fd_ping_tracker_t)             );
     166          15 :   void * _entrypoints              = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_ip4_port_t),  entrypoints_len*sizeof(fd_ip4_port_t) );
     167          15 :   void * _pool                     = FD_SCRATCH_ALLOC_APPEND( l, pool_align(),            pool_footprint( FD_PING_TRACKER_MAX ) );
     168          15 :   void * _lru                      = FD_SCRATCH_ALLOC_APPEND( l, lru_list_align(),        lru_list_footprint()                  );
     169          15 :   void * _unpinged                 = FD_SCRATCH_ALLOC_APPEND( l, unpinged_list_align(),   unpinged_list_footprint()             );
     170          15 :   void * _waiting                  = FD_SCRATCH_ALLOC_APPEND( l, waiting_list_align(),    waiting_list_footprint()              );
     171          15 :   void * _refreshing               = FD_SCRATCH_ALLOC_APPEND( l, refreshing_list_align(), refreshing_list_footprint()           );
     172          15 :   void * _peers                    = FD_SCRATCH_ALLOC_APPEND( l, peer_map_align(),        peer_map_footprint( 8192UL )          );
     173             : 
     174           0 :   ping_tracker->rng = rng;
     175          15 :   ping_tracker->pool = pool_join( pool_new( _pool, FD_PING_TRACKER_MAX ) );
     176          15 :   FD_TEST( ping_tracker->pool );
     177          15 :   ping_tracker->lru  = lru_list_join( lru_list_new( _lru ) );
     178          15 :   FD_TEST( ping_tracker->lru );
     179          15 :   ping_tracker->unpinged = unpinged_list_join( unpinged_list_new( _unpinged ) );
     180          15 :   FD_TEST( ping_tracker->unpinged );
     181          15 :   ping_tracker->waiting = waiting_list_join( waiting_list_new( _waiting ) );
     182          15 :   FD_TEST( ping_tracker->waiting );
     183          15 :   ping_tracker->refreshing = refreshing_list_join( refreshing_list_new( _refreshing ) );
     184          15 :   FD_TEST( ping_tracker->refreshing );
     185          15 :   ping_tracker->peers = peer_map_join( peer_map_new( _peers, 8192UL, fd_rng_ulong( rng ) ) );
     186          15 :   FD_TEST( ping_tracker->peers );
     187             : 
     188          15 :   ping_tracker->entrypoints_cnt = entrypoints_len;
     189          15 :   ping_tracker->entrypoints = (fd_ip4_port_t *)_entrypoints;
     190          15 :   fd_memcpy( ping_tracker->entrypoints, entrypoints, entrypoints_len*sizeof(fd_ip4_port_t) );
     191             : 
     192          15 :   ping_tracker->change_fn     = change_fn;
     193          15 :   ping_tracker->change_fn_ctx = change_fn_ctx;
     194             : 
     195          15 :   FD_TEST( fd_sha256_join( fd_sha256_new( ping_tracker->sha ) ) );
     196             : 
     197          15 :   fd_memset( ping_tracker->metrics, 0, sizeof(fd_ping_tracker_metrics_t) );
     198             : 
     199          15 :   FD_COMPILER_MFENCE();
     200          15 :   FD_VOLATILE( ping_tracker->magic ) = FD_PING_TRACKER_MAGIC;
     201          15 :   FD_COMPILER_MFENCE();
     202             : 
     203          15 :   return (void *)ping_tracker;
     204          15 : }
     205             : 
     206             : fd_ping_tracker_t *
     207          15 : fd_ping_tracker_join( void * shpt ) {
     208          15 :   if( FD_UNLIKELY( !shpt ) ) {
     209           0 :     FD_LOG_WARNING(( "NULL shpt" ));
     210           0 :     return NULL;
     211           0 :   }
     212             : 
     213          15 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shpt, fd_ping_tracker_align() ) ) ) {
     214           0 :     FD_LOG_WARNING(( "misaligned shpt" ));
     215           0 :     return NULL;
     216           0 :   }
     217             : 
     218          15 :   fd_ping_tracker_t * ping_tracker = (fd_ping_tracker_t *)shpt;
     219             : 
     220          15 :   if( FD_UNLIKELY( ping_tracker->magic!=FD_PING_TRACKER_MAGIC ) ) {
     221           0 :     FD_LOG_WARNING(( "bad magic" ));
     222           0 :     return NULL;
     223           0 :   }
     224             : 
     225          15 :   return ping_tracker;
     226          15 : }
     227             : 
     228             : static inline void
     229             : hash_ping_token( uchar const * ping_token,
     230             :                  uchar         expected_pong_token[ static 32UL ],
     231          15 :                  fd_sha256_t * sha ) {
     232          15 :   fd_sha256_init( sha );
     233          15 :   fd_sha256_append( sha, "SOLANA_PING_PONG", 16UL );
     234          15 :   fd_sha256_append( sha, ping_token, 32UL );
     235          15 :   fd_sha256_fini( sha, expected_pong_token );
     236          15 : }
     237             : 
     238             : static void
     239             : remove_tracking( fd_ping_tracker_t * ping_tracker,
     240          21 :                  fd_ping_peer_t *    peer ) {
     241          21 :   if( FD_UNLIKELY( peer->state==FD_PING_TRACKER_STATE_UNPINGED ) ) unpinged_list_ele_remove( ping_tracker->unpinged, peer, ping_tracker->pool );
     242          21 :   else if( FD_LIKELY( peer->state==FD_PING_TRACKER_STATE_VALID ) ) waiting_list_ele_remove( ping_tracker->waiting, peer, ping_tracker->pool );
     243          15 :   else                                                             refreshing_list_ele_remove( ping_tracker->refreshing, peer, ping_tracker->pool );
     244          21 : }
     245             : 
     246             : static void
     247             : generate_ping_token( fd_ping_peer_t * peer,
     248          15 :                      fd_rng_t *       rng ) {
     249          15 :   fd_memcpy( peer->ping_token, "SOLANA_PING_PONG", 16UL );
     250         255 :   for( ulong i=16UL; i<32UL; i++ ) peer->ping_token[ i ] = fd_rng_uchar( rng );
     251          15 : }
     252             : 
     253             : static inline int
     254             : is_entrypoint( fd_ping_tracker_t const * ping_tracker,
     255          48 :                fd_ip4_port_t             peer_addr ) {
     256          93 :   for( ulong i=0UL; i<ping_tracker->entrypoints_cnt; i++ ) {
     257          48 :     if( FD_UNLIKELY( peer_addr.addr==ping_tracker->entrypoints[ i ].addr && peer_addr.port==ping_tracker->entrypoints[ i ].port ) ) return 1;
     258          48 :   }
     259          45 :   return 0;
     260          48 : }
     261             : 
     262             : void
     263             : fd_ping_tracker_track( fd_ping_tracker_t * ping_tracker,
     264             :                        uchar const *       peer_pubkey,
     265             :                        ulong               peer_stake,
     266             :                        fd_ip4_port_t       peer_address,
     267       74754 :                        long                now ) {
     268       74754 :   fd_ping_peer_t * peer = peer_map_ele_query( ping_tracker->peers, fd_type_pun_const( peer_pubkey ), NULL, ping_tracker->pool );
     269             : 
     270       74754 :   if( FD_UNLIKELY( !peer ) ) {
     271       74742 :     if( FD_LIKELY( peer_stake>=1000000000UL ) ) return;
     272          15 :     if( FD_UNLIKELY( is_entrypoint( ping_tracker, peer_address ) ) ) return;
     273             : 
     274          12 :     if( FD_UNLIKELY( !pool_free( ping_tracker->pool ) ) ) {
     275           0 :       peer = lru_list_ele_pop_head( ping_tracker->lru, ping_tracker->pool );
     276           0 :       remove_tracking( ping_tracker, peer );
     277           0 :       peer_map_ele_remove_fast( ping_tracker->peers, peer, ping_tracker->pool );
     278           0 :       if( FD_LIKELY( peer->state==FD_PING_TRACKER_STATE_VALID || peer->state==FD_PING_TRACKER_STATE_VALID_REFRESHING ) ) {
     279           0 :         ping_tracker->change_fn( ping_tracker->change_fn_ctx, peer->identity_pubkey.b, peer->address, now, FD_PING_TRACKER_CHANGE_TYPE_INACTIVE );
     280           0 :       }
     281           0 :       switch( peer->state ) {
     282           0 :         case FD_PING_TRACKER_STATE_UNPINGED:         ping_tracker->metrics->unpinged_cnt--; break;
     283           0 :         case FD_PING_TRACKER_STATE_INVALID:          ping_tracker->metrics->invalid_cnt--; break;
     284           0 :         case FD_PING_TRACKER_STATE_VALID:            ping_tracker->metrics->valid_cnt--; break;
     285           0 :         case FD_PING_TRACKER_STATE_VALID_REFRESHING: ping_tracker->metrics->refreshing_cnt--; break;
     286           0 :         default: FD_LOG_ERR(( "Unknown state %d", peer->state )); return;
     287           0 :       }
     288           0 :       ping_tracker->metrics->peers_evicted++;
     289          12 :     } else {
     290          12 :       peer = pool_ele_acquire( ping_tracker->pool );
     291          12 :     }
     292             : 
     293          12 :     fd_memcpy( peer->identity_pubkey.b, peer_pubkey, 32UL );
     294          12 :     peer->address           = peer_address;
     295          12 :     peer->valid_until_nanos = 0L;
     296          12 :     peer->next_ping_nanos   = now;
     297          12 :     peer->state             = FD_PING_TRACKER_STATE_UNPINGED;
     298          12 :     ping_tracker->metrics->unpinged_cnt++;
     299          12 :     ping_tracker->metrics->tracked_cnt++;
     300             : 
     301          12 :     generate_ping_token( peer, ping_tracker->rng );
     302          12 :     hash_ping_token( peer->ping_token, peer->expected_pong_hash, ping_tracker->sha );
     303             : 
     304          12 :     unpinged_list_ele_push_head( ping_tracker->unpinged, peer, ping_tracker->pool );
     305          12 :     peer_map_ele_insert( ping_tracker->peers, peer, ping_tracker->pool );
     306          12 :     lru_list_ele_push_tail( ping_tracker->lru, peer, ping_tracker->pool );
     307          12 :   } else {
     308          12 :     if( FD_LIKELY( peer_stake>=1000000000UL || is_entrypoint( ping_tracker, peer_address ) ) ) {
     309             :       /* Node went from unstaked (or low staked) to >=1 SOL, or to being
     310             :          an entrypoint.  No longer need to ping it. */
     311           0 :       peer_map_ele_remove_fast( ping_tracker->peers, peer, ping_tracker->pool );
     312           0 :       lru_list_ele_remove( ping_tracker->lru, peer, ping_tracker->pool );
     313           0 :       remove_tracking( ping_tracker, peer );
     314           0 :       pool_ele_release( ping_tracker->pool, peer );
     315           0 :       if( FD_LIKELY( peer->state==FD_PING_TRACKER_STATE_VALID || peer->state==FD_PING_TRACKER_STATE_VALID_REFRESHING ) ) {
     316           0 :         ping_tracker->change_fn( ping_tracker->change_fn_ctx, peer->identity_pubkey.b, peer->address, now, FD_PING_TRACKER_CHANGE_TYPE_INACTIVE_STAKED );
     317           0 :       }
     318           0 :       ping_tracker->metrics->stake_changed_cnt++;
     319           0 :       switch( peer->state ) {
     320           0 :         case FD_PING_TRACKER_STATE_UNPINGED:         ping_tracker->metrics->unpinged_cnt--; break;
     321           0 :         case FD_PING_TRACKER_STATE_INVALID:          ping_tracker->metrics->invalid_cnt--; break;
     322           0 :         case FD_PING_TRACKER_STATE_VALID:            ping_tracker->metrics->valid_cnt--; break;
     323           0 :         case FD_PING_TRACKER_STATE_VALID_REFRESHING: ping_tracker->metrics->refreshing_cnt--; break;
     324           0 :         default: FD_LOG_ERR(( "Unknown state %d", peer->state )); return;
     325           0 :       }
     326           0 :       return;
     327           0 :     }
     328             : 
     329          12 :     if( FD_UNLIKELY( peer_address.addr!=peer->address.addr || peer_address.port!=peer->address.port ) ) {
     330             :       /* Node changed address, update the address.  Any existing pongs
     331             :          are no longer valid. */
     332           3 :       peer->address           = peer_address;
     333           3 :       peer->valid_until_nanos = 0UL;
     334           3 :       remove_tracking( ping_tracker, peer );
     335           3 :       if( FD_LIKELY( peer->state==FD_PING_TRACKER_STATE_VALID || peer->state==FD_PING_TRACKER_STATE_VALID_REFRESHING ) ) {
     336           3 :         ping_tracker->change_fn( ping_tracker->change_fn_ctx, peer->identity_pubkey.b, peer->address, now, FD_PING_TRACKER_CHANGE_TYPE_INACTIVE );
     337           3 :       }
     338           3 :       ping_tracker->metrics->address_changed_cnt++;
     339           3 :       switch( peer->state ) {
     340           0 :         case FD_PING_TRACKER_STATE_UNPINGED:         ping_tracker->metrics->unpinged_cnt--; break;
     341           0 :         case FD_PING_TRACKER_STATE_INVALID:          ping_tracker->metrics->invalid_cnt--; break;
     342           3 :         case FD_PING_TRACKER_STATE_VALID:            ping_tracker->metrics->valid_cnt--; break;
     343           0 :         case FD_PING_TRACKER_STATE_VALID_REFRESHING: ping_tracker->metrics->refreshing_cnt--; break;
     344           0 :         default: FD_LOG_ERR(( "Unknown state %d", peer->state )); return;
     345           3 :       }
     346           3 :       peer->next_ping_nanos = now;
     347           3 :       peer->state           = FD_PING_TRACKER_STATE_UNPINGED;
     348           3 :       ping_tracker->metrics->unpinged_cnt++;
     349           3 :       generate_ping_token( peer, ping_tracker->rng );
     350           3 :       hash_ping_token( peer->ping_token, peer->expected_pong_hash, ping_tracker->sha );
     351             : 
     352           3 :       unpinged_list_ele_push_head( ping_tracker->unpinged, peer, ping_tracker->pool );
     353           3 :     }
     354          12 :   }
     355             : 
     356          24 :   peer->last_rx_nanos = now;
     357          24 :   lru_list_ele_remove( ping_tracker->lru, peer, ping_tracker->pool );
     358          24 :   lru_list_ele_push_tail( ping_tracker->lru, peer, ping_tracker->pool );
     359          24 : }
     360             : 
     361             : void
     362             : fd_ping_tracker_register( fd_ping_tracker_t * ping_tracker,
     363             :                           uchar const *       peer_pubkey,
     364             :                           ulong               peer_stake,
     365             :                           fd_ip4_port_t       peer_address,
     366             :                           uchar const *       pong_token,
     367          21 :                           long                now ) {
     368          21 :   if( FD_UNLIKELY( peer_stake>=1000000000UL ) ) {
     369           0 :     ping_tracker->metrics->pong_result[ 0UL ]++;
     370           0 :     return;
     371           0 :   }
     372          21 :   if( FD_UNLIKELY( is_entrypoint( ping_tracker, peer_address ) ) ) {
     373           0 :     ping_tracker->metrics->pong_result[ 1UL ]++;
     374           0 :     return;
     375           0 :   }
     376             : 
     377          21 :   fd_ping_peer_t * peer = peer_map_ele_query( ping_tracker->peers, fd_type_pun_const( peer_pubkey ), NULL, ping_tracker->pool );
     378          21 :   if( FD_UNLIKELY( !peer ) ) {
     379           3 :     ping_tracker->metrics->pong_result[ 2UL ]++;
     380           3 :     return;
     381           3 :   }
     382             : 
     383          18 :   if( FD_UNLIKELY( peer_address.addr!=peer->address.addr || peer_address.port!=peer->address.port ) ) {
     384           3 :     ping_tracker->metrics->pong_result[ 3UL ]++;
     385           3 :     return;
     386           3 :   }
     387          15 :   if( FD_UNLIKELY( memcmp( pong_token, peer->expected_pong_hash, 32UL ) ) ) {
     388           3 :     ping_tracker->metrics->pong_result[ 4UL ]++;
     389           3 :     return;
     390           3 :   }
     391             : 
     392          12 :   remove_tracking( ping_tracker, peer );
     393          12 :   peer->valid_until_nanos = now+20L*60L*1000L*1000L*1000L; /* 20 mintues of validity */
     394          12 :   peer->next_ping_nanos   = now+18L*60L*1000L*1000L*1000L; /* 18 minutes til we start trying to refresh */
     395          12 :   if( FD_UNLIKELY( peer->state==FD_PING_TRACKER_STATE_INVALID || peer->state==FD_PING_TRACKER_STATE_UNPINGED ) ) {
     396           9 :     ping_tracker->change_fn( ping_tracker->change_fn_ctx, peer->identity_pubkey.b, peer->address, now, FD_PING_TRACKER_CHANGE_TYPE_ACTIVE );
     397           9 :   }
     398          12 :   switch( peer->state ) {
     399           0 :     case FD_PING_TRACKER_STATE_UNPINGED:         ping_tracker->metrics->unpinged_cnt--; break;
     400           9 :     case FD_PING_TRACKER_STATE_INVALID:          ping_tracker->metrics->invalid_cnt--; break;
     401           3 :     case FD_PING_TRACKER_STATE_VALID:            ping_tracker->metrics->valid_cnt--; break;
     402           0 :     case FD_PING_TRACKER_STATE_VALID_REFRESHING: ping_tracker->metrics->refreshing_cnt--; break;
     403           0 :     default: FD_LOG_ERR(( "Unknown state %d", peer->state )); return;
     404          12 :   }
     405          12 :   peer->state = FD_PING_TRACKER_STATE_VALID;
     406          12 :   ping_tracker->metrics->valid_cnt++;
     407          12 :   waiting_list_ele_push_tail( ping_tracker->waiting, peer, ping_tracker->pool );
     408          12 :   ping_tracker->metrics->pong_result[ 5UL ]++;
     409          12 : }
     410             : 
     411             : int
     412             : fd_ping_tracker_pop_request( fd_ping_tracker_t *    ping_tracker,
     413             :                              long                   now,
     414             :                              uchar const **         out_peer_pubkey,
     415             :                              fd_ip4_port_t const ** out_peer_address,
     416       75714 :                              uchar const **         out_token ) {
     417       75714 :   if( FD_UNLIKELY( !unpinged_list_is_empty( ping_tracker->unpinged, ping_tracker->pool ) ) ) {
     418          12 :     fd_ping_peer_t * unpinged = unpinged_list_ele_pop_head( ping_tracker->unpinged, ping_tracker->pool );
     419          12 :     FD_TEST( unpinged->state==FD_PING_TRACKER_STATE_UNPINGED );
     420          12 :     refreshing_list_ele_push_tail( ping_tracker->refreshing, unpinged, ping_tracker->pool );
     421          12 :     unpinged->state           = FD_PING_TRACKER_STATE_INVALID;
     422          12 :     ping_tracker->metrics->unpinged_cnt--;
     423          12 :     ping_tracker->metrics->invalid_cnt++;
     424          12 :     unpinged->next_ping_nanos = now+1L*1000L*1000L*1000L;
     425          12 :     *out_peer_pubkey          = unpinged->identity_pubkey.b;
     426          12 :     *out_peer_address         = &unpinged->address;
     427          12 :     *out_token                = unpinged->ping_token;
     428          12 :     return 1;
     429          12 :   }
     430             : 
     431       75708 :   for(;;) {
     432       75708 :     fd_ping_peer_t * peer_refreshing = NULL;
     433       75708 :     if( FD_UNLIKELY( !refreshing_list_is_empty( ping_tracker->refreshing, ping_tracker->pool ) ) ) peer_refreshing = refreshing_list_ele_peek_head( ping_tracker->refreshing, ping_tracker->pool );
     434       75708 :     fd_ping_peer_t * peer_waiting = NULL;
     435       75708 :     if( FD_UNLIKELY( !waiting_list_is_empty( ping_tracker->waiting, ping_tracker->pool ) ) ) peer_waiting = waiting_list_ele_peek_head( ping_tracker->waiting, ping_tracker->pool );
     436             : 
     437       75708 :     fd_ping_peer_t * next;
     438       75708 :     if(      FD_UNLIKELY( !peer_refreshing && !peer_waiting ) ) return 0;
     439          36 :     else if( FD_UNLIKELY(  peer_refreshing && !peer_waiting ) ) next = peer_refreshing;
     440           3 :     else if( FD_UNLIKELY( !peer_refreshing &&  peer_waiting ) ) next = peer_waiting;
     441           0 :     else if( FD_UNLIKELY( peer_waiting->next_ping_nanos<peer_refreshing->next_ping_nanos ) ) next = peer_waiting;
     442           0 :     else next = peer_refreshing;
     443             : 
     444          36 :     FD_TEST( next->state!=FD_PING_TRACKER_STATE_UNPINGED );
     445          36 :     FD_TEST( next->next_ping_nanos );
     446          36 :     if( FD_LIKELY( next->state!=FD_PING_TRACKER_STATE_INVALID ) ) FD_TEST( next->valid_until_nanos );
     447          30 :     else                                                          FD_TEST( !next->valid_until_nanos );
     448             : 
     449          36 :     if( FD_UNLIKELY( next->last_rx_nanos<now-20L*1000L*1000L*1000L ) ) {
     450             :       /* The peer is no longer sending us contact information, no need
     451             :          to ping it and instead remove it from the table. */
     452           6 :       peer_map_ele_remove_fast( ping_tracker->peers, next, ping_tracker->pool );
     453           6 :       lru_list_ele_remove( ping_tracker->lru, next, ping_tracker->pool );
     454           6 :       remove_tracking( ping_tracker, next );
     455           6 :       pool_ele_release( ping_tracker->pool, next );
     456           6 :       if( FD_LIKELY( next->state==FD_PING_TRACKER_STATE_VALID || next->state==FD_PING_TRACKER_STATE_VALID_REFRESHING ) ) {
     457           0 :         ping_tracker->change_fn( ping_tracker->change_fn_ctx, next->identity_pubkey.b, next->address, now, FD_PING_TRACKER_CHANGE_TYPE_INACTIVE );
     458           0 :       }
     459           6 :       switch( next->state ) {
     460           0 :         case FD_PING_TRACKER_STATE_UNPINGED:         ping_tracker->metrics->unpinged_cnt--; break;
     461           6 :         case FD_PING_TRACKER_STATE_INVALID:          ping_tracker->metrics->invalid_cnt--; break;
     462           0 :         case FD_PING_TRACKER_STATE_VALID:            ping_tracker->metrics->valid_cnt--; break;
     463           0 :         case FD_PING_TRACKER_STATE_VALID_REFRESHING: ping_tracker->metrics->refreshing_cnt--; break;
     464           0 :         default: FD_LOG_ERR(( "Unknown state %d", next->state ));
     465           6 :       }
     466           6 :       continue;
     467           6 :     }
     468             : 
     469             :     /* The next ping we want to send is still in the future, so do
     470             :        nothing for now. */
     471          30 :     if( FD_LIKELY( next->next_ping_nanos>now ) ) return 0;
     472             : 
     473          21 :     if( FD_LIKELY( next==peer_refreshing ) )   refreshing_list_ele_pop_head( ping_tracker->refreshing, ping_tracker->pool );
     474           3 :     else if( FD_LIKELY( next==peer_waiting ) ) waiting_list_ele_pop_head( ping_tracker->waiting, ping_tracker->pool );
     475           0 :     else                                       __builtin_unreachable();
     476             : 
     477             :     /* Push the element to the back of the refreshing list now, so it
     478             :        starts getting pinged every second. */
     479          21 :     refreshing_list_ele_push_tail( ping_tracker->refreshing, next, ping_tracker->pool );
     480          21 :     if( FD_LIKELY( next->state==FD_PING_TRACKER_STATE_VALID ) ) {
     481           3 :       next->state = FD_PING_TRACKER_STATE_VALID_REFRESHING;
     482           3 :       ping_tracker->metrics->valid_cnt--;
     483           3 :       ping_tracker->metrics->refreshing_cnt++;
     484          18 :     } else if( FD_LIKELY( next->state==FD_PING_TRACKER_STATE_VALID_REFRESHING && next->valid_until_nanos<=now ) ) {
     485           3 :       ping_tracker->change_fn( ping_tracker->change_fn_ctx, next->identity_pubkey.b, next->address, now, FD_PING_TRACKER_CHANGE_TYPE_INACTIVE );
     486           3 :       switch( next->state ) {
     487           0 :         case FD_PING_TRACKER_STATE_UNPINGED:         ping_tracker->metrics->unpinged_cnt--; break;
     488           0 :         case FD_PING_TRACKER_STATE_INVALID:          ping_tracker->metrics->invalid_cnt--; break;
     489           0 :         case FD_PING_TRACKER_STATE_VALID:            ping_tracker->metrics->valid_cnt--; break;
     490           3 :         case FD_PING_TRACKER_STATE_VALID_REFRESHING: ping_tracker->metrics->refreshing_cnt--; break;
     491           0 :         default: FD_LOG_ERR(( "Unknown state %d", next->state ));
     492           3 :       }
     493           3 :       next->state = FD_PING_TRACKER_STATE_INVALID;
     494           3 :       next->valid_until_nanos = 0L;
     495           3 :       ping_tracker->metrics->invalid_cnt++;
     496           3 :     }
     497          21 :     next->next_ping_nanos = now+1L*1000L*1000L*1000L;
     498          21 :     *out_peer_pubkey      = next->identity_pubkey.b;
     499          21 :     *out_peer_address     = &next->address;
     500          21 :     *out_token            = next->ping_token;
     501          21 :     return 1;
     502          21 :   }
     503       75702 : }
     504             : 
     505             : fd_ping_tracker_metrics_t const *
     506           0 : fd_ping_tracker_metrics( fd_ping_tracker_t const * ping_tracker ) {
     507           0 :   return ping_tracker->metrics;
     508           0 : }

Generated by: LCOV version 1.14