LCOV - code coverage report
Current view: top level - discof/replay - fd_sched.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 11 62 17.7 %
Date: 2026-11-11 12:40:43 Functions: 0 0 -

          Line data    Source code
       1             : #ifndef HEADER_fd_src_discof_replay_fd_sched_h
       2             : #define HEADER_fd_src_discof_replay_fd_sched_h
       3             : 
       4             : #include "fd_rdisp.h"
       5             : #include "../../flamenco/alpenglow/fd_block_marker.h"
       6             : #include "../../disco/fd_txn_p.h"
       7             : #include "../../disco/store/fd_store.h" /* for fd_store_fec_t */
       8             : #include "../../flamenco/accdb/fd_accdb.h"
       9             : #include "../../disco/fd_clock_tile.h"
      10             : #include "../../ballet/lthash/fd_lthash.h"
      11             : 
      12             : /* fd_sched schedules replay work across a fork tree.  It uses fd_rdisp
      13             :    to order conflicting transactions and adds fork-aware lane
      14             :    management, out-of-band signature verification, out-of-band LtHash,
      15             :    and various block validity checks as well as block boundary work.
      16             : 
      17             :    Conceptually, transactions in a block form a DAG.  We would like to
      18             :    make our way through a block with a sufficient degree of parallelism,
      19             :    such that the execution time of the critical path of the DAG is the
      20             :    limiting factor.  The dispatcher does a good job of emerging the
      21             :    critical path of the DAG on the fly.  Blocks are tracked by the
      22             :    dispatcher either as a block staged on a lane, or as an unstaged
      23             :    block.  When a block is staged, it will enjoy the most intelligent
      24             :    online scheduling that the dispatcher has to offer.  Lanes have to
      25             :    consist of linear chains of blocks down a fork.  So to map a fork
      26             :    tree to lanes, we will need multiple lanes.  Ideally, every branch in
      27             :    the fork tree sits on some lane.  However, memory footprint limits us
      28             :    to a few number of lanes.
      29             : 
      30             :    This module implements a state machine for ensuring that blocks enter
      31             :    into and exit out of lanes in an orderly fashion.  The public APIs of
      32             :    this module are invoked to drive state transitions on a small number
      33             :    of events, such as new transactions arriving, or transactions
      34             :    completing, or a block being aborted/abandoned.  We also implement
      35             :    policies for deciding which blocks get staged onto lanes, or evicted
      36             :    from lanes, as well as which lanes to prioritize for execution.
      37             : 
      38             :    To further enhance performance, the scheduler has a policy of placing
      39             :    one block per lane.  So rather than treating lanes as lanes, we treat
      40             :    them as parking spots.  Callers are encouraged to check for lane
      41             :    availability before inserting new blocks.  A new block inserted when
      42             :    every lane is taken gets the lane of an idle block if there is one,
      43             :    and is unstaged otherwise.  See fd_sched_fec_waits_for_lane().
      44             : 
      45             :    Callers ingest FEC sets, poll fd_sched_task_next_ready(), and return
      46             :    each result through fd_sched_task_done().  BLOCK_START and BLOCK_END
      47             :    tasks bracket the caller's block processing. */
      48             : 
      49             : struct fd_sched;
      50             : typedef struct fd_sched fd_sched_t;
      51             : 
      52             : /* Max microblocks (including ticks) that fit in a block's shreds;
      53             :    scaled with max_shreds_per_block at runtime. */
      54        1000 : #define FD_SCHED_MAX_MBLK_PER_SLOT (FD_SHRED_DATA_PAYLOAD_MAX_PER_SLOT/sizeof(fd_microblock_hdr_t))
      55             : 
      56       23120 : #define FD_SCHED_MAX_STAGING_LANES_LOG (2)
      57       23120 : #define FD_SCHED_MAX_STAGING_LANES     (1UL<<FD_SCHED_MAX_STAGING_LANES_LOG)
      58             : 
      59           0 : #define FD_SCHED_MIN_DEPTH 478
      60             : #define FD_SCHED_MAX_DEPTH FD_RDISP_MAX_DEPTH
      61             : 
      62        5029 : #define FD_SCHED_MAX_EXEC_TILE_CNT (64UL)
      63             : 
      64             : /* Out-of-band LtHash batch size, at most FD_EXECRP_LTHASH_BATCH_MAX.
      65             :    This seems to be a sweet spot in scheduling overhead vs task
      66             :    granularity. */
      67           0 : #define FD_SCHED_LTHASH_BATCH_MAX (32UL)
      68             : 
      69             : /* While a transaction of the block is in flight, a batch carries at
      70             :    most this many accounts, so that the tile it takes is free again
      71             :    soon.  Otherwise, a batch is allowed to carry up to
      72             :    FD_SCHED_LTHASH_BATCH_MAX accounts. */
      73           0 : #define FD_SCHED_LTHASH_BATCH_BUSY_MAX (8UL)
      74             : 
      75             : /* A staged fec_eos block turns its owed additions into pseudo
      76             :    transactions this many at a time. */
      77           0 : #define FD_SCHED_LTHASH_DRAIN_CHUNK (64UL)
      78             : 
      79             : /* Bounds on the writable accounts a block declares in its transactions
      80             :    and writes in start-of-block processing.  The 8k for inflation
      81             :    rewards is twice the per-block target of 4096.  A partition's size is
      82             :    binomial with a mean of at most the target, and exceeding 8k is a
      83             :    super high deviation event.  Only a warmup epoch, which pays every
      84             :    stake account in a single partition, could potentially escape that
      85             :    bound.
      86             : 
      87             :    FIXME These should scale with CU and block time. */
      88        1000 : #define FD_SCHED_LTHASH_TXN_WRITERS_MAX  (200802UL)
      89           0 : #define FD_SCHED_LTHASH_START_WRITES_MAX (FD_RDISP_MAX_WRITERS_PER_BLOCK-FD_SCHED_LTHASH_TXN_WRITERS_MAX)
      90             : 
      91             : struct fd_sched_alut_ctx {
      92             :   fd_accdb_t *       accdb;
      93             :   fd_accdb_fork_id_t fork_id;
      94             :   ulong              els; /* Effective lookup slot. */
      95             : };
      96             : typedef struct fd_sched_alut_ctx fd_sched_alut_ctx_t;
      97             : 
      98             : struct fd_sched_fec {
      99             :   ulong            bank_idx;            /* Index of the block.  Assumed to be in [0, block_cnt_max).  Caller
     100             :                                            is responsible for ensuring that bank idx is in bounds and unique
     101             :                                            across equivocated blocks. */
     102             :   ulong            parent_bank_idx;     /* Index of the parent block.  Assumed to be in [0, block_cnt_max).
     103             :                                            Caller is responsible for ensuring that parent bank idx is in
     104             :                                            bounds and unique across equivocated blocks. */
     105             :   ulong            slot;                /* Slot number of the block. */
     106             :   ulong            parent_slot;         /* Slot number of the parent block. */
     107             :   fd_store_fec_t * fec;                 /* FEC set metadata. */
     108             :   uchar          * data;                /* Resolved laddr of the FEC set data buffer. */
     109             :   uint             shred_cnt;           /* Number of shreds in the FEC set. */
     110             :   uint             is_last_in_batch:1;  /* Set if this is the last FEC set in the batch; relevant because the
     111             :                                            parser should ignore trailing bytes at the end of a batch. */
     112             :   uint             is_last_in_block:1;  /* Set if this is the last FEC set in the block. */
     113             :   uint             is_first_in_block:1; /* Set if this is the first FEC set in the block.  Bank should increment refcnt for sched if such a FEC set has been ingested by sched. */
     114             :   uint             starts_at_update_parent:1; /* Set with is_first_in_block if replay starts the block at its UpdateParent FEC set, skipping the abandoned prefix.  The block must then open with an UpdateParent naming parent_slot. */
     115             :   long             completed_ns;        /* Network arrival (wallclock ns) of the shred that completed this FEC set; 0 if unavailable. */
     116             : 
     117             :   fd_sched_alut_ctx_t alut_ctx[ 1 ];
     118             : };
     119             : typedef struct fd_sched_fec fd_sched_fec_t;
     120             : 
     121             : /* The state of a transaction.  Non mutually exclusive. */
     122           0 : #define FD_SCHED_TXN_EXEC_DONE      (0x0001UL)
     123           0 : #define FD_SCHED_TXN_SIGVERIFY_DONE (0x0002UL)
     124           0 : #define FD_SCHED_TXN_IS_COMMITTABLE (0x0004UL)
     125           0 : #define FD_SCHED_TXN_IS_FEES_ONLY   (0x0008UL)
     126           0 : #define FD_SCHED_TXN_IS_NOOP        (0x0010UL)
     127        1541 : #define FD_SCHED_TXN_ALT_UNRESOLVED (0x0020UL)
     128             : #define FD_SCHED_TXN_REPLAY_DONE    (FD_SCHED_TXN_EXEC_DONE|FD_SCHED_TXN_SIGVERIFY_DONE)
     129             : 
     130             : struct fd_sched_txn_info {
     131             :    ulong flags;
     132             :    int   txn_err;
     133             :    uint  next_idx;
     134             :    long  received_ns;
     135             : 
     136             :    /* LONG_MAX if stage was not reached */
     137             :    long  tick_parsed;
     138             :    long  tick_sigverify_disp;
     139             :    long  tick_sigverify_done;
     140             :    long  tick_exec_disp;
     141             :    long  tick_exec_done;
     142             :    long  tick_load_start;
     143             :    long  tick_check_start;
     144             :    long  tick_exec_start;
     145             :    long  tick_commit_start;
     146             :    long  tick_commit_end;
     147             : 
     148             :    ulong slot;
     149             :    ulong bank_seq;
     150             :    ulong index_in_slot; /* 0-indexed position of this transaction within its block. */
     151             :    ulong exec_tile_idx;
     152             :    ulong sigverify_exec_tile_idx;
     153             :    uint  compute_units_consumed; /* possibly zero if is_committable is zero */
     154             :    ulong max_compute_units;
     155             :    ulong transaction_fee;
     156             :    ulong priority_fee;
     157             :    ulong tips;
     158             : };
     159             : typedef struct fd_sched_txn_info fd_sched_txn_info_t;
     160             : 
     161             : /* The scheduler may return one of the following types of tasks for the
     162             :    replay tile.
     163             : 
     164             :    e - passed down to exec tiles.
     165             :    i - replay completes the task immediately.
     166             :    q - replay may either do it immediately or queue the task up. */
     167           0 : #define FD_SCHED_TT_NULL          (0UL)
     168           0 : #define FD_SCHED_TT_BLOCK_START   (1UL) /* (i) Start-of-block processing. */
     169           0 : #define FD_SCHED_TT_BLOCK_END     (2UL) /* (q) End-of-block processing. */
     170           0 : #define FD_SCHED_TT_TXN_EXEC      (3UL) /* (e) Transaction execution. */
     171           0 : #define FD_SCHED_TT_TXN_SIGVERIFY (4UL) /* (e) Transaction sigverify. */
     172           0 : #define FD_SCHED_TT_LTHASH_SUB    (5UL) /* (e) Hash an account from the parent fork and subtract. */
     173           0 : #define FD_SCHED_TT_POH_HASH      (6UL) /* (e) PoH hashing. */
     174           0 : #define FD_SCHED_TT_MARK_DEAD     (7UL) /* (i) Mark the block dead. */
     175           0 : #define FD_SCHED_TT_CERT_VERIFY   (8UL) /* (e) Footer cert verify. */
     176           0 : #define FD_SCHED_TT_LTHASH_ADD    (9UL) /* (e) Hash an account from this fork and add. */
     177           0 : #define FD_SCHED_TT_REWARDS       (10UL) /* (e) Footer vote rewards slice. */
     178             : 
     179             : /* Slot-level replay states.  States are tracked for one block at a
     180             :    time, the one the scheduler is working on.  A block's interval opens
     181             :    at its first dispatch (BLOCK_START).  It closes when another block's
     182             :    interval opens, or when end of block processing completes or the
     183             :    block dies.  A block deactivated while waiting on the network stays
     184             :    tracked until another block takes over.
     185             : 
     186             :    BLOCKED_TILES     no exec tile is free
     187             :    BLOCKED_CONFLICTS txns queued, but waiting on in-flight conflicting txns
     188             :    BLOCKED_NETWORK   no txns queued, waiting for more to arrive
     189             :    FINISH            end of the slot received, txns or PoH still in flight
     190             : 
     191             :    States are only reevaluated on FEC ingest, task_next_ready and
     192             :    task_done.  A new state is committed only once it has held for at
     193             :    least FD_SCHED_SLOT_STATE_DEBOUNCE_NS. */
     194             : 
     195           0 : #define FD_SCHED_SLOT_STATE_NONE              (0)
     196           0 : #define FD_SCHED_SLOT_STATE_BLOCKED_TILES     (1)
     197           0 : #define FD_SCHED_SLOT_STATE_BLOCKED_CONFLICTS (2)
     198           0 : #define FD_SCHED_SLOT_STATE_BLOCKED_NETWORK   (3)
     199           1 : #define FD_SCHED_SLOT_STATE_FINISH            (4)
     200             : 
     201        1000 : #define FD_SCHED_SLOT_STATE_DEBOUNCE_NS (10000L)
     202             : 
     203             : /* Max state transitions between after_credit drains.  The real bound
     204             :    is ~3, but a tight bound needs an exhaustive proof tightly coupled
     205             :    to the sched state machine.  Filled buffer is handled gracefully. */
     206             : #define FD_SCHED_SLOT_STATE_MAX (32UL)
     207             : 
     208             : struct fd_sched_slot_state {
     209             :   ulong slot;
     210             :   long  start_tick;
     211             :   long  end_tick;
     212             :   ulong state; /* FD_SCHED_SLOT_STATE_* */
     213             : };
     214             : typedef struct fd_sched_slot_state fd_sched_slot_state_t;
     215             : 
     216             : struct fd_sched_block_start {
     217             :   ulong bank_idx;        /* Same as in fd_sched_fec_t. */
     218             :   ulong parent_bank_idx; /* Same as in fd_sched_fec_t. */
     219             :   ulong slot;            /* Slot number of the block. */
     220             :   int   lthash_inband;   /* 1 if the block hashes in band, 0 if out of band.  An in-band block
     221             :                             reports no start-of-block writes and has no delta to fold from
     222             :                             sched at its end. */
     223             : };
     224             : typedef struct fd_sched_block_start fd_sched_block_start_t;
     225             : 
     226             : struct fd_sched_block_end {
     227             :   ulong bank_idx;
     228             : };
     229             : typedef struct fd_sched_block_end fd_sched_block_end_t;
     230             : 
     231             : struct fd_sched_txn_exec {
     232             :   ulong bank_idx;
     233             :   ulong slot;
     234             :   ulong txn_idx;
     235             :   ulong exec_idx;
     236             : };
     237             : typedef struct fd_sched_txn_exec fd_sched_txn_exec_t;
     238             : 
     239             : struct fd_sched_txn_sigverify {
     240             :   ulong bank_idx;
     241             :   ulong txn_idx;
     242             :   ulong exec_idx;
     243             : };
     244             : typedef struct fd_sched_txn_sigverify fd_sched_txn_sigverify_t;
     245             : 
     246           0 : #define FD_SCHED_POH_PARA 16
     247             : struct fd_sched_poh_hash {
     248             :   ulong     bank_idx;
     249             :   ulong     exec_idx;
     250             :   ulong     cnt;     /* In [1,FD_SCHED_POH_PARA] */
     251             :   ulong     hashcnt; /* 0 or 1, same for every element of the batch */
     252             :   ulong     mblk_idx[ FD_SCHED_POH_PARA ];
     253             :   fd_hash_t hash    [ FD_SCHED_POH_PARA ];
     254             : };
     255             : typedef struct fd_sched_poh_hash fd_sched_poh_hash_t;
     256             : 
     257             : struct fd_sched_mark_dead {
     258             :   ulong     bank_idx;
     259             : };
     260             : typedef struct fd_sched_mark_dead fd_sched_mark_dead_t;
     261             : 
     262             : struct fd_sched_lthash_task {
     263             :   ulong                  bank_idx;
     264             :   ulong                  exec_idx;
     265             :   ulong                  cnt;   /* In [1,FD_SCHED_LTHASH_BATCH_MAX] */
     266             :   fd_acct_addr_t const * accts; /* Points into sched memory that stays as it is until the task completes. */
     267             : };
     268             : typedef struct fd_sched_lthash_task fd_sched_lthash_task_t;
     269             : 
     270             : /* A footer cert verify task.  Between the footer's parse and BLOCK_END,
     271             :    fd_sched_task_next_ready may return one when no transaction is ready,
     272             :    one cert per task. */
     273             : struct fd_sched_cert_task {
     274             :   ulong bank_idx;
     275             :   ulong cert_idx; /* The cert's index in fd_alpenglow_footer_certs order. */
     276             :   ulong exec_idx; /* Target tile. */
     277             : };
     278             : typedef struct fd_sched_cert_task fd_sched_cert_task_t;
     279             : 
     280             : /* The writable lookup table accounts of a completed TXN_EXEC task that
     281             :    was flagged FD_SCHED_TXN_ALT_UNRESOLVED. */
     282             : struct fd_sched_txn_alts {
     283             :   ulong                  cnt;
     284             :   fd_acct_addr_t const * addrs;
     285             : };
     286             : typedef struct fd_sched_txn_alts fd_sched_txn_alts_t;
     287             : 
     288             : struct fd_sched_task {
     289             :   ulong task_type; /* Set to one of the task types defined above. */
     290             :   union {
     291             :     fd_sched_block_start_t   block_start[ 1 ];
     292             :     fd_sched_block_end_t     block_end[ 1 ];
     293             :     fd_sched_txn_exec_t      txn_exec[ 1 ];
     294             :     fd_sched_txn_sigverify_t txn_sigverify[ 1 ];
     295             :     fd_sched_poh_hash_t      poh_hash[ 1 ];
     296             :     fd_sched_mark_dead_t     mark_dead[ 1 ];
     297             :     fd_sched_lthash_task_t   lthash[ 1 ];
     298             :     fd_sched_cert_task_t     cert_verify[ 1 ];
     299             :   };
     300             : };
     301             : typedef struct fd_sched_task fd_sched_task_t;
     302             : 
     303             : 
     304       16722 : #define FD_SCHED_DEAD_REASON_NONE                        (0)  /* Block was not ruled invalid by the scheduler.  The replay tile may still rule it invalid, unbeknownst to the scheduler. */
     305           0 : #define FD_SCHED_DEAD_REASON_UNPARSEABLE_CONTENT         (1)  /* Bytes at the head of the stream failed to parse out as any structure (transaction, microblock header, or count) within the largest size a valid block allows: malformed content. */
     306           2 : #define FD_SCHED_DEAD_REASON_SHORT_BLOCK                 (2)  /* Block bytes ended short of the microblocks and transactions declared. */
     307           0 : #define FD_SCHED_DEAD_REASON_TOO_MANY_TXNS               (3)  /* More transactions than a valid block can hold. */
     308           0 : #define FD_SCHED_DEAD_REASON_TOO_MANY_MICROBLOCKS        (4)  /* More microblocks than a valid block can hold. */
     309           0 : #define FD_SCHED_DEAD_REASON_DUPLICATE_ACCOUNT           (5)  /* Transaction referenced the same account more than once. */
     310           0 : #define FD_SCHED_DEAD_REASON_TRAILING_ENTRY              (6)  /* Block did not end on a tick. */
     311        1486 : #define FD_SCHED_DEAD_REASON_TOO_MANY_TICKS              (7)  /* More ticks than required. */
     312           0 : #define FD_SCHED_DEAD_REASON_TOO_FEW_TICKS               (8)  /* Fewer ticks than required. */
     313           0 : #define FD_SCHED_DEAD_REASON_TICK_HASH_MISMATCH          (16) /* PoH hash of a tick did not verify. */
     314           0 : #define FD_SCHED_DEAD_REASON_ENTRY_HASH_MISMATCH         (17) /* PoH hash of a transaction entry did not verify, detected when the entry's PoH hashing task completed. */
     315           0 : #define FD_SCHED_DEAD_REASON_ENTRY_HASH_MISMATCH_INGEST  (18) /* PoH hash of a transaction entry did not verify, detected at FEC ingest when a later FEC set completed the entry's transactions. */
     316           0 : #define FD_SCHED_DEAD_REASON_DEAD_ANCESTOR               (19) /* The block went down with its lineage.  Whether the lineage was discarded or ruled invalid is distinguished by fd_sched_block_is_discarded. */
     317           0 : #define FD_SCHED_DEAD_REASON_BAD_BLOCK_MARKER            (20) /* An Alpenglow block marker (header, footer, genesis certificate or update parent) failed to parse or had an unknown kind. */
     318           0 : #define FD_SCHED_DEAD_REASON_ALPENGLOW_HASH_CNT          (21) /* An Alpenglow block had an entry whose hash count was not exactly one, detected at FEC ingest. */
     319             : /* Alpenglow block structure, mirroring agave's BlockComponentProcessor:
     320             :    header | [genesis cert] | entries* | footer | alpentick */
     321           0 : #define FD_SCHED_DEAD_REASON_MISSING_PARENT_MARKER       (22) /* An Alpenglow block carried an entry batch or footer before any block header. */
     322           0 : #define FD_SCHED_DEAD_REASON_MULTIPLE_BLOCK_HEADERS      (23) /* An Alpenglow block carried more than one block header. */
     323           0 : #define FD_SCHED_DEAD_REASON_GENESIS_CERT_OUT_OF_ORDER   (24) /* An Alpenglow genesis certificate marker did not immediately follow the block header. */
     324           0 : #define FD_SCHED_DEAD_REASON_MULTIPLE_BLOCK_FOOTERS      (25) /* An Alpenglow block carried more than one block footer. */
     325           0 : #define FD_SCHED_DEAD_REASON_ENTRY_AFTER_BLOCK_FOOTER    (26) /* An Alpenglow block carried an entry batch other than the alpentick after its footer. */
     326           0 : #define FD_SCHED_DEAD_REASON_INVALID_ALPENTICK_POSITION  (27) /* An Alpenglow block ended without the alpentick directly after its footer. */
     327           0 : #define FD_SCHED_DEAD_REASON_MISSING_BLOCK_FOOTER        (28) /* An Alpenglow block ended without a block footer. */
     328           0 : #define FD_SCHED_DEAD_REASON_SPURIOUS_UPDATE_PARENT      (29) /* An Alpenglow block carried an UpdateParent marker after its header or footer.  Agave replays one after the header (before the footer) as a valid block, so that case means replay was handed the abandoned prefix rather than a bad block. */
     329           0 : #define FD_SCHED_DEAD_REASON_TOO_MANY_WRITABLE_ACCOUNTS  (30) /* The block's transactions declare more writable accounts than a valid block can afford. */
     330           0 : #define FD_SCHED_DEAD_REASON_MULTIPLE_UPDATE_PARENTS     (31) /* An Alpenglow block carried more than one UpdateParent marker. */
     331           0 : #define FD_SCHED_DEAD_REASON_UPDATE_PARENT_MISMATCH      (33) /* An Alpenglow block's initial UpdateParent named a parent other than the one replay built it on. */
     332             : /* Cause to pass to fd_sched_block_abandon().  A block is considered
     333             :    invalid when it violates the protocol, so validity is a function of
     334             :    the block's content.  A block may be discarded (temporarily) because
     335             :    the validator is under resource pressure.  A block may be discarded
     336             :    (permanently) if consensus converged on an alternative fork, which is
     337             :    done implicitly in fd_sched_root_notify() for the minority forks it
     338             :    abandons. */
     339           0 : #define FD_SCHED_ABANDON_DISCARDED (0)
     340           0 : #define FD_SCHED_ABANDON_INVALID   (1)
     341             : 
     342             : struct __attribute__((packed)) fd_microblock_hdr {
     343             :   /* Number of PoH hashes between this and last microblock */
     344             :   /* 0x00 */ ulong hash_cnt;
     345             : 
     346             :   /* PoH state after evaluating this microblock (including all
     347             :      appends and mixin). The input to the poh calculation of the first
     348             :      microblock is the last hash of the parent block, otherwise it is the
     349             :      hash of the previous microblock. */
     350             :   /* 0x08 */ uchar hash[32];
     351             : 
     352             :   /* Number of transactions in this microblock */
     353             :   /* 0x28 */ ulong txn_cnt;
     354             : };
     355             : typedef struct fd_microblock_hdr fd_microblock_hdr_t;
     356             : 
     357             : FD_PROTOTYPES_BEGIN
     358             : 
     359             : /* fd_sched_{align,footprint} return the required alignment and
     360             :    footprint in bytes for a region of memory to be used as a scheduler.
     361             :    footprint silently returns 0 if params are invalid (thus convenient
     362             :    to validate params).
     363             : 
     364             :    depth controls the reorder buffer transaction count (~1 million
     365             :    recommended for live replay, ~10k recommended for async replay).
     366             :    block_cnt_max is the maximum number of blocks that will be tracked by
     367             :    the scheduler.  max_shreds_per_block bounds the data shreds a block
     368             :    may hold (the shred tile enforces the same limit upstream, sched
     369             :    asserts it); a block declaring more than max_txn_per_slot
     370             :    transactions is ruled invalid.  FD_SHRED_BLK_MAX and
     371             :    FD_MAX_TXN_PER_SLOT in production. */
     372             : 
     373             : ulong
     374             : fd_sched_align( void );
     375             : 
     376             : ulong
     377             : fd_sched_footprint( ulong depth,                /* in [FD_SCHED_MIN_DEPTH,FD_SCHED_MAX_DEPTH] */
     378             :                     ulong block_cnt_max,        /* >= 1 */
     379             :                     ulong max_shreds_per_block, /* in [1,UINT_MAX] */
     380             :                     ulong max_txn_per_slot );   /* in [1,UINT_MAX] */
     381             : 
     382             : /* fd_sched_new creates a sched object backed by the given memory region
     383             :    (conforming to align() and footprint()).  Returns NULL if any
     384             :    parameter is invalid. */
     385             : 
     386             : void *
     387             : fd_sched_new( void *     mem,
     388             :               fd_rng_t * rng,
     389             :               ulong      depth,
     390             :               ulong      block_cnt_max,
     391             :               ulong      max_shreds_per_block,
     392             :               ulong      max_txn_per_slot,
     393             :               ulong      exec_cnt );
     394             : 
     395             : fd_sched_t *
     396             : fd_sched_join( void * mem );
     397             : 
     398             : /* Add the data in the FEC set to the scheduler.  If is_last_fec is 1,
     399             :    then this is the last FEC set in the block.  Transactions may span
     400             :    FEC set boundaries.  The scheduler is responsible for incrementally
     401             :    parsing transactions from concatenated FEC set data.  Assumes that
     402             :    FEC sets are delivered in replay order.  That is, forks form a
     403             :    partial ordering over FEC sets: in-order per fork, but arbitrary
     404             :    ordering across forks.  The fork tree is implied by the stream of
     405             :    parent-child relationships delivered in FEC sets.  Also assumes that
     406             :    there is enough space in the scheduler to ingest the FEC set.  The
     407             :    caller should generally call fd_sched_fec_can_ingest() first.
     408             : 
     409             :    Returns 1 on success, 0 if the block is bad and should be marked
     410             :    dead. */
     411             : FD_WARN_UNUSED int
     412             : fd_sched_fec_ingest( fd_sched_t * sched, fd_sched_fec_t * fec );
     413             : 
     414             : /* Check if there is enough space in the scheduler to ingest the data in
     415             :    the FEC set.  Returns 1 if there is, 0 otherwise.  This is a cheap
     416             :    and conservative check.  Staging lanes are a separate matter.  See
     417             :    fd_sched_fec_waits_for_lane(). */
     418             : int
     419             : fd_sched_fec_can_ingest( fd_sched_t * sched, fd_sched_fec_t * fec );
     420             : 
     421             : /* Returns the number of worst-case FEC sets sched can ingest. This is a
     422             :    cheap and conservative check. */
     423             : ulong
     424             : fd_sched_can_ingest_cnt( fd_sched_t * sched );
     425             : 
     426             : /* Returns 1 if the caller is advised to delay the ingestion of the FEC
     427             :    set due to hopefully transient lane shortage, 0 otherwise.  A
     428             :    parent_bank_idx of ULONG_MAX stands for a parent the caller has not
     429             :    resolved yet, in which case it will be assumed that a lane is needed.
     430             :    Any other parent_bank_idx must be a block tracked by the scheduler.
     431             :    A caller that ingests a FEC set anyway against the advice will get
     432             :    the block unstaged. */
     433             : int
     434             : fd_sched_fec_waits_for_lane( fd_sched_t * sched, ulong parent_bank_idx, int is_first_in_block );
     435             : 
     436             : /* Returns 1 if sched has no queued or in-flight work, 0 otherwise.  A
     437             :    non-drained scheduler may still return no task while it waits for
     438             :    in-flight work or advances an LtHash drain. */
     439             : int
     440             : fd_sched_is_drained( fd_sched_t * sched );
     441             : 
     442             : /* Claims up to cnt idle exec tiles for footer tasks of the active
     443             :    block, whose BLOCK_END is signaled and not done yet.  The tasks
     444             :    include the cert verifies the scheduler has not sent out as tasks of
     445             :    its own and the vote reward slices.  Returns the claimed tiles, bit i
     446             :    for tile i.  Each completes with
     447             : 
     448             :    fd_sched_task_done( FD_SCHED_TT_CERT_VERIFY or FD_SCHED_TT_REWARDS, ULONG_MAX, i, NULL )
     449             : 
     450             :    and the block is not done until all tasks have completed. */
     451             : 
     452             : ulong
     453             : fd_sched_footer_dispatch( fd_sched_t * sched,
     454             :                           ulong        bank_idx,
     455             :                           ulong        cnt );
     456             : 
     457             : /* Writes one dispatchable task to out and returns 1, or returns 0 if no
     458             :    task can be dispatched now.  Transaction tasks respect prior
     459             :    read-write and write-write conflicts.  Tasks from different forks may
     460             :    interleave, but a child does not start until its parent completes.
     461             : 
     462             :    LtHash tasks carry up to FD_SCHED_LTHASH_BATCH_MAX accounts.  A
     463             :    subtraction reads the parent fork and an addition reads the block's
     464             :    fork.  The caller returns the account hash sum through
     465             :    fd_sched_task_done(). */
     466             : ulong
     467             : fd_sched_task_next_ready( fd_sched_t * sched, fd_sched_task_t * out );
     468             : 
     469             : /* Marks a task complete.  Transaction effects must be visible to every
     470             :    core that could execute a dependent transaction before this call.
     471             :    data carries late writable lookup table accounts for a transaction,
     472             :    hash results for PoH and LtHash tasks, and is NULL for the other task
     473             :    types.
     474             : 
     475             :    Returns FD_SCHED_DEAD_REASON_NONE on success or the reason the result
     476             :    ruled the block invalid.
     477             : 
     478             :    If a block has been abandoned or marked dead for any reason, it'll be
     479             :    pruned the moment in-flight task count hits 0 due to the last task
     480             :    completing.  Then, in the immediate ensuing stem run loop,
     481             :    sched_pruned_next() will return the index for the corresponding bank
     482             :    so the refcnt can be decremented for sched.
     483             : 
     484             :    The transaction at the given index may be freed upon return from this
     485             :    function.  Nonetheless, as long as there is no intervening FEC
     486             :    ingestion, it would still be safe to query the transaction using
     487             :    get_txn(). */
     488             : int
     489             : fd_sched_task_done( fd_sched_t * sched, ulong task_type, ulong txn_idx, ulong exec_idx, void * data );
     490             : 
     491             : /* Returns the block's LtHash delta accumulated so far.  The delta is
     492             :    final once the block's BLOCK_END task has been handed out.  The block
     493             :    must be tracked by the scheduler and its BLOCK_END must not have
     494             :    completed.  It must hash out of band, which its BLOCK_START task
     495             :    reports in lthash_inband.  A block hashing in band has no delta from
     496             :    sched. */
     497             : fd_lthash_value_t const *
     498             : fd_sched_lthash_delta( fd_sched_t * sched, ulong bank_idx );
     499             : 
     500             : /* Inform the scheduler which accounts start-of-block processing wrote
     501             :    (e.g. sysvars, rewards), so their LtHash can be done out of band.
     502             :    Call between the block's BLOCK_START task being handed out and its
     503             :    completion, and only for a block whose BLOCK_START said it hashes out
     504             :    of band.  cnt must not exceed FD_SCHED_LTHASH_START_WRITES_MAX,
     505             :    duplicates included. */
     506             : void
     507             : fd_sched_block_start_writes( fd_sched_t * sched, ulong bank_idx, fd_acct_addr_t const * addrs, ulong cnt );
     508             : 
     509             : /* Abandon a block.  This means that we are no longer interested in
     510             :    executing the block.  This also implies that any block which chains
     511             :    off of the provided block shall be abandoned.  This is mainly used
     512             :    when a block is aborted because we decided that it would be a
     513             :    dead/invalid block, and so there's no point in spending resources
     514             :    executing it.  The scheduler will no longer return transactions from
     515             :    abandoned blocks for execution.  May be called on completed blocks
     516             :    still tracked by the scheduler.  Repeated calls retain the original
     517             :    abandonment cause.
     518             : 
     519             :    For the purposes of bank lifetime management, sched is a subsidiary
     520             :    of banks.  So while sched sets things in motion for a bad block to be
     521             :    eagerly pruned, banks/replay is the sole initiator of actual pruning.
     522             :    The way this works is that an abandoned block will have its refcnt
     523             :    queued for release by sched as soon as, and only if, the block has no
     524             :    more in-flight tasks associated with it.  No sooner, no later.  In
     525             :    the immediate ensuing stem run loop, sched_pruned_next() will return
     526             :    the index for the corresponding bank so the refcnt can be decremented
     527             :    for sched.  After that point, banks will eventually instruct sched to
     528             :    prune the block, when all other components release their refcnts on
     529             :    said bank.  Then the bank_idx may be recycled for another block.
     530             : 
     531             :    Pass FD_SCHED_ABANDON_INVALID if the block is ruled invalid for any
     532             :    reason, or FD_SCHED_ABANDON_DISCARDED if we are merely giving up on
     533             :    it without fault, e.g. eviction under resource pressure.  Descendants
     534             :    inherit the flavor: they record DEAD_ANCESTOR, and are marked
     535             :    discarded iff the lineage was discarded, provided they have no dead
     536             :    reason of their own.  A block that is already going down keeps the
     537             :    flavor it went down with, so a later abandon cannot re-label it. */
     538             : void
     539             : fd_sched_block_abandon( fd_sched_t * sched, ulong bank_idx, int cause );
     540             : 
     541             : /* fd_sched_get_dead_reason returns the scheduler's reason (one of
     542             :    FD_SCHED_DEAD_REASON_*) for why the block at bank_idx went down.
     543             :    Returns FD_SCHED_DEAD_REASON_NONE if the block itself was merely
     544             :    discarded (root advance, eviction) or if no block is currently
     545             :    tracked at bank_idx.  Descendants of a discarded lineage carry
     546             :    DEAD_ANCESTOR like any other lineage death;
     547             :    fd_sched_block_is_discarded disambiguates discarded from
     548             :    ruled-invalid.  The recorded reason is the first one; later failures
     549             :    on an already-dead block (e.g. an in-flight PoH task draining after
     550             :    the block was abandoned) do not overwrite it. */
     551             : int
     552             : fd_sched_get_dead_reason( fd_sched_t * sched, ulong bank_idx );
     553             : 
     554             : /* fd_sched_block_is_discarded returns 1 if the block went down with a
     555             :    discarded (not invalid) lineage, 0 otherwise (including when no
     556             :    block is tracked at bank_idx).  Never set on a block that has a dead
     557             :    reason of its own, so it does not mask the scheduler's own verdict. */
     558             : int
     559             : fd_sched_block_is_discarded( fd_sched_t * sched, ulong bank_idx );
     560             : 
     561             : /* Prune the given block including descendants of it. */
     562             : void
     563             : fd_sched_cancel( fd_sched_t * sched, ulong bank_idx );
     564             : 
     565             : /* Add a block as immediately done to the scheduler.  This is useful for
     566             :    installing the snapshot slot, or for informing the scheduler of a
     567             :    packed leader block.  Parent block should be ULONG_MAX for the
     568             :    snapshot slot, and otherwise a block that hasn't been pruned. */
     569             : void
     570             : fd_sched_block_add_done( fd_sched_t * sched, ulong bank_idx, ulong parent_bank_idx, ulong slot );
     571             : 
     572             : /* Advance the root, pruning all blocks across forks that do not descend
     573             :    from the new root.  Assumes the new root is in the fork tree and
     574             :    connected to the current root.  Also assumes that there are no more
     575             :    in-flight transactions from the soon-to-be-pruned blocks.  This
     576             :    should be called after root_notify() and the caller is responsible
     577             :    for figuring out the new root to safely prune to. */
     578             : void
     579             : fd_sched_advance_root( fd_sched_t * sched, ulong root_idx );
     580             : 
     581             : /* Notify the scheduler of a new root.  This has the effect of calling
     582             :    abandon() on all minority forks that do not descend from the new
     583             :    root.  Shortly after a call to this function, in-flight transactions
     584             :    from these abandoned blocks should retire from the execution
     585             :    pipeline, and the new root will be safe for pruning. */
     586             : void
     587             : fd_sched_root_notify( fd_sched_t * sched, ulong root_idx );
     588             : 
     589             : /* Returns the index of a bank whose refcnt should be decremented for
     590             :    sched.  This function should be called in a loop to drain all
     591             :    outstanding refcnt decrements before any other sched API is called in
     592             :    a stem run loop.  Returns ULONG_MAX when there are no more
     593             :    outstanding references from sched and the loop should break. */
     594             : ulong
     595             : fd_sched_pruned_block_next( fd_sched_t * sched );
     596             : 
     597             : /* fd_sched_slot_states_drain copies the slot state intervals closed
     598             :    since the last drain into out (room for FD_SCHED_SLOT_STATE_MAX) and
     599             :    returns how many were copied.  Intervals are in tickcount units. */
     600             : ulong
     601             : fd_sched_slot_states_drain( fd_sched_t * sched, fd_sched_slot_state_t * out );
     602             : 
     603             : void
     604             : fd_sched_set_poh_params( fd_sched_t * sched, ulong bank_idx, ulong tick_height, ulong max_tick_height, fd_hash_t const * start_poh );
     605             : 
     606             : /* fd_sched_set_flh_active records whether alpenglow_fast_leader_handover
     607             :    is active on the block's bank.  Called during BLOCK_START, once the
     608             :    bank is cloned.  A block started at its UpdateParent without the
     609             :    feature dies as SPURIOUS_UPDATE_PARENT when BLOCK_START is done. */
     610             : void
     611             : fd_sched_set_flh_active( fd_sched_t * sched, ulong bank_idx, int flh_active );
     612             : 
     613             : /* fd_sched_block_verify_ticks sets the tick window and verifies
     614             :    ticks on bank_idx (shred fuzz harness, no exec).  Returns
     615             :    FD_SCHED_DEAD_REASON_NONE (0) if valid, else the
     616             :    FD_SCHED_DEAD_REASON_* the ticks are invalid for.  Does not rule the
     617             :    block invalid; the caller decides what to do with the verdict. */
     618             : int
     619             : fd_sched_block_verify_ticks( fd_sched_t * sched,
     620             :                              ulong        bank_idx,
     621             :                              ulong        tick_height,
     622             :                              ulong        max_tick_height );
     623             : 
     624             : /* fd_sched_set_bypass_poh_verify configures whether the per-microblock
     625             :    PoH end_hash comparison in maybe_mixin is bypassed.  This is intended
     626             :    for test and fuzz harnesses: the expected end_hash is carried in the
     627             :    shred payload, so comparing it would reject any mutated input before
     628             :    the deeper parse/tick logic is exercised.  Production call sites
     629             :    should leave this disabled. */
     630             : void
     631             : fd_sched_set_bypass_poh_verify( fd_sched_t * sched, int bypass_poh_verify );
     632             : 
     633             : /* fd_sched_set_bypass_alut_resolution bypasses ALUT resolution during
     634             :    parsing (test/fuzz: no accounts DB).  ALUT txns become serializing.
     635             :    Production call sites should leave this disabled. */
     636             : void
     637             : fd_sched_set_bypass_alut_resolution( fd_sched_t * sched, int bypass_alut_resolution );
     638             : 
     639             : /* fd_sched_set_lthash_txn_writers_max lowers the bound on writable
     640             :    accounts declared by a block's transactions from
     641             :    FD_SCHED_LTHASH_TXN_WRITERS_MAX.  This is intended for use by tests
     642             :    to reach the bound with a few transactions.  Production code should
     643             :    not use this. */
     644             : void
     645             : fd_sched_set_lthash_txn_writers_max( fd_sched_t * sched, ulong lthash_txn_writers_max );
     646             : 
     647             : /* fd_sched_set_lthash_oob_block_max lowers the bound on blocks hashing
     648             :    out of band at once from the number of demoted blocks' writable sets
     649             :    the dispatcher has room to park.  This is intended for use by tests
     650             :    to reach the in-band fallback with a few blocks.  Production code
     651             :    should not use this. */
     652             : void
     653             : fd_sched_set_lthash_oob_block_max( fd_sched_t * sched, ulong lthash_oob_block_max );
     654             : 
     655             : fd_txn_p_t *
     656             : fd_sched_get_txn( fd_sched_t * sched, ulong txn_idx );
     657             : 
     658             : fd_sched_txn_info_t *
     659             : fd_sched_get_txn_info( fd_sched_t * sched, ulong txn_idx );
     660             : 
     661             : fd_hash_t *
     662             : fd_sched_get_poh( fd_sched_t * sched, ulong bank_idx );
     663             : 
     664             : uint
     665             : fd_sched_get_shred_cnt( fd_sched_t * sched, ulong bank_idx );
     666             : 
     667             : /* fd_sched_get_footer returns the block footer, or NULL if no footer
     668             :    marker has been parsed for the block.  The shapes were validated at
     669             :    parse time; the signatures are not verified.  The footer stays valid
     670             :    until the block is pruned. */
     671             : fd_block_footer_t const *
     672             : fd_sched_get_footer( fd_sched_t * sched, ulong bank_idx );
     673             : 
     674             : void
     675             : fd_sched_metrics_write( fd_sched_t *            sched,
     676             :                         fd_clock_tile_t const * clock );
     677             : 
     678             : /* Serialize the current state as a cstr to the returned buffer.  Caller
     679             :    may read from the buffer until the next invocation of any fd_sched
     680             :    function. */
     681             : char *
     682             : fd_sched_get_state_cstr( fd_sched_t * sched );
     683             : 
     684             : void *
     685             : fd_sched_leave( fd_sched_t * sched );
     686             : 
     687             : void *
     688             : fd_sched_delete( void * mem );
     689             : 
     690             : FD_PROTOTYPES_END
     691             : 
     692             : #endif /* HEADER_fd_src_discof_replay_fd_sched_h */

Generated by: LCOV version 1.14