Line data Source code
1 : #ifndef HEADER_fd_src_choreo_voter_fd_voter_h 2 : #define HEADER_fd_src_choreo_voter_fd_voter_h 3 : 4 : /* fd_voter provides APIs for zero-copy serializing and deserializing 5 : on-chain vote accounts. Vote accounts contain "vote states" which 6 : store a voter's metadata and tower. */ 7 : 8 : #include "../fd_choreo_base.h" 9 : 10 : /* FD_VOTER_USE_HANDHOLDING: Define this to non-zero at compile time 11 : to turn on additional runtime checks and logging. */ 12 : 13 : #ifndef FD_VOTER_USE_HANDHOLDING 14 : #define FD_VOTER_USE_HANDHOLDING 1 15 : #endif 16 : 17 0 : #define FD_VOTER_V2 (1) 18 0 : #define FD_VOTER_V3 (2) 19 : FD_STATIC_ASSERT( FD_VOTER_V2==fd_vote_state_versioned_enum_v1_14_11, FD_VOTER_V2 ); 20 : FD_STATIC_ASSERT( FD_VOTER_V3==fd_vote_state_versioned_enum_current, FD_VOTER_V3 ); 21 : 22 : /* fd_voter describes the layout of a vote state stored in a vote 23 : account. These structs are used to support zero-copy access (direct 24 : casts) of byte arrays containing the vote account data. 25 : 26 : fd_voter is versioned, and the serialized formats differ depending on 27 : this. They correspond to Agave's VoteState0_23_5, VoteState1_14_11 28 : and VoteState structs. 29 : 30 : VoteStatev0_23_5 is deprecated and there are no longer vote accounts 31 : of that version on testnet / mainnet. VoteState1_14_11 corresponds 32 : to FD_VOTER_V2 and VoteState corresponds to FD_VOTER_V3. The only 33 : difference between the two is the votes in V3 contain an additional 34 : uchar field `latency`. 35 : 36 : The binary layout begins with metadata in the vote account, followed by the voter's votes (tower), and terminates with the root. */ 37 : struct __attribute__((packed)) fd_voter { 38 : uint kind; 39 : fd_pubkey_t node_pubkey; 40 : fd_pubkey_t authorized_withdrawer; 41 : uchar commission; 42 : ulong votes_cnt; 43 : union { 44 : struct __attribute__((packed)) { 45 : ulong slot; 46 : uint conf; 47 : } votes_v2[31]; /* variable-length */ 48 : struct __attribute__((packed)) { 49 : uchar latency; 50 : ulong slot; 51 : uint conf; 52 : } votes_v3[31]; /* variable-length */ 53 : /* uchar root_option */ 54 : /* ulong root */ 55 : }; 56 : }; 57 : typedef struct fd_voter fd_voter_t; 58 : 59 : /* fd_voter_vote_slot takes a voter's vote account data and returns the 60 : voter's most recent vote slot in the tower. Returns ULONG_MAX if 61 : they have an empty tower. */ 62 : 63 : static inline ulong 64 0 : fd_voter_vote_slot( uchar const * vote_account_data ) { 65 0 : fd_voter_t const * voter = (fd_voter_t const *)fd_type_pun_const( vote_account_data ); 66 0 : ulong cnt = voter->votes_cnt; 67 0 : switch( voter->kind ) { 68 0 : case FD_VOTER_V3: return cnt ? voter->votes_v3[cnt-1].slot : ULONG_MAX; 69 0 : case FD_VOTER_V2: return cnt ? voter->votes_v2[cnt-1].slot : ULONG_MAX; 70 0 : default: FD_LOG_HEXDUMP_CRIT(( "bad voter %u", vote_account_data, 3762 )); 71 0 : } 72 0 : } 73 : 74 : /* fd_voter_root_slot takes a voter's vote account data and returns the 75 : voter's root slot. Returns ULONG_MAX if they don't have a root. */ 76 : 77 : static inline ulong 78 0 : fd_voter_root_slot( uchar const * vote_account_data ) { 79 0 : fd_voter_t const * voter = (fd_voter_t const *)fd_type_pun_const( vote_account_data ); 80 0 : ulong cnt = voter->votes_cnt; 81 0 : switch( voter->kind ) { 82 0 : case FD_VOTER_V3: { uchar root_option = fd_uchar_load_1_fast( (uchar *)&voter->votes_v3[cnt] ); return root_option ? fd_ulong_load_8_fast( (uchar *)&voter->votes_v3[cnt] ) : ULONG_MAX; } 83 0 : case FD_VOTER_V2: { uchar root_option = fd_uchar_load_1_fast( (uchar *)&voter->votes_v2[cnt] ); return root_option ? fd_ulong_load_8_fast( (uchar *)&voter->votes_v2[cnt] ) : ULONG_MAX; } 84 0 : default: FD_LOG_CRIT(( "unhandled kind %u", voter->kind )); 85 0 : } 86 0 : } 87 : 88 : #endif /* HEADER_fd_src_choreo_voter_fd_voter_h */