Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_runtime_fd_bank_h
2 : #define HEADER_fd_src_flamenco_runtime_fd_bank_h
3 :
4 : #include "../leaders/fd_leaders.h"
5 : #include "../features/fd_features.h"
6 : #include "../stakes/fd_stake_delegations.h"
7 : #include "../stakes/fd_vote_stakes.h"
8 : #include "../stakes/fd_collector_overrides.h"
9 : #include "../progcache/fd_progcache_xid.h"
10 : #include "../fd_rwlock.h"
11 : #include "fd_blockhashes.h"
12 : #include "fd_cost_tracker.h"
13 : #include "fd_slot_params.h"
14 : #include "sysvar/fd_sysvar_cache.h"
15 : #include "../../ballet/lthash/fd_lthash.h"
16 : #include "fd_txncache_shmem.h"
17 : #include "../progcache/fd_progcache_base.h"
18 :
19 : FD_PROTOTYPES_BEGIN
20 :
21 114 : #define FD_BANKS_MAGIC (0XF17EDA2C7EBA2451) /* FIREDANCER BANKS V1 */
22 102 : #define FD_BANKS_MAX_BANKS (4096UL)
23 2100 : #define FD_BANKS_ALIGN (128UL)
24 :
25 : /* A fd_bank_t struct is the representation of the bank state on Solana
26 : for a given block. More specifically, the bank state corresponds to
27 : all information needed during execution that is not stored on-chain,
28 : but is instead cached in a validator's memory. Each of these bank
29 : fields are represented by a member of the fd_bank_t struct.
30 :
31 : Management of fd_bank_t structs must be fork-aware: the state of each
32 : fd_bank_t must be based on the fd_bank_t of its parent block. This
33 : state is managed by the fd_banks_t struct.
34 :
35 : In order to support fork-awareness, there are several key features
36 : that fd_banks_t and fd_bank_t MUST support:
37 : 1. Query for any non-rooted block's bank: create a fast lookup
38 : from bank index to bank
39 : 2. Be able to create a new bank for a given block from the bank of
40 : that block's parent and maintain some tree-like structure to
41 : track the parent-child relationships: copy the contents from a
42 : parent bank into a child bank.
43 : 3. Prune the set of active banks to keep the root updated as the
44 : network progresses: free resources of fd_bank_t structs that
45 : are are not direct descendants of the root bank (remove parents
46 : and any competing lineages). When a bank is marked as dead (ie.
47 : if the block corresponding to the bank is invalid), it also must
48 : be able to be eagerly pruned away.
49 : 4. Each bank will have field(s) that are concurrently read/write
50 : from multiple threads: add read-write locks to the fields that are
51 : concurrently written to.
52 : 5. In practice, a bank state for a given block can be very large and
53 : not all of the fields are written to every block. Therefore, it
54 : can be very expensive to copy the entire bank state for a given
55 : block each time a bank is created. In order to avoid large
56 : memcpys, we can use a CoW mechanism for certain fields.
57 : 6. In a similar vein, some fields are very large and are not written
58 : to very often, and are only read at the epoch boundary. The most
59 : notable example is the stake delegations cache. In order to
60 : handle this, we can use a delta-based approach where each bank
61 : only has a delta of the stake delegations. The root bank will own
62 : the full set of stake delegations. This means that the deltas are
63 : only applied to the root bank as each bank gets rooted. If the
64 : caller needs to access the full set of stake delegations for a
65 : given bank, they can assemble the full set of stake delegations by
66 : applying all of the deltas from the current bank and all of its
67 : ancestors up to the root bank.
68 :
69 : fd_banks_t is represented by a left-child, right-sibling n-ary tree
70 : (inspired by fd_ghost) to keep track of the parent-child fork tree.
71 : The underlying data structure is a pool of fd_bank_t structs. Banks
72 : are then accessed via an index into the bank pool (bank index).
73 :
74 : NOTE: The reason fd_banks_t is keyed by bank index and not by slot is
75 : to handle block equivocation: if there are two different blocks for
76 : the same slot, we need to be able to differentiate and handle both
77 : blocks against different banks. As mentioned above, the bank index is
78 : just an index into the bank pool. The caller is responsible for
79 : establishing a mapping from the bank index (which is managed by
80 : fd_banks_t) and runtime state (e.g. slot number).
81 :
82 : The fields in fd_bank_t can be categorized into two groups:
83 : 1. Simple fields: these are fields which don't need any special
84 : handling and are laid out contiguously in the fd_bank_t struct
85 : at bank->f.<field>.
86 : 2. Complex fields: these are fields which need special handling
87 : (e.g. locking, copy on write semantics, delta-based semantics).
88 : These types are not templatized and are manually defined below.
89 :
90 : Each field that is CoW has its own memory pool. The memory
91 : corresponding to the field is not located in the fd_bank_t struct and
92 : is instead represented by a pool/fork index. When the field is
93 : modified, a new element of the pool is acquired and the data is
94 : copied over from the parent.
95 :
96 : fd_stake_delegations_t stores its full state in fd_banks_t in
97 : out-of-line memory, with each bank carrying the fork index for its
98 : delta.
99 :
100 : The cost tracker is allocated from a pool. The lifetime of a cost
101 : tracker element starts when the bank is linked to a parent with a
102 : call to fd_banks_clone_from_parent() which makes the bank replayable.
103 : The lifetime of a cost tracker element ends when the bank is marked
104 : dead or when the bank is frozen.
105 :
106 : The lthash is a simple field that is laid out contiguously in the
107 : fd_bank_t struct, but is not templatized and it has its own lock.
108 :
109 : So, when a bank is cloned from a parent, the non CoW fields are copied
110 : over and the CoW fields just copy over a pool index. The CoW behavior
111 : is completely abstracted away from the caller as callers have to
112 : query/modify fields using specific APIs.
113 :
114 : The memory for the banks is based off of two bounds:
115 : 1. the max number of unrooted blocks at any given time. Most fields
116 : can be bounded by this value.
117 : 2. the max number of forks that execute through any 1 block. We bound
118 : fields that are only written to at the epoch boundary by
119 : the max fork width that can execute through the boundary instead of
120 : by the max number of banks. See fd_banks_footprint() for more
121 : details.
122 :
123 : There are also some important states that a bank can be in:
124 : - Initialized: This bank has been created and linked to a parent bank
125 : index with a call to fd_banks_new_bank(). However, it is not yet
126 : replayable.
127 : - Replayable: This bank has inherited state from its parent and now
128 : transactions can be executed against it. For a bank to become
129 : replayable, it must've been initialized beforehand.
130 : - Dead: This bank has been marked as dead. This means that the block
131 : that this bank is associated with is invalid. A bank can be marked
132 : dead before, during, or after it has finished replaying (i.e. the
133 : bank being marked dead just needs to be initialized). A bank
134 : can still be executing transactions while it is marked dead, but it
135 : shouldn't be dispatched any more work. In other words, a key
136 : invariant is that a bank's reference count should NEVER be increased
137 : after it has been marked dead.
138 : - Frozen: This bank has been marked as frozen and no other tasks
139 : should be dispatched to it. Any bank-specific resources will be
140 : released (e.g. cost tracker element). A bank can be marked frozen
141 : if the bank has finished executing all of its transactions or if the
142 : bank is marked as dead and has no outstanding references. A bank
143 : can only be copied from a parent bank (fd_banks_clone_from_parent)
144 : if the parent bank has been frozen. The program will crash if this
145 : invariant is violated.
146 : - Prunable: This bank has been marked for pruning away due to memory
147 : pressure on the banks. Additional references on the bank should not
148 : be accumulated after the bank has been marked prunable and once
149 : references reach zero, it is safe to evict the bank and free any
150 : related resources. At most one bank may be prunable. It must be a
151 : non-root, non-leader leaf in the initialized, replayable, or frozen
152 : state.
153 :
154 : The usage pattern is as follows:
155 :
156 : To create an initial bank:
157 : fd_bank_t * bank_init = fd_banks_init_bank( banks );
158 :
159 : To create a new bank. This simply provisions the memory for the bank
160 : but it should not be used to execute transactions against.
161 : ulong bank_index = fd_banks_new_bank( banks, parent_bank_index )->idx;
162 :
163 : To clone bank from parent banks. This makes a bank replayable by
164 : copying over the state from the parent bank into the child. It
165 : assumes that the bank index has been previously provisioned by a call
166 : to fd_banks_new_bank and that the parent bank index has been frozen.
167 : fd_bank_t * bank_clone = fd_banks_clone_from_parent( banks, bank_index );
168 :
169 : To ensure that the bank index we want to advance our root to is safe
170 : and that there are no outstanding references to the banks that are
171 : not descendants of the target bank.
172 : fd_banks_advance_root_prepare( banks, target_bank_idx, &advanceable_bank_idx_out );
173 :
174 : To advance the root bank. This assumes that the bank index is "safe"
175 : to advance to. This means that none of the ancestors of the bank
176 : index have a non-zero reference count.
177 : fd_banks_advance_root( banks, bank_index );
178 :
179 : To query some arbitrary bank:
180 : fd_bank_t * bank_query = fd_banks_bank_query( banks, bank_index );
181 :
182 : To access the fields in the bank if they are templatized:
183 :
184 : fd_struct_t const * field = fd_bank_field_query( bank );
185 : OR
186 : fd_struct field = fd_bank_field_get( bank );
187 :
188 : fd_struct_t * field = fd_bank_field_modify( bank );
189 : OR
190 : fd_bank_field_set( bank, value );
191 :
192 : If a bank is marked dead, the caller should call
193 : fd_banks_mark_bank_dead() to mark the bank and all of its descendants
194 : as dead. This does not actually free the underlying resources that
195 : the dead bank has allocated and instead just queues them up for
196 : pruning:
197 : fd_banks_mark_bank_dead( banks, dead_bank_idx, NULL, NULL );
198 :
199 : To actually prune away any dead banks, the caller should call:
200 : fd_banks_prune_one_bank( banks, cancel_info )
201 :
202 : The data used by an fd_bank_t or an fd_banks_t is stored in an
203 : fd_banks_t struct.
204 :
205 : If the fields are not templatized, their accessor and modifier
206 : patterns vary and are documented below.
207 : */
208 :
209 : struct fd_bank_cost_tracker {
210 : ulong next;
211 : uchar data[FD_COST_TRACKER_FOOTPRINT] __attribute__((aligned(FD_COST_TRACKER_ALIGN)));
212 : };
213 : typedef struct fd_bank_cost_tracker fd_bank_cost_tracker_t;
214 :
215 : #define POOL_NAME fd_bank_cost_tracker_pool
216 342 : #define POOL_T fd_bank_cost_tracker_t
217 : #include "../../util/tmpl/fd_pool.c"
218 :
219 : /* The banks follow a state machine that generally transitions forward:
220 : All banks start off as INACTIVE. Once a bank is provisioned (when
221 : the first FEC is received from the reassembler), it is in the state
222 : INIT; at this point, the bank is not yet replayable but the memory
223 : has been reserved. At this point, it is part of the bank tree and
224 : additional children bank can be assigned to the bank. Once the bank
225 : is replayable, it is moved from INIT to REPLAYABLE and any relevant
226 : state is copied over from the parent bank. We know that the parent
227 : bank is done executing at this point. Transactions can now be
228 : dispatched and scheduled against the bank. If the block for the bank
229 : is done executing then it transitions to the state FROZEN and the
230 : fields in the bank should no longer change.
231 :
232 : A bank can be marked DEAD even before it enters the replayable or
233 : frozen state. A dead bank can only transition to INACTIVE.
234 :
235 : INACTIVE -> INIT -> REPLAYABLE -> FROZEN -> INACTIVE
236 : | \ | \ \ |
237 : | v | v v v
238 : | DEAD | DEAD PRUNABLE
239 : | \ | / |
240 : v v v v v
241 : PRUNABLE INACTIVE INACTIVE
242 : | \
243 : v v
244 : DEAD INACTIVE
245 :
246 : A bank can also transition directly from INIT or REPLAYABLE to
247 : INACTIVE when root advancement prunes an unrooted, unreferenced
248 : sibling subtree. */
249 :
250 65196 : #define FD_BANK_STATE_INACTIVE (0UL)
251 4659 : #define FD_BANK_STATE_INIT (1UL)
252 4635 : #define FD_BANK_STATE_REPLAYABLE (2UL)
253 4833 : #define FD_BANK_STATE_FROZEN (3UL)
254 147 : #define FD_BANK_STATE_DEAD (4UL)
255 75 : #define FD_BANK_STATE_PRUNABLE (5UL)
256 :
257 : struct fd_bank {
258 :
259 : /* Fields used for internal pool and bank management */
260 : ulong idx; /* current fork idx of the bank (synchronized with the pool index) */
261 : ulong next; /* reserved for internal use by pool and fd_banks_advance_root */
262 : ulong parent_idx; /* index of the parent in the node pool */
263 : ulong child_idx; /* index of the left-child in the node pool */
264 : ulong sibling_idx; /* index of the right-sibling in the node pool */
265 : ulong state; /* keeps track of the state of the bank */
266 : ulong bank_seq; /* app-wide bank sequence number */
267 : uchar is_leader; /* whether the bank is the leader */
268 :
269 : ulong refcnt; /* reference count on the bank, see replay for more details */
270 :
271 : fd_txncache_fork_id_t txncache_fork_id;
272 : fd_progcache_fork_id_t progcache_fork_id;
273 : fd_accdb_fork_id_t accdb_fork_id;
274 : fd_accdb_fork_id_t parent_accdb_fork_id;
275 : ulong vote_stakes_fork_id;
276 : ushort collector_overrides_fork_id;
277 : uchar stake_rewards_fork_id;
278 : uchar epoch_credits_fork_id;
279 : ushort stake_delegations_fork_id;
280 : ulong cost_tracker_pool_idx;
281 :
282 : ulong banks_data_offset; /* offset from this fd_bank_t back to fd_banks_t */
283 :
284 : /* Timestamps written and read only by replay */
285 :
286 : long first_fec_set_received_nanos;
287 : long preparation_begin_nanos;
288 : long first_transaction_scheduled_nanos;
289 : long last_transaction_finished_nanos;
290 : long block_completed_nanos;
291 :
292 : /* This field should only be accessed by the replay and executor
293 : tiles. */
294 : fd_rwlock_t lthash_lock;
295 :
296 : struct {
297 : fd_lthash_value_t lthash;
298 : fd_blockhashes_t block_hash_queue;
299 : fd_fee_rate_governor_t fee_rate_governor;
300 : ulong rbh_lamports_per_sig;
301 : ulong slot;
302 : ulong parent_slot;
303 : ulong capitalization;
304 : ulong parent_signature_cnt;
305 : ulong parent_txn_count; /* cumulative txn_count of all ancestors */
306 : ulong tick_height;
307 : ulong max_tick_height;
308 : ulong ticks_per_slot;
309 : ulong genesis_creation_time;
310 : fd_inflation_t inflation;
311 : ulong cluster_type;
312 : ulong total_epoch_stake; /* total staked to active vote accounts */
313 : ulong total_effective_stake; /* effective stake from stake delegations */
314 : ulong total_activating_stake;
315 : ulong total_deactivating_stake;
316 : ulong warmup_cooldown_rate_epoch; /* epoch when reduce_stake_warmup_cooldown */
317 : ulong block_height;
318 : ulong execution_fees;
319 : ulong priority_fees;
320 : ulong tips;
321 : ulong signature_count;
322 : fd_hash_t poh;
323 : ulong hard_fork_cnt;
324 : fd_hard_fork_t hard_forks[ FD_HARD_FORKS_MAX ]; /* never changes at runtime, required for snapshot creation */
325 : fd_hash_t bank_hash;
326 : fd_hash_t prev_bank_hash;
327 : fd_epoch_schedule_t epoch_schedule;
328 : fd_rent_t rent;
329 : fd_sysvar_cache_t sysvar_cache;
330 : fd_features_t features;
331 : ulong txn_count;
332 : ulong nonvote_txn_count;
333 : ulong failed_txn_count;
334 : ulong nonvote_failed_txn_count;
335 : ulong total_compute_units_used;
336 : ulong shred_cnt;
337 : ulong epoch;
338 : ulong identity_vote_idx;
339 : fd_slot_params_t slot_params; /* parameters that need to change with the reduce_slot_time feature gates */
340 : fd_slot_params_t slot_params_default; /* slot params this cluster uses when no reduce_slot_time gate is active */
341 : fd_hash_t block_id;
342 : } f;
343 :
344 : };
345 : typedef struct fd_bank fd_bank_t;
346 :
347 : struct fd_banks_prune_cancel_info {
348 : fd_txncache_fork_id_t txncache_fork_id;
349 : fd_progcache_fork_id_t progcache_fork_id;
350 : fd_accdb_fork_id_t accdb_fork_id;
351 : ulong slot;
352 : ulong bank_seq;
353 : ulong bank_idx;
354 : };
355 : typedef struct fd_banks_prune_cancel_info fd_banks_prune_cancel_info_t;
356 :
357 : fd_stake_delegations_t *
358 : fd_bank_stake_delegations_modify( fd_bank_t * bank );
359 :
360 : /* fd_banks_t is the main struct used to manage the bank state. It can
361 : be used to query/modify/clone/publish the bank state.
362 :
363 : fd_banks_t contains some metadata to a pool to manage the banks.
364 : It also contains pointers to the CoW pools.
365 :
366 : The data is laid out contiguously in memory starting from fd_banks_t;
367 : this can be seen in fd_banks_footprint(). */
368 :
369 : #define POOL_NAME fd_banks_pool
370 342 : #define POOL_T fd_bank_t
371 : #include "../../util/tmpl/fd_pool.c"
372 :
373 : struct fd_bank_idx_seq {
374 : ulong idx;
375 : ulong seq;
376 : };
377 : typedef struct fd_bank_idx_seq fd_bank_idx_seq_t;
378 :
379 : #define DEQUE_NAME fd_banks_dead
380 33 : #define DEQUE_T fd_bank_idx_seq_t
381 102 : #define DEQUE_MAX FD_BANKS_MAX_BANKS
382 : #include "../../util/tmpl/fd_deque.c"
383 :
384 : struct fd_banks {
385 : ulong magic; /* ==FD_BANKS_MAGIC */
386 : ulong max_total_banks; /* Maximum number of banks */
387 : ulong max_fork_width; /* Maximum fork width executing through any given slot. */
388 : ulong max_stake_accounts; /* Maximum number of stake accounts */
389 : ulong max_vote_accounts; /* Maximum number of vote accounts */
390 : ulong root_idx; /* root idx */
391 : ulong bank_seq; /* app-wide bank sequence number counter; starts at 1 (0 is reserved as an invalid bank_seq sentinel) */
392 : ulong evict_rr_idx; /* internal index for round-robin banks eviction */
393 : ulong prunable_idx; /* index of pending prunable bank, ULONG_MAX if none */
394 : ulong max_fallback_stake_accounts; /* Maximum number of stake accounts nameable by the pubkey fallback tier */
395 :
396 : ulong curr_fork_width;
397 :
398 : ulong pool_offset; /* offset of pool from banks */
399 :
400 : ulong cost_tracker_pool_offset; /* offset of cost tracker pool from banks */
401 :
402 : ulong collector_overrides_offset;
403 :
404 : ulong stake_rewards_offset;
405 :
406 : ulong dead_banks_deque_offset;
407 :
408 : /* The epoch credits of every rewarded vote account are captured when a
409 : bank crosses an epoch boundary, and are read again for the rest of
410 : the epoch: by a recalculation that repositions a stake rewards
411 : window, and by snapshot creation. Sibling banks crossing the same
412 : boundary capture different sets, so the store holds one set per
413 : boundary-crossing fork, inherited by descendants and reference
414 : counted so that a set lives exactly as long as the banks reading it.
415 : There is one more set than max_fork_width because a bank sitting
416 : behind a boundary still holds the previous epoch's set while every
417 : fork crosses. */
418 :
419 : ulong epoch_credits_offset;
420 : ulong epoch_credits_len_offset;
421 : ulong epoch_credits_refcnt_offset;
422 :
423 : /* The set of epoch leaders for the current and previous epochs is
424 : allocated out-of-line and tracked by epoch_leaders_offset. Only
425 : two need to be stored because in the worst case we will have a root
426 : that sits behind an epoch boundary, with leaf banks executing into
427 : the next epoch. All banks that execute behind the boundary, will
428 : use the previous epoch's leader schedule, and all nodes after the
429 : epoch boundary are guaranteed to produce identical leader
430 : schedules. */
431 :
432 : ulong epoch_leaders_offset;
433 : ulong epoch_leaders_footprint;
434 :
435 : ulong stake_delegations_offset;
436 : ulong vote_stakes_offset;
437 : };
438 : typedef struct fd_banks fd_banks_t;
439 :
440 : /* Bank accessors and mutators. Different accessors are emitted for
441 : different types depending on if the field has a lock or not. */
442 :
443 : /* fd_bank_epoch_credits{,_len} return the epoch credits of the fork the
444 : bank belongs to. fd_bank_epoch_credits_new_fork acquires a fresh set
445 : for the bank and must be called before the bank captures new epoch
446 : credits, i.e. when it crosses an epoch boundary or restores a
447 : snapshot. */
448 :
449 : fd_epoch_credits_t *
450 : fd_bank_epoch_credits( fd_bank_t * bank );
451 :
452 : ulong *
453 : fd_bank_epoch_credits_len( fd_bank_t * bank );
454 :
455 : void
456 : fd_bank_epoch_credits_new_fork( fd_bank_t * bank );
457 :
458 : fd_collector_overrides_t *
459 : fd_bank_collector_overrides( fd_bank_t const * bank );
460 :
461 : fd_stake_rewards_t const *
462 : fd_bank_stake_rewards_query( fd_bank_t * bank );
463 :
464 : fd_stake_rewards_t *
465 : fd_bank_stake_rewards_modify( fd_bank_t * bank );
466 :
467 : fd_epoch_leaders_t const *
468 : fd_bank_epoch_leaders_query( fd_bank_t const * bank,
469 : ulong epoch );
470 :
471 : fd_epoch_leaders_t *
472 : fd_bank_epoch_leaders_modify( fd_bank_t * bank,
473 : ulong epoch );
474 :
475 : fd_vote_stakes_t *
476 : fd_bank_vote_stakes( fd_bank_t const * bank );
477 :
478 : fd_cost_tracker_t *
479 : fd_bank_cost_tracker_modify( fd_bank_t * bank );
480 :
481 : fd_cost_tracker_t const *
482 : fd_bank_cost_tracker_query( fd_bank_t * bank );
483 :
484 : fd_lthash_value_t const *
485 : fd_bank_lthash_locking_query( fd_bank_t * bank );
486 :
487 : void
488 : fd_bank_lthash_end_locking_query( fd_bank_t * bank );
489 :
490 : fd_lthash_value_t *
491 : fd_bank_lthash_locking_modify( fd_bank_t * bank );
492 :
493 : void
494 : fd_bank_lthash_end_locking_modify( fd_bank_t * bank );
495 :
496 : /* fd_bank_stake_delegations_frontier_query() will return a pointer to
497 : the full stake delegations for the current frontier. It takes the
498 : stake delegations write lock, excluding mutators in other tiles until
499 : fd_bank_stake_delegations_end_frontier_query() releases it.
500 :
501 : Under the hood, the function applies all of the stake delegation
502 : deltas from all banks starting from the root down to the current bank
503 : to the rooted version of the stake delegations. This is done in a
504 : reversible way and is unwound with a call to
505 : fd_bank_stake_delegations_end_frontier_query(). */
506 :
507 : fd_stake_delegations_t *
508 : fd_bank_stake_delegations_frontier_query( fd_banks_t * banks,
509 : fd_bank_t * bank );
510 :
511 : /* fd_bank_stake_delegations_end_frontier_query() will finish the
512 : reversible operation started by
513 : fd_bank_stake_delegations_frontier_query(). It is unsafe to call
514 : fd_bank_stake_delegations_frontier_query multiple times without
515 : calling this function in between.
516 :
517 : Under the hood, it undoes any references to the stake delegation
518 : deltas that were applied. */
519 :
520 : void
521 : fd_bank_stake_delegations_end_frontier_query( fd_banks_t * banks,
522 : fd_bank_t * bank );
523 :
524 : /* fd_banks_stake_delegations_root_query() will return a pointer to the
525 : full stake delegations for the current root. This function should
526 : only be called on boot. */
527 :
528 : fd_stake_delegations_t *
529 : fd_banks_stake_delegations_root_query( fd_banks_t * banks );
530 :
531 : /* fd_banks_pool_used_cnt returns the number of bank pool elements
532 : currently in use. */
533 :
534 : ulong
535 : fd_banks_pool_used_cnt( fd_banks_t * banks );
536 :
537 : /* fd_banks_pool_max_cnt returns the max number of bank pool elements. */
538 :
539 : ulong
540 : fd_banks_pool_max_cnt( fd_banks_t * banks );
541 :
542 : /* fd_banks_stake_delegations_evict_bank_fork evicts the stake
543 : delegations fork for the given bank. This is used to clean up
544 : resources during teardown. */
545 :
546 : void
547 : fd_banks_stake_delegations_evict_bank_fork( fd_banks_t * banks,
548 : fd_bank_t * bank );
549 :
550 : /* fd_banks_root() returns a pointer to the root bank respectively. */
551 :
552 : fd_bank_t *
553 : fd_banks_root( fd_banks_t * banks );
554 :
555 : /* fd_banks_align() returns the alignment of fd_banks_t */
556 :
557 : ulong
558 : fd_banks_align( void );
559 :
560 : /* fd_banks_footprint() returns the footprint of fd_banks_t. This
561 : includes the struct itself but also the footprint for all of the
562 : pools.
563 :
564 : The footprint of fd_banks_t is determined by the total number
565 : of banks that the bank manages. This is an analog for the max number
566 : of unrooted blocks the bank can manage at any given time.
567 :
568 : We can also further bound the memory footprint of the banks by the
569 : max width of forks that can exist at any given time. The reason for
570 : this is that there are several large CoW structs that are only
571 : written to during the epoch boundary (e.g. epoch_stakes, etc.).
572 : These structs are read-only afterwards. This
573 : means if we also bound the max number of forks that can execute
574 : through the epoch boundary, we can bound the memory footprint of
575 : the banks. */
576 :
577 : ulong
578 : fd_banks_footprint( ulong max_total_banks,
579 : ulong max_fork_width,
580 : ulong max_stake_accounts,
581 : ulong max_fallback_stake_accounts,
582 : ulong max_vote_accounts );
583 :
584 : /* fd_banks_new() creates a new fd_banks_t struct. This function
585 : lays out the memory for all of the constituent fd_bank_t structs
586 : and pools depending on the max_total_banks and the max_fork_width for
587 : a given block. */
588 :
589 : void *
590 : fd_banks_new( void * mem,
591 : ulong max_total_banks,
592 : ulong max_fork_width,
593 : ulong max_stake_accounts,
594 : ulong max_fallback_stake_accounts,
595 : ulong max_vote_accounts,
596 : int larger_max_cost_per_block,
597 : ulong seed );
598 :
599 : /* fd_banks_join() joins an fd_banks_t struct. It takes in a valid
600 : banks_data_mem. Returns a pointer to the joined fd_banks_t struct
601 : on success and NULL on failure (logs details). */
602 :
603 : fd_banks_t *
604 : fd_banks_join( void * banks_data_mem );
605 :
606 : /* fd_banks_init_bank() initializes a new bank in the bank manager.
607 : This should only be used during bootup. The bank is set to the
608 : FROZEN state (skipping INIT/REPLAYABLE since no replay is needed for
609 : the initial root) and is established as the root bank. */
610 :
611 : fd_bank_t *
612 : fd_banks_init_bank( fd_banks_t * banks );
613 :
614 : /* fd_banks_get_bank_idx returns a bank for a given bank index. */
615 :
616 : fd_bank_t *
617 : fd_banks_bank_query( fd_banks_t * banks,
618 : ulong bank_idx );
619 :
620 : fd_bank_t *
621 : fd_banks_get_parent( fd_banks_t * banks,
622 : fd_bank_t * bank );
623 :
624 : /* fd_banks_clone_from_parent() clones a bank from a parent bank.
625 : This function links the child bank to its parent bank and copies
626 : over the data from the parent bank to the child. This function
627 : assumes that the child and parent banks both have been allocated.
628 : The parent bank must be frozen and the child bank must be initialized
629 : but not yet used. It also assumes that the parent bank is not dead.
630 :
631 : A more detailed note: not all of the data is copied over and this
632 : is a shallow clone. All of the CoW fields are not copied over and
633 : will only be done so if the caller explicitly calls
634 : fd_bank_{*}_modify(). This naming was chosen to emulate the
635 : semantics of the Agave client. */
636 :
637 : fd_bank_t *
638 : fd_banks_clone_from_parent( fd_banks_t * banks,
639 : ulong bank_idx );
640 :
641 : /* fd_banks_advance_root() advances the root bank to the bank manager.
642 : This should only be used when a bank is no longer needed and has no
643 : active refcnts. This will prune off the bank from the bank manager.
644 : It returns the new root bank. An invariant of this function is that
645 : the new root bank should be a child of the current root bank.
646 :
647 : All banks that are ancestors or siblings of the new root bank will be
648 : cancelled and their resources will be released back to the pool. */
649 :
650 : void
651 : fd_banks_advance_root( fd_banks_t * banks,
652 : ulong bank_idx );
653 :
654 : /* fd_banks_clear releases all banks back to the pool and resets the
655 : banks manager to its post-new state. Assumes no active references to
656 : any bank. WARNING: collision risk, resets bank_seq to 1 (0 is the
657 : reserved invalid sentinel). */
658 :
659 : void
660 : fd_banks_clear( fd_banks_t * banks );
661 :
662 : /* fd_banks_advance_root_prepare returns the highest block that can be
663 : safely advanced between the current root of the fork tree and the
664 : target block. See the note on safe publishing for more details. In
665 : general, a node in the fork tree can be pruned if:
666 : (1) the node itself can be pruned, and
667 : (2) all subtrees (except for the one on the rooted fork) forking off
668 : of the node can be pruned.
669 :
670 : This function is read-only: it does not modify any bank state. It
671 : walks from the target bank up to the current root to find the direct
672 : child of root on the path, then checks whether all sibling subtrees
673 : of that child can be pruned.
674 :
675 : Highest advanceable block is written to the out pointer. Returns 1
676 : if the advanceable block can be advanced beyond the current root.
677 : Returns 0 if no such block can be found (e.g. the root still has a
678 : non-zero refcnt, or a sibling subtree cannot be pruned). We will
679 : ONLY advance our advanceable_bank_idx to a child of the current root.
680 : In order to advance to the target bank,
681 : fd_banks_advance_root_prepare() must be called repeatedly. */
682 :
683 : int
684 : fd_banks_advance_root_prepare( fd_banks_t * banks,
685 : ulong target_bank_idx,
686 : ulong * advanceable_bank_idx_out );
687 :
688 : /* fd_banks_mark_bank_dead marks the current bank (and all of its
689 : descendants) as dead. Already-dead subtrees are skipped. If
690 : opt_idxs is non-NULL, it is populated with each bank index newly
691 : marked dead. The caller is responsible for ensuring the buffer is
692 : large enough to hold the whole subtree. If opt_idxs_cnt is non-NULL,
693 : it is set to the number of banks newly marked dead. The caller is
694 : still responsible for handling the behavior of the dead bank
695 : correctly. After a bank is marked dead, the caller should never
696 : increment the reference count on the bank. */
697 :
698 : void
699 : fd_banks_mark_bank_dead( fd_banks_t * banks,
700 : ulong bank_idx,
701 : ulong * opt_idxs,
702 : ulong * opt_idxs_cnt );
703 :
704 : /* fd_banks_prune_one_bank will try to prune one bank that was
705 : marked as dead or prunable. It will not prune a bank that has a
706 : non-zero reference count. Returns 0 if nothing was pruned, 1 if a
707 : bank was pruned but no accdb/txncache cancellation is needed, or 2 if
708 : a bank was pruned and cancellation is needed. Whenever a bank is
709 : pruned (returns 1 or 2), cancel->bank_idx is populated if cancel is
710 : non-NULL. The remaining cancel fields are only populated if
711 : available. */
712 :
713 : int
714 : fd_banks_prune_one_bank( fd_banks_t * banks,
715 : fd_banks_prune_cancel_info_t * cancel );
716 :
717 : /* fd_banks_mark_bank_frozen marks the current bank as frozen. This
718 : should be done when the bank is no longer being updated: it should be
719 : done at the end of a slot. This also releases the memory for the
720 : cost tracker which only has to be persisted from the start of a slot
721 : to the end. */
722 :
723 : void
724 : fd_banks_mark_bank_frozen( fd_bank_t * bank );
725 :
726 : /* fd_banks_new_bank reserves a bank index for a new bank. New bank
727 : indices should always be available. After this function is called,
728 : the bank will be linked to its parent bank, but not yet replayable.
729 : After a call to fd_banks_clone_from_parent, the bank will be
730 : replayable. This assumes that there is a parent bank which exists
731 : and that there are available bank indices in the bank pool. It also
732 : assumes that the parent bank is not dead, inactive, or prunable. */
733 :
734 : fd_bank_t *
735 : fd_banks_new_bank( fd_banks_t * banks,
736 : ulong parent_bank_idx,
737 : long now,
738 : uchar is_leader );
739 :
740 :
741 : /* fd_banks_get_evictable_bank selects one evictable leaf according to
742 : the current fd_banks eviction policy, marks it prunable, records it
743 : as pending, and returns its bank index. Eviction collects all
744 : eligible leaves in DFS order (left-child, then siblings) and picks
745 : banks->evict_rr_idx % leaf_count, then increments evict_rr_idx.
746 : Only a single leaf may be prunable at a time (prunable_idx).
747 : The eviction is selected in a round-robin manner to avoid a livelock
748 : where we repeatedly evict and replay the same bank, halting progress.
749 : The root, leader banks (or banks we were previously leaders for),
750 : dead banks, inactive banks, already prunable banks, and
751 : protected_bank are not evictable. Pass NULL for protected_bank if no
752 : additional bank needs protection. Returns ULONG_MAX if there is no
753 : evictable bank, or if a prunable bank is already pending pruning.
754 : TODO: It is possible that we can still wedge under very adverse
755 : conditions even with the round-robin eviction policy. The starting
756 : evict_idx is different for each validator, ensuring that some nodes
757 : will still be able to make forward progress. */
758 :
759 : ulong
760 : fd_banks_get_evictable_bank( fd_banks_t * banks,
761 : fd_bank_t const * protected_bank );
762 :
763 : /* fd_banks_can_start_bank returns 1 if banks has capacity to start
764 : preparing another child bank. This check is currently conservative,
765 : if the max fork width is reached, it will return 0 even if the new
766 : bank doesn't exceed the max fork width. */
767 :
768 : int
769 : fd_banks_can_start_bank( fd_banks_t * banks );
770 :
771 : /* fd_bank_clear_bank() clears the contents of a bank. This should ONLY
772 : be used with banks that have no children and should only be used in
773 : testing and fuzzing. WARNING: This should NOT be used in production.
774 :
775 : This function will memset all non-CoW fields to 0.
776 :
777 : For all CoW fields, we will reset the indices to its parent. */
778 :
779 : void
780 : fd_banks_clear_bank( fd_banks_t * banks,
781 : fd_bank_t * bank );
782 :
783 : FD_PROTOTYPES_END
784 :
785 : #endif /* HEADER_fd_src_flamenco_runtime_fd_bank_h */
|