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