LCOV - code coverage report
Current view: top level - choreo/rotor - fd_rotor_strat.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 23 0.0 %
Date: 2026-10-22 18:10:43 Functions: 0 3 0.0 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_choreo_rotor_fd_rotor_strat_h
       2             : #define HEADER_fd_src_choreo_rotor_fd_rotor_strat_h
       3             : 
       4             : /* fd_rotor_strat picks the repair peer for each request.  It does no
       5             :    I/O: the rotor tile feeds it contact infos, epoch stakes and request
       6             :    outcomes.  Peers sit in slots by stake rank, unstaked last, and in
       7             :    latency buckets by srtt+rttvar/4.  A pick takes the fastest
       8             :    bucket's cheaper of the next two peers by srtt*(inflight+1), the
       9             :    cursor advancing one peer so every peer meets every neighbor,
      10             :    every FD_ROTOR_STRAT_EXPLORE-th pick tries an unmeasured peer first,
      11             :    and a request is hedged after srtt+4*rttvar (RFC 6298).  It also
      12             :    estimates each leader's turbine time, which decides how long a
      13             :    missing FEC set waits for turbine before it is repaired. */
      14             : 
      15             : #include "../../flamenco/gossip/fd_gossip_message.h"
      16             : #include "../../flamenco/stakes/fd_stake_weight.h"
      17             : 
      18           0 : #define FD_ROTOR_STRAT_PEER_MAX     FD_CONTACT_INFO_TABLE_SIZE
      19           0 : #define FD_ROTOR_STRAT_INFLIGHT_MAX (8U)
      20           0 : #define FD_ROTOR_STRAT_EXPLORE      (16UL) /* every 16th pick tries an unmeasured peer first */
      21           0 : #define FD_ROTOR_STRAT_ESCAPE_TOP   (100UL) /* an escape pick draws only from the top stake ranks, small stakers are often far or offline */
      22           0 : #define FD_ROTOR_STRAT_EXPIRED_MAX  (32U)  /* requests in a row a peer leaves unanswered before it is banned */
      23           0 : #define FD_ROTOR_STRAT_BYID_MAX     (4U)   /* by-id requests in a row, other replies aside */
      24           0 : #define FD_ROTOR_STRAT_HEDGE_NS     (100L*1000000L) /* hedge time of an unmeasured peer, and the longest any request waits for a retry */
      25           0 : #define FD_ROTOR_STRAT_EAGER_MIN_NS (20L*1000000L)
      26           0 : #define FD_ROTOR_STRAT_EAGER_MAX_NS (250L*1000000L)  /* also the eager wait until turbine is measured */
      27           0 : #define FD_ROTOR_STRAT_TURBINE_MIN  (8UL)            /* samples before a leader's own estimate is used */
      28             : 
      29             : /* Latency buckets, fastest first.  UNMEASURED holds peers with no rtt
      30             :    sample yet. */
      31             : 
      32           0 : #define FD_ROTOR_STRAT_BUCKET_25MS       (0UL)
      33           0 : #define FD_ROTOR_STRAT_BUCKET_50MS       (1UL)
      34           0 : #define FD_ROTOR_STRAT_BUCKET_100MS      (2UL)
      35           0 : #define FD_ROTOR_STRAT_BUCKET_200MS      (3UL)
      36           0 : #define FD_ROTOR_STRAT_BUCKET_SLOW       (4UL)
      37           0 : #define FD_ROTOR_STRAT_BUCKET_UNMEASURED (5UL)
      38           0 : #define FD_ROTOR_STRAT_BUCKET_CNT        (6UL)
      39             : 
      40             : struct fd_rotor_strat_peer {
      41             :   fd_pubkey_t id_key;
      42             :   ulong       next;           /* map chain */
      43             :   uint        ip4;            /* 0 while gossip has no address for it */
      44             :   ushort      port;
      45             :   uint        inflight;       /* requests in flight */
      46             :   ulong       bucket;         /* the bucket of its rtt */
      47             :   long        srtt;           /* smoothed round trip in ns, 0 if never measured */
      48             :   long        rttvar;         /* its mean deviation */
      49             :   long        ping_ts;        /* last ping, 0 if none */
      50             :   long        ban_ts;         /* skipped until this time */
      51             :   uint        expired_cnt;    /* requests in a row it left unanswered */
      52             :   uint        byid_expired_cnt; /* by-id requests in a row it left unanswered */
      53             :   long        turbine_srtt;   /* as leader, smoothed time from a FEC set's first shred to complete, 0 if never measured */
      54             :   long        turbine_rttvar; /* its mean deviation */
      55             :   ulong       turbine_cnt;    /* its samples */
      56             : };
      57             : typedef struct fd_rotor_strat_peer fd_rotor_strat_peer_t;
      58             : 
      59             : #define MAP_NAME               fd_rotor_strat_peer_map
      60             : #define MAP_ELE_T              fd_rotor_strat_peer_t
      61             : #define MAP_KEY_T              fd_pubkey_t
      62           0 : #define MAP_KEY                id_key
      63           0 : #define MAP_KEY_EQ(k0,k1)      (!memcmp( (k0), (k1), sizeof(fd_pubkey_t) ))
      64           0 : #define MAP_KEY_HASH(key,seed) fd_ulong_hash( (seed)^FD_LOAD( ulong, (key)->uc ) )
      65             : #include "../../util/tmpl/fd_map_chain.c"
      66             : 
      67             : #define SET_NAME fd_rotor_strat_set
      68             : #define SET_MAX  FD_ROTOR_STRAT_PEER_MAX
      69             : #include "../../util/tmpl/fd_set.c"
      70             : 
      71             : /* Slots and their map are double buffered so the epoch re-sort can
      72             :    read the old order while it builds the new one. */
      73             : 
      74             : struct fd_rotor_strat_order {
      75             :   fd_rotor_strat_peer_t *     peers; /* FD_ROTOR_STRAT_PEER_MAX slots */
      76             :   fd_rotor_strat_peer_map_t * map;
      77             : };
      78             : typedef struct fd_rotor_strat_order fd_rotor_strat_order_t;
      79             : 
      80             : struct fd_rotor_strat_private {
      81             :   fd_rotor_strat_order_t cur;
      82             :   fd_rotor_strat_order_t old;
      83             :   ulong                  staked_cnt;
      84             :   uint *                 free;     /* unstaked slots not in use, a stack */
      85             :   ulong                  free_cnt;
      86             :   fd_rotor_strat_set_t * buckets[ FD_ROTOR_STRAT_BUCKET_CNT ];
      87             :   ulong                  cursor [ FD_ROTOR_STRAT_BUCKET_CNT ]; /* slot last picked in each bucket */
      88             :   ulong                  pick_cnt;
      89             :   ulong                  seed;
      90             :   ulong                  epoch_cnt;
      91             :   long                   turbine_srtt;   /* over all leaders */
      92             :   long                   turbine_rttvar;
      93             : };
      94             : typedef struct fd_rotor_strat_private fd_rotor_strat_t;
      95             : 
      96             : FD_PROTOTYPES_BEGIN
      97             : 
      98             : FD_FN_CONST ulong
      99             : fd_rotor_strat_align( void );
     100             : 
     101             : FD_FN_CONST ulong
     102             : fd_rotor_strat_footprint( void );
     103             : 
     104             : void *
     105             : fd_rotor_strat_new( void * shmem,
     106             :                     ulong  seed );
     107             : 
     108             : fd_rotor_strat_t *
     109             : fd_rotor_strat_join( void * shstrat );
     110             : 
     111             : /* fd_rotor_strat_epoch_advanced re-sorts the peers by the epoch's
     112             :    identity stakes, ids sorted by stake descending.  Peers keep their
     113             :    address, rtt and ping state.  Invalidates peer pointers. */
     114             : 
     115             : void
     116             : fd_rotor_strat_epoch_advanced( fd_rotor_strat_t *        strat,
     117             :                                fd_stake_weight_t const * ids,
     118             :                                ulong                     id_cnt );
     119             : 
     120             : /* fd_rotor_strat_contact_info_updated records a peer's repair address
     121             :    from gossip.  A new address resets its rtt and ping.  A new unstaked
     122             :    peer is dropped if every unstaked slot is in use. */
     123             : 
     124             : void
     125             : fd_rotor_strat_contact_info_updated( fd_rotor_strat_t *  strat,
     126             :                                      fd_pubkey_t const * id_key,
     127             :                                      uint                ip4,
     128             :                                      ushort              port );
     129             : 
     130             : /* fd_rotor_strat_contact_info_removed forgets a peer's address.  A
     131             :    staked peer keeps its slot. */
     132             : 
     133             : void
     134             : fd_rotor_strat_contact_info_removed( fd_rotor_strat_t *  strat,
     135             :                                      fd_pubkey_t const * id_key );
     136             : 
     137             : /* fd_rotor_strat_pick returns the peer for a request and counts it in
     138             :    flight, or NULL if none is available.  staked restricts it to staked
     139             :    peers.  The fastest bucket with an available peer wins; within it the
     140             :    cheaper of the next two peers after its cursor, in stake order.
     141             :    Banned peers are skipped, and slot avoid unless no other peer is
     142             :    available (ULONG_MAX for none). */
     143             : 
     144             : fd_rotor_strat_peer_t *
     145             : fd_rotor_strat_pick( fd_rotor_strat_t * strat,
     146             :                      long               now,
     147             :                      int                staked,
     148             :                      ulong              avoid );
     149             : 
     150             : /* fd_rotor_strat_pick_staked returns a staked peer at random among the
     151             :    top FD_ROTOR_STRAT_ESCAPE_TOP stake ranks, higher ranks likelier,
     152             :    other than slot avoid, for a request the bucket
     153             :    order keeps failing, and counts it in flight.  r is a random number.
     154             :    NULL if none is available. */
     155             : 
     156             : fd_rotor_strat_peer_t *
     157             : fd_rotor_strat_pick_staked( fd_rotor_strat_t * strat,
     158             :                             long               now,
     159             :                             ulong              avoid,
     160             :                             ulong              r );
     161             : 
     162             : /* fd_rotor_strat_request_done ends a request picked from id_key with a
     163             :    reply that verified.  rtt is its round trip, byid if it answered a
     164             :    by-id request. */
     165             : 
     166             : void
     167             : fd_rotor_strat_request_done( fd_rotor_strat_t *  strat,
     168             :                              fd_pubkey_t const * id_key,
     169             :                              long                rtt,
     170             :                              int                 byid );
     171             : 
     172             : /* fd_rotor_strat_request_failed ends a request picked from id_key with
     173             :    a reply that failed to verify, or no reply at all, and skips the peer
     174             :    until ban_ts.  It takes no rtt sample. */
     175             : 
     176             : void
     177             : fd_rotor_strat_request_failed( fd_rotor_strat_t *  strat,
     178             :                                fd_pubkey_t const * id_key,
     179             :                                long                ban_ts );
     180             : 
     181             : /* fd_rotor_strat_request_expired ends a request picked from id_key that
     182             :    a live peer should have answered but did not.  It takes no rtt
     183             :    sample; after FD_ROTOR_STRAT_EXPIRED_MAX in a row with no reply, or
     184             :    FD_ROTOR_STRAT_BYID_MAX by-id ones (byid) with no by-id reply, the
     185             :    peer is skipped until ban_ts.  Returns 1 if the by-id run banned it,
     186             :    -1 if the run of any kind did, 0 if not banned. */
     187             : 
     188             : int
     189             : fd_rotor_strat_request_expired( fd_rotor_strat_t *  strat,
     190             :                                 fd_pubkey_t const * id_key,
     191             :                                 long                ban_ts,
     192             :                                 int                 byid );
     193             : 
     194             : /* fd_rotor_strat_turbine_done records t, the time from a FEC set's
     195             :    first shred to its completion, for the slot's leader id_key. */
     196             : 
     197             : void
     198             : fd_rotor_strat_turbine_done( fd_rotor_strat_t *  strat,
     199             :                              fd_pubkey_t const * id_key,
     200             :                              long                t );
     201             : 
     202             : /* fd_rotor_strat_eager_ns returns how long a missing FEC set of
     203             :    leader id_key waits for turbine before it is repaired: about the p95
     204             :    of its turbine time, from all leaders until it has
     205             :    FD_ROTOR_STRAT_TURBINE_MIN samples.  id_key may be NULL. */
     206             : 
     207             : long
     208             : fd_rotor_strat_eager_ns( fd_rotor_strat_t *  strat,
     209             :                          fd_pubkey_t const * id_key );
     210             : 
     211             : /* fd_rotor_strat_hedge_ns returns how long a request to peer may be
     212             :    outstanding before it is hedged to another peer. */
     213             : 
     214             : static inline long
     215           0 : fd_rotor_strat_hedge_ns( fd_rotor_strat_peer_t const * peer ) {
     216           0 :   return fd_long_if( !!peer->srtt, peer->srtt+4L*peer->rttvar, FD_ROTOR_STRAT_HEDGE_NS );
     217           0 : }
     218             : 
     219             : fd_rotor_strat_peer_t *
     220             : fd_rotor_strat_query( fd_rotor_strat_t *  strat,
     221             :                       fd_pubkey_t const * id_key );
     222             : 
     223             : /* fd_rotor_strat_slot_remap returns the slot now held by the peer that
     224             :    held slot idx before the last epoch re-sort, or ULONG_MAX if it is
     225             :    gone or idx is ULONG_MAX. */
     226             : 
     227             : ulong
     228             : fd_rotor_strat_slot_remap( fd_rotor_strat_t const * strat,
     229             :                            ulong                    idx );
     230             : 
     231             : FD_PROTOTYPES_END
     232             : 
     233             : #endif /* HEADER_fd_src_choreo_rotor_fd_rotor_strat_h */

Generated by: LCOV version 1.14