Line data Source code
1 : #ifndef HEADER_fd_src_choreo_forks_fd_forks_h 2 : #define HEADER_fd_src_choreo_forks_fd_forks_h 3 : 4 : #include "../../flamenco/runtime/context/fd_exec_epoch_ctx.h" 5 : #include "../../flamenco/runtime/context/fd_exec_slot_ctx.h" 6 : #include "../../flamenco/runtime/fd_blockstore.h" 7 : #include "../fd_choreo_base.h" 8 : #include "../ghost/fd_ghost.h" 9 : #include "../voter/fd_voter.h" 10 : 11 : /* FD_FORKS_USE_HANDHOLDING: Define this to non-zero at compile time 12 : to turn on additional runtime checks and logging. */ 13 : 14 : #ifndef FD_FORKS_USE_HANDHOLDING 15 : #define FD_FORKS_USE_HANDHOLDING 1 16 : #endif 17 : 18 : struct fd_fork { 19 : ulong slot; /* the fork head and frontier key */ 20 : ulong next; /* reserved for use by fd_pool and fd_map_chain */ 21 : ulong prev; /* reserved for use by fd_forks_publish */ 22 : int lock; /* IMPORTANT SAFETY TIP! lock is a boolean indicating 23 : whether a fork's most recent block is still being 24 : actively replayed (executed) and should generally not 25 : be read or written to by downstream consumers (eg. 26 : consensus, publishing) and should definitely not be 27 : removed. */ 28 : fd_exec_slot_ctx_t slot_ctx; 29 : }; 30 : 31 : typedef struct fd_fork fd_fork_t; 32 : 33 : #define POOL_NAME fd_fork_pool 34 0 : #define POOL_T fd_fork_t 35 : #include "../../util/tmpl/fd_pool.c" 36 : 37 : #define MAP_NAME fd_fork_frontier 38 : #define MAP_ELE_T fd_fork_t 39 0 : #define MAP_KEY slot 40 : #include "../../util/tmpl/fd_map_chain.c" 41 : 42 : /* fd_forks maintains all the outstanding fork heads known as the 43 : frontier. The memory required for these fork heads is pre-allocated 44 : in `pool`. 45 : 46 : {processed, confirmed, finalized} correspond to the highest slots 47 : that have achieved each of these cluster commitment levels. This is 48 : based on what Firedancer has locally observed, so these values are 49 : not atomically synchronized with other nodes in the cluster (ie. 50 : other nodes may report higher or lower slot numbers for each of 51 : these) but are "eventually consistent" as long as Firedancer is 52 : connected to the cluster and replaying blocks. All three values are 53 : strictly monotonically increasing. 54 : 55 : processed - a slot has been replayed. 56 : confirmed - a slot has been "optimistically confirmed" ie. 2/3 of 57 : stake has voted for it. 58 : finalized - a slot has been "supermajority rooted" ie. 2/3 of stake 59 : has rooted it or any of its descendants. */ 60 : 61 : struct fd_forks { 62 : fd_fork_frontier_t * frontier; /* map of slot->fd_fork_t */ 63 : fd_fork_t * pool; /* memory pool of fd_fork_t */ 64 : ulong processed; 65 : ulong confirmed; 66 : ulong finalized; 67 : }; 68 : typedef struct fd_forks fd_forks_t; 69 : 70 : /* fd_forks_{align,footprint} return the required alignment and 71 : footprint of a memory region suitable for use as forks with up to max 72 : fork heads in the frontier. */ 73 : 74 : FD_FN_CONST static inline ulong 75 0 : fd_forks_align( void ) { 76 0 : return alignof( fd_forks_t ); 77 0 : } 78 : 79 : FD_FN_CONST static inline ulong 80 0 : fd_forks_footprint( ulong max ) { 81 0 : return FD_LAYOUT_FINI( 82 0 : FD_LAYOUT_APPEND( 83 0 : FD_LAYOUT_APPEND( 84 0 : FD_LAYOUT_APPEND( 85 0 : FD_LAYOUT_INIT, 86 0 : alignof(fd_forks_t), sizeof(fd_forks_t) ), 87 0 : fd_fork_pool_align(), fd_fork_pool_footprint( max ) ), 88 0 : fd_fork_frontier_align(), fd_fork_frontier_footprint( max ) ), 89 0 : alignof(fd_forks_t) ); 90 0 : } 91 : 92 : /* fd_forks_new formats an unused memory region for use as a forks. mem 93 : is a non-NULL pointer to this region in the local address space with 94 : the required footprint and alignment. */ 95 : 96 : void * 97 : fd_forks_new( void * shmem, ulong max, ulong seed ); 98 : 99 : /* fd_forks_join joins the caller to the forks. forks points to the 100 : first byte of the memory region backing the forks in the caller's 101 : address space. 102 : 103 : Returns a pointer in the local address space to forks on success. */ 104 : 105 : fd_forks_t * 106 : fd_forks_join( void * forks ); 107 : 108 : /* fd_forks_leave leaves a current local join. Returns a pointer to the 109 : underlying shared memory region on success and NULL on failure (logs 110 : details). Reasons for failure include forks is NULL. */ 111 : 112 : void * 113 : fd_forks_leave( fd_forks_t const * forks ); 114 : 115 : /* fd_forks_delete unformats a memory region used as a forks. Assumes 116 : only the local process is joined to the region. Returns a pointer to 117 : the underlying shared memory region or NULL if used obviously in 118 : error (e.g. forks is obviously not a forks ... logs details). The 119 : ownership of the memory region is transferred to the caller. */ 120 : 121 : void * 122 : fd_forks_delete( void * forks ); 123 : 124 : /* fd_forks_init initializes forks. Assumes forks is a valid local join 125 : and no one else is joined, and non-NULL slot_ctx. Inserts the first 126 : fork into the frontier containing slot_ctx. This should be the 127 : slot_ctx from loading a snapshot, restoring a bank from Funk, or the 128 : genesis slot_ctx. The slot_ctx will be copied into an element 129 : acquired from the memory pool owned by forks. Returns fork on 130 : success, NULL on failure. 131 : 132 : In general, this should be called by the same process that formatted 133 : forks' memory, ie. the caller of fd_forks_new. */ 134 : 135 : fd_fork_t * 136 : fd_forks_init( fd_forks_t * forks, fd_exec_slot_ctx_t const * slot_ctx ); 137 : 138 : /* fd_forks_query queries for the fork corresponding to slot in the 139 : frontier. Returns the fork if found, otherwise NULL. */ 140 : 141 : fd_fork_t * 142 : fd_forks_query( fd_forks_t * forks, ulong slot ); 143 : 144 : /* fd_forks_query_const is the const version of the above. */ 145 : 146 : fd_fork_t const * 147 : fd_forks_query_const( fd_forks_t const * forks, ulong slot ); 148 : 149 : /* fd_forks_advance advances a parent_slot to slot in the frontier. 150 : Assumes parent_slot corresponds to a fork currently in the frontier 151 : (ie. has already been prepared), slot is a child of parent_slot, and 152 : parent_slot has already been replayed. Fails if fork is not frozen. 153 : Returns the updated fork on success, NULL on failure. */ 154 : 155 : fd_fork_t * 156 : fd_forks_advance( fd_forks_t const * forks, fd_fork_t * fork, ulong slot ); 157 : 158 : /* fd_forks_prepare prepares a fork for execution. The fork will either 159 : be an existing fork in the frontier if parent_slot is already a fork 160 : head or it will start a new fork at parent_slot and add it to the 161 : frontier. 162 : 163 : Returns fork on success, NULL on failure. Failure reasons include 164 : parent_slot is not present in the blockstore, is not present in funk, 165 : or does not have a valid ancestry. 166 : 167 : It is possible for the fork to return NULL in a non-error condition. 168 : For example, a leader tries to rollback and start a new fork from a 169 : very old slot that the blockstore has already pruned. In this 170 : scenario, we cannot prepare a new fork at parent_slot because we have 171 : already rooted past it. */ 172 : 173 : fd_fork_t * 174 : fd_forks_prepare( fd_forks_t const * forks, 175 : ulong parent_slot, 176 : fd_acc_mgr_t * acc_mgr, 177 : fd_blockstore_t * blockstore, 178 : fd_exec_epoch_ctx_t * epoch_ctx, 179 : fd_funk_t * funk, 180 : fd_spad_t * runtime_spad ); 181 : 182 : /* fd_forks_update updates `blockstore` and `ghost` with the latest 183 : state resulting from replaying `slot`. Assumes `slot` is a fork head 184 : in the frontier. In general, this should be called immediately after 185 : `slot` has been replayed. */ 186 : 187 : void 188 : fd_forks_update( fd_forks_t * forks, 189 : fd_epoch_t * epoch, 190 : fd_funk_t * funk, 191 : fd_ghost_t * ghost, 192 : ulong slot ); 193 : 194 : /* fd_forks_publish publishes a new root into forks. Assumes root is a 195 : valid slot that exists in the cluster and has already been replayed. 196 : This prunes all the existing forks in the frontier except descendants 197 : of root. Forks that are not frozen will also not be pruned (warns 198 : when handholding is enabled). */ 199 : 200 : void 201 : fd_forks_publish( fd_forks_t * fork, 202 : ulong root, 203 : fd_ghost_t const * ghost ); 204 : 205 : /* fd_forks_print prints a forks as a list of the frontiers and number 206 : of forks (pool eles acquired). */ 207 : 208 : void 209 : fd_forks_print( fd_forks_t const * forks ); 210 : 211 : #endif /* HEADER_fd_src_choreo_forks_fd_forks_h */