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 :
17 : FD_PROTOTYPES_BEGIN
18 :
19 12 : #define FD_BANKS_MAGIC (0XF17EDA2C7EBA2450) /* FIREDANCER BANKS V0 */
20 :
21 49164 : #define FD_BANKS_MAX_BANKS (4096UL)
22 :
23 : /* TODO:FIXME: REREVIEW ALL DOCUMENTATION FOR BANKS */
24 :
25 : /* A fd_bank_t struct is the representation of the bank state on Solana
26 : for a given block. More specifically, the bank state corresponds to
27 : all information needed during execution that is not stored on-chain,
28 : but is instead cached in a validator's memory. Each of these bank
29 : fields are repesented by a member of the fd_bank_t struct.
30 :
31 : Management of fd_bank_t structs must be fork-aware: the state of each
32 : fd_bank_t must be based on the fd_bank_t of its parent block. This
33 : state is managed by the fd_banks_t struct.
34 :
35 : In order to support fork-awareness, there are several key features
36 : that fd_banks_t and fd_bank_t MUST support:
37 : 1. Query for any non-rooted block's bank: create a fast lookup
38 : from bank index to bank
39 : 2. Be able to create a new bank for a given block from the bank of
40 : that block's parent and maintain some tree-like structure to
41 : track the parent-child relationships: copy the contents from a
42 : parent bank into a child bank.
43 : 3. Prune the set of active banks to keep the root updated as the
44 : network progresses: free resources of fd_bank_t structs that
45 : are are not direct descendants of the root bank (remove parents
46 : and any competing lineages). When a bank is marked as dead (ie.
47 : if the block corresponding to the bank is invalid), it also must
48 : be able to be eagerly pruned away.
49 : 4. Each bank will have field(s) that are concurrently read/write
50 : from multiple threads: add read-write locks to the fields that are
51 : concurrently written to.
52 : 5. In practice, a bank state for a given block can be very large and
53 : not all of the fields are written to every block. Therefore, it
54 : can be very expensive to copy the entire bank state for a given
55 : block each time a bank is created. In order to avoid large
56 : memcpys, we can use a CoW mechanism for certain fields.
57 : 6. In a similar vein, some fields are very large and are not written
58 : to very often, and are only read at the epoch boundary. The most
59 : notable example is the stake delegations cache. In order to
60 : handle this, we can use a delta-based approach where each bank
61 : only has a delta of the stake delegations. The root bank will own
62 : the full set of stake delegations. This means that the deltas are
63 : only applied to the root bank as each bank gets rooted. If the
64 : caller needs to access the full set of stake delegations for a
65 : given bank, they can assemble the full set of stake delegations by
66 : applying all of the deltas from the current bank and all of its
67 : ancestors up to the root bank.
68 :
69 : fd_banks_t is represented by a left-child, right-sibling n-ary tree
70 : (inspired by fd_ghost) to keep track of the parent-child fork tree.
71 : The underlying data structure is a pool of fd_bank_t structs. Banks
72 : are then accessed via an index into the bank pool (bank index).
73 :
74 : NOTE: The reason fd_banks_t is keyed by bank index and not by slot is
75 : to handle block equivocation: if there are two different blocks for
76 : the same slot, we need to be able to differentiate and handle both
77 : blocks against different banks. As mentioned above, the bank index is
78 : just an index into the bank pool. The caller is responsible for
79 : establishing a mapping from the bank index (which is managed by
80 : fd_banks_t) and runtime state (e.g. slot number).
81 :
82 : The fields in fd_bank_t can be categorized into two groups:
83 : 1. Simple fields: these are fields which don't need any special
84 : handling and are laid out contiguously in the fd_bank_t struct.
85 : These types are also templatized out and are defined in the
86 : FD_BANKS_ITER macro.
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 index and a dirty flag. If the field
94 : is modified, then the dirty flag is set, and an element of the pool
95 : is acquired and the data is copied over from the parent pool idx.
96 :
97 : Currently, there is a delta-based field, fd_stake_delegations_t.
98 : Each bank stores a delta-based representation in the form of an
99 : aligned uchar buffer. The full state is stored in fd_banks_t in
100 : out-of-line memory sized using max_stake_accounts, and fd_banks_t
101 : also reserves another out-of-line buffer which can store the full
102 : state of the stake delegations for frontier queries.
103 :
104 : The cost tracker is allocated from a pool. The lifetime of a cost
105 : tracker element starts when the bank is linked to a parent with a
106 : call to fd_banks_clone_from_parent() which makes the bank replayable.
107 : The lifetime of a cost tracker element ends when the bank is marked
108 : dead or when the bank is frozen.
109 :
110 : The lthash is a simple field that is laid out contiguously in the
111 : fd_bank_t struct, but is not templatized and it has its own lock.
112 :
113 : So, when a bank is cloned from a parent, the non CoW fields are copied
114 : over and the CoW fields just copy over a pool index. The CoW behavior
115 : is completely abstracted away from the caller as callers have to
116 : query/modify fields using specific APIs.
117 :
118 : The memory for the banks is based off of two bounds:
119 : 1. the max number of unrooted blocks at any given time. Most fields
120 : can be bounded by this value.
121 : 2. the max number of forks that execute through any 1 block. We bound
122 : fields that are only written to at the epoch boundary by
123 : the max fork width that can execute through the boundary instead of
124 : by the max number of banks. See fd_banks_footprint() for more
125 : details.
126 :
127 : There are also some important states that a bank can be in:
128 : - Initialized: This bank has been created and linked to a parent bank
129 : index with a call to fd_banks_new_bank(). However, it is not yet
130 : replayable.
131 : - Replayable: This bank has inherited state from its parent and now
132 : transactions can be executed against it. For a bank to become
133 : replayable, it must've been initialized beforehand.
134 : - Dead: This bank has been marked as dead. This means that the block
135 : that this bank is associated with is invalid. A bank can be marked
136 : dead before, during, or after it has finished replaying (i.e. the
137 : bank being marked dead just needs to be initialized). A bank
138 : can still be executing transactions while it is marked dead, but it
139 : shouldn't be dispatched any more work. In other words, a key
140 : invariant is that a bank's reference count should NEVER be increased
141 : after it has been marked dead.
142 : - Frozen: This bank has been marked as frozen and no other tasks
143 : should be dispatched to it. Any bank-specific resources will be
144 : released (e.g. cost tracker element). A bank can be marked frozen
145 : if the bank has finished executing all of its transactions or if the
146 : bank is marked as dead and has no outstanding references. A bank
147 : can only be copied from a parent bank (fd_banks_clone_from_parent)
148 : if the parent bank has been frozen. The program will crash if this
149 : invariant is violated.
150 :
151 : The usage pattern is as follows:
152 :
153 : To create an initial bank:
154 : fd_banks_t bank[1];
155 : fd_bank_t * bank_init = fd_bank_init_bank( bank, banks );
156 :
157 : To create a new bank. This simply provisions the memory for the bank
158 : but it should not be used to execute transactions against.
159 : ulong bank_index = fd_banks_new_bank( bank, banks, parent_bank_index )->data->idx;
160 :
161 : To clone bank from parent banks. This makes a bank replayable by
162 : copying over the state from the parent bank into the child. It
163 : assumes that the bank index has been previously provisioned by a call
164 : to fd_banks_new_bank and that the parent bank index has been frozen.
165 : fd_bank_t * bank_clone = fd_banks_clone_from_parent( bank, banks, bank_index );
166 :
167 : To ensure that the bank index we want to advance our root to is safe
168 : and that there are no outstanding references to the banks that are
169 : not descendants of the target bank.
170 : fd_banks_advance_root_prepare( banks, target_bank_idx, &advanceable_bank_idx_out );
171 :
172 : To advance the root bank. This assumes that the bank index is "safe"
173 : to advance to. This means that none of the ancestors of the bank
174 : index have a non-zero reference count.
175 : fd_banks_advance_root( banks, bank_index );
176 :
177 : To query some arbitrary bank:
178 : fd_bank_t * bank_query = fd_banks_bank_query( bank, banks, bank_index );
179 :
180 : To access the fields in the bank if they are templatized:
181 :
182 : fd_struct_t const * field = fd_bank_field_query( bank );
183 : OR
184 : fd_struct field = fd_bank_field_get( bank );
185 :
186 : fd_struct_t * field = fd_bank_field_modify( bank );
187 : OR
188 : fd_bank_field_set( bank, value );
189 :
190 : If a bank is marked dead, the caller should call
191 : fd_banks_mark_bank_dead() to mark the bank and all of its descendants
192 : as dead. This does not actually free the underlying resources that
193 : the dead bank has allocated and instead just queues them up for
194 : pruning:
195 : fd_banks_mark_bank_dead( banks, dead_bank_idx );
196 :
197 : To actually prune away any dead banks, the caller should call:
198 : fd_banks_prune_one_dead_bank( banks, cancel_info )
199 :
200 : The locks and data used by an fd_bank_t or an fd_banks_t are stored as
201 : separate objects. The locks are stored in an fd_banks_locks_t struct
202 : and the data is stored in an fd_banks_data_t struct for an fd_banks_t.
203 : Each fd_bank_t uses a fd_bank_data_t struct to store its state and
204 : fd_banks_locks_t to store the locks for the bank. The reason for
205 : splitting out the locks and data is to allow for more fine-grained
206 : security isolation: this allows for the data for the banks to be
207 : mapped in read-only to specific tiles while still being able to use
208 : locks to access concurrent fields in the banks.
209 :
210 : If the fields are not templatized, their accessor and modifier
211 : patterns vary and are documented below.
212 : */
213 : #define FD_BANKS_ITER(X) \
214 : /* type, name */ \
215 : X(fd_blockhashes_t, block_hash_queue ) /* Block hash queue */ \
216 : X(fd_fee_rate_governor_t, fee_rate_governor ) /* Fee rate governor */ \
217 : X(ulong, rbh_lamports_per_sig ) /* Recent Block Hashes lamports per signature */ \
218 : X(ulong, slot ) /* Slot */ \
219 : X(ulong, parent_slot ) /* Parent slot */ \
220 : X(ulong, capitalization ) /* Capitalization */ \
221 : X(ulong, transaction_count ) /* Transaction count */ \
222 : X(ulong, parent_signature_cnt ) /* Parent signature count */ \
223 : X(ulong, tick_height ) /* Tick height */ \
224 : X(ulong, max_tick_height ) /* Max tick height */ \
225 : X(ulong, hashes_per_tick ) /* Hashes per tick */ \
226 : X(fd_w_u128_t, ns_per_slot ) /* NS per slot */ \
227 : X(ulong, ticks_per_slot ) /* Ticks per slot */ \
228 : X(ulong, genesis_creation_time ) /* Genesis creation time */ \
229 : X(double, slots_per_year ) /* Slots per year */ \
230 : X(fd_inflation_t, inflation ) /* Inflation */ \
231 : X(ulong, cluster_type ) /* Cluster type */ \
232 : X(ulong, total_epoch_stake ) /* Total epoch stake */ \
233 : /* This is only used for the get_epoch_stake syscall. */ \
234 : /* If we are executing in epoch E, this is the total */ \
235 : /* stake at the end of epoch E-1. */ \
236 : X(ulong, block_height ) /* Block height */ \
237 : X(ulong, execution_fees ) /* Execution fees */ \
238 : X(ulong, priority_fees ) /* Priority fees */ \
239 : X(ulong, tips ) /* Tips collected */ \
240 : X(ulong, signature_count ) /* Signature count */ \
241 : X(fd_hash_t, poh ) /* PoH */ \
242 : X(fd_sol_sysvar_last_restart_slot_t, last_restart_slot ) /* Last restart slot */ \
243 : X(fd_hash_t, bank_hash ) /* Bank hash */ \
244 : X(fd_hash_t, prev_bank_hash ) /* Previous bank hash */ \
245 : X(fd_hash_t, genesis_hash ) /* Genesis hash */ \
246 : X(fd_epoch_schedule_t, epoch_schedule ) /* Epoch schedule */ \
247 : X(fd_rent_t, rent ) /* Rent */ \
248 : X(fd_sysvar_cache_t, sysvar_cache ) /* Sysvar cache */ \
249 : /* then there can be 100k unique leaders in the worst */ \
250 : /* case. We also can assume 432k slots per epoch. */ \
251 : X(fd_features_t, features ) /* Features */ \
252 : X(ulong, txn_count ) /* Transaction count */ \
253 : X(ulong, nonvote_txn_count ) /* Nonvote transaction count */ \
254 : X(ulong, failed_txn_count ) /* Failed transaction count */ \
255 : X(ulong, nonvote_failed_txn_count ) /* Nonvote failed transaction count */ \
256 : X(ulong, total_compute_units_used ) /* Total compute units used */ \
257 : X(ulong, slots_per_epoch ) /* Slots per epoch */ \
258 : X(ulong, shred_cnt ) /* Shred count */ \
259 : X(ulong, epoch ) /* Epoch */ \
260 : X(ulong, identity_vote_idx ) /* Identity vote index */
261 :
262 : /* Defining pooled fields. */
263 :
264 : struct fd_bank_cost_tracker {
265 : ulong next;
266 : uchar data[FD_COST_TRACKER_FOOTPRINT] __attribute__((aligned(FD_COST_TRACKER_ALIGN)));
267 : };
268 : typedef struct fd_bank_cost_tracker fd_bank_cost_tracker_t;
269 :
270 : struct fd_bank_top_votes {
271 : ulong next;
272 : uchar data[FD_TOP_VOTES_MAX_FOOTPRINT] __attribute__((aligned(FD_TOP_VOTES_ALIGN)));
273 : };
274 : typedef struct fd_bank_top_votes fd_bank_top_votes_t;
275 :
276 : #define POOL_NAME fd_bank_cost_tracker_pool
277 31143 : #define POOL_T fd_bank_cost_tracker_t
278 : #include "../../util/tmpl/fd_pool.c"
279 :
280 : #define POOL_NAME fd_bank_top_votes_pool
281 36 : #define POOL_T fd_bank_top_votes_t
282 : #include "../../util/tmpl/fd_pool.c"
283 :
284 : /* Initialized. Not yet replayable. */
285 12 : #define FD_BANK_FLAGS_INIT (0x00000001UL)
286 : /* Replayable. Implies that FD_BANK_FLAGS_INIT is also set. */
287 12 : #define FD_BANK_FLAGS_REPLAYABLE (0x00000002UL)
288 : /* Frozen. We finished replaying or because it was a snapshot/genesis
289 : loaded bank. Implies that FD_BANK_FLAGS_REPLAYABLE is also set. */
290 12 : #define FD_BANK_FLAGS_FROZEN (0x00000004UL)
291 : /* Dead. We stopped replaying it before we could finish it (e.g.
292 : invalid block or pruned minority fork). It is implied that
293 : FD_BANK_FLAGS_INIT is set, but not necessarily
294 : FD_BANK_FLAGS_REPLAYABLE. */
295 0 : #define FD_BANK_FLAGS_DEAD (0x00000008UL)
296 : /* Rooted. Part of the consnensus root fork. Implies that
297 : FD_BANK_FLAGS_FROZEN is also set. */
298 0 : #define FD_BANK_FLAGS_ROOTED (0x00000010UL)
299 :
300 : /* As mentioned above, the overall layout of the bank struct:
301 : - Fields used for internal pool/bank management
302 : - Non-Cow fields
303 : - CoW fields
304 : - Locks for CoW fields
305 :
306 : The CoW fields are laid out contiguously in the bank struct.
307 : The locks for the CoW fields are laid out contiguously after the
308 : CoW fields.
309 :
310 : (r) Field is owned by the replay tile, and should be updated only by
311 : the replay tile.
312 : */
313 :
314 : struct fd_bank_data {
315 :
316 : /* Fields used for internal pool and bank management */
317 : ulong idx; /* current fork idx of the bank (synchronized with the pool index) */
318 : ulong next; /* reserved for internal use by pool and fd_banks_advance_root */
319 : ulong parent_idx; /* index of the parent in the node pool */
320 : ulong child_idx; /* index of the left-child in the node pool */
321 : ulong sibling_idx; /* index of the right-sibling in the node pool */
322 : ulong flags; /* keeps track of the state of the bank */
323 : ulong bank_seq; /* app-wide bank sequence number */
324 :
325 : ulong refcnt; /* reference count on the bank, see replay for more details */
326 :
327 : fd_txncache_fork_id_t txncache_fork_id; /* fork id used by the txn cache */
328 :
329 : ushort vote_stakes_fork_id; /* fork id used by the vote stakes */
330 :
331 : uchar stake_rewards_fork_id; /* fork id used by stake rewards */
332 :
333 : ushort stake_delegations_fork_id; /* fork id used by stake delegations deltas */
334 :
335 : /* Timestamps written and read only by replay */
336 :
337 : long first_fec_set_received_nanos;
338 : long preparation_begin_nanos;
339 : long first_transaction_scheduled_nanos;
340 : long last_transaction_finished_nanos;
341 :
342 : /* First, layout all non-CoW fields contiguously. This is done to
343 : allow for cloning the bank state with a simple memcpy. Each
344 : non-CoW field is just represented as a byte array. */
345 :
346 : struct {
347 : fd_lthash_value_t lthash;
348 :
349 : #define X(type, name) uchar name[sizeof(type)] __attribute__((aligned(alignof(type))));
350 : FD_BANKS_ITER(X)
351 : #undef X
352 : } non_cow;
353 :
354 : /* Layout all information needed for non-templatized fields. */
355 :
356 : ulong stake_rewards_offset;
357 :
358 : ulong cost_tracker_pool_idx;
359 : ulong cost_tracker_pool_offset;
360 :
361 : ulong vote_stakes_offset;
362 :
363 : ulong stake_delegations_offset;
364 :
365 : ulong epoch_leaders_idx; /* always 0 or 1 based on % epoch */
366 : ulong epoch_leaders_offset;
367 : ulong epoch_leaders_footprint;
368 :
369 : int top_votes_dirty;
370 : ulong top_votes_pool_idx;
371 : ulong top_votes_pool_offset;
372 :
373 : ulong stake_weights_cnt_off;
374 : ulong stake_weights_off;
375 :
376 : ulong stake_weights_cnt_next_off;
377 : ulong stake_weights_next_off;
378 : };
379 : typedef struct fd_bank_data fd_bank_data_t;
380 :
381 : struct fd_banks_locks {
382 : /* This lock is only used to serialize banks fork tree reads with
383 : respect to fork tree writes. In other words, tree traversals
384 : cannot happen at the same time as a tree pruning operation or a
385 : tree insertion operation. So the public APIs on banks take either
386 : a read lock or a write lock depending on what they do on the fork
387 : tree. For example, publishing takes a write lock, and bank lookups
388 : take a read lock. Notably, individual banks can still be
389 : concurrently accessed or modified, and this lock does not offer
390 : synchronization on individual fields within a bank. */
391 : fd_rwlock_t banks_lock;
392 :
393 : /* These pools are shared between each fd_bank_t and fd_banks_t.
394 : These locks are used to guard against concurrent access to the
395 : pools (e.g. acquires and releases). These locks are currently just
396 : write locks and have no readers. */
397 : fd_rwlock_t epoch_leaders_pool_lock;
398 :
399 : fd_rwlock_t top_votes_pool_lock;
400 :
401 : fd_rwlock_t vote_stakes_lock;
402 :
403 : /* These locks are per bank and are used to atomically update their
404 : corresponding fields in each bank. The locks are indexed by the
405 : bank index. */
406 : fd_rwlock_t lthash_lock[ FD_BANKS_MAX_BANKS ];
407 : fd_rwlock_t cost_tracker_lock[ FD_BANKS_MAX_BANKS ];
408 : };
409 : typedef struct fd_banks_locks fd_banks_locks_t;
410 :
411 : struct fd_bank {
412 : fd_bank_data_t * data;
413 : fd_banks_locks_t * locks;
414 : };
415 : typedef struct fd_bank fd_bank_t;
416 :
417 : struct fd_banks_prune_cancel_info {
418 : fd_txncache_fork_id_t txncache_fork_id;
419 : ulong slot;
420 : ulong bank_idx;
421 : };
422 : typedef struct fd_banks_prune_cancel_info fd_banks_prune_cancel_info_t;
423 :
424 : static inline void
425 24 : fd_bank_set_stake_weights( fd_bank_data_t * bank, uchar * stake_weights_mem ) {
426 24 : bank->stake_weights_off = (ulong)bank - (ulong)stake_weights_mem;
427 24 : }
428 :
429 : static inline fd_vote_stake_weight_t *
430 301 : fd_bank_get_stake_weights( fd_bank_data_t * bank ) {
431 301 : return (fd_vote_stake_weight_t *)fd_type_pun( (uchar *)bank - bank->stake_weights_off );
432 301 : }
433 :
434 : static inline void
435 24 : fd_bank_set_stake_weights_cnt_off( fd_bank_data_t * bank, uchar * stake_weights_cnt_mem ) {
436 24 : bank->stake_weights_cnt_off = (ulong)bank - (ulong)stake_weights_cnt_mem;
437 24 : }
438 :
439 : static inline ulong *
440 301 : fd_bank_get_stake_weights_cnt( fd_bank_data_t * bank ) {
441 301 : return (ulong *)fd_type_pun( (uchar *)bank - bank->stake_weights_cnt_off );
442 301 : }
443 :
444 : static inline void
445 24 : fd_bank_set_stake_weights_next( fd_bank_data_t * bank, uchar * stake_weights_mem ) {
446 24 : bank->stake_weights_next_off = (ulong)bank - (ulong)stake_weights_mem;
447 24 : }
448 :
449 : static inline fd_vote_stake_weight_t *
450 301 : fd_bank_get_stake_weights_next( fd_bank_data_t * bank ) {
451 301 : return (fd_vote_stake_weight_t *)fd_type_pun( (uchar *)bank - bank->stake_weights_next_off );
452 301 : }
453 :
454 : static inline void
455 24 : fd_bank_set_stake_weights_cnt_next_off( fd_bank_data_t * bank, uchar * stake_weights_cnt_next_mem ) {
456 24 : bank->stake_weights_cnt_next_off = (ulong)bank - (ulong)stake_weights_cnt_next_mem;
457 24 : }
458 :
459 : static inline ulong *
460 300 : fd_bank_get_stake_weights_cnt_next( fd_bank_data_t * bank ) {
461 300 : return (ulong *)fd_type_pun( (uchar *)bank - bank->stake_weights_cnt_next_off );
462 300 : }
463 :
464 : static inline void
465 : fd_bank_set_epoch_leaders( fd_bank_data_t * bank,
466 : uchar * epoch_leaders_mem,
467 24 : ulong epoch_leaders_footprint ) {
468 24 : bank->epoch_leaders_offset = (ulong)bank - (ulong)epoch_leaders_mem;
469 24 : bank->epoch_leaders_footprint = epoch_leaders_footprint;
470 24 : }
471 :
472 : static inline uchar *
473 1199 : fd_bank_get_epoch_leaders( fd_bank_data_t * bank ) {
474 1199 : return (uchar *)bank - bank->epoch_leaders_offset;
475 1199 : }
476 :
477 : /* Do the same setup for the cost tracker pool. */
478 :
479 : static inline void
480 24 : fd_bank_set_cost_tracker_pool( fd_bank_data_t * bank, fd_bank_cost_tracker_t * cost_tracker_pool ) {
481 24 : void * cost_tracker_pool_mem = fd_bank_cost_tracker_pool_leave( cost_tracker_pool );
482 24 : if( FD_UNLIKELY( !cost_tracker_pool_mem ) ) {
483 0 : FD_LOG_CRIT(( "Failed to leave cost tracker pool" ));
484 0 : }
485 24 : bank->cost_tracker_pool_offset = (ulong)cost_tracker_pool_mem - (ulong)bank;
486 24 : }
487 :
488 : static inline fd_bank_cost_tracker_t *
489 31072 : fd_bank_get_cost_tracker_pool( fd_bank_data_t * bank ) {
490 31072 : return fd_bank_cost_tracker_pool_join( (uchar *)bank + bank->cost_tracker_pool_offset );
491 31072 : }
492 :
493 : static inline void
494 24 : fd_bank_set_top_votes_pool( fd_bank_data_t * bank, fd_bank_top_votes_t * top_votes_pool ) {
495 24 : bank->top_votes_pool_offset = (ulong)top_votes_pool - (ulong)bank;
496 24 : }
497 :
498 : static inline fd_bank_top_votes_t *
499 31055 : fd_bank_get_top_votes_pool( fd_bank_data_t * bank ) {
500 31055 : return fd_type_pun( (uchar *)bank + bank->top_votes_pool_offset );
501 31055 : }
502 :
503 : static inline void
504 24 : fd_bank_set_vote_stakes( fd_bank_data_t * bank, fd_vote_stakes_t * vote_stakes ) {
505 24 : bank->vote_stakes_offset = (ulong)vote_stakes - (ulong)bank;
506 24 : }
507 :
508 : static inline fd_vote_stakes_t *
509 917 : fd_bank_vote_stakes_locking_modify( fd_bank_t const * bank ) {
510 917 : fd_rwlock_write( &bank->locks->vote_stakes_lock );
511 917 : return fd_type_pun( (uchar *)bank->data + bank->data->vote_stakes_offset );
512 917 : }
513 :
514 : static inline void
515 917 : fd_bank_vote_stakes_end_locking_modify( fd_bank_t * bank ) {
516 917 : fd_rwlock_unwrite( &bank->locks->vote_stakes_lock );
517 917 : }
518 :
519 : static inline void
520 24 : fd_bank_set_stake_delegations( fd_bank_data_t * bank, fd_stake_delegations_t * stake_delegations ) {
521 24 : bank->stake_delegations_offset = (ulong)stake_delegations - (ulong)bank;
522 24 : }
523 :
524 : static inline fd_stake_delegations_t *
525 2 : fd_bank_stake_delegations_modify( fd_bank_t * bank ) {
526 2 : return fd_type_pun( (uchar *)bank->data + bank->data->stake_delegations_offset );
527 2 : }
528 :
529 : /* fd_bank_t is the alignment for the bank state. */
530 :
531 : ulong
532 : fd_bank_align( void );
533 :
534 : /* fd_bank_t is the footprint for the bank state. This does NOT
535 : include the footprint for the CoW state. */
536 :
537 : ulong
538 : fd_bank_footprint( void );
539 :
540 : /**********************************************************************/
541 : /* fd_banks_t is the main struct used to manage the bank state. It can
542 : be used to query/modify/clone/publish the bank state.
543 :
544 : fd_banks_t contains some metadata to a pool to manage the banks.
545 : It also contains pointers to the CoW pools.
546 :
547 : The data is laid out contiguously in memory starting from fd_banks_t;
548 : this can be seen in fd_banks_footprint(). */
549 :
550 : #define POOL_NAME fd_banks_pool
551 30241 : #define POOL_T fd_bank_data_t
552 : #include "../../util/tmpl/fd_pool.c"
553 :
554 : struct fd_bank_idx_seq {
555 : ulong idx;
556 : ulong seq;
557 : };
558 : typedef struct fd_bank_idx_seq fd_bank_idx_seq_t;
559 :
560 : #define DEQUE_NAME fd_banks_dead
561 0 : #define DEQUE_T fd_bank_idx_seq_t
562 0 : #define DEQUE_MAX FD_BANKS_MAX_BANKS
563 : #include "../../util/tmpl/fd_deque.c"
564 :
565 : struct fd_banks_data {
566 : ulong magic; /* ==FD_BANKS_MAGIC */
567 : ulong max_total_banks; /* Maximum number of banks */
568 : ulong max_fork_width; /* Maximum fork width executing through any given slot. */
569 : ulong max_stake_accounts; /* Maximum number of stake accounts */
570 : ulong max_vote_accounts; /* Maximum number of vote accounts */
571 : ulong root_idx; /* root idx */
572 : ulong bank_seq; /* app-wide bank sequence number */
573 :
574 : ulong pool_offset; /* offset of pool from banks */
575 :
576 : ulong cost_tracker_pool_offset; /* offset of cost tracker pool from banks */
577 :
578 : ulong vote_stakes_pool_offset;
579 :
580 : ulong stake_rewards_offset;
581 :
582 : ulong dead_banks_deque_offset;
583 :
584 : /* The set of epoch leaders for the current and previous epochs is
585 : allocated out-of-line and tracked by epoch_leaders_offset. Only
586 : two need to be stored because in the worst case we will have a root
587 : that sits behind an epoch boundary, with leaf banks executing into
588 : the next epoch. All banks that execute behind the boundary, will
589 : use the previous epoch's leader schedule, and all nodes after the
590 : epoch boundary are guaranteed to produce identical leader
591 : schedules. */
592 :
593 : ulong epoch_leaders_offset;
594 : ulong epoch_leaders_footprint;
595 :
596 : ulong stake_delegations_offset;
597 :
598 : /* Set of compressed stake weights for the leader schedule for the
599 : current epoch. */
600 :
601 : fd_vote_stake_weight_t stake_weights[ MAX_COMPRESSED_STAKE_WEIGHTS ];
602 : ulong stake_weights_cnt;
603 :
604 : /* Set of compressed stake weights for the leader schedule for the
605 : next epoch. */
606 :
607 : fd_vote_stake_weight_t next_stake_weights[ MAX_COMPRESSED_STAKE_WEIGHTS ];
608 : ulong next_stake_weights_cnt;
609 :
610 : /* Lay out pool offsets */
611 :
612 : ulong top_votes_pool_offset;
613 : };
614 : typedef struct fd_banks_data fd_banks_data_t;
615 :
616 : struct fd_banks {
617 : fd_banks_data_t * data;
618 : fd_banks_locks_t * locks;
619 : };
620 : typedef struct fd_banks fd_banks_t;
621 :
622 : /* Bank accesssors and mutators. Different accessors are emitted for
623 : different types depending on if the field has a lock or not. */
624 :
625 : fd_stake_rewards_t const *
626 : fd_bank_stake_rewards_query( fd_bank_t * bank );
627 :
628 : fd_stake_rewards_t *
629 : fd_bank_stake_rewards_modify( fd_bank_t * bank );
630 :
631 : fd_epoch_leaders_t const *
632 : fd_bank_epoch_leaders_query( fd_bank_t const * bank );
633 :
634 : fd_epoch_leaders_t *
635 : fd_bank_epoch_leaders_modify( fd_bank_t * bank );
636 :
637 : fd_top_votes_t const *
638 : fd_bank_top_votes_query( fd_bank_t const * bank );
639 :
640 : fd_top_votes_t *
641 : fd_bank_top_votes_modify( fd_bank_t * bank );
642 :
643 : fd_cost_tracker_t *
644 : fd_bank_cost_tracker_locking_modify( fd_bank_t * bank );
645 :
646 : void
647 : fd_bank_cost_tracker_end_locking_modify( fd_bank_t * bank );
648 :
649 : fd_cost_tracker_t const *
650 : fd_bank_cost_tracker_locking_query( fd_bank_t * bank );
651 :
652 : void
653 : fd_bank_cost_tracker_end_locking_query( fd_bank_t * bank );
654 :
655 : fd_lthash_value_t const *
656 : fd_bank_lthash_locking_query( fd_bank_t * bank );
657 :
658 : void
659 : fd_bank_lthash_end_locking_query( fd_bank_t * bank );
660 :
661 : fd_lthash_value_t *
662 : fd_bank_lthash_locking_modify( fd_bank_t * bank );
663 :
664 : void
665 : fd_bank_lthash_end_locking_modify( fd_bank_t * bank );
666 :
667 : #define X(type, name) \
668 : void fd_bank_##name##_set( fd_bank_t * bank, type value ); \
669 : type fd_bank_##name##_get( fd_bank_t const * bank ); \
670 : type const * fd_bank_##name##_query( fd_bank_t const * bank ); \
671 : type * fd_bank_##name##_modify( fd_bank_t * bank );
672 : FD_BANKS_ITER(X)
673 : #undef X
674 :
675 : /* fd_bank_stake_delegations_frontier_query() will return a pointer to
676 : the full stake delegations for the current frontier. The caller is
677 : responsible that there are no concurrent readers or writers to
678 : the stake delegations returned by this function.
679 :
680 : Under the hood, the function applies all of the stake delegation
681 : deltas from all banks starting from the root down to the current bank
682 : to the rooted version of the stake delegations. This is done in a
683 : reversible way and is unwound with a call to
684 : fd_bank_stake_delegations_end_frontier_query(). */
685 :
686 : fd_stake_delegations_t *
687 : fd_bank_stake_delegations_frontier_query( fd_banks_t * banks,
688 : fd_bank_t * bank );
689 :
690 : /* fd_bank_stake_delegations_end_frontier_query() will finish the
691 : reversible operation started by
692 : fd_bank_stake_delegations_frontier_query(). It is unsafe to call
693 : fd_bank_stake_delegations_frontier_query multiple times without
694 : calling this function in between.
695 :
696 : Under the hood, it undoes any references to the stake delegation
697 : deltas that were applied. */
698 :
699 : void
700 : fd_bank_stake_delegations_end_frontier_query( fd_banks_t * banks,
701 : fd_bank_t * bank );
702 :
703 : /* fd_banks_stake_delegations_root_query() will return a pointer to the
704 : full stake delegations for the current root. This function should
705 : only be called on boot. */
706 :
707 : fd_stake_delegations_t *
708 : fd_banks_stake_delegations_root_query( fd_banks_t * banks );
709 :
710 : /* Simple getters and setters for the pools/maps in fd_banks_t. Notably,
711 : the pool for the fd_bank_t structs as well as a map and pool pair of
712 : the CoW structs in the banks. */
713 :
714 : static inline fd_bank_data_t *
715 30205 : fd_banks_get_bank_pool( fd_banks_data_t * banks_data ) {
716 30205 : return fd_banks_pool_join( (uchar *)banks_data + banks_data->pool_offset );
717 30205 : }
718 :
719 : static inline void
720 : fd_banks_set_bank_pool( fd_banks_data_t * banks_data,
721 12 : fd_bank_data_t * bank_pool ) {
722 12 : void * bank_pool_mem = fd_banks_pool_leave( bank_pool );
723 12 : if( FD_UNLIKELY( !bank_pool_mem ) ) {
724 0 : FD_LOG_CRIT(( "Failed to leave bank pool" ));
725 0 : }
726 12 : banks_data->pool_offset = (ulong)bank_pool_mem - (ulong)banks_data;
727 12 : }
728 :
729 : static inline fd_bank_idx_seq_t *
730 0 : fd_banks_get_dead_banks_deque( fd_banks_data_t * banks_data ) {
731 0 : return fd_type_pun( (uchar *)banks_data + banks_data->dead_banks_deque_offset );
732 0 : }
733 :
734 : static inline void
735 : fd_banks_set_dead_banks_deque( fd_banks_data_t * banks_data,
736 12 : fd_bank_idx_seq_t * dead_banks_deque ) {
737 12 : banks_data->dead_banks_deque_offset = (ulong)dead_banks_deque - (ulong)banks_data;
738 12 : }
739 :
740 : static inline fd_epoch_leaders_t *
741 12 : fd_banks_get_epoch_leaders( fd_banks_data_t * banks_data ) {
742 12 : return fd_type_pun( (uchar *)banks_data + banks_data->epoch_leaders_offset );
743 12 : }
744 :
745 : static inline void
746 : fd_banks_set_epoch_leaders( fd_banks_data_t * banks_data,
747 : uchar * epoch_leaders_mem,
748 12 : ulong epoch_leaders_footprint ) {
749 12 : banks_data->epoch_leaders_offset = (ulong)epoch_leaders_mem - (ulong)banks_data;
750 12 : banks_data->epoch_leaders_footprint = epoch_leaders_footprint;
751 12 : }
752 :
753 : static inline fd_stake_delegations_t *
754 654 : fd_banks_get_stake_delegations( fd_banks_data_t * banks_data ) {
755 654 : return fd_type_pun( (uchar *)banks_data + banks_data->stake_delegations_offset );
756 654 : }
757 :
758 : static inline void
759 : fd_banks_set_stake_delegations( fd_banks_data_t * banks_data,
760 12 : uchar * stake_delegations_mem ) {
761 12 : banks_data->stake_delegations_offset = (ulong)stake_delegations_mem - (ulong)banks_data;
762 12 : }
763 :
764 : static inline fd_bank_top_votes_t *
765 48 : fd_banks_get_top_votes_pool( fd_banks_data_t * banks_data ) {
766 48 : return fd_type_pun( (uchar *)banks_data + banks_data->top_votes_pool_offset );
767 48 : }
768 :
769 : static inline void
770 : fd_banks_set_top_votes_pool( fd_banks_data_t * banks_data,
771 12 : fd_bank_top_votes_t * top_votes_pool ) {
772 12 : banks_data->top_votes_pool_offset = (ulong)top_votes_pool - (ulong)banks_data;
773 12 : }
774 :
775 : static inline fd_bank_cost_tracker_t *
776 36 : fd_banks_get_cost_tracker_pool( fd_banks_data_t * banks_data ) {
777 36 : return fd_bank_cost_tracker_pool_join( (uchar *)banks_data + banks_data->cost_tracker_pool_offset );
778 36 : }
779 :
780 : static inline void
781 : fd_banks_set_cost_tracker_pool( fd_banks_data_t * banks_data,
782 12 : fd_bank_cost_tracker_t * cost_tracker_pool ) {
783 12 : void * cost_tracker_pool_mem = fd_bank_cost_tracker_pool_leave( cost_tracker_pool );
784 12 : if( FD_UNLIKELY( !cost_tracker_pool_mem ) ) {
785 0 : FD_LOG_CRIT(( "Failed to leave cost tracker pool" ));
786 0 : }
787 12 : banks_data->cost_tracker_pool_offset = (ulong)cost_tracker_pool_mem - (ulong)banks_data;
788 12 : }
789 :
790 : static inline void
791 : fd_banks_set_stake_rewards( fd_banks_data_t * bank,
792 12 : fd_stake_rewards_t * stake_rewards ) {
793 12 : bank->stake_rewards_offset = (ulong)stake_rewards - (ulong)bank;
794 12 : }
795 :
796 : static inline void
797 : fd_bank_set_stake_rewards( fd_bank_data_t * bank,
798 24 : fd_stake_rewards_t * stake_rewards ) {
799 24 : bank->stake_rewards_offset = (ulong)stake_rewards - (ulong)bank;
800 24 : }
801 :
802 : static inline fd_vote_stakes_t *
803 30198 : fd_banks_get_vote_stakes( fd_banks_data_t * banks_data ) {
804 30198 : return fd_type_pun( (uchar *)banks_data + banks_data->vote_stakes_pool_offset );
805 30198 : }
806 :
807 : static inline void
808 12 : fd_banks_set_vote_stakes( fd_banks_data_t * banks_data, fd_vote_stakes_t * vote_stakes ) {
809 12 : banks_data->vote_stakes_pool_offset = (ulong)vote_stakes - (ulong)banks_data;
810 12 : }
811 :
812 : /* fd_banks_root() returns a pointer to the root bank respectively. */
813 :
814 : FD_FN_PURE static inline fd_bank_t *
815 : fd_banks_root( fd_bank_t * bank_l,
816 0 : fd_banks_t * banks ) {
817 :
818 0 : fd_bank_data_t * bank_data = fd_banks_pool_ele( fd_banks_get_bank_pool( banks->data ), banks->data->root_idx );
819 0 : if( FD_UNLIKELY( !bank_data ) ) {
820 0 : return NULL;
821 0 : }
822 0 : bank_l->data = bank_data;
823 0 : bank_l->locks = banks->locks;
824 0 : return bank_l;
825 0 : }
826 :
827 : /* fd_banks_align() returns the alignment of fd_banks_data_t */
828 :
829 : ulong
830 : fd_banks_align( void );
831 :
832 : /* fd_banks_footprint() returns the footprint of fd_banks_data_t. This
833 : includes the struct itself but also the footprint for all of the
834 : pools.
835 :
836 : The footprint of fd_banks_data_t is determined by the total number
837 : of banks that the bank manages. This is an analog for the max number
838 : of unrooted blocks the bank can manage at any given time.
839 :
840 : We can also further bound the memory footprint of the banks by the
841 : max width of forks that can exist at any given time. The reason for
842 : this is that there are several large CoW structs that are only
843 : written to during the epoch boundary (e.g. epoch_stakes, etc.).
844 : These structs are read-only afterwards. This
845 : means if we also bound the max number of forks that can execute
846 : through the epoch boundary, we can bound the memory footprint of
847 : the banks. */
848 :
849 : ulong
850 : fd_banks_footprint( ulong max_total_banks,
851 : ulong max_fork_width,
852 : ulong max_stake_accounts,
853 : ulong max_vote_accounts );
854 :
855 :
856 : /* fd_banks_locks_init() initializes the locks for the fd_banks_t
857 : struct. In practice, this initializes all of the locks used by the
858 : underlying banks. */
859 :
860 : void
861 : fd_banks_locks_init( fd_banks_locks_t * locks );
862 :
863 : /* fd_banks_new() creates a new fd_banks_data_t struct. This function
864 : lays out the memory for all of the constituent fd_bank_data_t structs
865 : and pools depending on the max_total_banks and the max_fork_width for
866 : a given block. */
867 :
868 : void *
869 : fd_banks_new( void * mem,
870 : ulong max_total_banks,
871 : ulong max_fork_width,
872 : ulong max_stake_accounts,
873 : ulong max_vote_accounts,
874 : int larger_max_cost_per_block,
875 : ulong seed );
876 :
877 : /* fd_banks_join() joins a new fd_banks_t struct. It takes in a local
878 : handle to an fd_banks_t struct along with a valid banks_data_mem and
879 : banks_locks_mem. It returns the local handle to the joined
880 : fd_banks_t struct on success and NULL on failure (logs details). */
881 :
882 : fd_banks_t *
883 : fd_banks_join( fd_banks_t * banks_ljoin,
884 : void * banks_data_mem,
885 : void * bank_locks_mem );
886 :
887 : /* fd_banks_init_bank() initializes a new bank in the bank manager.
888 : This should only be used during bootup. This returns an initial
889 : fd_bank_t with the corresponding bank index set to 0. */
890 :
891 : fd_bank_t *
892 : fd_banks_init_bank( fd_bank_t * bank_l,
893 : fd_banks_t * banks );
894 :
895 : /* fd_banks_get_bank_idx returns a bank for a given bank index. */
896 :
897 : static inline fd_bank_t *
898 : fd_banks_bank_query( fd_bank_t * bank_l,
899 : fd_banks_t * banks,
900 0 : ulong bank_idx ) {
901 0 : fd_bank_data_t * bank_data = fd_banks_pool_ele( fd_banks_get_bank_pool( banks->data ), bank_idx );
902 0 : if( FD_UNLIKELY( !bank_data ) ) {
903 0 : return NULL;
904 0 : }
905 0 : if( FD_UNLIKELY( !(bank_data->flags&FD_BANK_FLAGS_INIT) ) ) {
906 0 : return NULL;
907 0 : }
908 0 : bank_l->data = bank_data;
909 0 : bank_l->locks = banks->locks;
910 0 : return bank_l;
911 0 : }
912 :
913 : static inline fd_bank_t *
914 : fd_banks_get_parent( fd_bank_t * bank_l,
915 : fd_banks_t * banks,
916 0 : fd_bank_t * bank ) {
917 0 : bank_l->data = fd_banks_pool_ele( fd_banks_get_bank_pool( banks->data ), bank->data->parent_idx );
918 0 : bank_l->locks = banks->locks;
919 0 : if( FD_UNLIKELY( !bank_l->data ) ) {
920 0 : return NULL;
921 0 : }
922 0 : return bank_l;
923 0 : }
924 :
925 : /* fd_banks_clone_from_parent() clones a bank from a parent bank.
926 : This function links the child bank to its parent bank and copies
927 : over the data from the parent bank to the child. This function
928 : assumes that the child and parent banks both have been allocated.
929 : The parent bank must be frozen and the child bank must be initialized
930 : but not yet used. It also assumes that the parent bank is not dead.
931 :
932 : A more detailed note: not all of the data is copied over and this
933 : is a shallow clone. All of the CoW fields are not copied over and
934 : will only be done so if the caller explicitly calls
935 : fd_bank_{*}_modify(). This naming was chosen to emulate the
936 : semantics of the Agave client. */
937 :
938 : fd_bank_t *
939 : fd_banks_clone_from_parent( fd_bank_t * bank_l,
940 : fd_banks_t * banks,
941 : ulong bank_idx );
942 :
943 : /* fd_banks_advance_root() advances the root bank to the bank manager.
944 : This should only be used when a bank is no longer needed and has no
945 : active refcnts. This will prune off the bank from the bank manager.
946 : It returns the new root bank. An invariant of this function is that
947 : the new root bank should be a child of the current root bank.
948 :
949 : All banks that are ancestors or siblings of the new root bank will be
950 : cancelled and their resources will be released back to the pool. */
951 :
952 : void
953 : fd_banks_advance_root( fd_banks_t * banks,
954 : ulong bank_idx );
955 :
956 : /* fd_bank_clear_bank() clears the contents of a bank. This should ONLY
957 : be used with banks that have no children and should only be used in
958 : testing and fuzzing.
959 :
960 : This function will memset all non-CoW fields to 0.
961 :
962 : For all CoW fields, we will reset the indices to its parent. */
963 :
964 : void
965 : fd_banks_clear_bank( fd_banks_t * banks,
966 : fd_bank_t * bank,
967 : ulong max_vote_accounts );
968 :
969 : /* fd_banks_advance_root_prepare returns the highest block that can be
970 : safely advanced between the current root of the fork tree and the
971 : target block. See the note on safe publishing for more details. In
972 : general, a node in the fork tree can be pruned if:
973 : (1) the node itself can be pruned, and
974 : (2) all subtrees (except for the one on the rooted fork) forking off
975 : of the node can be pruned.
976 : The highest publishable block is the highest block on the rooted fork
977 : where the above is true, or the rooted child block of such if there
978 : is one.
979 :
980 : This function assumes that the given target block has been rooted by
981 : consensus. It will mark every block on the rooted fork as rooted, up
982 : to the given target block. It will also mark minority forks as dead.
983 :
984 : Highest advanceable block is written to the out pointer. Returns 1
985 : if the advanceable block can be advanced beyond the current root.
986 : Returns 0 if no such block can be found. We will ONLY advance our
987 : advanceable_bank_idx to a child of the current root. In order to
988 : advance to the target bank, fd_banks_advance_root_prepare() must be
989 : called repeatedly. */
990 :
991 : int
992 : fd_banks_advance_root_prepare( fd_banks_t * banks,
993 : ulong target_bank_idx,
994 : ulong * advanceable_bank_idx_out );
995 :
996 : /* fd_banks_mark_bank_dead marks the current bank (and all of its
997 : descendants) as dead. The caller is still responsible for handling
998 : the behavior of the dead bank correctly. The function should not be
999 : called on a bank that is already dead nor on any ancestor of an
1000 : already dead bank. After a bank is marked dead, the caller should
1001 : never increment the reference count on the bank. */
1002 :
1003 : void
1004 : fd_banks_mark_bank_dead( fd_banks_t * banks,
1005 : ulong bank_idx );
1006 :
1007 : /* fd_banks_prune_one_dead_bank will try to prune one bank that was
1008 : marked as dead. It will not prune a dead bank that has a non-zero
1009 : reference count. Returns 0 if nothing was pruned, 1 if a bank was
1010 : pruned but no accdb/txncache cancellation is needed, or 2 if a bank
1011 : was pruned and cancellation is needed, in which case opt_cancel will
1012 : be populated if non-NULL. */
1013 :
1014 : int
1015 : fd_banks_prune_one_dead_bank( fd_banks_t * banks,
1016 : fd_banks_prune_cancel_info_t * cancel );
1017 :
1018 : /* fd_banks_mark_bank_frozen marks the current bank as frozen. This
1019 : should be done when the bank is no longer being updated: it should be
1020 : done at the end of a slot. This also releases the memory for the
1021 : cost tracker which only has to be persisted from the start of a slot
1022 : to the end.
1023 : TODO: bank param should be replaced with bank_idx */
1024 :
1025 : void
1026 : fd_banks_mark_bank_frozen( fd_banks_t * banks,
1027 : fd_bank_t * bank );
1028 :
1029 : /* fd_banks_new_bank reserves a bank index for a new bank. New bank
1030 : indicies should always be available. After this function is called,
1031 : the bank will be linked to its parent bank, but not yet replayable.
1032 : After a call to fd_banks_clone_from_parent, the bank will be
1033 : replayable. This assumes that there is a parent bank which exists
1034 : and that there are available bank indices in the bank pool. It also
1035 : assumes that the parent bank is not dead. */
1036 :
1037 : fd_bank_t *
1038 : fd_banks_new_bank( fd_bank_t * bank_l,
1039 : fd_banks_t * banks,
1040 : ulong parent_bank_idx,
1041 : long now );
1042 :
1043 :
1044 : /* fd_banks_get_frontier returns the frontier set of bank indices in the
1045 : banks tree. The frontier is defined as any bank which has no
1046 : no children and is initialized or replayable but not dead or frozen.
1047 : The caller is expected to have enough memory to store the bank
1048 : indices for the frontier. The bank indices are written to
1049 : frontier_indices_out in no particular order. The number of banks in
1050 : the frontier is written to the frontier_cnt_out pointer. */
1051 :
1052 : void
1053 : fd_banks_get_frontier( fd_banks_t * banks,
1054 : ulong * frontier_indices_out,
1055 : ulong * frontier_cnt_out );
1056 :
1057 : /* fd_banks_is_full returns 1 if the banks are full, 0 otherwise. Banks
1058 : can be full in two cases:
1059 : 1. All banks have been allocated
1060 : 2. There are too many active forks
1061 : a. There are too many cost tracker elements. This happens from
1062 : wide forking across blocks.
1063 : b. Too many forks have crossed the epoch boundary. */
1064 :
1065 : static inline int
1066 0 : fd_banks_is_full( fd_banks_t * banks ) {
1067 0 : return fd_banks_pool_free( fd_banks_get_bank_pool( banks->data ) )==0UL ||
1068 0 : fd_bank_cost_tracker_pool_free( fd_banks_get_cost_tracker_pool( banks->data ) )==0UL ||
1069 0 : fd_bank_top_votes_pool_free( fd_banks_get_top_votes_pool( banks->data ) )==0UL;
1070 0 : }
1071 :
1072 : FD_PROTOTYPES_END
1073 :
1074 : #endif /* HEADER_fd_src_flamenco_runtime_fd_bank_h */
|