Skip to content

Commit

Permalink
use VoteState::deserialize() everywhere
Browse files Browse the repository at this point in the history
  • Loading branch information
2501babe committed Feb 7, 2024
1 parent 8ea98e6 commit 89a46cd
Show file tree
Hide file tree
Showing 9 changed files with 32 additions and 57 deletions.
3 changes: 1 addition & 2 deletions account-decoder/src/parse_vote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ use {
};

pub fn parse_vote(data: &[u8]) -> Result<VoteAccountType, ParseAccountError> {
let mut vote_state =
VoteState::deserialize_with_bincode(data).map_err(ParseAccountError::from)?;
let mut vote_state = VoteState::deserialize(data).map_err(ParseAccountError::from)?;
let epoch_credits = vote_state
.epoch_credits()
.iter()
Expand Down
32 changes: 11 additions & 21 deletions programs/vote/src/vote_state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ impl From<VoteStateUpdate> for VoteTransaction {

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

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

match vote_authorize {
VoteAuthorize::Voter => {
Expand Down Expand Up @@ -853,9 +851,7 @@ pub fn update_validator_identity<S: std::hash::BuildHasher>(
signers: &HashSet<Pubkey, S>,
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
let mut vote_state: VoteState = vote_account
.get_state::<VoteStateVersions>()?
.convert_to_current();
let mut vote_state = VoteState::deserialize(vote_account.get_data())?;

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

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

let mut vote_state = match vote_state {
Some(vote_state) => vote_state,
None => vote_account
.get_state::<VoteStateVersions>()?
.convert_to_current(),
None => VoteState::deserialize(vote_account.get_data())?,
};

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

verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?;

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

if !versioned.is_uninitialized() {
let vote_state = VoteState::deserialize(vote_account.get_data())?;
if !vote_state.is_uninitialized() {
return Err(InstructionError::AccountAlreadyInitialized);
}

Expand All @@ -1044,13 +1036,11 @@ fn verify_and_get_vote_state<S: std::hash::BuildHasher>(
clock: &Clock,
signers: &HashSet<Pubkey, S>,
) -> Result<VoteState, InstructionError> {
let versioned = vote_account.get_state::<VoteStateVersions>()?;

if versioned.is_uninitialized() {
let mut vote_state = VoteState::deserialize(vote_account.get_data())?;
if vote_state.is_uninitialized() {
return Err(InstructionError::UninitializedAccount);
}

let mut vote_state = versioned.convert_to_current();
let authorized_voter = vote_state.get_and_update_authorized_voter(clock.epoch)?;
verify_authorized_signer(&authorized_voter, signers)?;

Expand Down
2 changes: 1 addition & 1 deletion runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2650,7 +2650,7 @@ impl Bank {
// vote_accounts_cache_miss_count is shown to be always zero.
let account = self.get_account_with_fixed_root(vote_pubkey)?;
if account.owner() == &solana_vote_program
&& VoteState::deserialize_with_bincode(account.data()).is_ok()
&& VoteState::deserialize(account.data()).is_ok()
{
vote_accounts_cache_miss_count.fetch_add(1, Relaxed);
}
Expand Down
5 changes: 5 additions & 0 deletions sdk/program/src/vote/authorized_voters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ impl AuthorizedVoters {
self.authorized_voters.is_empty()
}

// when an uninitialized V0_23_5 account is converted to current, it inserts a null voter
pub fn is_uninitialized(&self) -> bool {
self.is_empty() || (self.len() == 1 && self.first() == Some((&0, &Pubkey::default())))
}

pub fn first(&self) -> Option<(&u64, &Pubkey)> {
self.authorized_voters.iter().next()
}
Expand Down
18 changes: 4 additions & 14 deletions sdk/program/src/vote/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,20 +382,6 @@ impl VoteState {
Ok(vote_state)
}

// this only exists for the sake of the feature gated upgrade to the new parser; do not use it
#[doc(hidden)]
#[allow(clippy::used_underscore_binding)]
pub fn deserialize_with_bincode(_input: &[u8]) -> Result<Self, InstructionError> {
#[cfg(not(target_os = "solana"))]
{
bincode::deserialize::<VoteStateVersions>(_input)
.map(|versioned| versioned.convert_to_current())
.map_err(|_| InstructionError::InvalidAccountData)
}
#[cfg(target_os = "solana")]
unimplemented!()
}

/// Deserializes the input buffer into the provided `VoteState`
///
/// This function is exposed to allow deserialization in a BPF context directly into boxed memory.
Expand Down Expand Up @@ -777,6 +763,10 @@ impl VoteState {
data.len() == VoteState::size_of()
&& data[VERSION_OFFSET..DEFAULT_PRIOR_VOTERS_END] != [0; DEFAULT_PRIOR_VOTERS_OFFSET]
}

pub fn is_uninitialized(&self) -> bool {
self.authorized_voters.is_uninitialized()
}
}

pub mod serde_compact_vote_state_update {
Expand Down
4 changes: 4 additions & 0 deletions sdk/program/src/vote/state/vote_state_1_14_11.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ impl VoteState1_14_11 {
data.len() == VoteState1_14_11::size_of()
&& data[VERSION_OFFSET..DEFAULT_PRIOR_VOTERS_END] != [0; DEFAULT_PRIOR_VOTERS_OFFSET]
}

pub fn is_uninitialized(&self) -> bool {
self.authorized_voters.is_uninitialized()
}
}

impl From<VoteState> for VoteState1_14_11 {
Expand Down
14 changes: 2 additions & 12 deletions sdk/program/src/vote/state/vote_state_deserialize.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use {
crate::{
instruction::InstructionError,
pubkey::Pubkey,
serialize_utils::cursor::*,
vote::state::{BlockTimestamp, LandedVote, Lockout, VoteState, MAX_ITEMS},
},
Expand Down Expand Up @@ -87,21 +86,12 @@ fn read_prior_voters_into<T: AsRef<[u8]>>(
if !is_empty {
cursor.set_position(prior_voters_position);

let mut encountered_null_voter = false;
for i in 0..MAX_ITEMS {
let prior_voter = read_pubkey(cursor)?;
let from_epoch = read_u64(cursor)?;
let until_epoch = read_u64(cursor)?;
let item = (prior_voter, from_epoch, until_epoch);

if item == (Pubkey::default(), 0, 0) {
encountered_null_voter = true;
} else if encountered_null_voter {
// `prior_voters` should never be sparse
return Err(InstructionError::InvalidAccountData);
} else {
vote_state.prior_voters.buf[i] = item;
}

vote_state.prior_voters.buf[i] = (prior_voter, from_epoch, until_epoch);
}

vote_state.prior_voters.idx = read_u64(cursor)? as usize;
Expand Down
4 changes: 2 additions & 2 deletions sdk/program/src/vote/state/vote_state_versions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ impl VoteStateVersions {
vote_state.authorized_voter == Pubkey::default()
}

VoteStateVersions::V1_14_11(vote_state) => vote_state.authorized_voters.is_empty(),
VoteStateVersions::V1_14_11(vote_state) => vote_state.is_uninitialized(),

VoteStateVersions::Current(vote_state) => vote_state.authorized_voters.is_empty(),
VoteStateVersions::Current(vote_state) => vote_state.is_uninitialized(),
}
}

Expand Down
7 changes: 2 additions & 5 deletions vote/src/vote_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,10 @@ impl VoteAccount {
}

pub fn vote_state(&self) -> Result<&VoteState, &Error> {
// VoteState::deserialize_with_bincode deserializes a VoteStateVersions and then
// calls VoteStateVersions::convert_to_current.
// VoteState::deserialize deserializes a VoteStateVersions directly into VoteState
self.0
.vote_state
.get_or_init(|| {
VoteState::deserialize_with_bincode(self.0.account.data()).map_err(Error::from)
})
.get_or_init(|| VoteState::deserialize(self.0.account.data()).map_err(Error::from))
.as_ref()
}

Expand Down

0 comments on commit 89a46cd

Please sign in to comment.