diff --git a/genesis/src/main.rs b/genesis/src/main.rs
index 4cb4bbb509..be0b0efb0b 100644
--- a/genesis/src/main.rs
+++ b/genesis/src/main.rs
@@ -41,7 +41,9 @@ use {
solana_rent::Rent,
solana_rpc_client::rpc_client::RpcClient,
solana_rpc_client_api::request::MAX_MULTIPLE_ACCOUNTS,
- solana_runtime::genesis_utils::include_alpenglow_bpf_program,
+ solana_runtime::genesis_utils::{
+ bls_pubkey_to_compressed_bytes, include_alpenglow_bpf_program,
+ },
solana_sdk_ids::system_program,
solana_signer::Signer,
solana_stake_interface::state::StakeStateV2,
@@ -268,13 +270,13 @@ fn add_validator_accounts(
let bls_pubkey = bls_pubkeys_iter
.next()
.expect("Missing BLS pubkey for {identity_pubkey}");
- AlpenglowVoteState::create_account_with_authorized(
+ vote_state::create_v4_account_with_authorized(
identity_pubkey,
identity_pubkey,
identity_pubkey,
- commission,
+ Some(bls_pubkey_to_compressed_bytes(bls_pubkey)),
+ commission.into(),
AlpenglowVoteState::get_rent_exempt_reserve(rent).max(1),
- *bls_pubkey,
)
} else {
vote_state::create_account_with_authorized(
diff --git a/programs/stake/src/stake_state.rs b/programs/stake/src/stake_state.rs
index 106e8f03f5..3b820f9e84 100644
--- a/programs/stake/src/stake_state.rs
+++ b/programs/stake/src/stake_state.rs
@@ -12,8 +12,7 @@ use {
solana_rent::Rent,
solana_sdk_ids::stake::id,
solana_stake_interface::stake_flags::StakeFlags,
- solana_vote_interface::state::VoteStateV3,
- solana_votor_messages::state::VoteState as AlpenglowVoteState,
+ solana_vote_interface::state::{VoteStateV3, VoteStateV4},
};
// utility function, used by Stakes, tests
@@ -41,12 +40,7 @@ pub fn meta_from(account: &AccountSharedData) -> Option {
from(account).and_then(|state: StakeStateV2| state.meta())
}
-pub(crate) fn new_stake_with_credits(
- stake: u64,
- voter_pubkey: &Pubkey,
- credits: u64,
- activation_epoch: Epoch,
-) -> Stake {
+fn new_stake(stake: u64, voter_pubkey: &Pubkey, credits: u64, activation_epoch: Epoch) -> Stake {
Stake {
delegation: Delegation::new(voter_pubkey, stake, activation_epoch),
credits_observed: credits,
@@ -94,6 +88,25 @@ pub fn create_account(
rent,
lamports,
Epoch::MAX,
+ false,
+ )
+}
+
+pub fn create_alpenglow_account(
+ authorized: &Pubkey,
+ voter_pubkey: &Pubkey,
+ vote_account: &AccountSharedData,
+ rent: &Rent,
+ lamports: u64,
+) -> AccountSharedData {
+ do_create_account(
+ authorized,
+ voter_pubkey,
+ vote_account,
+ rent,
+ lamports,
+ Epoch::MAX,
+ true,
)
}
@@ -104,18 +117,16 @@ fn do_create_account(
rent: &Rent,
lamports: u64,
activation_epoch: Epoch,
+ is_alpenglow: bool,
) -> AccountSharedData {
let mut stake_account = AccountSharedData::new(lamports, StakeStateV2::size_of(), &id());
- let credits = if solana_votor_messages::check_id(vote_account.owner()) {
- AlpenglowVoteState::deserialize(vote_account.data())
- .expect("alpenglow_vote_state")
- .epoch_credits()
- .credits()
+ let credits = if is_alpenglow {
+ let vote_state_v4 = VoteStateV4::deserialize(vote_account.data(), voter_pubkey).unwrap();
+ vote_state_v4.epoch_credits.last().map_or(0, |(_, c, _)| *c)
} else {
- VoteStateV3::deserialize(vote_account.data())
- .expect("vote_state")
- .credits()
+ let vote_state = VoteStateV3::deserialize(vote_account.data()).expect("vote_state");
+ vote_state.credits()
};
let rent_exempt_reserve = rent.minimum_balance(stake_account.data().len());
@@ -127,7 +138,7 @@ fn do_create_account(
rent_exempt_reserve,
..Meta::default()
},
- new_stake_with_credits(
+ new_stake(
lamports - rent_exempt_reserve, // underflow is an error, is basically: assert!(lamports > rent_exempt_reserve);
voter_pubkey,
credits,
diff --git a/programs/vote/src/vote_state/mod.rs b/programs/vote/src/vote_state/mod.rs
index 2839175a6e..db8c95e4dc 100644
--- a/programs/vote/src/vote_state/mod.rs
+++ b/programs/vote/src/vote_state/mod.rs
@@ -16,7 +16,7 @@ use {
solana_rent::Rent,
solana_slot_hashes::SlotHash,
solana_transaction_context::{BorrowedInstructionAccount, IndexOfAccount, InstructionContext},
- solana_vote_interface::{error::VoteError, program::id},
+ solana_vote_interface::{authorized_voters::AuthorizedVoters, error::VoteError, program::id},
std::{
cmp::Ordering,
collections::{HashSet, VecDeque},
@@ -1044,6 +1044,51 @@ pub fn create_account_with_authorized(
vote_account
}
+// TODO(wen): when we have VoteStateV4::new(), switch all users there.
+pub fn new_v4_vote_state(
+ node_pubkey: &Pubkey,
+ authorized_voter: &Pubkey,
+ authorized_withdrawer: &Pubkey,
+ bls_pubkey_compressed: Option<[u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE]>,
+ inflation_rewards_commission_bps: u16,
+) -> VoteStateV4 {
+ VoteStateV4 {
+ node_pubkey: *node_pubkey,
+ authorized_voters: AuthorizedVoters::new(0, *authorized_voter),
+ authorized_withdrawer: *authorized_withdrawer,
+ bls_pubkey_compressed,
+ inflation_rewards_commission_bps,
+ ..VoteStateV4::default()
+ }
+}
+
+pub fn create_v4_account_with_authorized(
+ node_pubkey: &Pubkey,
+ authorized_voter: &Pubkey,
+ authorized_withdrawer: &Pubkey,
+ bls_pubkey_compressed: Option<[u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE]>,
+ inflation_rewards_commission_bps: u16,
+ lamports: u64,
+) -> AccountSharedData {
+ let mut vote_account = AccountSharedData::new(lamports, VoteStateV4::size_of(), &id());
+
+ let vote_state = new_v4_vote_state(
+ node_pubkey,
+ authorized_voter,
+ authorized_withdrawer,
+ bls_pubkey_compressed,
+ inflation_rewards_commission_bps,
+ );
+
+ VoteStateV4::serialize(
+ &VoteStateVersions::V4(Box::new(vote_state)),
+ vote_account.data_as_mut_slice(),
+ )
+ .unwrap();
+
+ vote_account
+}
+
// create_account() should be removed, use create_account_with_authorized() instead
pub fn create_account(
vote_pubkey: &Pubkey,
@@ -1084,7 +1129,7 @@ mod tests {
fn create_test_account() -> (Pubkey, RefCell) {
let rent = Rent::default();
- let balance = VoteStateV3::get_rent_exempt_reserve(&rent);
+ let balance = rent.minimum_balance(VoteStateV3::size_of());
let vote_pubkey = solana_pubkey::new_rand();
(
vote_pubkey,
@@ -1223,7 +1268,7 @@ mod tests {
// Test that when the feature is enabled, if the vote account does have sufficient lamports, the
// new vote state is written out
assert_eq!(
- borrowed_account.set_lamports(rent.minimum_balance(VoteStateV3::size_of()),),
+ borrowed_account.set_lamports(rent.minimum_balance(VoteStateV3::size_of())),
Ok(())
);
assert_eq!(
@@ -3535,4 +3580,40 @@ mod tests {
expected_allowed
);
}
+
+ #[test]
+ fn test_create_v4_account_with_authorized() {
+ let node_pubkey = Pubkey::new_unique();
+ let authorized_voter = Pubkey::new_unique();
+ let authorized_withdrawer = Pubkey::new_unique();
+ let bls_pubkey_compressed = [42; 48];
+ let inflation_rewards_commission_bps = 10000;
+ let lamports = 100;
+ let vote_account = create_v4_account_with_authorized(
+ &node_pubkey,
+ &authorized_voter,
+ &authorized_withdrawer,
+ Some(bls_pubkey_compressed),
+ inflation_rewards_commission_bps,
+ lamports,
+ );
+ assert_eq!(vote_account.lamports(), lamports);
+ assert_eq!(vote_account.owner(), &id());
+ assert_eq!(vote_account.data().len(), VoteStateV4::size_of());
+ let vote_state_v4 = VoteStateV4::deserialize(vote_account.data(), &node_pubkey).unwrap();
+ assert_eq!(vote_state_v4.node_pubkey, node_pubkey);
+ assert_eq!(
+ vote_state_v4.authorized_voters,
+ AuthorizedVoters::new(0, authorized_voter)
+ );
+ assert_eq!(vote_state_v4.authorized_withdrawer, authorized_withdrawer);
+ assert_eq!(
+ vote_state_v4.bls_pubkey_compressed,
+ Some(bls_pubkey_compressed)
+ );
+ assert_eq!(
+ vote_state_v4.inflation_rewards_commission_bps,
+ inflation_rewards_commission_bps
+ );
+ }
}
diff --git a/runtime/src/bank/serde_snapshot.rs b/runtime/src/bank/serde_snapshot.rs
index 24f965c1b5..53cb408c7b 100644
--- a/runtime/src/bank/serde_snapshot.rs
+++ b/runtime/src/bank/serde_snapshot.rs
@@ -28,7 +28,6 @@ mod tests {
solana_pubkey::Pubkey,
solana_signer::Signer,
solana_vote::vote_account::VoteAccount,
- solana_votor_messages::state::VoteState as AlpenglowVoteState,
std::{
collections::HashMap,
io::{BufReader, BufWriter, Cursor},
@@ -208,7 +207,7 @@ mod tests {
// Give some real stake distribution and generate real VersionedEpochStakes, to
// make sure bls_pubkey_to_rank_map is populated correctly after deserialize.
let vote_account = if is_alpenglow {
- VoteAccount::new_from_alpenglow_vote_state(&AlpenglowVoteState::default())
+ VoteAccount::new_random_alpenglow()
} else {
VoteAccount::new_random()
};
diff --git a/runtime/src/bank/tests.rs b/runtime/src/bank/tests.rs
index 084e68dab9..73a6f471f6 100644
--- a/runtime/src/bank/tests.rs
+++ b/runtime/src/bank/tests.rs
@@ -119,7 +119,7 @@ use {
vote_instruction,
vote_state::{
self, create_account_with_authorized, BlockTimestamp, VoteAuthorize, VoteInit,
- VoteStateV3, VoteStateVersions, MAX_LOCKOUT_HISTORY,
+ VoteStateV3, VoteStateV4, VoteStateVersions, MAX_LOCKOUT_HISTORY,
},
},
spl_generic_token::token,
@@ -731,13 +731,20 @@ where
// generate some rewards
if is_alpenglow {
let mut vote_state =
- *solana_votor_messages::state::VoteState::deserialize(vote_account.data()).unwrap();
+ VoteStateV4::deserialize(vote_account.data(), &Pubkey::default()).unwrap();
+ vote_state.epoch_credits.push((0, 0, 0));
for _ in 0..MAX_LOCKOUT_HISTORY + 42 {
- let mut epoch_credits = *vote_state.epoch_credits();
- epoch_credits.set_credits(epoch_credits.credits() + 16);
- vote_state.set_epoch_credits(epoch_credits);
- vote_state.serialize_into(vote_account.data_as_mut_slice());
+ let (_, current_credits, _) = vote_state.epoch_credits.last_mut().unwrap();
+ *current_credits += 16;
+ let versioned = VoteStateVersions::V4(Box::new(vote_state.clone()));
+ vote_state::to(&versioned, &mut vote_account).unwrap();
bank0.store_account_and_update_capitalization(&vote_id, &vote_account);
+ match versioned {
+ VoteStateVersions::V4(v) => {
+ vote_state = *v;
+ }
+ _ => panic!("Has to be of type Current"),
+ };
}
} else {
let mut vote_state = Some(vote_state::from(&vote_account).unwrap());
diff --git a/runtime/src/epoch_stakes.rs b/runtime/src/epoch_stakes.rs
index 6d78f4cb17..27fb8f71dd 100644
--- a/runtime/src/epoch_stakes.rs
+++ b/runtime/src/epoch_stakes.rs
@@ -1,7 +1,7 @@
use {
crate::stakes::SerdeStakesToStakeFormat,
serde::{Deserialize, Serialize},
- solana_bls_signatures::Pubkey as BLSPubkey,
+ solana_bls_signatures::{Pubkey as BLSPubkey, PubkeyCompressed as BLSPubkeyCompressed},
solana_clock::Epoch,
solana_pubkey::Pubkey,
solana_vote::vote_account::VoteAccountsHashMap,
@@ -13,7 +13,6 @@ use {
pub type NodeIdToVoteAccounts = HashMap;
pub type EpochAuthorizedVoters = HashMap;
-pub type SortedPubkeys = Vec<(Pubkey, BLSPubkey)>;
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
@@ -31,9 +30,13 @@ impl BLSPubkeyToRankMap {
.iter()
.filter_map(|(pubkey, (stake, account))| {
if *stake > 0 {
- account
- .bls_pubkey()
- .map(|bls_pubkey| (*pubkey, *bls_pubkey, *stake))
+ account.vote_state_view().and_then(|vote_state| {
+ let bls_pubkey_compressed_bytes = vote_state.bls_pubkey_compressed()?;
+ let bls_pubkey_compressed =
+ BLSPubkeyCompressed(bls_pubkey_compressed_bytes);
+ let bls_pubkey = BLSPubkey::try_from(bls_pubkey_compressed).ok()?;
+ Some((*pubkey, bls_pubkey, *stake))
+ })
} else {
None
}
@@ -200,18 +203,20 @@ impl VersionedEpochStakes {
let epoch_authorized_voters = epoch_vote_accounts
.iter()
.filter_map(|(key, (stake, account))| {
+ let vote_state = account.vote_state_view()?;
+
if *stake > 0 {
if let Some(authorized_voter) =
- account.get_authorized_voter(leader_schedule_epoch)
+ vote_state.get_authorized_voter(leader_schedule_epoch)
{
let node_vote_accounts = node_id_to_vote_accounts
- .entry(*account.node_pubkey())
+ .entry(*vote_state.node_pubkey())
.or_default();
node_vote_accounts.total_stake += stake;
node_vote_accounts.vote_accounts.push(*key);
- Some((*key, authorized_voter))
+ Some((*key, *authorized_voter))
} else {
None
}
@@ -231,11 +236,15 @@ impl VersionedEpochStakes {
#[cfg(test)]
pub(crate) mod tests {
use {
- super::*, solana_account::AccountSharedData,
+ super::*,
+ crate::genesis_utils::bls_pubkey_to_compressed_bytes,
+ solana_account::AccountSharedData,
solana_bls_signatures::keypair::Keypair as BLSKeypair,
solana_vote::vote_account::VoteAccount,
- solana_vote_program::vote_state::create_account_with_authorized,
- solana_votor_messages::state::VoteState as AlpenglowVoteState, std::iter,
+ solana_vote_program::vote_state::{
+ create_account_with_authorized, create_v4_account_with_authorized,
+ },
+ std::iter,
test_case::test_case,
};
@@ -258,15 +267,14 @@ pub(crate) mod tests {
node_id,
iter::repeat_with(|| {
let authorized_voter = solana_pubkey::new_rand();
- let bls_keypair = BLSKeypair::new();
let account = if is_alpenglow {
- AlpenglowVoteState::create_account_with_authorized(
+ create_v4_account_with_authorized(
&node_id,
&authorized_voter,
&node_id,
+ Some(bls_pubkey_to_compressed_bytes(&BLSKeypair::new().public)),
0,
100,
- bls_keypair.public,
)
} else {
create_account_with_authorized(
@@ -400,6 +408,7 @@ pub(crate) mod tests {
#[test_case(1; "single_vote_account")]
#[test_case(2; "multiple_vote_accounts")]
fn test_bls_pubkey_rank_map(num_vote_accounts_per_node: usize) {
+ solana_logger::setup();
let num_nodes = 10;
let num_vote_accounts = num_nodes * num_vote_accounts_per_node;
@@ -416,13 +425,17 @@ pub(crate) mod tests {
let bls_pubkey_to_rank_map = epoch_stakes.bls_pubkey_to_rank_map();
assert_eq!(bls_pubkey_to_rank_map.len(), num_vote_accounts);
for (pubkey, (_, vote_account)) in epoch_vote_accounts {
- let index = bls_pubkey_to_rank_map
- .get_rank(vote_account.bls_pubkey().unwrap())
- .unwrap();
+ let vote_state_view = vote_account.vote_state_view().unwrap();
+ let bls_pubkey_compressed = bincode::deserialize::(
+ &vote_state_view.bls_pubkey_compressed().unwrap(),
+ )
+ .unwrap();
+ let bls_pubkey = BLSPubkey::try_from(bls_pubkey_compressed).unwrap();
+ let index = bls_pubkey_to_rank_map.get_rank(&bls_pubkey).unwrap();
assert!(index >= &0 && index < &(num_vote_accounts as u16));
assert_eq!(
bls_pubkey_to_rank_map.get_pubkey(*index as usize),
- Some(&(pubkey, *vote_account.bls_pubkey().unwrap()))
+ Some(&(pubkey, bls_pubkey))
);
}
diff --git a/runtime/src/genesis_utils.rs b/runtime/src/genesis_utils.rs
index c49a1e17af..313598e385 100644
--- a/runtime/src/genesis_utils.rs
+++ b/runtime/src/genesis_utils.rs
@@ -2,7 +2,10 @@ use {
agave_feature_set::{FeatureSet, FEATURE_NAMES},
log::*,
solana_account::{Account, AccountSharedData},
- solana_bls_signatures::{keypair::Keypair as BLSKeypair, Pubkey as BLSPubkey},
+ solana_bls_signatures::{
+ keypair::Keypair as BLSKeypair, pubkey::PubkeyCompressed as BLSPubkeyCompressed,
+ Pubkey as BLSPubkey,
+ },
solana_cluster_type::ClusterType,
solana_feature_gate_interface::{self as feature, Feature},
solana_fee_calculator::FeeRateGovernor,
@@ -17,10 +20,9 @@ use {
solana_stake_interface::state::StakeStateV2,
solana_stake_program::stake_state,
solana_system_interface::program as system_program,
+ solana_vote_interface::state::BLS_PUBLIC_KEY_COMPRESSED_SIZE,
solana_vote_program::vote_state,
- solana_votor_messages::{
- self, consensus_message::BLS_KEYPAIR_DERIVE_SEED, state::VoteState as AlpenglowVoteState,
- },
+ solana_votor_messages::{self, consensus_message::BLS_KEYPAIR_DERIVE_SEED},
std::{borrow::Borrow, fs::File, io::Read},
};
@@ -174,24 +176,34 @@ pub fn create_genesis_config_with_vote_accounts_and_cluster_type(
// Create accounts
let node_account = Account::new(VALIDATOR_LAMPORTS, 0, &system_program::id());
let vote_account = if alpenglow_so_path.is_some() {
- AlpenglowVoteState::create_account_with_authorized(
+ vote_state::create_v4_account_with_authorized(
&node_pubkey,
&vote_pubkey,
&vote_pubkey,
+ Some(bls_pubkey_to_compressed_bytes(&bls_pubkey)),
0,
*stake,
- bls_pubkey,
)
} else {
vote_state::create_account(&vote_pubkey, &node_pubkey, 0, *stake)
};
- let stake_account = Account::from(stake_state::create_account(
- &stake_pubkey,
- &vote_pubkey,
- &vote_account,
- &genesis_config_info.genesis_config.rent,
- *stake,
- ));
+ let stake_account = if alpenglow_so_path.is_some() {
+ Account::from(stake_state::create_alpenglow_account(
+ &stake_pubkey,
+ &vote_pubkey,
+ &vote_account,
+ &genesis_config_info.genesis_config.rent,
+ *stake,
+ ))
+ } else {
+ Account::from(stake_state::create_account(
+ &stake_pubkey,
+ &vote_pubkey,
+ &vote_account,
+ &genesis_config_info.genesis_config.rent,
+ *stake,
+ ))
+ };
let vote_account = Account::from(vote_account);
@@ -351,6 +363,13 @@ pub fn activate_feature(genesis_config: &mut GenesisConfig, feature_id: Pubkey)
);
}
+pub fn bls_pubkey_to_compressed_bytes(
+ bls_pubkey: &BLSPubkey,
+) -> [u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE] {
+ let key = BLSPubkeyCompressed::try_from(bls_pubkey).unwrap();
+ bincode::serialize(&key).unwrap().try_into().unwrap()
+}
+
pub fn include_alpenglow_bpf_program(genesis_config: &mut GenesisConfig, alpenglow_so_path: &str) {
// Parse out the elf
let mut program_data_elf: Vec = vec![];
@@ -428,13 +447,13 @@ pub fn create_genesis_config_with_leader_ex_no_features(
alpenglow_so_path: Option<&str>,
) -> GenesisConfig {
let validator_vote_account = if alpenglow_so_path.is_some() {
- AlpenglowVoteState::create_account_with_authorized(
+ vote_state::create_v4_account_with_authorized(
validator_pubkey,
validator_vote_account_pubkey,
validator_vote_account_pubkey,
+ validator_bls_pubkey.map(bls_pubkey_to_compressed_bytes),
0,
validator_stake_lamports,
- *validator_bls_pubkey.unwrap(),
)
} else {
vote_state::create_account(
@@ -445,13 +464,23 @@ pub fn create_genesis_config_with_leader_ex_no_features(
)
};
- let validator_stake_account = stake_state::create_account(
- validator_stake_account_pubkey,
- validator_vote_account_pubkey,
- &validator_vote_account,
- &rent,
- validator_stake_lamports,
- );
+ let validator_stake_account = if alpenglow_so_path.is_some() {
+ stake_state::create_alpenglow_account(
+ validator_stake_account_pubkey,
+ validator_vote_account_pubkey,
+ &validator_vote_account,
+ &rent,
+ validator_stake_lamports,
+ )
+ } else {
+ stake_state::create_account(
+ validator_stake_account_pubkey,
+ validator_vote_account_pubkey,
+ &validator_vote_account,
+ &rent,
+ validator_stake_lamports,
+ )
+ };
initial_accounts.push((
*mint_pubkey,
diff --git a/runtime/src/inflation_rewards/mod.rs b/runtime/src/inflation_rewards/mod.rs
index fd3ccf3852..bf837163d8 100644
--- a/runtime/src/inflation_rewards/mod.rs
+++ b/runtime/src/inflation_rewards/mod.rs
@@ -260,8 +260,7 @@ mod tests {
use {
self::points::null_tracer, super::*, solana_native_token::LAMPORTS_PER_SOL,
solana_pubkey::Pubkey, solana_stake_interface::state::Delegation,
- solana_vote_program::vote_state::VoteStateV3,
- solana_votor_messages::state::VoteState as AlpenglowVoteState, test_case::test_case,
+ solana_vote_program::vote_state::VoteStateV3, test_case::test_case,
};
fn new_stake(
@@ -701,7 +700,6 @@ mod tests {
#[test]
fn test_stake_state_calculate_points_with_typical_values() {
let vote_state = VoteStateV3::default();
- let alpenglow_vote_state = AlpenglowVoteState::default();
// bootstrap means fully-vested stake at epoch 0 with
// 10_000_000 SOL is a big but not unreasaonable stake
@@ -737,7 +735,7 @@ mod tests {
rewards: 1_000_000_000,
points: 1
},
- &VoteAccount::new_from_alpenglow_vote_state(&alpenglow_vote_state),
+ &VoteAccount::new_random_alpenglow(),
&StakeHistory::default(),
null_tracer(),
None,
diff --git a/runtime/src/stakes.rs b/runtime/src/stakes.rs
index cd7d33f01b..13ac3eb264 100644
--- a/runtime/src/stakes.rs
+++ b/runtime/src/stakes.rs
@@ -556,15 +556,15 @@ fn refresh_vote_accounts(
pub(crate) mod tests {
use {
super::*,
+ crate::genesis_utils::bls_pubkey_to_compressed_bytes,
rayon::ThreadPoolBuilder,
solana_account::WritableAccount,
solana_bls_signatures::keypair::Keypair as BLSKeypair,
solana_pubkey::Pubkey,
solana_rent::Rent,
solana_stake_program::stake_state,
- solana_vote_interface::state::{VoteStateV3, VoteStateVersions},
+ solana_vote_interface::state::{VoteStateV3, VoteStateV4, VoteStateVersions},
solana_vote_program::vote_state,
- solana_votor_messages::state::VoteState as AlpenglowVoteState,
test_case::test_case,
};
@@ -576,13 +576,13 @@ pub(crate) mod tests {
let vote_pubkey = solana_pubkey::new_rand();
let bls_keypair = BLSKeypair::new();
let vote_account = if is_alpenglow {
- AlpenglowVoteState::create_account_with_authorized(
- &vote_pubkey,
+ vote_state::create_v4_account_with_authorized(
+ &solana_pubkey::new_rand(),
&vote_pubkey,
&vote_pubkey,
+ Some(bls_pubkey_to_compressed_bytes(&bls_keypair.public)),
0,
1,
- bls_keypair.public,
)
} else {
vote_state::create_account(&vote_pubkey, &solana_pubkey::new_rand(), 0, 1)
@@ -695,9 +695,9 @@ pub(crate) mod tests {
stakes_cache.check_and_store(&stake11_pubkey, &stake11_account, None);
let vote11_node_pubkey = if is_alpenglow {
- *AlpenglowVoteState::deserialize(vote11_account.data())
+ VoteStateV4::deserialize(vote11_account.data(), &vote11_pubkey)
.unwrap()
- .node_pubkey()
+ .node_pubkey
} else {
vote_state::from(&vote11_account).unwrap().node_pubkey
};
@@ -763,9 +763,9 @@ pub(crate) mod tests {
// Vote account uninitialized
if is_alpenglow {
- vote_account.set_data(cache_data.clone());
- let default_vote_state = AlpenglowVoteState::default();
- default_vote_state.serialize_into(vote_account.data_as_mut_slice());
+ let default_vote_state = VoteStateV4::default();
+ let versioned = VoteStateVersions::new_v4(default_vote_state);
+ vote_state::to(&versioned, &mut vote_account).unwrap();
} else {
let default_vote_state = VoteStateV3::default();
let versioned = VoteStateVersions::new_v3(default_vote_state);
diff --git a/vote/src/vote_account.rs b/vote/src/vote_account.rs
index 307581230a..9c9ec5c2fc 100644
--- a/vote/src/vote_account.rs
+++ b/vote/src/vote_account.rs
@@ -1,3 +1,6 @@
+// The following imports are only needed for dev-context-only-utils.
+#[cfg(feature = "dev-context-only-utils")]
+use solana_vote_interface::state::{VoteStateV3, VoteStateV4, VoteStateVersions};
use {
crate::vote_state_view::VoteStateView,
itertools::Itertools,
@@ -6,11 +9,15 @@ use {
ser::{Serialize, Serializer},
},
solana_account::{AccountSharedData, ReadableAccount},
- solana_bls_signatures::Pubkey as BLSPubkey,
+ solana_bls_signatures::{
+ keypair::Keypair as BLSKeypair,
+ pubkey::{AsPubkey, PubkeyCompressed as BLSPubkeyCompressed},
+ Pubkey as BLSPubkey,
+ },
solana_instruction::error::InstructionError,
solana_program::program_error::ProgramError,
solana_pubkey::Pubkey,
- solana_vote_interface::state::BlockTimestamp,
+ solana_vote_interface::{authorized_voters::AuthorizedVoters, state::BlockTimestamp},
solana_votor_messages::state::VoteState as AlpenglowVoteState,
std::{
cmp::Ordering,
@@ -22,12 +29,6 @@ use {
},
thiserror::Error,
};
-// The following imports are only needed for dev-context-only-utils.
-#[cfg(feature = "dev-context-only-utils")]
-use {
- solana_account::WritableAccount,
- solana_vote_interface::state::{VoteStateV3, VoteStateVersions},
-};
#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
#[derive(Clone, Debug, PartialEq)]
@@ -194,14 +195,14 @@ impl VoteAccount {
}
}
- pub fn bls_pubkey(&self) -> Option<&BLSPubkey> {
+ pub fn bls_pubkey(&self) -> Option {
match &self.0.vote_state_view {
- VoteAccountState::TowerBFT(_) => None,
- VoteAccountState::Alpenglow => Some(
- AlpenglowVoteState::deserialize(self.0.account.data())
- .unwrap()
- .bls_pubkey(),
- ),
+ VoteAccountState::TowerBFT(vote_state) => vote_state.bls_pubkey_compressed().map(|b| {
+ let bls_pubkey_compressed =
+ bincode::deserialize::(&b).unwrap();
+ BLSPubkeyCompressed::try_as_affine(&bls_pubkey_compressed).unwrap()
+ }),
+ VoteAccountState::Alpenglow => None,
}
}
@@ -252,13 +253,23 @@ impl VoteAccount {
}
#[cfg(feature = "dev-context-only-utils")]
- pub fn new_from_alpenglow_vote_state(vote_state: &AlpenglowVoteState) -> VoteAccount {
- let mut account = AccountSharedData::new(
+ pub fn new_random_alpenglow() -> VoteAccount {
+ let bls_pubkey_compressed: BLSPubkeyCompressed =
+ BLSKeypair::new().public.try_into().unwrap();
+ let bls_pubkey_compressed_buffer = bincode::serialize(&bls_pubkey_compressed).unwrap();
+ let vote_state = VoteStateV4 {
+ node_pubkey: Pubkey::new_unique(),
+ authorized_voters: AuthorizedVoters::new(0, Pubkey::new_unique()),
+ authorized_withdrawer: Pubkey::new_unique(),
+ bls_pubkey_compressed: Some(bls_pubkey_compressed_buffer.try_into().unwrap()),
+ ..VoteStateV4::default()
+ };
+ let account = AccountSharedData::new_data(
100, // lamports
- AlpenglowVoteState::size(),
- &solana_votor_messages::id(),
- );
- vote_state.serialize_into(account.data_as_mut_slice());
+ &VoteStateVersions::new_v4(vote_state),
+ &solana_sdk_ids::vote::id(), // owner
+ )
+ .unwrap();
VoteAccount::try_from(account).unwrap()
}
diff --git a/votor/src/voting_utils.rs b/votor/src/voting_utils.rs
index 392571fb68..1299f2ed4b 100644
--- a/votor/src/voting_utils.rs
+++ b/votor/src/voting_utils.rs
@@ -6,7 +6,10 @@ use {
voting_service::BLSOp,
},
crossbeam_channel::{SendError, Sender},
- solana_bls_signatures::{keypair::Keypair as BLSKeypair, BlsError, Pubkey as BLSPubkey},
+ solana_bls_signatures::{
+ keypair::Keypair as BLSKeypair, pubkey::PubkeyCompressed as BLSPubkeyCompressed, BlsError,
+ Pubkey as BLSPubkey,
+ },
solana_clock::Slot,
solana_keypair::Keypair,
solana_pubkey::Pubkey,
@@ -169,34 +172,43 @@ pub fn generate_vote_tx(
let Some(vote_account) = bank.get_vote_account(&vote_account_pubkey) else {
return GenerateVoteTxResult::VoteAccountNotFound(vote_account_pubkey);
};
- let Some(vote_state) = vote_account.alpenglow_vote_state() else {
+ let Some(vote_state_view) = vote_account.vote_state_view() else {
return GenerateVoteTxResult::NoVoteState(vote_account_pubkey);
};
- if *vote_state.node_pubkey() != context.identity_keypair.pubkey() {
+ if vote_state_view.node_pubkey() != &context.identity_keypair.pubkey() {
info!(
"Vote account node_pubkey mismatch: {} (expected: {}). Unable to vote",
- vote_state.node_pubkey(),
+ vote_state_view.node_pubkey(),
context.identity_keypair.pubkey()
);
return GenerateVoteTxResult::HotSpare;
}
- bls_pubkey_in_vote_account = match vote_account.bls_pubkey() {
+ let bls_pubkey_serialized = match vote_state_view.bls_pubkey_compressed() {
None => {
panic!(
"No BLS pubkey in vote account {}",
context.identity_keypair.pubkey()
);
}
- Some(key) => *key,
+ Some(key) => key,
};
-
- let Some(authorized_voter_pubkey) = vote_state.get_authorized_voter(bank.epoch()) else {
+ bls_pubkey_in_vote_account =
+ (bincode::deserialize::(&bls_pubkey_serialized).unwrap())
+ .try_into()
+ .unwrap_or_else(|_| {
+ panic!(
+ "Failed to decompress BLS pubkey in vote account {}",
+ context.identity_keypair.pubkey()
+ );
+ });
+ let Some(authorized_voter_pubkey) = vote_state_view.get_authorized_voter(bank.epoch())
+ else {
return GenerateVoteTxResult::NoAuthorizedVoter(vote_account_pubkey, bank.epoch());
};
let Some(keypair) = authorized_voter_keypairs
.iter()
- .find(|keypair| keypair.pubkey() == authorized_voter_pubkey)
+ .find(|keypair| &keypair.pubkey() == authorized_voter_pubkey)
else {
warn!(
"The authorized keypair {authorized_voter_pubkey} for vote account \