Skip to main content

solana_vote_interface/state/
vote_state_1_14_11.rs

1use super::*;
2#[cfg(feature = "dev-context-only-utils")]
3use arbitrary::Arbitrary;
4#[cfg(feature = "frozen-abi")]
5use solana_frozen_abi_macro::{frozen_abi, AbiExample, StableAbi, StableAbiSample};
6
7// Offset used for VoteState version 1_14_11
8const DEFAULT_PRIOR_VOTERS_OFFSET: usize = 82;
9
10#[cfg_attr(
11    feature = "frozen-abi",
12    frozen_abi(
13        api_digest = "2rjXSWaNeAdoUNJDC5otC7NPR1qXHvLMuAs5faE4DPEt",
14        abi_digest = "3zLH9BFk2HeY4UTTWY82p6z4v9gNyyGkH3qZYWeGP2Fw",
15        abi_serializer = ["bincode", "wincode"]
16    ),
17    derive(AbiExample, StableAbi, StableAbiSample)
18)]
19#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
20#[cfg_attr(feature = "wincode", derive(wincode::SchemaWrite, wincode::SchemaRead))]
21#[derive(Debug, Default, PartialEq, Eq, Clone)]
22#[cfg_attr(feature = "dev-context-only-utils", derive(Arbitrary))]
23pub struct VoteState1_14_11 {
24    /// the node that votes in this account
25    pub node_pubkey: Pubkey,
26
27    /// the signer for withdrawals
28    pub authorized_withdrawer: Pubkey,
29    /// percentage (0-100) that represents what part of a rewards
30    ///  payout should be given to this VoteAccount
31    pub commission: u8,
32
33    pub votes: VecDeque<Lockout>,
34
35    // This usually the last Lockout which was popped from self.votes.
36    // However, it can be arbitrary slot, when being used inside Tower
37    pub root_slot: Option<Slot>,
38
39    /// the signer for vote transactions
40    pub authorized_voters: AuthorizedVoters,
41
42    /// history of prior authorized voters and the epochs for which
43    /// they were set, the bottom end of the range is inclusive,
44    /// the top of the range is exclusive
45    pub prior_voters: CircBuf<(Pubkey, Epoch, Epoch)>,
46
47    /// history of how many credits earned by the end of each epoch
48    ///  each tuple is (Epoch, credits, prev_credits)
49    pub epoch_credits: Vec<(Epoch, u64, u64)>,
50
51    /// most recent timestamp submitted with a vote
52    pub last_timestamp: BlockTimestamp,
53}
54
55impl VoteState1_14_11 {
56    /// Upper limit on the size of the Vote State
57    /// when votes.len() is MAX_LOCKOUT_HISTORY.
58    pub fn size_of() -> usize {
59        3731 // see test_vote_state_size_of
60    }
61
62    pub fn is_uninitialized(&self) -> bool {
63        self.authorized_voters.is_empty()
64    }
65
66    pub fn is_correct_size_and_initialized(data: &[u8]) -> bool {
67        const VERSION_OFFSET: usize = 4;
68        const DEFAULT_PRIOR_VOTERS_END: usize = VERSION_OFFSET + DEFAULT_PRIOR_VOTERS_OFFSET;
69        data.len() == VoteState1_14_11::size_of()
70            && data[VERSION_OFFSET..DEFAULT_PRIOR_VOTERS_END] != [0; DEFAULT_PRIOR_VOTERS_OFFSET]
71    }
72}
73
74impl From<VoteStateV3> for VoteState1_14_11 {
75    fn from(vote_state: VoteStateV3) -> Self {
76        Self {
77            node_pubkey: vote_state.node_pubkey,
78            authorized_withdrawer: vote_state.authorized_withdrawer,
79            commission: vote_state.commission,
80            votes: vote_state
81                .votes
82                .into_iter()
83                .map(|landed_vote| landed_vote.into())
84                .collect(),
85            root_slot: vote_state.root_slot,
86            authorized_voters: vote_state.authorized_voters,
87            prior_voters: vote_state.prior_voters,
88            epoch_credits: vote_state.epoch_credits,
89            last_timestamp: vote_state.last_timestamp,
90        }
91    }
92}
93
94#[cfg(test)]
95mod tests {
96    use {super::*, arbitrary::Unstructured, core::mem::MaybeUninit};
97
98    #[test]
99    fn test_vote_deserialize_1_14_11() {
100        // base case
101        let target_vote_state = VoteState1_14_11::default();
102        let target_vote_state_versions = VoteStateVersions::V1_14_11(Box::new(target_vote_state));
103        let vote_state_buf = bincode::serialize(&target_vote_state_versions).unwrap();
104
105        // v3
106        let mut test_vote_state_v3 = MaybeUninit::uninit();
107        VoteStateV3::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state_v3).unwrap();
108        let test_vote_state = unsafe { test_vote_state_v3.assume_init() };
109
110        assert_eq!(
111            target_vote_state_versions
112                .clone()
113                .try_convert_to_v3()
114                .unwrap(),
115            test_vote_state
116        );
117
118        // v4
119        let vote_pubkey = Pubkey::new_unique();
120        let mut test_vote_state_v4 = MaybeUninit::uninit();
121        VoteStateV4::deserialize_into_uninit(
122            &vote_state_buf,
123            &mut test_vote_state_v4,
124            &vote_pubkey,
125        )
126        .unwrap();
127        let test_vote_state = unsafe { test_vote_state_v4.assume_init() };
128
129        assert_eq!(
130            target_vote_state_versions
131                .try_convert_to_v4(&vote_pubkey)
132                .unwrap(),
133            test_vote_state
134        );
135
136        // variant
137        // provide 4x the minimum struct size in bytes to ensure we typically touch every field
138        let struct_bytes_x4 = std::mem::size_of::<VoteState1_14_11>() * 4;
139        for _ in 0..1000 {
140            let raw_data: Vec<u8> = (0..struct_bytes_x4).map(|_| rand::random::<u8>()).collect();
141            let mut unstructured = Unstructured::new(&raw_data);
142
143            let arbitrary_vote_state = VoteState1_14_11::arbitrary(&mut unstructured).unwrap();
144            let target_vote_state_versions =
145                VoteStateVersions::V1_14_11(Box::new(arbitrary_vote_state));
146
147            // v3
148            let vote_state_buf = bincode::serialize(&target_vote_state_versions).unwrap();
149            let target_vote_state_v3 = target_vote_state_versions
150                .clone()
151                .try_convert_to_v3()
152                .unwrap();
153
154            let mut test_vote_state_v3 = MaybeUninit::uninit();
155            VoteStateV3::deserialize_into_uninit(&vote_state_buf, &mut test_vote_state_v3).unwrap();
156            let test_vote_state = unsafe { test_vote_state_v3.assume_init() };
157
158            assert_eq!(target_vote_state_v3, test_vote_state);
159
160            // v4
161            let vote_pubkey = Pubkey::new_unique();
162            let target_vote_state_v4 = target_vote_state_versions
163                .try_convert_to_v4(&vote_pubkey)
164                .unwrap();
165
166            let mut test_vote_state_v4 = MaybeUninit::uninit();
167            VoteStateV4::deserialize_into_uninit(
168                &vote_state_buf,
169                &mut test_vote_state_v4,
170                &vote_pubkey,
171            )
172            .unwrap();
173            let test_vote_state = unsafe { test_vote_state_v4.assume_init() };
174
175            assert_eq!(target_vote_state_v4, test_vote_state);
176        }
177    }
178}