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