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