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 : #include "../fd_choreo_base.h" 5 : #include "../../funk/fd_funk_rec.h" 6 : 7 : /* A fd_voter_t describes a voter. The voter is generic to the context 8 : in which it is used, eg. it might be a voter in a slot-level context 9 : in which its stake value may be different from the same voter in an 10 : epoch-level context which in turn is different from the same voter in 11 : the prior epoch's context. 12 : 13 : The voter is used by various choreo APIs including fd_epoch which 14 : tracks all the voters in a given epoch, fd_forks which performs 15 : choreo-related fork updates after replaying a slot, and ghost and 16 : tower which both require bookkeeping the epoch voters. */ 17 : 18 : struct fd_voter { 19 : union { 20 : fd_pubkey_t key; /* vote account address */ 21 : fd_funk_rec_key_t rec; /* funk record key to query above */ 22 : }; 23 : uint hash; /* reserved for fd_map_dynamic.c */ 24 : 25 : /* IMPORTANT! The values below should only be modified by fd_epoch and 26 : fd_ghost. */ 27 : 28 : ulong stake; /* voter's stake */ 29 : ulong replay_vote; /* cached read of last tower vote via replay */ 30 : ulong gossip_vote; /* cached read of last tower vote via gossip */ 31 : ulong rooted_vote; /* cached read of last tower root via replay */ 32 : }; 33 : typedef struct fd_voter fd_voter_t; 34 : 35 : /* fd_voter_state is a struct representation of the bincode-serialized 36 : layout of a voter's state (known in Agave parlance as "VoteState"). 37 : This struct is then used to support zero-copy access of members. 38 : 39 : The voter's state is versioned, and the serialized formats differ 40 : depending on this. Currently, the only version that differs from the 41 : others that is relevant here is v0.23.5. Thus v0.23.5 has its own 42 : dedicated struct definition with a different set of fields that 43 : precede the votes than the other versions. Furthermore, v0.23.5 44 : contains votes of type `fd_vote_lockout_t` vs. the other versions 45 : which are of type `fd_landed_vote_t`. The only difference between 46 : `fd_vote_lockout_t` and `fd_landed_vote_t` is there is an additional 47 : uchar field `latency`, so that is we include an offset of 0 or 1 48 : depending on which vote state type it is. 49 : 50 : The layout begins with a set of fields providing important metadata 51 : about the voter. Immediately following these fields is the tower 52 : itself. The tower layout begins with the number of votes currently in 53 : the tower ie. `cnt`. Then the votes themselves follow. The format of 54 : the votes varies depending on the version. Finally the layout 55 : concludes with the tower's root slot. 56 : 57 : -------- 58 : metadata <- variable. depends on vote state version 59 : -------- 60 : cnt <- 8 bytes. bincode-serialized u64 61 : -------- 62 : votes <- variable. depends on vote state version and cnt 63 : -------- 64 : root <- 5 or 1 byte(s). bincode-serialized Option<u64> 65 : -------- 66 : */ 67 : 68 : struct __attribute__((packed)) fd_voter_state { 69 : uint discriminant; 70 : union { 71 : struct __attribute__((packed)) { 72 : fd_pubkey_t node_pubkey; 73 : fd_pubkey_t authorized_voter; 74 : ulong authorized_voter_epoch; 75 : uchar prior_voters[ (32*56+sizeof(ulong)) /* serialized bincode sz */ ]; 76 : fd_pubkey_t authorized_withdrawer; 77 : uchar commission; 78 : struct __attribute__((packed)) fd_voter_state_tower_v0_23_5 { 79 : ulong cnt; 80 : struct __attribute__((packed)) fd_voter_state_tower_vote_v0_23_5 { 81 : ulong slot; 82 : uint conf; 83 : } votes[32]; /* only first `cnt` elements are valid */ 84 : } tower; 85 : } v0_23_5; 86 : 87 : struct __attribute__((packed)) { 88 : fd_pubkey_t node_pubkey; 89 : fd_pubkey_t authorized_withdrawer; 90 : uchar commission; 91 : struct __attribute__((packed)) fd_voter_state_tower { 92 : ulong cnt; 93 : struct __attribute__((packed)) fd_voter_state_tower_vote { 94 : uchar latency; 95 : ulong slot; 96 : uint conf; 97 : } votes[32]; /* only first `cnt` elements are valid */ 98 : } tower; 99 : }; 100 : 101 : /* The tower's root (a bincode-serialized Option<u64>) follows 102 : votes. Because the preceding votes are variable-length in 103 : serialized form, we cannot encode the root directly inside the 104 : struct. */ 105 : }; 106 : }; 107 : typedef struct fd_voter_state_tower_vote_v0_23_5 fd_voter_state_tower_vote_v0_23_5_t; 108 : typedef struct fd_voter_state_tower_vote fd_voter_state_tower_vote_t; 109 : typedef struct fd_voter_state_tower_v0_23_5 fd_voter_state_tower_v0_23_5_t; 110 : typedef struct fd_voter_state_tower fd_voter_state_tower_t; 111 : typedef struct fd_voter_state fd_voter_state_t; 112 : 113 : /* fd_voter_state queries funk for the record in the provided `txn` and 114 : `key`. Returns a pointer to the start of the voter's state. Assumes 115 : `key` is a vote account address and the record is a voter's state 116 : (fd_voter_state_t). U.B. if `key` does not point to a valid vote 117 : account. */ 118 : 119 : fd_voter_state_t const * 120 : fd_voter_state( fd_funk_t * funk, fd_funk_txn_t const * txn, fd_funk_rec_key_t const * key ); 121 : 122 : /* fd_voter_state_cnt returns the number of votes in the voter's tower. 123 : Assumes `state` is a valid fd_voter_state_t. */ 124 : 125 : FD_FN_PURE static inline ulong 126 0 : fd_voter_state_cnt( fd_voter_state_t const * state ) { 127 0 : if( FD_UNLIKELY( state->discriminant == fd_vote_state_versioned_enum_v0_23_5 ) ) { 128 0 : return state->v0_23_5.tower.cnt; 129 0 : } 130 0 : return state->tower.cnt; 131 0 : } 132 : 133 : /* fd_voter_state_vote returns the voter's most recent vote (ie. the 134 : last vote of the tower in the voter's state). Assumes `state` is a 135 : valid fd_voter_state_t. */ 136 : 137 : FD_FN_PURE static inline ulong 138 0 : fd_voter_state_vote( fd_voter_state_t const * state ) { 139 0 : if( FD_UNLIKELY( !fd_voter_state_cnt( state ) ) ) return FD_SLOT_NULL; 140 0 : if( FD_UNLIKELY( state->discriminant == fd_vote_state_versioned_enum_v0_23_5 ) ) { 141 0 : return state->v0_23_5.tower.votes[state->tower.cnt - 1].slot; 142 0 : } 143 0 : return state->tower.votes[state->tower.cnt - 1].slot; 144 0 : } 145 : 146 : /* fd_voter_state_root returns the voter's tower root. Assumes `state` 147 : is a valid fd_voter_state_t. */ 148 : 149 : FD_FN_PURE static inline ulong 150 0 : fd_voter_state_root( fd_voter_state_t const * state ) { 151 0 : uchar * root = fd_ptr_if( 152 0 : state->discriminant == fd_vote_state_versioned_enum_v0_23_5, 153 0 : (uchar *)&state->v0_23_5.tower.votes + sizeof(fd_voter_state_tower_vote_v0_23_5_t) * state->v0_23_5.tower.cnt, 154 0 : (uchar *)&state->tower.votes + sizeof(fd_voter_state_tower_vote_t) * state->tower.cnt 155 0 : ); 156 0 : uchar is_some = *(uchar *)root; /* whether the Option is a Some type */ 157 0 : if( FD_UNLIKELY( !is_some ) ) return 0; /* the implicit root is the genesis slot */ 158 0 : return *(ulong *)(root+sizeof(uchar)); 159 0 : } 160 : 161 : #endif /* HEADER_fd_src_choreo_voter_fd_voter_h */