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 */
|