atlas_vote_interface/state/
vote_state_versions.rs1#[cfg(test)]
2use arbitrary::{Arbitrary, Unstructured};
3use {
4 crate::{
5 authorized_voters::AuthorizedVoters,
6 state::{
7 vote_state_0_23_5::VoteState0_23_5, vote_state_1_14_11::VoteState1_14_11, CircBuf,
8 LandedVote, Lockout, VoteStateV3, VoteStateV4,
9 },
10 },
11 atlas_instruction::error::InstructionError,
12 atlas_pubkey::Pubkey,
13 std::collections::VecDeque,
14};
15
16#[cfg_attr(
17 feature = "serde",
18 derive(serde_derive::Deserialize, serde_derive::Serialize)
19)]
20#[derive(Debug, PartialEq, Eq, Clone)]
21pub enum VoteStateVersions {
22 V0_23_5(Box<VoteState0_23_5>),
23 V1_14_11(Box<VoteState1_14_11>),
24 V3(Box<VoteStateV3>),
25 V4(Box<VoteStateV4>),
26}
27
28impl VoteStateVersions {
29 pub fn new_v3(vote_state: VoteStateV3) -> Self {
30 Self::V3(Box::new(vote_state))
31 }
32
33 pub fn new_v4(vote_state: VoteStateV4) -> Self {
34 Self::V4(Box::new(vote_state))
35 }
36
37 pub fn try_convert_to_v3(self) -> Result<VoteStateV3, InstructionError> {
42 match self {
43 VoteStateVersions::V0_23_5(state) => {
44 let authorized_voters = if state.is_uninitialized() {
45 AuthorizedVoters::default()
46 } else {
47 AuthorizedVoters::new(state.authorized_voter_epoch, state.authorized_voter)
48 };
49
50 Ok(VoteStateV3 {
51 node_pubkey: state.node_pubkey,
52
53 authorized_withdrawer: state.authorized_withdrawer,
54
55 commission: state.commission,
56
57 votes: Self::landed_votes_from_lockouts(state.votes),
58
59 root_slot: state.root_slot,
60
61 authorized_voters,
62
63 prior_voters: CircBuf::default(),
64
65 epoch_credits: state.epoch_credits.clone(),
66
67 last_timestamp: state.last_timestamp.clone(),
68 })
69 }
70
71 VoteStateVersions::V1_14_11(state) => Ok(VoteStateV3 {
72 node_pubkey: state.node_pubkey,
73 authorized_withdrawer: state.authorized_withdrawer,
74 commission: state.commission,
75
76 votes: Self::landed_votes_from_lockouts(state.votes),
77
78 root_slot: state.root_slot,
79
80 authorized_voters: state.authorized_voters.clone(),
81
82 prior_voters: state.prior_voters,
83
84 epoch_credits: state.epoch_credits,
85
86 last_timestamp: state.last_timestamp,
87 }),
88
89 VoteStateVersions::V3(state) => Ok(*state),
90
91 VoteStateVersions::V4(_) => Err(InstructionError::InvalidArgument),
93 }
94 }
95
96 pub fn try_convert_to_v4(self, vote_pubkey: &Pubkey) -> Result<VoteStateV4, InstructionError> {
101 Ok(match self {
102 VoteStateVersions::V0_23_5(state) => {
103 let authorized_voters = if state.is_uninitialized() {
104 AuthorizedVoters::default()
105 } else {
106 AuthorizedVoters::new(state.authorized_voter_epoch, state.authorized_voter)
107 };
108
109 VoteStateV4 {
110 node_pubkey: state.node_pubkey,
111 authorized_withdrawer: state.authorized_withdrawer,
112 inflation_rewards_collector: *vote_pubkey,
113 block_revenue_collector: state.node_pubkey,
114 inflation_rewards_commission_bps: u16::from(state.commission)
115 .saturating_mul(100),
116 block_revenue_commission_bps: 10_000u16,
117 pending_delegator_rewards: 0,
118 bls_pubkey_compressed: None,
119 votes: Self::landed_votes_from_lockouts(state.votes),
120 root_slot: state.root_slot,
121 authorized_voters,
122 epoch_credits: state.epoch_credits.clone(),
123 last_timestamp: state.last_timestamp.clone(),
124 }
125 }
126
127 VoteStateVersions::V1_14_11(state) => VoteStateV4 {
128 node_pubkey: state.node_pubkey,
129 authorized_withdrawer: state.authorized_withdrawer,
130 inflation_rewards_collector: *vote_pubkey,
131 block_revenue_collector: state.node_pubkey,
132 inflation_rewards_commission_bps: u16::from(state.commission).saturating_mul(100),
133 block_revenue_commission_bps: 10_000u16,
134 pending_delegator_rewards: 0,
135 bls_pubkey_compressed: None,
136 votes: Self::landed_votes_from_lockouts(state.votes),
137 root_slot: state.root_slot,
138 authorized_voters: state.authorized_voters.clone(),
139 epoch_credits: state.epoch_credits,
140 last_timestamp: state.last_timestamp,
141 },
142
143 VoteStateVersions::V3(state) => VoteStateV4 {
144 node_pubkey: state.node_pubkey,
145 authorized_withdrawer: state.authorized_withdrawer,
146 inflation_rewards_collector: *vote_pubkey,
147 block_revenue_collector: state.node_pubkey,
148 inflation_rewards_commission_bps: u16::from(state.commission).saturating_mul(100),
149 block_revenue_commission_bps: 10_000u16,
150 pending_delegator_rewards: 0,
151 bls_pubkey_compressed: None,
152 votes: state.votes,
153 root_slot: state.root_slot,
154 authorized_voters: state.authorized_voters,
155 epoch_credits: state.epoch_credits,
156 last_timestamp: state.last_timestamp,
157 },
158
159 VoteStateVersions::V4(state) => *state,
160 })
161 }
162
163 fn landed_votes_from_lockouts(lockouts: VecDeque<Lockout>) -> VecDeque<LandedVote> {
164 lockouts.into_iter().map(|lockout| lockout.into()).collect()
165 }
166
167 pub fn is_uninitialized(&self) -> bool {
168 match self {
169 VoteStateVersions::V0_23_5(vote_state) => vote_state.is_uninitialized(),
170
171 VoteStateVersions::V1_14_11(vote_state) => vote_state.is_uninitialized(),
172
173 VoteStateVersions::V3(vote_state) => vote_state.is_uninitialized(),
174
175 VoteStateVersions::V4(_) => false,
177 }
178 }
179
180 pub fn is_correct_size_and_initialized(data: &[u8]) -> bool {
181 VoteStateV4::is_correct_size_and_initialized(data)
182 || VoteStateV3::is_correct_size_and_initialized(data)
183 || VoteState1_14_11::is_correct_size_and_initialized(data)
184 }
185}
186
187#[cfg(test)]
188impl Arbitrary<'_> for VoteStateVersions {
189 fn arbitrary(u: &mut Unstructured<'_>) -> arbitrary::Result<Self> {
190 let variant = u.choose_index(3)?;
191 match variant {
192 0 => Ok(Self::V4(Box::new(VoteStateV4::arbitrary(u)?))),
193 1 => Ok(Self::V3(Box::new(VoteStateV3::arbitrary(u)?))),
194 2 => Ok(Self::V1_14_11(Box::new(VoteState1_14_11::arbitrary(u)?))),
195 _ => unreachable!(),
196 }
197 }
198}