LCOV - code coverage report
Current view: top level - flamenco/gossip - fd_ping_tracker.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 252 299 84.3 %
Date: 2026-09-17 04:28:31 Functions: 13 14 92.9 %

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

Generated by: LCOV version 1.14