Remove `KeyedAccount` in builtin program "vote" (#24189)
* Uses transaction_context.get_key_of_account_at_index() in vote. * Inline keyed_account_at_index() in all instructions of vote which have more than one KeyedAccount parameter, because these could cause a borrow collision. * Replaces KeyedAccount by BorrowedAccount in vote.
This commit is contained in:
parent
fad9bd0538
commit
2e5042d8bd
|
@ -7,10 +7,7 @@ use {
|
|||
solana_program_runtime::{
|
||||
invoke_context::InvokeContext, sysvar_cache::get_sysvar_with_account_check,
|
||||
},
|
||||
solana_sdk::{
|
||||
feature_set, instruction::InstructionError, keyed_account::keyed_account_at_index,
|
||||
program_utils::limited_deserialize,
|
||||
},
|
||||
solana_sdk::{feature_set, instruction::InstructionError, program_utils::limited_deserialize},
|
||||
};
|
||||
|
||||
pub fn process_instruction(
|
||||
|
@ -20,13 +17,12 @@ pub fn process_instruction(
|
|||
let transaction_context = &invoke_context.transaction_context;
|
||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||
let data = instruction_context.get_instruction_data();
|
||||
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
||||
|
||||
trace!("process_instruction: {:?}", data);
|
||||
trace!("keyed_accounts: {:?}", keyed_accounts);
|
||||
|
||||
let me = &mut keyed_account_at_index(keyed_accounts, first_instruction_account)?;
|
||||
if me.owner()? != id() {
|
||||
let mut me =
|
||||
instruction_context.try_borrow_account(transaction_context, first_instruction_account)?;
|
||||
if *me.get_owner() != id() {
|
||||
return Err(InstructionError::InvalidAccountOwner);
|
||||
}
|
||||
|
||||
|
@ -34,18 +30,18 @@ pub fn process_instruction(
|
|||
match limited_deserialize(data)? {
|
||||
VoteInstruction::InitializeAccount(vote_init) => {
|
||||
let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 1)?;
|
||||
if !rent.is_exempt(me.lamports()?, me.data_len()?) {
|
||||
if !rent.is_exempt(me.get_lamports(), me.get_data().len()) {
|
||||
return Err(InstructionError::InsufficientFunds);
|
||||
}
|
||||
let clock =
|
||||
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?;
|
||||
vote_state::initialize_account(me, &vote_init, &signers, &clock)
|
||||
vote_state::initialize_account(&mut me, &vote_init, &signers, &clock)
|
||||
}
|
||||
VoteInstruction::Authorize(voter_pubkey, vote_authorize) => {
|
||||
let clock =
|
||||
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?;
|
||||
vote_state::authorize(
|
||||
me,
|
||||
&mut me,
|
||||
&voter_pubkey,
|
||||
vote_authorize,
|
||||
&signers,
|
||||
|
@ -55,15 +51,13 @@ pub fn process_instruction(
|
|||
}
|
||||
VoteInstruction::UpdateValidatorIdentity => {
|
||||
instruction_context.check_number_of_instruction_accounts(2)?;
|
||||
vote_state::update_validator_identity(
|
||||
me,
|
||||
keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?
|
||||
.unsigned_key(),
|
||||
&signers,
|
||||
)
|
||||
let node_pubkey = transaction_context.get_key_of_account_at_index(
|
||||
instruction_context.get_index_in_transaction(first_instruction_account + 1)?,
|
||||
)?;
|
||||
vote_state::update_validator_identity(&mut me, node_pubkey, &signers)
|
||||
}
|
||||
VoteInstruction::UpdateCommission(commission) => {
|
||||
vote_state::update_commission(me, commission, &signers)
|
||||
vote_state::update_commission(&mut me, commission, &signers)
|
||||
}
|
||||
VoteInstruction::Vote(vote) | VoteInstruction::VoteSwitch(vote, _) => {
|
||||
inc_new_counter_info!("vote-native", 1);
|
||||
|
@ -72,7 +66,7 @@ pub fn process_instruction(
|
|||
let clock =
|
||||
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?;
|
||||
vote_state::process_vote(
|
||||
me,
|
||||
&mut me,
|
||||
&slot_hashes,
|
||||
&clock,
|
||||
&vote,
|
||||
|
@ -91,7 +85,7 @@ pub fn process_instruction(
|
|||
let slot_hashes = sysvar_cache.get_slot_hashes()?;
|
||||
let clock = sysvar_cache.get_clock()?;
|
||||
vote_state::process_vote_state_update(
|
||||
me,
|
||||
&mut me,
|
||||
slot_hashes.slot_hashes(),
|
||||
&clock,
|
||||
vote_state_update,
|
||||
|
@ -103,7 +97,6 @@ pub fn process_instruction(
|
|||
}
|
||||
VoteInstruction::Withdraw(lamports) => {
|
||||
instruction_context.check_number_of_instruction_accounts(2)?;
|
||||
let to = keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?;
|
||||
let rent_sysvar = if invoke_context
|
||||
.feature_set
|
||||
.is_active(&feature_set::reject_non_rent_exempt_vote_withdraws::id())
|
||||
|
@ -122,10 +115,13 @@ pub fn process_instruction(
|
|||
None
|
||||
};
|
||||
|
||||
drop(me);
|
||||
vote_state::withdraw(
|
||||
me,
|
||||
transaction_context,
|
||||
instruction_context,
|
||||
first_instruction_account,
|
||||
lamports,
|
||||
to,
|
||||
first_instruction_account + 1,
|
||||
&signers,
|
||||
rent_sysvar.as_deref(),
|
||||
clock_if_feature_active.as_deref(),
|
||||
|
@ -137,14 +133,16 @@ pub fn process_instruction(
|
|||
.is_active(&feature_set::vote_stake_checked_instructions::id())
|
||||
{
|
||||
instruction_context.check_number_of_instruction_accounts(4)?;
|
||||
let voter_pubkey =
|
||||
&keyed_account_at_index(keyed_accounts, first_instruction_account + 3)?
|
||||
.signer_key()
|
||||
.ok_or(InstructionError::MissingRequiredSignature)?;
|
||||
let voter_pubkey = transaction_context.get_key_of_account_at_index(
|
||||
instruction_context.get_index_in_transaction(first_instruction_account + 3)?,
|
||||
)?;
|
||||
if !instruction_context.is_signer(first_instruction_account + 3)? {
|
||||
return Err(InstructionError::MissingRequiredSignature);
|
||||
}
|
||||
let clock =
|
||||
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?;
|
||||
vote_state::authorize(
|
||||
me,
|
||||
&mut me,
|
||||
voter_pubkey,
|
||||
vote_authorize,
|
||||
&signers,
|
||||
|
|
|
@ -7,17 +7,16 @@ use {
|
|||
serde_derive::{Deserialize, Serialize},
|
||||
solana_sdk::{
|
||||
account::{AccountSharedData, ReadableAccount, WritableAccount},
|
||||
account_utils::State,
|
||||
clock::{Epoch, Slot, UnixTimestamp},
|
||||
epoch_schedule::MAX_LEADER_SCHEDULE_EPOCH_OFFSET,
|
||||
feature_set::{self, filter_votes_outside_slot_hashes, FeatureSet},
|
||||
hash::Hash,
|
||||
instruction::InstructionError,
|
||||
keyed_account::KeyedAccount,
|
||||
pubkey::Pubkey,
|
||||
rent::Rent,
|
||||
slot_hashes::SlotHash,
|
||||
sysvar::clock::Clock,
|
||||
transaction_context::{BorrowedAccount, InstructionContext, TransactionContext},
|
||||
},
|
||||
std::{
|
||||
cmp::Ordering,
|
||||
|
@ -1165,15 +1164,16 @@ impl VoteState {
|
|||
/// but will implicitly withdraw authorization from the previously authorized
|
||||
/// key
|
||||
pub fn authorize<S: std::hash::BuildHasher>(
|
||||
vote_account: &KeyedAccount,
|
||||
vote_account: &mut BorrowedAccount,
|
||||
authorized: &Pubkey,
|
||||
vote_authorize: VoteAuthorize,
|
||||
signers: &HashSet<Pubkey, S>,
|
||||
clock: &Clock,
|
||||
feature_set: &FeatureSet,
|
||||
) -> Result<(), InstructionError> {
|
||||
let mut vote_state: VoteState =
|
||||
State::<VoteStateVersions>::state(vote_account)?.convert_to_current();
|
||||
let mut vote_state: VoteState = vote_account
|
||||
.get_state::<VoteStateVersions>()?
|
||||
.convert_to_current();
|
||||
|
||||
match vote_authorize {
|
||||
VoteAuthorize::Voter => {
|
||||
|
@ -1211,12 +1211,13 @@ pub fn authorize<S: std::hash::BuildHasher>(
|
|||
|
||||
/// Update the node_pubkey, requires signature of the authorized voter
|
||||
pub fn update_validator_identity<S: std::hash::BuildHasher>(
|
||||
vote_account: &KeyedAccount,
|
||||
vote_account: &mut BorrowedAccount,
|
||||
node_pubkey: &Pubkey,
|
||||
signers: &HashSet<Pubkey, S>,
|
||||
) -> Result<(), InstructionError> {
|
||||
let mut vote_state: VoteState =
|
||||
State::<VoteStateVersions>::state(vote_account)?.convert_to_current();
|
||||
let mut vote_state: VoteState = vote_account
|
||||
.get_state::<VoteStateVersions>()?
|
||||
.convert_to_current();
|
||||
|
||||
// current authorized withdrawer must say "yay"
|
||||
verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?;
|
||||
|
@ -1231,12 +1232,13 @@ pub fn update_validator_identity<S: std::hash::BuildHasher>(
|
|||
|
||||
/// Update the vote account's commission
|
||||
pub fn update_commission<S: std::hash::BuildHasher>(
|
||||
vote_account: &KeyedAccount,
|
||||
vote_account: &mut BorrowedAccount,
|
||||
commission: u8,
|
||||
signers: &HashSet<Pubkey, S>,
|
||||
) -> Result<(), InstructionError> {
|
||||
let mut vote_state: VoteState =
|
||||
State::<VoteStateVersions>::state(vote_account)?.convert_to_current();
|
||||
let mut vote_state: VoteState = vote_account
|
||||
.get_state::<VoteStateVersions>()?
|
||||
.convert_to_current();
|
||||
|
||||
// current authorized withdrawer must say "yay"
|
||||
verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?;
|
||||
|
@ -1259,20 +1261,25 @@ fn verify_authorized_signer<S: std::hash::BuildHasher>(
|
|||
|
||||
/// Withdraw funds from the vote account
|
||||
pub fn withdraw<S: std::hash::BuildHasher>(
|
||||
vote_account: &KeyedAccount,
|
||||
transaction_context: &TransactionContext,
|
||||
instruction_context: &InstructionContext,
|
||||
vote_account_index: usize,
|
||||
lamports: u64,
|
||||
to_account: &KeyedAccount,
|
||||
to_account_index: usize,
|
||||
signers: &HashSet<Pubkey, S>,
|
||||
rent_sysvar: Option<&Rent>,
|
||||
clock: Option<&Clock>,
|
||||
) -> Result<(), InstructionError> {
|
||||
let vote_state: VoteState =
|
||||
State::<VoteStateVersions>::state(vote_account)?.convert_to_current();
|
||||
let mut vote_account =
|
||||
instruction_context.try_borrow_account(transaction_context, vote_account_index)?;
|
||||
let vote_state: VoteState = vote_account
|
||||
.get_state::<VoteStateVersions>()?
|
||||
.convert_to_current();
|
||||
|
||||
verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?;
|
||||
|
||||
let remaining_balance = vote_account
|
||||
.lamports()?
|
||||
.get_lamports()
|
||||
.checked_sub(lamports)
|
||||
.ok_or(InstructionError::InsufficientFunds)?;
|
||||
|
||||
|
@ -1295,18 +1302,17 @@ pub fn withdraw<S: std::hash::BuildHasher>(
|
|||
vote_account.set_state(&VoteStateVersions::new_current(VoteState::default()))?;
|
||||
}
|
||||
} else if let Some(rent_sysvar) = rent_sysvar {
|
||||
let min_rent_exempt_balance = rent_sysvar.minimum_balance(vote_account.data_len()?);
|
||||
let min_rent_exempt_balance = rent_sysvar.minimum_balance(vote_account.get_data().len());
|
||||
if remaining_balance < min_rent_exempt_balance {
|
||||
return Err(InstructionError::InsufficientFunds);
|
||||
}
|
||||
}
|
||||
|
||||
vote_account
|
||||
.try_account_ref_mut()?
|
||||
.checked_sub_lamports(lamports)?;
|
||||
to_account
|
||||
.try_account_ref_mut()?
|
||||
.checked_add_lamports(lamports)?;
|
||||
vote_account.checked_sub_lamports(lamports)?;
|
||||
drop(vote_account);
|
||||
let mut to_account =
|
||||
instruction_context.try_borrow_account(transaction_context, to_account_index)?;
|
||||
to_account.checked_add_lamports(lamports)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -1314,15 +1320,15 @@ pub fn withdraw<S: std::hash::BuildHasher>(
|
|||
/// Assumes that the account is being init as part of a account creation or balance transfer and
|
||||
/// that the transaction must be signed by the staker's keys
|
||||
pub fn initialize_account<S: std::hash::BuildHasher>(
|
||||
vote_account: &KeyedAccount,
|
||||
vote_account: &mut BorrowedAccount,
|
||||
vote_init: &VoteInit,
|
||||
signers: &HashSet<Pubkey, S>,
|
||||
clock: &Clock,
|
||||
) -> Result<(), InstructionError> {
|
||||
if vote_account.data_len()? != VoteState::size_of() {
|
||||
if vote_account.get_data().len() != VoteState::size_of() {
|
||||
return Err(InstructionError::InvalidAccountData);
|
||||
}
|
||||
let versioned = State::<VoteStateVersions>::state(vote_account)?;
|
||||
let versioned = vote_account.get_state::<VoteStateVersions>()?;
|
||||
|
||||
if !versioned.is_uninitialized() {
|
||||
return Err(InstructionError::AccountAlreadyInitialized);
|
||||
|
@ -1337,11 +1343,11 @@ pub fn initialize_account<S: std::hash::BuildHasher>(
|
|||
}
|
||||
|
||||
fn verify_and_get_vote_state<S: std::hash::BuildHasher>(
|
||||
vote_account: &KeyedAccount,
|
||||
vote_account: &BorrowedAccount,
|
||||
clock: &Clock,
|
||||
signers: &HashSet<Pubkey, S>,
|
||||
) -> Result<VoteState, InstructionError> {
|
||||
let versioned = State::<VoteStateVersions>::state(vote_account)?;
|
||||
let versioned = vote_account.get_state::<VoteStateVersions>()?;
|
||||
|
||||
if versioned.is_uninitialized() {
|
||||
return Err(InstructionError::UninitializedAccount);
|
||||
|
@ -1355,7 +1361,7 @@ fn verify_and_get_vote_state<S: std::hash::BuildHasher>(
|
|||
}
|
||||
|
||||
pub fn process_vote<S: std::hash::BuildHasher>(
|
||||
vote_account: &KeyedAccount,
|
||||
vote_account: &mut BorrowedAccount,
|
||||
slot_hashes: &[SlotHash],
|
||||
clock: &Clock,
|
||||
vote: &Vote,
|
||||
|
@ -1376,7 +1382,7 @@ pub fn process_vote<S: std::hash::BuildHasher>(
|
|||
}
|
||||
|
||||
pub fn process_vote_state_update<S: std::hash::BuildHasher>(
|
||||
vote_account: &KeyedAccount,
|
||||
vote_account: &mut BorrowedAccount,
|
||||
slot_hashes: &[SlotHash],
|
||||
clock: &Clock,
|
||||
mut vote_state_update: VoteStateUpdate,
|
||||
|
|
Loading…
Reference in New Issue