LCOV - code coverage report
Current view: top level - discof/replay - fd_replay_tile_private.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 7 0.0 %
Date: 2026-10-22 18:10:43 Functions: 0 0 -

          Line data    Source code
       1             : #ifndef HEADER_fd_src_discof_replay_fd_replay_tile_private_h
       2             : #define HEADER_fd_src_discof_replay_fd_replay_tile_private_h
       3             : 
       4             : #include "fd_vote_tracker.h"
       5             : #include "../../disco/fd_clock_tile.h"
       6             : #include "../../disco/store/fd_store.h"
       7             : #include "../../disco/bundle/fd_bundle_crank.h"
       8             : #include "../../disco/keyguard/fd_keyswitch.h"
       9             : #include "../../disco/node_info/fd_node_info.h"
      10             : #include "../../disco/wait_info/fd_wait_info.h"
      11             : #include "../../discof/poh/fd_poh.h"
      12             : #include "../../discof/rotor/fd_rotor_tile.h"
      13             : #include "../../discof/replay/fd_sched.h"
      14             : #include "../../discof/votor/fd_votor_tile.h"
      15             : #include "../../flamenco/capture/fd_capture_ctx.h"
      16             : #include "../../flamenco/genesis/fd_genesis_parse.h"
      17             : #include "../../flamenco/leaders/fd_multi_epoch_leaders.h"
      18             : #include "../../flamenco/progcache/fd_progcache.h"
      19             : #include "../../flamenco/alpenglow/fd_alpenglow.h"
      20             : #include "../../flamenco/runtime/fd_bank.h"
      21             : #include "../../flamenco/runtime/fd_txncache.h"
      22             : #include "../../flamenco/runtime/tests/fd_dump_pb.h"
      23             : #include "../../disco/events/generated/fd_event_gen.h"
      24             : #include "../../util/fd_hash32.h"
      25             : #include "../../ballet/bmtree/fd_bmtree.h"
      26             : #include <stdio.h>
      27             : 
      28             : struct fd_replay_in_link {
      29             :   fd_wksp_t * mem;
      30             :   ulong       chunk0;
      31             :   ulong       wmark;
      32             :   ulong       mtu;
      33             : };
      34             : 
      35             : typedef struct fd_replay_in_link fd_replay_in_link_t;
      36             : 
      37             : struct fd_replay_out_link {
      38             :   ulong       idx;
      39             :   fd_wksp_t * mem;
      40             :   ulong       chunk0;
      41             :   ulong       wmark;
      42             :   ulong       chunk;
      43             : };
      44             : 
      45             : typedef struct fd_replay_out_link fd_replay_out_link_t;
      46             : 
      47             : struct fd_block_id_ele {
      48             :   fd_hash_t     latest_mr;  /* merkle root of the latest observed FEC set.  This is NEVER the
      49             :                                block id: on completion it holds the last FEC set's merkle root,
      50             :                                which the next block's shreds chain off (the cmr). */
      51             :   fd_hash_t     dmr;        /* block id (double merkle root).  Only valid once block_id_seen is
      52             :                                set. */
      53             :   ag_block_id_t block_info; /* key for the compound map */
      54             :   uint          latest_fec_idx;
      55             :   int           block_id_seen;
      56             :   ulong         slot;
      57             :   ulong         bank_seq;
      58             :   ulong         ag_next_;
      59             :   uint          fec_cnt;
      60             : };
      61             : typedef struct fd_block_id_ele fd_block_id_ele_t;
      62             : 
      63             : struct fd_reception_stats {
      64             :   ulong                     bank_seq; /* alpenglow guard: valid iff ==bank->bank_seq */
      65             :   uint                      fec_set_idx;
      66             : 
      67             :   union {
      68             :     fd_rotor_fec_metrics_t rotor;
      69             :   } metrics;
      70             : };
      71             : typedef struct fd_reception_stats fd_reception_stats_t;
      72             : 
      73           0 : #define FD_REPLAY_TXN_TIMING_SLOTS (16UL)
      74             : 
      75             : struct fd_replay_txn_timing {
      76             :   long received_ns;
      77             : 
      78             :   long parsed_ticks;
      79             :   long sigverify_disp_ticks;
      80             :   long sigverify_done_ticks;
      81             :   long exec_disp_ticks;
      82             :   long exec_done_ticks;
      83             : };
      84             : 
      85             : typedef struct fd_replay_txn_timing fd_replay_txn_timing_t;
      86             : 
      87             : struct fd_replay_txn_timing_slot {
      88             :   struct {
      89             :     ulong next;
      90             :   } pool;
      91             : 
      92             :   ulong cnt;
      93             : };
      94             : 
      95             : typedef struct fd_replay_txn_timing_slot fd_replay_txn_timing_slot_t;
      96             : 
      97             : #define POOL_NAME fd_timing_slot_pool
      98           0 : #define POOL_T    fd_replay_txn_timing_slot_t
      99           0 : #define POOL_NEXT pool.next
     100             : #include "../../util/tmpl/fd_pool.c"
     101             : 
     102             : /* fd_ag_block_id_map indexes the same fd_block_id_ele_t array by the
     103             :    compound {slot, block_id} key.  A block that is still being received
     104             :    through turbing is keyed by {slot, 0}: the DMR is only known once the
     105             :    slot-complete FEC arrives. FECs of a block thus resolve their bank
     106             :    via {slot, 0} without any per-FEC re-keying; on slot complete the
     107             :    entry is re-keyed once to the real {slot, block_id}.
     108             : 
     109             :    For blocks that were repaired due to a votor block id event, the
     110             :    block id is known at the slot start.  So the entry is keyed by {slot,
     111             :    block_id} from the start and never rekeyed. */
     112             : 
     113             : #define MAP_NAME               fd_ag_block_id_map
     114             : #define MAP_ELE_T              fd_block_id_ele_t
     115             : #define MAP_KEY_T              ag_block_id_t
     116           0 : #define MAP_KEY                block_info
     117           0 : #define MAP_NEXT               ag_next_
     118           0 : #define MAP_KEY_EQ(k0,k1)      (ag_block_id_eq( (k0), (k1) ))
     119           0 : #define MAP_KEY_HASH(key,seed) (fd_hash( (seed), (key), sizeof(ag_block_id_t) ))
     120             : #include "../../util/tmpl/fd_map_chain.c"
     121             : 
     122             : FD_STATIC_ASSERT( FD_EVENT_BLOCK_COMPLETED_TXN_TIMING_MAX>=FD_MAX_TXN_PER_SLOT, txn_timing_ships_full_block );
     123             : 
     124             : struct fd_replay_tile {
     125             :   fd_wksp_t * wksp;
     126             : 
     127             :   uint rng_seed;
     128             :   fd_rng_t rng[ 1 ];
     129             : 
     130             :   fd_clock_tile_t clock[1];
     131             : 
     132             :   fd_progcache_join_t progcache[1];
     133             : 
     134             :   fd_accdb_t *    accdb;
     135             :   fd_txncache_t * txncache;
     136             :   fd_store_t *    store;
     137             :   fd_store_map_t  map_join[1];
     138             :   int             store_disk_fd;
     139             :   fd_banks_t *    banks;
     140             : 
     141             :   /* This flag is 1 If we have seen a vote signature that our node has
     142             :      sent out get rooted at least one time.  The value is 0 otherwise.
     143             :      We can't become leader and pack blocks until this flag has been
     144             :      set.  This parallels the Agave 'has_new_vote_been_rooted'. */
     145             :   int identity_vote_rooted;
     146             :   int wait_for_vote_to_start_leader; /* FD_BOOLAU_{FALSE,TRUE,AUTO} */
     147             : 
     148             :   /* vote_account_staked is 1 if stake was delegated to our vote
     149             :      account at boot.  vote_account_inadmissible is 1 while our staked
     150             :      vote account fails the admission ticket filter, or passes it but
     151             :      has not yet been admitted at an epoch boundary. */
     152             :   int vote_account_staked;
     153             :   int vote_account_inadmissible;
     154             : 
     155             :   /* wfs_enabled is 1 if the validator is booted in
     156             :      wait_for_supermajority mode. In this mode replay (and, by extension,
     157             :      downstream consumers) is not allowed to make progress until 80% of
     158             :      the cluster has published their ContactInfo in Gossip with a
     159             :      shred version matching expected_shred_version. When this happens,
     160             :      wfs_complete will be set to 1. */
     161             :   int   wfs_enabled;
     162             :   int   wfs_complete;
     163             : 
     164             :   ulong     wait_for_supermajority_at_slot;
     165             :   fd_hash_t expected_bank_hash;
     166             :   int       wfs_hash_is_zero;
     167             : 
     168             :   ulong            blockhash_seed;
     169             :   fd_reception_stats_t * reception_stats;
     170             :   ulong                  reception_stats_cnt;
     171             : 
     172             :   /* When a bank is evicted, the replayable chain of FECs delivered from rotor is broken. i.e.
     173             :      we lose context for a parent we needed to replay off of. When this happens,
     174             :      on the first FEC we see we can't replay, we need to drain everything in the dcache
     175             :      until there's something we can replay off of.  Set this flag to enter that state (i.e. ignore FECs
     176             :      until there's one we can replay. )*/
     177             :   int drain_rotor_fecs;
     178             : 
     179             :   fd_sched_t * sched;
     180             :   ulong        in_cnt;
     181             :   ulong        execrp_idle_cnt;
     182             : 
     183             :   ulong                vote_tracker_seed;
     184             :   fd_vote_tracker_t *  vote_tracker;
     185             : 
     186             :   uint has_genesis_hash:1;
     187             :   uint has_cluster_type:1;
     188             :   uint has_genesis_timestamp:1;
     189             :   uint has_expected_genesis_timestamp:1;
     190             : 
     191             :   char         genesis_path[ PATH_MAX ];
     192             :   fd_hash_t    genesis_hash[1];
     193             :   fd_genesis_t * genesis;
     194             :   ulong        cluster_type;
     195             :   ulong        genesis_timestamp;
     196             :   ulong        expected_genesis_timestamp;
     197             : 
     198             :   ulong          hard_fork_cnt;
     199             :   fd_hard_fork_t hard_forks[ FD_HARD_FORKS_MAX ];
     200             : 
     201             :   ushort expected_shred_version; /* from config, 0 if unset */
     202             :   ushort ipecho_shred_version;   /* from the entrypoints via ipecho, 0 until it answers */
     203             :   ushort shred_version;          /* 0 until computed. the two above only cross-check
     204             :                                     it, and replay holds off executing until it is known. */
     205             : 
     206             :   ulong enable_features_cnt;
     207             :   char  enable_features[ 16 ][ FD_BASE58_ENCODED_32_SZ ];
     208             : 
     209             :   /* A note on publishing ...
     210             : 
     211             :      The watermarks are used to publish our fork-aware structures.  For
     212             :      example, store, banks, and txncache need to be published to release
     213             :      resources occupied by rooted or dead blocks.  In general,
     214             :      publishing has the effect of pruning forks in those structures,
     215             :      indicating that it is ok to release the memory being occupied by
     216             :      the blocks on said forks.  Finalization determines the latest
     217             :      block on the consensus rooted fork.  As soon as we can,
     218             :      we should move the published root as close as possible to the
     219             :      latest consensus root, publishing/pruning everything on the fork
     220             :      tree along the way.  That is, all the blocks that directly descend
     221             :      from the current published root (inclusive) to the new published
     222             :      root (exclusive) on the rooted fork, as well as all the minority
     223             :      forks that branch from said blocks.
     224             : 
     225             :      Ideally, we'd move the published root to the consensus root
     226             :      immediately upon receiving a new consensus root.  However, that's
     227             :      not always safe to do.  One thing we need to be careful about is
     228             :      making sure that there are no more users/consumers of
     229             :      soon-to-be-pruned blocks, lest a use-after-free occurs.  This can
     230             :      be done by using a reference counter for each block.  Any
     231             :      concurrent activity, such as transaction execution in the exec
     232             :      tiles, should retain a refcnt on the block for as
     233             :      long as it needs access to the shared fork-aware structures related
     234             :      to that block.  Eventually, refcnt on a given block will drop down
     235             :      to 0 as the block either finishes replaying or gets marked as dead,
     236             :      and any other tile that has retained a refcnt on the block releases
     237             :      it.  At that point, it becomes a candidate for pruning.  The key to
     238             :      safe publishing then becomes figuring out how far we could advance
     239             :      the published root, such that every minority fork branching off of
     240             :      blocks in between the current published root (inclusive) and the
     241             :      new published root (exclusive) is safe to be pruned.  This is a
     242             :      straightforward tree traversal, where if a block B on the rooted
     243             :      fork has refcnt 0, and all minority forks branching off of B also
     244             :      have refcnt 0, then B is safe to be pruned.  We advance the
     245             :      published root to the farthest consecutively prunable block on the
     246             :      rooted fork.  Note that rotor presents the replay tile with a clean
     247             :      view of the world where every block is chained off of a parent
     248             :      block.  So there are no orpahned/dangling tree nodes to worry
     249             :      about.  The world is a nice single tree as far as replay is
     250             :      concerned.
     251             : 
     252             :      In the following fork tree, every node is a block and the number in
     253             :      parentheses is the refcnt on the block.  The chain marked with
     254             :      double slashes is the rooted fork.  Suppose the published root is
     255             :      at block P, and consensus root is at block T.  We can't publish
     256             :      past block P because Q has refcnt 1.
     257             : 
     258             : 
     259             :           P(0)
     260             :         /    \\
     261             :       Q(1)    A(0)
     262             :             / ||  \
     263             :         X(0) B(0)  C(0)
     264             :        /      || \
     265             :       Y(0)   M(0) R(0)
     266             :             / ||   /  \
     267             :         D(2) T(0) J(0) L(0)
     268             :               ||
     269             :               ..
     270             :               ..
     271             :               ..
     272             :               ||
     273             :       blocks we might be actively replaying
     274             : 
     275             : 
     276             :      When refcnt on Q drops to 0, we would be able to advance the
     277             :      published root to block M, because blocks P, A, and B, as well as
     278             :      all subtrees branching off of them, have refcnt 0, and therefore
     279             :      can be pruned.  Block M itself cannot be pruned yet because its
     280             :      child block D has refcnt 2.  After publishing/pruning, the fork
     281             :      tree would be:
     282             : 
     283             : 
     284             :              M(0)
     285             :             / ||
     286             :         D(2) T(0)
     287             :               ||
     288             :               ..
     289             :               ..
     290             :               ..
     291             :               ||
     292             :       blocks we might be actively replaying
     293             : 
     294             : 
     295             :      As a result, the shared fork-aware structures can free resources
     296             :      for blocks P, A, B, and all subtrees branching off of them.
     297             : 
     298             :      For the reference counting part, the replay tile is the sole entity
     299             :      that can update the refcnt.  This ensures that all refcnt increment
     300             :      and decrement attempts are serialized at the replay tile, and that
     301             :      there are no racy resurrection of a soon-to-be-pruned block.  If a
     302             :      refcnt increment request arrives after a block has been pruned,
     303             :      replay simply rejects the request.
     304             : 
     305             :      A note on the implementation of the above ...
     306             : 
     307             :      Upon receiving a new consensus root, we descend down the rooted
     308             :      fork from the current published root to the new consensus root.  On
     309             :      each node/block of the rooted fork, we do a summation of the refcnt
     310             :      on the block and all the minority fork blocks branching from the
     311             :      block.  If the summation is 0, the block is safe for pruning.  We
     312             :      advance the published root to the far end of the consecutive run of
     313             :      0 refcnt sums originating from the current published root.  On our
     314             :      descent down the minority forks, we also mark any block that hasn't
     315             :      finished replaying as dead, so we don't waste time executing them.
     316             :      No more transactions shall be dispatched for execution from dead
     317             :      blocks.
     318             : 
     319             :      Blocks start out with a refcnt of 0.  Other tiles may send a
     320             :      request to the replay tile for a reference on a block.  The
     321             :      transaction dispatcher is another source of refcnt updates.  On
     322             :      every dispatch of a transaction for block B, we increment the
     323             :      refcnt for B.  And on every transaction finalization, we decrement
     324             :      the refcnt for B.  This means that whenever the refcnt on a block
     325             :      is 0, there is no more reference on that block from the execution
     326             :      pipeline.  While it might be tempting to simply increment the
     327             :      refcnt once when we start replaying a block, and decrement the
     328             :      refcnt once when we finish a block, this more fine-grained refcnt
     329             :      update strategy allows for aborting and potentially immediate
     330             :      pruning of blocks under interleaved block replay.  Upon receiving a
     331             :      new consensus root, we can simply look at the refcnt on minority
     332             :      fork blocks, and a refcnt of 0 would imply that the block is safe
     333             :      for pruning, even if we haven't finished replaying it.  Without the
     334             :      fine-grained refcnt, we would need to first stop dispatching from
     335             :      the aborted block, and then wait for a full drain of the execution
     336             :      pipeline to know for sure that there are no more in-flight
     337             :      transactions executing on the aborted block.  Note that this will
     338             :      allow the refcnt on any block to transiently drop down to 0.  We
     339             :      will not mistakenly prune an actively replaying block, aka a leaf
     340             :      node, that is chaining off of the rooted fork, because the
     341             :      consensus root is always an ancestor of the actively replaying tip.
     342             :      */
     343             :   fd_hash_t consensus_root;          /* finalized and replayed */
     344             :   ulong     consensus_root_slot;     /* slot number of the above. */
     345             :   fd_hash_t notified_root;           /* The most recent consensus root sent to sched, RPC, and resolv. */
     346             :   ulong     notified_root_slot;      /* slot number of the above. */
     347             :   fd_bank_t * notified_root_bank;    /* bank held by sched, RPC, and resolv for the notified root. */
     348             :   ulong     published_root_slot;     /* slot number of the published root. */
     349             :   ulong     published_root_bank_idx; /* bank index of the published root. */
     350             : 
     351             :   /* ALPENGLOW-ONLY.  Watermarks marking the finalized but unreplayed
     352             :      slots.  lo is the oldest and held until replay reaches it.  hi is
     353             :      the newest and continuously updated.  If the gap between hi and lo
     354             :      exceeds max_live_slots, Firedancer halts. */
     355             :   ag_block_id_t finalized_block_id_lo;
     356             :   ag_block_id_t finalized_block_id_hi;
     357             : 
     358             :   /* Randomly generated block id for the initial genesis/snapshot slot.
     359             :      Used as a fallback when the snapshot manifest does not contain a
     360             :      block_id (block_id will be populated in Agave 4.1 snapshots and
     361             :      will be required in Agave 4.2). */
     362             : 
     363             :   fd_hash_t initial_block_id;
     364             : 
     365             :   /* The merkle root of the snapshot slot's block.
     366             :      Only present in snapshots generated by Agave >=4.1. */
     367             : 
     368             :   int       has_manifest_block_id;
     369             :   fd_hash_t manifest_block_id;
     370             : 
     371             :   /* We need to maintain a tile-local mapping of block-ids to bank index
     372             :      and vice versa.  This translation layer is needed for conversion
     373             :      since votor operates on block-ids and downstream consumers of FEC
     374             :      sets operate on bank indices.  This mapping must happen both ways:
     375             :      1. votor sends us block ids and we must map them to bank indices.
     376             :      2. when a block is completed, we must map the bank index to a block
     377             :         id to send a slot complete message. */
     378             :   ulong               block_id_len;
     379             :   ulong               max_live_slots;
     380             :   fd_block_id_ele_t * block_id_arr;
     381             :   ulong *             dead_idxs; /* max_live_slots scratch for mark_bank_dead */
     382             : 
     383             :   fd_hash_t *         fec_chain;
     384             : 
     385             :   ulong                  ag_block_id_map_seed;
     386             :   fd_ag_block_id_map_t * ag_block_id_map;
     387             : 
     388             :   /* Capture-related configs */
     389             :   fd_capture_ctx_t *     capture_ctx;
     390             :   FILE *                 capture_file;
     391             :   fd_capture_link_buf_t  cap_repl_out[1];
     392             : 
     393             :   /* Protobuf dumping context for debugging runtime execution and
     394             :      collecting seed corpora. */
     395             :   fd_dump_proto_ctx_t * dump_proto_ctx;
     396             : 
     397             :   /* Per-txn lifecycle timing capture.  The scheduler's txn_info_pool
     398             :      entries are recycled the moment a txn completes, so the ticks are
     399             :      copied out at completion time into a leased capture slot, indexed by
     400             :      the txn's position in the block.  A full-depth buffer per live bank
     401             :      would be ~9.6 GiB, but only a handful of blocks replay concurrently,
     402             :      so a small pool of full-depth slots is leased to banks as they start
     403             :      replaying.  A block that cannot get a slot (more than
     404             :      FD_REPLAY_TXN_TIMING_SLOTS blocks replaying at once) captures
     405             :      nothing.  Slot depth is max_txn_per_slot, so the records sit in a
     406             :      side array sized at footprint time. */
     407             :   fd_replay_txn_timing_slot_t * timing_slot_pool;    /* fd_pool, FD_REPLAY_TXN_TIMING_SLOTS elements */
     408             :   fd_replay_txn_timing_t *      timing_rec;          /* [FD_REPLAY_TXN_TIMING_SLOTS*max_txn_per_slot], slot i at i*max_txn_per_slot */
     409             :   ulong *                       timing_slot_of_bank; /* [max_live_slots] bank_idx -> pool idx or idx_null */
     410             : 
     411             :   /* Whether the runtime has been booted either from snapshot loading
     412             :      or from genesis. */
     413             :   int is_booted;
     414             : 
     415             :   fd_multi_epoch_leaders_t * mleaders;
     416             : 
     417             :   ulong max_txn_per_slot;
     418             :   ulong max_shreds_per_block;
     419             : 
     420             :   /* When we transition to becoming leader, we can only unbecome leader
     421             :      if we have received a block id from the FEC reassembler, and a
     422             :      message from PoH that the leader slot has ended.  After both of
     423             :      these conditions are met, then we are free to unbecome leader.
     424             :      Exception: a slot aborted by a reset unbecomes leader on the PoH
     425             :      slot-ended message alone; no block id will ever arrive for it. */
     426             :   uint        is_leader : 1;
     427             :   uint        supports_leader : 1;
     428             :   int         recv_poh;
     429             : 
     430             :   ulong       leader_execution_fees; /* ALPENGLOW-ONLY */
     431             :   ulong       leader_priority_fees;  /* ALPENGLOW-ONLY */
     432             :   ulong       leader_tips;           /* ALPENGLOW-ONLY */
     433             :   fd_block_footer_t leader_footer[ 1 ];
     434             : 
     435             :   fd_votor_certed_t votor_final[ 1 ];                                                /* ALPENGLOW-ONLY: highest finalization, fast over slow at the same slot */
     436             :   fd_votor_leader_t votor_leader[ 1 ];                                               /* ALPENGLOW-ONLY: ParentReady trigger behind next_leader_slot     */
     437             :   ulong             votor_parent_ready_slot;                                         /* ALPENGLOW-ONLY: highest window start certs made ParentReady   */
     438             :   long              leader_window_start_ns;                                          /* ALPENGLOW-ONLY: ParentReady time of the window we are leading   */
     439             :   fd_votor_reward_t votor_reward[ FD_NUM_SLOTS_FOR_REWARD+AG_SLOTS_PER_WINDOW+1UL ];
     440             : 
     441             :   ulong       next_leader_slot;
     442             :   long        next_leader_tickcount;
     443             : 
     444             : 
     445             :   ulong next_leader_query_start;
     446             :   ulong next_leader_query_slot;
     447             : 
     448             :   double      tick_per_ns;
     449             :   ulong       highwater_leader_slot;
     450             :   ulong       reset_slot;
     451             :   ulong       epoch_end_slot;
     452             :   ulong       slots_per_epoch;
     453             :   ulong       ns_per_slot;
     454             : 
     455             :   /* Caught up to the cluster: replay has completed a slot within a few
     456             :      slots of the cluster tip.  Rotor tracks the tip and ships it on
     457             :      each delivered FEC, because rotor delivers only
     458             :      replayable FECs in order and their slots track replay itself. */
     459             :   int         caught_up;
     460             :   ulong       catch_up_max_fec_slot;
     461             :   ulong       catch_up_tip_advance_cnt;
     462             :   long        boot_timestamp_nanos;
     463             : 
     464             :   fd_hash_t   reset_dmr; /* double merkle root of the reset block */
     465             :   long        reset_timestamp_nanos;
     466             :   fd_bank_t * leader_bank;
     467             : 
     468             :   struct {
     469             :     ulong slot;
     470             :     long  became_leader_nanos;
     471             :     long  leader_slot_start_nanos;
     472             :     long  first_fec_returned_nanos;
     473             :     ulong microblock_count;
     474             :     ulong pack_block_cost;
     475             :     ulong pack_vote_cost;
     476             :     ulong pack_data_bytes;
     477             :     ulong bundle_txn_count;
     478             :     int   pack_end_reason;
     479             :     long  pack_start_nanos;
     480             :     long  pack_end_nanos;
     481             :     ulong timing_table_idx;
     482             :   } leader_stats;
     483             : 
     484             :   fd_pubkey_t      identity_pubkey[1];
     485             :   ulong            identity_idx;
     486             :   int              identity_dirty;
     487             : 
     488             :   int              has_vote_account;
     489             :   fd_pubkey_t      vote_account[ 1 ];
     490             : 
     491             :   fd_node_info_box_t * node_info; /* shared */
     492             :   fd_wait_info_box_t * wait_info; /* shared */
     493             : 
     494             :   /* Delinquency, published through wait_info only; not a metric. */
     495             :   int   delinquent_known;
     496             :   ulong delinquent_sample_slot;
     497             :   ulong delinquent_stake_lamports;
     498             :   ulong cluster_active_stake_lamports;
     499             :   /* Alpenglow-only delinquency tracking, from the block footer reward
     500             :      certs since last_vote_slot stalls without vote transactions.
     501             :      Indexed by alpenglow rank, which is epoch-scoped. */
     502             :   ulong ag_last_voted[ AG_VAT_MAX ];
     503             :   ulong ag_last_voted_epoch; /* ULONG_MAX before the first reward cert */
     504             :   ulong ag_last_settled;     /* highest settled slot observed */
     505             :   ulong ag_stamp_since;      /* first slot stamped into an empty table */
     506             : 
     507             :   /* Signing payload of each exec tile's footer cert verify task */
     508             :   uchar cert_payload   [ FD_SCHED_MAX_EXEC_TILE_CNT ][ FD_ALPENGLOW_CERT_PAYLOAD_MAX ];
     509             :   ulong cert_payload_sz[ FD_SCHED_MAX_EXEC_TILE_CNT ];
     510             : 
     511             :   fd_keyswitch_t * keyswitch;
     512             :   int              halt_replay;
     513             : 
     514             :   ulong  resolv_tile_cnt;
     515             : 
     516             :   int in_kind[ 128 ];
     517             :   fd_replay_in_link_t in[ 128 ];
     518             : 
     519             :   ulong                exec_cnt;
     520             :   fd_replay_out_link_t exec_out[ FD_SCHED_MAX_EXEC_TILE_CNT ];
     521             : 
     522             :   fd_replay_out_link_t replay_out[1];
     523             :   fd_replay_out_link_t slot_out[1];
     524             :   fd_replay_out_link_t rotor_out[1]; /* REPLAY_SIG_MISSING_FEC */
     525             :   ulong const *        slot_out_seq;
     526             :   fd_replay_out_link_t snapmk_out[1];
     527             :   ulong admin_out_idx;
     528             : 
     529             :   fd_replay_out_link_t epoch_out[1];
     530             : 
     531             :   /* The rpc tile needs to occasionally own a reference to a live bank.
     532             :      Replay needs to know if the rpc as a consumer is enabled so it can
     533             :      increment the bank's refcnt before publishing bank_idx. */
     534             :   int rpc_enabled;
     535             : 
     536             :   /* For dumping blocks to protobuf. For backtest only. */
     537             :   fd_block_dump_ctx_t * block_dump_ctx;
     538             : 
     539             :   /* We need a few pieces of information to compute the right addresses
     540             :      for bundle crank information that we need to send to pack. */
     541             :   struct {
     542             :     int                   enabled;
     543             :     fd_pubkey_t           vote_account;
     544             :     fd_bundle_crank_gen_t gen[1];
     545             :   } bundle;
     546             : 
     547             :   /* snapshot producer */
     548             :   struct {
     549             :     uint  supported:1;
     550             :     uint  active:1;
     551             :     uint  incremental:1;
     552             :     ulong bank_idx;
     553             :     ulong scheduled_at_slot;
     554             :     ulong full_interval_blocks;
     555             :     ulong next_full_block_height;
     556             :     ulong incremental_interval_blocks;
     557             :     ulong next_incremental_block_height;
     558             :     ulong base_slot;
     559             :     ulong snap_finished_full;
     560             :     ulong snap_finished_incr;
     561             :     ulong snap_produced_incr_cnt;
     562             :     fd_epoch_credits_view_t epoch_credits_view[1];
     563             :   } snapmk;
     564             : 
     565             :   struct {
     566             :     fd_histf_t store_query_work[1];
     567             :     ulong      store_query_cnt;
     568             :     ulong      store_query_missing_cnt;
     569             : 
     570             :     ulong slots_total;
     571             :     ulong transactions_total;
     572             : 
     573             :     ulong reasm_latest_slot;
     574             :     ulong reasm_latest_fec_idx;
     575             : 
     576             :     ulong sched_full;
     577             :     ulong leader_bid_wait;
     578             :     ulong banks_full;
     579             :     ulong parent_unavailable;
     580             :     ulong leader_slot_already_produced;
     581             :     ulong leader_window_superseded;
     582             :     ulong fec_rooted_past;
     583             :     ulong storage_root_behind;
     584             : 
     585             :     ulong voted_slot; /* monotone, ULONG_MAX if none */
     586             :   } metrics;
     587             : 
     588             :   uchar __attribute__((aligned(FD_MULTI_EPOCH_LEADERS_ALIGN))) mleaders_mem[ FD_MULTI_EPOCH_LEADERS_FOOTPRINT ];
     589             : 
     590             :   ulong                runtime_stack_seed;
     591             :   fd_runtime_stack_t * runtime_stack;
     592             : 
     593             :   fd_footer_cache_t * footer_cache;
     594             : 
     595             :   fd_event_block_completed_t * block_completed_event;
     596             : 
     597             :   fd_leader_txn_timing_table_t const * leader_txn_timing;
     598             : 
     599             :   /* If non-zero, emit the runtime events during replay. */
     600             :   int report_runtime_diffs;
     601             : };
     602             : 
     603             : typedef struct fd_replay_tile fd_replay_tile_t;
     604             : 
     605             : #endif /* HEADER_fd_src_discof_replay_fd_replay_tile_private_h */

Generated by: LCOV version 1.14