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