From 16222553b889c96ae9fa665cfca50820fe650a98 Mon Sep 17 00:00:00 2001 From: behzad nouri Date: Tue, 19 Apr 2022 13:10:14 +0000 Subject: [PATCH] defines const fn for serialized size of VoteState, Feature and Nonce (#24435) bincode::serialized_sized requires constructing a temporary object and it is slow. Silently changing serialized size of these structs can also be a backward incompatible change. This commit instead hard-codes serialized size of VoteState, Feature and Nonce, and defines the functions as const. Added tests verify hard-coded values. --- programs/vote/src/vote_state/mod.rs | 23 ++++++++++++++++------- sdk/program/src/feature.rs | 15 +++++++++------ sdk/program/src/nonce/state/current.rs | 15 ++++++++++----- 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/programs/vote/src/vote_state/mod.rs b/programs/vote/src/vote_state/mod.rs index a56e4927f..1fe68117a 100644 --- a/programs/vote/src/vote_state/mod.rs +++ b/programs/vote/src/vote_state/mod.rs @@ -1,14 +1,15 @@ //! Vote state, vote program //! Receive and processes votes from validators +#[cfg(test)] +use solana_sdk::epoch_schedule::MAX_LEADER_SCHEDULE_EPOCH_OFFSET; use { crate::{authorized_voters::AuthorizedVoters, id, vote_error::VoteError}, - bincode::{deserialize, serialize_into, serialized_size, ErrorKind}, + bincode::{deserialize, serialize_into, ErrorKind}, log::*, serde_derive::{Deserialize, Serialize}, solana_sdk::{ account::{AccountSharedData, ReadableAccount, WritableAccount}, clock::{Epoch, Slot, UnixTimestamp}, - epoch_schedule::MAX_LEADER_SCHEDULE_EPOCH_OFFSET, feature_set::{self, filter_votes_outside_slot_hashes, FeatureSet}, hash::Hash, instruction::InstructionError, @@ -349,11 +350,10 @@ impl VoteState { rent.minimum_balance(VoteState::size_of()) } - pub fn size_of() -> usize { - // Upper limit on the size of the Vote State. Equal to - // size_of(VoteState) when votes.len() is MAX_LOCKOUT_HISTORY - let vote_state = VoteStateVersions::new_current(Self::get_max_sized_vote_state()); - serialized_size(&vote_state).unwrap() as usize + /// Upper limit on the size of the Vote State + /// when votes.len() is MAX_LOCKOUT_HISTORY. + pub const fn size_of() -> usize { + 3731 // see test_vote_state_size_of. } // utility function, used by Stakes, tests @@ -416,6 +416,7 @@ impl VoteState { .is_ok() } + #[cfg(test)] fn get_max_sized_vote_state() -> VoteState { let mut authorized_voters = AuthorizedVoters::default(); for i in 0..=MAX_LEADER_SCHEDULE_EPOCH_OFFSET { @@ -2144,6 +2145,14 @@ mod tests { assert_eq!(vote_state.get_authorized_voter(3), Some(new_voter)); } + #[test] + fn test_vote_state_size_of() { + let vote_state = VoteState::get_max_sized_vote_state(); + let vote_state = VoteStateVersions::new_current(vote_state); + let size = bincode::serialized_size(&vote_state).unwrap(); + assert_eq!(VoteState::size_of() as u64, size); + } + #[test] fn test_vote_state_max_size() { let mut max_sized_data = vec![0; VoteState::size_of()]; diff --git a/sdk/program/src/feature.rs b/sdk/program/src/feature.rs index c9a2af158..3bd2243c5 100644 --- a/sdk/program/src/feature.rs +++ b/sdk/program/src/feature.rs @@ -24,11 +24,8 @@ pub struct Feature { } impl Feature { - pub fn size_of() -> usize { - bincode::serialized_size(&Feature { - activated_at: Some(0), - }) - .unwrap() as usize + pub const fn size_of() -> usize { + 9 // see test_feature_size_of. } pub fn from_account_info(account_info: &AccountInfo) -> Result { @@ -65,7 +62,13 @@ mod test { use {super::*, solana_program::clock::Slot}; #[test] - fn feature_sizeof() { + fn test_feature_size_of() { + assert_eq!(Feature::size_of() as u64, { + let feature = Feature { + activated_at: Some(0), + }; + bincode::serialized_size(&feature).unwrap() + }); assert!( Feature::size_of() >= bincode::serialized_size(&Feature::default()).unwrap() as usize ); diff --git a/sdk/program/src/nonce/state/current.rs b/sdk/program/src/nonce/state/current.rs index 7c23246ed..4ed4fc760 100644 --- a/sdk/program/src/nonce/state/current.rs +++ b/sdk/program/src/nonce/state/current.rs @@ -1,5 +1,4 @@ use { - super::Versions, crate::{fee_calculator::FeeCalculator, hash::Hash, pubkey::Pubkey}, serde_derive::{Deserialize, Serialize}, }; @@ -60,18 +59,24 @@ impl State { } /// Get the serialized size of the nonce state. - pub fn size() -> usize { - let data = Versions::new_current(State::Initialized(Data::default())); - bincode::serialized_size(&data).unwrap() as usize + pub const fn size() -> usize { + 80 // see test_nonce_state_size. } } #[cfg(test)] mod test { - use super::*; + use {super::*, crate::nonce::state::Versions}; #[test] fn default_is_uninitialized() { assert_eq!(State::default(), State::Uninitialized) } + + #[test] + fn test_nonce_state_size() { + let data = Versions::new_current(State::Initialized(Data::default())); + let size = bincode::serialized_size(&data).unwrap(); + assert_eq!(State::size() as u64, size); + } }