Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.

Commit b86cd45

Browse files
committed
use VoteState::deserialize() everywhere
1 parent 8ea98e6 commit b86cd45

File tree

9 files changed

+47
-60
lines changed

9 files changed

+47
-60
lines changed

account-decoder/src/parse_vote.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ use {
88
};
99

1010
pub fn parse_vote(data: &[u8]) -> Result<VoteAccountType, ParseAccountError> {
11-
let mut vote_state =
12-
VoteState::deserialize_with_bincode(data).map_err(ParseAccountError::from)?;
11+
let mut vote_state = VoteState::deserialize(data).map_err(ParseAccountError::from)?;
1312
let epoch_credits = vote_state
1413
.epoch_credits()
1514
.iter()

programs/vote/src/vote_state/mod.rs

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ impl From<VoteStateUpdate> for VoteTransaction {
133133

134134
// utility function, used by Stakes, tests
135135
pub fn from<T: ReadableAccount>(account: &T) -> Option<VoteState> {
136-
VoteState::deserialize_with_bincode(account.data()).ok()
136+
VoteState::deserialize(account.data()).ok()
137137
}
138138

139139
// utility function, used by Stakes, tests
@@ -810,9 +810,7 @@ pub fn authorize<S: std::hash::BuildHasher>(
810810
clock: &Clock,
811811
feature_set: &FeatureSet,
812812
) -> Result<(), InstructionError> {
813-
let mut vote_state: VoteState = vote_account
814-
.get_state::<VoteStateVersions>()?
815-
.convert_to_current();
813+
let mut vote_state = VoteState::deserialize(vote_account.get_data())?;
816814

817815
match vote_authorize {
818816
VoteAuthorize::Voter => {
@@ -853,9 +851,7 @@ pub fn update_validator_identity<S: std::hash::BuildHasher>(
853851
signers: &HashSet<Pubkey, S>,
854852
feature_set: &FeatureSet,
855853
) -> Result<(), InstructionError> {
856-
let mut vote_state: VoteState = vote_account
857-
.get_state::<VoteStateVersions>()?
858-
.convert_to_current();
854+
let mut vote_state = VoteState::deserialize(vote_account.get_data())?;
859855

860856
// current authorized withdrawer must say "yay"
861857
verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?;
@@ -882,8 +878,8 @@ pub fn update_commission<S: std::hash::BuildHasher>(
882878

883879
let enforce_commission_update_rule =
884880
if feature_set.is_active(&feature_set::allow_commission_decrease_at_any_time::id()) {
885-
if let Ok(decoded_vote_state) = vote_account.get_state::<VoteStateVersions>() {
886-
vote_state = Some(decoded_vote_state.convert_to_current());
881+
if let Ok(decoded_vote_state) = VoteState::deserialize(vote_account.get_data()) {
882+
vote_state = Some(decoded_vote_state);
887883
is_commission_increase(vote_state.as_ref().unwrap(), commission)
888884
} else {
889885
true
@@ -904,9 +900,7 @@ pub fn update_commission<S: std::hash::BuildHasher>(
904900

905901
let mut vote_state = match vote_state {
906902
Some(vote_state) => vote_state,
907-
None => vote_account
908-
.get_state::<VoteStateVersions>()?
909-
.convert_to_current(),
903+
None => VoteState::deserialize(vote_account.get_data())?,
910904
};
911905

912906
// current authorized withdrawer must say "yay"
@@ -963,9 +957,7 @@ pub fn withdraw<S: std::hash::BuildHasher>(
963957
) -> Result<(), InstructionError> {
964958
let mut vote_account = instruction_context
965959
.try_borrow_instruction_account(transaction_context, vote_account_index)?;
966-
let vote_state: VoteState = vote_account
967-
.get_state::<VoteStateVersions>()?
968-
.convert_to_current();
960+
let vote_state = VoteState::deserialize(vote_account.get_data())?;
969961

970962
verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?;
971963

@@ -1027,9 +1019,9 @@ pub fn initialize_account<S: std::hash::BuildHasher>(
10271019
{
10281020
return Err(InstructionError::InvalidAccountData);
10291021
}
1030-
let versioned = vote_account.get_state::<VoteStateVersions>()?;
10311022

1032-
if !versioned.is_uninitialized() {
1023+
let vote_state = VoteState::deserialize(vote_account.get_data())?;
1024+
if !vote_state.is_uninitialized() {
10331025
return Err(InstructionError::AccountAlreadyInitialized);
10341026
}
10351027

@@ -1044,13 +1036,11 @@ fn verify_and_get_vote_state<S: std::hash::BuildHasher>(
10441036
clock: &Clock,
10451037
signers: &HashSet<Pubkey, S>,
10461038
) -> Result<VoteState, InstructionError> {
1047-
let versioned = vote_account.get_state::<VoteStateVersions>()?;
1048-
1049-
if versioned.is_uninitialized() {
1039+
let mut vote_state = VoteState::deserialize(vote_account.get_data())?;
1040+
if vote_state.is_uninitialized() {
10501041
return Err(InstructionError::UninitializedAccount);
10511042
}
10521043

1053-
let mut vote_state = versioned.convert_to_current();
10541044
let authorized_voter = vote_state.get_and_update_authorized_voter(clock.epoch)?;
10551045
verify_authorized_signer(&authorized_voter, signers)?;
10561046

runtime/src/bank.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2650,7 +2650,7 @@ impl Bank {
26502650
// vote_accounts_cache_miss_count is shown to be always zero.
26512651
let account = self.get_account_with_fixed_root(vote_pubkey)?;
26522652
if account.owner() == &solana_vote_program
2653-
&& VoteState::deserialize_with_bincode(account.data()).is_ok()
2653+
&& VoteState::deserialize(account.data()).is_ok()
26542654
{
26552655
vote_accounts_cache_miss_count.fetch_add(1, Relaxed);
26562656
}

sdk/program/src/vote/authorized_voters.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ impl AuthorizedVoters {
6464
self.authorized_voters.is_empty()
6565
}
6666

67+
// when an uninitialized V0_23_5 account is converted to current, it inserts a null voter
68+
pub fn is_uninitialized(&self) -> bool {
69+
self.is_empty() || (self.len() == 1 && self.first() == Some((&0, &Pubkey::default())))
70+
}
71+
6772
pub fn first(&self) -> Option<(&u64, &Pubkey)> {
6873
self.authorized_voters.iter().next()
6974
}

sdk/program/src/vote/state/mod.rs

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -382,20 +382,6 @@ impl VoteState {
382382
Ok(vote_state)
383383
}
384384

385-
// this only exists for the sake of the feature gated upgrade to the new parser; do not use it
386-
#[doc(hidden)]
387-
#[allow(clippy::used_underscore_binding)]
388-
pub fn deserialize_with_bincode(_input: &[u8]) -> Result<Self, InstructionError> {
389-
#[cfg(not(target_os = "solana"))]
390-
{
391-
bincode::deserialize::<VoteStateVersions>(_input)
392-
.map(|versioned| versioned.convert_to_current())
393-
.map_err(|_| InstructionError::InvalidAccountData)
394-
}
395-
#[cfg(target_os = "solana")]
396-
unimplemented!()
397-
}
398-
399385
/// Deserializes the input buffer into the provided `VoteState`
400386
///
401387
/// This function is exposed to allow deserialization in a BPF context directly into boxed memory.
@@ -777,6 +763,10 @@ impl VoteState {
777763
data.len() == VoteState::size_of()
778764
&& data[VERSION_OFFSET..DEFAULT_PRIOR_VOTERS_END] != [0; DEFAULT_PRIOR_VOTERS_OFFSET]
779765
}
766+
767+
pub fn is_uninitialized(&self) -> bool {
768+
self.authorized_voters.is_uninitialized()
769+
}
780770
}
781771

782772
pub mod serde_compact_vote_state_update {
@@ -936,11 +926,23 @@ mod tests {
936926
let mut rng = rand::thread_rng();
937927
for _ in 0..1000 {
938928
let raw_data_length = rng.gen_range(1..serialized_len_x4);
939-
let raw_data: Vec<u8> = (0..raw_data_length).map(|_| rng.gen::<u8>()).collect();
929+
let mut raw_data: Vec<u8> = (0..raw_data_length).map(|_| rng.gen::<u8>()).collect();
930+
931+
// pure random data will ~never have a valid enum tag, so lets help it out
932+
if raw_data_length >= 4 && rng.gen::<bool>() {
933+
let tag = rng.gen::<u8>() % 3;
934+
raw_data[0] = tag;
935+
raw_data[1] = 0;
936+
raw_data[2] = 0;
937+
raw_data[3] = 0;
938+
}
940939

941940
// it is extremely improbable, though theoretically possible, for random bytes to be syntactically valid
942-
// so we only check that the deserialize function does not panic
943-
let _ = VoteState::deserialize(&raw_data);
941+
// so we only check that the parser does not panic and that it succeeds or fails exactly in line with bincode
942+
let test_res = VoteState::deserialize(&raw_data);
943+
let bincode_res = bincode::deserialize::<VoteStateVersions>(&raw_data);
944+
945+
assert_eq!(test_res.is_ok(), bincode_res.is_ok());
944946
}
945947
}
946948

sdk/program/src/vote/state/vote_state_1_14_11.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ impl VoteState1_14_11 {
5757
data.len() == VoteState1_14_11::size_of()
5858
&& data[VERSION_OFFSET..DEFAULT_PRIOR_VOTERS_END] != [0; DEFAULT_PRIOR_VOTERS_OFFSET]
5959
}
60+
61+
pub fn is_uninitialized(&self) -> bool {
62+
self.authorized_voters.is_uninitialized()
63+
}
6064
}
6165

6266
impl From<VoteState> for VoteState1_14_11 {

sdk/program/src/vote/state/vote_state_deserialize.rs

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use {
22
crate::{
33
instruction::InstructionError,
4-
pubkey::Pubkey,
54
serialize_utils::cursor::*,
65
vote::state::{BlockTimestamp, LandedVote, Lockout, VoteState, MAX_ITEMS},
76
},
@@ -87,21 +86,12 @@ fn read_prior_voters_into<T: AsRef<[u8]>>(
8786
if !is_empty {
8887
cursor.set_position(prior_voters_position);
8988

90-
let mut encountered_null_voter = false;
9189
for i in 0..MAX_ITEMS {
9290
let prior_voter = read_pubkey(cursor)?;
9391
let from_epoch = read_u64(cursor)?;
9492
let until_epoch = read_u64(cursor)?;
95-
let item = (prior_voter, from_epoch, until_epoch);
96-
97-
if item == (Pubkey::default(), 0, 0) {
98-
encountered_null_voter = true;
99-
} else if encountered_null_voter {
100-
// `prior_voters` should never be sparse
101-
return Err(InstructionError::InvalidAccountData);
102-
} else {
103-
vote_state.prior_voters.buf[i] = item;
104-
}
93+
94+
vote_state.prior_voters.buf[i] = (prior_voter, from_epoch, until_epoch);
10595
}
10696

10797
vote_state.prior_voters.idx = read_u64(cursor)? as usize;

sdk/program/src/vote/state/vote_state_versions.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@ impl VoteStateVersions {
7373
vote_state.authorized_voter == Pubkey::default()
7474
}
7575

76-
VoteStateVersions::V1_14_11(vote_state) => vote_state.authorized_voters.is_empty(),
76+
VoteStateVersions::V1_14_11(vote_state) => vote_state.is_uninitialized(),
7777

78-
VoteStateVersions::Current(vote_state) => vote_state.authorized_voters.is_empty(),
78+
VoteStateVersions::Current(vote_state) => vote_state.is_uninitialized(),
7979
}
8080
}
8181

vote/src/vote_account.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,10 @@ impl VoteAccount {
6565
}
6666

6767
pub fn vote_state(&self) -> Result<&VoteState, &Error> {
68-
// VoteState::deserialize_with_bincode deserializes a VoteStateVersions and then
69-
// calls VoteStateVersions::convert_to_current.
68+
// VoteState::deserialize deserializes a VoteStateVersions directly into VoteState
7069
self.0
7170
.vote_state
72-
.get_or_init(|| {
73-
VoteState::deserialize_with_bincode(self.0.account.data()).map_err(Error::from)
74-
})
71+
.get_or_init(|| VoteState::deserialize(self.0.account.data()).map_err(Error::from))
7572
.as_ref()
7673
}
7774

0 commit comments

Comments
 (0)