Add new CreateVoteAccount instruction-set builders (#31330)
* Add failing test * Add config struct for vote-account creation * Add create-vote-account ix builders that use CreateVoteAccountConfig * Test now passes; add case to demonstrate failure after activation * Deprecate existing ix builders * Use new builders in solana-cli * Query feature status to use correct VoteState size in solana-cli * Fix tests and clippy warnings * Improve ugly conditional block
This commit is contained in:
parent
54f1595dfa
commit
9af7009bb4
|
@ -31,14 +31,14 @@ use {
|
|||
solana_rpc_client_api::config::RpcGetVoteAccountsConfig,
|
||||
solana_rpc_client_nonce_utils::blockhash_query::BlockhashQuery,
|
||||
solana_sdk::{
|
||||
account::Account, commitment_config::CommitmentConfig, message::Message,
|
||||
account::Account, commitment_config::CommitmentConfig, feature, message::Message,
|
||||
native_token::lamports_to_sol, pubkey::Pubkey, system_instruction::SystemError,
|
||||
transaction::Transaction,
|
||||
},
|
||||
solana_vote_program::{
|
||||
vote_error::VoteError,
|
||||
vote_instruction::{self, withdraw},
|
||||
vote_state::{VoteAuthorize, VoteInit, VoteState},
|
||||
vote_instruction::{self, withdraw, CreateVoteAccountConfig},
|
||||
vote_state::{VoteAuthorize, VoteInit, VoteState, VoteStateVersions},
|
||||
},
|
||||
std::sync::Arc,
|
||||
};
|
||||
|
@ -800,6 +800,13 @@ pub fn process_create_vote_account(
|
|||
let fee_payer = config.signers[fee_payer];
|
||||
let nonce_authority = config.signers[nonce_authority];
|
||||
|
||||
let is_feature_active = (!sign_only)
|
||||
.then(solana_sdk::feature_set::vote_state_add_vote_latency::id)
|
||||
.and_then(|feature_address| rpc_client.get_account(&feature_address).ok())
|
||||
.and_then(|account| feature::from_account(&account))
|
||||
.map_or(false, |feature| feature.activated_at.is_some());
|
||||
let space = VoteStateVersions::vote_state_size_of(is_feature_active) as u64;
|
||||
|
||||
let build_message = |lamports| {
|
||||
let vote_init = VoteInit {
|
||||
node_pubkey: identity_pubkey,
|
||||
|
@ -807,28 +814,27 @@ pub fn process_create_vote_account(
|
|||
authorized_withdrawer,
|
||||
commission,
|
||||
};
|
||||
|
||||
let ixs = if let Some(seed) = seed {
|
||||
vote_instruction::create_account_with_seed(
|
||||
&config.signers[0].pubkey(), // from
|
||||
&vote_account_address, // to
|
||||
&vote_account_pubkey, // base
|
||||
seed, // seed
|
||||
&vote_init,
|
||||
lamports,
|
||||
)
|
||||
.with_memo(memo)
|
||||
.with_compute_unit_price(compute_unit_price)
|
||||
} else {
|
||||
vote_instruction::create_account(
|
||||
&config.signers[0].pubkey(),
|
||||
&vote_account_pubkey,
|
||||
&vote_init,
|
||||
lamports,
|
||||
)
|
||||
.with_memo(memo)
|
||||
.with_compute_unit_price(compute_unit_price)
|
||||
let mut create_vote_account_config = CreateVoteAccountConfig {
|
||||
space,
|
||||
..CreateVoteAccountConfig::default()
|
||||
};
|
||||
let to = if let Some(seed) = seed {
|
||||
create_vote_account_config.with_seed = Some((&vote_account_pubkey, seed));
|
||||
&vote_account_address
|
||||
} else {
|
||||
&vote_account_pubkey
|
||||
};
|
||||
|
||||
let ixs = vote_instruction::create_account_with_config(
|
||||
&config.signers[0].pubkey(),
|
||||
to,
|
||||
&vote_init,
|
||||
lamports,
|
||||
create_vote_account_config,
|
||||
)
|
||||
.with_memo(memo)
|
||||
.with_compute_unit_price(compute_unit_price);
|
||||
|
||||
if let Some(nonce_account) = &nonce_account {
|
||||
Message::new_with_nonce(
|
||||
ixs,
|
||||
|
|
|
@ -46,7 +46,7 @@ pub(crate) mod tests {
|
|||
process_instructions(
|
||||
bank,
|
||||
&[from_account, vote_account, validator_identity_account],
|
||||
&vote_instruction::create_account(
|
||||
&vote_instruction::create_account_with_config(
|
||||
&from_account.pubkey(),
|
||||
&vote_pubkey,
|
||||
&VoteInit {
|
||||
|
@ -56,6 +56,10 @@ pub(crate) mod tests {
|
|||
commission: 0,
|
||||
},
|
||||
amount,
|
||||
vote_instruction::CreateVoteAccountConfig {
|
||||
space: VoteStateVersions::vote_state_size_of(true) as u64,
|
||||
..vote_instruction::CreateVoteAccountConfig::default()
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
|
|
|
@ -653,7 +653,7 @@ impl LocalCluster {
|
|||
{
|
||||
// 1) Create vote account
|
||||
|
||||
let instructions = vote_instruction::create_account(
|
||||
let instructions = vote_instruction::create_account_with_config(
|
||||
&from_account.pubkey(),
|
||||
&vote_account_pubkey,
|
||||
&VoteInit {
|
||||
|
@ -663,6 +663,10 @@ impl LocalCluster {
|
|||
commission: 0,
|
||||
},
|
||||
amount,
|
||||
vote_instruction::CreateVoteAccountConfig {
|
||||
space: vote_state::VoteStateVersions::vote_state_size_of(true) as u64,
|
||||
..vote_instruction::CreateVoteAccountConfig::default()
|
||||
},
|
||||
);
|
||||
let message = Message::new(&instructions, Some(&from_account.pubkey()));
|
||||
let mut transaction = Transaction::new(
|
||||
|
|
|
@ -82,7 +82,7 @@ async fn setup_vote(context: &mut ProgramTestContext) -> Pubkey {
|
|||
let vote_lamports = Rent::default().minimum_balance(VoteState::size_of());
|
||||
let vote_keypair = Keypair::new();
|
||||
let user_keypair = Keypair::new();
|
||||
instructions.append(&mut vote_instruction::create_account(
|
||||
instructions.append(&mut vote_instruction::create_account_with_config(
|
||||
&context.payer.pubkey(),
|
||||
&vote_keypair.pubkey(),
|
||||
&VoteInit {
|
||||
|
@ -91,6 +91,10 @@ async fn setup_vote(context: &mut ProgramTestContext) -> Pubkey {
|
|||
..VoteInit::default()
|
||||
},
|
||||
vote_lamports,
|
||||
vote_instruction::CreateVoteAccountConfig {
|
||||
space: vote_state::VoteStateVersions::vote_state_size_of(true) as u64,
|
||||
..vote_instruction::CreateVoteAccountConfig::default()
|
||||
},
|
||||
));
|
||||
|
||||
let transaction = Transaction::new_signed_with_payer(
|
||||
|
|
|
@ -283,9 +283,9 @@ mod tests {
|
|||
crate::{
|
||||
vote_error::VoteError,
|
||||
vote_instruction::{
|
||||
authorize, authorize_checked, create_account, update_commission,
|
||||
authorize, authorize_checked, create_account_with_config, update_commission,
|
||||
update_validator_identity, update_vote_state, update_vote_state_switch, vote,
|
||||
vote_switch, withdraw, VoteInstruction,
|
||||
vote_switch, withdraw, CreateVoteAccountConfig, VoteInstruction,
|
||||
},
|
||||
vote_state::{
|
||||
self, Lockout, Vote, VoteAuthorize, VoteAuthorizeCheckedWithSeedArgs,
|
||||
|
@ -1795,15 +1795,113 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_account_vote_state_1_14_11() {
|
||||
let node_pubkey = Pubkey::new_unique();
|
||||
let vote_pubkey = Pubkey::new_unique();
|
||||
let instructions = create_account_with_config(
|
||||
&node_pubkey,
|
||||
&vote_pubkey,
|
||||
&VoteInit {
|
||||
node_pubkey,
|
||||
authorized_voter: vote_pubkey,
|
||||
authorized_withdrawer: vote_pubkey,
|
||||
commission: 0,
|
||||
},
|
||||
101,
|
||||
CreateVoteAccountConfig::default(),
|
||||
);
|
||||
// grab the `space` value from SystemInstruction::CreateAccount by directly indexing, for
|
||||
// expediency
|
||||
let space = usize::from_le_bytes(instructions[0].data[12..20].try_into().unwrap());
|
||||
assert_eq!(space, vote_state::VoteState1_14_11::size_of());
|
||||
let empty_vote_account = AccountSharedData::new(101, space, &id());
|
||||
|
||||
let transaction_accounts = vec![
|
||||
(vote_pubkey, empty_vote_account),
|
||||
(node_pubkey, AccountSharedData::default()),
|
||||
(sysvar::clock::id(), create_default_clock_account()),
|
||||
(sysvar::rent::id(), create_default_rent_account()),
|
||||
];
|
||||
|
||||
// should succeed when vote_state_add_vote_latency is disabled
|
||||
process_instruction_disabled_features(
|
||||
&instructions[1].data,
|
||||
transaction_accounts.clone(),
|
||||
instructions[1].accounts.clone(),
|
||||
Ok(()),
|
||||
);
|
||||
|
||||
// should fail, if vote_state_add_vote_latency is enabled
|
||||
process_instruction(
|
||||
&instructions[1].data,
|
||||
transaction_accounts,
|
||||
instructions[1].accounts.clone(),
|
||||
Err(InstructionError::InvalidAccountData),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_account_vote_state_current() {
|
||||
let node_pubkey = Pubkey::new_unique();
|
||||
let vote_pubkey = Pubkey::new_unique();
|
||||
let instructions = create_account_with_config(
|
||||
&node_pubkey,
|
||||
&vote_pubkey,
|
||||
&VoteInit {
|
||||
node_pubkey,
|
||||
authorized_voter: vote_pubkey,
|
||||
authorized_withdrawer: vote_pubkey,
|
||||
commission: 0,
|
||||
},
|
||||
101,
|
||||
CreateVoteAccountConfig {
|
||||
space: vote_state::VoteState::size_of() as u64,
|
||||
..CreateVoteAccountConfig::default()
|
||||
},
|
||||
);
|
||||
// grab the `space` value from SystemInstruction::CreateAccount by directly indexing, for
|
||||
// expediency
|
||||
let space = usize::from_le_bytes(instructions[0].data[12..20].try_into().unwrap());
|
||||
assert_eq!(space, vote_state::VoteState::size_of());
|
||||
let empty_vote_account = AccountSharedData::new(101, space, &id());
|
||||
|
||||
let transaction_accounts = vec![
|
||||
(vote_pubkey, empty_vote_account),
|
||||
(node_pubkey, AccountSharedData::default()),
|
||||
(sysvar::clock::id(), create_default_clock_account()),
|
||||
(sysvar::rent::id(), create_default_rent_account()),
|
||||
];
|
||||
|
||||
// should fail, if vote_state_add_vote_latency is disabled
|
||||
process_instruction_disabled_features(
|
||||
&instructions[1].data,
|
||||
transaction_accounts.clone(),
|
||||
instructions[1].accounts.clone(),
|
||||
Err(InstructionError::InvalidAccountData),
|
||||
);
|
||||
|
||||
// succeeds, since vote_state_add_vote_latency is enabled
|
||||
process_instruction(
|
||||
&instructions[1].data,
|
||||
transaction_accounts,
|
||||
instructions[1].accounts.clone(),
|
||||
Ok(()),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vote_process_instruction() {
|
||||
solana_logger::setup();
|
||||
let instructions = create_account(
|
||||
let instructions = create_account_with_config(
|
||||
&Pubkey::new_unique(),
|
||||
&Pubkey::new_unique(),
|
||||
&VoteInit::default(),
|
||||
101,
|
||||
CreateVoteAccountConfig::default(),
|
||||
);
|
||||
// this case fails regardless of CreateVoteAccountConfig::space, because
|
||||
// process_instruction_as_one_arg passes a default (empty) account
|
||||
process_instruction_as_one_arg(&instructions[1], Err(InstructionError::InvalidAccountData));
|
||||
process_instruction_as_one_arg(
|
||||
&vote(
|
||||
|
|
|
@ -4439,7 +4439,7 @@ fn test_bank_vote_accounts() {
|
|||
// to have a vote account
|
||||
|
||||
let vote_keypair = Keypair::new();
|
||||
let instructions = vote_instruction::create_account(
|
||||
let instructions = vote_instruction::create_account_with_config(
|
||||
&mint_keypair.pubkey(),
|
||||
&vote_keypair.pubkey(),
|
||||
&VoteInit {
|
||||
|
@ -4449,6 +4449,10 @@ fn test_bank_vote_accounts() {
|
|||
commission: 0,
|
||||
},
|
||||
10,
|
||||
vote_instruction::CreateVoteAccountConfig {
|
||||
space: VoteStateVersions::vote_state_size_of(true) as u64,
|
||||
..vote_instruction::CreateVoteAccountConfig::default()
|
||||
},
|
||||
);
|
||||
|
||||
let message = Message::new(&instructions, Some(&mint_keypair.pubkey()));
|
||||
|
@ -4503,7 +4507,7 @@ fn test_bank_cloned_stake_delegations() {
|
|||
};
|
||||
|
||||
let vote_keypair = Keypair::new();
|
||||
let mut instructions = vote_instruction::create_account(
|
||||
let mut instructions = vote_instruction::create_account_with_config(
|
||||
&mint_keypair.pubkey(),
|
||||
&vote_keypair.pubkey(),
|
||||
&VoteInit {
|
||||
|
@ -4513,6 +4517,10 @@ fn test_bank_cloned_stake_delegations() {
|
|||
commission: 0,
|
||||
},
|
||||
vote_balance,
|
||||
vote_instruction::CreateVoteAccountConfig {
|
||||
space: VoteStateVersions::vote_state_size_of(true) as u64,
|
||||
..vote_instruction::CreateVoteAccountConfig::default()
|
||||
},
|
||||
);
|
||||
|
||||
let stake_keypair = Keypair::new();
|
||||
|
@ -4817,7 +4825,7 @@ fn test_add_builtin() {
|
|||
|
||||
let mock_account = Keypair::new();
|
||||
let mock_validator_identity = Keypair::new();
|
||||
let mut instructions = vote_instruction::create_account(
|
||||
let mut instructions = vote_instruction::create_account_with_config(
|
||||
&mint_keypair.pubkey(),
|
||||
&mock_account.pubkey(),
|
||||
&VoteInit {
|
||||
|
@ -4825,6 +4833,10 @@ fn test_add_builtin() {
|
|||
..VoteInit::default()
|
||||
},
|
||||
1,
|
||||
vote_instruction::CreateVoteAccountConfig {
|
||||
space: VoteStateVersions::vote_state_size_of(true) as u64,
|
||||
..vote_instruction::CreateVoteAccountConfig::default()
|
||||
},
|
||||
);
|
||||
instructions[1].program_id = mock_vote_program_id();
|
||||
|
||||
|
@ -4859,7 +4871,7 @@ fn test_add_duplicate_static_program() {
|
|||
|
||||
let mock_account = Keypair::new();
|
||||
let mock_validator_identity = Keypair::new();
|
||||
let instructions = vote_instruction::create_account(
|
||||
let instructions = vote_instruction::create_account_with_config(
|
||||
&mint_keypair.pubkey(),
|
||||
&mock_account.pubkey(),
|
||||
&VoteInit {
|
||||
|
@ -4867,6 +4879,10 @@ fn test_add_duplicate_static_program() {
|
|||
..VoteInit::default()
|
||||
},
|
||||
1,
|
||||
vote_instruction::CreateVoteAccountConfig {
|
||||
space: VoteStateVersions::vote_state_size_of(true) as u64,
|
||||
..vote_instruction::CreateVoteAccountConfig::default()
|
||||
},
|
||||
);
|
||||
|
||||
let message = Message::new(&instructions, Some(&mint_keypair.pubkey()));
|
||||
|
@ -9504,7 +9520,7 @@ fn test_vote_epoch_panic() {
|
|||
|
||||
let mut setup_ixs = Vec::new();
|
||||
setup_ixs.extend(
|
||||
vote_instruction::create_account(
|
||||
vote_instruction::create_account_with_config(
|
||||
&mint_keypair.pubkey(),
|
||||
&vote_keypair.pubkey(),
|
||||
&VoteInit {
|
||||
|
@ -9514,6 +9530,10 @@ fn test_vote_epoch_panic() {
|
|||
commission: 0,
|
||||
},
|
||||
1_000_000_000,
|
||||
vote_instruction::CreateVoteAccountConfig {
|
||||
space: VoteStateVersions::vote_state_size_of(true) as u64,
|
||||
..vote_instruction::CreateVoteAccountConfig::default()
|
||||
},
|
||||
)
|
||||
.into_iter(),
|
||||
);
|
||||
|
|
|
@ -304,7 +304,7 @@ fn test_stake_account_lifetime() {
|
|||
|
||||
// Create Vote Account
|
||||
let message = Message::new(
|
||||
&vote_instruction::create_account(
|
||||
&vote_instruction::create_account_with_config(
|
||||
&mint_pubkey,
|
||||
&vote_pubkey,
|
||||
&VoteInit {
|
||||
|
@ -314,6 +314,10 @@ fn test_stake_account_lifetime() {
|
|||
commission: 50,
|
||||
},
|
||||
vote_balance,
|
||||
vote_instruction::CreateVoteAccountConfig {
|
||||
space: VoteStateVersions::vote_state_size_of(true) as u64,
|
||||
..vote_instruction::CreateVoteAccountConfig::default()
|
||||
},
|
||||
),
|
||||
Some(&mint_pubkey),
|
||||
);
|
||||
|
@ -569,7 +573,7 @@ fn test_create_stake_account_from_seed() {
|
|||
|
||||
// Create Vote Account
|
||||
let message = Message::new(
|
||||
&vote_instruction::create_account(
|
||||
&vote_instruction::create_account_with_config(
|
||||
&mint_pubkey,
|
||||
&vote_pubkey,
|
||||
&VoteInit {
|
||||
|
@ -579,6 +583,10 @@ fn test_create_stake_account_from_seed() {
|
|||
commission: 50,
|
||||
},
|
||||
10,
|
||||
vote_instruction::CreateVoteAccountConfig {
|
||||
space: VoteStateVersions::vote_state_size_of(true) as u64,
|
||||
..vote_instruction::CreateVoteAccountConfig::default()
|
||||
},
|
||||
),
|
||||
Some(&mint_pubkey),
|
||||
);
|
||||
|
|
|
@ -11,8 +11,8 @@ use {
|
|||
program::id,
|
||||
state::{
|
||||
serde_compact_vote_state_update, Vote, VoteAuthorize,
|
||||
VoteAuthorizeCheckedWithSeedArgs, VoteAuthorizeWithSeedArgs, VoteInit, VoteState,
|
||||
VoteStateUpdate,
|
||||
VoteAuthorizeCheckedWithSeedArgs, VoteAuthorizeWithSeedArgs, VoteInit,
|
||||
VoteStateUpdate, VoteStateVersions,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -202,19 +202,43 @@ fn initialize_account(vote_pubkey: &Pubkey, vote_init: &VoteInit) -> Instruction
|
|||
)
|
||||
}
|
||||
|
||||
pub struct CreateVoteAccountConfig<'a> {
|
||||
pub space: u64,
|
||||
pub with_seed: Option<(&'a Pubkey, &'a str)>,
|
||||
}
|
||||
|
||||
impl<'a> Default for CreateVoteAccountConfig<'a> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
space: VoteStateVersions::vote_state_size_of(false) as u64,
|
||||
with_seed: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[deprecated(
|
||||
since = "1.16.0",
|
||||
note = "Please use `create_account_with_config()` instead."
|
||||
)]
|
||||
pub fn create_account(
|
||||
from_pubkey: &Pubkey,
|
||||
vote_pubkey: &Pubkey,
|
||||
vote_init: &VoteInit,
|
||||
lamports: u64,
|
||||
) -> Vec<Instruction> {
|
||||
let space = VoteState::size_of() as u64;
|
||||
let create_ix =
|
||||
system_instruction::create_account(from_pubkey, vote_pubkey, lamports, space, &id());
|
||||
let init_ix = initialize_account(vote_pubkey, vote_init);
|
||||
vec![create_ix, init_ix]
|
||||
create_account_with_config(
|
||||
from_pubkey,
|
||||
vote_pubkey,
|
||||
vote_init,
|
||||
lamports,
|
||||
CreateVoteAccountConfig::default(),
|
||||
)
|
||||
}
|
||||
|
||||
#[deprecated(
|
||||
since = "1.16.0",
|
||||
note = "Please use `create_account_with_config()` instead."
|
||||
)]
|
||||
pub fn create_account_with_seed(
|
||||
from_pubkey: &Pubkey,
|
||||
vote_pubkey: &Pubkey,
|
||||
|
@ -223,16 +247,27 @@ pub fn create_account_with_seed(
|
|||
vote_init: &VoteInit,
|
||||
lamports: u64,
|
||||
) -> Vec<Instruction> {
|
||||
let space = VoteState::size_of() as u64;
|
||||
let create_ix = system_instruction::create_account_with_seed(
|
||||
create_account_with_config(
|
||||
from_pubkey,
|
||||
vote_pubkey,
|
||||
base,
|
||||
seed,
|
||||
vote_init,
|
||||
lamports,
|
||||
space,
|
||||
&id(),
|
||||
);
|
||||
CreateVoteAccountConfig {
|
||||
with_seed: Some((base, seed)),
|
||||
..CreateVoteAccountConfig::default()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn create_account_with_config(
|
||||
from_pubkey: &Pubkey,
|
||||
vote_pubkey: &Pubkey,
|
||||
vote_init: &VoteInit,
|
||||
lamports: u64,
|
||||
config: CreateVoteAccountConfig,
|
||||
) -> Vec<Instruction> {
|
||||
let create_ix =
|
||||
system_instruction::create_account(from_pubkey, vote_pubkey, lamports, config.space, &id());
|
||||
let init_ix = initialize_account(vote_pubkey, vote_init);
|
||||
vec![create_ix, init_ix]
|
||||
}
|
||||
|
|
|
@ -255,7 +255,7 @@ mod test {
|
|||
sysvar,
|
||||
vote::{
|
||||
instruction as vote_instruction,
|
||||
state::{Vote, VoteAuthorize, VoteInit, VoteStateUpdate},
|
||||
state::{Vote, VoteAuthorize, VoteInit, VoteStateUpdate, VoteStateVersions},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -276,11 +276,15 @@ mod test {
|
|||
commission,
|
||||
};
|
||||
|
||||
let instructions = vote_instruction::create_account(
|
||||
let instructions = vote_instruction::create_account_with_config(
|
||||
&Pubkey::new_unique(),
|
||||
&vote_pubkey,
|
||||
&vote_init,
|
||||
lamports,
|
||||
vote_instruction::CreateVoteAccountConfig {
|
||||
space: VoteStateVersions::vote_state_size_of(true) as u64,
|
||||
..vote_instruction::CreateVoteAccountConfig::default()
|
||||
},
|
||||
);
|
||||
let mut message = Message::new(&instructions, None);
|
||||
assert_eq!(
|
||||
|
|
Loading…
Reference in New Issue