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 "../../disco/topo/fd_topo.h" 5 : 6 0 : #define FD_TOWER_SIG_SLOT_DONE (0) 7 0 : #define FD_TOWER_SIG_SLOT_CONFIRMED (1) 8 : 9 : /* In response to finishing replay of a slot, the tower tile will 10 : produce both a block to vote for and block to reset to, and 11 : potentially advance the root. */ 12 : 13 : struct fd_tower_slot_done { 14 : 15 : /* The completed replay slot which triggered this message */ 16 : 17 : ulong replay_slot; 18 : 19 : /* The slot being voted on. There is not always a vote slot (locked 20 : out, failed switch threshhold, etc.) and will be set to ULONG_MAX 21 : when there is no slot to vote on. When set, the vote slot is used 22 : by the vote sending tile to do some internal book-keeping related 23 : to leader targeting. */ 24 : 25 : ulong vote_slot; 26 : 27 : /* The slot to reset leader pipeline to. Unlike vote slot, the reset 28 : slot is always set and represents the consensus fork to build on. 29 : It may be unchanged since the last slot done. reset_block_id is 30 : a unique identifier in case there are multiple blocks for the reset 31 : slot due to equivocation. */ 32 : 33 : ulong reset_slot; 34 : fd_hash_t reset_block_id; 35 : 36 : /* Sometimes, finishing replay of a slot may cause a new slot to be 37 : rooted. If this happens, new root will be 1 and both root_slot and 38 : root_block_id will be set to the new root values accordingly. 39 : Otherwise, new_root will be 0 and root_slot and root_block_id will 40 : be undefined. Note it is possible tower emits a new root slot but 41 : the new root slot's block_id is unavailable (eg. it is an old tower 42 : vote that precedes the snapshot slot). In this case new_root will 43 : _not_ be set to 1. */ 44 : 45 : ulong root_slot; 46 : fd_hash_t root_block_id; 47 : 48 : /* The number of leaves in the forks tree. */ 49 : ulong active_fork_cnt; 50 : 51 : /* This tower_slot_done message is 1-to-1 with the completion of a 52 : replayed slot. When that slot was done, the bank_idx was sent to 53 : tower, which tower used to query the bank and populate the vote 54 : accounts. Tower needs to send back the bank_idx to replay so it 55 : can decrement the reference count on the bank. */ 56 : 57 : ulong replay_bank_idx; 58 : 59 : /* This always contains a vote transaction with our current tower, 60 : regardless of whether there is a new vote slot or not (ie. vote 61 : slot can be ULONG_MAX and vote_txn will contain a txn of our 62 : current tower). The vote is not yet signed. This is necessary to 63 : support refreshing our last vote, ie. we retransmit our vote even 64 : when we are locked out / can't switch vote forks. 65 : 66 : TODO: Need to implement "refresh last vote" logic. */ 67 : 68 : ulong vote_txn_sz; 69 : uchar vote_txn[ FD_TPU_MTU ]; 70 : }; 71 : typedef struct fd_tower_slot_done fd_tower_slot_done_t; 72 : 73 : /* fd_tower_slot_confirmed provides confirmed notifications of different 74 : Solana confirmation levels. The levels are: 75 : 76 : - duplicate: a block is duplicate confirmed if it has received votes 77 : from at least 52% of stake in the cluster. 78 : 79 : - optimistic: a block is optimistically confirmed if it has received 80 : votes from at least 2/3 of stake in the cluster and we have already 81 : replayed it (bank is available). 82 : 83 : - cluster: same as optimistic, but may not have replayed / can be 84 : delivered out of order. 85 : 86 : - rooted: a block is rooted if it or any of its descendants reach max 87 : lockout per TowerBFT rules. 88 : 89 : For optimistic and rooted confirmations, the tower tile guarantees 90 : that we have already replayed the block. This is not the case for 91 : duplicate and cluster confirmations (a block can get duplicate or 92 : cluster confirmed before it has been replayed). Optimistic and 93 : rooted confirmations are also guaranteed to be delivered in-order 94 : with no gaps from tower. That is, if we receive a rooted frag for 95 : slot N, we will have already received rooted frags for any ancestor 96 : slots N - 1, N - 2, ... (if they are not skipped / on a different 97 : fork) and likewise for optimistic. 98 : 99 : Note even if tower never actually voted on a slot (and therefore the 100 : slot never became a tower root), tower will still send a rooted 101 : confirmation for that slot if a descendant is voted on and eventually 102 : rooted. 103 : 104 : The reason both optimistic and cluster confirmed exist is "cluster" 105 : is intended to be consumed by the Solana RPC protocol, whereas 106 : optimistic is intended for Firedancer-specific APIs (hence in-order 107 : and no gap guarantees) */ 108 : 109 0 : #define FD_TOWER_SLOT_CONFIRMED_DUPLICATE 0 110 0 : #define FD_TOWER_SLOT_CONFIRMED_OPTIMISTIC 1 111 0 : #define FD_TOWER_SLOT_CONFIRMED_CLUSTER 2 112 0 : #define FD_TOWER_SLOT_CONFIRMED_ROOTED 3 113 : 114 : struct fd_tower_slot_confirmed { 115 : ulong slot; 116 : fd_hash_t block_id; 117 : ulong bank_idx; /* only valid for OPTIMISTIC or ROOTED kind (otherwise ULONG_MAX) */ 118 : int kind; 119 : }; 120 : typedef struct fd_tower_slot_confirmed fd_tower_slot_confirmed_t; 121 : 122 : union fd_tower_msg { 123 : fd_tower_slot_done_t slot_done; 124 : fd_tower_slot_confirmed_t slot_confirmed; 125 : }; 126 : typedef union fd_tower_msg fd_tower_msg_t; 127 : 128 : extern fd_topo_run_tile_t fd_tile_tower; 129 : 130 : #endif /* HEADER_fd_src_discof_tower_fd_tower_tile_h */