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 :
11 : /* Max microblocks (including ticks) that fit in a block's shreds;
12 : scaled with max_shreds_per_block at runtime. */
13 0 : #define FD_SCHED_MAX_MBLK_PER_SLOT (FD_SHRED_DATA_PAYLOAD_MAX_PER_SLOT/sizeof(fd_microblock_hdr_t))
14 :
15 : /* Most exec tiles a scheduler can dispatch to. */
16 0 : #define FD_SCHED_MAX_EXEC_TILE_CNT (64UL)
17 :
18 : /* Most banks with transactions in flight at once, one per staging
19 : lane. */
20 0 : #define FD_SCHED_MAX_STAGING_LANES_LOG (2)
21 0 : #define FD_SCHED_MAX_STAGING_LANES (1UL<<FD_SCHED_MAX_STAGING_LANES_LOG)
22 :
23 : /* fd_sched wraps all the smarts and mechanical chores around scheduling
24 : transactions for replay execution. It is built on top of the
25 : dispatcher fd_rdisp. The dispatcher is responsible for high
26 : performance lane-based scheduling of transactions. On top of that,
27 : we add fork-aware management of lanes, and policies regarding which
28 : lanes to prioritize for execution.
29 :
30 : Conceptually, transactions in a block form a DAG. We would like to
31 : make our way through a block with a sufficient degree of parallelism,
32 : such that the execution time of the critical path of the DAG is the
33 : limiting factor. The dispatcher does a good job of emerging the
34 : critical path of the DAG on the fly. Blocks are tracked by the
35 : dispatcher either as a block staged on a lane, or as an unstaged
36 : block. When a block is staged, it will enjoy the most intelligent
37 : online scheduling that the dispatcher has to offer. Lanes have to
38 : consist of linear chains of blocks down a fork. So to map a fork
39 : tree to lanes, we will need multiple lanes. Ideally, every branch in
40 : the fork tree sits on some lane. However, memory footprint limits us
41 : to a few number of lanes.
42 :
43 : This module implements a state machine for ensuring that blocks enter
44 : into and exit out of lanes in an orderly fashion. The public APIs of
45 : this module are invoked to drive state transitions on a small number
46 : of events, such as new transactions arriving, or transactions
47 : completing, or a block being aborted/abandoned. We also implement
48 : policies for deciding which blocks get staged onto lanes, or evicted
49 : from lanes, as well as which lanes to prioritize for execution.
50 :
51 :
52 : The general order in which calls happen under the normal case is:
53 :
54 : fd_sched_fec_ingest()* ... fd_sched_txn_next_ready()* ... fd_sched_txn_done()* ...
55 : more ingest, more ready, more done ...
56 : ...
57 : fd_sched_txn_next_ready() indicates that the last transaction in the block is being scheduled
58 : fd_sched_txn_done()*
59 : fd_sched_block_is_done()
60 : end-of-block processing in caller
61 : fd_sched_txn_next_ready() starts returning transactions from the next block
62 : more ingest, more ready, more done ...
63 : ... */
64 :
65 0 : #define FD_SCHED_MIN_DEPTH 478
66 : #define FD_SCHED_MAX_DEPTH FD_RDISP_MAX_DEPTH
67 :
68 : struct fd_sched;
69 : typedef struct fd_sched fd_sched_t;
70 :
71 : struct fd_sched_alut_ctx {
72 : fd_accdb_t * accdb;
73 : fd_accdb_fork_id_t fork_id;
74 : ulong els; /* Effective lookup slot. */
75 : };
76 : typedef struct fd_sched_alut_ctx fd_sched_alut_ctx_t;
77 :
78 : struct fd_sched_fec {
79 : ulong bank_idx; /* Index of the block. Assumed to be in [0, block_cnt_max). Caller
80 : is responsible for ensuring that bank idx is in bounds and unique
81 : across equivocated blocks. */
82 : ulong parent_bank_idx; /* Index of the parent block. Assumed to be in [0, block_cnt_max).
83 : Caller is responsible for ensuring that parent bank idx is in
84 : bounds and unique across equivocated blocks. */
85 : ulong slot; /* Slot number of the block. */
86 : ulong parent_slot; /* Slot number of the parent block. */
87 : fd_store_fec_t * fec; /* FEC set metadata. */
88 : uchar * data; /* Resolved laddr of the FEC set data buffer. */
89 : uint shred_cnt; /* Number of shreds in the FEC set. */
90 : uint is_last_in_batch:1; /* Set if this is the last FEC set in the batch; relevant because the
91 : parser should ignore trailing bytes at the end of a batch. */
92 : uint is_last_in_block:1; /* Set if this is the last FEC set in the block. */
93 : 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. */
94 : long completed_ns; /* Network arrival (wallclock ns) of the shred that completed this FEC set; 0 if unavailable. */
95 :
96 : fd_sched_alut_ctx_t alut_ctx[ 1 ];
97 : };
98 : typedef struct fd_sched_fec fd_sched_fec_t;
99 :
100 : /* The state of a transaction. Non mutually exclusive. */
101 0 : #define FD_SCHED_TXN_EXEC_DONE (0x0001UL)
102 0 : #define FD_SCHED_TXN_SIGVERIFY_DONE (0x0002UL)
103 0 : #define FD_SCHED_TXN_IS_COMMITTABLE (0x0004UL)
104 0 : #define FD_SCHED_TXN_IS_FEES_ONLY (0x0008UL)
105 0 : #define FD_SCHED_TXN_IS_NOOP (0x0010UL)
106 : #define FD_SCHED_TXN_REPLAY_DONE (FD_SCHED_TXN_EXEC_DONE|FD_SCHED_TXN_SIGVERIFY_DONE)
107 :
108 : struct fd_sched_txn_info {
109 : ulong flags;
110 : int txn_err;
111 : uint next_idx;
112 : long received_ns;
113 : int is_simple_vote;
114 :
115 : /* LONG_MAX if stage was not reached */
116 : long tick_parsed;
117 : long tick_sigverify_disp;
118 : long tick_sigverify_done;
119 : long tick_exec_disp;
120 : long tick_exec_done;
121 : long tick_load_start;
122 : long tick_check_start;
123 : long tick_exec_start;
124 : long tick_commit_start;
125 : long tick_commit_end;
126 :
127 : ulong slot;
128 : ulong bank_seq;
129 : ulong index_in_slot; /* 0-indexed position of this transaction within its block. */
130 : ulong exec_tile_idx;
131 : ulong sigverify_exec_tile_idx;
132 : uint compute_units_consumed; /* possibly zero if is_committable is zero */
133 : ulong max_compute_units;
134 : ulong transaction_fee;
135 : ulong priority_fee;
136 : ulong tips;
137 : };
138 : typedef struct fd_sched_txn_info fd_sched_txn_info_t;
139 :
140 : /* The scheduler may return one of the following types of tasks for the
141 : replay tile.
142 :
143 : e - passed down to exec tiles.
144 : i - replay completes the task immediately.
145 : q - replay may either do it immediately or queue the task up. */
146 0 : #define FD_SCHED_TT_NULL (0UL)
147 0 : #define FD_SCHED_TT_BLOCK_START (1UL) /* (i) Start-of-block processing. */
148 0 : #define FD_SCHED_TT_BLOCK_END (2UL) /* (q) End-of-block processing. */
149 0 : #define FD_SCHED_TT_TXN_EXEC (3UL) /* (e) Transaction execution. */
150 0 : #define FD_SCHED_TT_TXN_SIGVERIFY (4UL) /* (e) Transaction sigverify. */
151 : #define FD_SCHED_TT_LTHASH (5UL) /* (e) Account lthash. */
152 0 : #define FD_SCHED_TT_POH_HASH (6UL) /* (e) PoH hashing. */
153 0 : #define FD_SCHED_TT_MARK_DEAD (7UL) /* (i) Mark the block dead. */
154 0 : #define FD_SCHED_TT_CERT_VERIFY (8UL) /* (e) Footer cert verify. */
155 :
156 : struct fd_sched_block_start {
157 : ulong bank_idx; /* Same as in fd_sched_fec_t. */
158 : ulong parent_bank_idx; /* Same as in fd_sched_fec_t. */
159 : ulong slot; /* Slot number of the block. */
160 : };
161 : typedef struct fd_sched_block_start fd_sched_block_start_t;
162 :
163 : struct fd_sched_block_end {
164 : ulong bank_idx;
165 : };
166 : typedef struct fd_sched_block_end fd_sched_block_end_t;
167 :
168 : struct fd_sched_txn_exec {
169 : ulong bank_idx;
170 : ulong slot;
171 : ulong txn_idx;
172 : ulong exec_idx;
173 : };
174 : typedef struct fd_sched_txn_exec fd_sched_txn_exec_t;
175 :
176 : struct fd_sched_txn_sigverify {
177 : ulong bank_idx;
178 : ulong txn_idx;
179 : ulong exec_idx;
180 : };
181 : typedef struct fd_sched_txn_sigverify fd_sched_txn_sigverify_t;
182 :
183 : #define FD_SCHED_POH_PARA 16
184 : struct fd_sched_poh_hash {
185 : ulong bank_idx;
186 : ulong exec_idx;
187 : ulong cnt; /* In [1,FD_SCHED_POH_PARA] */
188 : ulong hashcnt; /* Same for every element of the batch */
189 : ulong mblk_idx[ FD_SCHED_POH_PARA ];
190 : fd_hash_t hash [ FD_SCHED_POH_PARA ];
191 : };
192 : typedef struct fd_sched_poh_hash fd_sched_poh_hash_t;
193 :
194 : struct fd_sched_mark_dead {
195 : ulong bank_idx;
196 : };
197 : typedef struct fd_sched_mark_dead fd_sched_mark_dead_t;
198 :
199 : struct fd_sched_task {
200 : ulong task_type; /* Set to one of the task types defined above. */
201 : union {
202 : fd_sched_block_start_t block_start[ 1 ];
203 : fd_sched_block_end_t block_end[ 1 ];
204 : fd_sched_txn_exec_t txn_exec[ 1 ];
205 : fd_sched_txn_sigverify_t txn_sigverify[ 1 ];
206 : fd_sched_poh_hash_t poh_hash[ 1 ];
207 : fd_sched_mark_dead_t mark_dead[ 1 ];
208 : };
209 : };
210 : typedef struct fd_sched_task fd_sched_task_t;
211 :
212 :
213 0 : #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. */
214 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. */
215 0 : #define FD_SCHED_DEAD_REASON_SHORT_BLOCK (2) /* Block bytes ended short of the microblocks and transactions declared. */
216 0 : #define FD_SCHED_DEAD_REASON_TOO_MANY_TXNS (3) /* More transactions than a valid block can hold. */
217 0 : #define FD_SCHED_DEAD_REASON_TOO_MANY_MICROBLOCKS (4) /* More microblocks than a valid block can hold. */
218 0 : #define FD_SCHED_DEAD_REASON_DUPLICATE_ACCOUNT (5) /* Transaction referenced the same account more than once. */
219 0 : #define FD_SCHED_DEAD_REASON_TRAILING_ENTRY (6) /* Block did not end on a tick. */
220 0 : #define FD_SCHED_DEAD_REASON_TOO_MANY_TICKS (7) /* More ticks than required. */
221 0 : #define FD_SCHED_DEAD_REASON_TOO_FEW_TICKS (8) /* Fewer ticks than required. */
222 0 : #define FD_SCHED_DEAD_REASON_ZERO_MICROBLOCKS (9) /* A batch header declared zero microblocks. */
223 0 : #define FD_SCHED_DEAD_REASON_WRONG_HASHES_PER_TICK (10) /* Tick hash count did not advance the expected hashes per tick. */
224 0 : #define FD_SCHED_DEAD_REASON_INCONSISTENT_TICK_HASHES (11) /* Tick hash count differs from the block's preceding ticks, detected at FEC ingest. */
225 0 : #define FD_SCHED_DEAD_REASON_TICK_HASHES_OVERFLOW (12) /* More hashes since the last tick than hashes per tick allows. */
226 0 : #define FD_SCHED_DEAD_REASON_TICK_HASHES_OVERFLOW_INGEST (13) /* Tick header declared more hashes than can fit before the next tick, detected at FEC ingest. */
227 0 : #define FD_SCHED_DEAD_REASON_ZERO_HASH_TICK (14) /* Tick advanced zero hashes; PoH params were unknown when the tick parsed. */
228 0 : #define FD_SCHED_DEAD_REASON_ZERO_HASH_TICK_INGEST (15) /* Tick advanced zero hashes, detected at FEC ingest. */
229 0 : #define FD_SCHED_DEAD_REASON_TICK_HASH_MISMATCH (16) /* PoH hash of a tick did not verify. */
230 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. */
231 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. */
232 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. */
233 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. */
234 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. */
235 : /* Alpenglow block structure, mirroring agave's BlockComponentProcessor:
236 : header | [genesis cert] | entries* | footer | alpentick */
237 0 : #define FD_SCHED_DEAD_REASON_MISSING_PARENT_MARKER (22) /* An Alpenglow block carried an entry batch or footer before any block header. */
238 0 : #define FD_SCHED_DEAD_REASON_MULTIPLE_BLOCK_HEADERS (23) /* An Alpenglow block carried more than one block header. */
239 0 : #define FD_SCHED_DEAD_REASON_GENESIS_CERT_OUT_OF_ORDER (24) /* An Alpenglow genesis certificate marker did not immediately follow the block header. */
240 0 : #define FD_SCHED_DEAD_REASON_MULTIPLE_BLOCK_FOOTERS (25) /* An Alpenglow block carried more than one block footer. */
241 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. */
242 0 : #define FD_SCHED_DEAD_REASON_INVALID_ALPENTICK_POSITION (27) /* An Alpenglow block ended without the alpentick directly after its footer. */
243 0 : #define FD_SCHED_DEAD_REASON_MISSING_BLOCK_FOOTER (28) /* An Alpenglow block ended without a block footer. */
244 0 : #define FD_SCHED_DEAD_REASON_SPURIOUS_UPDATE_PARENT (29) /* An Alpenglow block carried an UpdateParent marker where none is valid: before the header or after the footer. */
245 : /* Cause to pass to fd_sched_block_abandon(). A block is considered
246 : invalid when it violates the protocol, so validity is a function of
247 : the block's content. A block may be discarded (temporarily) because
248 : the validator is under resource pressure. A block may be discarded
249 : (permanently) if consensus converged on an alternative fork, which is
250 : done implicitly in fd_sched_root_notify() for the minority forks it
251 : abandons. */
252 0 : #define FD_SCHED_ABANDON_DISCARDED (0)
253 0 : #define FD_SCHED_ABANDON_INVALID (1)
254 :
255 : struct __attribute__((packed)) fd_microblock_hdr {
256 : /* Number of PoH hashes between this and last microblock */
257 : /* 0x00 */ ulong hash_cnt;
258 :
259 : /* PoH state after evaluating this microblock (including all
260 : appends and mixin). The input to the poh calculation of the first
261 : microblock is the last hash of the parent block, otherwise it is the
262 : hash of the previous microblock. */
263 : /* 0x08 */ uchar hash[32];
264 :
265 : /* Number of transactions in this microblock */
266 : /* 0x28 */ ulong txn_cnt;
267 : };
268 : typedef struct fd_microblock_hdr fd_microblock_hdr_t;
269 :
270 : FD_PROTOTYPES_BEGIN
271 :
272 : /* fd_sched_{align,footprint} return the required alignment and
273 : footprint in bytes for a region of memory to be used as a scheduler.
274 : footprint silently returns 0 if params are invalid (thus convenient
275 : to validate params).
276 :
277 : depth controls the reorder buffer transaction count (~1 million
278 : recommended for live replay, ~10k recommended for async replay).
279 : block_cnt_max is the maximum number of blocks that will be tracked by
280 : the scheduler. max_shreds_per_block bounds the data shreds a block
281 : may hold (the shred tile enforces the same limit upstream, sched
282 : asserts it); a block declaring more than max_txn_per_slot
283 : transactions is ruled invalid. FD_SHRED_BLK_MAX and
284 : FD_MAX_TXN_PER_SLOT in production. */
285 :
286 : ulong
287 : fd_sched_align( void );
288 :
289 : ulong
290 : fd_sched_footprint( ulong depth, /* in [FD_SCHED_MIN_DEPTH,FD_SCHED_MAX_DEPTH] */
291 : ulong block_cnt_max, /* >= 1 */
292 : ulong max_shreds_per_block, /* in [1,UINT_MAX] */
293 : ulong max_txn_per_slot ); /* in [1,UINT_MAX] */
294 :
295 : /* fd_sched_new creates a sched object backed by the given memory region
296 : (conforming to align() and footprint()). Returns NULL if any
297 : parameter is invalid. */
298 :
299 : void *
300 : fd_sched_new( void * mem,
301 : fd_rng_t * rng,
302 : ulong depth,
303 : ulong block_cnt_max,
304 : ulong max_shreds_per_block,
305 : ulong max_txn_per_slot,
306 : ulong exec_cnt,
307 : int is_alpenglow );
308 :
309 : fd_sched_t *
310 : fd_sched_join( void * mem );
311 :
312 : /* Add the data in the FEC set to the scheduler. If is_last_fec is 1,
313 : then this is the last FEC set in the block. Transactions may span
314 : FEC set boundaries. The scheduler is responsible for incrementally
315 : parsing transactions from concatenated FEC set data. Assumes that
316 : FEC sets are delivered in replay order. That is, forks form a
317 : partial ordering over FEC sets: in-order per fork, but arbitrary
318 : ordering across forks. The fork tree is implied by the stream of
319 : parent-child relationships delivered in FEC sets. Also assumes that
320 : there is enough space in the scheduler to ingest the FEC set. The
321 : caller should generally call fd_sched_fec_can_ingest() first.
322 :
323 : Returns 1 on success, 0 if the block is bad and should be marked
324 : dead. */
325 : FD_WARN_UNUSED int
326 : fd_sched_fec_ingest( fd_sched_t * sched, fd_sched_fec_t * fec );
327 :
328 : /* Check if there is enough space in the scheduler to ingest the data in
329 : the FEC set. Returns 1 if there is, 0 otherwise. This is a cheap
330 : and conservative check. */
331 : int
332 : fd_sched_fec_can_ingest( fd_sched_t * sched, fd_sched_fec_t * fec );
333 :
334 : /* Returns the number of worst-case FEC sets sched can ingest. This is a
335 : cheap and conservative check. */
336 : ulong
337 : fd_sched_can_ingest_cnt( fd_sched_t * sched );
338 :
339 : /* Returns 1 if sched is drained, 0 otherwise. A drained scheduler will
340 : not return more work. Otherwise, next_ready will return more work,
341 : so long as there are exec tiles available. */
342 : int
343 : fd_sched_is_drained( fd_sched_t * sched );
344 :
345 : /* Returns 1 if the active block has not been started yet, i.e. the
346 : next task next_ready returns for it is a BLOCK_START, 0 otherwise. */
347 : int
348 : fd_sched_block_start_pending( fd_sched_t * sched );
349 :
350 : /* fd_sched_cert_dispatch claims up to cnt idle exec tiles for footer
351 : cert verify tasks of the active block, whose BLOCK_END is signaled
352 : and not done yet. Returns the claimed tiles (bit i for tile i).
353 : Each completes with fd_sched_task_done( FD_SCHED_TT_CERT_VERIFY,
354 : ULONG_MAX, i, NULL ), and the block is not done until all have. */
355 :
356 : ulong
357 : fd_sched_cert_dispatch( fd_sched_t * sched,
358 : ulong bank_idx,
359 : ulong cnt );
360 :
361 : /* Obtain a transaction eligible for execution. This implies that all
362 : prior transactions with w-r or w-w conflicts have completed.
363 : Information regarding the scheduled transaction is written to the out
364 : pointer. Returns 1 on success, 0 on failure. Failures are generally
365 : transient and non-fatal, and are simply an indication that no
366 : transaction is ready for execution yet. When in-flight transactions
367 : retire or when more FEC sets are ingested, more transactions may
368 : become ready for execution.
369 :
370 : Transactions on the same fork will be returned in a way that
371 : maintains the serial fiction. That is, reordering can happen, but
372 : only within the constraint that transactions appear to be ready in
373 : the order in which they occur in the block. Transactions from
374 : different forks may interleave, and the caller should be prepared to
375 : switch execution context in response to interleavings. The scheduler
376 : will barrier on block boundaries, in the sense that transactions from
377 : a subsequent block will not be returned for execution until all
378 : transactions from the previous block have completed. This gives the
379 : caller a chance to perform end-of-block processing before
380 : transactions from a subsequent block start executing. In general,
381 : the caller should check if the last transaction in the current block
382 : is done, and if so, do end-of-block processing before calling this
383 : function to start the next block.
384 :
385 : In addition to returning transactions for execution, this function
386 : may also return a sigverify task. Sigverify can be completed
387 : asynchronously outside the critical path of transaction execution, as
388 : long as every transaction in a block passes sigverify before we
389 : commit the block. The scheduler prioritizes actual execution of
390 : transactions over sigverify, and in general sigverify tasks are only
391 : returned when no real transaction can be dispatched. In other words,
392 : the scheduler tries to exploit idle cycles in the exec tiles during
393 : times of low parallelism critical path progression.
394 :
395 : This function may also return a PoH hashing task. These tasks are
396 : lower priority than transaction execution, but higher priority than
397 : sigverify. This is because sigverify tasks are generally bite-sized,
398 : whereas PoH hashing can be longer, so we would like to get started on
399 : hashing sooner rather than later. */
400 : ulong
401 : fd_sched_task_next_ready( fd_sched_t * sched, fd_sched_task_t * out );
402 :
403 : /* Mark a task as complete. For transaction execution, this means that
404 : the effects of the execution are now visible on any core that could
405 : execute a subsequent transaction. Returns FD_SCHED_DEAD_REASON_NONE
406 : (0) on success. If, given the result of the task, the block turns
407 : out to be bad, returns the nonzero FD_SCHED_DEAD_REASON_* it was
408 : ruled bad for. Only PoH tasks can rule a block bad, and not only
409 : for a PoH hash mismatch: eager tick verification also runs on this
410 : path.
411 :
412 : If a block has been abandoned or marked dead for any reason, it'll be
413 : pruned the moment in-flight task count hits 0 due to the last task
414 : completing. Then, in the immediate ensuing stem run loop,
415 : sched_pruned_next() will return the index for the corresponding bank
416 : so the refcnt can be decremented for sched.
417 :
418 : The transaction at the given index may be freed upon return from this
419 : function. Nonetheless, as long as there is no intervening FEC
420 : ingestion, it would still be safe to query the transaction using
421 : get_txn(). */
422 : int
423 : fd_sched_task_done( fd_sched_t * sched, ulong task_type, ulong txn_idx, ulong exec_idx, void * data );
424 :
425 : /* Abandon a block. This means that we are no longer interested in
426 : executing the block. This also implies that any block which chains
427 : off of the provided block shall be abandoned. This is mainly used
428 : when a block is aborted because we decided that it would be a
429 : dead/invalid block, and so there's no point in spending resources
430 : executing it. The scheduler will no longer return transactions from
431 : abandoned blocks for execution. This should only be invoked on an
432 : actively replayed block, and should only be invoked once on it.
433 :
434 : For the purposes of bank lifetime management, sched is a subsidiary
435 : of banks. So while sched sets things in motion for a bad block to be
436 : eagerly pruned, banks/replay is the sole initiator of actual pruning.
437 : The way this works is that an abandoned block will have its refcnt
438 : queued for release by sched as soon as, and only if, the block has no
439 : more in-flight tasks associated with it. No sooner, no later. In
440 : the immediate ensuing stem run loop, sched_pruned_next() will return
441 : the index for the corresponding bank so the refcnt can be decremented
442 : for sched. After that point, banks will eventually instruct sched to
443 : prune the block, when all other components release their refcnts on
444 : said bank. Then the bank_idx may be recycled for another block.
445 :
446 : Pass FD_SCHED_ABANDON_INVALID if the block is ruled invalid for any
447 : reason, or FD_SCHED_ABANDON_DISCARDED if we are merely giving up on
448 : it without fault, e.g. eviction under resource pressure. Descendants
449 : inherit the flavor: they record DEAD_ANCESTOR, and are marked
450 : discarded iff the lineage was discarded, provided they have no dead
451 : reason of their own. A block that is already going down keeps the
452 : flavor it went down with, so a later abandon cannot re-label it. */
453 : void
454 : fd_sched_block_abandon( fd_sched_t * sched, ulong bank_idx, int cause );
455 :
456 : /* fd_sched_get_dead_reason returns the scheduler's reason (one of
457 : FD_SCHED_DEAD_REASON_*) for why the block at bank_idx went down.
458 : Returns FD_SCHED_DEAD_REASON_NONE if the block itself was merely
459 : discarded (root advance, eviction) or if no block is currently
460 : tracked at bank_idx. Descendants of a discarded lineage carry
461 : DEAD_ANCESTOR like any other lineage death;
462 : fd_sched_block_is_discarded disambiguates discarded from
463 : ruled-invalid. The recorded reason is the first one; later failures
464 : on an already-dead block (e.g. an in-flight PoH task draining after
465 : the block was abandoned) do not overwrite it. */
466 : int
467 : fd_sched_get_dead_reason( fd_sched_t * sched, ulong bank_idx );
468 :
469 : /* fd_sched_block_is_discarded returns 1 if the block went down with a
470 : discarded (not invalid) lineage, 0 otherwise (including when no
471 : block is tracked at bank_idx). Never set on a block that has a dead
472 : reason of its own, so it does not mask the scheduler's own verdict. */
473 : int
474 : fd_sched_block_is_discarded( fd_sched_t * sched, ulong bank_idx );
475 :
476 : /* Prune the given block including descendants of it. */
477 : void
478 : fd_sched_cancel( fd_sched_t * sched, ulong bank_idx );
479 :
480 : /* Add a block as immediately done to the scheduler. This is useful for
481 : installing the snapshot slot, or for informing the scheduler of a
482 : packed leader block. Parent block should be ULONG_MAX for the
483 : snapshot slot, and otherwise a block that hasn't been pruned. */
484 : void
485 : fd_sched_block_add_done( fd_sched_t * sched, ulong bank_idx, ulong parent_bank_idx, ulong slot );
486 :
487 : /* Advance the root, pruning all blocks across forks that do not descend
488 : from the new root. Assumes the new root is in the fork tree and
489 : connected to the current root. Also assumes that there are no more
490 : in-flight transactions from the soon-to-be-pruned blocks. This
491 : should be called after root_notify() and the caller is responsible
492 : for figuring out the new root to safely prune to. */
493 : void
494 : fd_sched_advance_root( fd_sched_t * sched, ulong root_idx );
495 :
496 : /* Notify the scheduler of a new root. This has the effect of calling
497 : abandon() on all minority forks that do not descend from the new
498 : root. Shortly after a call to this function, in-flight transactions
499 : from these abandoned blocks should retire from the execution
500 : pipeline, and the new root will be safe for pruning. */
501 : void
502 : fd_sched_root_notify( fd_sched_t * sched, ulong root_idx );
503 :
504 : /* Returns the index of a bank whose refcnt should be decremented for
505 : sched. This function should be called in a loop to drain all
506 : outstanding refcnt decrements before any other sched API is called in
507 : a stem run loop. Returns ULONG_MAX when there are no more
508 : outstanding references from sched and the loop should break. */
509 : ulong
510 : fd_sched_pruned_block_next( fd_sched_t * sched );
511 :
512 : void
513 : fd_sched_set_poh_params( fd_sched_t * sched, ulong bank_idx, ulong tick_height, ulong max_tick_height, ulong hashes_per_tick, fd_hash_t const * start_poh );
514 :
515 : /* fd_sched_block_verify_ticks sets the tick window and verifies
516 : ticks on bank_idx (shred fuzz harness, no exec). Returns
517 : FD_SCHED_DEAD_REASON_NONE (0) if valid, else the
518 : FD_SCHED_DEAD_REASON_* the ticks are invalid for. Does not rule the
519 : block invalid; the caller decides what to do with the verdict. */
520 : int
521 : fd_sched_block_verify_ticks( fd_sched_t * sched,
522 : ulong bank_idx,
523 : ulong tick_height,
524 : ulong max_tick_height,
525 : ulong hashes_per_tick );
526 :
527 : /* fd_sched_set_bypass_poh_verify configures whether the per-microblock
528 : PoH end_hash comparison in maybe_mixin is bypassed. This is intended
529 : for test and fuzz harnesses: the expected end_hash is carried in the
530 : shred payload, so comparing it would reject any mutated input before
531 : the deeper parse/tick logic is exercised. Production call sites
532 : should leave this disabled. */
533 : void
534 : fd_sched_set_bypass_poh_verify( fd_sched_t * sched, int bypass_poh_verify );
535 :
536 : /* fd_sched_set_bypass_alut_resolution bypasses ALUT resolution during
537 : parsing (test/fuzz: no accounts DB). ALUT txns become serializing.
538 : Production call sites should leave this disabled. */
539 : void
540 : fd_sched_set_bypass_alut_resolution( fd_sched_t * sched, int bypass_alut_resolution );
541 :
542 : fd_txn_p_t *
543 : fd_sched_get_txn( fd_sched_t * sched, ulong txn_idx );
544 :
545 : fd_sched_txn_info_t *
546 : fd_sched_get_txn_info( fd_sched_t * sched, ulong txn_idx );
547 :
548 : fd_hash_t *
549 : fd_sched_get_poh( fd_sched_t * sched, ulong bank_idx );
550 :
551 : uint
552 : fd_sched_get_shred_cnt( fd_sched_t * sched, ulong bank_idx );
553 :
554 : /* fd_sched_get_footer returns the block footer, or NULL if no footer
555 : marker has been parsed for the block. The shapes were validated at
556 : parse time; the signatures are not verified. The footer stays valid
557 : until the block is pruned. */
558 : fd_block_footer_t const *
559 : fd_sched_get_footer( fd_sched_t * sched, ulong bank_idx );
560 :
561 : void
562 : fd_sched_metrics_write( fd_sched_t * sched,
563 : fd_clock_tile_t const * clock );
564 :
565 : /* Serialize the current state as a cstr to the returned buffer. Caller
566 : may read from the buffer until the next invocation of any fd_sched
567 : function. */
568 : char *
569 : fd_sched_get_state_cstr( fd_sched_t * sched );
570 :
571 : void *
572 : fd_sched_leave( fd_sched_t * sched );
573 :
574 : void *
575 : fd_sched_delete( void * mem );
576 :
577 : FD_PROTOTYPES_END
578 :
579 : #endif /* HEADER_fd_src_discof_replay_fd_sched_h */
|