LCOV - code coverage report
Current view: top level - flamenco/gossip - fd_ping_tracker.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 277 308 89.9 %
Date: 2026-11-12 04:25:03 Functions: 17 17 100.0 %

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

Generated by: LCOV version 1.14