Replaces `KeyedAccount` by `BorrowedAccount` in vote processor (#23348)
* Use instruction_account_indices, get_sysvar_with_account_check2 and instruction_context.get_signers in vote processor. * Replaces KeyedAccount by BorrowedAccount in vote processor. * Removes KeyedAccount from benches in vote processor.
This commit is contained in:
parent
533eca3b4c
commit
e2fa6a0f7a
|
@ -7,36 +7,30 @@ use {
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
account::{create_account_for_test, Account, AccountSharedData},
|
account::{create_account_for_test, Account, AccountSharedData},
|
||||||
clock::{Clock, Slot},
|
clock::{Clock, Slot},
|
||||||
feature_set::FeatureSet,
|
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
instruction::{AccountMeta, Instruction},
|
|
||||||
keyed_account::KeyedAccount,
|
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
slot_hashes::{SlotHashes, MAX_ENTRIES},
|
slot_hashes::{SlotHashes, MAX_ENTRIES},
|
||||||
sysvar,
|
sysvar,
|
||||||
transaction_context::{InstructionAccount, TransactionContext},
|
transaction_context::{InstructionAccount, TransactionAccount, TransactionContext},
|
||||||
},
|
},
|
||||||
solana_vote_program::{
|
solana_vote_program::{
|
||||||
vote_instruction::VoteInstruction,
|
vote_instruction::VoteInstruction,
|
||||||
vote_state::{
|
vote_state::{
|
||||||
self, Vote, VoteInit, VoteState, VoteStateUpdate, VoteStateVersions,
|
Vote, VoteInit, VoteState, VoteStateUpdate, VoteStateVersions, MAX_LOCKOUT_HISTORY,
|
||||||
MAX_LOCKOUT_HISTORY,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
std::{cell::RefCell, collections::HashSet, sync::Arc},
|
|
||||||
test::Bencher,
|
test::Bencher,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VoteComponents {
|
fn create_accounts() -> (
|
||||||
slot_hashes: SlotHashes,
|
Slot,
|
||||||
clock: Clock,
|
SlotHashes,
|
||||||
signers: HashSet<Pubkey>,
|
Vec<TransactionAccount>,
|
||||||
authority_pubkey: Pubkey,
|
Vec<InstructionAccount>,
|
||||||
vote_pubkey: Pubkey,
|
) {
|
||||||
vote_account: Account,
|
// vote accounts are usually almost full of votes in normal operation
|
||||||
}
|
let num_initial_votes = MAX_LOCKOUT_HISTORY as Slot;
|
||||||
|
|
||||||
fn create_components(num_initial_votes: Slot) -> VoteComponents {
|
|
||||||
let clock = Clock::default();
|
let clock = Clock::default();
|
||||||
let mut slot_hashes = SlotHashes::new(&[]);
|
let mut slot_hashes = SlotHashes::new(&[]);
|
||||||
for i in 0..MAX_ENTRIES {
|
for i in 0..MAX_ENTRIES {
|
||||||
|
@ -46,7 +40,6 @@ fn create_components(num_initial_votes: Slot) -> VoteComponents {
|
||||||
|
|
||||||
let vote_pubkey = Pubkey::new_unique();
|
let vote_pubkey = Pubkey::new_unique();
|
||||||
let authority_pubkey = Pubkey::new_unique();
|
let authority_pubkey = Pubkey::new_unique();
|
||||||
let signers: HashSet<Pubkey> = vec![authority_pubkey].into_iter().collect();
|
|
||||||
let vote_account = {
|
let vote_account = {
|
||||||
let mut vote_state = VoteState::new(
|
let mut vote_state = VoteState::new(
|
||||||
&VoteInit {
|
&VoteInit {
|
||||||
|
@ -62,7 +55,7 @@ fn create_components(num_initial_votes: Slot) -> VoteComponents {
|
||||||
vote_state.process_next_vote_slot(next_vote_slot, 0);
|
vote_state.process_next_vote_slot(next_vote_slot, 0);
|
||||||
}
|
}
|
||||||
let mut vote_account_data: Vec<u8> = vec![0; VoteState::size_of()];
|
let mut vote_account_data: Vec<u8> = vec![0; VoteState::size_of()];
|
||||||
let versioned = VoteStateVersions::new_current(vote_state.clone());
|
let versioned = VoteStateVersions::new_current(vote_state);
|
||||||
VoteState::serialize(&versioned, &mut vote_account_data).unwrap();
|
VoteState::serialize(&versioned, &mut vote_account_data).unwrap();
|
||||||
|
|
||||||
Account {
|
Account {
|
||||||
|
@ -74,131 +67,65 @@ fn create_components(num_initial_votes: Slot) -> VoteComponents {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
VoteComponents {
|
let transaction_accounts = vec![
|
||||||
|
(solana_vote_program::id(), AccountSharedData::default()),
|
||||||
|
(vote_pubkey, AccountSharedData::from(vote_account)),
|
||||||
|
(
|
||||||
|
sysvar::slot_hashes::id(),
|
||||||
|
AccountSharedData::from(create_account_for_test(&slot_hashes)),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
sysvar::clock::id(),
|
||||||
|
AccountSharedData::from(create_account_for_test(&clock)),
|
||||||
|
),
|
||||||
|
(authority_pubkey, AccountSharedData::default()),
|
||||||
|
];
|
||||||
|
let mut instruction_accounts = (0..4)
|
||||||
|
.map(|index| InstructionAccount {
|
||||||
|
index_in_transaction: 1usize.saturating_add(index),
|
||||||
|
index_in_caller: 1usize.saturating_add(index),
|
||||||
|
is_signer: false,
|
||||||
|
is_writable: false,
|
||||||
|
})
|
||||||
|
.collect::<Vec<InstructionAccount>>();
|
||||||
|
instruction_accounts[0].is_writable = true;
|
||||||
|
instruction_accounts[3].is_signer = true;
|
||||||
|
|
||||||
|
(
|
||||||
|
num_initial_votes,
|
||||||
slot_hashes,
|
slot_hashes,
|
||||||
clock,
|
transaction_accounts,
|
||||||
signers,
|
instruction_accounts,
|
||||||
authority_pubkey,
|
)
|
||||||
vote_pubkey,
|
|
||||||
vote_account,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `feature` can be used to change vote program behavior per bench run.
|
fn bench_process_vote_instruction(
|
||||||
fn do_bench_process_vote_instruction(bencher: &mut Bencher, feature: Option<Pubkey>) {
|
bencher: &mut Bencher,
|
||||||
// vote accounts are usually almost full of votes in normal operation
|
transaction_accounts: Vec<TransactionAccount>,
|
||||||
let num_initial_votes = MAX_LOCKOUT_HISTORY as Slot;
|
instruction_accounts: Vec<InstructionAccount>,
|
||||||
|
instruction_data: Vec<u8>,
|
||||||
let VoteComponents {
|
) {
|
||||||
slot_hashes,
|
|
||||||
clock,
|
|
||||||
authority_pubkey,
|
|
||||||
vote_pubkey,
|
|
||||||
vote_account,
|
|
||||||
..
|
|
||||||
} = create_components(num_initial_votes);
|
|
||||||
|
|
||||||
let slot_hashes_account = create_account_for_test(&slot_hashes);
|
|
||||||
let clock_account = create_account_for_test(&clock);
|
|
||||||
let authority_account = Account::default();
|
|
||||||
|
|
||||||
let mut feature_set = FeatureSet::all_enabled();
|
|
||||||
if let Some(feature) = feature {
|
|
||||||
feature_set.activate(&feature, 0);
|
|
||||||
}
|
|
||||||
let feature_set = Arc::new(feature_set);
|
|
||||||
|
|
||||||
let num_vote_slots = 4;
|
|
||||||
let last_vote_slot = num_initial_votes
|
|
||||||
.saturating_add(num_vote_slots)
|
|
||||||
.saturating_sub(1);
|
|
||||||
let last_vote_hash = slot_hashes
|
|
||||||
.iter()
|
|
||||||
.find(|(slot, _hash)| *slot == last_vote_slot)
|
|
||||||
.unwrap()
|
|
||||||
.1;
|
|
||||||
|
|
||||||
let vote_ix_data = bincode::serialize(&VoteInstruction::Vote(Vote::new(
|
|
||||||
(num_initial_votes..=last_vote_slot).collect(),
|
|
||||||
last_vote_hash,
|
|
||||||
)))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let instruction = Instruction {
|
|
||||||
program_id: solana_vote_program::id(),
|
|
||||||
data: vote_ix_data,
|
|
||||||
accounts: vec![
|
|
||||||
AccountMeta::new(vote_pubkey, false),
|
|
||||||
AccountMeta::new_readonly(sysvar::slot_hashes::id(), false),
|
|
||||||
AccountMeta::new_readonly(sysvar::clock::id(), false),
|
|
||||||
AccountMeta::new_readonly(authority_pubkey, true),
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
let program_indices = vec![4];
|
|
||||||
let instruction_accounts = instruction
|
|
||||||
.accounts
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(index_in_transaction, account_meta)| InstructionAccount {
|
|
||||||
index_in_transaction,
|
|
||||||
index_in_caller: index_in_transaction,
|
|
||||||
is_signer: account_meta.is_signer,
|
|
||||||
is_writable: account_meta.is_writable,
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
bencher.iter(|| {
|
bencher.iter(|| {
|
||||||
let mut transaction_context = TransactionContext::new(
|
let mut transaction_context = TransactionContext::new(transaction_accounts.clone(), 1, 1);
|
||||||
vec![
|
|
||||||
(vote_pubkey, AccountSharedData::from(vote_account.clone())),
|
|
||||||
(
|
|
||||||
sysvar::slot_hashes::id(),
|
|
||||||
AccountSharedData::from(slot_hashes_account.clone()),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
sysvar::clock::id(),
|
|
||||||
AccountSharedData::from(clock_account.clone()),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
authority_pubkey,
|
|
||||||
AccountSharedData::from(authority_account.clone()),
|
|
||||||
),
|
|
||||||
(solana_vote_program::id(), AccountSharedData::default()),
|
|
||||||
],
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
|
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
|
||||||
invoke_context.feature_set = feature_set.clone();
|
|
||||||
invoke_context
|
invoke_context
|
||||||
.push(&instruction_accounts, &program_indices, &[])
|
.push(&instruction_accounts, &[0], &instruction_data)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let first_instruction_account = 1;
|
|
||||||
assert!(solana_vote_program::vote_processor::process_instruction(
|
assert!(solana_vote_program::vote_processor::process_instruction(
|
||||||
first_instruction_account,
|
1,
|
||||||
&instruction.data,
|
&instruction_data,
|
||||||
&mut invoke_context
|
&mut invoke_context
|
||||||
)
|
)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
|
invoke_context.pop().unwrap();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `feature` can be used to change vote program behavior per bench run.
|
#[bench]
|
||||||
fn do_bench_process_vote(bencher: &mut Bencher, feature: Option<Pubkey>) {
|
#[ignore]
|
||||||
// vote accounts are usually almost full of votes in normal operation
|
fn bench_process_vote(bencher: &mut Bencher) {
|
||||||
let num_initial_votes = MAX_LOCKOUT_HISTORY as Slot;
|
let (num_initial_votes, slot_hashes, transaction_accounts, instruction_accounts) =
|
||||||
|
create_accounts();
|
||||||
let VoteComponents {
|
|
||||||
slot_hashes,
|
|
||||||
clock,
|
|
||||||
signers,
|
|
||||||
vote_pubkey,
|
|
||||||
vote_account,
|
|
||||||
..
|
|
||||||
} = create_components(num_initial_votes);
|
|
||||||
|
|
||||||
let num_vote_slots = 4;
|
let num_vote_slots = 4;
|
||||||
let last_vote_slot = num_initial_votes
|
let last_vote_slot = num_initial_votes
|
||||||
|
@ -209,45 +136,25 @@ fn do_bench_process_vote(bencher: &mut Bencher, feature: Option<Pubkey>) {
|
||||||
.find(|(slot, _hash)| *slot == last_vote_slot)
|
.find(|(slot, _hash)| *slot == last_vote_slot)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.1;
|
.1;
|
||||||
|
|
||||||
let vote = Vote::new(
|
let vote = Vote::new(
|
||||||
(num_initial_votes..=last_vote_slot).collect(),
|
(num_initial_votes..=last_vote_slot).collect(),
|
||||||
last_vote_hash,
|
last_vote_hash,
|
||||||
);
|
);
|
||||||
|
let instruction_data = bincode::serialize(&VoteInstruction::Vote(vote)).unwrap();
|
||||||
|
|
||||||
let mut feature_set = FeatureSet::all_enabled();
|
bench_process_vote_instruction(
|
||||||
if let Some(feature) = feature {
|
bencher,
|
||||||
feature_set.activate(&feature, 0);
|
transaction_accounts,
|
||||||
}
|
instruction_accounts,
|
||||||
let feature_set = Arc::new(feature_set);
|
instruction_data,
|
||||||
|
);
|
||||||
bencher.iter(|| {
|
|
||||||
let vote_account = RefCell::new(AccountSharedData::from(vote_account.clone()));
|
|
||||||
let keyed_account = KeyedAccount::new(&vote_pubkey, true, &vote_account);
|
|
||||||
assert!(vote_state::process_vote(
|
|
||||||
&keyed_account,
|
|
||||||
&slot_hashes,
|
|
||||||
&clock,
|
|
||||||
&vote,
|
|
||||||
&signers,
|
|
||||||
&feature_set,
|
|
||||||
)
|
|
||||||
.is_ok());
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_bench_process_vote_state_update(bencher: &mut Bencher) {
|
#[bench]
|
||||||
// vote accounts are usually almost full of votes in normal operation
|
#[ignore]
|
||||||
let num_initial_votes = MAX_LOCKOUT_HISTORY as Slot;
|
fn bench_process_vote_state_update(bencher: &mut Bencher) {
|
||||||
|
let (num_initial_votes, slot_hashes, transaction_accounts, instruction_accounts) =
|
||||||
let VoteComponents {
|
create_accounts();
|
||||||
slot_hashes,
|
|
||||||
clock,
|
|
||||||
signers,
|
|
||||||
vote_pubkey,
|
|
||||||
vote_account,
|
|
||||||
..
|
|
||||||
} = create_components(num_initial_votes);
|
|
||||||
|
|
||||||
let num_vote_slots = MAX_LOCKOUT_HISTORY as Slot;
|
let num_vote_slots = MAX_LOCKOUT_HISTORY as Slot;
|
||||||
let last_vote_slot = num_initial_votes
|
let last_vote_slot = num_initial_votes
|
||||||
|
@ -258,46 +165,18 @@ fn do_bench_process_vote_state_update(bencher: &mut Bencher) {
|
||||||
.find(|(slot, _hash)| *slot == last_vote_slot)
|
.find(|(slot, _hash)| *slot == last_vote_slot)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.1;
|
.1;
|
||||||
|
|
||||||
let slots_and_lockouts: Vec<(Slot, u32)> =
|
let slots_and_lockouts: Vec<(Slot, u32)> =
|
||||||
((num_initial_votes.saturating_add(1)..=last_vote_slot).zip((1u32..=31).rev())).collect();
|
((num_initial_votes.saturating_add(1)..=last_vote_slot).zip((1u32..=31).rev())).collect();
|
||||||
|
|
||||||
let mut vote_state_update = VoteStateUpdate::from(slots_and_lockouts);
|
let mut vote_state_update = VoteStateUpdate::from(slots_and_lockouts);
|
||||||
vote_state_update.root = Some(num_initial_votes);
|
vote_state_update.root = Some(num_initial_votes);
|
||||||
|
|
||||||
vote_state_update.hash = last_vote_hash;
|
vote_state_update.hash = last_vote_hash;
|
||||||
|
let instruction_data =
|
||||||
|
bincode::serialize(&VoteInstruction::UpdateVoteState(vote_state_update)).unwrap();
|
||||||
|
|
||||||
bencher.iter(|| {
|
bench_process_vote_instruction(
|
||||||
let vote_account = RefCell::new(AccountSharedData::from(vote_account.clone()));
|
bencher,
|
||||||
let keyed_account = KeyedAccount::new(&vote_pubkey, true, &vote_account);
|
transaction_accounts,
|
||||||
let vote_state_update = vote_state_update.clone();
|
instruction_accounts,
|
||||||
assert!(vote_state::process_vote_state_update(
|
instruction_data,
|
||||||
&keyed_account,
|
);
|
||||||
&slot_hashes,
|
|
||||||
&clock,
|
|
||||||
vote_state_update,
|
|
||||||
&signers,
|
|
||||||
)
|
|
||||||
.is_ok());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bench]
|
|
||||||
#[ignore]
|
|
||||||
fn bench_process_vote_instruction(bencher: &mut Bencher) {
|
|
||||||
do_bench_process_vote_instruction(bencher, None);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Benches a specific type of vote instruction
|
|
||||||
#[bench]
|
|
||||||
#[ignore]
|
|
||||||
fn bench_process_vote(bencher: &mut Bencher) {
|
|
||||||
do_bench_process_vote(bencher, None);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Benches a specific type of vote instruction
|
|
||||||
#[bench]
|
|
||||||
#[ignore]
|
|
||||||
fn bench_process_vote_state_update(bencher: &mut Bencher) {
|
|
||||||
do_bench_process_vote_state_update(bencher);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,87 +5,157 @@ use {
|
||||||
log::*,
|
log::*,
|
||||||
solana_metrics::inc_new_counter_info,
|
solana_metrics::inc_new_counter_info,
|
||||||
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_check2,
|
||||||
},
|
},
|
||||||
solana_sdk::{
|
solana_sdk::{feature_set, instruction::InstructionError, program_utils::limited_deserialize},
|
||||||
feature_set,
|
|
||||||
instruction::InstructionError,
|
|
||||||
keyed_account::{get_signers, keyed_account_at_index, KeyedAccount},
|
|
||||||
program_utils::limited_deserialize,
|
|
||||||
pubkey::Pubkey,
|
|
||||||
sysvar::rent::Rent,
|
|
||||||
},
|
|
||||||
std::collections::HashSet,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub mod instruction_account_indices {
|
||||||
|
pub enum InitializeAccount {
|
||||||
|
VoteAccount = 0,
|
||||||
|
Rent = 1,
|
||||||
|
Clock = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Authorize {
|
||||||
|
VoteAccount = 0,
|
||||||
|
Clock = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum UpdateValidatorIdentity {
|
||||||
|
VoteAccount = 0,
|
||||||
|
Node = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum UpdateCommission {
|
||||||
|
VoteAccount = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Vote {
|
||||||
|
VoteAccount = 0,
|
||||||
|
SlotHashes = 1,
|
||||||
|
Clock = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum UpdateVoteState {
|
||||||
|
VoteAccount = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Withdraw {
|
||||||
|
VoteAccount = 0,
|
||||||
|
Recipient = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum AuthorizeChecked {
|
||||||
|
VoteAccount = 0,
|
||||||
|
Clock = 1,
|
||||||
|
// Ignores = 2,
|
||||||
|
Voter = 3,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn process_instruction(
|
pub fn process_instruction(
|
||||||
first_instruction_account: usize,
|
_first_instruction_account: usize,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
|
|
||||||
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)?;
|
{
|
||||||
if me.owner()? != id() {
|
let vote_account =
|
||||||
return Err(InstructionError::InvalidAccountOwner);
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
|
if vote_account.get_owner() != &id() {
|
||||||
|
return Err(InstructionError::InvalidAccountOwner);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let signers: HashSet<Pubkey> = get_signers(&keyed_accounts[first_instruction_account..]);
|
let signers = instruction_context.get_signers(transaction_context);
|
||||||
match limited_deserialize(data)? {
|
match limited_deserialize(data)? {
|
||||||
VoteInstruction::InitializeAccount(vote_init) => {
|
VoteInstruction::InitializeAccount(vote_init) => {
|
||||||
let rent = get_sysvar_with_account_check::rent(
|
let rent = get_sysvar_with_account_check2::rent(
|
||||||
keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?,
|
|
||||||
invoke_context,
|
invoke_context,
|
||||||
|
instruction_context,
|
||||||
|
instruction_account_indices::InitializeAccount::Rent as usize,
|
||||||
)?;
|
)?;
|
||||||
verify_rent_exemption(me, &rent)?;
|
{
|
||||||
let clock = get_sysvar_with_account_check::clock(
|
// Verify rent exemption
|
||||||
keyed_account_at_index(keyed_accounts, first_instruction_account + 2)?,
|
let vote_account = instruction_context.try_borrow_instruction_account(
|
||||||
|
transaction_context,
|
||||||
|
instruction_account_indices::InitializeAccount::VoteAccount as usize,
|
||||||
|
)?;
|
||||||
|
if !rent.is_exempt(vote_account.get_lamports(), vote_account.get_data().len()) {
|
||||||
|
return Err(InstructionError::InsufficientFunds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let _clock = get_sysvar_with_account_check2::clock(
|
||||||
invoke_context,
|
invoke_context,
|
||||||
|
instruction_context,
|
||||||
|
instruction_account_indices::InitializeAccount::Clock as usize,
|
||||||
)?;
|
)?;
|
||||||
vote_state::initialize_account(me, &vote_init, &signers, &clock)
|
vote_state::initialize_account(
|
||||||
}
|
|
||||||
VoteInstruction::Authorize(voter_pubkey, vote_authorize) => {
|
|
||||||
let clock = get_sysvar_with_account_check::clock(
|
|
||||||
keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?,
|
|
||||||
invoke_context,
|
invoke_context,
|
||||||
)?;
|
instruction_context,
|
||||||
vote_state::authorize(
|
|
||||||
me,
|
|
||||||
&voter_pubkey,
|
|
||||||
vote_authorize,
|
|
||||||
&signers,
|
&signers,
|
||||||
&clock,
|
instruction_account_indices::InitializeAccount::VoteAccount as usize,
|
||||||
&invoke_context.feature_set,
|
&vote_init,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
VoteInstruction::UpdateValidatorIdentity => vote_state::update_validator_identity(
|
VoteInstruction::Authorize(voter_pubkey, vote_authorize) => {
|
||||||
me,
|
let _clock = get_sysvar_with_account_check2::clock(
|
||||||
keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?.unsigned_key(),
|
invoke_context,
|
||||||
&signers,
|
instruction_context,
|
||||||
),
|
instruction_account_indices::Authorize::Clock as usize,
|
||||||
VoteInstruction::UpdateCommission(commission) => {
|
)?;
|
||||||
vote_state::update_commission(me, commission, &signers)
|
vote_state::authorize(
|
||||||
|
invoke_context,
|
||||||
|
instruction_context,
|
||||||
|
&signers,
|
||||||
|
instruction_account_indices::Authorize::VoteAccount as usize,
|
||||||
|
&voter_pubkey,
|
||||||
|
vote_authorize,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
VoteInstruction::UpdateValidatorIdentity => {
|
||||||
|
instruction_context.check_number_of_instruction_accounts(2)?;
|
||||||
|
vote_state::update_validator_identity(
|
||||||
|
invoke_context,
|
||||||
|
instruction_context,
|
||||||
|
&signers,
|
||||||
|
instruction_account_indices::UpdateValidatorIdentity::VoteAccount as usize,
|
||||||
|
instruction_context.get_instruction_account_key(
|
||||||
|
transaction_context,
|
||||||
|
instruction_account_indices::UpdateValidatorIdentity::Node as usize,
|
||||||
|
)?,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
VoteInstruction::UpdateCommission(commission) => vote_state::update_commission(
|
||||||
|
invoke_context,
|
||||||
|
instruction_context,
|
||||||
|
&signers,
|
||||||
|
instruction_account_indices::UpdateCommission::VoteAccount as usize,
|
||||||
|
commission,
|
||||||
|
),
|
||||||
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);
|
||||||
let slot_hashes = get_sysvar_with_account_check::slot_hashes(
|
let _slot_hashes = get_sysvar_with_account_check2::slot_hashes(
|
||||||
keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?,
|
|
||||||
invoke_context,
|
invoke_context,
|
||||||
|
instruction_context,
|
||||||
|
instruction_account_indices::Vote::SlotHashes as usize,
|
||||||
)?;
|
)?;
|
||||||
let clock = get_sysvar_with_account_check::clock(
|
let _clock = get_sysvar_with_account_check2::clock(
|
||||||
keyed_account_at_index(keyed_accounts, first_instruction_account + 2)?,
|
|
||||||
invoke_context,
|
invoke_context,
|
||||||
|
instruction_context,
|
||||||
|
instruction_account_indices::Vote::Clock as usize,
|
||||||
)?;
|
)?;
|
||||||
vote_state::process_vote(
|
vote_state::process_vote(
|
||||||
me,
|
invoke_context,
|
||||||
&slot_hashes,
|
instruction_context,
|
||||||
&clock,
|
|
||||||
&vote,
|
|
||||||
&signers,
|
&signers,
|
||||||
&invoke_context.feature_set,
|
instruction_account_indices::Vote::VoteAccount as usize,
|
||||||
|
&vote,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
VoteInstruction::UpdateVoteState(vote_state_update)
|
VoteInstruction::UpdateVoteState(vote_state_update)
|
||||||
|
@ -95,47 +165,26 @@ pub fn process_instruction(
|
||||||
.is_active(&feature_set::allow_votes_to_directly_update_vote_state::id())
|
.is_active(&feature_set::allow_votes_to_directly_update_vote_state::id())
|
||||||
{
|
{
|
||||||
inc_new_counter_info!("vote-state-native", 1);
|
inc_new_counter_info!("vote-state-native", 1);
|
||||||
let sysvar_cache = invoke_context.get_sysvar_cache();
|
|
||||||
let slot_hashes = sysvar_cache.get_slot_hashes()?;
|
|
||||||
let clock = sysvar_cache.get_clock()?;
|
|
||||||
vote_state::process_vote_state_update(
|
vote_state::process_vote_state_update(
|
||||||
me,
|
invoke_context,
|
||||||
slot_hashes.slot_hashes(),
|
instruction_context,
|
||||||
&clock,
|
|
||||||
vote_state_update,
|
|
||||||
&signers,
|
&signers,
|
||||||
|
instruction_account_indices::UpdateVoteState::VoteAccount as usize,
|
||||||
|
vote_state_update,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Err(InstructionError::InvalidInstructionData)
|
Err(InstructionError::InvalidInstructionData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VoteInstruction::Withdraw(lamports) => {
|
VoteInstruction::Withdraw(lamports) => {
|
||||||
let to = keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?;
|
instruction_context.check_number_of_instruction_accounts(2)?;
|
||||||
let rent_sysvar = if invoke_context
|
|
||||||
.feature_set
|
|
||||||
.is_active(&feature_set::reject_non_rent_exempt_vote_withdraws::id())
|
|
||||||
{
|
|
||||||
Some(invoke_context.get_sysvar_cache().get_rent()?)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let clock_if_feature_active = if invoke_context
|
|
||||||
.feature_set
|
|
||||||
.is_active(&feature_set::reject_vote_account_close_unless_zero_credit_epoch::id())
|
|
||||||
{
|
|
||||||
Some(invoke_context.get_sysvar_cache().get_clock()?)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
vote_state::withdraw(
|
vote_state::withdraw(
|
||||||
me,
|
invoke_context,
|
||||||
lamports,
|
instruction_context,
|
||||||
to,
|
|
||||||
&signers,
|
&signers,
|
||||||
rent_sysvar.as_deref(),
|
instruction_account_indices::Withdraw::VoteAccount as usize,
|
||||||
clock_if_feature_active.as_deref(),
|
instruction_account_indices::Withdraw::Recipient as usize,
|
||||||
|
lamports,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
VoteInstruction::AuthorizeChecked(vote_authorize) => {
|
VoteInstruction::AuthorizeChecked(vote_authorize) => {
|
||||||
|
@ -143,21 +192,28 @@ pub fn process_instruction(
|
||||||
.feature_set
|
.feature_set
|
||||||
.is_active(&feature_set::vote_stake_checked_instructions::id())
|
.is_active(&feature_set::vote_stake_checked_instructions::id())
|
||||||
{
|
{
|
||||||
let voter_pubkey =
|
instruction_context.check_number_of_instruction_accounts(4)?;
|
||||||
&keyed_account_at_index(keyed_accounts, first_instruction_account + 3)?
|
if !instruction_context.is_signer(
|
||||||
.signer_key()
|
instruction_context.get_number_of_program_accounts()
|
||||||
.ok_or(InstructionError::MissingRequiredSignature)?;
|
+ instruction_account_indices::AuthorizeChecked::Voter as usize,
|
||||||
let clock = get_sysvar_with_account_check::clock(
|
)? {
|
||||||
keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?,
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
|
}
|
||||||
|
let _clock = get_sysvar_with_account_check2::clock(
|
||||||
invoke_context,
|
invoke_context,
|
||||||
|
instruction_context,
|
||||||
|
instruction_account_indices::AuthorizeChecked::Clock as usize,
|
||||||
)?;
|
)?;
|
||||||
vote_state::authorize(
|
vote_state::authorize(
|
||||||
me,
|
invoke_context,
|
||||||
voter_pubkey,
|
instruction_context,
|
||||||
vote_authorize,
|
|
||||||
&signers,
|
&signers,
|
||||||
&clock,
|
instruction_account_indices::AuthorizeChecked::VoteAccount as usize,
|
||||||
&invoke_context.feature_set,
|
instruction_context.get_instruction_account_key(
|
||||||
|
transaction_context,
|
||||||
|
instruction_account_indices::AuthorizeChecked::Voter as usize,
|
||||||
|
)?,
|
||||||
|
vote_authorize,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Err(InstructionError::InvalidInstructionData)
|
Err(InstructionError::InvalidInstructionData)
|
||||||
|
@ -166,17 +222,6 @@ pub fn process_instruction(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_rent_exemption(
|
|
||||||
keyed_account: &KeyedAccount,
|
|
||||||
rent: &Rent,
|
|
||||||
) -> Result<(), InstructionError> {
|
|
||||||
if !rent.is_exempt(keyed_account.lamports()?, keyed_account.data_len()?) {
|
|
||||||
Err(InstructionError::InsufficientFunds)
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use {
|
use {
|
||||||
|
@ -201,9 +246,10 @@ mod tests {
|
||||||
feature_set::FeatureSet,
|
feature_set::FeatureSet,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
instruction::{AccountMeta, Instruction},
|
instruction::{AccountMeta, Instruction},
|
||||||
sysvar::{self, clock::Clock, slot_hashes::SlotHashes},
|
pubkey::Pubkey,
|
||||||
|
sysvar::{self, clock::Clock, rent::Rent, slot_hashes::SlotHashes},
|
||||||
},
|
},
|
||||||
std::str::FromStr,
|
std::{collections::HashSet, str::FromStr},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn create_default_account() -> AccountSharedData {
|
fn create_default_account() -> AccountSharedData {
|
||||||
|
|
|
@ -5,19 +5,19 @@ use {
|
||||||
bincode::{deserialize, serialize_into, serialized_size, ErrorKind},
|
bincode::{deserialize, serialize_into, serialized_size, ErrorKind},
|
||||||
log::*,
|
log::*,
|
||||||
serde_derive::{Deserialize, Serialize},
|
serde_derive::{Deserialize, Serialize},
|
||||||
|
solana_program_runtime::invoke_context::InvokeContext,
|
||||||
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},
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
|
@ -1165,19 +1165,24 @@ 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,
|
invoke_context: &InvokeContext,
|
||||||
|
instruction_context: &InstructionContext,
|
||||||
|
signers: &HashSet<Pubkey, S>,
|
||||||
|
vote_account_index: usize,
|
||||||
authorized: &Pubkey,
|
authorized: &Pubkey,
|
||||||
vote_authorize: VoteAuthorize,
|
vote_authorize: VoteAuthorize,
|
||||||
signers: &HashSet<Pubkey, S>,
|
|
||||||
clock: &Clock,
|
|
||||||
feature_set: &FeatureSet,
|
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
let mut vote_state: VoteState =
|
let mut vote_account = instruction_context
|
||||||
State::<VoteStateVersions>::state(vote_account)?.convert_to_current();
|
.try_borrow_instruction_account(invoke_context.transaction_context, vote_account_index)?;
|
||||||
|
let clock = invoke_context.get_sysvar_cache().get_clock()?;
|
||||||
|
let mut vote_state: VoteState = vote_account
|
||||||
|
.get_state::<VoteStateVersions>()?
|
||||||
|
.convert_to_current();
|
||||||
|
|
||||||
match vote_authorize {
|
match vote_authorize {
|
||||||
VoteAuthorize::Voter => {
|
VoteAuthorize::Voter => {
|
||||||
let authorized_withdrawer_signer = if feature_set
|
let authorized_withdrawer_signer = if invoke_context
|
||||||
|
.feature_set
|
||||||
.is_active(&feature_set::vote_withdraw_authority_may_change_authorized_voter::id())
|
.is_active(&feature_set::vote_withdraw_authority_may_change_authorized_voter::id())
|
||||||
{
|
{
|
||||||
verify_authorized_signer(&vote_state.authorized_withdrawer, signers).is_ok()
|
verify_authorized_signer(&vote_state.authorized_withdrawer, signers).is_ok()
|
||||||
|
@ -1211,12 +1216,17 @@ 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,
|
invoke_context: &InvokeContext,
|
||||||
node_pubkey: &Pubkey,
|
instruction_context: &InstructionContext,
|
||||||
signers: &HashSet<Pubkey, S>,
|
signers: &HashSet<Pubkey, S>,
|
||||||
|
vote_account_index: usize,
|
||||||
|
node_pubkey: &Pubkey,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
let mut vote_state: VoteState =
|
let mut vote_account = instruction_context
|
||||||
State::<VoteStateVersions>::state(vote_account)?.convert_to_current();
|
.try_borrow_instruction_account(invoke_context.transaction_context, vote_account_index)?;
|
||||||
|
let mut vote_state: VoteState = vote_account
|
||||||
|
.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 +1241,17 @@ 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,
|
invoke_context: &InvokeContext,
|
||||||
commission: u8,
|
instruction_context: &InstructionContext,
|
||||||
signers: &HashSet<Pubkey, S>,
|
signers: &HashSet<Pubkey, S>,
|
||||||
|
vote_account_index: usize,
|
||||||
|
commission: u8,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
let mut vote_state: VoteState =
|
let mut vote_account = instruction_context
|
||||||
State::<VoteStateVersions>::state(vote_account)?.convert_to_current();
|
.try_borrow_instruction_account(invoke_context.transaction_context, vote_account_index)?;
|
||||||
|
let mut vote_state: VoteState = vote_account
|
||||||
|
.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 +1274,42 @@ 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,
|
invoke_context: &InvokeContext,
|
||||||
lamports: u64,
|
instruction_context: &InstructionContext,
|
||||||
to_account: &KeyedAccount,
|
|
||||||
signers: &HashSet<Pubkey, S>,
|
signers: &HashSet<Pubkey, S>,
|
||||||
rent_sysvar: Option<&Rent>,
|
vote_account_index: usize,
|
||||||
clock: Option<&Clock>,
|
recipient_account_index: usize,
|
||||||
|
lamports: u64,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
let vote_state: VoteState =
|
let mut vote_account = instruction_context
|
||||||
State::<VoteStateVersions>::state(vote_account)?.convert_to_current();
|
.try_borrow_instruction_account(invoke_context.transaction_context, vote_account_index)?;
|
||||||
|
|
||||||
|
let rent_sysvar = if invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&feature_set::reject_non_rent_exempt_vote_withdraws::id())
|
||||||
|
{
|
||||||
|
Some(invoke_context.get_sysvar_cache().get_rent()?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let clock = if invoke_context
|
||||||
|
.feature_set
|
||||||
|
.is_active(&feature_set::reject_vote_account_close_unless_zero_credit_epoch::id())
|
||||||
|
{
|
||||||
|
Some(invoke_context.get_sysvar_cache().get_clock()?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
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 +1332,19 @@ 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 recipient_account = instruction_context.try_borrow_instruction_account(
|
||||||
to_account
|
invoke_context.transaction_context,
|
||||||
.try_account_ref_mut()?
|
recipient_account_index,
|
||||||
.checked_add_lamports(lamports)?;
|
)?;
|
||||||
|
recipient_account.checked_add_lamports(lamports)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1314,15 +1352,19 @@ 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,
|
invoke_context: &InvokeContext,
|
||||||
vote_init: &VoteInit,
|
instruction_context: &InstructionContext,
|
||||||
signers: &HashSet<Pubkey, S>,
|
signers: &HashSet<Pubkey, S>,
|
||||||
clock: &Clock,
|
vote_account_index: usize,
|
||||||
|
vote_init: &VoteInit,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
if vote_account.data_len()? != VoteState::size_of() {
|
let mut vote_account = instruction_context
|
||||||
|
.try_borrow_instruction_account(invoke_context.transaction_context, vote_account_index)?;
|
||||||
|
let clock = invoke_context.get_sysvar_cache().get_clock()?;
|
||||||
|
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);
|
||||||
|
@ -1332,16 +1374,16 @@ pub fn initialize_account<S: std::hash::BuildHasher>(
|
||||||
verify_authorized_signer(&vote_init.node_pubkey, signers)?;
|
verify_authorized_signer(&vote_init.node_pubkey, signers)?;
|
||||||
|
|
||||||
vote_account.set_state(&VoteStateVersions::new_current(VoteState::new(
|
vote_account.set_state(&VoteStateVersions::new_current(VoteState::new(
|
||||||
vote_init, clock,
|
vote_init, &clock,
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
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,16 +1397,25 @@ 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,
|
invoke_context: &InvokeContext,
|
||||||
slot_hashes: &[SlotHash],
|
instruction_context: &InstructionContext,
|
||||||
clock: &Clock,
|
|
||||||
vote: &Vote,
|
|
||||||
signers: &HashSet<Pubkey, S>,
|
signers: &HashSet<Pubkey, S>,
|
||||||
feature_set: &FeatureSet,
|
vote_account_index: usize,
|
||||||
|
vote: &Vote,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
let mut vote_state = verify_and_get_vote_state(vote_account, clock, signers)?;
|
let mut vote_account = instruction_context
|
||||||
|
.try_borrow_instruction_account(invoke_context.transaction_context, vote_account_index)?;
|
||||||
|
let sysvar_cache = invoke_context.get_sysvar_cache();
|
||||||
|
let slot_hashes = sysvar_cache.get_slot_hashes()?;
|
||||||
|
let clock = sysvar_cache.get_clock()?;
|
||||||
|
let mut vote_state = verify_and_get_vote_state(&vote_account, &clock, signers)?;
|
||||||
|
|
||||||
vote_state.process_vote(vote, slot_hashes, clock.epoch, Some(feature_set))?;
|
vote_state.process_vote(
|
||||||
|
vote,
|
||||||
|
slot_hashes.slot_hashes(),
|
||||||
|
clock.epoch,
|
||||||
|
Some(&invoke_context.feature_set),
|
||||||
|
)?;
|
||||||
if let Some(timestamp) = vote.timestamp {
|
if let Some(timestamp) = vote.timestamp {
|
||||||
vote.slots
|
vote.slots
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -1376,14 +1427,19 @@ 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,
|
invoke_context: &InvokeContext,
|
||||||
slot_hashes: &[SlotHash],
|
instruction_context: &InstructionContext,
|
||||||
clock: &Clock,
|
|
||||||
mut vote_state_update: VoteStateUpdate,
|
|
||||||
signers: &HashSet<Pubkey, S>,
|
signers: &HashSet<Pubkey, S>,
|
||||||
|
vote_account_index: usize,
|
||||||
|
mut vote_state_update: VoteStateUpdate,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
let mut vote_state = verify_and_get_vote_state(vote_account, clock, signers)?;
|
let mut vote_account = instruction_context
|
||||||
vote_state.check_update_vote_state_slots_are_valid(&mut vote_state_update, slot_hashes)?;
|
.try_borrow_instruction_account(invoke_context.transaction_context, vote_account_index)?;
|
||||||
|
let sysvar_cache = invoke_context.get_sysvar_cache();
|
||||||
|
let slot_hashes = sysvar_cache.get_slot_hashes()?;
|
||||||
|
let clock = sysvar_cache.get_clock()?;
|
||||||
|
let mut vote_state = verify_and_get_vote_state(&vote_account, &clock, signers)?;
|
||||||
|
vote_state.check_update_vote_state_slots_are_valid(&mut vote_state_update, &slot_hashes)?;
|
||||||
vote_state.process_new_vote_state(
|
vote_state.process_new_vote_state(
|
||||||
vote_state_update.lockouts,
|
vote_state_update.lockouts,
|
||||||
vote_state_update.root,
|
vote_state_update.root,
|
||||||
|
|
Loading…
Reference in New Issue