Refactor: Cleanup InvokeContext (#20785)

* Move blockhash and fee_calculator in ThisInvokeContext instead of using a reference.

* Moves tx_wide_compute_cap into InvokeContext::push().

* Adds ThisInvokeContext::new_mock() constructor.

* Adds missing loader account in uses of MockInvokeContext.

* Use keyed_account_at_index() when accessing keyed_accounts.

* Makes sysvar interface consistent between ThisInvokeContext and MockInvokeContext,
in order to add InvokeContext::get_sysvars().

* Adds InvokeContext::set_blockhash() and InvokeContext ::set_fee_calculator().

* Adds new_mock_with_features.

* Makes ancestors optional in ThisInvokeContext.

* Adds prepare_mock_invoke_context() and mock_process_instruction().
This commit is contained in:
Alexander Meißner
2021-10-21 20:57:42 +02:00
committed by GitHub
parent 0ac89841bf
commit 97c2732d02
11 changed files with 350 additions and 248 deletions

View File

@ -94,8 +94,28 @@ fn bench_program_alu(bencher: &mut Bencher) {
.write_u64::<LittleEndian>(ARMSTRONG_LIMIT)
.unwrap();
inner_iter.write_u64::<LittleEndian>(0).unwrap();
let loader_id = bpf_loader::id();
let mut invoke_context = MockInvokeContext::new(&Pubkey::default(), vec![]);
let program_id = solana_sdk::pubkey::new_rand();
let accounts = [
(
program_id,
RefCell::new(AccountSharedData::new(0, 0, &loader_id)),
),
(
solana_sdk::pubkey::new_rand(),
RefCell::new(AccountSharedData::new(
1,
10000001,
&solana_sdk::pubkey::new_rand(),
)),
),
];
let keyed_accounts: Vec<_> = accounts
.iter()
.map(|(key, account)| solana_sdk::keyed_account::KeyedAccount::new(&key, false, &account))
.collect();
let mut invoke_context = MockInvokeContext::new(&program_id, keyed_accounts);
let elf = load_elf("bench_alu").unwrap();
let mut executable = <dyn Executable<BpfError, ThisInstructionMeter>>::from_elf(
@ -254,29 +274,35 @@ fn bench_create_vm(bencher: &mut Bencher) {
fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
const BUDGET: u64 = 200_000;
let loader_id = bpf_loader::id();
let program_id = solana_sdk::pubkey::new_rand();
let accounts = [RefCell::new(AccountSharedData::new(
1,
10000001,
&solana_sdk::pubkey::new_rand(),
))];
let keys = [solana_sdk::pubkey::new_rand()];
let keyed_accounts: Vec<_> = keys
let accounts = [
(
program_id,
RefCell::new(AccountSharedData::new(0, 0, &loader_id)),
),
(
solana_sdk::pubkey::new_rand(),
RefCell::new(AccountSharedData::new(
1,
10000001,
&solana_sdk::pubkey::new_rand(),
)),
),
];
let keyed_accounts: Vec<_> = accounts
.iter()
.zip(&accounts)
.map(|(key, account)| solana_sdk::keyed_account::KeyedAccount::new(&key, false, &account))
.collect();
let instruction_data = vec![0u8];
let mut invoke_context = MockInvokeContext::new(&loader_id, keyed_accounts);
let mut invoke_context = MockInvokeContext::new(&program_id, keyed_accounts);
invoke_context.compute_meter.remaining = BUDGET;
// Serialize account data
let keyed_accounts = invoke_context.get_keyed_accounts().unwrap();
let (mut serialized, account_lengths) = serialize_parameters(
&loader_id,
&solana_sdk::pubkey::new_rand(),
keyed_accounts,
&program_id,
&invoke_context.get_keyed_accounts().unwrap()[1..],
&instruction_data,
)
.unwrap();

View File

@ -192,24 +192,23 @@ fn upgrade_bpf_program(
fn run_program(
name: &str,
loader_id: &Pubkey,
program_id: &Pubkey,
parameter_accounts: Vec<KeyedAccount>,
instruction_data: &[u8],
) -> Result<u64, InstructionError> {
let path = create_bpf_path(name);
let mut file = File::open(path).unwrap();
let mut file = File::open(create_bpf_path(name)).unwrap();
let mut data = vec![];
file.read_to_end(&mut data).unwrap();
let loader_id = bpf_loader::id();
let mut invoke_context = MockInvokeContext::new(&program_id, parameter_accounts);
let (parameter_bytes, account_lengths) = serialize_parameters(
&loader_id,
program_id,
&parameter_accounts,
&invoke_context.get_keyed_accounts().unwrap()[1..],
&instruction_data,
)
.unwrap();
let mut invoke_context = MockInvokeContext::new(&loader_id, parameter_accounts);
let compute_meter = invoke_context.get_compute_meter();
let mut instruction_meter = ThisInstructionMeter { compute_meter };
@ -1405,11 +1404,17 @@ fn assert_instruction_count() {
let mut passed = true;
println!("\n {:36} expected actual diff", "BPF program");
for program in programs.iter() {
let loader_id = bpf_loader::id();
let program_id = Pubkey::new_unique();
let key = Pubkey::new_unique();
let mut program_account = RefCell::new(AccountSharedData::new(0, 0, &loader_id));
let mut account = RefCell::new(AccountSharedData::default());
let parameter_accounts = vec![KeyedAccount::new(&key, false, &mut account)];
let count = run_program(program.0, &program_id, parameter_accounts, &[]).unwrap();
let parameter_accounts = vec![
KeyedAccount::new(&program_id, false, &mut program_account),
KeyedAccount::new(&key, false, &mut account),
];
let count =
run_program(program.0, &loader_id, &program_id, parameter_accounts, &[]).unwrap();
let diff: i64 = count as i64 - program.1 as i64;
println!(
" {:36} {:8} {:6} {:+5} ({:+3.0}%)",

View File

@ -3335,7 +3335,8 @@ mod tests {
let mut data = vec![];
bincode::serialize_into(&mut data, &src_clock).unwrap();
invoke_context
.sysvars
.get_sysvars()
.borrow_mut()
.push((sysvar::clock::id(), Some(Rc::new(data))));
let mut syscall = SyscallGetClockSysvar {
@ -3380,7 +3381,8 @@ mod tests {
let mut data = vec![];
bincode::serialize_into(&mut data, &src_epochschedule).unwrap();
invoke_context
.sysvars
.get_sysvars()
.borrow_mut()
.push((sysvar::epoch_schedule::id(), Some(Rc::new(data))));
let mut syscall = SyscallGetEpochScheduleSysvar {
@ -3432,7 +3434,8 @@ mod tests {
let mut data = vec![];
bincode::serialize_into(&mut data, &src_fees).unwrap();
invoke_context
.sysvars
.get_sysvars()
.borrow_mut()
.push((sysvar::fees::id(), Some(Rc::new(data))));
let mut syscall = SyscallGetFeesSysvar {
@ -3475,7 +3478,8 @@ mod tests {
let mut data = vec![];
bincode::serialize_into(&mut data, &src_rent).unwrap();
invoke_context
.sysvars
.get_sysvars()
.borrow_mut()
.push((sysvar::rent::id(), Some(Rc::new(data))));
let mut syscall = SyscallGetRentSysvar {

View File

@ -54,20 +54,19 @@ pub fn process_instruction(
}
let mut counter = 0;
let mut keyed_accounts_iter = keyed_accounts.iter().skip(2);
for (signer, _) in key_list.keys.iter().filter(|(_, is_signer)| *is_signer) {
counter += 1;
if signer != config_keyed_account.unsigned_key() {
let signer_account = keyed_accounts_iter.next();
if signer_account.is_none() {
ic_msg!(
invoke_context,
"account {:?} is not in account list",
signer
);
return Err(InstructionError::MissingRequiredSignature);
}
let signer_key = signer_account.unwrap().signer_key();
let signer_account =
keyed_account_at_index(keyed_accounts, counter + 1).map_err(|_| {
ic_msg!(
invoke_context,
"account {:?} is not in account list",
signer,
);
InstructionError::MissingRequiredSignature
})?;
let signer_key = signer_account.signer_key();
if signer_key.is_none() {
ic_msg!(
invoke_context,

View File

@ -37,7 +37,7 @@ pub fn process_instruction(
return Err(InstructionError::InvalidAccountOwner);
}
let signers = get_signers(&keyed_accounts[1..]);
let signers = get_signers(&keyed_accounts[first_instruction_account..]);
match limited_deserialize(data)? {
StakeInstruction::Initialize(authorized, lockup) => me.initialize(
&authorized,
@ -330,7 +330,7 @@ mod tests {
account::{self, Account, AccountSharedData, WritableAccount},
instruction::{AccountMeta, Instruction},
keyed_account::create_keyed_accounts_unified,
process_instruction::{mock_set_sysvar, MockInvokeContext},
process_instruction::MockInvokeContext,
pubkey::Pubkey,
rent::Rent,
stake::{
@ -338,7 +338,7 @@ mod tests {
instruction::{self, LockupArgs},
state::{Authorized, Lockup, StakeAuthorize},
},
sysvar::stake_history::StakeHistory,
sysvar::{stake_history::StakeHistory, Sysvar},
};
use std::{cell::RefCell, rc::Rc, str::FromStr};
@ -442,12 +442,12 @@ mod tests {
&processor_id,
create_keyed_accounts_unified(&keyed_accounts),
);
mock_set_sysvar(
&mut invoke_context,
sysvar::clock::id(),
sysvar::clock::Clock::default(),
)
.unwrap();
let mut data = Vec::with_capacity(sysvar::clock::Clock::size_of());
bincode::serialize_into(&mut data, &sysvar::clock::Clock::default()).unwrap();
invoke_context
.get_sysvars()
.borrow_mut()
.push((sysvar::clock::id(), Some(Rc::new(data))));
super::process_instruction(1, &instruction.data, &mut invoke_context)
}
}
@ -1100,11 +1100,11 @@ mod tests {
];
let mut invoke_context =
MockInvokeContext::new(&id(), create_keyed_accounts_unified(&keyed_accounts));
let clock = Clock::default();
let mut data = vec![];
bincode::serialize_into(&mut data, &clock).unwrap();
let mut data = Vec::with_capacity(sysvar::clock::Clock::size_of());
bincode::serialize_into(&mut data, &sysvar::clock::Clock::default()).unwrap();
invoke_context
.sysvars
.get_sysvars()
.borrow_mut()
.push((sysvar::clock::id(), Some(Rc::new(data))));
assert_eq!(

View File

@ -322,7 +322,7 @@ pub fn process_instruction(
return Err(InstructionError::InvalidAccountOwner);
}
let signers: HashSet<Pubkey> = get_signers(&keyed_accounts[1..]);
let signers: HashSet<Pubkey> = get_signers(&keyed_accounts[first_instruction_account..]);
match limited_deserialize(data)? {
VoteInstruction::InitializeAccount(vote_init) => {
verify_rent_exemption(