LCOV - code coverage report
Current view: top level - discof/replay - fd_replay_tile.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 3 13 23.1 %
Date: 2026-09-17 04:28:31 Functions: 0 0 -

          Line data    Source code
       1             : #ifndef HEADER_fd_src_discof_replay_fd_replay_tile_h
       2             : #define HEADER_fd_src_discof_replay_fd_replay_tile_h
       3             : 
       4             : /* Banks and Reasm
       5             :    =================
       6             : 
       7             :    OVERVIEW
       8             : 
       9             :    Reasm maintains a tree of FEC sets organized as a main tree (rooted
      10             :    at the published root) plus orphan trees.  Each FEC set in the
      11             :    connected tree may be associated with a bank via bank_idx, or be
      12             :    still unreplayed.  In general, reasm tries to approximate the state
      13             :    of banks as closely as possible.  It's inexact, because reasm is
      14             :    stored at the FEC unit, while banks are stored at the slot unit.
      15             : 
      16             :    When reasm delivers a FEC set (via fd_reasm_pop), the replay tile
      17             :    processes it by assigning it a bank.  If it's the first FEC in a
      18             :    slot (fec_set_idx==0), a new bank is provisioned from the parent's
      19             :    bank.  Subsequent FECs in the same slot inherit the bank_idx from
      20             :    the preceding FEC.  This means all FEC sets within a single slot
      21             :    share the same bank_idx, with the exception of equivocating FECs.
      22             : 
      23             :    PUBLISHING (ROOT ADVANCEMENT)
      24             : 
      25             :    When tower sends a new consensus root, replay advances the
      26             :    published root along the rooted fork as far as possible.  A block
      27             :    on the rooted fork is safe to prune when it and all minority fork
      28             :    subtrees branching from it have refcnt 0.  Publishing calls
      29             :    fd_reasm_publish to prune the reasm tree (and the store) of any
      30             :    FEC sets that do not descend from the new root.
      31             : 
      32             :    REASM EVICTION (POOL-PRESSURE EVICTION)
      33             : 
      34             :    When the reasm pool is nearly full (1 free element remaining) and a
      35             :    new FEC needs to be inserted, reasm runs its eviction policy to free
      36             :    space.  The eviction in general prioritizes orphans first, and then
      37             :    frontier slots that are incomplete.
      38             : 
      39             :    If eviction succeeds, the evicted chain is returned as a linked
      40             :    list of pool elements (removed from maps but still acquired in
      41             :    the pool).  The replay tile is responsible for:
      42             :      1. Publishing each evicted FEC to repair (REPLAY_SIG_REASM_EVICTED)
      43             :         so repair can re-request the data.
      44             :      2. Releasing each evicted element back to the reasm pool before
      45             :         the next insert.
      46             : 
      47             :    It's important to note that replay bank eviction is NOT coupled with
      48             :    reasm FEC eviction.  Reasm FEC eviction is triggered by the reasm pool
      49             :    being full, and is independent of the replay bank eviction.  Reasm
      50             :    FEC eviction is triggered by the reasm pool being full while banks
      51             :    eviction is triggered by the banks being full and the scheduler
      52             :    being drained.
      53             : 
      54             :    By evicting and publishing evicted FECs to repair, replay is
      55             :    attempting a "go-around" strategy to ensure progress is made even
      56             :    when memory pressure is high.  An evicted FEC - if valid - will be
      57             :    requested by repair and eventually re-delivered to replay, where
      58             :    hopefully by then there will be pool capacity to insert and replay
      59             :    the FEC.
      60             : 
      61             :    SNAPSHOT PRODUCTION
      62             : 
      63             :    Snapshot production is either periodically scheduled (driven by
      64             :    replay tile) or externally requested (through admin tile).  The
      65             :    replay tile stops compaction (via snapshot_sync) and rooting until
      66             :    the snapshot is created.
      67             : 
      68             :    ALPENGLOW
      69             : 
      70             :    Under alpenglow, the replay tile doesn't use the reasm, but rather
      71             :    relies on rotor to deliver FECs. Similar to reasm, rotor delivers
      72             :    FECs in replayable order, with no restrictions on interleaving
      73             :    between forks. Every delivered FEC is already in store. Alpenglow
      74             :    also introduces the double merkle root, which uniquely identifies
      75             :    each FEC set as part of one slot version. For equivocating slots, the
      76             :    block_id is known before delivery, and so replay can identify how to
      77             :    allocate banks in the equivocation case.
      78             : 
      79             :    Replay can rely on the fact that any new version of the slot
      80             :    (equivocations or not) is delivered from FEC 0 — blocks are never
      81             :    delivered starting mid-block. There is also at most one live delivery
      82             :    stream per logical block.  When the turbine version is being streamed
      83             :    in, the block_id is still unknown, but if a votor-driven version of
      84             :    the block arrives before the turbine copy is complete, the turbine
      85             :    copy is abandoned, and will never finish delivering to replay.
      86             : 
      87             :    Alpenglow simplifies eviction logic by removing the notion of reasm
      88             :    evictions.  Rotor is sized to protocol limits and will not have
      89             :    evictions; and thus can be relied on to always have all data since
      90             :    the root. Banks can still evict.  On an eviction, some context in the
      91             :    replayable chain of FECs is lost, and newer incoming FECs may be
      92             :    unlinked.  When this happens, replay sends a signal to rotor to send
      93             :    the next FEC with the full replayable path from root. Replay will
      94             :    need to drain the rotor dcache until it receives a FEC that is
      95             :    connected, and then resume normal replay.  It may need to drop FECs
      96             :    that have already been replayed, or send multiple signals to rotor to
      97             :    re-deliver. */
      98             : 
      99             : #include "../poh/fd_poh_tile.h"
     100             : #include "../../disco/tiles.h"
     101             : #include "../../choreo/votor/ag_cert.h"
     102             : #include "../../flamenco/alpenglow/fd_block_marker.h"
     103             : 
     104           0 : #define REPLAY_SIG_SLOT_COMPLETED (0)
     105           0 : #define REPLAY_SIG_SLOT_DEAD      (1)
     106          48 : #define REPLAY_SIG_ROOT_ADVANCED  (2)
     107          42 : #define REPLAY_SIG_RESET          (3)
     108           0 : #define REPLAY_SIG_BECAME_LEADER  (4)
     109           0 : #define REPLAY_SIG_OC_ADVANCED    (5)
     110           0 : #define REPLAY_SIG_TXN_EXECUTED   (6)
     111           0 : #define REPLAY_SIG_REASM_EVICTED  (7)
     112           0 : #define REPLAY_SIG_WFS_DONE       (8)
     113           0 : #define REPLAY_SIG_DROP_BANK_REF  (9)
     114           0 : #define REPLAY_SIG_SNAP_START     (10)
     115             : #define REPLAY_SIG_FINAL_CERT     (11)
     116           0 : #define REPLAY_SIG_LEADER_FOOTER  (12)
     117          72 : #define REPLAY_SIG_MISSING_FEC    (13)
     118             : 
     119             : /* replay_out mcache seq[i] slots */
     120             : #define REPLAY_SYNC_SEQ  (0UL) /* mcache->seq[0]: recently published seq no */
     121             : #define REPLAY_SYNC_SNAP (1UL) /* mcache->seq[1]: last published snap msg (acq-rel) */
     122             : 
     123             : /* fd_replay_slot_completed promises that it will deliver at most 2
     124             :    frags for a given slot (at most 2 equivocating blocks).  The first
     125             :    block is the first one we replay to completion.  The second version
     126             :    (if there is) is always the confirmed equivocating block.  This
     127             :    guarantee is provided by fd_reasm. */
     128             : 
     129             : struct fd_replay_slot_completed {
     130             :   ulong slot;
     131             :   ulong root_slot;
     132             :   ulong storage_slot;
     133             :   ulong epoch;
     134             :   ulong slot_in_epoch;
     135             :   ulong slots_per_epoch;
     136             :   ulong block_height;
     137             :   ulong parent_slot;
     138             : 
     139             :   fd_hash_t block_id;        /* block id (last FEC set's merkle root) of the slot received from replay */
     140             :   fd_hash_t parent_block_id; /* parent block id of the slot received from replay */
     141             :   fd_hash_t bank_hash;       /* bank hash of the slot received from replay */
     142             :   fd_hash_t block_hash;      /* last microblock header hash of slot received from replay */
     143             :   ulong     transaction_count;   /* since genesis */
     144             : 
     145             :   struct {
     146             :     double initial;
     147             :     double terminal;
     148             :     double taper;
     149             :     double foundation;
     150             :     double foundation_term;
     151             :   } inflation;
     152             : 
     153             :   struct {
     154             :     ulong lamports_per_uint8_year;
     155             :     double exemption_threshold;
     156             :     uchar burn_percent;
     157             :   } rent;
     158             : 
     159             :   /* Reference to the bank for this completed slot. */
     160             :   ulong bank_idx;
     161             :   ulong bank_seq;
     162             :   ulong parent_bank_idx;   /* parent bank's pool index (ULONG_MAX if none) */
     163             :   ulong parent_bank_seq;   /* parent bank's app-wide seq    (ULONG_MAX if none) */
     164             :   fd_accdb_fork_id_t accdb_fork_id;
     165             : 
     166             :   long first_fec_set_received_nanos;      /* timestamp when replay received the first fec of the slot from turbine or repair */
     167             :   long preparation_begin_nanos;           /* timestamp when replay began preparing the state to begin execution of the slot */
     168             :   long first_transaction_scheduled_nanos; /* timestamp when replay first sent a transaction to be executed */
     169             :   long last_transaction_finished_nanos;   /* timestamp when replay received the last execution completion */
     170             :   long completion_time_nanos;             /* timestamp when replay completed finalizing the slot and notified tower */
     171             : 
     172             :   int is_leader; /* whether we were leader for this slot */
     173             :   ulong identity_balance;
     174             : 
     175             :   /* since slot start, default ULONG_MAX */
     176             :   ulong vote_success;
     177             :   ulong vote_failed;
     178             :   ulong nonvote_success;
     179             :   ulong nonvote_failed;
     180             : 
     181             :   ulong transaction_fee;
     182             :   ulong priority_fee;
     183             :   ulong tips;
     184             :   ulong shred_cnt;
     185             : 
     186             :   int    voted;           /* our vote was in the reward cert this block carried */
     187             :   ushort voted_rank;      /* our rank in the reward slot's epoch, USHORT_MAX if we are not a voter */
     188             :   ulong  vote_balance;    /* ULONG_MAX if not sampled */
     189             :   ushort vote_commission; /* USHORT_MAX if not sampled */
     190             : 
     191             :   struct {
     192             :     ulong block_cost;
     193             :     ulong allocated_accounts_data_size;
     194             :     ulong block_cost_limit;
     195             :     ulong account_cost_limit;
     196             :     ulong pool_idx;
     197             :   } cost_tracker;
     198             : };
     199             : 
     200             : typedef struct fd_replay_slot_completed fd_replay_slot_completed_t;
     201             : 
     202             : struct fd_replay_slot_dead {
     203             :   ulong     slot;
     204             :   fd_hash_t block_id;
     205             : };
     206             : typedef struct fd_replay_slot_dead fd_replay_slot_dead_t;
     207             : 
     208             : struct fd_replay_oc_advanced {
     209             :   ulong slot;
     210             :   ulong bank_idx;
     211             :   ulong bank_seq;  /* fork discriminator of the optimistically-confirmed bank */
     212             : };
     213             : typedef struct fd_replay_oc_advanced fd_replay_oc_advanced_t;
     214             : 
     215             : struct fd_replay_root_advanced {
     216             :   ulong     bank_idx;
     217             :   ulong     bank_seq;  /* fork discriminator of the rooted bank */
     218             :   ulong     slot;
     219             :   fd_hash_t bank_hash;
     220             :   fd_hash_t block_id;
     221             : };
     222             : typedef struct fd_replay_root_advanced fd_replay_root_advanced_t;
     223             : 
     224             : struct fd_replay_txn_executed {
     225             :   fd_txn_p_t txn[ 1 ];
     226             :   int is_committable;
     227             :   int is_fees_only;
     228             :   int is_noop;
     229             :   int txn_err;
     230             :   int is_simple_vote;
     231             : 
     232             :   /* LONG_MAX if stage was not reached */
     233             :   long  tick_parsed;
     234             :   long  tick_sigverify_disp;
     235             :   long  tick_sigverify_done;
     236             :   long  tick_exec_disp;
     237             :   long  tick_exec_done;
     238             :   long  tick_load_start;
     239             :   long  tick_check_start;
     240             :   long  tick_exec_start;
     241             :   long  tick_commit_start;
     242             :   long  tick_commit_end;
     243             : 
     244             :   ulong slot;
     245             :   ulong bank_seq;
     246             :   ulong index_in_slot;
     247             :   ulong exec_tile_idx;
     248             :   ulong sigverify_exec_tile_idx;
     249             :   uint  compute_units_consumed; /* possibly zero if is_committable is zero */
     250             :   ulong max_compute_units;
     251             :   ulong transaction_fee;
     252             :   ulong priority_fee;
     253             :   ulong tips;
     254             : };
     255             : typedef struct fd_replay_txn_executed fd_replay_txn_executed_t;
     256             : 
     257             : struct fd_replay_fec_evicted {
     258             :   fd_hash_t mr;
     259             :   ulong     slot;
     260             :   uint      fec_set_idx;
     261             :   ulong     bank_idx;
     262             : };
     263             : typedef struct fd_replay_fec_evicted fd_replay_fec_evicted_t;
     264             : 
     265             : /* Only rpc needs to consume this message since tower holds refcnts
     266             :    transiently and will drop them without a further trigger from the
     267             :    replay tile and the resolv tile holds onto a bank reference based on
     268             :    the root, which will never be forced to drop its bank reference. */
     269             : struct fd_replay_drop_bank_ref {
     270             :   ulong bank_idx;
     271             : };
     272             : typedef struct fd_replay_drop_bank_ref fd_replay_drop_bank_ref_t;
     273             : 
     274             : /* The replay tile broadcasts fd_replay_snap_start_t
     275             :    (REPLAY_SIG_SNAP_START) just before starting snapshot creation. */
     276             : 
     277             : struct fd_replay_snap_start {
     278             :   ulong bank_idx;
     279             :   ulong base_slot;
     280             :   ulong slot; /* ==base_slot implies full snapshot, else incremental */
     281             : };
     282             : typedef struct fd_replay_snap_start fd_replay_snap_start_t;
     283             : 
     284             : /* fd_replay_final_cert carries the finalization cert parsed out of an
     285             :    Alpenglow block footer. */
     286             : struct fd_replay_final_cert {
     287             :   ulong     slot;     /* the block whose footer carried the cert */
     288             :   uint      cert_cnt;
     289             :   ag_cert_t certs[ 2 ];
     290             : };
     291             : typedef struct fd_replay_final_cert fd_replay_final_cert_t;
     292             : 
     293             : struct fd_replay_leader_footer {
     294             :   ulong             slot;
     295             :   fd_block_footer_t footer;
     296             : };
     297             : typedef struct fd_replay_leader_footer fd_replay_leader_footer_t;
     298             : 
     299             : union fd_replay_message {
     300             :   fd_replay_slot_completed_t  slot_completed;
     301             :   fd_replay_slot_dead_t       slot_dead;
     302             :   fd_replay_root_advanced_t   root_advanced;
     303             :   fd_replay_oc_advanced_t     oc_advanced;
     304             :   fd_poh_reset_t              reset;
     305             :   fd_became_leader_t          became_leader;
     306             :   fd_replay_txn_executed_t    txn_executed;
     307             :   fd_replay_fec_evicted_t     reasm_evicted;
     308             :   fd_replay_drop_bank_ref_t   drop_bank_ref;
     309             :   fd_replay_leader_footer_t   leader_footer;
     310             : };
     311             : 
     312             : typedef union fd_replay_message fd_replay_message_t;
     313             : 
     314             : #endif /* HEADER_fd_src_discof_replay_fd_replay_tile_h */

Generated by: LCOV version 1.14