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:
parent
0ac89841bf
commit
97c2732d02
|
@ -9,6 +9,7 @@ use solana_sdk::{
|
||||||
},
|
},
|
||||||
ic_msg,
|
ic_msg,
|
||||||
instruction::{Instruction, InstructionError},
|
instruction::{Instruction, InstructionError},
|
||||||
|
keyed_account::keyed_account_at_index,
|
||||||
message::Message,
|
message::Message,
|
||||||
process_instruction::{Executor, InvokeContext, ProcessInstructionWithContext},
|
process_instruction::{Executor, InvokeContext, ProcessInstructionWithContext},
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
|
@ -355,7 +356,8 @@ impl InstructionProcessor {
|
||||||
instruction_data: &[u8],
|
instruction_data: &[u8],
|
||||||
invoke_context: &mut dyn InvokeContext,
|
invoke_context: &mut dyn InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
if let Some(root_account) = invoke_context.get_keyed_accounts()?.iter().next() {
|
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
||||||
|
if let Ok(root_account) = keyed_account_at_index(keyed_accounts, 0) {
|
||||||
let root_id = root_account.unsigned_key();
|
let root_id = root_account.unsigned_key();
|
||||||
let owner_id = &root_account.owner()?;
|
let owner_id = &root_account.owner()?;
|
||||||
if solana_sdk::native_loader::check_id(owner_id) {
|
if solana_sdk::native_loader::check_id(owner_id) {
|
||||||
|
@ -536,7 +538,8 @@ impl InstructionProcessor {
|
||||||
caller_write_privileges = Vec::with_capacity(1 + keyed_account_indices_obsolete.len());
|
caller_write_privileges = Vec::with_capacity(1 + keyed_account_indices_obsolete.len());
|
||||||
caller_write_privileges.push(false);
|
caller_write_privileges.push(false);
|
||||||
for index in keyed_account_indices_obsolete.iter() {
|
for index in keyed_account_indices_obsolete.iter() {
|
||||||
caller_write_privileges.push(caller_keyed_accounts[*index].is_writable());
|
caller_write_privileges
|
||||||
|
.push(keyed_account_at_index(caller_keyed_accounts, *index)?.is_writable());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut account_indices = Vec::with_capacity(message.account_keys.len());
|
let mut account_indices = Vec::with_capacity(message.account_keys.len());
|
||||||
|
|
|
@ -33,7 +33,7 @@ use {
|
||||||
message::Message,
|
message::Message,
|
||||||
native_token::sol_to_lamports,
|
native_token::sol_to_lamports,
|
||||||
poh_config::PohConfig,
|
poh_config::PohConfig,
|
||||||
process_instruction::{stable_log, InvokeContext, ProcessInstructionWithContext},
|
process_instruction::{self, stable_log, InvokeContext, ProcessInstructionWithContext},
|
||||||
program_error::{ProgramError, ACCOUNT_BORROW_FAILED, UNSUPPORTED_SYSVAR},
|
program_error::{ProgramError, ACCOUNT_BORROW_FAILED, UNSUPPORTED_SYSVAR},
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
rent::Rent,
|
rent::Rent,
|
||||||
|
@ -204,24 +204,6 @@ fn get_sysvar<T: Default + Sysvar + Sized + serde::de::DeserializeOwned>(
|
||||||
var_addr: *mut u8,
|
var_addr: *mut u8,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let invoke_context = get_invoke_context();
|
let invoke_context = get_invoke_context();
|
||||||
|
|
||||||
let sysvar_data = match invoke_context.get_sysvar_data(id).ok_or_else(|| {
|
|
||||||
ic_msg!(invoke_context, "Unable to get Sysvar {}", id);
|
|
||||||
UNSUPPORTED_SYSVAR
|
|
||||||
}) {
|
|
||||||
Ok(sysvar_data) => sysvar_data,
|
|
||||||
Err(err) => return err,
|
|
||||||
};
|
|
||||||
|
|
||||||
let var: T = match bincode::deserialize(&sysvar_data) {
|
|
||||||
Ok(sysvar_data) => sysvar_data,
|
|
||||||
Err(_) => return UNSUPPORTED_SYSVAR,
|
|
||||||
};
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
*(var_addr as *mut _ as *mut T) = var;
|
|
||||||
}
|
|
||||||
|
|
||||||
if invoke_context
|
if invoke_context
|
||||||
.get_compute_meter()
|
.get_compute_meter()
|
||||||
.try_borrow_mut()
|
.try_borrow_mut()
|
||||||
|
@ -233,7 +215,13 @@ fn get_sysvar<T: Default + Sysvar + Sized + serde::de::DeserializeOwned>(
|
||||||
panic!("Exceeded compute budget");
|
panic!("Exceeded compute budget");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
match process_instruction::get_sysvar::<T>(invoke_context, id) {
|
||||||
|
Ok(sysvar_data) => unsafe {
|
||||||
|
*(var_addr as *mut _ as *mut T) = sysvar_data;
|
||||||
SUCCESS
|
SUCCESS
|
||||||
|
},
|
||||||
|
Err(_) => UNSUPPORTED_SYSVAR,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SyscallStubs {}
|
struct SyscallStubs {}
|
||||||
|
|
|
@ -94,8 +94,28 @@ fn bench_program_alu(bencher: &mut Bencher) {
|
||||||
.write_u64::<LittleEndian>(ARMSTRONG_LIMIT)
|
.write_u64::<LittleEndian>(ARMSTRONG_LIMIT)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
inner_iter.write_u64::<LittleEndian>(0).unwrap();
|
inner_iter.write_u64::<LittleEndian>(0).unwrap();
|
||||||
|
|
||||||
let loader_id = bpf_loader::id();
|
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 elf = load_elf("bench_alu").unwrap();
|
||||||
let mut executable = <dyn Executable<BpfError, ThisInstructionMeter>>::from_elf(
|
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) {
|
fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
|
||||||
const BUDGET: u64 = 200_000;
|
const BUDGET: u64 = 200_000;
|
||||||
let loader_id = bpf_loader::id();
|
let loader_id = bpf_loader::id();
|
||||||
|
let program_id = solana_sdk::pubkey::new_rand();
|
||||||
|
|
||||||
let accounts = [RefCell::new(AccountSharedData::new(
|
let accounts = [
|
||||||
|
(
|
||||||
|
program_id,
|
||||||
|
RefCell::new(AccountSharedData::new(0, 0, &loader_id)),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
solana_sdk::pubkey::new_rand(),
|
||||||
|
RefCell::new(AccountSharedData::new(
|
||||||
1,
|
1,
|
||||||
10000001,
|
10000001,
|
||||||
&solana_sdk::pubkey::new_rand(),
|
&solana_sdk::pubkey::new_rand(),
|
||||||
))];
|
)),
|
||||||
let keys = [solana_sdk::pubkey::new_rand()];
|
),
|
||||||
let keyed_accounts: Vec<_> = keys
|
];
|
||||||
|
let keyed_accounts: Vec<_> = accounts
|
||||||
.iter()
|
.iter()
|
||||||
.zip(&accounts)
|
|
||||||
.map(|(key, account)| solana_sdk::keyed_account::KeyedAccount::new(&key, false, &account))
|
.map(|(key, account)| solana_sdk::keyed_account::KeyedAccount::new(&key, false, &account))
|
||||||
.collect();
|
.collect();
|
||||||
let instruction_data = vec![0u8];
|
let instruction_data = vec![0u8];
|
||||||
|
let mut invoke_context = MockInvokeContext::new(&program_id, keyed_accounts);
|
||||||
let mut invoke_context = MockInvokeContext::new(&loader_id, keyed_accounts);
|
|
||||||
invoke_context.compute_meter.remaining = BUDGET;
|
invoke_context.compute_meter.remaining = BUDGET;
|
||||||
|
|
||||||
// Serialize account data
|
// Serialize account data
|
||||||
let keyed_accounts = invoke_context.get_keyed_accounts().unwrap();
|
|
||||||
let (mut serialized, account_lengths) = serialize_parameters(
|
let (mut serialized, account_lengths) = serialize_parameters(
|
||||||
&loader_id,
|
&loader_id,
|
||||||
&solana_sdk::pubkey::new_rand(),
|
&program_id,
|
||||||
keyed_accounts,
|
&invoke_context.get_keyed_accounts().unwrap()[1..],
|
||||||
&instruction_data,
|
&instruction_data,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -192,24 +192,23 @@ fn upgrade_bpf_program(
|
||||||
|
|
||||||
fn run_program(
|
fn run_program(
|
||||||
name: &str,
|
name: &str,
|
||||||
|
loader_id: &Pubkey,
|
||||||
program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
parameter_accounts: Vec<KeyedAccount>,
|
parameter_accounts: Vec<KeyedAccount>,
|
||||||
instruction_data: &[u8],
|
instruction_data: &[u8],
|
||||||
) -> Result<u64, InstructionError> {
|
) -> Result<u64, InstructionError> {
|
||||||
let path = create_bpf_path(name);
|
let mut file = File::open(create_bpf_path(name)).unwrap();
|
||||||
let mut file = File::open(path).unwrap();
|
|
||||||
|
|
||||||
let mut data = vec![];
|
let mut data = vec![];
|
||||||
file.read_to_end(&mut data).unwrap();
|
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(
|
let (parameter_bytes, account_lengths) = serialize_parameters(
|
||||||
&loader_id,
|
&loader_id,
|
||||||
program_id,
|
program_id,
|
||||||
¶meter_accounts,
|
&invoke_context.get_keyed_accounts().unwrap()[1..],
|
||||||
&instruction_data,
|
&instruction_data,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut invoke_context = MockInvokeContext::new(&loader_id, parameter_accounts);
|
|
||||||
let compute_meter = invoke_context.get_compute_meter();
|
let compute_meter = invoke_context.get_compute_meter();
|
||||||
let mut instruction_meter = ThisInstructionMeter { compute_meter };
|
let mut instruction_meter = ThisInstructionMeter { compute_meter };
|
||||||
|
|
||||||
|
@ -1405,11 +1404,17 @@ fn assert_instruction_count() {
|
||||||
let mut passed = true;
|
let mut passed = true;
|
||||||
println!("\n {:36} expected actual diff", "BPF program");
|
println!("\n {:36} expected actual diff", "BPF program");
|
||||||
for program in programs.iter() {
|
for program in programs.iter() {
|
||||||
|
let loader_id = bpf_loader::id();
|
||||||
let program_id = Pubkey::new_unique();
|
let program_id = Pubkey::new_unique();
|
||||||
let key = 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 mut account = RefCell::new(AccountSharedData::default());
|
||||||
let parameter_accounts = vec![KeyedAccount::new(&key, false, &mut account)];
|
let parameter_accounts = vec![
|
||||||
let count = run_program(program.0, &program_id, parameter_accounts, &[]).unwrap();
|
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;
|
let diff: i64 = count as i64 - program.1 as i64;
|
||||||
println!(
|
println!(
|
||||||
" {:36} {:8} {:6} {:+5} ({:+3.0}%)",
|
" {:36} {:8} {:6} {:+5} ({:+3.0}%)",
|
||||||
|
|
|
@ -3335,7 +3335,8 @@ mod tests {
|
||||||
let mut data = vec![];
|
let mut data = vec![];
|
||||||
bincode::serialize_into(&mut data, &src_clock).unwrap();
|
bincode::serialize_into(&mut data, &src_clock).unwrap();
|
||||||
invoke_context
|
invoke_context
|
||||||
.sysvars
|
.get_sysvars()
|
||||||
|
.borrow_mut()
|
||||||
.push((sysvar::clock::id(), Some(Rc::new(data))));
|
.push((sysvar::clock::id(), Some(Rc::new(data))));
|
||||||
|
|
||||||
let mut syscall = SyscallGetClockSysvar {
|
let mut syscall = SyscallGetClockSysvar {
|
||||||
|
@ -3380,7 +3381,8 @@ mod tests {
|
||||||
let mut data = vec![];
|
let mut data = vec![];
|
||||||
bincode::serialize_into(&mut data, &src_epochschedule).unwrap();
|
bincode::serialize_into(&mut data, &src_epochschedule).unwrap();
|
||||||
invoke_context
|
invoke_context
|
||||||
.sysvars
|
.get_sysvars()
|
||||||
|
.borrow_mut()
|
||||||
.push((sysvar::epoch_schedule::id(), Some(Rc::new(data))));
|
.push((sysvar::epoch_schedule::id(), Some(Rc::new(data))));
|
||||||
|
|
||||||
let mut syscall = SyscallGetEpochScheduleSysvar {
|
let mut syscall = SyscallGetEpochScheduleSysvar {
|
||||||
|
@ -3432,7 +3434,8 @@ mod tests {
|
||||||
let mut data = vec![];
|
let mut data = vec![];
|
||||||
bincode::serialize_into(&mut data, &src_fees).unwrap();
|
bincode::serialize_into(&mut data, &src_fees).unwrap();
|
||||||
invoke_context
|
invoke_context
|
||||||
.sysvars
|
.get_sysvars()
|
||||||
|
.borrow_mut()
|
||||||
.push((sysvar::fees::id(), Some(Rc::new(data))));
|
.push((sysvar::fees::id(), Some(Rc::new(data))));
|
||||||
|
|
||||||
let mut syscall = SyscallGetFeesSysvar {
|
let mut syscall = SyscallGetFeesSysvar {
|
||||||
|
@ -3475,7 +3478,8 @@ mod tests {
|
||||||
let mut data = vec![];
|
let mut data = vec![];
|
||||||
bincode::serialize_into(&mut data, &src_rent).unwrap();
|
bincode::serialize_into(&mut data, &src_rent).unwrap();
|
||||||
invoke_context
|
invoke_context
|
||||||
.sysvars
|
.get_sysvars()
|
||||||
|
.borrow_mut()
|
||||||
.push((sysvar::rent::id(), Some(Rc::new(data))));
|
.push((sysvar::rent::id(), Some(Rc::new(data))));
|
||||||
|
|
||||||
let mut syscall = SyscallGetRentSysvar {
|
let mut syscall = SyscallGetRentSysvar {
|
||||||
|
|
|
@ -54,20 +54,19 @@ pub fn process_instruction(
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut counter = 0;
|
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) {
|
for (signer, _) in key_list.keys.iter().filter(|(_, is_signer)| *is_signer) {
|
||||||
counter += 1;
|
counter += 1;
|
||||||
if signer != config_keyed_account.unsigned_key() {
|
if signer != config_keyed_account.unsigned_key() {
|
||||||
let signer_account = keyed_accounts_iter.next();
|
let signer_account =
|
||||||
if signer_account.is_none() {
|
keyed_account_at_index(keyed_accounts, counter + 1).map_err(|_| {
|
||||||
ic_msg!(
|
ic_msg!(
|
||||||
invoke_context,
|
invoke_context,
|
||||||
"account {:?} is not in account list",
|
"account {:?} is not in account list",
|
||||||
signer
|
signer,
|
||||||
);
|
);
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
InstructionError::MissingRequiredSignature
|
||||||
}
|
})?;
|
||||||
let signer_key = signer_account.unwrap().signer_key();
|
let signer_key = signer_account.signer_key();
|
||||||
if signer_key.is_none() {
|
if signer_key.is_none() {
|
||||||
ic_msg!(
|
ic_msg!(
|
||||||
invoke_context,
|
invoke_context,
|
||||||
|
|
|
@ -37,7 +37,7 @@ pub fn process_instruction(
|
||||||
return Err(InstructionError::InvalidAccountOwner);
|
return Err(InstructionError::InvalidAccountOwner);
|
||||||
}
|
}
|
||||||
|
|
||||||
let signers = get_signers(&keyed_accounts[1..]);
|
let signers = get_signers(&keyed_accounts[first_instruction_account..]);
|
||||||
match limited_deserialize(data)? {
|
match limited_deserialize(data)? {
|
||||||
StakeInstruction::Initialize(authorized, lockup) => me.initialize(
|
StakeInstruction::Initialize(authorized, lockup) => me.initialize(
|
||||||
&authorized,
|
&authorized,
|
||||||
|
@ -330,7 +330,7 @@ mod tests {
|
||||||
account::{self, Account, AccountSharedData, WritableAccount},
|
account::{self, Account, AccountSharedData, WritableAccount},
|
||||||
instruction::{AccountMeta, Instruction},
|
instruction::{AccountMeta, Instruction},
|
||||||
keyed_account::create_keyed_accounts_unified,
|
keyed_account::create_keyed_accounts_unified,
|
||||||
process_instruction::{mock_set_sysvar, MockInvokeContext},
|
process_instruction::MockInvokeContext,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
rent::Rent,
|
rent::Rent,
|
||||||
stake::{
|
stake::{
|
||||||
|
@ -338,7 +338,7 @@ mod tests {
|
||||||
instruction::{self, LockupArgs},
|
instruction::{self, LockupArgs},
|
||||||
state::{Authorized, Lockup, StakeAuthorize},
|
state::{Authorized, Lockup, StakeAuthorize},
|
||||||
},
|
},
|
||||||
sysvar::stake_history::StakeHistory,
|
sysvar::{stake_history::StakeHistory, Sysvar},
|
||||||
};
|
};
|
||||||
use std::{cell::RefCell, rc::Rc, str::FromStr};
|
use std::{cell::RefCell, rc::Rc, str::FromStr};
|
||||||
|
|
||||||
|
@ -442,12 +442,12 @@ mod tests {
|
||||||
&processor_id,
|
&processor_id,
|
||||||
create_keyed_accounts_unified(&keyed_accounts),
|
create_keyed_accounts_unified(&keyed_accounts),
|
||||||
);
|
);
|
||||||
mock_set_sysvar(
|
let mut data = Vec::with_capacity(sysvar::clock::Clock::size_of());
|
||||||
&mut invoke_context,
|
bincode::serialize_into(&mut data, &sysvar::clock::Clock::default()).unwrap();
|
||||||
sysvar::clock::id(),
|
invoke_context
|
||||||
sysvar::clock::Clock::default(),
|
.get_sysvars()
|
||||||
)
|
.borrow_mut()
|
||||||
.unwrap();
|
.push((sysvar::clock::id(), Some(Rc::new(data))));
|
||||||
super::process_instruction(1, &instruction.data, &mut invoke_context)
|
super::process_instruction(1, &instruction.data, &mut invoke_context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1100,11 +1100,11 @@ mod tests {
|
||||||
];
|
];
|
||||||
let mut invoke_context =
|
let mut invoke_context =
|
||||||
MockInvokeContext::new(&id(), create_keyed_accounts_unified(&keyed_accounts));
|
MockInvokeContext::new(&id(), create_keyed_accounts_unified(&keyed_accounts));
|
||||||
let clock = Clock::default();
|
let mut data = Vec::with_capacity(sysvar::clock::Clock::size_of());
|
||||||
let mut data = vec![];
|
bincode::serialize_into(&mut data, &sysvar::clock::Clock::default()).unwrap();
|
||||||
bincode::serialize_into(&mut data, &clock).unwrap();
|
|
||||||
invoke_context
|
invoke_context
|
||||||
.sysvars
|
.get_sysvars()
|
||||||
|
.borrow_mut()
|
||||||
.push((sysvar::clock::id(), Some(Rc::new(data))));
|
.push((sysvar::clock::id(), Some(Rc::new(data))));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
@ -322,7 +322,7 @@ pub fn process_instruction(
|
||||||
return Err(InstructionError::InvalidAccountOwner);
|
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)? {
|
match limited_deserialize(data)? {
|
||||||
VoteInstruction::InitializeAccount(vote_init) => {
|
VoteInstruction::InitializeAccount(vote_init) => {
|
||||||
verify_rent_exemption(
|
verify_rent_exemption(
|
||||||
|
|
|
@ -6332,6 +6332,7 @@ pub(crate) mod tests {
|
||||||
genesis_config::create_genesis_config,
|
genesis_config::create_genesis_config,
|
||||||
hash,
|
hash,
|
||||||
instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError},
|
instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError},
|
||||||
|
keyed_account::keyed_account_at_index,
|
||||||
message::{Message, MessageHeader},
|
message::{Message, MessageHeader},
|
||||||
nonce,
|
nonce,
|
||||||
poh_config::PohConfig,
|
poh_config::PohConfig,
|
||||||
|
@ -6713,11 +6714,11 @@ pub(crate) mod tests {
|
||||||
if let Ok(instruction) = bincode::deserialize(data) {
|
if let Ok(instruction) = bincode::deserialize(data) {
|
||||||
match instruction {
|
match instruction {
|
||||||
MockInstruction::Deduction => {
|
MockInstruction::Deduction => {
|
||||||
keyed_accounts[first_instruction_account + 1]
|
keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?
|
||||||
.account
|
.account
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.checked_add_lamports(1)?;
|
.checked_add_lamports(1)?;
|
||||||
keyed_accounts[first_instruction_account + 2]
|
keyed_account_at_index(keyed_accounts, first_instruction_account + 2)?
|
||||||
.account
|
.account
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.checked_sub_lamports(1)?;
|
.checked_sub_lamports(1)?;
|
||||||
|
@ -11295,18 +11296,16 @@ pub(crate) mod tests {
|
||||||
) -> result::Result<(), InstructionError> {
|
) -> result::Result<(), InstructionError> {
|
||||||
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
||||||
let lamports = data[0] as u64;
|
let lamports = data[0] as u64;
|
||||||
{
|
keyed_account_at_index(keyed_accounts, first_instruction_account + 2)?
|
||||||
let mut to_account =
|
|
||||||
keyed_accounts[first_instruction_account + 1].try_account_ref_mut()?;
|
|
||||||
let mut dup_account =
|
|
||||||
keyed_accounts[first_instruction_account + 2].try_account_ref_mut()?;
|
|
||||||
dup_account.checked_sub_lamports(lamports)?;
|
|
||||||
to_account.checked_add_lamports(lamports)?;
|
|
||||||
}
|
|
||||||
keyed_accounts[first_instruction_account]
|
|
||||||
.try_account_ref_mut()?
|
.try_account_ref_mut()?
|
||||||
.checked_sub_lamports(lamports)?;
|
.checked_sub_lamports(lamports)?;
|
||||||
keyed_accounts[first_instruction_account + 1]
|
keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?
|
||||||
|
.try_account_ref_mut()?
|
||||||
|
.checked_add_lamports(lamports)?;
|
||||||
|
keyed_account_at_index(keyed_accounts, first_instruction_account)?
|
||||||
|
.try_account_ref_mut()?
|
||||||
|
.checked_sub_lamports(lamports)?;
|
||||||
|
keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?
|
||||||
.try_account_ref_mut()?
|
.try_account_ref_mut()?
|
||||||
.checked_add_lamports(lamports)?;
|
.checked_add_lamports(lamports)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -11790,14 +11789,9 @@ pub(crate) mod tests {
|
||||||
invoke_context: &mut dyn InvokeContext,
|
invoke_context: &mut dyn InvokeContext,
|
||||||
) -> result::Result<(), InstructionError> {
|
) -> result::Result<(), InstructionError> {
|
||||||
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
||||||
assert_eq!(
|
let account = keyed_account_at_index(keyed_accounts, first_instruction_account)?;
|
||||||
42,
|
assert_eq!(42, account.lamports().unwrap());
|
||||||
keyed_accounts[first_instruction_account]
|
account.try_account_ref_mut()?.checked_add_lamports(1)?;
|
||||||
.lamports()
|
|
||||||
.unwrap()
|
|
||||||
);
|
|
||||||
let mut account = keyed_accounts[first_instruction_account].try_account_ref_mut()?;
|
|
||||||
account.checked_add_lamports(1)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14598,8 +14592,8 @@ pub(crate) mod tests {
|
||||||
) -> std::result::Result<(), InstructionError> {
|
) -> std::result::Result<(), InstructionError> {
|
||||||
use solana_sdk::account::WritableAccount;
|
use solana_sdk::account::WritableAccount;
|
||||||
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
||||||
let mut data = keyed_accounts[first_instruction_account + 1].try_account_ref_mut()?;
|
let data = keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?;
|
||||||
data.data_as_mut_slice()[0] = 5;
|
data.try_account_ref_mut()?.data_as_mut_slice()[0] = 5;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ use solana_sdk::{
|
||||||
fee_calculator::FeeCalculator,
|
fee_calculator::FeeCalculator,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
ic_logger_msg,
|
ic_logger_msg,
|
||||||
instruction::{CompiledInstruction, Instruction, InstructionError},
|
instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError},
|
||||||
keyed_account::{create_keyed_accounts_unified, KeyedAccount},
|
keyed_account::{create_keyed_accounts_unified, KeyedAccount},
|
||||||
message::Message,
|
message::Message,
|
||||||
precompiles::is_precompile,
|
precompiles::is_precompile,
|
||||||
|
@ -48,6 +48,32 @@ impl ComputeMeter for ThisComputeMeter {
|
||||||
self.remaining
|
self.remaining
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl ThisComputeMeter {
|
||||||
|
pub fn new_ref(remaining: u64) -> Rc<RefCell<Self>> {
|
||||||
|
Rc::new(RefCell::new(Self { remaining }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ThisLogger {
|
||||||
|
log_collector: Option<Rc<LogCollector>>,
|
||||||
|
}
|
||||||
|
impl Logger for ThisLogger {
|
||||||
|
fn log_enabled(&self) -> bool {
|
||||||
|
log_enabled!(log::Level::Info) || self.log_collector.is_some()
|
||||||
|
}
|
||||||
|
fn log(&self, message: &str) {
|
||||||
|
debug!("{}", message);
|
||||||
|
if let Some(log_collector) = &self.log_collector {
|
||||||
|
log_collector.log(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ThisLogger {
|
||||||
|
pub fn new_ref(log_collector: Option<Rc<LogCollector>>) -> Rc<RefCell<Self>> {
|
||||||
|
Rc::new(RefCell::new(Self { log_collector }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ThisInvokeContext<'a> {
|
pub struct ThisInvokeContext<'a> {
|
||||||
instruction_index: usize,
|
instruction_index: usize,
|
||||||
invoke_stack: Vec<InvokeContextStackFrame<'a>>,
|
invoke_stack: Vec<InvokeContextStackFrame<'a>>,
|
||||||
|
@ -63,11 +89,11 @@ pub struct ThisInvokeContext<'a> {
|
||||||
feature_set: Arc<FeatureSet>,
|
feature_set: Arc<FeatureSet>,
|
||||||
pub timings: ExecuteDetailsTimings,
|
pub timings: ExecuteDetailsTimings,
|
||||||
account_db: Arc<Accounts>,
|
account_db: Arc<Accounts>,
|
||||||
ancestors: &'a Ancestors,
|
ancestors: Option<&'a Ancestors>,
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
sysvars: RefCell<Vec<(Pubkey, Option<Rc<Vec<u8>>>)>>,
|
sysvars: RefCell<Vec<(Pubkey, Option<Rc<Vec<u8>>>)>>,
|
||||||
blockhash: &'a Hash,
|
blockhash: Hash,
|
||||||
fee_calculator: &'a FeeCalculator,
|
fee_calculator: FeeCalculator,
|
||||||
return_data: (Pubkey, Vec<u8>),
|
return_data: (Pubkey, Vec<u8>),
|
||||||
}
|
}
|
||||||
impl<'a> ThisInvokeContext<'a> {
|
impl<'a> ThisInvokeContext<'a> {
|
||||||
|
@ -83,9 +109,9 @@ impl<'a> ThisInvokeContext<'a> {
|
||||||
instruction_recorders: Option<&'a [InstructionRecorder]>,
|
instruction_recorders: Option<&'a [InstructionRecorder]>,
|
||||||
feature_set: Arc<FeatureSet>,
|
feature_set: Arc<FeatureSet>,
|
||||||
account_db: Arc<Accounts>,
|
account_db: Arc<Accounts>,
|
||||||
ancestors: &'a Ancestors,
|
ancestors: Option<&'a Ancestors>,
|
||||||
blockhash: &'a Hash,
|
blockhash: Hash,
|
||||||
fee_calculator: &'a FeeCalculator,
|
fee_calculator: FeeCalculator,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
instruction_index: 0,
|
instruction_index: 0,
|
||||||
|
@ -94,7 +120,7 @@ impl<'a> ThisInvokeContext<'a> {
|
||||||
pre_accounts: Vec::new(),
|
pre_accounts: Vec::new(),
|
||||||
accounts,
|
accounts,
|
||||||
programs,
|
programs,
|
||||||
logger: Rc::new(RefCell::new(ThisLogger { log_collector })),
|
logger: ThisLogger::new_ref(log_collector),
|
||||||
compute_budget,
|
compute_budget,
|
||||||
compute_meter,
|
compute_meter,
|
||||||
executors,
|
executors,
|
||||||
|
@ -103,12 +129,41 @@ impl<'a> ThisInvokeContext<'a> {
|
||||||
timings: ExecuteDetailsTimings::default(),
|
timings: ExecuteDetailsTimings::default(),
|
||||||
account_db,
|
account_db,
|
||||||
ancestors,
|
ancestors,
|
||||||
sysvars: RefCell::new(vec![]),
|
sysvars: RefCell::new(Vec::new()),
|
||||||
blockhash,
|
blockhash,
|
||||||
fee_calculator,
|
fee_calculator,
|
||||||
return_data: (Pubkey::default(), Vec::new()),
|
return_data: (Pubkey::default(), Vec::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_mock_with_features(
|
||||||
|
accounts: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
|
||||||
|
programs: &'a [(Pubkey, ProcessInstructionWithContext)],
|
||||||
|
feature_set: Arc<FeatureSet>,
|
||||||
|
) -> Self {
|
||||||
|
Self::new(
|
||||||
|
Rent::default(),
|
||||||
|
accounts,
|
||||||
|
programs,
|
||||||
|
None,
|
||||||
|
ComputeBudget::default(),
|
||||||
|
ThisComputeMeter::new_ref(std::i64::MAX as u64),
|
||||||
|
Rc::new(RefCell::new(Executors::default())),
|
||||||
|
None,
|
||||||
|
feature_set,
|
||||||
|
Arc::new(Accounts::default_for_tests()),
|
||||||
|
None,
|
||||||
|
Hash::default(),
|
||||||
|
FeeCalculator::default(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_mock(
|
||||||
|
accounts: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
|
||||||
|
programs: &'a [(Pubkey, ProcessInstructionWithContext)],
|
||||||
|
) -> Self {
|
||||||
|
Self::new_mock_with_features(accounts, programs, Arc::new(FeatureSet::all_enabled()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl<'a> InvokeContext for ThisInvokeContext<'a> {
|
impl<'a> InvokeContext for ThisInvokeContext<'a> {
|
||||||
fn push(
|
fn push(
|
||||||
|
@ -140,6 +195,10 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.invoke_stack.is_empty() {
|
if self.invoke_stack.is_empty() {
|
||||||
|
if !self.feature_set.is_active(&tx_wide_compute_cap::id()) {
|
||||||
|
self.compute_meter = ThisComputeMeter::new_ref(self.compute_budget.max_units);
|
||||||
|
}
|
||||||
|
|
||||||
self.pre_accounts = Vec::with_capacity(instruction.accounts.len());
|
self.pre_accounts = Vec::with_capacity(instruction.accounts.len());
|
||||||
let mut work = |_unique_index: usize, account_index: usize| {
|
let mut work = |_unique_index: usize, account_index: usize| {
|
||||||
if account_index < self.accounts.len() {
|
if account_index < self.accounts.len() {
|
||||||
|
@ -364,11 +423,6 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
|
||||||
self.executors.borrow().get(pubkey)
|
self.executors.borrow().get(pubkey)
|
||||||
}
|
}
|
||||||
fn set_instruction_index(&mut self, instruction_index: usize) {
|
fn set_instruction_index(&mut self, instruction_index: usize) {
|
||||||
if !self.feature_set.is_active(&tx_wide_compute_cap::id()) {
|
|
||||||
self.compute_meter = Rc::new(RefCell::new(ThisComputeMeter {
|
|
||||||
remaining: self.compute_budget.max_units,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
self.instruction_index = instruction_index;
|
self.instruction_index = instruction_index;
|
||||||
}
|
}
|
||||||
fn record_instruction(&self, instruction: &Instruction) {
|
fn record_instruction(&self, instruction: &Instruction) {
|
||||||
|
@ -399,6 +453,10 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
|
||||||
self.timings.execute_us += execute_us;
|
self.timings.execute_us += execute_us;
|
||||||
self.timings.deserialize_us += deserialize_us;
|
self.timings.deserialize_us += deserialize_us;
|
||||||
}
|
}
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
fn get_sysvars(&self) -> &RefCell<Vec<(Pubkey, Option<Rc<Vec<u8>>>)>> {
|
||||||
|
&self.sysvars
|
||||||
|
}
|
||||||
fn get_sysvar_data(&self, id: &Pubkey) -> Option<Rc<Vec<u8>>> {
|
fn get_sysvar_data(&self, id: &Pubkey) -> Option<Rc<Vec<u8>>> {
|
||||||
if let Ok(mut sysvars) = self.sysvars.try_borrow_mut() {
|
if let Ok(mut sysvars) = self.sysvars.try_borrow_mut() {
|
||||||
// Try share from cache
|
// Try share from cache
|
||||||
|
@ -406,14 +464,16 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
|
||||||
.iter()
|
.iter()
|
||||||
.find_map(|(key, sysvar)| if id == key { sysvar.clone() } else { None });
|
.find_map(|(key, sysvar)| if id == key { sysvar.clone() } else { None });
|
||||||
if result.is_none() {
|
if result.is_none() {
|
||||||
|
if let Some(ancestors) = self.ancestors {
|
||||||
// Load it
|
// Load it
|
||||||
result = self
|
result = self
|
||||||
.account_db
|
.account_db
|
||||||
.load_with_fixed_root(self.ancestors, id)
|
.load_with_fixed_root(ancestors, id)
|
||||||
.map(|(account, _)| Rc::new(account.data().to_vec()));
|
.map(|(account, _)| Rc::new(account.data().to_vec()));
|
||||||
// Cache it
|
// Cache it
|
||||||
sysvars.push((*id, result.clone()));
|
sysvars.push((*id, result.clone()));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
result
|
result
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -422,11 +482,17 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
|
||||||
fn get_compute_budget(&self) -> &ComputeBudget {
|
fn get_compute_budget(&self) -> &ComputeBudget {
|
||||||
&self.compute_budget
|
&self.compute_budget
|
||||||
}
|
}
|
||||||
|
fn set_blockhash(&mut self, hash: Hash) {
|
||||||
|
self.blockhash = hash;
|
||||||
|
}
|
||||||
fn get_blockhash(&self) -> &Hash {
|
fn get_blockhash(&self) -> &Hash {
|
||||||
self.blockhash
|
&self.blockhash
|
||||||
|
}
|
||||||
|
fn set_fee_calculator(&mut self, fee_calculator: FeeCalculator) {
|
||||||
|
self.fee_calculator = fee_calculator;
|
||||||
}
|
}
|
||||||
fn get_fee_calculator(&self) -> &FeeCalculator {
|
fn get_fee_calculator(&self) -> &FeeCalculator {
|
||||||
self.fee_calculator
|
&self.fee_calculator
|
||||||
}
|
}
|
||||||
fn set_return_data(&mut self, data: Vec<u8>) -> Result<(), InstructionError> {
|
fn set_return_data(&mut self, data: Vec<u8>) -> Result<(), InstructionError> {
|
||||||
self.return_data = (*self.get_caller()?, data);
|
self.return_data = (*self.get_caller()?, data);
|
||||||
|
@ -436,19 +502,88 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
|
||||||
(self.return_data.0, &self.return_data.1)
|
(self.return_data.0, &self.return_data.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub struct ThisLogger {
|
|
||||||
log_collector: Option<Rc<LogCollector>>,
|
pub struct MockInvokeContextPreparation {
|
||||||
|
pub accounts: Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>,
|
||||||
|
pub message: Message,
|
||||||
|
pub account_indices: Vec<usize>,
|
||||||
}
|
}
|
||||||
impl Logger for ThisLogger {
|
|
||||||
fn log_enabled(&self) -> bool {
|
pub fn prepare_mock_invoke_context(
|
||||||
log_enabled!(log::Level::Info) || self.log_collector.is_some()
|
program_indices: &[usize],
|
||||||
|
instruction_data: &[u8],
|
||||||
|
keyed_accounts: &[(bool, bool, Pubkey, Rc<RefCell<AccountSharedData>>)],
|
||||||
|
) -> MockInvokeContextPreparation {
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
let (accounts, mut metas): (
|
||||||
|
Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>,
|
||||||
|
Vec<AccountMeta>,
|
||||||
|
) = keyed_accounts
|
||||||
|
.iter()
|
||||||
|
.map(|(is_signer, is_writable, pubkey, account)| {
|
||||||
|
(
|
||||||
|
(*pubkey, account.clone()),
|
||||||
|
AccountMeta {
|
||||||
|
pubkey: *pubkey,
|
||||||
|
is_signer: *is_signer,
|
||||||
|
is_writable: *is_writable,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unzip();
|
||||||
|
let program_id = if let Some(program_index) = program_indices.last() {
|
||||||
|
accounts[*program_index].0
|
||||||
|
} else {
|
||||||
|
Pubkey::default()
|
||||||
|
};
|
||||||
|
for program_index in program_indices.iter().rev() {
|
||||||
|
metas.remove(*program_index);
|
||||||
}
|
}
|
||||||
fn log(&self, message: &str) {
|
let message = Message::new(
|
||||||
debug!("{}", message);
|
&[Instruction::new_with_bytes(
|
||||||
if let Some(log_collector) = &self.log_collector {
|
program_id,
|
||||||
log_collector.log(message);
|
instruction_data,
|
||||||
|
metas,
|
||||||
|
)],
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
let account_indices: Vec<usize> = message
|
||||||
|
.account_keys
|
||||||
|
.iter()
|
||||||
|
.map(|search_key| {
|
||||||
|
accounts
|
||||||
|
.iter()
|
||||||
|
.position(|(key, _account)| key == search_key)
|
||||||
|
.unwrap_or(accounts.len())
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
MockInvokeContextPreparation {
|
||||||
|
accounts,
|
||||||
|
message,
|
||||||
|
account_indices,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mock_process_instruction(
|
||||||
|
loader_id: &Pubkey,
|
||||||
|
mut program_indices: Vec<usize>,
|
||||||
|
instruction_data: &[u8],
|
||||||
|
keyed_accounts: &[(bool, bool, Pubkey, Rc<RefCell<AccountSharedData>>)],
|
||||||
|
process_instruction: ProcessInstructionWithContext,
|
||||||
|
) -> Result<(), InstructionError> {
|
||||||
|
let mut preparation =
|
||||||
|
prepare_mock_invoke_context(&program_indices, instruction_data, keyed_accounts);
|
||||||
|
let processor_account = AccountSharedData::new_ref(0, 0, &solana_sdk::native_loader::id());
|
||||||
|
program_indices.insert(0, preparation.accounts.len());
|
||||||
|
preparation.accounts.push((*loader_id, processor_account));
|
||||||
|
let mut invoke_context = ThisInvokeContext::new_mock(&preparation.accounts, &[]);
|
||||||
|
invoke_context.push(
|
||||||
|
&preparation.message,
|
||||||
|
&preparation.message.instructions[0],
|
||||||
|
&program_indices,
|
||||||
|
Some(&preparation.account_indices),
|
||||||
|
)?;
|
||||||
|
process_instruction(1, instruction_data, &mut invoke_context)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Deserialize, Serialize)]
|
#[derive(Debug, Default, Clone, Deserialize, Serialize)]
|
||||||
|
@ -500,9 +635,9 @@ impl MessageProcessor {
|
||||||
instruction_recorders,
|
instruction_recorders,
|
||||||
feature_set,
|
feature_set,
|
||||||
account_db,
|
account_db,
|
||||||
ancestors,
|
Some(ancestors),
|
||||||
&blockhash,
|
blockhash,
|
||||||
&fee_calculator,
|
fee_calculator,
|
||||||
);
|
);
|
||||||
let compute_meter = invoke_context.get_compute_meter();
|
let compute_meter = invoke_context.get_compute_meter();
|
||||||
|
|
||||||
|
@ -585,9 +720,9 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
instruction::{AccountMeta, Instruction, InstructionError},
|
instruction::{AccountMeta, Instruction, InstructionError},
|
||||||
|
keyed_account::keyed_account_at_index,
|
||||||
message::Message,
|
message::Message,
|
||||||
native_loader::{self, create_loadable_account_for_test},
|
native_loader::{self, create_loadable_account_for_test},
|
||||||
process_instruction::MockComputeMeter,
|
|
||||||
secp256k1_instruction::new_secp256k1_instruction,
|
secp256k1_instruction::new_secp256k1_instruction,
|
||||||
secp256k1_program,
|
secp256k1_program,
|
||||||
};
|
};
|
||||||
|
@ -610,11 +745,11 @@ mod tests {
|
||||||
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*program_id,
|
*program_id,
|
||||||
keyed_accounts[first_instruction_account].owner()?
|
keyed_account_at_index(keyed_accounts, first_instruction_account)?.owner()?
|
||||||
);
|
);
|
||||||
assert_ne!(
|
assert_ne!(
|
||||||
keyed_accounts[first_instruction_account + 1].owner()?,
|
keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?.owner()?,
|
||||||
*keyed_accounts[first_instruction_account].unsigned_key()
|
*keyed_account_at_index(keyed_accounts, first_instruction_account)?.unsigned_key()
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Ok(instruction) = bincode::deserialize(data) {
|
if let Ok(instruction) = bincode::deserialize(data) {
|
||||||
|
@ -622,17 +757,17 @@ mod tests {
|
||||||
MockInstruction::NoopSuccess => (),
|
MockInstruction::NoopSuccess => (),
|
||||||
MockInstruction::NoopFail => return Err(InstructionError::GenericError),
|
MockInstruction::NoopFail => return Err(InstructionError::GenericError),
|
||||||
MockInstruction::ModifyOwned => {
|
MockInstruction::ModifyOwned => {
|
||||||
keyed_accounts[first_instruction_account]
|
keyed_account_at_index(keyed_accounts, first_instruction_account)?
|
||||||
.try_account_ref_mut()?
|
.try_account_ref_mut()?
|
||||||
.data_as_mut_slice()[0] = 1
|
.data_as_mut_slice()[0] = 1
|
||||||
}
|
}
|
||||||
MockInstruction::ModifyNotOwned => {
|
MockInstruction::ModifyNotOwned => {
|
||||||
keyed_accounts[first_instruction_account + 1]
|
keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?
|
||||||
.try_account_ref_mut()?
|
.try_account_ref_mut()?
|
||||||
.data_as_mut_slice()[0] = 1
|
.data_as_mut_slice()[0] = 1
|
||||||
}
|
}
|
||||||
MockInstruction::ModifyReadonly => {
|
MockInstruction::ModifyReadonly => {
|
||||||
keyed_accounts[first_instruction_account + 2]
|
keyed_account_at_index(keyed_accounts, first_instruction_account + 2)?
|
||||||
.try_account_ref_mut()?
|
.try_account_ref_mut()?
|
||||||
.data_as_mut_slice()[0] = 1
|
.data_as_mut_slice()[0] = 1
|
||||||
}
|
}
|
||||||
|
@ -678,24 +813,7 @@ mod tests {
|
||||||
&[Instruction::new_with_bytes(invoke_stack[0], &[0], metas)],
|
&[Instruction::new_with_bytes(invoke_stack[0], &[0], metas)],
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
let ancestors = Ancestors::default();
|
let mut invoke_context = ThisInvokeContext::new_mock(&accounts, &[]);
|
||||||
let blockhash = Hash::default();
|
|
||||||
let fee_calculator = FeeCalculator::default();
|
|
||||||
let mut invoke_context = ThisInvokeContext::new(
|
|
||||||
Rent::default(),
|
|
||||||
&accounts,
|
|
||||||
&[],
|
|
||||||
None,
|
|
||||||
ComputeBudget::default(),
|
|
||||||
Rc::new(RefCell::new(MockComputeMeter::default())),
|
|
||||||
Rc::new(RefCell::new(Executors::default())),
|
|
||||||
None,
|
|
||||||
Arc::new(FeatureSet::all_enabled()),
|
|
||||||
Arc::new(Accounts::default_for_tests()),
|
|
||||||
&ancestors,
|
|
||||||
&blockhash,
|
|
||||||
&fee_calculator,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check call depth increases and has a limit
|
// Check call depth increases and has a limit
|
||||||
let mut depth_reached = 0;
|
let mut depth_reached = 0;
|
||||||
|
@ -782,24 +900,7 @@ mod tests {
|
||||||
)],
|
)],
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
let ancestors = Ancestors::default();
|
let mut invoke_context = ThisInvokeContext::new_mock(&accounts, &[]);
|
||||||
let blockhash = Hash::default();
|
|
||||||
let fee_calculator = FeeCalculator::default();
|
|
||||||
let mut invoke_context = ThisInvokeContext::new(
|
|
||||||
Rent::default(),
|
|
||||||
&accounts,
|
|
||||||
&[],
|
|
||||||
None,
|
|
||||||
ComputeBudget::default(),
|
|
||||||
Rc::new(RefCell::new(MockComputeMeter::default())),
|
|
||||||
Rc::new(RefCell::new(Executors::default())),
|
|
||||||
None,
|
|
||||||
Arc::new(FeatureSet::all_enabled()),
|
|
||||||
Arc::new(Accounts::default_for_tests()),
|
|
||||||
&ancestors,
|
|
||||||
&blockhash,
|
|
||||||
&fee_calculator,
|
|
||||||
);
|
|
||||||
invoke_context
|
invoke_context
|
||||||
.push(&message, &message.instructions[0], &[0], None)
|
.push(&message, &message.instructions[0], &[0], None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -833,11 +934,11 @@ mod tests {
|
||||||
match instruction {
|
match instruction {
|
||||||
MockSystemInstruction::Correct => Ok(()),
|
MockSystemInstruction::Correct => Ok(()),
|
||||||
MockSystemInstruction::AttemptCredit { lamports } => {
|
MockSystemInstruction::AttemptCredit { lamports } => {
|
||||||
keyed_accounts[first_instruction_account]
|
keyed_account_at_index(keyed_accounts, first_instruction_account)?
|
||||||
.account
|
.account
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.checked_sub_lamports(lamports)?;
|
.checked_sub_lamports(lamports)?;
|
||||||
keyed_accounts[first_instruction_account + 1]
|
keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?
|
||||||
.account
|
.account
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.checked_add_lamports(lamports)?;
|
.checked_add_lamports(lamports)?;
|
||||||
|
@ -845,7 +946,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
// Change data in a read-only account
|
// Change data in a read-only account
|
||||||
MockSystemInstruction::AttemptDataChange { data } => {
|
MockSystemInstruction::AttemptDataChange { data } => {
|
||||||
keyed_accounts[first_instruction_account + 1]
|
keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?
|
||||||
.account
|
.account
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.set_data(vec![data]);
|
.set_data(vec![data]);
|
||||||
|
@ -905,7 +1006,7 @@ mod tests {
|
||||||
None,
|
None,
|
||||||
Arc::new(FeatureSet::all_enabled()),
|
Arc::new(FeatureSet::all_enabled()),
|
||||||
ComputeBudget::new(),
|
ComputeBudget::new(),
|
||||||
Rc::new(RefCell::new(MockComputeMeter::default())),
|
ThisComputeMeter::new_ref(std::i64::MAX as u64),
|
||||||
&mut ExecuteDetailsTimings::default(),
|
&mut ExecuteDetailsTimings::default(),
|
||||||
Arc::new(Accounts::default_for_tests()),
|
Arc::new(Accounts::default_for_tests()),
|
||||||
&ancestors,
|
&ancestors,
|
||||||
|
@ -936,7 +1037,7 @@ mod tests {
|
||||||
None,
|
None,
|
||||||
Arc::new(FeatureSet::all_enabled()),
|
Arc::new(FeatureSet::all_enabled()),
|
||||||
ComputeBudget::new(),
|
ComputeBudget::new(),
|
||||||
Rc::new(RefCell::new(MockComputeMeter::default())),
|
ThisComputeMeter::new_ref(std::i64::MAX as u64),
|
||||||
&mut ExecuteDetailsTimings::default(),
|
&mut ExecuteDetailsTimings::default(),
|
||||||
Arc::new(Accounts::default_for_tests()),
|
Arc::new(Accounts::default_for_tests()),
|
||||||
&ancestors,
|
&ancestors,
|
||||||
|
@ -971,7 +1072,7 @@ mod tests {
|
||||||
None,
|
None,
|
||||||
Arc::new(FeatureSet::all_enabled()),
|
Arc::new(FeatureSet::all_enabled()),
|
||||||
ComputeBudget::new(),
|
ComputeBudget::new(),
|
||||||
Rc::new(RefCell::new(MockComputeMeter::default())),
|
ThisComputeMeter::new_ref(std::i64::MAX as u64),
|
||||||
&mut ExecuteDetailsTimings::default(),
|
&mut ExecuteDetailsTimings::default(),
|
||||||
Arc::new(Accounts::default_for_tests()),
|
Arc::new(Accounts::default_for_tests()),
|
||||||
&ancestors,
|
&ancestors,
|
||||||
|
@ -1006,9 +1107,11 @@ mod tests {
|
||||||
match instruction {
|
match instruction {
|
||||||
MockSystemInstruction::BorrowFail => {
|
MockSystemInstruction::BorrowFail => {
|
||||||
let from_account =
|
let from_account =
|
||||||
keyed_accounts[first_instruction_account].try_account_ref_mut()?;
|
keyed_account_at_index(keyed_accounts, first_instruction_account)?
|
||||||
|
.try_account_ref_mut()?;
|
||||||
let dup_account =
|
let dup_account =
|
||||||
keyed_accounts[first_instruction_account + 2].try_account_ref_mut()?;
|
keyed_account_at_index(keyed_accounts, first_instruction_account + 2)?
|
||||||
|
.try_account_ref_mut()?;
|
||||||
if from_account.lamports() != dup_account.lamports() {
|
if from_account.lamports() != dup_account.lamports() {
|
||||||
return Err(InstructionError::InvalidArgument);
|
return Err(InstructionError::InvalidArgument);
|
||||||
}
|
}
|
||||||
|
@ -1017,11 +1120,15 @@ mod tests {
|
||||||
MockSystemInstruction::MultiBorrowMut => {
|
MockSystemInstruction::MultiBorrowMut => {
|
||||||
let from_lamports = {
|
let from_lamports = {
|
||||||
let from_account =
|
let from_account =
|
||||||
keyed_accounts[first_instruction_account].try_account_ref_mut()?;
|
keyed_account_at_index(keyed_accounts, first_instruction_account)?
|
||||||
|
.try_account_ref_mut()?;
|
||||||
from_account.lamports()
|
from_account.lamports()
|
||||||
};
|
};
|
||||||
let dup_lamports = {
|
let dup_lamports = {
|
||||||
let dup_account = keyed_accounts[first_instruction_account + 2]
|
let dup_account = keyed_account_at_index(
|
||||||
|
keyed_accounts,
|
||||||
|
first_instruction_account + 2,
|
||||||
|
)?
|
||||||
.try_account_ref_mut()?;
|
.try_account_ref_mut()?;
|
||||||
dup_account.lamports()
|
dup_account.lamports()
|
||||||
};
|
};
|
||||||
|
@ -1032,18 +1139,24 @@ mod tests {
|
||||||
}
|
}
|
||||||
MockSystemInstruction::DoWork { lamports, data } => {
|
MockSystemInstruction::DoWork { lamports, data } => {
|
||||||
{
|
{
|
||||||
let mut to_account = keyed_accounts[first_instruction_account + 1]
|
let mut to_account = keyed_account_at_index(
|
||||||
|
keyed_accounts,
|
||||||
|
first_instruction_account + 1,
|
||||||
|
)?
|
||||||
.try_account_ref_mut()?;
|
.try_account_ref_mut()?;
|
||||||
let mut dup_account = keyed_accounts[first_instruction_account + 2]
|
let mut dup_account = keyed_account_at_index(
|
||||||
|
keyed_accounts,
|
||||||
|
first_instruction_account + 2,
|
||||||
|
)?
|
||||||
.try_account_ref_mut()?;
|
.try_account_ref_mut()?;
|
||||||
dup_account.checked_sub_lamports(lamports)?;
|
dup_account.checked_sub_lamports(lamports)?;
|
||||||
to_account.checked_add_lamports(lamports)?;
|
to_account.checked_add_lamports(lamports)?;
|
||||||
dup_account.set_data(vec![data]);
|
dup_account.set_data(vec![data]);
|
||||||
}
|
}
|
||||||
keyed_accounts[first_instruction_account]
|
keyed_account_at_index(keyed_accounts, first_instruction_account)?
|
||||||
.try_account_ref_mut()?
|
.try_account_ref_mut()?
|
||||||
.checked_sub_lamports(lamports)?;
|
.checked_sub_lamports(lamports)?;
|
||||||
keyed_accounts[first_instruction_account + 1]
|
keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?
|
||||||
.try_account_ref_mut()?
|
.try_account_ref_mut()?
|
||||||
.checked_add_lamports(lamports)?;
|
.checked_add_lamports(lamports)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1104,7 +1217,7 @@ mod tests {
|
||||||
None,
|
None,
|
||||||
Arc::new(FeatureSet::all_enabled()),
|
Arc::new(FeatureSet::all_enabled()),
|
||||||
ComputeBudget::new(),
|
ComputeBudget::new(),
|
||||||
Rc::new(RefCell::new(MockComputeMeter::default())),
|
ThisComputeMeter::new_ref(std::i64::MAX as u64),
|
||||||
&mut ExecuteDetailsTimings::default(),
|
&mut ExecuteDetailsTimings::default(),
|
||||||
Arc::new(Accounts::default_for_tests()),
|
Arc::new(Accounts::default_for_tests()),
|
||||||
&ancestors,
|
&ancestors,
|
||||||
|
@ -1139,7 +1252,7 @@ mod tests {
|
||||||
None,
|
None,
|
||||||
Arc::new(FeatureSet::all_enabled()),
|
Arc::new(FeatureSet::all_enabled()),
|
||||||
ComputeBudget::new(),
|
ComputeBudget::new(),
|
||||||
Rc::new(RefCell::new(MockComputeMeter::default())),
|
ThisComputeMeter::new_ref(std::i64::MAX as u64),
|
||||||
&mut ExecuteDetailsTimings::default(),
|
&mut ExecuteDetailsTimings::default(),
|
||||||
Arc::new(Accounts::default_for_tests()),
|
Arc::new(Accounts::default_for_tests()),
|
||||||
&ancestors,
|
&ancestors,
|
||||||
|
@ -1172,7 +1285,7 @@ mod tests {
|
||||||
None,
|
None,
|
||||||
Arc::new(FeatureSet::all_enabled()),
|
Arc::new(FeatureSet::all_enabled()),
|
||||||
ComputeBudget::new(),
|
ComputeBudget::new(),
|
||||||
Rc::new(RefCell::new(MockComputeMeter::default())),
|
ThisComputeMeter::new_ref(std::i64::MAX as u64),
|
||||||
&mut ExecuteDetailsTimings::default(),
|
&mut ExecuteDetailsTimings::default(),
|
||||||
Arc::new(Accounts::default_for_tests()),
|
Arc::new(Accounts::default_for_tests()),
|
||||||
&ancestors,
|
&ancestors,
|
||||||
|
@ -1233,24 +1346,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
let message = Message::new(&[callee_instruction], None);
|
let message = Message::new(&[callee_instruction], None);
|
||||||
|
|
||||||
let ancestors = Ancestors::default();
|
let mut invoke_context = ThisInvokeContext::new_mock(&accounts, programs.as_slice());
|
||||||
let blockhash = Hash::default();
|
|
||||||
let fee_calculator = FeeCalculator::default();
|
|
||||||
let mut invoke_context = ThisInvokeContext::new(
|
|
||||||
Rent::default(),
|
|
||||||
&accounts,
|
|
||||||
programs.as_slice(),
|
|
||||||
None,
|
|
||||||
ComputeBudget::default(),
|
|
||||||
Rc::new(RefCell::new(MockComputeMeter::default())),
|
|
||||||
Rc::new(RefCell::new(Executors::default())),
|
|
||||||
None,
|
|
||||||
Arc::new(FeatureSet::all_enabled()),
|
|
||||||
Arc::new(Accounts::default_for_tests()),
|
|
||||||
&ancestors,
|
|
||||||
&blockhash,
|
|
||||||
&fee_calculator,
|
|
||||||
);
|
|
||||||
invoke_context
|
invoke_context
|
||||||
.push(&message, &caller_instruction, &program_indices[..1], None)
|
.push(&message, &caller_instruction, &program_indices[..1], None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -1378,24 +1474,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
let message = Message::new(&[callee_instruction.clone()], None);
|
let message = Message::new(&[callee_instruction.clone()], None);
|
||||||
|
|
||||||
let ancestors = Ancestors::default();
|
let mut invoke_context = ThisInvokeContext::new_mock(&accounts, programs.as_slice());
|
||||||
let blockhash = Hash::default();
|
|
||||||
let fee_calculator = FeeCalculator::default();
|
|
||||||
let mut invoke_context = ThisInvokeContext::new(
|
|
||||||
Rent::default(),
|
|
||||||
&accounts,
|
|
||||||
programs.as_slice(),
|
|
||||||
None,
|
|
||||||
ComputeBudget::default(),
|
|
||||||
Rc::new(RefCell::new(MockComputeMeter::default())),
|
|
||||||
Rc::new(RefCell::new(Executors::default())),
|
|
||||||
None,
|
|
||||||
Arc::new(FeatureSet::all_enabled()),
|
|
||||||
Arc::new(Accounts::default_for_tests()),
|
|
||||||
&ancestors,
|
|
||||||
&blockhash,
|
|
||||||
&fee_calculator,
|
|
||||||
);
|
|
||||||
invoke_context
|
invoke_context
|
||||||
.push(&message, &caller_instruction, &program_indices, None)
|
.push(&message, &caller_instruction, &program_indices, None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -1509,7 +1588,7 @@ mod tests {
|
||||||
None,
|
None,
|
||||||
Arc::new(FeatureSet::all_enabled()),
|
Arc::new(FeatureSet::all_enabled()),
|
||||||
ComputeBudget::new(),
|
ComputeBudget::new(),
|
||||||
Rc::new(RefCell::new(MockComputeMeter::default())),
|
ThisComputeMeter::new_ref(std::i64::MAX as u64),
|
||||||
&mut ExecuteDetailsTimings::default(),
|
&mut ExecuteDetailsTimings::default(),
|
||||||
Arc::new(Accounts::default_for_tests()),
|
Arc::new(Accounts::default_for_tests()),
|
||||||
&Ancestors::default(),
|
&Ancestors::default(),
|
||||||
|
|
|
@ -121,12 +121,19 @@ pub trait InvokeContext {
|
||||||
execute_us: u64,
|
execute_us: u64,
|
||||||
deserialize_us: u64,
|
deserialize_us: u64,
|
||||||
);
|
);
|
||||||
|
/// Get sysvars
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
fn get_sysvars(&self) -> &RefCell<Vec<(Pubkey, Option<Rc<Vec<u8>>>)>>;
|
||||||
/// Get sysvar data
|
/// Get sysvar data
|
||||||
fn get_sysvar_data(&self, id: &Pubkey) -> Option<Rc<Vec<u8>>>;
|
fn get_sysvar_data(&self, id: &Pubkey) -> Option<Rc<Vec<u8>>>;
|
||||||
/// Get this invocation's compute budget
|
/// Get this invocation's compute budget
|
||||||
fn get_compute_budget(&self) -> &ComputeBudget;
|
fn get_compute_budget(&self) -> &ComputeBudget;
|
||||||
|
/// Set this invocation's blockhash
|
||||||
|
fn set_blockhash(&mut self, hash: Hash);
|
||||||
/// Get this invocation's blockhash
|
/// Get this invocation's blockhash
|
||||||
fn get_blockhash(&self) -> &Hash;
|
fn get_blockhash(&self) -> &Hash;
|
||||||
|
/// Set this invocation's `FeeCalculator`
|
||||||
|
fn set_fee_calculator(&mut self, fee_calculator: FeeCalculator);
|
||||||
/// Get this invocation's `FeeCalculator`
|
/// Get this invocation's `FeeCalculator`
|
||||||
fn get_fee_calculator(&self) -> &FeeCalculator;
|
fn get_fee_calculator(&self) -> &FeeCalculator;
|
||||||
/// Set the return data
|
/// Set the return data
|
||||||
|
@ -350,7 +357,8 @@ pub struct MockInvokeContext<'a> {
|
||||||
pub compute_meter: MockComputeMeter,
|
pub compute_meter: MockComputeMeter,
|
||||||
pub programs: Vec<(Pubkey, ProcessInstructionWithContext)>,
|
pub programs: Vec<(Pubkey, ProcessInstructionWithContext)>,
|
||||||
pub accounts: Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>,
|
pub accounts: Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>,
|
||||||
pub sysvars: Vec<(Pubkey, Option<Rc<Vec<u8>>>)>,
|
#[allow(clippy::type_complexity)]
|
||||||
|
pub sysvars: RefCell<Vec<(Pubkey, Option<Rc<Vec<u8>>>)>>,
|
||||||
pub disabled_features: HashSet<Pubkey>,
|
pub disabled_features: HashSet<Pubkey>,
|
||||||
pub blockhash: Hash,
|
pub blockhash: Hash,
|
||||||
pub fee_calculator: FeeCalculator,
|
pub fee_calculator: FeeCalculator,
|
||||||
|
@ -369,7 +377,7 @@ impl<'a> MockInvokeContext<'a> {
|
||||||
},
|
},
|
||||||
programs: vec![],
|
programs: vec![],
|
||||||
accounts: vec![],
|
accounts: vec![],
|
||||||
sysvars: vec![],
|
sysvars: RefCell::new(Vec::new()),
|
||||||
disabled_features: HashSet::default(),
|
disabled_features: HashSet::default(),
|
||||||
blockhash: Hash::default(),
|
blockhash: Hash::default(),
|
||||||
fee_calculator: FeeCalculator::default(),
|
fee_calculator: FeeCalculator::default(),
|
||||||
|
@ -390,21 +398,6 @@ impl<'a> MockInvokeContext<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mock_set_sysvar<T: Sysvar>(
|
|
||||||
mock_invoke_context: &mut MockInvokeContext,
|
|
||||||
id: Pubkey,
|
|
||||||
sysvar: T,
|
|
||||||
) -> Result<(), InstructionError> {
|
|
||||||
let mut data = Vec::with_capacity(T::size_of());
|
|
||||||
|
|
||||||
bincode::serialize_into(&mut data, &sysvar).map_err(|err| {
|
|
||||||
ic_msg!(mock_invoke_context, "Unable to serialize sysvar: {:?}", err);
|
|
||||||
InstructionError::GenericError
|
|
||||||
})?;
|
|
||||||
mock_invoke_context.sysvars.push((id, Some(Rc::new(data))));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> InvokeContext for MockInvokeContext<'a> {
|
impl<'a> InvokeContext for MockInvokeContext<'a> {
|
||||||
fn push(
|
fn push(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -498,17 +491,28 @@ impl<'a> InvokeContext for MockInvokeContext<'a> {
|
||||||
_deserialize_us: u64,
|
_deserialize_us: u64,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
fn get_sysvars(&self) -> &RefCell<Vec<(Pubkey, Option<Rc<Vec<u8>>>)>> {
|
||||||
|
&self.sysvars
|
||||||
|
}
|
||||||
fn get_sysvar_data(&self, id: &Pubkey) -> Option<Rc<Vec<u8>>> {
|
fn get_sysvar_data(&self, id: &Pubkey) -> Option<Rc<Vec<u8>>> {
|
||||||
self.sysvars
|
self.sysvars
|
||||||
|
.borrow()
|
||||||
.iter()
|
.iter()
|
||||||
.find_map(|(key, sysvar)| if id == key { sysvar.clone() } else { None })
|
.find_map(|(key, sysvar)| if id == key { sysvar.clone() } else { None })
|
||||||
}
|
}
|
||||||
fn get_compute_budget(&self) -> &ComputeBudget {
|
fn get_compute_budget(&self) -> &ComputeBudget {
|
||||||
&self.compute_budget
|
&self.compute_budget
|
||||||
}
|
}
|
||||||
|
fn set_blockhash(&mut self, hash: Hash) {
|
||||||
|
self.blockhash = hash;
|
||||||
|
}
|
||||||
fn get_blockhash(&self) -> &Hash {
|
fn get_blockhash(&self) -> &Hash {
|
||||||
&self.blockhash
|
&self.blockhash
|
||||||
}
|
}
|
||||||
|
fn set_fee_calculator(&mut self, fee_calculator: FeeCalculator) {
|
||||||
|
self.fee_calculator = fee_calculator;
|
||||||
|
}
|
||||||
fn get_fee_calculator(&self) -> &FeeCalculator {
|
fn get_fee_calculator(&self) -> &FeeCalculator {
|
||||||
&self.fee_calculator
|
&self.fee_calculator
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue