Line data Source code
1 : #ifndef HEADER_fd_src_discof_replay_fd_replay_tile_private_h
2 : #define HEADER_fd_src_discof_replay_fd_replay_tile_private_h
3 :
4 : #include "fd_vote_tracker.h"
5 : #include "../../disco/fd_clock_tile.h"
6 : #include "../../disco/store/fd_store.h"
7 : #include "../../disco/bundle/fd_bundle_crank.h"
8 : #include "../../disco/keyguard/fd_keyswitch.h"
9 : #include "../../disco/node_info/fd_node_info.h"
10 : #include "../../disco/wait_info/fd_wait_info.h"
11 : #include "../../discof/poh/fd_poh.h"
12 : #include "../../disco/repair/fd_repair_tile.h"
13 : #include "../../discof/replay/fd_sched.h"
14 : #include "../../discof/replay/fd_execrp.h"
15 : #include "../../discof/votor/fd_votor_tile.h"
16 : #include "../../flamenco/capture/fd_capture_ctx.h"
17 : #include "../../flamenco/genesis/fd_genesis_parse.h"
18 : #include "../../flamenco/leaders/fd_multi_epoch_leaders.h"
19 : #include "../../flamenco/progcache/fd_progcache.h"
20 : #include "../../flamenco/alpenglow/fd_alpenglow.h"
21 : #include "../../flamenco/runtime/fd_bank.h"
22 : #include "../../flamenco/runtime/fd_txncache.h"
23 : #include "../../flamenco/runtime/tests/fd_dump_pb.h"
24 : #include "../../disco/events/generated/fd_event_gen.h"
25 : #include "../../util/fd_hash32.h"
26 : #include "../../ballet/bmtree/fd_bmtree.h"
27 : #include <stdio.h>
28 :
29 : struct fd_replay_in_link {
30 : fd_wksp_t * mem;
31 : ulong chunk0;
32 : ulong wmark;
33 : ulong mtu;
34 : };
35 :
36 : typedef struct fd_replay_in_link fd_replay_in_link_t;
37 :
38 : struct fd_replay_out_link {
39 : ulong idx;
40 : fd_wksp_t * mem;
41 : ulong chunk0;
42 : ulong wmark;
43 : ulong chunk;
44 : };
45 :
46 : typedef struct fd_replay_out_link fd_replay_out_link_t;
47 :
48 : struct fd_block_id_ele {
49 : fd_hash_t latest_mr; /* merkle root of the latest observed FEC set. This is NEVER the
50 : block id: on completion it holds the last FEC set's merkle root,
51 : which the next block's shreds chain off (the cmr). */
52 : fd_hash_t dmr; /* block id (double merkle root). Only valid once block_id_seen is
53 : set. */
54 : fd_block_id_t block_info; /* key for the compound map */
55 : uint latest_fec_idx;
56 : ulong slot;
57 : ulong bank_seq;
58 : ulong next;
59 : uint fec_cnt;
60 : uint block_id_seen : 1;
61 : uint finalized : 1; /* set only on slot_complete (block_id_seen) and finalized block.
62 : Is not consensus critical and does not affect replay order.
63 : It is only used to detect hard forks. */
64 : };
65 : typedef struct fd_block_id_ele fd_block_id_ele_t;
66 :
67 : struct fd_reception_stats {
68 : ulong bank_seq; /* alpenglow guard: valid iff ==bank->bank_seq */
69 : uint fec_set_idx;
70 : uchar votor_repaired; /* of the last FEC set delivered for the bank */
71 : };
72 : typedef struct fd_reception_stats fd_reception_stats_t;
73 :
74 0 : #define FD_REPLAY_TXN_TIMING_SLOTS (16UL)
75 :
76 : struct fd_replay_txn_timing {
77 : long received_ns;
78 :
79 : long parsed_ticks;
80 : long sigverify_disp_ticks;
81 : long sigverify_done_ticks;
82 : long exec_disp_ticks;
83 : long exec_done_ticks;
84 : };
85 :
86 : typedef struct fd_replay_txn_timing fd_replay_txn_timing_t;
87 :
88 : struct fd_replay_txn_timing_slot {
89 : struct {
90 : ulong next;
91 : } pool;
92 :
93 : ulong cnt;
94 : };
95 :
96 : typedef struct fd_replay_txn_timing_slot fd_replay_txn_timing_slot_t;
97 :
98 : #define POOL_NAME fd_timing_slot_pool
99 0 : #define POOL_T fd_replay_txn_timing_slot_t
100 0 : #define POOL_NEXT pool.next
101 : #include "../../util/tmpl/fd_pool.c"
102 :
103 : /* fd_ag_block_id_map indexes the same fd_block_id_ele_t array by the
104 : compound {slot, block_id} key. A block that is still being received
105 : through turbing is keyed by {slot, 0}: the DMR is only known once the
106 : slot-complete FEC arrives. FECs of a block thus resolve their bank
107 : via {slot, 0} without any per-FEC re-keying; on slot complete the
108 : entry is re-keyed once to the real {slot, block_id}.
109 :
110 : For blocks that were repaired due to a votor block id event, the
111 : block id is known at the slot start. So the entry is keyed by {slot,
112 : block_id} from the start and never rekeyed. */
113 :
114 : #define MAP_NAME fd_block_id_map
115 : #define MAP_ELE_T fd_block_id_ele_t
116 : #define MAP_KEY_T fd_block_id_t
117 0 : #define MAP_KEY block_info
118 0 : #define MAP_NEXT next
119 0 : #define MAP_KEY_EQ(k0,k1) (fd_block_id_eq( (k0), (k1) ))
120 0 : #define MAP_KEY_HASH(key,seed) (fd_hash( (seed), (key), sizeof(fd_block_id_t) ))
121 : #include "../../util/tmpl/fd_map_chain.c"
122 :
123 : /* fd_bhm_map (bank hash mismatch) remembers blocks that replay marked
124 : dead because the executed bank hash did not match the one the footer
125 : declared. A finalization (explicit or implicit) for an entry in this
126 : map means the cluster agreed on a bank hash we could not reproduce,
127 : i.e. this validator has diverged.
128 :
129 : The entries are FIFO evicted, so detection is best effort. On another
130 : note, if we mark a slot dead due to diverging bank hash, but it is on
131 : the finalized lineage but we do not receive a finalize for it (ex. it
132 : only reached notar fallback threshold), we would also miss detecting
133 : this bank hash mismatch. */
134 :
135 : struct fd_bhm_ele {
136 : fd_block_id_t block_id;
137 : ulong next;
138 : struct {
139 : ulong next;
140 : ulong prev;
141 : } dlist;
142 : };
143 : typedef struct fd_bhm_ele fd_bhm_ele_t;
144 :
145 : #define POOL_NAME fd_bhm_pool
146 0 : #define POOL_T fd_bhm_ele_t
147 : #include "../../util/tmpl/fd_pool.c"
148 :
149 : #define MAP_NAME fd_bhm_map
150 : #define MAP_ELE_T fd_bhm_ele_t
151 : #define MAP_KEY_T fd_block_id_t
152 0 : #define MAP_KEY block_id
153 0 : #define MAP_NEXT next
154 0 : #define MAP_KEY_EQ(k0,k1) (fd_block_id_eq( (k0), (k1) ))
155 0 : #define MAP_KEY_HASH(key,seed) (fd_hash( (seed), (key), sizeof(fd_block_id_t) ))
156 : #include "../../util/tmpl/fd_map_chain.c"
157 :
158 : #define DLIST_NAME fd_bhm_dlist
159 : #define DLIST_ELE_T fd_bhm_ele_t
160 0 : #define DLIST_PREV dlist.prev
161 0 : #define DLIST_NEXT dlist.next
162 : #include "../../util/tmpl/fd_dlist.c"
163 :
164 : FD_STATIC_ASSERT( FD_EVENT_BLOCK_COMPLETED_TXN_TIMING_MAX>=FD_MAX_TXN_PER_SLOT, txn_timing_ships_full_block );
165 :
166 : /* Per bank state of a block's footer tasks on exec tiles. */
167 :
168 : struct fd_replay_footer_end {
169 : fd_alpenglow_rewards_plan_t plan;
170 : ulong leader_credits; /* Summed from the reward slices as they complete. */
171 : ulong cert_next; /* Footer certs sent to tiles so far, in fd_alpenglow_footer_certs order. */
172 : int finalized; /* Set once BLOCK_END is processed. The block then fully completes on its last footer task. */
173 : };
174 : typedef struct fd_replay_footer_end fd_replay_footer_end_t;
175 :
176 : struct fd_replay_tile {
177 : fd_wksp_t * wksp;
178 :
179 : uint rng_seed;
180 : fd_rng_t rng[ 1 ];
181 :
182 : fd_clock_tile_t clock[1];
183 :
184 : fd_progcache_join_t progcache[1];
185 :
186 : fd_accdb_t * accdb;
187 : fd_txncache_t * txncache;
188 : fd_store_t * store;
189 : fd_store_map_t map_join[1];
190 : int store_disk_fd;
191 : fd_banks_t * banks;
192 :
193 : /* This flag is 1 If we have seen a vote signature that our node has
194 : sent out get rooted at least one time. The value is 0 otherwise.
195 : We can't become leader and pack blocks until this flag has been
196 : set. This parallels the Agave 'has_new_vote_been_rooted'. */
197 : int identity_vote_rooted;
198 : int wait_for_vote_to_start_leader; /* FD_BOOLAU_{FALSE,TRUE,AUTO} */
199 :
200 : /* vote_account_staked is 1 if stake was delegated to our vote
201 : account at boot. vote_account_inadmissible is 1 while our staked
202 : vote account fails the admission ticket filter, or passes it but
203 : has not yet been admitted at an epoch boundary. */
204 : int vote_account_staked;
205 : int vote_account_inadmissible;
206 :
207 : /* wfs_enabled is 1 if the validator is booted in
208 : wait_for_supermajority mode. In this mode replay (and, by extension,
209 : downstream consumers) is not allowed to make progress until 80% of
210 : the cluster has published their ContactInfo in Gossip with a
211 : shred version matching expected_shred_version. When this happens,
212 : wfs_complete will be set to 1. */
213 : int wfs_enabled;
214 : int wfs_complete;
215 :
216 : ulong wait_for_supermajority_at_slot;
217 : fd_hash_t expected_bank_hash;
218 : int wfs_hash_is_zero;
219 :
220 : ulong blockhash_seed;
221 : fd_reception_stats_t * reception_stats;
222 : ulong reception_stats_cnt;
223 :
224 : /* When a bank is evicted, the replayable chain of FECs delivered from rotor is broken. i.e.
225 : we lose context for a parent we needed to replay off of. When this happens,
226 : on the first FEC we see we can't replay, we need to drain everything in the dcache
227 : until there's something we can replay off of. Set this flag to enter that state (i.e. ignore FECs
228 : until there's one we can replay. )*/
229 : int drain_rotor_fecs;
230 :
231 : fd_sched_t * sched;
232 : ulong in_cnt;
233 : ulong execrp_idle_cnt;
234 :
235 : fd_bank_lthash_rec_t lthash_rec[ 1 ];
236 : fd_execrp_result_t * execrp_result; /* One entry per exec tile. */
237 :
238 : /* Signing payload of each exec tile's footer cert verify task */
239 : uchar cert_payload [ FD_SCHED_MAX_EXEC_TILE_CNT ][ FD_ALPENGLOW_CERT_PAYLOAD_MAX ];
240 : ulong cert_payload_sz[ FD_SCHED_MAX_EXEC_TILE_CNT ];
241 :
242 : fd_replay_footer_end_t * footer_end; /* Indexed by bank idx. */
243 : ulong rewards_in_flight_cnt; /* Reward slices out on exec tiles, over every bank. */
244 :
245 : ulong vote_tracker_seed;
246 : fd_vote_tracker_t * vote_tracker;
247 :
248 : uint has_genesis_hash:1;
249 : uint has_cluster_type:1;
250 : uint has_genesis_timestamp:1;
251 : uint has_expected_genesis_timestamp:1;
252 :
253 : char genesis_path[ PATH_MAX ];
254 : fd_hash_t genesis_hash[1];
255 : fd_genesis_t * genesis;
256 : ulong cluster_type;
257 : ulong genesis_timestamp;
258 : ulong expected_genesis_timestamp;
259 :
260 : ulong hard_fork_cnt;
261 : fd_hard_fork_t hard_forks[ FD_HARD_FORKS_MAX ];
262 :
263 : ushort expected_shred_version; /* from config, 0 if unset */
264 : ushort ipecho_shred_version; /* from the entrypoints via ipecho, 0 until it answers */
265 : ushort shred_version; /* 0 until computed. the two above only cross-check
266 : it, and replay holds off executing until it is known. */
267 :
268 : ulong enable_features_cnt;
269 : char enable_features[ 16 ][ FD_BASE58_ENCODED_32_SZ ];
270 :
271 : /* A note on publishing ...
272 :
273 : The watermarks are used to publish our fork-aware structures. For
274 : example, store, banks, and txncache need to be published to release
275 : resources occupied by rooted or dead blocks. In general,
276 : publishing has the effect of pruning forks in those structures,
277 : indicating that it is ok to release the memory being occupied by
278 : the blocks on said forks. Finalization determines the latest
279 : block on the consensus rooted fork. As soon as we can,
280 : we should move the published root as close as possible to the
281 : latest consensus root, publishing/pruning everything on the fork
282 : tree along the way. That is, all the blocks that directly descend
283 : from the current published root (inclusive) to the new published
284 : root (exclusive) on the rooted fork, as well as all the minority
285 : forks that branch from said blocks.
286 :
287 : Ideally, we'd move the published root to the consensus root
288 : immediately upon receiving a new consensus root. However, that's
289 : not always safe to do. One thing we need to be careful about is
290 : making sure that there are no more users/consumers of
291 : soon-to-be-pruned blocks, lest a use-after-free occurs. This can
292 : be done by using a reference counter for each block. Any
293 : concurrent activity, such as transaction execution in the exec
294 : tiles, should retain a refcnt on the block for as
295 : long as it needs access to the shared fork-aware structures related
296 : to that block. Eventually, refcnt on a given block will drop down
297 : to 0 as the block either finishes replaying or gets marked as dead,
298 : and any other tile that has retained a refcnt on the block releases
299 : it. At that point, it becomes a candidate for pruning. The key to
300 : safe publishing then becomes figuring out how far we could advance
301 : the published root, such that every minority fork branching off of
302 : blocks in between the current published root (inclusive) and the
303 : new published root (exclusive) is safe to be pruned. This is a
304 : straightforward tree traversal, where if a block B on the rooted
305 : fork has refcnt 0, and all minority forks branching off of B also
306 : have refcnt 0, then B is safe to be pruned. We advance the
307 : published root to the farthest consecutively prunable block on the
308 : rooted fork. Note that rotor presents the replay tile with a clean
309 : view of the world where every block is chained off of a parent
310 : block. So there are no orpahned/dangling tree nodes to worry
311 : about. The world is a nice single tree as far as replay is
312 : concerned.
313 :
314 : In the following fork tree, every node is a block and the number in
315 : parentheses is the refcnt on the block. The chain marked with
316 : double slashes is the rooted fork. Suppose the published root is
317 : at block P, and consensus root is at block T. We can't publish
318 : past block P because Q has refcnt 1.
319 :
320 :
321 : P(0)
322 : / \\
323 : Q(1) A(0)
324 : / || \
325 : X(0) B(0) C(0)
326 : / || \
327 : Y(0) M(0) R(0)
328 : / || / \
329 : D(2) T(0) J(0) L(0)
330 : ||
331 : ..
332 : ..
333 : ..
334 : ||
335 : blocks we might be actively replaying
336 :
337 :
338 : When refcnt on Q drops to 0, we would be able to advance the
339 : published root to block M, because blocks P, A, and B, as well as
340 : all subtrees branching off of them, have refcnt 0, and therefore
341 : can be pruned. Block M itself cannot be pruned yet because its
342 : child block D has refcnt 2. After publishing/pruning, the fork
343 : tree would be:
344 :
345 :
346 : M(0)
347 : / ||
348 : D(2) T(0)
349 : ||
350 : ..
351 : ..
352 : ..
353 : ||
354 : blocks we might be actively replaying
355 :
356 :
357 : As a result, the shared fork-aware structures can free resources
358 : for blocks P, A, B, and all subtrees branching off of them.
359 :
360 : For the reference counting part, the replay tile is the sole entity
361 : that can update the refcnt. This ensures that all refcnt increment
362 : and decrement attempts are serialized at the replay tile, and that
363 : there is no racy resurrection of a soon-to-be-pruned block.
364 :
365 : A note on the implementation of the above ...
366 :
367 : Upon receiving a new consensus root, we descend down the rooted
368 : fork from the current published root to the new consensus root. On
369 : each node/block of the rooted fork, we do a summation of the refcnt
370 : on the block and all the minority fork blocks branching from the
371 : block. If the summation is 0, the block is safe for pruning. We
372 : advance the published root to the far end of the consecutive run of
373 : 0 refcnt sums originating from the current published root. On our
374 : descent down the minority forks, we also mark any block that hasn't
375 : finished replaying as dead, so we don't waste time executing them.
376 : No more transactions shall be dispatched for execution from dead
377 : blocks.
378 :
379 : Blocks start out with a refcnt of 0. Replay increments refcnt before
380 : publishing a bank reference to another tile; that tile notifies
381 : replay when it releases the reference. Each task dispatched to an
382 : exec tile also holds a reference until its completion message.
383 :
384 : The scheduler holds an additional reference from the first FEC set
385 : until the block finishes replaying or is abandoned and its in-flight
386 : tasks have drained. This prevents an actively replaying bank from
387 : being pruned between task dispatches.
388 :
389 : Marking a minority fork dead stops further execution dispatch. Once
390 : the outstanding tasks drain and the scheduler and other consumers
391 : release their references, the bank can be pruned even if it never
392 : finished replaying.
393 : */
394 : fd_hash_t consensus_root; /* finalized and replayed */
395 : ulong consensus_root_slot; /* slot number of the above. */
396 : fd_hash_t notified_root; /* The most recent consensus root sent to sched, RPC, and resolv. */
397 : ulong notified_root_slot; /* slot number of the above. */
398 : fd_bank_t * notified_root_bank; /* bank held by sched, RPC, and resolv for the notified root. */
399 : ulong published_root_slot; /* slot number of the published root. */
400 : ulong published_root_bank_idx; /* bank index of the published root. */
401 :
402 : /* Watermarks marking the finalized but unreplayed slots. lo is the
403 : oldest and held until replay reaches it. hi is the newest and
404 : continuously updated. Finalizations between lo and hi are dropped
405 : since rooting hi implies its ancestors. */
406 : fd_block_id_t finalized_block_id_lo;
407 : fd_block_id_t finalized_block_id_hi;
408 :
409 : /* Randomly generated block id for the initial genesis/snapshot slot.
410 : Used as a fallback when the snapshot manifest does not contain a
411 : block_id (block_id will be populated in Agave 4.1 snapshots and
412 : will be required in Agave 4.2). */
413 :
414 : fd_hash_t initial_block_id;
415 :
416 : /* Snapshot manifest claims */
417 :
418 : int has_manifest_block_id;
419 : fd_hash_t manifest_block_id; /* block ID of snapshot slot */
420 : fd_pubkey_t manifest_leader_id; /* leader identity of snapshot slot */
421 :
422 : /* We need to maintain a tile-local mapping of block-ids to bank index
423 : and vice versa. This translation layer is needed for conversion
424 : since votor operates on block-ids and downstream consumers of FEC
425 : sets operate on bank indices. This mapping must happen both ways:
426 : 1. votor sends us block ids and we must map them to bank indices.
427 : 2. when a block is completed, we must map the bank index to a block
428 : id to send a slot complete message. */
429 : ulong block_id_len;
430 : ulong max_live_slots;
431 : fd_block_id_ele_t * block_id_arr;
432 : ulong * dead_idxs; /* max_live_slots scratch for mark_bank_dead */
433 :
434 : fd_hash_t * fec_chain;
435 :
436 : ulong block_id_map_seed;
437 : fd_block_id_map_t * block_id_map;
438 :
439 : ulong bhm_map_seed;
440 : fd_bhm_map_t * bhm_map;
441 : fd_bhm_ele_t * bhm_pool;
442 : fd_bhm_dlist_t * bhm_dlist;
443 :
444 : /* Capture-related configs */
445 : fd_capture_ctx_t * capture_ctx;
446 : FILE * capture_file;
447 : fd_capture_link_buf_t cap_repl_out[1];
448 :
449 : /* Protobuf dumping context for debugging runtime execution and
450 : collecting seed corpora. */
451 : fd_dump_proto_ctx_t * dump_proto_ctx;
452 :
453 : /* Per-txn lifecycle timing capture. The scheduler's txn_info_pool
454 : entries are recycled the moment a txn completes, so the ticks are
455 : copied out at completion time into a leased capture slot, indexed by
456 : the txn's position in the block. A full-depth buffer per live bank
457 : would be ~9.6 GiB, but only a handful of blocks replay concurrently,
458 : so a small pool of full-depth slots is leased to banks as they start
459 : replaying. A block that cannot get a slot (more than
460 : FD_REPLAY_TXN_TIMING_SLOTS blocks replaying at once) captures
461 : nothing. Slot depth is max_txn_per_slot, so the records sit in a
462 : side array sized at footprint time. */
463 : fd_replay_txn_timing_slot_t * timing_slot_pool; /* fd_pool, FD_REPLAY_TXN_TIMING_SLOTS elements */
464 : fd_replay_txn_timing_t * timing_rec; /* [FD_REPLAY_TXN_TIMING_SLOTS*max_txn_per_slot], slot i at i*max_txn_per_slot */
465 : ulong * timing_slot_of_bank; /* [max_live_slots] bank_idx -> pool idx or idx_null */
466 :
467 : /* Whether the runtime has been booted either from snapshot loading
468 : or from genesis. */
469 : int is_booted;
470 :
471 : fd_multi_epoch_leaders_t * mleaders;
472 :
473 : ulong max_txn_per_slot;
474 : ulong max_shreds_per_block;
475 :
476 : /* When we transition to becoming leader, we can only unbecome leader
477 : if we have received a block id from the FEC reassembler, and a
478 : message from PoH that the leader slot has ended. After both of
479 : these conditions are met, then we are free to unbecome leader.
480 : Exception: a slot aborted by a reset unbecomes leader on the PoH
481 : slot-ended message alone; no block id will ever arrive for it. */
482 : uint is_leader : 1;
483 : uint supports_leader : 1;
484 : int recv_poh;
485 :
486 : ulong leader_execution_fees;
487 : ulong leader_priority_fees;
488 : ulong leader_tips;
489 : fd_block_footer_t leader_footer[ 1 ];
490 :
491 : fd_votor_certed_t votor_final[ 1 ]; /* highest finalization, fast over slow at the same slot */
492 : fd_votor_leader_t votor_leader[ 1 ]; /* ParentReady trigger behind next_leader_slot */
493 : ulong votor_parent_ready_slot; /* highest window start certs made ParentReady */
494 : long leader_window_start_ns; /* ParentReady time of the window we are leading */
495 : fd_votor_reward_t votor_reward[ FD_NUM_SLOTS_FOR_REWARD+FD_VOTOR_SLOTS_PER_WINDOW+1UL ];
496 :
497 : ulong next_leader_slot;
498 :
499 :
500 : ulong next_leader_query_start;
501 : ulong next_leader_query_slot;
502 :
503 : ulong highwater_leader_slot;
504 : ulong reset_slot;
505 : ulong epoch_end_slot;
506 : ulong slots_per_epoch;
507 : ulong ns_per_slot;
508 :
509 : /* Caught up to the cluster: replay has completed a slot within a few
510 : slots of the cluster tip. Rotor tracks the tip and ships it on
511 : each delivered FEC, because rotor delivers only
512 : replayable FECs in order and their slots track replay itself. */
513 : int caught_up;
514 : ulong catch_up_max_fec_slot;
515 : ulong catch_up_tip_advance_cnt;
516 : long boot_timestamp_nanos;
517 :
518 : fd_bank_t * leader_bank;
519 :
520 : struct {
521 : ulong slot;
522 : long became_leader_nanos;
523 : long leader_slot_start_nanos;
524 : long first_fec_returned_nanos;
525 : ulong microblock_count;
526 : ulong pack_block_cost;
527 : ulong pack_data_bytes;
528 : ulong bundle_txn_count;
529 : int pack_end_reason;
530 : long pack_start_nanos;
531 : long pack_end_nanos;
532 : ulong timing_table_idx;
533 : } leader_stats;
534 :
535 : fd_pubkey_t identity_pubkey[1];
536 : ulong identity_idx;
537 : int identity_dirty;
538 :
539 : int has_vote_account;
540 : fd_pubkey_t vote_account[ 1 ];
541 :
542 : fd_node_info_box_t * node_info; /* shared */
543 : fd_wait_info_box_t * wait_info; /* shared */
544 :
545 : /* Delinquency, published through wait_info only; not a metric. */
546 : int delinquent_known;
547 : ulong delinquent_sample_slot;
548 : ulong delinquent_stake_lamports;
549 : ulong cluster_active_stake_lamports;
550 : /* Delinquency tracking, from the block footer reward certs since
551 : last_vote_slot stalls without vote transactions. Indexed by
552 : alpenglow rank, which is epoch-scoped. */
553 : ulong ag_last_voted[ FD_VOTOR_VAT_MAX ];
554 : ulong ag_last_voted_epoch; /* ULONG_MAX before the first reward cert */
555 : ulong ag_last_settled; /* highest settled slot observed */
556 : ulong ag_stamp_since; /* first slot stamped into an empty table */
557 :
558 : /* Our identity's rank in the vote stakes snapshot of an epoch.
559 : USHORT_MAX if unranked. Cached since the snapshot is fixed for the
560 : epoch. */
561 : int voter_rank_cached;
562 : ulong voter_rank_epoch;
563 : ushort voter_rank;
564 :
565 : fd_keyswitch_t * keyswitch;
566 : int halt_replay;
567 :
568 : ulong resolv_tile_cnt;
569 :
570 : int in_kind[ 128 ];
571 : fd_replay_in_link_t in[ 128 ];
572 :
573 : ulong exec_cnt;
574 : fd_replay_out_link_t exec_out[ FD_SCHED_MAX_EXEC_TILE_CNT ];
575 :
576 : fd_replay_out_link_t replay_out[1];
577 : fd_replay_out_link_t slot_out[1];
578 : fd_replay_out_link_t rotor_out[1]; /* REPLAY_SIG_MISSING_FEC */
579 : ulong const * slot_out_seq;
580 : fd_replay_out_link_t snapmk_out[1];
581 : ulong admin_out_idx;
582 :
583 : fd_replay_out_link_t epoch_out[1];
584 :
585 : /* The rpc tile needs to occasionally own a reference to a live bank.
586 : Replay needs to know if the rpc as a consumer is enabled so it can
587 : increment the bank's refcnt before publishing bank_idx. */
588 : int rpc_enabled;
589 :
590 : /* For dumping blocks to protobuf. For backtest only. */
591 : fd_block_dump_ctx_t * block_dump_ctx;
592 :
593 : /* We need a few pieces of information to compute the right addresses
594 : for bundle crank information that we need to send to pack. */
595 : struct {
596 : int enabled;
597 : fd_pubkey_t vote_account;
598 : fd_bundle_crank_gen_t gen[1];
599 : } bundle;
600 :
601 : /* snapshot producer */
602 : struct {
603 : uint supported:1;
604 : uint active:1;
605 : uint incremental:1;
606 : ulong bank_idx;
607 : ulong scheduled_at_slot;
608 : ulong full_interval_blocks;
609 : ulong next_full_block_height;
610 : ulong incremental_interval_blocks;
611 : ulong next_incremental_block_height;
612 : ulong base_slot;
613 : ulong snap_finished_full;
614 : ulong snap_finished_incr;
615 : ulong snap_produced_incr_cnt;
616 : fd_epoch_credits_view_t epoch_credits_view[1];
617 : } snapmk;
618 :
619 : struct {
620 : fd_histf_t store_query_work[1];
621 : ulong store_query_cnt;
622 : ulong store_query_missing_cnt;
623 :
624 : ulong slots_total;
625 : ulong transactions_total;
626 :
627 : ulong reasm_latest_slot;
628 : ulong reasm_latest_fec_idx;
629 :
630 : ulong sched_full;
631 : ulong lane_wait;
632 : ulong leader_bid_wait;
633 : ulong banks_full;
634 : ulong parent_unavailable;
635 : ulong leader_slot_already_produced;
636 : ulong leader_window_superseded;
637 : ulong fec_rooted_past;
638 : ulong storage_root_behind;
639 :
640 : ulong voted_slot; /* monotone, ULONG_MAX if none */
641 : } metrics;
642 :
643 : uchar __attribute__((aligned(FD_MULTI_EPOCH_LEADERS_ALIGN))) mleaders_mem[ FD_MULTI_EPOCH_LEADERS_FOOTPRINT ];
644 :
645 : ulong runtime_stack_seed;
646 : fd_runtime_stack_t * runtime_stack;
647 :
648 : fd_footer_cache_t * footer_cache;
649 :
650 : fd_event_block_completed_t * block_completed_event;
651 :
652 : fd_leader_txn_timing_table_t const * leader_txn_timing;
653 :
654 : /* If non-zero, emit the runtime events during replay. */
655 : int report_runtime_diffs;
656 : };
657 :
658 : typedef struct fd_replay_tile fd_replay_tile_t;
659 :
660 : #endif /* HEADER_fd_src_discof_replay_fd_replay_tile_private_h */
|