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