Line data Source code
1 : #ifndef HEADER_fd_src_discof_tower_fd_tower_tile_h 2 : #define HEADER_fd_src_discof_tower_fd_tower_tile_h 3 : 4 : #include "fd_tower_slot_rooted.h" 5 : #include "../../choreo/eqvoc/fd_eqvoc.h" 6 : #include "../../choreo/tower/fd_tower.h" 7 : #include "../../choreo/tower/fd_tower_serdes.h" 8 : #include "../../disco/topo/fd_topo.h" 9 : 10 0 : #define FD_TOWER_SIG_SLOT_CONFIRMED (0) 11 0 : #define FD_TOWER_SIG_SLOT_DONE (1) 12 0 : #define FD_TOWER_SIG_SLOT_DUPLICATE (2) 13 0 : #define FD_TOWER_SIG_SLOT_IGNORED (3) 14 : // #define FD_TOWER_SIG_SLOT_ROOTED (4) /* defined in fd_tower_slot_rooted.h */ 15 : 16 : /* fd_tower_slot_confirmed describes a Tower frag that notifies protocol 17 : confirmations. There are multiple confirmation levels: 18 : 19 : - propagation confirmed: a block is propagated if it has received 20 : votes from at least 1/3 of stake in the cluster. This threshold is 21 : important in two contexts: 22 : 23 : 1. When becoming leader, we need to check that our previous leader 24 : block _as of_ the parent slot we're building on, has propagated. 25 : If it has not propagated, we need to instead retransmit our last 26 : block that failed to propagate. The protocol currently allows 27 : for a grace period of one leader rotation for leader blocks to 28 : propagate. 29 : 30 : 2. When voting, we need to check our previous leader block _as of_ 31 : the slot we're voting for has propagated (unless we're voting 32 : for one of our own leader blocks). We cannot vote for a slot in 33 : which our last ancestor leader block failed to propagate. 34 : 35 : - duplicate confirmed: a block is duplicate confirmed if it has 36 : received votes from at least 52% of stake in the cluster. The 37 : "duplicate" adjective is a bit of a misnomer, and a more accurate 38 : technical term is equivocation: two (or more) different blocks for 39 : the same slot. This threshold is important for consensus safety, 40 : because it ensures Solana eventually converges to the same block 41 : per slot. Specifically fork choice allows choosing a fork if it is 42 : duplicate confirmed, even if there is equivocation. 43 : 44 : - optimistically confirmed: a block is optimistically confirmed if it 45 : has received votes from at least 2/3 of stake in the cluster. This 46 : threshold is important for end-users, who rely on the "confirmed" 47 : commitment status of blocks (queryable via RPC) to determine that 48 : their transaction has landed on a block that will not rollback. 49 : This is unimplemented in Firedancer and only relevant for RPC. 50 : (TODO verify this?) 51 : 52 : - super confirmed: same as optimistic, but the stake threshold is 4/5 53 : of stake. This is used during boot for `--wait-for-supermajority`. 54 : 55 : It's possible Firedancer reaches a confirmation level before the 56 : block has actually been replayed. Firedancer listens to votes from 57 : both Gossip and TPU, so if a given block id has received enough votes 58 : it might get "forward-confirmed". 59 : 60 : Tower will also notify of forward confirmations, denoted by the `fwd` 61 : field on the fd_tower_slot_confirmed frag. Forward confirmations are 62 : only for the given block, and do not imply the ancestry chain leading 63 : up to the block are also confirmed. This is distinct from replay 64 : confirmations, which are only emitted after replaying a block (`fwd` 65 : = 0), and imply the ancestry chain up from that block is also 66 : confirmed. Forward confirmations are needed for both repair (in case 67 : we never got the block over Turbine) and for RPC (since RPC needs to 68 : know about confirmations even if replay is behind). 69 : 70 : Other guarantees include that the confirmation frags with `fwd` = 0 71 : are delivered in-order with no gaps from tower (there still might be 72 : skipped slots, but no gaps means you will always receive an ancestor 73 : block's confirmation before its descendants). That is, if a consumer 74 : receives a confirmation frag for slot N, it will have prior received 75 : confirmations for all ancestor slots N - 1, N - 2, ... (if they are 76 : not skipped / on a different fork). */ 77 : 78 0 : #define FD_TOWER_SLOT_CONFIRMED_PROPAGATED (0) 79 0 : #define FD_TOWER_SLOT_CONFIRMED_DUPLICATE (1) 80 0 : #define FD_TOWER_SLOT_CONFIRMED_OPTIMISTIC (2) 81 0 : #define FD_TOWER_SLOT_CONFIRMED_SUPER (3) 82 0 : #define FD_TOWER_SLOT_CONFIRMED_LEVEL_CNT (4) 83 : #define FD_TOWER_SLOT_CONFIRMED_RATIO_CNT FD_TOWER_SLOT_CONFIRMED_LEVEL_CNT 84 0 : #define FD_TOWER_SLOT_CONFIRMED_LEVELS { FD_TOWER_SLOT_CONFIRMED_PROPAGATED, FD_TOWER_SLOT_CONFIRMED_DUPLICATE, FD_TOWER_SLOT_CONFIRMED_OPTIMISTIC, FD_TOWER_SLOT_CONFIRMED_SUPER } 85 0 : #define FD_TOWER_SLOT_CONFIRMED_RATIOS { 1.0/3, 0.52, 2.0/3, 4.0/5 } 86 : 87 : struct fd_tower_slot_confirmed { 88 : int level; /* the confirmation level, see FD_TOWER_SLOT_CONFIRMED_{...} above */ 89 : int fwd; /* whether this is a "forward confirmation" ie. we have not yet replayed but the slot is confirmed based on gossip and TPU votes */ 90 : ulong slot; /* slot being confirmed (in general, a slot being confirmed more than once is possible but highly unlikely ) */ 91 : fd_hash_t block_id; /* block id being confirmed (guaranteed unique) */ 92 : }; 93 : typedef struct fd_tower_slot_confirmed fd_tower_slot_confirmed_t; 94 : 95 : /* In response to finishing replay of a slot, the tower tile will 96 : produce both a block to vote for and block to reset to, and 97 : potentially advance the root. */ 98 : 99 : struct fd_tower_slot_done { 100 : 101 : /* This tower_slot_done message is 1-to-1 with the completion of a 102 : replayed slot. When that slot was done, the bank_idx was sent to 103 : tower, which tower used to query the bank and populate the vote 104 : accounts. Tower needs to send back the bank_idx to replay so it 105 : can decrement the reference count on the bank. */ 106 : 107 : ulong replay_slot; 108 : ulong replay_bank_idx; 109 : 110 : /* The slot being voted on. There is not always a vote slot (locked 111 : out, failed switch threshhold, etc.) and will be set to ULONG_MAX 112 : when there is no slot to vote on. When set, the vote slot is used 113 : by the vote sending tile to do some internal book-keeping related 114 : to leader targeting. */ 115 : 116 : ulong vote_slot; 117 : 118 : /* The slot to reset leader pipeline to. Unlike vote slot, the reset 119 : slot is always set and represents the consensus fork to build on. 120 : It may be unchanged since the last slot done. reset_block_id is 121 : a unique identifier in case there are multiple blocks for the reset 122 : slot due to equivocation. */ 123 : 124 : ulong reset_slot; 125 : fd_hash_t reset_block_id; 126 : 127 : /* Sometimes, finishing replay of a slot may cause a new slot to be 128 : rooted. If this happens, new root will be 1 and both root_slot and 129 : root_block_id will be set to the new root values accordingly. 130 : Otherwise, new_root will be 0 and root_slot and root_block_id will 131 : be undefined. Note it is possible tower emits a new root slot but 132 : the new root slot's block_id is unavailable (eg. it is an old tower 133 : vote that precedes the snapshot slot). In this case new_root will 134 : _not_ be set to 1. */ 135 : 136 : ulong root_slot; 137 : fd_hash_t root_block_id; 138 : 139 : /* The number of leaves in the forks tree. */ 140 : 141 : ulong active_fork_cnt; 142 : 143 : /* This always contains a vote transaction with our current tower, 144 : regardless of whether there is a new vote slot or not (ie. vote 145 : slot can be ULONG_MAX and vote_txn will contain a txn of our 146 : current tower). The vote is not yet signed. This is necessary to 147 : support refreshing our last vote, ie. we retransmit our vote even 148 : when we are locked out / can't switch vote forks. If the vote 149 : account's authorized voter is either the identity or one of the 150 : authorized voters, then is_valid_vote will be 1; otherwise it will 151 : be 0. 152 : 153 : The authority_idx is the index of the authorized voter that needs 154 : to sign the vote transaction. If the authorized voter is the 155 : identity, the authority_idx will be ULONG_MAX. 156 : 157 : TODO: Need to implement "refresh last vote" logic. */ 158 : 159 : int has_vote_txn; 160 : ulong authority_idx; 161 : ulong vote_txn_sz; 162 : uchar vote_txn[ FD_TPU_MTU ]; 163 : 164 : /* The latest balance in lamports of our vote account, or ULONG_MAX if 165 : our account is not found. */ 166 : 167 : ulong vote_acct_bal; 168 : 169 : /* Our current on-chain tower with latencies optionally included. */ 170 : 171 : ulong tower_cnt; 172 : fd_vote_acc_vote_t tower[FD_TOWER_VOTE_MAX]; 173 : }; 174 : typedef struct fd_tower_slot_done fd_tower_slot_done_t; 175 : 176 : struct fd_tower_slot_duplicate { 177 : fd_gossip_duplicate_shred_t chunks[ FD_EQVOC_CHUNK_CNT ]; 178 : }; 179 : typedef struct fd_tower_slot_duplicate fd_tower_slot_duplicate_t; 180 : 181 : struct fd_tower_slot_ignored { 182 : ulong slot; 183 : ulong bank_idx; 184 : }; 185 : typedef struct fd_tower_slot_ignored fd_tower_slot_ignored_t; 186 : 187 : union fd_tower_msg { 188 : fd_tower_slot_confirmed_t slot_confirmed; 189 : fd_tower_slot_done_t slot_done; 190 : fd_tower_slot_duplicate_t slot_duplicate; 191 : fd_tower_slot_ignored_t slot_ignored; 192 : fd_tower_slot_rooted_t slot_rooted; 193 : }; 194 : typedef union fd_tower_msg fd_tower_msg_t; 195 : 196 : extern fd_topo_run_tile_t fd_tile_tower; 197 : 198 : /* The danger of the circular reliable link between tower and replay is 199 : that if tower backpressures replay, and happens to have backed-up 200 : confirmations to publish in after_credit, then tower_out link will 201 : become full. If tower doesn't drain from replay_exec in the next 202 : returnable_frag call, this will cause a credit starvation loop 203 : between tower and replay, which causes both tiles to stall 204 : completely. 205 : 206 : Since there's no way to guarantee tower read from a specific link, 207 : (and no way to guarantee replay will read from a specific link), so 208 : we just make sure tower_out is large enough that the likelihood that 209 : the link is close to full and the above scenario happens is low. */ 210 : 211 : #endif /* HEADER_fd_src_discof_tower_fd_tower_tile_h */