diff --git a/vote-interface/src/state/mod.rs b/vote-interface/src/state/mod.rs index 21ee84511..d94cfd45a 100644 --- a/vote-interface/src/state/mod.rs +++ b/vote-interface/src/state/mod.rs @@ -935,6 +935,7 @@ mod tests { authorized_voter: original_voter, authorized_withdrawer: original_voter, commission: 0, + bls_pubkey_compressed: None, }, &Clock::default(), ); @@ -1002,6 +1003,7 @@ mod tests { authorized_voter: original_voter, authorized_withdrawer: original_voter, commission: 0, + bls_pubkey_compressed: None, }, &Clock::default(), ); @@ -1100,6 +1102,7 @@ mod tests { authorized_voter: original_voter, authorized_withdrawer: original_voter, commission: 0, + bls_pubkey_compressed: None, }, &Clock::default(), ); @@ -1217,6 +1220,7 @@ mod tests { authorized_voter: Pubkey::new_unique(), authorized_withdrawer: Pubkey::new_unique(), commission: 0, + bls_pubkey_compressed: None, }, &Clock::default(), ); diff --git a/vote-interface/src/state/vote_instruction_data.rs b/vote-interface/src/state/vote_instruction_data.rs index 136f2d71c..988067ecc 100644 --- a/vote-interface/src/state/vote_instruction_data.rs +++ b/vote-interface/src/state/vote_instruction_data.rs @@ -1,9 +1,11 @@ #[cfg(feature = "serde")] use serde_derive::{Deserialize, Serialize}; +#[cfg(feature = "serde")] +use serde_with::serde_as; #[cfg(feature = "frozen-abi")] use solana_frozen_abi_macro::{frozen_abi, AbiExample}; use { - crate::state::{Lockout, MAX_LOCKOUT_HISTORY}, + crate::state::{Lockout, BLS_PUBLIC_KEY_COMPRESSED_SIZE, MAX_LOCKOUT_HISTORY}, solana_clock::{Slot, UnixTimestamp}, solana_hash::Hash, solana_pubkey::Pubkey, @@ -192,6 +194,7 @@ impl TowerSync { } } +#[cfg_attr(feature = "serde", cfg_eval::cfg_eval, serde_as)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[derive(Default, Debug, PartialEq, Eq, Clone, Copy)] pub struct VoteInit { @@ -199,6 +202,13 @@ pub struct VoteInit { pub authorized_voter: Pubkey, pub authorized_withdrawer: Pubkey, pub commission: u8, + + /// Compressed BLS pubkey for Alpenglow. + #[cfg_attr( + feature = "serde", + serde_as(as = "Option<[_; BLS_PUBLIC_KEY_COMPRESSED_SIZE]>") + )] + pub bls_pubkey_compressed: Option<[u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE]>, } #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] diff --git a/vote-interface/src/state/vote_state_v3.rs b/vote-interface/src/state/vote_state_v3.rs index 20270950f..3341ae02d 100644 --- a/vote-interface/src/state/vote_state_v3.rs +++ b/vote-interface/src/state/vote_state_v3.rs @@ -12,7 +12,9 @@ use { MAX_LOCKOUT_HISTORY, VOTE_CREDITS_GRACE_SLOTS, VOTE_CREDITS_MAXIMUM_PER_SLOT, }, crate::{ - authorized_voters::AuthorizedVoters, error::VoteError, state::DEFAULT_PRIOR_VOTERS_OFFSET, + authorized_voters::AuthorizedVoters, + error::VoteError, + state::{VoteStateV4, DEFAULT_PRIOR_VOTERS_OFFSET}, }, solana_clock::{Clock, Epoch, Slot, UnixTimestamp}, solana_instruction_error::InstructionError, @@ -513,3 +515,26 @@ impl VoteStateV3 { && data[VERSION_OFFSET..DEFAULT_PRIOR_VOTERS_END] != [0; DEFAULT_PRIOR_VOTERS_OFFSET] } } + +impl From for VoteStateV3 { + fn from(vote_state: VoteStateV4) -> Self { + let commission_bps = vote_state + .inflation_rewards_commission_bps + .checked_add(vote_state.block_revenue_commission_bps) + .expect("Inflation rewards commission and block revenue commission bps overflow."); + + let commission = commission_bps.div_ceil(10_000) as u8; + + Self { + node_pubkey: vote_state.node_pubkey, + authorized_withdrawer: vote_state.authorized_withdrawer, + commission, + votes: vote_state.votes, + root_slot: vote_state.root_slot, + authorized_voters: vote_state.authorized_voters, + prior_voters: CircBuf::default(), + epoch_credits: vote_state.epoch_credits, + last_timestamp: vote_state.last_timestamp, + } + } +} diff --git a/vote-interface/src/state/vote_state_v4.rs b/vote-interface/src/state/vote_state_v4.rs index 448d815f5..cd25a6f93 100644 --- a/vote-interface/src/state/vote_state_v4.rs +++ b/vote-interface/src/state/vote_state_v4.rs @@ -8,12 +8,11 @@ use serde_derive::{Deserialize, Serialize}; use serde_with::serde_as; #[cfg(feature = "frozen-abi")] use solana_frozen_abi_macro::{frozen_abi, AbiExample}; -#[cfg(any(target_os = "solana", feature = "bincode"))] -use solana_instruction::error::InstructionError; use { super::{BlockTimestamp, LandedVote, BLS_PUBLIC_KEY_COMPRESSED_SIZE}, - crate::authorized_voters::AuthorizedVoters, - solana_clock::{Epoch, Slot}, + crate::{authorized_voters::AuthorizedVoters, state::VoteInit}, + solana_clock::{Clock, Epoch, Slot}, + solana_instruction_error::InstructionError, solana_pubkey::Pubkey, std::{collections::VecDeque, fmt::Debug}, }; @@ -71,6 +70,21 @@ pub struct VoteStateV4 { } impl VoteStateV4 { + pub fn new(vote_init: &VoteInit, clock: &Clock) -> Self { + let inflation_rewards_commission_bps = (vote_init.commission as u16) + .checked_mul(10_000) + .expect("Turning commission into basis points results in an overflow."); + + Self { + node_pubkey: vote_init.node_pubkey, + authorized_voters: AuthorizedVoters::new(clock.epoch, vote_init.authorized_voter), + authorized_withdrawer: vote_init.authorized_withdrawer, + inflation_rewards_commission_bps, + bls_pubkey_compressed: vote_init.bls_pubkey_compressed, + ..VoteStateV4::default() + } + } + /// Upper limit on the size of the Vote State /// when votes.len() is MAX_LOCKOUT_HISTORY. pub const fn size_of() -> usize { @@ -214,4 +228,13 @@ impl VoteStateV4 { ..Self::default() } } + + pub fn commission(&self) -> Result { + let commission_bps = self + .inflation_rewards_commission_bps + .checked_add(self.block_revenue_commission_bps) + .ok_or(InstructionError::ArithmeticOverflow)?; + + Ok(commission_bps.div_ceil(10_000) as u8) + } }