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 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 } 84 : 85 : struct fd_tower_slot_confirmed { 86 : int level; /* the confirmation level, see FD_TOWER_SLOT_CONFIRMED_{...} above */ 87 : 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 */ 88 : ulong slot; /* slot being confirmed (in general, a slot being confirmed more than once is possible but highly unlikely ) */ 89 : fd_hash_t block_id; /* block id being confirmed (guaranteed unique) */ 90 : }; 91 : typedef struct fd_tower_slot_confirmed fd_tower_slot_confirmed_t; 92 : 93 : /* In response to finishing replay of a slot, the tower tile will 94 : produce both a block to vote for and block to reset to, and 95 : potentially advance the root. */ 96 : 97 : struct fd_tower_slot_done { 98 : 99 : /* This tower_slot_done message is 1-to-1 with the completion of a 100 : replayed slot. When that slot was done, the bank_idx was sent to 101 : tower, which tower used to query the bank and populate the vote 102 : accounts. Tower needs to send back the bank_idx to replay so it 103 : can decrement the reference count on the bank. */ 104 : 105 : ulong replay_slot; 106 : ulong replay_bank_idx; 107 : 108 : /* The slot being voted on. There is not always a vote slot (locked 109 : out, failed switch threshhold, etc.) and will be set to ULONG_MAX 110 : when there is no slot to vote on. When set, the vote slot is used 111 : by the vote sending tile to do some internal book-keeping related 112 : to leader targeting. */ 113 : 114 : ulong vote_slot; 115 : 116 : /* The slot to reset leader pipeline to. Unlike vote slot, the reset 117 : slot is always set and represents the consensus fork to build on. 118 : It may be unchanged since the last slot done. reset_block_id is 119 : a unique identifier in case there are multiple blocks for the reset 120 : slot due to equivocation. */ 121 : 122 : ulong reset_slot; 123 : fd_hash_t reset_block_id; 124 : 125 : /* Sometimes, finishing replay of a slot may cause a new slot to be 126 : rooted. If this happens, new root will be 1 and both root_slot and 127 : root_block_id will be set to the new root values accordingly. 128 : Otherwise, new_root will be 0 and root_slot and root_block_id will 129 : be undefined. Note it is possible tower emits a new root slot but 130 : the new root slot's block_id is unavailable (eg. it is an old tower 131 : vote that precedes the snapshot slot). In this case new_root will 132 : _not_ be set to 1. */ 133 : 134 : ulong root_slot; 135 : fd_hash_t root_block_id; 136 : 137 : /* The number of leaves in the forks tree. */ 138 : 139 : ulong active_fork_cnt; 140 : 141 : /* This always contains a vote transaction with our current tower, 142 : regardless of whether there is a new vote slot or not (ie. vote 143 : slot can be ULONG_MAX and vote_txn will contain a txn of our 144 : current tower). The vote is not yet signed. This is necessary to 145 : support refreshing our last vote, ie. we retransmit our vote even 146 : when we are locked out / can't switch vote forks. If the vote 147 : account's authorized voter is either the identity or one of the 148 : authorized voters, then is_valid_vote will be 1; otherwise it will 149 : be 0. 150 : 151 : The authority_idx is the index of the authorized voter that needs 152 : to sign the vote transaction. If the authorized voter is the 153 : identity, the authority_idx will be ULONG_MAX. 154 : 155 : TODO: Need to implement "refresh last vote" logic. */ 156 : 157 : int has_vote_txn; 158 : ulong authority_idx; 159 : ulong vote_txn_sz; 160 : uchar vote_txn[ FD_TPU_MTU ]; 161 : 162 : /* The latest balance in lamports of our vote account, or ULONG_MAX if 163 : our account is not found. */ 164 : 165 : ulong vote_acct_bal; 166 : 167 : /* Our current on-chain tower with latencies optionally included. */ 168 : 169 : ulong tower_cnt; 170 : fd_vote_acc_vote_t tower[FD_TOWER_VOTE_MAX]; 171 : }; 172 : typedef struct fd_tower_slot_done fd_tower_slot_done_t; 173 : 174 : struct fd_tower_slot_duplicate { 175 : fd_gossip_duplicate_shred_t chunks[ FD_EQVOC_CHUNK_CNT ]; 176 : }; 177 : typedef struct fd_tower_slot_duplicate fd_tower_slot_duplicate_t; 178 : 179 : struct fd_tower_slot_ignored { 180 : ulong slot; 181 : ulong bank_idx; 182 : }; 183 : typedef struct fd_tower_slot_ignored fd_tower_slot_ignored_t; 184 : 185 : union fd_tower_msg { 186 : fd_tower_slot_confirmed_t slot_confirmed; 187 : fd_tower_slot_done_t slot_done; 188 : fd_tower_slot_duplicate_t slot_duplicate; 189 : fd_tower_slot_ignored_t slot_ignored; 190 : fd_tower_slot_rooted_t slot_rooted; 191 : }; 192 : typedef union fd_tower_msg fd_tower_msg_t; 193 : 194 : extern fd_topo_run_tile_t fd_tile_tower; 195 : 196 : /* The danger of the circular reliable link between tower and replay is 197 : that if tower backpressures replay, and happens to have backed-up 198 : confirmations to publish in after_credit, then tower_out link will 199 : become full. If tower doesn't drain from replay_exec in the next 200 : returnable_frag call, this will cause a credit starvation loop 201 : between tower and replay, which causes both tiles to stall 202 : completely. 203 : 204 : Since there's no way to guarantee tower read from a specific link, 205 : (and no way to guarantee replay will read from a specific link), so 206 : we just make sure tower_out is large enough that the likelihood that 207 : the link is close to full and the above scenario happens is low. */ 208 : 209 : #endif /* HEADER_fd_src_discof_tower_fd_tower_tile_h */