Line data Source code
1 : #ifndef HEADER_fd_src_choreo_notar_fd_notar_h 2 : #define HEADER_fd_src_choreo_notar_fd_notar_h 3 : 4 : #include "../fd_choreo_base.h" 5 : #include "../tower/fd_tower.h" 6 : 7 : /* fd_notar ("notarization") is an API for tracking when blocks reach 8 : key stake thresholds from votes. Solana calls them "confirmation 9 : levels", and they are as follows: 10 : 11 : - propagation confirmed: a block is propagated if it has received 12 : votes from at least 1/3 of stake in the cluster. This threshold is 13 : important for the leader pipeline, which ensures a previous leader 14 : block has propagated before producing the next one. It is also 15 : used when voting, as we do not vote for forks in which our last 16 : leader block failed to propagate. 17 : 18 : - duplicate confirmed: a block is duplicate confirmed if it has 19 : received votes from at least 52% of stake in the cluster. The 20 : "duplicate" adjective is a bit of a misnomer, and a more accurate 21 : technical term is equivocation: two (or more) different blocks for 22 : the same slot. This threshold is important for consensus safety, 23 : because it ensures Solana eventually converges to a single block 24 : per slot. 25 : 26 : - optimistically confirmed: a block is optimistically confirmed it 27 : has received votes from at least 2/3 of stake in the cluster. This 28 : threshold is important for end-users, who rely on the "confirmed" 29 : commitment status of blocks (queryable via RPC) to determine that 30 : their transaction has landed on a block that will not rollback. */ 31 : 32 : /* TODO duplicate confirmed / optimistc confirmed currently not 33 : implemented through this API */ 34 : 35 : /* FD_NOTAR_PARANOID: Define this to non-zero at compile time 36 : to turn on additional runtime integrity checks. */ 37 : 38 : #ifndef FD_NOTAR_PARANOID 39 : #define FD_NOTAR_PARANOID 1 40 : #endif 41 : 42 : struct fd_notar_vtr { 43 : fd_pubkey_t pubkey; /* map key */ 44 : uint memo; /* reserved for fd_map_dynamic */ 45 : ulong bit; /* bit position in fd_notar_blk_vtrs (fd_set) */ 46 : ulong vote; /* the most recent slot the validator voted for */ 47 : fd_hash_t hash; /* the most recent hash the validator voted for */ 48 : }; 49 : typedef struct fd_notar_vtr fd_notar_vtr_t; 50 : 51 : static const fd_pubkey_t pubkey_null = {{ 0 }}; 52 : 53 : #define MAP_NAME fd_notar_vtr 54 0 : #define MAP_T fd_notar_vtr_t 55 0 : #define MAP_HASH memo 56 0 : #define MAP_KEY pubkey 57 0 : #define MAP_KEY_T fd_pubkey_t 58 : #define MAP_KEY_NULL pubkey_null 59 : #define MAP_KEY_EQUAL_IS_SLOW 1 60 0 : #define MAP_KEY_INVAL(k) MAP_KEY_EQUAL((k),MAP_KEY_NULL) 61 0 : #define MAP_KEY_EQUAL(k0,k1) (!memcmp( (k0).key, (k1).key, 32UL )) 62 0 : #define MAP_KEY_HASH(key) ((MAP_HASH_T)( (key).ul[1] )) 63 : #include "../../util/tmpl/fd_map_dynamic.c" 64 : 65 : #define SET_NAME fd_notar_blk_vtrs 66 : #define SET_MAX FD_VOTER_MAX 67 : #include "../../util/tmpl/fd_set.c" 68 : 69 : struct fd_notar_blk { 70 : ulong slot; 71 : ulong parent_slot; 72 : fd_hash_t bank_hash; 73 : ulong stake; 74 : int pro_conf; 75 : int dup_conf; /* TODO unimplemented */ 76 : int opt_conf; /* TODO unimplemented */ 77 : fd_notar_blk_vtrs_t vtrs[fd_notar_blk_vtrs_word_cnt]; /* pubkeys (validator identity) that have voted for this block */ 78 : }; 79 : typedef struct fd_notar_blk fd_notar_blk_t; 80 : 81 : #define MAP_NAME fd_notar_blk 82 0 : #define MAP_T fd_notar_blk_t 83 0 : #define MAP_KEY slot 84 : #define MAP_MEMOIZE 0 85 : #include "../../util/tmpl/fd_map_dynamic.c" 86 : 87 : struct __attribute__((aligned(128UL))) fd_notar { 88 : fd_notar_blk_t * blks; 89 : fd_notar_vtr_t * vtrs; 90 : ulong root; /* current root slot */ 91 : ulong stake; /* total stake in the current epoch */ 92 : }; 93 : typedef struct fd_notar fd_notar_t; 94 : 95 : /* fd_notar_{align,footprint} return the required alignment and 96 : footprint of a memory region suitable for use as a notar. align 97 : returns FD_NOTAR_ALIGN. footprint returns FD_NOTAR_FOOTPRINT. */ 98 : 99 : FD_FN_CONST static inline ulong 100 0 : fd_notar_align( void ) { 101 0 : return alignof(fd_notar_t); 102 0 : } 103 : 104 : FD_FN_CONST static inline ulong 105 0 : fd_notar_footprint( ulong blk_max ) { 106 0 : int lg_blk_max = fd_ulong_find_msb( fd_ulong_pow2_up( blk_max ) ); 107 0 : int lg_vtr_max = fd_ulong_find_msb( fd_ulong_pow2_up( FD_VOTER_MAX ) ); 108 0 : return FD_LAYOUT_FINI( 109 0 : FD_LAYOUT_APPEND( 110 0 : FD_LAYOUT_APPEND( 111 0 : FD_LAYOUT_APPEND( 112 0 : FD_LAYOUT_INIT, 113 0 : alignof(fd_notar_t), sizeof(fd_notar_t) ), 114 0 : fd_notar_blk_align(), fd_notar_blk_footprint( lg_blk_max ) ), 115 0 : fd_notar_vtr_align(), fd_notar_vtr_footprint( lg_vtr_max ) ), 116 0 : fd_notar_align() ); 117 0 : } 118 : 119 : /* fd_notar_new formats an unused memory region for use as a notar. mem 120 : is a non-NULL pointer to this region in the local address space with 121 : the required footprint and alignment. */ 122 : 123 : void * 124 : fd_notar_new( void * mem, ulong blk_max ); 125 : 126 : /* fd_notar_join joins the caller to the notar. notar points to the 127 : first byte of the memory region backing the notar in the caller's 128 : address space. 129 : 130 : Returns a pointer in the local address space to notar on success. */ 131 : 132 : fd_notar_t * 133 : fd_notar_join( void * notar ); 134 : 135 : /* fd_notar_leave leaves a current local join. Returns a pointer to the 136 : underlying shared memory region on success and NULL on failure (logs 137 : details). Reasons for failure include notar is NULL. */ 138 : 139 : void * 140 : fd_notar_leave( fd_notar_t const * notar ); 141 : 142 : /* fd_notar_delete unformats a memory region used as a notar. Assumes 143 : only the local process is joined to the region. Returns a pointer to 144 : the underlying shared memory region or NULL if used obviously in 145 : error (e.g. notar is obviously not a notar ... logs details). The 146 : ownership of the memory region is transferred to the caller. */ 147 : 148 : void * 149 : fd_notar_delete( void * notar ); 150 : 151 : /* fd_notar_vote updates notar with a "vote" which is a 4-tuple of 152 : (pubkey, stake, tower, hash). pubkey is the voter's validator 153 : identity, stake is the voter's stake in the current epoch, vote_tower 154 : is the parsed tower from either the gossip vote transaction or replay 155 : vote state, and vote_hash is the voter's bank hash for the last slot 156 : in the tower. */ 157 : 158 : void 159 : fd_notar_vote( fd_notar_t * notar, 160 : fd_pubkey_t const * pubkey, 161 : ulong stake, 162 : fd_tower_t const * vote_tower, 163 : fd_hash_t const * vote_hash ); 164 : 165 : /* fd_notar_publish publishes root as the new notar root slot, removing 166 : all blocks with slot numbers < the old notar root slot. Some slots 167 : on minority forks that were pruned but > than the new root may remain 168 : but they will eventually be pruned as well as the root advances. */ 169 : 170 : void 171 : fd_notar_publish( fd_notar_t * notar, 172 : ulong root ); 173 : 174 : #endif /* HEADER_fd_src_choreo_notar_fd_notar_h */