LCOV - code coverage report
Current view: top level - flamenco/gossip - fd_gossip_purged.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 8 8 100.0 %
Date: 2026-10-31 04:25:24 Functions: 1 18 5.6 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_gossip_fd_gossip_purged_h
       2             : #define HEADER_fd_src_flamenco_gossip_fd_gossip_purged_h
       3             : 
       4             : #include "../fd_flamenco_base.h"
       5             : #include "../../util/fd_hash32.h"
       6             : 
       7             : /* fd_gossip_purged implements the "purged" side-table of the CRDS.
       8             :    When a CRDS entry is overridden by a newer value, fails to insert
       9             :    (stale), or is dropped because the origin has no known contact info,
      10             :    its hash is recorded here so it can appear in bloom filters and
      11             :    prevent peers from re-sending it.
      12             : 
      13             :    There are three mutually exclusive lists:
      14             : 
      15             :      - replaced_dlist:        Entries replaced by a newer value.  Expire in 60s.
      16             :      - failed_inserts_dlist:  Entries that failed to upsert.     Expire in 60s.
      17             :      - no_contact_info_dlist: Entries dropped for missing CI.    Expire in ~2 days.
      18             : 
      19             :    All three lists share a single pool, a map keyed by the first 8
      20             :    bytes of the value hash (so a hash is recorded once) and an hset of
      21             :    the hashes so they can be iterated together when building
      22             :    pull-request bloom filters. */
      23             : 
      24             : struct fd_gossip_purged_metrics {
      25             :   ulong purged_cnt;
      26             :   ulong purged_expired_cnt;
      27             :   ulong purged_evicted_cnt;
      28             : };
      29             : 
      30             : typedef struct fd_gossip_purged_metrics fd_gossip_purged_metrics_t;
      31             : 
      32             : struct fd_crds_purged {
      33             :   uchar hash[ 32UL ];
      34             : 
      35             :   struct {
      36             :     uint next;
      37             :   } pool;
      38             : 
      39             :   struct {
      40             :     ulong hash_prefix;
      41             :     uint  next;
      42             :     uint  prev;
      43             :   } map;
      44             : 
      45             :   /* We keep a linked list of purged values sorted by insertion time.
      46             :      The time used here is our node's wallclock.
      47             : 
      48             :      There are actually three (mutually exclusive) lists that reuse the
      49             :      same pointers here: one for "replaced" entries that expire in 60s,
      50             :      one for "failed_inserts" that expire after 60s, and one for
      51             :      "no_contact_info" entries that expire after 2 days. */
      52             :   struct {
      53             :     long  wallclock_nanos;
      54             :     uint  next;
      55             :     uint  prev;
      56             :   } expire;
      57             : 
      58             :   /* For no_contact_info entries, we also track the origin pubkey and
      59             :      chain entries by origin so they can all be drained when we learn
      60             :      the contact info for that pubkey. */
      61             :   fd_pubkey_t origin;
      62             :   struct {
      63             :     uint next;
      64             :     uint prev;
      65             :   } nci_map;
      66             : };
      67             : 
      68             : typedef struct fd_crds_purged fd_crds_purged_t;
      69             : 
      70             : FD_STATIC_ASSERT( sizeof(fd_crds_purged_t)==112UL, purged_entry_footprint );
      71             : 
      72             : struct fd_gossip_purged_private;
      73             : typedef struct fd_gossip_purged_private fd_gossip_purged_t;
      74             : 
      75             : struct fd_gossip_hset_private;
      76             : typedef struct fd_gossip_hset_private fd_gossip_hset_t;
      77             : 
      78          60 : #define FD_GOSSIP_PURGED_ALIGN 128UL
      79          18 : #define FD_GOSSIP_PURGED_MAGIC (0xf17eda2c39070ed0UL) /* firedancer purged v0 */
      80             : 
      81             : static inline void
      82             : fd_gossip_purged_generate_masks( ulong   mask,
      83             :                                  uint    mask_bits,
      84             :                                  ulong * start_mask,
      85       23808 :                                  ulong * end_mask ) {
      86             :   /* Agave defines the mask as a ulong with the top mask_bits bits set
      87             :      to the desired prefix and all other bits set to 1. */
      88       23808 :   FD_TEST( mask_bits<64U );
      89       23808 :   ulong range = fd_ulong_mask( 0U, (int)(63U-mask_bits) );
      90       23808 :   *start_mask = mask & ~range;
      91       23808 :   *end_mask   = mask | range;
      92       23808 : }
      93             : 
      94             : FD_PROTOTYPES_BEGIN
      95             : 
      96             : FD_FN_CONST ulong
      97             : fd_gossip_purged_align( void );
      98             : 
      99             : FD_FN_CONST ulong
     100             : fd_gossip_purged_footprint( ulong purged_max );
     101             : 
     102             : void *
     103             : fd_gossip_purged_new( void *     shmem,
     104             :                       fd_rng_t * rng,
     105             :                       ulong      purged_max );
     106             : 
     107             : fd_gossip_purged_t *
     108             : fd_gossip_purged_join( void * shpurged );
     109             : 
     110             : fd_gossip_purged_metrics_t const *
     111             : fd_gossip_purged_metrics( fd_gossip_purged_t const * purged );
     112             : 
     113             : /* fd_gossip_purged_len returns the number of entries currently tracked
     114             :    in the purged pool (across all three dlists). */
     115             : 
     116             : ulong
     117             : fd_gossip_purged_len( fd_gossip_purged_t const * purged );
     118             : 
     119             : /* fd_gossip_purged_hset returns the dense index of the hashes of all
     120             :    tracked entries, see fd_gossip_hset.h. */
     121             : 
     122             : fd_gossip_hset_t const *
     123             : fd_gossip_purged_hset( fd_gossip_purged_t const * purged );
     124             : 
     125             : /* fd_gossip_purged_insert_replaced records a hash that was purged
     126             :    because a newer CRDS value replaced it. */
     127             : 
     128             : void
     129             : fd_gossip_purged_insert_replaced( fd_gossip_purged_t * purged,
     130             :                                   uchar const *        hash,
     131             :                                   long                 now );
     132             : 
     133             : /* fd_gossip_purged_insert_failed_insert records a hash that failed to
     134             :    upsert the CRDS table (e.g. stale or lost a tiebreaker). */
     135             : 
     136             : void
     137             : fd_gossip_purged_insert_failed_insert( fd_gossip_purged_t * purged,
     138             :                                        uchar const *        hash,
     139             :                                        long                 now );
     140             : 
     141             : /* fd_gossip_purged_insert_no_contact_info records a hash that was
     142             :    dropped because the origin pubkey has no known contact info.  The
     143             :    hash is indexed like any other purged entry (so it appears in bloom
     144             :    filters) and chained per pubkey so all entries for a given origin
     145             :    can be drained when we learn their contact info. */
     146             : 
     147             : void
     148             : fd_gossip_purged_insert_no_contact_info( fd_gossip_purged_t * purged,
     149             :                                          uchar const *        origin,
     150             :                                          uchar const *        hash,
     151             :                                          long                 now );
     152             : 
     153             : /* fd_gossip_purged_drain_no_contact_info removes all no_contact_info
     154             :    entries associated with the given origin pubkey from the purged
     155             :    table, no_contact_info dlist, and per-pubkey chain.  This causes
     156             :    those hashes to disappear from bloom filters, so peers will re-send
     157             :    the corresponding CRDS values in future pull responses. */
     158             : 
     159             : void
     160             : fd_gossip_purged_drain_no_contact_info( fd_gossip_purged_t * purged,
     161             :                                         uchar const *        origin );
     162             : 
     163             : /* fd_gossip_purged_expire removes entries that have exceeded their
     164             :    expiry window from each of the three dlists. */
     165             : 
     166             : void
     167             : fd_gossip_purged_expire( fd_gossip_purged_t * purged,
     168             :                          long                 now );
     169             : 
     170             : FD_PROTOTYPES_END
     171             : 
     172             : #endif /* HEADER_fd_src_flamenco_gossip_fd_gossip_purged_h */

Generated by: LCOV version 1.14