LCOV - code coverage report
Current view: top level - choreo/tower - fd_tower_blocks.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 17 0.0 %
Date: 2026-03-19 18:19:27 Functions: 0 46 0.0 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_choreo_tower_fd_tower_blocks_h
       2             : #define HEADER_fd_src_choreo_tower_fd_tower_blocks_h
       3             : 
       4             : #include "../fd_choreo_base.h"
       5             : #include "fd_tower_voters.h"
       6             : 
       7             : /* fd_tower_blocks maintains tower-specific metadata about every block,
       8             :    such as what block_id we first replayed, what block_id we voted for,
       9             :    and what block_id was ultimately "duplicate confirmed".
      10             : 
      11             :    This is used by tower to make voting decisions, such as whether or
      12             :    not we can switch "forks".  In this context, a fork is a branch of a
      13             :    tree that extends from the root to a leaf.  For example:
      14             : 
      15             :         /-- 3-- 4  (A)
      16             :    1-- 2
      17             :         \-- 5      (B)
      18             : 
      19             :    Here, A and B are two different forks.  A is [1, 2, 3, 4] and B is
      20             :    [1, 2, 5], two branches that each extend from the root to a leaf.
      21             : 
      22             :    Note that even though fd_tower_blocks is block_id-aware, it does not
      23             :    use them for determining parentage.  Instead, parentage is based on
      24             :    slot numbers, so in cases of equivocation (duplicate blocks), tower
      25             :    will consider something an ancestor or descendant even if the block
      26             :    ids do not chain.
      27             : 
      28             :    This behavior intentionally mirrors the Agave logic implemented in
      29             :    `make_check_switch_threshold_decision`.  Essentially, tower is unable
      30             :    to distinguish duplicates because the vote account format (in which
      31             :    towers are stored) only stores slot numbers and not block_ids. */
      32             : 
      33             : struct fd_tower_blk {
      34             :   ulong     slot;               /* map key */
      35             :   ulong     parent_slot;        /* parent slot */
      36             :   ulong     epoch;              /* epoch of this slot */
      37             :   int       replayed;           /* whether we've replayed this slot yet */
      38             :   fd_hash_t replayed_block_id;  /* the block_id we _first_ replayed for this slot */
      39             :   int       voted;              /* whether we voted for this slot yet */
      40             :   fd_hash_t voted_block_id;     /* the block_id we voted on for this slot */
      41             :   int       confirmed;          /* whether this slot has been duplicate confirmed */
      42             :   fd_hash_t confirmed_block_id; /* the block_id that was duplicate confirmed */
      43             :   ulong     bank_idx;           /* pool idx of the bank as of this replayed block */
      44             : };
      45             : typedef struct fd_tower_blk fd_tower_blk_t;
      46             : 
      47             : #define MAP_NAME           fd_tower_blk
      48           0 : #define MAP_T              fd_tower_blk_t
      49           0 : #define MAP_KEY            slot
      50           0 : #define MAP_KEY_NULL       ULONG_MAX
      51           0 : #define MAP_KEY_INVAL(key) ((key)==ULONG_MAX)
      52             : #define MAP_MEMOIZE        0
      53             : #include "../../util/tmpl/fd_map_dynamic.c"
      54             : 
      55             : struct __attribute__((aligned(128UL))) fd_tower_blocks {
      56             :   fd_tower_blk_t * blk_map;
      57             : };
      58             : typedef struct fd_tower_blocks fd_tower_blocks_t;
      59             : 
      60             : FD_PROTOTYPES_BEGIN
      61             : 
      62             : FD_FN_CONST static inline ulong
      63           0 : fd_tower_blocks_align( void ) {
      64           0 :   return alignof(fd_tower_blocks_t);
      65           0 : }
      66             : 
      67             : FD_FN_CONST static inline ulong
      68           0 : fd_tower_blocks_footprint( ulong slot_max ) {
      69           0 :   int lg_slot_max = fd_ulong_find_msb( fd_ulong_pow2_up( slot_max ) ) + 1;
      70           0 :   return FD_LAYOUT_FINI(
      71           0 :     FD_LAYOUT_APPEND(
      72           0 :     FD_LAYOUT_APPEND(
      73           0 :     FD_LAYOUT_INIT,
      74           0 :       alignof(fd_tower_blocks_t), sizeof(fd_tower_blocks_t)             ),
      75           0 :       fd_tower_blk_align(),       fd_tower_blk_footprint( lg_slot_max ) ),
      76           0 :     fd_tower_blocks_align() );
      77           0 : }
      78             : 
      79             : /* fd_tower_blocks_new formats an unused memory region for use as a
      80             :    tower_blocks.  mem is a non-NULL pointer to this region in the local
      81             :    address space with the required footprint and alignment. */
      82             : 
      83             : void *
      84             : fd_tower_blocks_new( void * shmem,
      85             :                      ulong  slot_max,
      86             :                      ulong  seed );
      87             : 
      88             : /* fd_tower_blocks_join joins the caller to the tower_blocks. shblocks
      89             :    points to the first byte of the memory region backing the shblocks in
      90             :    the caller's address space.
      91             : 
      92             :    Returns a pointer in the local address space to blocks on success. */
      93             : 
      94             : fd_tower_blocks_t *
      95             : fd_tower_blocks_join( void * shblocks );
      96             : 
      97             : /* fd_tower_blocks_leave blocks a current local join.  Returns a pointer
      98             :    to the underlying shared memory region on success and NULL on failure
      99             :    (logs details).  Reasons for failure include blocks is NULL. */
     100             : 
     101             : void *
     102             : fd_tower_blocks_leave( fd_tower_blocks_t const * blocks );
     103             : 
     104             : /* fd_tower_blocks_delete unformats a memory region used as a blocks.
     105             :    Assumes only the local process is joined to the region.  Returns a
     106             :    pointer to the underlying shared memory region or NULL if used
     107             :    obviously in error (e.g. blocks is obviously not a blocks ...  logs
     108             :    details).  The ownership of the memory region is transferred to the
     109             :    caller. */
     110             : 
     111             : void *
     112             : fd_tower_blocks_delete( void * blocks );
     113             : 
     114             : /* fd_tower_is_slot_{ancestor,descendant} return 1 or 0 depending on
     115             :    whether the specified relationship is true in blocks. */
     116             : 
     117             : int
     118             : fd_tower_blocks_is_slot_ancestor( fd_tower_blocks_t * blocks,
     119             :                                   ulong               descendant_slot,
     120             :                                   ulong               ancestor_slot );
     121             : 
     122             : int
     123             : fd_tower_blocks_is_slot_descendant( fd_tower_blocks_t * blocks,
     124             :                                     ulong               ancestor_slot,
     125             :                                     ulong               descendant_slot );
     126             : 
     127             : /* fd_tower_blocks_lowest_common_ancestor returns the lowest common
     128             :    ancestor of slot1 and slot 2.  There is always an LCA in a valid
     129             :    tower_forks tree (the root). */
     130             : 
     131             : ulong
     132             : fd_tower_blocks_lowest_common_ancestor( fd_tower_blocks_t * blocks,
     133             :                                         ulong               slot1,
     134             :                                         ulong               slot2 );
     135             : 
     136             : /* fd_tower_blocks_canonical_block_id returns what we think to be the
     137             :    correct block id for a given slot, based on what we've observed.
     138             : 
     139             :    We prioritize in-order:
     140             :    1. the duplicate-confirmed block id
     141             :    2. our voted block id
     142             :    3. our first-replayed block id
     143             : 
     144             :    This is the canonical order because it reflects what we think is the
     145             :    "true" block id given the information we have.
     146             : 
     147             :    Agave behaves similarly, except they "purge" their replay bank hash
     148             :    so they're always comparing the confirmed block id */
     149             : 
     150             : fd_hash_t const *
     151             : fd_tower_blocks_canonical_block_id( fd_tower_blocks_t * blocks,
     152             :                                     ulong               slot );
     153             : 
     154             : /* fd_tower_blocks_{query,insert,remove} provide convenient wrappers for
     155             :    {querying,inserting,removing} into the underlying map. */
     156             : 
     157             : fd_tower_blk_t *
     158             : fd_tower_blocks_query( fd_tower_blocks_t * blocks,
     159             :                        ulong               slot );
     160             : 
     161             : fd_tower_blk_t *
     162             : fd_tower_blocks_insert( fd_tower_blocks_t * blocks,
     163             :                         ulong               slot,
     164             :                         ulong               parent_slot );
     165             : 
     166             : void
     167             : fd_tower_blocks_remove( fd_tower_blocks_t * blocks,
     168             :                         ulong               slot );
     169             : 
     170             : FD_PROTOTYPES_END
     171             : 
     172             : #endif /* HEADER_fd_src_choreo_tower_fd_tower_blocks_h */

Generated by: LCOV version 1.14