Refactoring: Move KeyedAccounts to InvokeContext (#15410)

Collects all parametric occurrences and the construction of keyed_accounts and puts them into InvokeContext.
This commit is contained in:
Alexander Meißner 2021-04-19 18:48:48 +02:00 committed by GitHub
parent 015bc034a5
commit 9dfcb921cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 1508 additions and 1408 deletions

View File

@ -25,7 +25,6 @@ use {
hash::Hash,
instruction::Instruction,
instruction::InstructionError,
keyed_account::KeyedAccount,
message::Message,
native_token::sol_to_lamports,
process_instruction::{
@ -99,12 +98,13 @@ fn get_invoke_context<'a>() -> &'a mut dyn InvokeContext {
pub fn builtin_process_instruction(
process_instruction: solana_sdk::entrypoint::ProcessInstruction,
program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
input: &[u8],
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
set_invoke_context(invoke_context);
let keyed_accounts = invoke_context.get_keyed_accounts()?;
// Copy all the accounts into a HashMap to ensure there are no duplicates
let mut accounts: HashMap<Pubkey, Account> = keyed_accounts
.iter()
@ -172,13 +172,11 @@ macro_rules! processor {
($process_instruction:expr) => {
Some(
|program_id: &Pubkey,
keyed_accounts: &[solana_sdk::keyed_account::KeyedAccount],
input: &[u8],
invoke_context: &mut dyn solana_sdk::process_instruction::InvokeContext| {
$crate::builtin_process_instruction(
$process_instruction,
program_id,
keyed_accounts,
input,
invoke_context,
)

View File

@ -76,7 +76,7 @@ fn bench_program_create_executable(bencher: &mut Bencher) {
bencher.iter(|| {
let _ =
Executable::<BpfError, ThisInstructionMeter>::from_elf(&elf, None, Config::default())
<dyn Executable::<BpfError, ThisInstructionMeter>>::from_elf(&elf, None, Config::default())
.unwrap();
});
}
@ -91,11 +91,11 @@ fn bench_program_alu(bencher: &mut Bencher) {
.unwrap();
inner_iter.write_u64::<LittleEndian>(0).unwrap();
let loader_id = bpf_loader::id();
let mut invoke_context = MockInvokeContext::default();
let mut invoke_context = MockInvokeContext::new(vec![]);
let elf = load_elf("bench_alu").unwrap();
let mut executable =
Executable::<BpfError, ThisInstructionMeter>::from_elf(&elf, None, Config::default())
<dyn Executable::<BpfError, ThisInstructionMeter>>::from_elf(&elf, None, Config::default())
.unwrap();
executable.set_syscall_registry(register_syscalls(&mut invoke_context).unwrap());
executable.jit_compile().unwrap();
@ -105,7 +105,6 @@ fn bench_program_alu(bencher: &mut Bencher) {
&loader_id,
executable.as_ref(),
&mut inner_iter,
&[],
&mut invoke_context,
)
.unwrap();
@ -195,8 +194,6 @@ fn bench_program_execute_noop(bencher: &mut Bencher) {
fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
const BUDGET: u64 = 200_000;
let loader_id = bpf_loader::id();
let mut invoke_context = MockInvokeContext::default();
invoke_context.compute_meter.remaining = BUDGET;
let accounts = [RefCell::new(AccountSharedData::new(
1,
@ -211,18 +208,22 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
.collect();
let instruction_data = vec![0u8];
let mut invoke_context = MockInvokeContext::new(keyed_accounts);
invoke_context.compute_meter.remaining = BUDGET;
// Serialize account data
let keyed_accounts = invoke_context.get_keyed_accounts().unwrap();
let mut serialized = serialize_parameters(
&bpf_loader::id(),
&solana_sdk::pubkey::new_rand(),
&keyed_accounts,
keyed_accounts,
&instruction_data,
)
.unwrap();
let elf = load_elf("tuner").unwrap();
let mut executable =
Executable::<BpfError, ThisInstructionMeter>::from_elf(&elf, None, Config::default())
<dyn Executable::<BpfError, ThisInstructionMeter>>::from_elf(&elf, None, Config::default())
.unwrap();
executable.set_syscall_registry(register_syscalls(&mut invoke_context).unwrap());
let compute_meter = invoke_context.get_compute_meter();
@ -231,7 +232,6 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
&loader_id,
executable.as_ref(),
&mut serialized,
&[],
&mut invoke_context,
)
.unwrap();

View File

@ -179,7 +179,7 @@ fn upgrade_bpf_program(
fn run_program(
name: &str,
program_id: &Pubkey,
parameter_accounts: &[KeyedAccount],
parameter_accounts: Vec<KeyedAccount>,
instruction_data: &[u8],
) -> Result<u64, InstructionError> {
let path = create_bpf_path(name);
@ -188,14 +188,14 @@ fn run_program(
let mut data = vec![];
file.read_to_end(&mut data).unwrap();
let loader_id = bpf_loader::id();
let mut invoke_context = MockInvokeContext::default();
let parameter_bytes = serialize_parameters(
&bpf_loader::id(),
program_id,
parameter_accounts,
&parameter_accounts,
&instruction_data,
)
.unwrap();
let mut invoke_context = MockInvokeContext::new(parameter_accounts);
let compute_meter = invoke_context.get_compute_meter();
let mut instruction_meter = ThisInstructionMeter { compute_meter };
@ -213,20 +213,46 @@ fn run_program(
let mut tracer = None;
for i in 0..2 {
let mut parameter_bytes = parameter_bytes.clone();
let mut vm = create_vm(
&loader_id,
executable.as_ref(),
&mut parameter_bytes,
parameter_accounts,
&mut invoke_context,
)
.unwrap();
let result = if i == 0 {
vm.execute_program_interpreted(&mut instruction_meter)
} else {
vm.execute_program_jit(&mut instruction_meter)
};
assert_eq!(SUCCESS, result.unwrap());
{
let mut vm = create_vm(
&loader_id,
executable.as_ref(),
&mut parameter_bytes,
&mut invoke_context,
)
.unwrap();
let result = if i == 0 {
vm.execute_program_interpreted(&mut instruction_meter)
} else {
vm.execute_program_jit(&mut instruction_meter)
};
assert_eq!(SUCCESS, result.unwrap());
if i == 1 {
assert_eq!(instruction_count, vm.get_total_instruction_count());
}
instruction_count = vm.get_total_instruction_count();
if config.enable_instruction_tracing {
if i == 1 {
if !Tracer::compare(tracer.as_ref().unwrap(), vm.get_tracer()) {
let mut tracer_display = String::new();
tracer
.as_ref()
.unwrap()
.write(&mut tracer_display, vm.get_program())
.unwrap();
println!("TRACE (interpreted): {}", tracer_display);
let mut tracer_display = String::new();
vm.get_tracer()
.write(&mut tracer_display, vm.get_program())
.unwrap();
println!("TRACE (jit): {}", tracer_display);
assert!(false);
}
}
tracer = Some(vm.get_tracer().clone());
}
}
let parameter_accounts = invoke_context.get_keyed_accounts().unwrap();
deserialize_parameters(
&bpf_loader::id(),
parameter_accounts,
@ -234,30 +260,6 @@ fn run_program(
true,
)
.unwrap();
if i == 1 {
assert_eq!(instruction_count, vm.get_total_instruction_count());
}
instruction_count = vm.get_total_instruction_count();
if config.enable_instruction_tracing {
if i == 1 {
if !Tracer::compare(tracer.as_ref().unwrap(), vm.get_tracer()) {
let mut tracer_display = String::new();
tracer
.as_ref()
.unwrap()
.write(&mut tracer_display, vm.get_program())
.unwrap();
println!("TRACE (interpreted): {}", tracer_display);
let mut tracer_display = String::new();
vm.get_tracer()
.write(&mut tracer_display, vm.get_program())
.unwrap();
println!("TRACE (jit): {}", tracer_display);
assert!(false);
}
}
tracer = Some(vm.get_tracer().clone());
}
}
Ok(instruction_count)
@ -1263,7 +1265,7 @@ fn assert_instruction_count() {
let key = solana_sdk::pubkey::new_rand();
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 count = run_program(program.0, &program_id, parameter_accounts, &[]).unwrap();
let diff: i64 = count as i64 - program.1 as i64;
println!(" {:30} {:8} {:6} {:+4}", program.0, program.1, count, diff);
if count > program.1 {

File diff suppressed because it is too large Load Diff

View File

@ -169,7 +169,6 @@ macro_rules! bind_feature_gated_syscall_context_object {
pub fn bind_syscall_context_objects<'a>(
loader_id: &'a Pubkey,
vm: &mut EbpfVm<'a, BpfError, crate::ThisInstructionMeter>,
callers_keyed_accounts: &'a [KeyedAccount<'a>],
invoke_context: &'a mut dyn InvokeContext,
heap: Vec<u8>,
) -> Result<(), EbpfError<BpfError>> {
@ -299,7 +298,6 @@ pub fn bind_syscall_context_objects<'a>(
// Cross-program invocation syscalls
vm.bind_syscall_context_object(
Box::new(SyscallInvokeSignedC {
callers_keyed_accounts,
invoke_context: invoke_context.clone(),
loader_id,
}),
@ -307,7 +305,6 @@ pub fn bind_syscall_context_objects<'a>(
)?;
vm.bind_syscall_context_object(
Box::new(SyscallInvokeSignedRust {
callers_keyed_accounts,
invoke_context: invoke_context.clone(),
loader_id,
}),
@ -1029,7 +1026,6 @@ type TranslatedAccounts<'a> = (
trait SyscallInvokeSigned<'a> {
fn get_context_mut(&self) -> Result<RefMut<&'a mut dyn InvokeContext>, EbpfError<BpfError>>;
fn get_context(&self) -> Result<Ref<&'a mut dyn InvokeContext>, EbpfError<BpfError>>;
fn get_callers_keyed_accounts(&self) -> &'a [KeyedAccount<'a>];
fn translate_instruction(
&self,
addr: u64,
@ -1055,7 +1051,6 @@ trait SyscallInvokeSigned<'a> {
/// Cross-program invocation called from Rust
pub struct SyscallInvokeSignedRust<'a> {
callers_keyed_accounts: &'a [KeyedAccount<'a>],
invoke_context: Rc<RefCell<&'a mut dyn InvokeContext>>,
loader_id: &'a Pubkey,
}
@ -1070,9 +1065,6 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> {
.try_borrow()
.map_err(|_| SyscallError::InvokeContextBorrowFailed.into())
}
fn get_callers_keyed_accounts(&self) -> &'a [KeyedAccount<'a>] {
self.callers_keyed_accounts
}
fn translate_instruction(
&self,
addr: u64,
@ -1350,7 +1342,6 @@ struct SolSignerSeedsC {
/// Cross-program invocation called from C
pub struct SyscallInvokeSignedC<'a> {
callers_keyed_accounts: &'a [KeyedAccount<'a>],
invoke_context: Rc<RefCell<&'a mut dyn InvokeContext>>,
loader_id: &'a Pubkey,
}
@ -1366,10 +1357,6 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> {
.map_err(|_| SyscallError::InvokeContextBorrowFailed.into())
}
fn get_callers_keyed_accounts(&self) -> &'a [KeyedAccount<'a>] {
self.callers_keyed_accounts
}
fn translate_instruction(
&self,
addr: u64,
@ -1777,8 +1764,9 @@ fn call<'a>(
signers_seeds_len,
memory_mapping,
)?;
let keyed_account_refs = syscall
.get_callers_keyed_accounts()
let keyed_account_refs = invoke_context
.get_keyed_accounts()
.map_err(SyscallError::InstructionError)?
.iter()
.collect::<Vec<&KeyedAccount>>();
let (message, callee_program_id, callee_program_id_index) =
@ -2683,7 +2671,7 @@ mod tests {
leader_schedule_epoch: 4,
unix_timestamp: 5,
};
let mut invoke_context = MockInvokeContext::default();
let mut invoke_context = MockInvokeContext::new(vec![]);
let mut data = vec![];
bincode::serialize_into(&mut data, &src_clock).unwrap();
invoke_context
@ -2725,7 +2713,7 @@ mod tests {
first_normal_epoch: 3,
first_normal_slot: 4,
};
let mut invoke_context = MockInvokeContext::default();
let mut invoke_context = MockInvokeContext::new(vec![]);
let mut data = vec![];
bincode::serialize_into(&mut data, &src_epochschedule).unwrap();
invoke_context
@ -2773,7 +2761,7 @@ mod tests {
lamports_per_signature: 1,
},
};
let mut invoke_context = MockInvokeContext::default();
let mut invoke_context = MockInvokeContext::new(vec![]);
let mut data = vec![];
bincode::serialize_into(&mut data, &src_fees).unwrap();
invoke_context
@ -2813,7 +2801,7 @@ mod tests {
exemption_threshold: 2.0,
burn_percent: 3,
};
let mut invoke_context = MockInvokeContext::default();
let mut invoke_context = MockInvokeContext::new(vec![]);
let mut data = vec![];
bincode::serialize_into(&mut data, &src_rent).unwrap();
invoke_context

View File

@ -10,7 +10,7 @@ use solana_sdk::{
account::{ReadableAccount, WritableAccount},
hash::hash,
instruction::InstructionError,
keyed_account::{next_keyed_account, KeyedAccount},
keyed_account::{keyed_account_at_index, KeyedAccount},
process_instruction::InvokeContext,
program_utils::limited_deserialize,
pubkey::Pubkey,
@ -116,22 +116,22 @@ fn apply_account_data(
pub fn process_instruction(
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
_invoke_context: &mut dyn InvokeContext,
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
let keyed_accounts_iter = &mut keyed_accounts.iter();
let keyed_accounts = invoke_context.get_keyed_accounts()?;
let instruction = limited_deserialize(data)?;
trace!("process_instruction: {:?}", instruction);
match instruction {
BudgetInstruction::InitializeAccount(expr) => {
let contract_keyed_account = next_keyed_account(keyed_accounts_iter)?;
let contract_keyed_account = keyed_account_at_index(keyed_accounts, 0)?;
if let Some(payment) = expr.final_payment() {
let to_keyed_account = contract_keyed_account;
let contract_keyed_account = next_keyed_account(keyed_accounts_iter)?;
let contract_keyed_account = keyed_account_at_index(keyed_accounts, 1)?;
contract_keyed_account.try_account_ref_mut()?.lamports = 0;
to_keyed_account.try_account_ref_mut()?.lamports += payment.lamports;
return Ok(());
@ -154,8 +154,8 @@ pub fn process_instruction(
)
}
BudgetInstruction::ApplyTimestamp(dt) => {
let witness_keyed_account = next_keyed_account(keyed_accounts_iter)?;
let contract_keyed_account = next_keyed_account(keyed_accounts_iter)?;
let witness_keyed_account = keyed_account_at_index(keyed_accounts, 0)?;
let contract_keyed_account = keyed_account_at_index(keyed_accounts, 1)?;
let mut budget_state =
BudgetState::deserialize(&contract_keyed_account.try_account_ref()?.data())?;
if !budget_state.is_pending() {
@ -173,7 +173,7 @@ pub fn process_instruction(
&mut budget_state,
witness_keyed_account,
contract_keyed_account,
next_keyed_account(keyed_accounts_iter),
keyed_account_at_index(keyed_accounts, 2),
dt,
)?;
trace!("apply timestamp committed");
@ -184,8 +184,8 @@ pub fn process_instruction(
)
}
BudgetInstruction::ApplySignature => {
let witness_keyed_account = next_keyed_account(keyed_accounts_iter)?;
let contract_keyed_account = next_keyed_account(keyed_accounts_iter)?;
let witness_keyed_account = keyed_account_at_index(keyed_accounts, 0)?;
let contract_keyed_account = keyed_account_at_index(keyed_accounts, 1)?;
let mut budget_state =
BudgetState::deserialize(&contract_keyed_account.try_account_ref()?.data())?;
if !budget_state.is_pending() {
@ -203,7 +203,7 @@ pub fn process_instruction(
&mut budget_state,
witness_keyed_account,
contract_keyed_account,
next_keyed_account(keyed_accounts_iter),
keyed_account_at_index(keyed_accounts, 2),
)?;
trace!("apply signature committed");
budget_state.serialize(
@ -213,8 +213,8 @@ pub fn process_instruction(
)
}
BudgetInstruction::ApplyAccountData => {
let witness_keyed_account = next_keyed_account(keyed_accounts_iter)?;
let contract_keyed_account = next_keyed_account(keyed_accounts_iter)?;
let witness_keyed_account = keyed_account_at_index(keyed_accounts, 0)?;
let contract_keyed_account = keyed_account_at_index(keyed_accounts, 1)?;
let mut budget_state =
BudgetState::deserialize(&contract_keyed_account.try_account_ref()?.data())?;
if !budget_state.is_pending() {
@ -228,7 +228,7 @@ pub fn process_instruction(
&mut budget_state,
witness_keyed_account,
contract_keyed_account,
next_keyed_account(keyed_accounts_iter),
keyed_account_at_index(keyed_accounts, 2),
)?;
trace!("apply account data committed");
budget_state.serialize(

View File

@ -6,7 +6,7 @@ use solana_sdk::{
account::{ReadableAccount, WritableAccount},
feature_set, ic_msg,
instruction::InstructionError,
keyed_account::{next_keyed_account, KeyedAccount},
keyed_account::keyed_account_at_index,
process_instruction::InvokeContext,
program_utils::limited_deserialize,
pubkey::Pubkey,
@ -14,14 +14,13 @@ use solana_sdk::{
pub fn process_instruction(
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
let key_list: ConfigKeys = limited_deserialize(data)?;
let keyed_accounts_iter = &mut keyed_accounts.iter();
let config_keyed_account = &mut next_keyed_account(keyed_accounts_iter)?;
let keyed_accounts = invoke_context.get_keyed_accounts()?;
let key_list: ConfigKeys = limited_deserialize(data)?;
let config_keyed_account = &mut keyed_account_at_index(keyed_accounts, 0)?;
let current_data: ConfigKeys = {
let config_account = config_keyed_account.try_account_ref_mut()?;
if invoke_context.is_feature_active(&feature_set::check_program_owner::id())
@ -55,6 +54,7 @@ pub fn process_instruction(
}
let mut counter = 0;
let mut keyed_accounts_iter = keyed_accounts.iter().skip(1);
for (signer, _) in key_list.keys.iter().filter(|(_, is_signer)| *is_signer) {
counter += 1;
if signer != config_keyed_account.unsigned_key() {
@ -132,7 +132,7 @@ mod tests {
use serde_derive::{Deserialize, Serialize};
use solana_sdk::{
account::{Account, AccountSharedData},
keyed_account::create_keyed_is_signer_accounts,
keyed_account::create_keyed_accounts_unified,
process_instruction::MockInvokeContext,
signature::{Keypair, Signer},
system_instruction::SystemInstruction,
@ -185,14 +185,13 @@ mod tests {
owner: id(),
..Account::default()
}));
let accounts = vec![(&config_pubkey, true, &config_account)];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
let accounts = vec![(true, false, &config_pubkey, &config_account)];
let keyed_accounts = create_keyed_accounts_unified(&accounts);
assert_eq!(
process_instruction(
&id(),
&keyed_accounts,
&instructions[1].data,
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Ok(())
);
@ -220,14 +219,13 @@ mod tests {
let my_config = MyConfig::new(42);
let instruction = config_instruction::store(&config_pubkey, true, keys, &my_config);
let accounts = vec![(&config_pubkey, true, &config_account)];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
let accounts = vec![(true, false, &config_pubkey, &config_account)];
let keyed_accounts = create_keyed_accounts_unified(&accounts);
assert_eq!(
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Ok(())
);
@ -247,14 +245,13 @@ mod tests {
let mut instruction = config_instruction::store(&config_pubkey, true, keys, &my_config);
instruction.data = vec![0; 123]; // <-- Replace data with a vector that's too large
let accounts = vec![(&config_pubkey, true, &config_account)];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
let accounts = vec![(true, false, &config_pubkey, &config_account)];
let keyed_accounts = create_keyed_accounts_unified(&accounts);
assert_eq!(
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Err(InstructionError::InvalidInstructionData)
);
@ -270,14 +267,13 @@ mod tests {
let mut instruction = config_instruction::store(&config_pubkey, true, vec![], &my_config);
instruction.accounts[0].is_signer = false; // <----- not a signer
let accounts = vec![(&config_pubkey, false, &config_account)];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
let accounts = vec![(false, false, &config_pubkey, &config_account)];
let keyed_accounts = create_keyed_accounts_unified(&accounts);
assert_eq!(
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Err(InstructionError::MissingRequiredSignature)
);
@ -302,17 +298,16 @@ mod tests {
let signer0_account = RefCell::new(AccountSharedData::default());
let signer1_account = RefCell::new(AccountSharedData::default());
let accounts = vec![
(&config_pubkey, true, &config_account),
(&signer0_pubkey, true, &signer0_account),
(&signer1_pubkey, true, &signer1_account),
(true, false, &config_pubkey, &config_account),
(true, false, &signer0_pubkey, &signer0_account),
(true, false, &signer1_pubkey, &signer1_account),
];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
let keyed_accounts = create_keyed_accounts_unified(&accounts);
assert_eq!(
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Ok(())
);
@ -339,14 +334,13 @@ mod tests {
owner: id(),
..Account::default()
}));
let accounts = vec![(&signer0_pubkey, true, &signer0_account)];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
let accounts = vec![(true, false, &signer0_pubkey, &signer0_account)];
let keyed_accounts = create_keyed_accounts_unified(&accounts);
assert_eq!(
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Err(InstructionError::InvalidAccountData)
);
@ -368,32 +362,30 @@ mod tests {
// Config-data pubkey doesn't match signer
let accounts = vec![
(&config_pubkey, true, &config_account),
(&signer1_pubkey, true, &signer1_account),
(true, false, &config_pubkey, &config_account),
(true, false, &signer1_pubkey, &signer1_account),
];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
let keyed_accounts = create_keyed_accounts_unified(&accounts);
assert_eq!(
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Err(InstructionError::MissingRequiredSignature)
);
// Config-data pubkey not a signer
let accounts = vec![
(&config_pubkey, true, &config_account),
(&signer0_pubkey, false, &signer0_account),
(true, false, &config_pubkey, &config_account),
(false, false, &signer0_pubkey, &signer0_account),
];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
let keyed_accounts = create_keyed_accounts_unified(&accounts);
assert_eq!(
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Err(InstructionError::MissingRequiredSignature)
);
@ -420,17 +412,16 @@ mod tests {
let instruction = config_instruction::store(&config_pubkey, true, keys.clone(), &my_config);
let accounts = vec![
(&config_pubkey, true, &config_account),
(&signer0_pubkey, true, &signer0_account),
(&signer1_pubkey, true, &signer1_account),
(true, false, &config_pubkey, &config_account),
(true, false, &signer0_pubkey, &signer0_account),
(true, false, &signer1_pubkey, &signer1_account),
];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
let keyed_accounts = create_keyed_accounts_unified(&accounts);
assert_eq!(
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Ok(())
);
@ -440,17 +431,16 @@ mod tests {
let instruction =
config_instruction::store(&config_pubkey, false, keys.clone(), &new_config);
let accounts = vec![
(&config_pubkey, false, &config_account),
(&signer0_pubkey, true, &signer0_account),
(&signer1_pubkey, true, &signer1_account),
(false, false, &config_pubkey, &config_account),
(true, false, &signer0_pubkey, &signer0_account),
(true, false, &signer1_pubkey, &signer1_account),
];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
let keyed_accounts = create_keyed_accounts_unified(&accounts);
assert_eq!(
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Ok(())
);
@ -466,17 +456,16 @@ mod tests {
let keys = vec![(pubkey, false), (signer0_pubkey, true)];
let instruction = config_instruction::store(&config_pubkey, false, keys, &my_config);
let accounts = vec![
(&config_pubkey, false, &config_account),
(&signer0_pubkey, true, &signer0_account),
(&signer1_pubkey, false, &signer1_account),
(false, false, &config_pubkey, &config_account),
(true, false, &signer0_pubkey, &signer0_account),
(false, false, &signer1_pubkey, &signer1_account),
];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
let keyed_accounts = create_keyed_accounts_unified(&accounts);
assert_eq!(
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Err(InstructionError::MissingRequiredSignature)
);
@ -489,17 +478,16 @@ mod tests {
];
let instruction = config_instruction::store(&config_pubkey, false, keys, &my_config);
let accounts = vec![
(&config_pubkey, false, &config_account),
(&signer0_pubkey, true, &signer0_account),
(&signer2_pubkey, true, &signer2_account),
(false, false, &config_pubkey, &config_account),
(true, false, &signer0_pubkey, &signer0_account),
(true, false, &signer2_pubkey, &signer2_account),
];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
let keyed_accounts = create_keyed_accounts_unified(&accounts);
assert_eq!(
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Err(InstructionError::MissingRequiredSignature)
);
@ -528,16 +516,15 @@ mod tests {
let instruction = config_instruction::store(&config_pubkey, true, keys.clone(), &my_config);
let accounts = vec![
(&config_pubkey, true, &config_account),
(&signer0_pubkey, true, &signer0_account),
(true, false, &config_pubkey, &config_account),
(true, false, &signer0_pubkey, &signer0_account),
];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
let keyed_accounts = create_keyed_accounts_unified(&accounts);
assert_eq!(
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Ok(())
);
@ -547,16 +534,15 @@ mod tests {
let instruction =
config_instruction::store(&config_pubkey, true, keys.clone(), &new_config);
let accounts = vec![
(&config_pubkey, true, &config_account),
(&signer0_pubkey, true, &signer0_account),
(true, false, &config_pubkey, &config_account),
(true, false, &signer0_pubkey, &signer0_account),
];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
let keyed_accounts = create_keyed_accounts_unified(&accounts);
assert_eq!(
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Ok(())
);
@ -571,14 +557,13 @@ mod tests {
// Attempt update with incomplete signatures
let keys = vec![(pubkey, false), (config_keypair.pubkey(), true)];
let instruction = config_instruction::store(&config_pubkey, true, keys, &my_config);
let accounts = vec![(&config_pubkey, true, &config_account)];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
let accounts = vec![(true, false, &config_pubkey, &config_account)];
let keyed_accounts = create_keyed_accounts_unified(&accounts);
assert_eq!(
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Err(InstructionError::MissingRequiredSignature)
);
@ -591,13 +576,12 @@ mod tests {
let instructions =
config_instruction::create_account::<MyConfig>(&from_pubkey, &config_pubkey, 1, vec![]);
let accounts = vec![];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
let keyed_accounts = create_keyed_accounts_unified(&accounts);
assert_eq!(
process_instruction(
&id(),
&keyed_accounts,
&instructions[1].data,
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Err(InstructionError::NotEnoughAccountKeys)
);
@ -619,16 +603,15 @@ mod tests {
let instruction = config_instruction::store(&config_pubkey, true, keys, &new_config);
let accounts = vec![
(&config_pubkey, true, &config_account),
(&signer0_pubkey, true, &signer0_account),
(true, false, &config_pubkey, &config_account),
(true, false, &signer0_pubkey, &signer0_account),
];
let keyed_accounts = create_keyed_is_signer_accounts(&accounts);
let keyed_accounts = create_keyed_accounts_unified(&accounts);
assert_eq!(
process_instruction(
&id(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts),
),
Err(InstructionError::InvalidAccountOwner)
);

View File

@ -487,12 +487,12 @@ impl ExchangeProcessor {
pub fn process_instruction(
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
_invoke_context: &mut dyn InvokeContext,
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
solana_logger::setup();
let keyed_accounts = invoke_context.get_keyed_accounts()?;
solana_logger::setup();
match limited_deserialize::<ExchangeInstruction>(data)? {
ExchangeInstruction::AccountRequest => {
ExchangeProcessor::do_account_request(keyed_accounts)

View File

@ -1,6 +1,5 @@
use solana_sdk::{
instruction::InstructionError, keyed_account::KeyedAccount, process_instruction::InvokeContext,
pubkey::Pubkey,
instruction::InstructionError, process_instruction::InvokeContext, pubkey::Pubkey,
};
solana_sdk::declare_program!(
@ -11,7 +10,6 @@ solana_sdk::declare_program!(
fn process_instruction(
_program_id: &Pubkey,
_keyed_accounts: &[KeyedAccount],
_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {

View File

@ -1,7 +1,6 @@
use log::*;
use solana_sdk::{
instruction::InstructionError, keyed_account::KeyedAccount, process_instruction::InvokeContext,
pubkey::Pubkey,
instruction::InstructionError, process_instruction::InvokeContext, pubkey::Pubkey,
};
solana_sdk::declare_program!(
@ -12,13 +11,11 @@ solana_sdk::declare_program!(
pub fn process_instruction(
program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
solana_logger::setup();
trace!("noop: program_id: {:?}", program_id);
trace!("noop: keyed_accounts: {:#?}", keyed_accounts);
trace!("noop: data: {:?}", data);
Ok(())
}

View File

@ -5,7 +5,7 @@ use bincode::serialize_into;
use solana_sdk::{
account::{ReadableAccount, WritableAccount},
instruction::InstructionError,
keyed_account::{next_keyed_account, KeyedAccount},
keyed_account::{keyed_account_at_index, KeyedAccount},
process_instruction::InvokeContext,
program_utils::limited_deserialize,
pubkey::Pubkey,
@ -30,20 +30,20 @@ fn set_owner(
pub fn process_instruction(
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
_invoke_context: &mut dyn InvokeContext,
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
let keyed_accounts = invoke_context.get_keyed_accounts()?;
let new_owner_pubkey: Pubkey = limited_deserialize(data)?;
let keyed_accounts_iter = &mut keyed_accounts.iter();
let account_keyed_account = &mut next_keyed_account(keyed_accounts_iter)?;
let account_keyed_account = &mut keyed_account_at_index(keyed_accounts, 0)?;
let mut account_owner_pubkey: Pubkey =
limited_deserialize(&account_keyed_account.try_account_ref()?.data())?;
if account_owner_pubkey == Pubkey::default() {
account_owner_pubkey = new_owner_pubkey;
} else {
let owner_keyed_account = &mut next_keyed_account(keyed_accounts_iter)?;
let owner_keyed_account = &mut keyed_account_at_index(keyed_accounts, 1)?;
set_owner(
&mut account_owner_pubkey,
new_owner_pubkey,

View File

@ -1,11 +1,9 @@
use solana_sdk::{
instruction::InstructionError, keyed_account::KeyedAccount, process_instruction::InvokeContext,
pubkey::Pubkey,
instruction::InstructionError, process_instruction::InvokeContext, pubkey::Pubkey,
};
pub fn process_instruction(
_program_id: &Pubkey,
_keyed_accounts: &[KeyedAccount],
_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {

View File

@ -10,7 +10,7 @@ use solana_sdk::{
decode_error::DecodeError,
feature_set,
instruction::{AccountMeta, Instruction, InstructionError},
keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount},
keyed_account::{from_keyed_account, get_signers, keyed_account_at_index},
process_instruction::InvokeContext,
program_utils::limited_deserialize,
pubkey::Pubkey,
@ -483,17 +483,17 @@ pub fn set_lockup(
pub fn process_instruction(
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
let keyed_accounts = invoke_context.get_keyed_accounts()?;
trace!("process_instruction: {:?}", data);
trace!("keyed_accounts: {:?}", keyed_accounts);
let signers = get_signers(keyed_accounts);
let keyed_accounts = &mut keyed_accounts.iter();
let me = &next_keyed_account(keyed_accounts)?;
let me = &keyed_account_at_index(keyed_accounts, 0)?;
if me.owner()? != id() {
if invoke_context.is_feature_active(&feature_set::check_program_owner::id()) {
@ -507,7 +507,7 @@ pub fn process_instruction(
StakeInstruction::Initialize(authorized, lockup) => me.initialize(
&authorized,
&lockup,
&from_keyed_account::<Rent>(next_keyed_account(keyed_accounts)?)?,
&from_keyed_account::<Rent>(keyed_account_at_index(keyed_accounts, 1)?)?,
),
StakeInstruction::Authorize(authorized_pubkey, stake_authorize) => {
let require_custodian_for_locked_stake_authorize = invoke_context.is_feature_active(
@ -515,9 +515,11 @@ pub fn process_instruction(
);
if require_custodian_for_locked_stake_authorize {
let clock = from_keyed_account::<Clock>(next_keyed_account(keyed_accounts)?)?;
let _current_authority = next_keyed_account(keyed_accounts)?;
let custodian = keyed_accounts.next().map(|ka| ka.unsigned_key());
let clock =
from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 1)?)?;
let _current_authority = keyed_account_at_index(keyed_accounts, 2)?;
let custodian =
keyed_account_at_index(keyed_accounts, 3).map(|ka| ka.unsigned_key());
me.authorize(
&signers,
@ -525,7 +527,7 @@ pub fn process_instruction(
stake_authorize,
require_custodian_for_locked_stake_authorize,
&clock,
custodian,
custodian.ok(),
)
} else {
me.authorize(
@ -539,14 +541,16 @@ pub fn process_instruction(
}
}
StakeInstruction::AuthorizeWithSeed(args) => {
let authority_base = next_keyed_account(keyed_accounts)?;
let authority_base = keyed_account_at_index(keyed_accounts, 1)?;
let require_custodian_for_locked_stake_authorize = invoke_context.is_feature_active(
&feature_set::require_custodian_for_locked_stake_authorize::id(),
);
if require_custodian_for_locked_stake_authorize {
let clock = from_keyed_account::<Clock>(next_keyed_account(keyed_accounts)?)?;
let custodian = keyed_accounts.next().map(|ka| ka.unsigned_key());
let clock =
from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 2)?)?;
let custodian =
keyed_account_at_index(keyed_accounts, 3).map(|ka| ka.unsigned_key());
me.authorize_with_seed(
&authority_base,
@ -556,7 +560,7 @@ pub fn process_instruction(
args.stake_authorize,
require_custodian_for_locked_stake_authorize,
&clock,
custodian,
custodian.ok(),
)
} else {
me.authorize_with_seed(
@ -572,44 +576,44 @@ pub fn process_instruction(
}
}
StakeInstruction::DelegateStake => {
let vote = next_keyed_account(keyed_accounts)?;
let vote = keyed_account_at_index(keyed_accounts, 1)?;
me.delegate(
&vote,
&from_keyed_account::<Clock>(next_keyed_account(keyed_accounts)?)?,
&from_keyed_account::<StakeHistory>(next_keyed_account(keyed_accounts)?)?,
&config::from_keyed_account(next_keyed_account(keyed_accounts)?)?,
&from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 2)?)?,
&from_keyed_account::<StakeHistory>(keyed_account_at_index(keyed_accounts, 3)?)?,
&config::from_keyed_account(keyed_account_at_index(keyed_accounts, 4)?)?,
&signers,
)
}
StakeInstruction::Split(lamports) => {
let split_stake = &next_keyed_account(keyed_accounts)?;
let split_stake = &keyed_account_at_index(keyed_accounts, 1)?;
me.split(lamports, split_stake, &signers)
}
StakeInstruction::Merge => {
let source_stake = &next_keyed_account(keyed_accounts)?;
let source_stake = &keyed_account_at_index(keyed_accounts, 1)?;
me.merge(
invoke_context,
source_stake,
&from_keyed_account::<Clock>(next_keyed_account(keyed_accounts)?)?,
&from_keyed_account::<StakeHistory>(next_keyed_account(keyed_accounts)?)?,
&from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 2)?)?,
&from_keyed_account::<StakeHistory>(keyed_account_at_index(keyed_accounts, 3)?)?,
&signers,
)
}
StakeInstruction::Withdraw(lamports) => {
let to = &next_keyed_account(keyed_accounts)?;
let to = &keyed_account_at_index(keyed_accounts, 1)?;
me.withdraw(
lamports,
to,
&from_keyed_account::<Clock>(next_keyed_account(keyed_accounts)?)?,
&from_keyed_account::<StakeHistory>(next_keyed_account(keyed_accounts)?)?,
next_keyed_account(keyed_accounts)?,
keyed_accounts.next(),
&from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 2)?)?,
&from_keyed_account::<StakeHistory>(keyed_account_at_index(keyed_accounts, 3)?)?,
keyed_account_at_index(keyed_accounts, 4)?,
keyed_account_at_index(keyed_accounts, 5).ok(),
)
}
StakeInstruction::Deactivate => me.deactivate(
&from_keyed_account::<Clock>(next_keyed_account(keyed_accounts)?)?,
&from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 1)?)?,
&signers,
),
@ -623,6 +627,7 @@ mod tests {
use bincode::serialize;
use solana_sdk::{
account::{self, Account, AccountSharedData},
keyed_account::KeyedAccount,
process_instruction::MockInvokeContext,
rent::Rent,
sysvar::stake_history::StakeHistory,
@ -707,9 +712,8 @@ mod tests {
.collect();
super::process_instruction(
&Pubkey::default(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default(),
&mut MockInvokeContext::new(keyed_accounts),
)
}
}
@ -918,202 +922,194 @@ mod tests {
assert_eq!(
super::process_instruction(
&Pubkey::default(),
&[],
&serialize(&StakeInstruction::Initialize(
Authorized::default(),
Lockup::default()
))
.unwrap(),
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(vec![])
),
Err(InstructionError::NotEnoughAccountKeys),
);
// no account for rent
let stake_address = Pubkey::default();
let stake_account = create_default_stake_account();
let keyed_accounts = vec![KeyedAccount::new(&stake_address, false, &stake_account)];
assert_eq!(
super::process_instruction(
&Pubkey::default(),
&[KeyedAccount::new(
&Pubkey::default(),
false,
&create_default_stake_account(),
)],
&serialize(&StakeInstruction::Initialize(
Authorized::default(),
Lockup::default()
))
.unwrap(),
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Err(InstructionError::NotEnoughAccountKeys),
);
// rent fails to deserialize
let stake_address = Pubkey::default();
let stake_account = create_default_stake_account();
let rent_address = sysvar::rent::id();
let rent_account = create_default_account();
let keyed_accounts = vec![
KeyedAccount::new(&stake_address, false, &stake_account),
KeyedAccount::new(&rent_address, false, &rent_account),
];
assert_eq!(
super::process_instruction(
&Pubkey::default(),
&[
KeyedAccount::new(&Pubkey::default(), false, &create_default_stake_account()),
KeyedAccount::new(&sysvar::rent::id(), false, &create_default_account())
],
&serialize(&StakeInstruction::Initialize(
Authorized::default(),
Lockup::default()
))
.unwrap(),
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Err(InstructionError::InvalidArgument),
);
// fails to deserialize stake state
let stake_address = Pubkey::default();
let stake_account = create_default_stake_account();
let rent_address = sysvar::rent::id();
let rent_account = RefCell::new(account::create_account_shared_data_for_test(
&Rent::default(),
));
let keyed_accounts = vec![
KeyedAccount::new(&stake_address, false, &stake_account),
KeyedAccount::new(&rent_address, false, &rent_account),
];
assert_eq!(
super::process_instruction(
&Pubkey::default(),
&[
KeyedAccount::new(&Pubkey::default(), false, &create_default_stake_account()),
KeyedAccount::new(
&sysvar::rent::id(),
false,
&RefCell::new(account::create_account_shared_data_for_test(
&Rent::default()
))
)
],
&serialize(&StakeInstruction::Initialize(
Authorized::default(),
Lockup::default()
))
.unwrap(),
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Err(InstructionError::InvalidAccountData),
);
// gets the first check in delegate, wrong number of accounts
let stake_address = Pubkey::default();
let stake_account = create_default_stake_account();
let keyed_accounts = vec![KeyedAccount::new(&stake_address, false, &stake_account)];
assert_eq!(
super::process_instruction(
&Pubkey::default(),
&[KeyedAccount::new(
&Pubkey::default(),
false,
&create_default_stake_account()
),],
&serialize(&StakeInstruction::DelegateStake).unwrap(),
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Err(InstructionError::NotEnoughAccountKeys),
);
// gets the sub-check for number of args
let stake_address = Pubkey::default();
let stake_account = create_default_stake_account();
let keyed_accounts = vec![KeyedAccount::new(&stake_address, false, &stake_account)];
assert_eq!(
super::process_instruction(
&Pubkey::default(),
&[KeyedAccount::new(
&Pubkey::default(),
false,
&create_default_stake_account()
)],
&serialize(&StakeInstruction::DelegateStake).unwrap(),
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Err(InstructionError::NotEnoughAccountKeys),
);
// gets the check non-deserialize-able account in delegate_stake
let stake_address = Pubkey::default();
let stake_account = create_default_stake_account();
let vote_address = Pubkey::default();
let mut bad_vote_account = create_default_account();
bad_vote_account.get_mut().owner = solana_vote_program::id();
let clock_address = sysvar::clock::id();
let clock_account = RefCell::new(account::create_account_shared_data_for_test(
&sysvar::clock::Clock::default(),
));
let stake_history_address = sysvar::stake_history::id();
let stake_history_account = RefCell::new(account::create_account_shared_data_for_test(
&sysvar::stake_history::StakeHistory::default(),
));
let config_address = config::id();
let config_account = RefCell::new(config::create_account(0, &config::Config::default()));
let keyed_accounts = vec![
KeyedAccount::new(&stake_address, true, &stake_account),
KeyedAccount::new(&vote_address, false, &bad_vote_account),
KeyedAccount::new(&clock_address, false, &clock_account),
KeyedAccount::new(&stake_history_address, false, &stake_history_account),
KeyedAccount::new(&config_address, false, &config_account),
];
assert_eq!(
super::process_instruction(
&Pubkey::default(),
&[
KeyedAccount::new(&Pubkey::default(), true, &create_default_stake_account()),
KeyedAccount::new(&Pubkey::default(), false, &bad_vote_account),
KeyedAccount::new(
&sysvar::clock::id(),
false,
&RefCell::new(account::create_account_shared_data_for_test(
&sysvar::clock::Clock::default(),
))
),
KeyedAccount::new(
&sysvar::stake_history::id(),
false,
&RefCell::new(account::create_account_shared_data_for_test(
&sysvar::stake_history::StakeHistory::default(),
))
),
KeyedAccount::new(
&config::id(),
false,
&RefCell::new(config::create_account(0, &config::Config::default()))
),
],
&serialize(&StakeInstruction::DelegateStake).unwrap(),
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Err(InstructionError::InvalidAccountData),
);
// Tests 3rd keyed account is of correct type (Clock instead of rewards) in withdraw
let stake_address = Pubkey::default();
let stake_account = create_default_stake_account();
let vote_address = Pubkey::default();
let vote_account = create_default_account();
let rewards_address = sysvar::rewards::id();
let rewards_account = RefCell::new(account::create_account_shared_data_for_test(
&sysvar::rewards::Rewards::new(0.0),
));
let stake_history_address = sysvar::stake_history::id();
let stake_history_account = RefCell::new(account::create_account_shared_data_for_test(
&StakeHistory::default(),
));
let keyed_accounts = vec![
KeyedAccount::new(&stake_address, false, &stake_account),
KeyedAccount::new(&vote_address, false, &vote_account),
KeyedAccount::new(&rewards_address, false, &rewards_account),
KeyedAccount::new(&stake_history_address, false, &stake_history_account),
];
assert_eq!(
super::process_instruction(
&Pubkey::default(),
&[
KeyedAccount::new(&Pubkey::default(), false, &create_default_stake_account()),
KeyedAccount::new(&Pubkey::default(), false, &create_default_account()),
KeyedAccount::new(
&sysvar::rewards::id(),
false,
&RefCell::new(account::create_account_shared_data_for_test(
&sysvar::rewards::Rewards::new(0.0),
))
),
KeyedAccount::new(
&sysvar::stake_history::id(),
false,
&RefCell::new(account::create_account_shared_data_for_test(
&StakeHistory::default(),
))
),
],
&serialize(&StakeInstruction::Withdraw(42)).unwrap(),
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Err(InstructionError::InvalidArgument),
);
// Tests correct number of accounts are provided in withdraw
let stake_address = Pubkey::default();
let stake_account = create_default_stake_account();
let keyed_accounts = vec![KeyedAccount::new(&stake_address, false, &stake_account)];
assert_eq!(
super::process_instruction(
&Pubkey::default(),
&[KeyedAccount::new(
&Pubkey::default(),
false,
&create_default_stake_account()
)],
&serialize(&StakeInstruction::Withdraw(42)).unwrap(),
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Err(InstructionError::NotEnoughAccountKeys),
);
// Tests 2nd keyed account is of correct type (Clock instead of rewards) in deactivate
let stake_address = Pubkey::default();
let stake_account = create_default_stake_account();
let rewards_address = sysvar::rewards::id();
let rewards_account = RefCell::new(account::create_account_shared_data_for_test(
&sysvar::rewards::Rewards::new(0.0),
));
let keyed_accounts = vec![
KeyedAccount::new(&stake_address, false, &stake_account),
KeyedAccount::new(&rewards_address, false, &rewards_account),
];
assert_eq!(
super::process_instruction(
&Pubkey::default(),
&[
KeyedAccount::new(&Pubkey::default(), false, &create_default_stake_account()),
KeyedAccount::new(
&sysvar::rewards::id(),
false,
&RefCell::new(account::create_account_shared_data_for_test(
&sysvar::rewards::Rewards::new(0.0),
))
),
],
&serialize(&StakeInstruction::Deactivate).unwrap(),
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(keyed_accounts)
),
Err(InstructionError::InvalidArgument),
);
@ -1122,9 +1118,8 @@ mod tests {
assert_eq!(
super::process_instruction(
&Pubkey::default(),
&[],
&serialize(&StakeInstruction::Deactivate).unwrap(),
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(vec![])
),
Err(InstructionError::NotEnoughAccountKeys),
);

View File

@ -5103,9 +5103,9 @@ mod tests {
let source_stake_pubkey = solana_sdk::pubkey::new_rand();
let authorized_pubkey = solana_sdk::pubkey::new_rand();
let stake_lamports = 42;
let invoke_context = MockInvokeContext::default();
let signers = vec![authorized_pubkey].into_iter().collect();
let invoke_context = MockInvokeContext::new(vec![]);
for state in &[
StakeState::Initialized(Meta::auto(&authorized_pubkey)),
@ -5213,7 +5213,7 @@ mod tests {
#[test]
fn test_merge_self_fails() {
let invoke_context = MockInvokeContext::default();
let invoke_context = MockInvokeContext::new(vec![]);
let stake_address = Pubkey::new_unique();
let authority_pubkey = Pubkey::new_unique();
let signers = HashSet::from_iter(vec![authority_pubkey]);
@ -5257,7 +5257,6 @@ mod tests {
#[test]
fn test_merge_incorrect_authorized_staker() {
let invoke_context = MockInvokeContext::default();
let stake_pubkey = solana_sdk::pubkey::new_rand();
let source_stake_pubkey = solana_sdk::pubkey::new_rand();
let authorized_pubkey = solana_sdk::pubkey::new_rand();
@ -5266,6 +5265,7 @@ mod tests {
let signers = vec![authorized_pubkey].into_iter().collect();
let wrong_signers = vec![wrong_authorized_pubkey].into_iter().collect();
let invoke_context = MockInvokeContext::new(vec![]);
for state in &[
StakeState::Initialized(Meta::auto(&authorized_pubkey)),
@ -5327,12 +5327,12 @@ mod tests {
#[test]
fn test_merge_invalid_account_data() {
let invoke_context = MockInvokeContext::default();
let stake_pubkey = solana_sdk::pubkey::new_rand();
let source_stake_pubkey = solana_sdk::pubkey::new_rand();
let authorized_pubkey = solana_sdk::pubkey::new_rand();
let stake_lamports = 42;
let signers = vec![authorized_pubkey].into_iter().collect();
let invoke_context = MockInvokeContext::new(vec![]);
for state in &[
StakeState::Uninitialized,
@ -5379,7 +5379,6 @@ mod tests {
#[test]
fn test_merge_fake_stake_source() {
let invoke_context = MockInvokeContext::default();
let stake_pubkey = solana_sdk::pubkey::new_rand();
let source_stake_pubkey = solana_sdk::pubkey::new_rand();
let authorized_pubkey = solana_sdk::pubkey::new_rand();
@ -5411,6 +5410,7 @@ mod tests {
.expect("source_stake_account");
let source_stake_keyed_account =
KeyedAccount::new(&source_stake_pubkey, true, &source_stake_account);
let invoke_context = MockInvokeContext::new(vec![]);
assert_eq!(
stake_keyed_account.merge(
@ -5426,7 +5426,6 @@ mod tests {
#[test]
fn test_merge_active_stake() {
let invoke_context = MockInvokeContext::default();
let base_lamports = 4242424242;
let stake_address = Pubkey::new_unique();
let source_address = Pubkey::new_unique();
@ -5480,6 +5479,7 @@ mod tests {
let mut clock = Clock::default();
let mut stake_history = StakeHistory::default();
let invoke_context = MockInvokeContext::new(vec![]);
clock.epoch = 0;
let mut effective = base_lamports;
@ -6144,7 +6144,6 @@ mod tests {
#[test]
fn test_things_can_merge() {
let invoke_context = MockInvokeContext::default();
let good_stake = Stake {
credits_observed: 4242,
delegation: Delegation {
@ -6154,6 +6153,7 @@ mod tests {
..Delegation::default()
},
};
let invoke_context = MockInvokeContext::new(vec![]);
let identical = good_stake;
assert!(
@ -6314,7 +6314,6 @@ mod tests {
#[test]
fn test_merge_kind_get_if_mergeable() {
let invoke_context = MockInvokeContext::default();
let authority_pubkey = Pubkey::new_unique();
let initial_lamports = 4242424242;
let rent = Rent::default();
@ -6333,9 +6332,9 @@ mod tests {
)
.expect("stake_account");
let stake_keyed_account = KeyedAccount::new(&authority_pubkey, true, &stake_account);
let mut clock = Clock::default();
let mut stake_history = StakeHistory::default();
let invoke_context = MockInvokeContext::new(vec![]);
// Uninitialized state fails
assert_eq!(
@ -6547,7 +6546,6 @@ mod tests {
#[test]
fn test_merge_kind_merge() {
let invoke_context = MockInvokeContext::default();
let lamports = 424242;
let meta = Meta {
rent_exempt_reserve: 42,
@ -6563,6 +6561,7 @@ mod tests {
let inactive = MergeKind::Inactive(Meta::default(), lamports);
let activation_epoch = MergeKind::ActivationEpoch(meta, stake);
let fully_active = MergeKind::FullyActive(meta, stake);
let invoke_context = MockInvokeContext::new(vec![]);
assert_eq!(
inactive

View File

@ -10,7 +10,7 @@ use solana_sdk::{
account::{AccountSharedData, ReadableAccount, WritableAccount},
feature_set,
instruction::InstructionError,
keyed_account::{next_keyed_account, KeyedAccount},
keyed_account::{keyed_account_at_index, KeyedAccount},
process_instruction::InvokeContext,
program_utils::limited_deserialize,
pubkey::Pubkey,
@ -59,12 +59,12 @@ fn verify_signed_account<'a>(
pub fn process_instruction(
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
let keyed_accounts_iter = &mut keyed_accounts.iter();
let contract_account = &mut next_keyed_account(keyed_accounts_iter)?.try_account_ref_mut()?;
let keyed_accounts = invoke_context.get_keyed_accounts()?;
let contract_account = &mut keyed_account_at_index(keyed_accounts, 0)?.try_account_ref_mut()?;
if invoke_context.is_feature_active(&feature_set::check_program_owner::id())
&& contract_account.owner != crate::id()
{
@ -97,25 +97,25 @@ pub fn process_instruction(
VestInstruction::InitializeAccount { .. } => {}
VestInstruction::SetTerminator(new_pubkey) => {
verify_signed_account(
next_keyed_account(keyed_accounts_iter)?,
keyed_account_at_index(keyed_accounts, 1)?,
&vest_state.terminator_pubkey,
)?;
vest_state.terminator_pubkey = new_pubkey;
}
VestInstruction::SetPayee(new_pubkey) => {
verify_signed_account(
next_keyed_account(keyed_accounts_iter)?,
keyed_account_at_index(keyed_accounts, 1)?,
&vest_state.payee_pubkey,
)?;
vest_state.payee_pubkey = new_pubkey;
}
VestInstruction::RedeemTokens => {
let current_date = verify_date_account(
next_keyed_account(keyed_accounts_iter)?,
keyed_account_at_index(keyed_accounts, 1)?,
&vest_state.date_pubkey,
)?;
let mut payee_account = verify_account(
next_keyed_account(keyed_accounts_iter)?,
keyed_account_at_index(keyed_accounts, 2)?,
&vest_state.payee_pubkey,
)?;
vest_state.redeem_tokens(contract_account, current_date, &mut payee_account);
@ -127,11 +127,11 @@ pub fn process_instruction(
contract_account.lamports
};
let terminator_account = verify_signed_account(
next_keyed_account(keyed_accounts_iter)?,
keyed_account_at_index(keyed_accounts, 1)?,
&vest_state.terminator_pubkey,
)?;
let payee_keyed_account = keyed_accounts_iter.next();
let mut payee_account = if let Some(payee_keyed_account) = payee_keyed_account {
let payee_keyed_account = keyed_account_at_index(keyed_accounts, 2);
let mut payee_account = if let Ok(payee_keyed_account) = payee_keyed_account {
payee_keyed_account.try_account_ref_mut()?
} else {
terminator_account
@ -140,7 +140,7 @@ pub fn process_instruction(
}
VestInstruction::VestAll => {
verify_signed_account(
next_keyed_account(keyed_accounts_iter)?,
keyed_account_at_index(keyed_accounts, 1)?,
&vest_state.terminator_pubkey,
)?;
vest_state.vest_all();

View File

@ -14,7 +14,7 @@ use solana_sdk::{
feature_set,
hash::Hash,
instruction::{AccountMeta, Instruction, InstructionError},
keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount},
keyed_account::{from_keyed_account, get_signers, keyed_account_at_index, KeyedAccount},
process_instruction::InvokeContext,
program_utils::limited_deserialize,
pubkey::Pubkey,
@ -277,17 +277,17 @@ fn verify_rent_exemption(
pub fn process_instruction(
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
let keyed_accounts = invoke_context.get_keyed_accounts()?;
trace!("process_instruction: {:?}", data);
trace!("keyed_accounts: {:?}", keyed_accounts);
let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
let keyed_accounts = &mut keyed_accounts.iter();
let me = &mut next_keyed_account(keyed_accounts)?;
let me = &mut keyed_account_at_index(keyed_accounts, 0)?;
if invoke_context.is_feature_active(&feature_set::check_program_owner::id())
&& me.owner()? != id()
@ -297,12 +297,12 @@ pub fn process_instruction(
match limited_deserialize(data)? {
VoteInstruction::InitializeAccount(vote_init) => {
verify_rent_exemption(me, next_keyed_account(keyed_accounts)?)?;
verify_rent_exemption(me, keyed_account_at_index(keyed_accounts, 1)?)?;
vote_state::initialize_account(
me,
&vote_init,
&signers,
&from_keyed_account::<Clock>(next_keyed_account(keyed_accounts)?)?,
&from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 2)?)?,
invoke_context.is_feature_active(&feature_set::check_init_vote_data::id()),
)
}
@ -311,11 +311,11 @@ pub fn process_instruction(
&voter_pubkey,
vote_authorize,
&signers,
&from_keyed_account::<Clock>(next_keyed_account(keyed_accounts)?)?,
&from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 1)?)?,
),
VoteInstruction::UpdateValidatorIdentity => vote_state::update_validator_identity(
me,
next_keyed_account(keyed_accounts)?.unsigned_key(),
keyed_account_at_index(keyed_accounts, 1)?.unsigned_key(),
&signers,
),
VoteInstruction::UpdateCommission(commission) => {
@ -325,14 +325,14 @@ pub fn process_instruction(
inc_new_counter_info!("vote-native", 1);
vote_state::process_vote(
me,
&from_keyed_account::<SlotHashes>(next_keyed_account(keyed_accounts)?)?,
&from_keyed_account::<Clock>(next_keyed_account(keyed_accounts)?)?,
&from_keyed_account::<SlotHashes>(keyed_account_at_index(keyed_accounts, 1)?)?,
&from_keyed_account::<Clock>(keyed_account_at_index(keyed_accounts, 2)?)?,
&vote,
&signers,
)
}
VoteInstruction::Withdraw(lamports) => {
let to = next_keyed_account(keyed_accounts)?;
let to = keyed_account_at_index(keyed_accounts, 1)?;
vote_state::withdraw(me, lamports, to, &signers)
}
}
@ -356,8 +356,7 @@ mod tests {
super::process_instruction(
&Pubkey::default(),
&[],
&[],
&mut MockInvokeContext::default()
&mut MockInvokeContext::new(vec![])
),
Err(InstructionError::NotEnoughAccountKeys),
);
@ -401,9 +400,8 @@ mod tests {
.collect();
super::process_instruction(
&Pubkey::default(),
&keyed_accounts,
&instruction.data,
&mut MockInvokeContext::default(),
&mut MockInvokeContext::new(keyed_accounts),
)
}
}

View File

@ -788,7 +788,7 @@ mod tests {
account::AccountSharedData,
account_utils::StateMut,
hash::hash,
keyed_account::{get_signers, next_keyed_account},
keyed_account::{get_signers, keyed_account_at_index},
};
use std::cell::RefCell;
@ -1715,9 +1715,8 @@ mod tests {
KeyedAccount::new(&authorized_withdrawer_pubkey, true, &withdrawer_account),
];
let signers: HashSet<Pubkey> = get_signers(keyed_accounts);
let keyed_accounts = &mut keyed_accounts.iter();
let vote_keyed_account = next_keyed_account(keyed_accounts).unwrap();
let withdrawer_keyed_account = next_keyed_account(keyed_accounts).unwrap();
let vote_keyed_account = keyed_account_at_index(keyed_accounts, 0).unwrap();
let withdrawer_keyed_account = keyed_account_at_index(keyed_accounts, 1).unwrap();
let res = withdraw(
vote_keyed_account,
lamports,

View File

@ -11,7 +11,6 @@ use solana_sdk::{
clock::MAX_RECENT_BLOCKHASHES,
genesis_config::create_genesis_config,
instruction::InstructionError,
keyed_account::KeyedAccount,
message::Message,
process_instruction::InvokeContext,
pubkey::Pubkey,
@ -34,7 +33,6 @@ const NOOP_PROGRAM_ID: [u8; 32] = [
#[allow(clippy::unnecessary_wraps)]
fn process_instruction(
_program_id: &Pubkey,
_keyed_accounts: &[KeyedAccount],
_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {

View File

@ -208,7 +208,7 @@ impl AbiExample for Builtin {
Self {
name: String::default(),
id: Pubkey::default(),
process_instruction_with_context: |_, _, _, _| Ok(()),
process_instruction_with_context: |_, _, _| Ok(()),
}
}
}
@ -5071,7 +5071,6 @@ pub(crate) mod tests {
feature::Feature,
genesis_config::create_genesis_config,
instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError},
keyed_account::KeyedAccount,
message::{Message, MessageHeader},
nonce,
poh_config::PohConfig,
@ -5430,10 +5429,10 @@ pub(crate) mod tests {
fn mock_process_instruction(
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
_invoke_context: &mut dyn InvokeContext,
invoke_context: &mut dyn InvokeContext,
) -> result::Result<(), InstructionError> {
let keyed_accounts = invoke_context.get_keyed_accounts()?;
if let Ok(instruction) = bincode::deserialize(data) {
match instruction {
MockInstruction::Deduction => {
@ -9007,7 +9006,6 @@ pub(crate) mod tests {
}
fn mock_vote_processor(
program_id: &Pubkey,
_keyed_accounts: &[KeyedAccount],
_instruction_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> std::result::Result<(), InstructionError> {
@ -9065,7 +9063,6 @@ pub(crate) mod tests {
fn mock_vote_processor(
_pubkey: &Pubkey,
_ka: &[KeyedAccount],
_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> std::result::Result<(), InstructionError> {
@ -9116,7 +9113,6 @@ pub(crate) mod tests {
fn mock_ix_processor(
_pubkey: &Pubkey,
_ka: &[KeyedAccount],
_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> std::result::Result<(), InstructionError> {
@ -9850,10 +9846,10 @@ pub(crate) mod tests {
fn mock_process_instruction(
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
_invoke_context: &mut dyn InvokeContext,
invoke_context: &mut dyn InvokeContext,
) -> result::Result<(), InstructionError> {
let keyed_accounts = invoke_context.get_keyed_accounts()?;
let lamports = data[0] as u64;
{
let mut to_account = keyed_accounts[1].try_account_ref_mut()?;
@ -9904,7 +9900,6 @@ pub(crate) mod tests {
#[allow(clippy::unnecessary_wraps)]
fn mock_process_instruction(
_program_id: &Pubkey,
_keyed_accounts: &[KeyedAccount],
_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> result::Result<(), InstructionError> {
@ -10091,7 +10086,6 @@ pub(crate) mod tests {
#[allow(clippy::unnecessary_wraps)]
fn mock_ok_vote_processor(
_pubkey: &Pubkey,
_ka: &[KeyedAccount],
_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> std::result::Result<(), InstructionError> {
@ -10342,10 +10336,10 @@ pub(crate) mod tests {
fn test_same_program_id_uses_unqiue_executable_accounts() {
fn nested_processor(
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
invoke_context: &mut dyn InvokeContext,
) -> result::Result<(), InstructionError> {
let keyed_accounts = invoke_context.get_keyed_accounts()?;
assert_eq!(42, keyed_accounts[0].lamports().unwrap());
let mut account = keyed_accounts[0].try_account_ref_mut()?;
account.lamports += 1;
@ -10622,7 +10616,6 @@ pub(crate) mod tests {
#[allow(clippy::unnecessary_wraps)]
fn mock_ix_processor(
_pubkey: &Pubkey,
_ka: &[KeyedAccount],
_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> std::result::Result<(), InstructionError> {
@ -10668,7 +10661,6 @@ pub(crate) mod tests {
#[allow(clippy::unnecessary_wraps)]
fn mock_ix_processor(
_pubkey: &Pubkey,
_ka: &[KeyedAccount],
_data: &[u8],
_context: &mut dyn InvokeContext,
) -> std::result::Result<(), InstructionError> {
@ -10962,7 +10954,6 @@ pub(crate) mod tests {
&self,
_loader_id: &Pubkey,
_program_id: &Pubkey,
_keyed_accounts: &[KeyedAccount],
_instruction_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
_use_jit: bool,
@ -12402,12 +12393,12 @@ pub(crate) mod tests {
fn mock_ix_processor(
_pubkey: &Pubkey,
ka: &[KeyedAccount],
_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
invoke_context: &mut dyn InvokeContext,
) -> std::result::Result<(), InstructionError> {
use solana_sdk::account::WritableAccount;
let mut data = ka[1].try_account_ref_mut()?;
let keyed_accounts = invoke_context.get_keyed_accounts()?;
let mut data = keyed_accounts[1].try_account_ref_mut()?;
data.data_as_mut_slice()[0] = 5;
Ok(())
}

View File

@ -5,7 +5,6 @@ use crate::{
use solana_sdk::{
feature_set,
instruction::InstructionError,
keyed_account::KeyedAccount,
process_instruction::{stable_log, InvokeContext, ProcessInstructionWithContext},
pubkey::Pubkey,
system_program,
@ -14,14 +13,13 @@ use solana_sdk::{
fn process_instruction_with_program_logging(
process_instruction: ProcessInstructionWithContext,
program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
instruction_data: &[u8],
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
let logger = invoke_context.get_logger();
stable_log::program_invoke(&logger, program_id, invoke_context.invoke_depth());
let result = process_instruction(program_id, keyed_accounts, instruction_data, invoke_context);
let result = process_instruction(program_id, instruction_data, invoke_context);
match &result {
Ok(()) => stable_log::program_success(&logger, program_id),
@ -32,14 +30,10 @@ fn process_instruction_with_program_logging(
macro_rules! with_program_logging {
($process_instruction:expr) => {
|program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
instruction_data: &[u8],
invoke_context: &mut dyn InvokeContext| {
|program_id: &Pubkey, instruction_data: &[u8], invoke_context: &mut dyn InvokeContext| {
process_instruction_with_program_logging(
$process_instruction,
program_id,
keyed_accounts,
instruction_data,
invoke_context,
)

View File

@ -14,11 +14,11 @@ use solana_sdk::{
},
ic_msg,
instruction::{CompiledInstruction, Instruction, InstructionError},
keyed_account::{create_keyed_readonly_accounts, KeyedAccount},
keyed_account::{create_keyed_accounts_unified, keyed_account_at_index, KeyedAccount},
message::Message,
native_loader,
process_instruction::{
BpfComputeBudget, ComputeMeter, Executor, InvokeContext, Logger,
BpfComputeBudget, ComputeMeter, Executor, InvokeContext, InvokeContextStackFrame, Logger,
ProcessInstructionWithContext,
},
pubkey::Pubkey,
@ -215,8 +215,8 @@ impl PreAccount {
self.changed = true;
}
pub fn key(&self) -> Pubkey {
self.key
pub fn key(&self) -> &Pubkey {
&self.key
}
pub fn lamports(&self) -> u64 {
@ -250,10 +250,11 @@ impl ComputeMeter for ThisComputeMeter {
}
}
pub struct ThisInvokeContext<'a> {
program_ids: Vec<Pubkey>,
invoke_stack: Vec<InvokeContextStackFrame<'a>>,
rent: Rent,
message: &'a Message,
pre_accounts: Vec<PreAccount>,
executables: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
executable_accounts: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
account_deps: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
programs: &'a [(Pubkey, ProcessInstructionWithContext)],
logger: Rc<RefCell<dyn Logger>>,
@ -272,8 +273,10 @@ impl<'a> ThisInvokeContext<'a> {
pub fn new(
program_id: &Pubkey,
rent: Rent,
pre_accounts: Vec<PreAccount>,
executables: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
message: &'a Message,
instruction: &'a CompiledInstruction,
executable_accounts: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
accounts: &'a [Rc<RefCell<AccountSharedData>>],
account_deps: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
programs: &'a [(Pubkey, ProcessInstructionWithContext)],
log_collector: Option<Rc<LogCollector>>,
@ -284,13 +287,20 @@ impl<'a> ThisInvokeContext<'a> {
account_db: Arc<Accounts>,
ancestors: &'a Ancestors,
) -> Self {
let mut program_ids = Vec::with_capacity(bpf_compute_budget.max_invoke_depth);
program_ids.push(*program_id);
Self {
program_ids,
let pre_accounts = MessageProcessor::create_pre_accounts(message, instruction, accounts);
let keyed_accounts = MessageProcessor::create_keyed_accounts(
message,
instruction,
executable_accounts,
accounts,
feature_set.is_active(&demote_sysvar_write_locks::id()),
);
let mut invoke_context = Self {
invoke_stack: Vec::with_capacity(bpf_compute_budget.max_invoke_depth),
rent,
message,
pre_accounts,
executables,
executable_accounts,
account_deps,
programs,
logger: Rc::new(RefCell::new(ThisLogger { log_collector })),
@ -305,26 +315,80 @@ impl<'a> ThisInvokeContext<'a> {
account_db,
ancestors,
sysvars: vec![],
}
};
invoke_context
.invoke_stack
.push(InvokeContextStackFrame::new(
*program_id,
create_keyed_accounts_unified(&keyed_accounts),
));
invoke_context
}
}
impl<'a> InvokeContext for ThisInvokeContext<'a> {
fn push(&mut self, key: &Pubkey) -> Result<(), InstructionError> {
if self.program_ids.len() > self.bpf_compute_budget.max_invoke_depth {
fn push(
&mut self,
key: &Pubkey,
keyed_accounts: &[(bool, bool, &Pubkey, &RefCell<AccountSharedData>)],
) -> Result<(), InstructionError> {
if self.invoke_stack.len() > self.bpf_compute_budget.max_invoke_depth {
return Err(InstructionError::CallDepth);
}
if self.program_ids.contains(key) && self.program_ids.last() != Some(key) {
let frame_index = self.invoke_stack.iter().position(|frame| frame.key == *key);
if frame_index != None && frame_index != Some(self.invoke_stack.len().saturating_sub(1)) {
// Reentrancy not allowed unless caller is calling itself
return Err(InstructionError::ReentrancyNotAllowed);
}
self.program_ids.push(*key);
// Alias the keys and account references in the provided keyed_accounts
// with the ones already existing in self, so that the lifetime 'a matches.
fn transmute_lifetime<'a, 'b, T: Sized>(value: &'a T) -> &'b T {
unsafe { std::mem::transmute(value) }
}
let keyed_accounts = keyed_accounts
.iter()
.map(|(is_signer, is_writable, search_key, account)| {
self.account_deps
.iter()
.map(|(key, _account)| key)
.chain(self.message.account_keys.iter())
.position(|key| key == *search_key)
.map(|mut index| {
if index < self.account_deps.len() {
(
*is_signer,
*is_writable,
&self.account_deps[index].0,
&self.account_deps[index].1 as &RefCell<AccountSharedData>,
)
} else {
index = index.saturating_sub(self.account_deps.len());
(
*is_signer,
*is_writable,
&self.message.account_keys[index],
// TODO
// Currently we are constructing new accounts on the stack
// before calling MessageProcessor::process_cross_program_instruction
// Ideally we would recycle the existing accounts here like this:
// &self.accounts[index] as &RefCell<AccountSharedData>,
transmute_lifetime(*account),
)
}
})
})
.collect::<Option<Vec<_>>>()
.ok_or(InstructionError::InvalidArgument)?;
self.invoke_stack.push(InvokeContextStackFrame::new(
*key,
create_keyed_accounts_unified(keyed_accounts.as_slice()),
));
Ok(())
}
fn pop(&mut self) {
self.program_ids.pop();
self.invoke_stack.pop();
}
fn invoke_depth(&self) -> usize {
self.program_ids.len()
self.invoke_stack.len()
}
fn verify_and_update(
&mut self,
@ -333,25 +397,42 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
accounts: &[Rc<RefCell<AccountSharedData>>],
caller_write_privileges: Option<&[bool]>,
) -> Result<(), InstructionError> {
match self.program_ids.last() {
Some(program_id) => MessageProcessor::verify_and_update(
message,
instruction,
&mut self.pre_accounts,
accounts,
program_id,
&self.rent,
caller_write_privileges,
&mut self.timings,
self.feature_set.is_active(&demote_sysvar_write_locks::id()),
),
None => Err(InstructionError::GenericError), // Should never happen
}
let stack_frame = self
.invoke_stack
.last()
.ok_or(InstructionError::CallDepth)?;
MessageProcessor::verify_and_update(
message,
instruction,
&mut self.pre_accounts,
accounts,
&stack_frame.key,
&self.rent,
caller_write_privileges,
&mut self.timings,
self.feature_set.is_active(&demote_sysvar_write_locks::id()),
)
}
fn get_caller(&self) -> Result<&Pubkey, InstructionError> {
self.program_ids
self.invoke_stack
.last()
.ok_or(InstructionError::GenericError)
.map(|frame| &frame.key)
.ok_or(InstructionError::CallDepth)
}
fn remove_first_keyed_account(&mut self) -> Result<(), InstructionError> {
let stack_frame = &mut self
.invoke_stack
.last_mut()
.ok_or(InstructionError::CallDepth)?;
stack_frame.keyed_accounts_range.start =
stack_frame.keyed_accounts_range.start.saturating_add(1);
Ok(())
}
fn get_keyed_accounts(&self) -> Result<&[KeyedAccount], InstructionError> {
self.invoke_stack
.last()
.map(|frame| &frame.keyed_accounts[frame.keyed_accounts_range.clone()])
.ok_or(InstructionError::CallDepth)
}
fn get_programs(&self) -> &[(Pubkey, ProcessInstructionWithContext)] {
self.programs
@ -381,7 +462,11 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
}
fn get_account(&self, pubkey: &Pubkey) -> Option<Rc<RefCell<AccountSharedData>>> {
if self.is_feature_active(&cpi_share_ro_and_exec_accounts::id()) {
if let Some((_, account)) = self.executables.iter().find(|(key, _)| key == pubkey) {
if let Some((_, account)) = self
.executable_accounts
.iter()
.find(|(key, _)| key == pubkey)
{
Some(account.clone())
} else if let Some((_, account)) =
self.account_deps.iter().find(|(key, _)| key == pubkey)
@ -476,7 +561,6 @@ impl std::fmt::Debug for MessageProcessor {
// These are just type aliases for work around of Debug-ing above pointers
type ErasedProcessInstructionWithContext = fn(
&'static Pubkey,
&'static [KeyedAccount<'static>],
&'static [u8],
&'static mut dyn InvokeContext,
) -> Result<(), InstructionError>;
@ -554,25 +638,20 @@ impl MessageProcessor {
executable_accounts: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
accounts: &'a [Rc<RefCell<AccountSharedData>>],
demote_sysvar_write_locks: bool,
) -> Vec<KeyedAccount<'a>> {
let mut keyed_accounts = create_keyed_readonly_accounts(&executable_accounts);
let mut keyed_accounts2: Vec<_> = instruction
.accounts
) -> Vec<(bool, bool, &'a Pubkey, &'a RefCell<AccountSharedData>)> {
executable_accounts
.iter()
.map(|&index| {
let is_signer = message.is_signer(index as usize);
let index = index as usize;
let key = &message.account_keys[index];
let account = &accounts[index];
if message.is_writable(index, demote_sysvar_write_locks) {
KeyedAccount::new(key, is_signer, account)
} else {
KeyedAccount::new_readonly(key, is_signer, account)
}
})
.collect();
keyed_accounts.append(&mut keyed_accounts2);
keyed_accounts
.map(|(key, account)| (false, false, key, account as &RefCell<AccountSharedData>))
.chain(instruction.accounts.iter().map(|index| {
let index = *index as usize;
(
message.is_signer(index),
message.is_writable(index, demote_sysvar_write_locks),
&message.account_keys[index],
&accounts[index] as &RefCell<AccountSharedData>,
)
}))
.collect::<Vec<_>>()
}
/// Process an instruction
@ -580,28 +659,22 @@ impl MessageProcessor {
fn process_instruction(
&self,
program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
instruction_data: &[u8],
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
if let Some(root_account) = keyed_accounts.iter().next() {
if let Some(root_account) = invoke_context.get_keyed_accounts()?.iter().next() {
let root_id = root_account.unsigned_key();
if native_loader::check_id(&root_account.owner()?) {
for (id, process_instruction) in &self.programs {
if id == root_id {
invoke_context.remove_first_keyed_account()?;
// Call the builtin program
return process_instruction(
&program_id,
&keyed_accounts[1..],
instruction_data,
invoke_context,
);
return process_instruction(&program_id, instruction_data, invoke_context);
}
}
// Call the program via the native loader
return self.native_loader.process_instruction(
&native_loader::id(),
keyed_accounts,
instruction_data,
invoke_context,
);
@ -610,12 +683,7 @@ impl MessageProcessor {
for (id, process_instruction) in &self.programs {
if id == owner_id {
// Call the program via a builtin loader
return process_instruction(
&program_id,
keyed_accounts,
instruction_data,
invoke_context,
);
return process_instruction(&program_id, instruction_data, invoke_context);
}
}
}
@ -704,43 +772,44 @@ impl MessageProcessor {
pub fn native_invoke(
invoke_context: &mut dyn InvokeContext,
instruction: Instruction,
keyed_accounts: &[&KeyedAccount],
signers_seeds: &[&[&[u8]]],
keyed_account_indices: &[usize],
signers: &[Pubkey],
) -> Result<(), InstructionError> {
let invoke_context = RefCell::new(invoke_context);
let (
message,
executables,
executable_accounts,
accounts,
account_refs,
keyed_account_indices_reordered,
caller_write_privileges,
demote_sysvar_write_locks,
) = {
let invoke_context = invoke_context.borrow();
let caller_program_id = invoke_context.get_caller()?;
// Translate and verify caller's data
let signers = signers_seeds
let keyed_accounts = invoke_context.get_keyed_accounts()?;
let keyed_accounts = keyed_account_indices
.iter()
.map(|seeds| Pubkey::create_program_address(&seeds, caller_program_id))
.collect::<Result<Vec<_>, solana_sdk::pubkey::PubkeyError>>()?;
let mut caller_write_privileges = keyed_accounts
.iter()
.map(|keyed_account| keyed_account.is_writable())
.collect::<Vec<bool>>();
caller_write_privileges.insert(0, false);
.map(|index| keyed_account_at_index(keyed_accounts, *index))
.collect::<Result<Vec<&KeyedAccount>, InstructionError>>()?;
let (message, callee_program_id, _) =
Self::create_message(&instruction, &keyed_accounts, &signers, &invoke_context)?;
let keyed_accounts = invoke_context.get_keyed_accounts()?;
let mut caller_write_privileges = keyed_account_indices
.iter()
.map(|index| keyed_accounts[*index].is_writable())
.collect::<Vec<bool>>();
caller_write_privileges.insert(0, false);
let mut accounts = vec![];
let mut account_refs = vec![];
let mut keyed_account_indices_reordered = vec![];
let keyed_accounts = invoke_context.get_keyed_accounts()?;
'root: for account_key in message.account_keys.iter() {
for keyed_account in keyed_accounts {
for keyed_account_index in keyed_account_indices {
let keyed_account = &keyed_accounts[*keyed_account_index];
if account_key == keyed_account.unsigned_key() {
accounts.push(Rc::new(keyed_account.account.clone()));
account_refs.push(keyed_account);
keyed_account_indices_reordered.push(*keyed_account_index);
continue 'root;
}
}
@ -771,42 +840,41 @@ impl MessageProcessor {
);
return Err(InstructionError::AccountNotExecutable);
}
let programdata_executable =
if program_account.borrow().owner == bpf_loader_upgradeable::id() {
if let UpgradeableLoaderState::Program {
programdata_address,
} = program_account.borrow().state()?
{
if let Some(account) = invoke_context.get_account(&programdata_address) {
Some((programdata_address, account))
} else {
ic_msg!(
invoke_context,
"Unknown upgradeable programdata account {}",
programdata_address,
);
return Err(InstructionError::MissingAccount);
}
let programdata = if program_account.borrow().owner == bpf_loader_upgradeable::id() {
if let UpgradeableLoaderState::Program {
programdata_address,
} = program_account.borrow().state()?
{
if let Some(account) = invoke_context.get_account(&programdata_address) {
Some((programdata_address, account))
} else {
ic_msg!(
invoke_context,
"Upgradeable program account state not valid {}",
callee_program_id,
"Unknown upgradeable programdata account {}",
programdata_address,
);
return Err(InstructionError::MissingAccount);
}
} else {
None
};
let mut executables = vec![(callee_program_id, program_account)];
if let Some(programdata) = programdata_executable {
executables.push(programdata);
ic_msg!(
invoke_context,
"Upgradeable program account state not valid {}",
callee_program_id,
);
return Err(InstructionError::MissingAccount);
}
} else {
None
};
let mut executable_accounts = vec![(callee_program_id, program_account)];
if let Some(programdata) = programdata {
executable_accounts.push(programdata);
}
(
message,
executables,
executable_accounts,
accounts,
account_refs,
keyed_account_indices_reordered,
caller_write_privileges,
invoke_context.is_feature_active(&demote_sysvar_write_locks::id()),
)
@ -815,7 +883,7 @@ impl MessageProcessor {
#[allow(clippy::deref_addrof)]
MessageProcessor::process_cross_program_instruction(
&message,
&executables,
&executable_accounts,
&accounts,
&caller_write_privileges,
*(&mut *(invoke_context.borrow_mut())),
@ -825,13 +893,19 @@ impl MessageProcessor {
{
let invoke_context = invoke_context.borrow();
for (i, (account, account_ref)) in accounts.iter().zip(account_refs).enumerate() {
let account = account.borrow();
if message.is_writable(i, demote_sysvar_write_locks) && !account.executable {
account_ref.try_account_ref_mut()?.lamports = account.lamports;
account_ref.try_account_ref_mut()?.owner = account.owner;
if account_ref.data_len()? != account.data().len()
&& account_ref.data_len()? != 0
let keyed_accounts = invoke_context.get_keyed_accounts()?;
for (src_keyed_account_index, (account, dst_keyed_account_index)) in accounts
.iter()
.zip(keyed_account_indices_reordered)
.enumerate()
{
let dst_keyed_account = &keyed_accounts[dst_keyed_account_index];
let src_keyed_account = account.borrow();
if message.is_writable(src_keyed_account_index, demote_sysvar_write_locks)
&& !src_keyed_account.executable
{
if dst_keyed_account.data_len()? != src_keyed_account.data().len()
&& dst_keyed_account.data_len()? != 0
{
// Only support for `CreateAccount` at this time.
// Need a way to limit total realloc size across multiple CPI calls
@ -841,9 +915,11 @@ impl MessageProcessor {
);
return Err(InstructionError::InvalidRealloc);
}
account_ref
dst_keyed_account.try_account_ref_mut()?.lamports = src_keyed_account.lamports;
dst_keyed_account.try_account_ref_mut()?.owner = src_keyed_account.owner;
dst_keyed_account
.try_account_ref_mut()?
.set_data(account.data().clone());
.set_data(src_keyed_account.data().clone());
}
}
}
@ -870,19 +946,18 @@ impl MessageProcessor {
accounts,
Some(caller_write_privileges),
)?;
let demote_sysvar_write_locks =
invoke_context.is_feature_active(&demote_sysvar_write_locks::id());
// Construct keyed accounts
let keyed_accounts = Self::create_keyed_accounts(
message,
instruction,
executable_accounts,
accounts,
demote_sysvar_write_locks,
invoke_context.is_feature_active(&demote_sysvar_write_locks::id()),
);
// Invoke callee
invoke_context.push(program_id)?;
invoke_context.push(program_id, &keyed_accounts)?;
let mut message_processor = MessageProcessor::default();
for (program_id, process_instruction) in invoke_context.get_programs().iter() {
@ -891,7 +966,6 @@ impl MessageProcessor {
let mut result = message_processor.process_instruction(
program_id,
&keyed_accounts,
&instruction.data,
invoke_context,
);
@ -899,8 +973,9 @@ impl MessageProcessor {
// Verify the called program has not misbehaved
result = invoke_context.verify_and_update(message, instruction, accounts, None);
}
invoke_context.pop();
// Restore previous state
invoke_context.pop();
result
} else {
// This function is always called with a valid instruction, if that changes return an error
@ -1013,7 +1088,7 @@ impl MessageProcessor {
};
// Find the matching PreAccount
for pre_account in pre_accounts.iter_mut() {
if *key == pre_account.key() {
if key == pre_account.key() {
{
// Verify account has no outstanding references
let _ = account
@ -1089,13 +1164,14 @@ impl MessageProcessor {
}
}
let pre_accounts = Self::create_pre_accounts(message, instruction, accounts);
let program_id = instruction.program_id(&message.account_keys);
let mut invoke_context = ThisInvokeContext::new(
program_id,
rent_collector.rent,
pre_accounts,
message,
instruction,
executable_accounts,
accounts,
account_deps,
&self.programs,
log_collector,
@ -1106,19 +1182,7 @@ impl MessageProcessor {
account_db,
ancestors,
);
let keyed_accounts = Self::create_keyed_accounts(
message,
instruction,
executable_accounts,
accounts,
demote_sysvar_write_locks,
);
self.process_instruction(
program_id,
&keyed_accounts,
&instruction.data,
&mut invoke_context,
)?;
self.process_instruction(program_id, &instruction.data, &mut invoke_context)?;
Self::verify(
message,
instruction,
@ -1198,31 +1262,41 @@ mod tests {
#[test]
fn test_invoke_context() {
const MAX_DEPTH: usize = 10;
let mut program_ids = vec![];
let mut invoke_stack = vec![];
let mut keys = vec![];
let mut pre_accounts = vec![];
let mut accounts = vec![];
let mut metas = vec![];
for i in 0..MAX_DEPTH {
program_ids.push(solana_sdk::pubkey::new_rand());
invoke_stack.push(solana_sdk::pubkey::new_rand());
keys.push(solana_sdk::pubkey::new_rand());
accounts.push(Rc::new(RefCell::new(AccountSharedData::new(
i as u64,
1,
&program_ids[i],
&invoke_stack[i],
))));
pre_accounts.push(PreAccount::new(&keys[i], &accounts[i].borrow()))
metas.push(AccountMeta::new(keys[i], false));
}
let account = AccountSharedData::new(1, 1, &solana_sdk::pubkey::Pubkey::default());
for program_id in program_ids.iter() {
pre_accounts.push(PreAccount::new(program_id, &account.clone()));
for program_id in invoke_stack.iter() {
accounts.push(Rc::new(RefCell::new(AccountSharedData::new(
1,
1,
&solana_sdk::pubkey::Pubkey::default(),
))));
metas.push(AccountMeta::new(*program_id, false));
}
let message = Message::new(
&[Instruction::new_with_bytes(invoke_stack[0], &[0], metas)],
None,
);
let ancestors = Ancestors::default();
let mut invoke_context = ThisInvokeContext::new(
&program_ids[0],
&invoke_stack[0],
Rent::default(),
pre_accounts,
&message,
&message.instructions[0],
&[],
&accounts,
&[],
&[],
None,
@ -1236,8 +1310,8 @@ mod tests {
// Check call depth increases and has a limit
let mut depth_reached = 1;
for program_id in program_ids.iter().skip(1) {
if Err(InstructionError::CallDepth) == invoke_context.push(program_id) {
for program_id in invoke_stack.iter().skip(1) {
if Err(InstructionError::CallDepth) == invoke_context.push(program_id, &[]) {
break;
}
depth_reached += 1;
@ -1254,7 +1328,7 @@ mod tests {
];
let message = Message::new(
&[Instruction::new_with_bytes(
program_ids[owned_index],
invoke_stack[owned_index],
&[0],
metas,
)],
@ -1743,10 +1817,10 @@ mod tests {
fn mock_system_process_instruction(
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
_invoke_context: &mut dyn InvokeContext,
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
let keyed_accounts = invoke_context.get_keyed_accounts()?;
if let Ok(instruction) = bincode::deserialize(data) {
match instruction {
MockSystemInstruction::Correct => Ok(()),
@ -1896,10 +1970,10 @@ mod tests {
fn mock_system_process_instruction(
_program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
_invoke_context: &mut dyn InvokeContext,
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
let keyed_accounts = invoke_context.get_keyed_accounts()?;
if let Ok(instruction) = bincode::deserialize(data) {
match instruction {
MockSystemInstruction::BorrowFail => {
@ -2075,10 +2149,10 @@ mod tests {
fn mock_process_instruction(
program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
_invoke_context: &mut dyn InvokeContext,
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
let keyed_accounts = invoke_context.get_keyed_accounts()?;
assert_eq!(*program_id, keyed_accounts[0].owner()?);
assert_ne!(
keyed_accounts[1].owner()?,
@ -2107,7 +2181,6 @@ mod tests {
let mut program_account = AccountSharedData::new(1, 0, &native_loader::id());
program_account.executable = true;
let executable_preaccount = PreAccount::new(&callee_program_id, &program_account);
let executable_accounts = vec![(
callee_program_id,
Rc::new(RefCell::new(program_account.clone())),
@ -2115,11 +2188,9 @@ mod tests {
let owned_key = solana_sdk::pubkey::new_rand();
let owned_account = AccountSharedData::new(42, 1, &callee_program_id);
let owned_preaccount = PreAccount::new(&owned_key, &owned_account);
let not_owned_key = solana_sdk::pubkey::new_rand();
let not_owned_account = AccountSharedData::new(84, 1, &solana_sdk::pubkey::new_rand());
let not_owned_preaccount = PreAccount::new(&not_owned_key, &not_owned_account);
#[allow(unused_mut)]
let mut accounts = vec![
@ -2127,18 +2198,30 @@ mod tests {
Rc::new(RefCell::new(not_owned_account)),
Rc::new(RefCell::new(program_account)),
];
let compiled_instruction = CompiledInstruction::new(2, &(), vec![0, 1, 2]);
let programs: Vec<(_, ProcessInstructionWithContext)> =
vec![(callee_program_id, mock_process_instruction)];
let metas = vec![
AccountMeta::new(owned_key, false),
AccountMeta::new(not_owned_key, false),
];
let instruction = Instruction::new_with_bincode(
callee_program_id,
&MockInstruction::NoopSuccess,
metas.clone(),
);
let message = Message::new(&[instruction], None);
let ancestors = Ancestors::default();
let mut invoke_context = ThisInvokeContext::new(
&caller_program_id,
Rent::default(),
vec![
owned_preaccount,
not_owned_preaccount,
executable_preaccount,
],
&[],
&message,
&compiled_instruction,
&executable_accounts,
&accounts,
&[],
programs.as_slice(),
None,
@ -2149,26 +2232,17 @@ mod tests {
Arc::new(Accounts::default()),
&ancestors,
);
let metas = vec![
AccountMeta::new(owned_key, false),
AccountMeta::new(not_owned_key, false),
];
// not owned account modified by the caller (before the invoke)
accounts[0].borrow_mut().data_as_mut_slice()[0] = 1;
let instruction = Instruction::new_with_bincode(
callee_program_id,
&MockInstruction::NoopSuccess,
metas.clone(),
);
let demote_sysvar_write_locks = true;
let message = Message::new(&[instruction], None);
let demote_sysvar_write_locks =
invoke_context.is_feature_active(&demote_sysvar_write_locks::id());
let caller_write_privileges = message
.account_keys
.iter()
.enumerate()
.map(|(i, _)| message.is_writable(i, demote_sysvar_write_locks))
.collect::<Vec<bool>>();
accounts[0].borrow_mut().data_as_mut_slice()[0] = 1;
assert_eq!(
MessageProcessor::process_cross_program_instruction(
&message,
@ -2198,6 +2272,26 @@ mod tests {
let instruction =
Instruction::new_with_bincode(callee_program_id, &case.0, metas.clone());
let message = Message::new(&[instruction], None);
let ancestors = Ancestors::default();
let mut invoke_context = ThisInvokeContext::new(
&caller_program_id,
Rent::default(),
&message,
&compiled_instruction,
&executable_accounts,
&accounts,
&[],
programs.as_slice(),
None,
BpfComputeBudget::default(),
Rc::new(RefCell::new(Executors::default())),
None,
Arc::new(FeatureSet::all_enabled()),
Arc::new(Accounts::default()),
&ancestors,
);
let caller_write_privileges = message
.account_keys
.iter()
@ -2223,7 +2317,6 @@ mod tests {
#[allow(clippy::unnecessary_wraps)]
fn mock_process_instruction(
_program_id: &Pubkey,
_keyed_accounts: &[KeyedAccount],
_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
@ -2232,7 +2325,6 @@ mod tests {
#[allow(clippy::unnecessary_wraps)]
fn mock_ix_processor(
_pubkey: &Pubkey,
_ka: &[KeyedAccount],
_data: &[u8],
_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {

View File

@ -10,7 +10,7 @@ use solana_sdk::{
decode_error::DecodeError,
entrypoint_native::ProgramEntrypoint,
instruction::InstructionError,
keyed_account::{next_keyed_account, KeyedAccount},
keyed_account::keyed_account_at_index,
native_loader,
process_instruction::{InvokeContext, LoaderEntrypoint},
pubkey::Pubkey,
@ -135,24 +135,30 @@ impl NativeLoader {
pub fn process_instruction(
&self,
program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
instruction_data: &[u8],
invoke_context: &dyn InvokeContext,
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
let mut keyed_accounts_iter = keyed_accounts.iter();
let program = next_keyed_account(&mut keyed_accounts_iter)?;
if native_loader::id() != *program_id {
error!("Program id mismatch");
return Err(InstructionError::IncorrectProgramId);
}
if program.owner()? != *program_id {
error!("Executable account now owned by loader");
return Err(InstructionError::IncorrectProgramId);
}
let (program_id, name_vec) = {
let keyed_accounts = invoke_context.get_keyed_accounts()?;
let program = keyed_account_at_index(keyed_accounts, 0)?;
if native_loader::id() != *program_id {
error!("Program id mismatch");
return Err(InstructionError::IncorrectProgramId);
}
if program.owner()? != *program_id {
error!("Executable account now owned by loader");
return Err(InstructionError::IncorrectProgramId);
}
// TODO: Remove these two copies (* deref is also a copy)
// Both could be avoided as we know that the first KeyedAccount
// still exists even after invoke_context.remove_first_keyed_account() is called
(
*program.unsigned_key(),
&program.try_account_ref()?.data().clone(),
)
};
let params = keyed_accounts_iter.as_slice();
let account = program.try_account_ref()?;
let name = match str::from_utf8(account.data()) {
let name = match str::from_utf8(name_vec) {
Ok(v) => v,
Err(e) => {
error!("Invalid UTF-8 sequence: {}", e);
@ -164,21 +170,21 @@ impl NativeLoader {
return Err(NativeLoaderError::InvalidAccountData.into());
}
trace!("Call native {:?}", name);
invoke_context.remove_first_keyed_account()?;
if name.ends_with("loader_program") {
let entrypoint =
Self::get_entrypoint::<LoaderEntrypoint>(name, &self.loader_symbol_cache)?;
unsafe {
entrypoint(
program.unsigned_key(),
params,
instruction_data,
invoke_context,
)
}
unsafe { entrypoint(&program_id, instruction_data, invoke_context) }
} else {
let entrypoint =
Self::get_entrypoint::<ProgramEntrypoint>(name, &self.program_symbol_cache)?;
unsafe { entrypoint(program.unsigned_key(), params, instruction_data) }
unsafe {
entrypoint(
&program_id,
invoke_context.get_keyed_accounts()?,
instruction_data,
)
}
}
}
}

View File

@ -4,7 +4,7 @@ use solana_sdk::{
account_utils::StateMut,
ic_msg,
instruction::InstructionError,
keyed_account::{from_keyed_account, get_signers, next_keyed_account, KeyedAccount},
keyed_account::{from_keyed_account, get_signers, keyed_account_at_index, KeyedAccount},
nonce,
nonce_keyed_account::NonceKeyedAccount,
process_instruction::InvokeContext,
@ -35,7 +35,7 @@ impl Address {
fn create(
address: &Pubkey,
with_seed: Option<(&Pubkey, &str, &Pubkey)>,
invoke_context: &mut dyn InvokeContext,
invoke_context: &dyn InvokeContext,
) -> Result<Self, InstructionError> {
let base = if let Some((base, seed, owner)) = with_seed {
let address_with_seed = Pubkey::create_with_seed(base, seed, owner)?;
@ -66,7 +66,7 @@ fn allocate(
address: &Address,
space: u64,
signers: &HashSet<Pubkey>,
invoke_context: &mut dyn InvokeContext,
invoke_context: &dyn InvokeContext,
) -> Result<(), InstructionError> {
if !address.is_signer(signers) {
ic_msg!(
@ -108,7 +108,7 @@ fn assign(
address: &Address,
owner: &Pubkey,
signers: &HashSet<Pubkey>,
invoke_context: &mut dyn InvokeContext,
invoke_context: &dyn InvokeContext,
) -> Result<(), InstructionError> {
// no work to do, just return
if account.owner == *owner {
@ -136,7 +136,7 @@ fn allocate_and_assign(
space: u64,
owner: &Pubkey,
signers: &HashSet<Pubkey>,
invoke_context: &mut dyn InvokeContext,
invoke_context: &dyn InvokeContext,
) -> Result<(), InstructionError> {
allocate(to, to_address, space, signers, invoke_context)?;
assign(to, to_address, owner, signers, invoke_context)
@ -150,7 +150,7 @@ fn create_account(
space: u64,
owner: &Pubkey,
signers: &HashSet<Pubkey>,
invoke_context: &mut dyn InvokeContext,
invoke_context: &dyn InvokeContext,
) -> Result<(), InstructionError> {
// if it looks like the `to` account is already in use, bail
{
@ -173,7 +173,7 @@ fn transfer_verified(
from: &KeyedAccount,
to: &KeyedAccount,
lamports: u64,
invoke_context: &mut dyn InvokeContext,
invoke_context: &dyn InvokeContext,
) -> Result<(), InstructionError> {
if !from.data_is_empty()? {
ic_msg!(invoke_context, "Transfer: `from` must not carry data");
@ -198,7 +198,7 @@ fn transfer(
from: &KeyedAccount,
to: &KeyedAccount,
lamports: u64,
invoke_context: &mut dyn InvokeContext,
invoke_context: &dyn InvokeContext,
) -> Result<(), InstructionError> {
if lamports == 0 {
return Ok(());
@ -223,7 +223,7 @@ fn transfer_with_seed(
from_owner: &Pubkey,
to: &KeyedAccount,
lamports: u64,
invoke_context: &mut dyn InvokeContext,
invoke_context: &dyn InvokeContext,
) -> Result<(), InstructionError> {
if lamports == 0 {
return Ok(());
@ -255,17 +255,16 @@ fn transfer_with_seed(
pub fn process_instruction(
_owner: &Pubkey,
keyed_accounts: &[KeyedAccount],
instruction_data: &[u8],
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
let keyed_accounts = invoke_context.get_keyed_accounts()?;
let instruction = limited_deserialize(instruction_data)?;
trace!("process_instruction: {:?}", instruction);
trace!("keyed_accounts: {:?}", keyed_accounts);
let signers = get_signers(keyed_accounts);
let keyed_accounts_iter = &mut keyed_accounts.iter();
match instruction {
SystemInstruction::CreateAccount {
@ -273,8 +272,8 @@ pub fn process_instruction(
space,
owner,
} => {
let from = next_keyed_account(keyed_accounts_iter)?;
let to = next_keyed_account(keyed_accounts_iter)?;
let from = keyed_account_at_index(keyed_accounts, 0)?;
let to = keyed_account_at_index(keyed_accounts, 1)?;
let to_address = Address::create(to.unsigned_key(), None, invoke_context)?;
create_account(
from,
@ -294,8 +293,8 @@ pub fn process_instruction(
space,
owner,
} => {
let from = next_keyed_account(keyed_accounts_iter)?;
let to = next_keyed_account(keyed_accounts_iter)?;
let from = keyed_account_at_index(keyed_accounts, 0)?;
let to = keyed_account_at_index(keyed_accounts, 1)?;
let to_address = Address::create(
&to.unsigned_key(),
Some((&base, &seed, &owner)),
@ -313,14 +312,14 @@ pub fn process_instruction(
)
}
SystemInstruction::Assign { owner } => {
let keyed_account = next_keyed_account(keyed_accounts_iter)?;
let keyed_account = keyed_account_at_index(keyed_accounts, 0)?;
let mut account = keyed_account.try_account_ref_mut()?;
let address = Address::create(keyed_account.unsigned_key(), None, invoke_context)?;
assign(&mut account, &address, &owner, &signers, invoke_context)
}
SystemInstruction::Transfer { lamports } => {
let from = next_keyed_account(keyed_accounts_iter)?;
let to = next_keyed_account(keyed_accounts_iter)?;
let from = keyed_account_at_index(keyed_accounts, 0)?;
let to = keyed_account_at_index(keyed_accounts, 1)?;
transfer(from, to, lamports, invoke_context)
}
SystemInstruction::TransferWithSeed {
@ -328,9 +327,9 @@ pub fn process_instruction(
from_seed,
from_owner,
} => {
let from = next_keyed_account(keyed_accounts_iter)?;
let base = next_keyed_account(keyed_accounts_iter)?;
let to = next_keyed_account(keyed_accounts_iter)?;
let from = keyed_account_at_index(keyed_accounts, 0)?;
let base = keyed_account_at_index(keyed_accounts, 1)?;
let to = keyed_account_at_index(keyed_accounts, 2)?;
transfer_with_seed(
from,
base,
@ -342,40 +341,49 @@ pub fn process_instruction(
)
}
SystemInstruction::AdvanceNonceAccount => {
let me = &mut next_keyed_account(keyed_accounts_iter)?;
let me = &mut keyed_account_at_index(keyed_accounts, 0)?;
me.advance_nonce_account(
&from_keyed_account::<RecentBlockhashes>(next_keyed_account(keyed_accounts_iter)?)?,
&from_keyed_account::<RecentBlockhashes>(keyed_account_at_index(
keyed_accounts,
1,
)?)?,
&signers,
invoke_context,
)
}
SystemInstruction::WithdrawNonceAccount(lamports) => {
let me = &mut next_keyed_account(keyed_accounts_iter)?;
let to = &mut next_keyed_account(keyed_accounts_iter)?;
let me = &mut keyed_account_at_index(keyed_accounts, 0)?;
let to = &mut keyed_account_at_index(keyed_accounts, 1)?;
me.withdraw_nonce_account(
lamports,
to,
&from_keyed_account::<RecentBlockhashes>(next_keyed_account(keyed_accounts_iter)?)?,
&from_keyed_account::<Rent>(next_keyed_account(keyed_accounts_iter)?)?,
&from_keyed_account::<RecentBlockhashes>(keyed_account_at_index(
keyed_accounts,
2,
)?)?,
&from_keyed_account::<Rent>(keyed_account_at_index(keyed_accounts, 3)?)?,
&signers,
invoke_context,
)
}
SystemInstruction::InitializeNonceAccount(authorized) => {
let me = &mut next_keyed_account(keyed_accounts_iter)?;
let me = &mut keyed_account_at_index(keyed_accounts, 0)?;
me.initialize_nonce_account(
&authorized,
&from_keyed_account::<RecentBlockhashes>(next_keyed_account(keyed_accounts_iter)?)?,
&from_keyed_account::<Rent>(next_keyed_account(keyed_accounts_iter)?)?,
&from_keyed_account::<RecentBlockhashes>(keyed_account_at_index(
keyed_accounts,
1,
)?)?,
&from_keyed_account::<Rent>(keyed_account_at_index(keyed_accounts, 2)?)?,
invoke_context,
)
}
SystemInstruction::AuthorizeNonceAccount(nonce_authority) => {
let me = &mut next_keyed_account(keyed_accounts_iter)?;
let me = &mut keyed_account_at_index(keyed_accounts, 0)?;
me.authorize_nonce_account(&nonce_authority, &signers, invoke_context)
}
SystemInstruction::Allocate { space } => {
let keyed_account = next_keyed_account(keyed_accounts_iter)?;
let keyed_account = keyed_account_at_index(keyed_accounts, 0)?;
let mut account = keyed_account.try_account_ref_mut()?;
let address = Address::create(keyed_account.unsigned_key(), None, invoke_context)?;
allocate(&mut account, &address, space, &signers, invoke_context)
@ -386,7 +394,7 @@ pub fn process_instruction(
space,
owner,
} => {
let keyed_account = next_keyed_account(keyed_accounts_iter)?;
let keyed_account = keyed_account_at_index(keyed_accounts, 0)?;
let mut account = keyed_account.try_account_ref_mut()?;
let address = Address::create(
keyed_account.unsigned_key(),
@ -403,7 +411,7 @@ pub fn process_instruction(
)
}
SystemInstruction::AssignWithSeed { base, seed, owner } => {
let keyed_account = next_keyed_account(keyed_accounts_iter)?;
let keyed_account = keyed_account_at_index(keyed_accounts, 0)?;
let mut account = keyed_account.try_account_ref_mut()?;
let address = Address::create(
keyed_account.unsigned_key(),
@ -475,14 +483,13 @@ mod tests {
fn process_instruction(
owner: &Pubkey,
keyed_accounts: &[KeyedAccount],
keyed_accounts: Vec<KeyedAccount>,
instruction_data: &[u8],
) -> Result<(), InstructionError> {
super::process_instruction(
owner,
keyed_accounts,
instruction_data,
&mut MockInvokeContext::default(),
&mut MockInvokeContext::new(keyed_accounts),
)
}
@ -515,7 +522,7 @@ mod tests {
assert_eq!(
process_instruction(
&Pubkey::default(),
&[
vec![
KeyedAccount::new(&from, true, &from_account),
KeyedAccount::new(&to, true, &to_account)
],
@ -547,7 +554,7 @@ mod tests {
assert_eq!(
process_instruction(
&Pubkey::default(),
&[
vec![
KeyedAccount::new(&from, true, &from_account),
KeyedAccount::new(&to, false, &to_account)
],
@ -583,7 +590,7 @@ mod tests {
assert_eq!(
process_instruction(
&Pubkey::default(),
&[
vec![
KeyedAccount::new(&from, true, &from_account),
KeyedAccount::new(&to, false, &to_account),
KeyedAccount::new(&base, true, &base_account)
@ -616,7 +623,7 @@ mod tests {
Address::create(
&to,
Some((&from, seed, &owner)),
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
),
Err(SystemError::AddressWithSeedMismatch.into())
);
@ -634,7 +641,7 @@ mod tests {
let to_address = Address::create(
&to,
Some((&from, seed, &new_owner)),
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
@ -647,7 +654,7 @@ mod tests {
2,
&new_owner,
&HashSet::new(),
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
),
Err(InstructionError::MissingRequiredSignature)
);
@ -674,7 +681,7 @@ mod tests {
2,
&new_owner,
&[to].iter().cloned().collect::<HashSet<_>>(),
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
),
Ok(())
);
@ -706,7 +713,7 @@ mod tests {
2,
&new_owner,
&[from, to].iter().cloned().collect::<HashSet<_>>(),
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(SystemError::ResultWithNegativeLamports.into()));
}
@ -730,7 +737,7 @@ mod tests {
MAX_PERMITTED_DATA_LENGTH + 1,
&system_program::id(),
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert!(result.is_err());
assert_eq!(
@ -747,7 +754,7 @@ mod tests {
MAX_PERMITTED_DATA_LENGTH,
&system_program::id(),
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert!(result.is_ok());
assert_eq!(to_account.borrow().lamports, 50);
@ -780,7 +787,7 @@ mod tests {
2,
&new_owner,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into()));
@ -799,7 +806,7 @@ mod tests {
2,
&new_owner,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into()));
let from_lamports = from_account.borrow().lamports;
@ -817,7 +824,7 @@ mod tests {
2,
&new_owner,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into()));
assert_eq!(from_lamports, 100);
@ -845,7 +852,7 @@ mod tests {
2,
&new_owner,
&[owned_key].iter().cloned().collect::<HashSet<_>>(),
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(InstructionError::MissingRequiredSignature));
@ -859,7 +866,7 @@ mod tests {
2,
&new_owner,
&[from].iter().cloned().collect::<HashSet<_>>(),
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(InstructionError::MissingRequiredSignature));
@ -873,7 +880,7 @@ mod tests {
2,
&new_owner,
&[owned_key].iter().cloned().collect::<HashSet<_>>(),
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Ok(()));
}
@ -899,7 +906,7 @@ mod tests {
2,
&sysvar::id(),
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(SystemError::InvalidProgramId.into()));
@ -933,7 +940,7 @@ mod tests {
2,
&new_owner,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(SystemError::AccountAlreadyInUse.into()));
}
@ -967,7 +974,7 @@ mod tests {
0,
&solana_sdk::pubkey::new_rand(),
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
),
Err(InstructionError::InvalidArgument),
);
@ -986,7 +993,7 @@ mod tests {
&pubkey.into(),
&new_owner,
&HashSet::new(),
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
),
Err(InstructionError::MissingRequiredSignature)
);
@ -997,7 +1004,7 @@ mod tests {
&pubkey.into(),
&system_program::id(),
&HashSet::new(),
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
),
Ok(())
);
@ -1006,7 +1013,7 @@ mod tests {
assert_eq!(
process_instruction(
&Pubkey::default(),
&[KeyedAccount::new(&pubkey, true, &account)],
vec![KeyedAccount::new(&pubkey, true, &account)],
&bincode::serialize(&SystemInstruction::Assign { owner: new_owner }).unwrap()
),
Ok(())
@ -1026,7 +1033,7 @@ mod tests {
&from.into(),
&new_owner,
&[from].iter().cloned().collect::<HashSet<_>>(),
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
),
Err(SystemError::InvalidProgramId.into())
);
@ -1039,7 +1046,7 @@ mod tests {
owner: solana_sdk::pubkey::new_rand(),
};
let data = serialize(&instruction).unwrap();
let result = process_instruction(&system_program::id(), &[], &data);
let result = process_instruction(&system_program::id(), vec![], &data);
assert_eq!(result, Err(InstructionError::NotEnoughAccountKeys));
let from = solana_sdk::pubkey::new_rand();
@ -1049,7 +1056,7 @@ mod tests {
let data = serialize(&instruction).unwrap();
let result = process_instruction(
&system_program::id(),
&[KeyedAccount::new(&from, true, &from_account)],
vec![KeyedAccount::new(&from, true, &from_account)],
&data,
);
assert_eq!(result, Err(InstructionError::NotEnoughAccountKeys));
@ -1067,7 +1074,7 @@ mod tests {
&from_keyed_account,
&to_keyed_account,
50,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
let from_lamports = from_keyed_account.account.borrow().lamports;
@ -1081,7 +1088,7 @@ mod tests {
&from_keyed_account,
&to_keyed_account,
100,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(SystemError::ResultWithNegativeLamports.into()));
assert_eq!(from_keyed_account.account.borrow().lamports, 50);
@ -1094,7 +1101,7 @@ mod tests {
&from_keyed_account,
&to_keyed_account,
0,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.is_ok(),);
assert_eq!(from_keyed_account.account.borrow().lamports, 50);
@ -1121,7 +1128,7 @@ mod tests {
&from_owner,
&to_keyed_account,
50,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
let from_lamports = from_keyed_account.account.borrow().lamports;
@ -1138,7 +1145,7 @@ mod tests {
&from_owner,
&to_keyed_account,
100,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(SystemError::ResultWithNegativeLamports.into()));
assert_eq!(from_keyed_account.account.borrow().lamports, 50);
@ -1153,7 +1160,7 @@ mod tests {
&from_owner,
&to_keyed_account,
0,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.is_ok(),);
assert_eq!(from_keyed_account.account.borrow().lamports, 50);
@ -1184,7 +1191,7 @@ mod tests {
&KeyedAccount::new(&from, true, &from_account),
&KeyedAccount::new(&to, false, &to_account),
50,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
),
Err(InstructionError::InvalidArgument),
)
@ -1391,7 +1398,7 @@ mod tests {
.zip(accounts.iter())
.map(|(meta, account)| KeyedAccount::new(&meta.pubkey, meta.is_signer, account))
.collect();
process_instruction(&Pubkey::default(), &keyed_accounts, &instruction.data)
process_instruction(&Pubkey::default(), keyed_accounts, &instruction.data)
}
}
@ -1411,7 +1418,7 @@ mod tests {
assert_eq!(
process_instruction(
&Pubkey::default(),
&[],
vec![],
&serialize(&SystemInstruction::AdvanceNonceAccount).unwrap()
),
Err(InstructionError::NotEnoughAccountKeys),
@ -1423,11 +1430,11 @@ mod tests {
assert_eq!(
process_instruction(
&Pubkey::default(),
&[KeyedAccount::new(
vec![KeyedAccount::new(
&Pubkey::default(),
true,
&create_default_account(),
),],
)],
&serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(),
),
Err(InstructionError::NotEnoughAccountKeys),
@ -1439,7 +1446,7 @@ mod tests {
assert_eq!(
process_instruction(
&Pubkey::default(),
&[
vec![
KeyedAccount::new(&Pubkey::default(), true, &create_default_account()),
KeyedAccount::new(
&sysvar::recent_blockhashes::id(),
@ -1458,7 +1465,7 @@ mod tests {
let nonce_acc = nonce_account::create_account(1_000_000);
process_instruction(
&Pubkey::default(),
&[
vec![
KeyedAccount::new(&Pubkey::default(), true, &nonce_acc),
KeyedAccount::new(
&sysvar::recent_blockhashes::id(),
@ -1486,7 +1493,7 @@ mod tests {
assert_eq!(
process_instruction(
&Pubkey::default(),
&[
vec![
KeyedAccount::new(&Pubkey::default(), true, &nonce_acc,),
KeyedAccount::new(
&sysvar::recent_blockhashes::id(),
@ -1518,7 +1525,7 @@ mod tests {
assert_eq!(
process_instruction(
&Pubkey::default(),
&[],
vec![],
&serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
),
Err(InstructionError::NotEnoughAccountKeys),
@ -1530,11 +1537,11 @@ mod tests {
assert_eq!(
process_instruction(
&Pubkey::default(),
&[KeyedAccount::new(
vec![KeyedAccount::new(
&Pubkey::default(),
true,
&create_default_account()
),],
)],
&serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
),
Err(InstructionError::NotEnoughAccountKeys),
@ -1546,7 +1553,7 @@ mod tests {
assert_eq!(
process_instruction(
&Pubkey::default(),
&[
vec![
KeyedAccount::new(&Pubkey::default(), true, &create_default_account()),
KeyedAccount::new(&Pubkey::default(), false, &create_default_account()),
KeyedAccount::new(
@ -1566,7 +1573,7 @@ mod tests {
assert_eq!(
process_instruction(
&Pubkey::default(),
&[
vec![
KeyedAccount::new(
&Pubkey::default(),
true,
@ -1591,7 +1598,7 @@ mod tests {
assert_eq!(
process_instruction(
&Pubkey::default(),
&[
vec![
KeyedAccount::new(
&Pubkey::default(),
true,
@ -1616,7 +1623,7 @@ mod tests {
assert_eq!(
process_instruction(
&Pubkey::default(),
&[],
vec![],
&serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(),
),
Err(InstructionError::NotEnoughAccountKeys),
@ -1628,11 +1635,11 @@ mod tests {
assert_eq!(
process_instruction(
&Pubkey::default(),
&[KeyedAccount::new(
vec![KeyedAccount::new(
&Pubkey::default(),
true,
&nonce_account::create_account(1_000_000),
),],
)],
&serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(),
),
Err(InstructionError::NotEnoughAccountKeys),
@ -1644,7 +1651,7 @@ mod tests {
assert_eq!(
process_instruction(
&Pubkey::default(),
&[
vec![
KeyedAccount::new(
&Pubkey::default(),
true,
@ -1667,7 +1674,7 @@ mod tests {
assert_eq!(
process_instruction(
&Pubkey::default(),
&[
vec![
KeyedAccount::new(
&Pubkey::default(),
true,
@ -1691,7 +1698,7 @@ mod tests {
assert_eq!(
process_instruction(
&Pubkey::default(),
&[
vec![
KeyedAccount::new(
&Pubkey::default(),
true,
@ -1715,7 +1722,7 @@ mod tests {
let nonce_acc = nonce_account::create_account(1_000_000);
process_instruction(
&Pubkey::default(),
&[
vec![
KeyedAccount::new(&Pubkey::default(), true, &nonce_acc),
KeyedAccount::new(
&sysvar::recent_blockhashes::id(),
@ -1730,7 +1737,7 @@ mod tests {
assert_eq!(
process_instruction(
&Pubkey::default(),
&[KeyedAccount::new(&Pubkey::default(), true, &nonce_acc,),],
vec![KeyedAccount::new(&Pubkey::default(), true, &nonce_acc,),],
&serialize(&SystemInstruction::AuthorizeNonceAccount(Pubkey::default(),)).unwrap(),
),
Ok(()),

View File

@ -89,14 +89,12 @@ macro_rules! declare_name {
/// use solana_sdk::{
/// declare_program,
/// instruction::InstructionError,
/// keyed_account::KeyedAccount,
/// process_instruction::InvokeContext,
/// pubkey::Pubkey,
/// };
///
/// fn my_process_instruction(
/// program_id: &Pubkey,
/// keyed_accounts: &[KeyedAccount],
/// instruction_data: &[u8],
/// invoke_context: &mut dyn InvokeContext,
/// ) -> Result<(), InstructionError> {
@ -124,14 +122,12 @@ macro_rules! declare_name {
/// use solana_sdk::{
/// declare_program,
/// instruction::InstructionError,
/// keyed_account::KeyedAccount,
/// process_instruction::InvokeContext,
/// pubkey::Pubkey,
/// };
///
/// fn my_process_instruction(
/// program_id: &Pubkey,
/// keyed_accounts: &[KeyedAccount],
/// instruction_data: &[u8],
/// invoke_context: &mut dyn InvokeContext,
/// ) -> Result<(), InstructionError> {
@ -158,11 +154,10 @@ macro_rules! declare_program(
#[no_mangle]
pub extern "C" fn $name(
program_id: &$crate::pubkey::Pubkey,
keyed_accounts: &[$crate::keyed_account::KeyedAccount],
instruction_data: &[u8],
invoke_context: &mut dyn $crate::process_instruction::InvokeContext,
) -> Result<(), $crate::instruction::InstructionError> {
$entrypoint(program_id, keyed_accounts, instruction_data, invoke_context)
$entrypoint(program_id, instruction_data, invoke_context)
}
)
);

View File

@ -10,7 +10,7 @@ use std::{
};
#[repr(C)]
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct KeyedAccount<'a> {
is_signer: bool, // Transaction was signed by this account's key
is_writable: bool,
@ -146,6 +146,10 @@ pub fn create_keyed_accounts<'a>(
accounts.iter().map(Into::into).collect()
}
#[deprecated(
since = "1.7.0",
note = "Please use create_keyed_accounts_unified instead"
)]
pub fn create_keyed_is_signer_accounts<'a>(
accounts: &'a [(&'a Pubkey, bool, &'a RefCell<AccountSharedData>)],
) -> Vec<KeyedAccount<'a>> {
@ -160,6 +164,10 @@ pub fn create_keyed_is_signer_accounts<'a>(
.collect()
}
#[deprecated(
since = "1.7.0",
note = "Please use create_keyed_accounts_unified instead"
)]
pub fn create_keyed_readonly_accounts(
accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
) -> Vec<KeyedAccount> {
@ -174,6 +182,20 @@ pub fn create_keyed_readonly_accounts(
.collect()
}
pub fn create_keyed_accounts_unified<'a>(
accounts: &[(bool, bool, &'a Pubkey, &'a RefCell<AccountSharedData>)],
) -> Vec<KeyedAccount<'a>> {
accounts
.iter()
.map(|(is_signer, is_writable, key, account)| KeyedAccount {
is_signer: *is_signer,
is_writable: *is_writable,
key,
account,
})
.collect()
}
/// Return all the signers from a set of KeyedAccounts
pub fn get_signers<A>(keyed_accounts: &[KeyedAccount]) -> A
where
@ -186,6 +208,7 @@ where
.collect::<A>()
}
#[deprecated(since = "1.7.0", note = "Please use keyed_account_at_index instead")]
/// Return the next KeyedAccount or a NotEnoughAccountKeys error
pub fn next_keyed_account<'a, 'b, I: Iterator<Item = &'a KeyedAccount<'b>>>(
iter: &mut I,
@ -193,6 +216,16 @@ pub fn next_keyed_account<'a, 'b, I: Iterator<Item = &'a KeyedAccount<'b>>>(
iter.next().ok_or(InstructionError::NotEnoughAccountKeys)
}
/// Return the KeyedAccount at the specified index or a NotEnoughAccountKeys error
pub fn keyed_account_at_index<'a>(
keyed_accounts: &'a [KeyedAccount],
index: usize,
) -> Result<&'a KeyedAccount<'a>, InstructionError> {
keyed_accounts
.get(index)
.ok_or(InstructionError::NotEnoughAccountKeys)
}
/// Return true if the first keyed_account is executable, used to determine if
/// the loader should call a program's 'main'
pub fn is_executable(keyed_accounts: &[KeyedAccount]) -> Result<bool, InstructionError> {

View File

@ -16,7 +16,7 @@ pub trait NonceKeyedAccount {
&self,
recent_blockhashes: &RecentBlockhashes,
signers: &HashSet<Pubkey>,
invoke_context: &mut dyn InvokeContext,
invoke_context: &dyn InvokeContext,
) -> Result<(), InstructionError>;
fn withdraw_nonce_account(
&self,
@ -25,20 +25,20 @@ pub trait NonceKeyedAccount {
recent_blockhashes: &RecentBlockhashes,
rent: &Rent,
signers: &HashSet<Pubkey>,
invoke_context: &mut dyn InvokeContext,
invoke_context: &dyn InvokeContext,
) -> Result<(), InstructionError>;
fn initialize_nonce_account(
&self,
nonce_authority: &Pubkey,
recent_blockhashes: &RecentBlockhashes,
rent: &Rent,
invoke_context: &mut dyn InvokeContext,
invoke_context: &dyn InvokeContext,
) -> Result<(), InstructionError>;
fn authorize_nonce_account(
&self,
nonce_authority: &Pubkey,
signers: &HashSet<Pubkey>,
invoke_context: &mut dyn InvokeContext,
invoke_context: &dyn InvokeContext,
) -> Result<(), InstructionError>;
}
@ -47,7 +47,7 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> {
&self,
recent_blockhashes: &RecentBlockhashes,
signers: &HashSet<Pubkey>,
invoke_context: &mut dyn InvokeContext,
invoke_context: &dyn InvokeContext,
) -> Result<(), InstructionError> {
if recent_blockhashes.is_empty() {
ic_msg!(
@ -102,7 +102,7 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> {
recent_blockhashes: &RecentBlockhashes,
rent: &Rent,
signers: &HashSet<Pubkey>,
invoke_context: &mut dyn InvokeContext,
invoke_context: &dyn InvokeContext,
) -> Result<(), InstructionError> {
let signer = match AccountUtilsState::<Versions>::state(self)?.convert_to_current() {
State::Uninitialized => {
@ -170,7 +170,7 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> {
nonce_authority: &Pubkey,
recent_blockhashes: &RecentBlockhashes,
rent: &Rent,
invoke_context: &mut dyn InvokeContext,
invoke_context: &dyn InvokeContext,
) -> Result<(), InstructionError> {
if recent_blockhashes.is_empty() {
ic_msg!(
@ -214,7 +214,7 @@ impl<'a> NonceKeyedAccount for KeyedAccount<'a> {
&self,
nonce_authority: &Pubkey,
signers: &HashSet<Pubkey>,
invoke_context: &mut dyn InvokeContext,
invoke_context: &dyn InvokeContext,
) -> Result<(), InstructionError> {
match AccountUtilsState::<Versions>::state(self)?.convert_to_current() {
State::Initialized(data) => {
@ -300,7 +300,7 @@ mod test {
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
let state = AccountUtilsState::<Versions>::state(keyed_account)
@ -318,7 +318,7 @@ mod test {
.advance_nonce_account(
&recent_blockhashes,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
let state = AccountUtilsState::<Versions>::state(keyed_account)
@ -336,7 +336,7 @@ mod test {
.advance_nonce_account(
&recent_blockhashes,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
let state = AccountUtilsState::<Versions>::state(keyed_account)
@ -362,7 +362,7 @@ mod test {
&recent_blockhashes,
&rent,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
// Empties Account balance
@ -396,7 +396,7 @@ mod test {
&authority,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
let pubkey = nonce_account.account.borrow().owner;
@ -415,7 +415,7 @@ mod test {
let result = nonce_account.advance_nonce_account(
&recent_blockhashes,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(InstructionError::MissingRequiredSignature),);
})
@ -438,14 +438,14 @@ mod test {
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
let recent_blockhashes = vec![].into_iter().collect();
let result = keyed_account.advance_nonce_account(
&recent_blockhashes,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(NonceError::NoRecentBlockhashes.into()));
})
@ -468,13 +468,13 @@ mod test {
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
let result = keyed_account.advance_nonce_account(
&recent_blockhashes,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(NonceError::NotExpired.into()));
})
@ -494,7 +494,7 @@ mod test {
let result = keyed_account.advance_nonce_account(
&recent_blockhashes,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(NonceError::BadAccountState.into()));
})
@ -518,7 +518,7 @@ mod test {
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
let mut signers = HashSet::new();
@ -527,7 +527,7 @@ mod test {
let result = nonce_account.advance_nonce_account(
&recent_blockhashes,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Ok(()));
});
@ -552,13 +552,13 @@ mod test {
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
let result = nonce_account.advance_nonce_account(
&recent_blockhashes,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(InstructionError::MissingRequiredSignature),);
});
@ -592,7 +592,7 @@ mod test {
&recent_blockhashes,
&rent,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
let state = AccountUtilsState::<Versions>::state(nonce_keyed)
@ -631,7 +631,7 @@ mod test {
&recent_blockhashes,
&rent,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(InstructionError::MissingRequiredSignature),);
})
@ -661,7 +661,7 @@ mod test {
&recent_blockhashes,
&rent,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(InstructionError::InsufficientFunds));
})
@ -691,7 +691,7 @@ mod test {
&recent_blockhashes,
&rent,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
let state = AccountUtilsState::<Versions>::state(nonce_keyed)
@ -711,7 +711,7 @@ mod test {
&recent_blockhashes,
&rent,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
let state = AccountUtilsState::<Versions>::state(nonce_keyed)
@ -741,7 +741,7 @@ mod test {
&authority,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
let state = AccountUtilsState::<Versions>::state(nonce_keyed)
@ -765,7 +765,7 @@ mod test {
&recent_blockhashes,
&rent,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
let state = AccountUtilsState::<Versions>::state(nonce_keyed)
@ -791,7 +791,7 @@ mod test {
&recent_blockhashes,
&rent,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
let state = AccountUtilsState::<Versions>::state(nonce_keyed)
@ -819,7 +819,7 @@ mod test {
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
with_test_keyed_account(42, false, |to_keyed| {
@ -832,7 +832,7 @@ mod test {
&recent_blockhashes,
&rent,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(NonceError::NotExpired.into()));
})
@ -854,7 +854,7 @@ mod test {
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
with_test_keyed_account(42, false, |to_keyed| {
@ -868,7 +868,7 @@ mod test {
&recent_blockhashes,
&rent,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(InstructionError::InsufficientFunds));
})
@ -890,7 +890,7 @@ mod test {
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
with_test_keyed_account(42, false, |to_keyed| {
@ -904,7 +904,7 @@ mod test {
&recent_blockhashes,
&rent,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(InstructionError::InsufficientFunds));
})
@ -926,7 +926,7 @@ mod test {
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
with_test_keyed_account(55, false, |to_keyed| {
@ -940,7 +940,7 @@ mod test {
&recent_blockhashes,
&rent,
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(InstructionError::InsufficientFunds));
})
@ -967,7 +967,7 @@ mod test {
&authority,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
let data = nonce::state::Data {
authority,
@ -998,7 +998,7 @@ mod test {
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(NonceError::NoRecentBlockhashes.into()));
})
@ -1019,7 +1019,7 @@ mod test {
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
let recent_blockhashes = create_test_recent_blockhashes(0);
@ -1027,7 +1027,7 @@ mod test {
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(NonceError::BadAccountState.into()));
})
@ -1047,7 +1047,7 @@ mod test {
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(InstructionError::InsufficientFunds));
})
@ -1070,7 +1070,7 @@ mod test {
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
let authority = Pubkey::default();
@ -1082,7 +1082,7 @@ mod test {
let result = nonce_account.authorize_nonce_account(
&Pubkey::default(),
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Ok(()));
let state = AccountUtilsState::<Versions>::state(nonce_account)
@ -1105,7 +1105,7 @@ mod test {
let result = nonce_account.authorize_nonce_account(
&Pubkey::default(),
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(NonceError::BadAccountState.into()));
})
@ -1128,13 +1128,13 @@ mod test {
&authorized,
&recent_blockhashes,
&rent,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
let result = nonce_account.authorize_nonce_account(
&Pubkey::default(),
&signers,
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
);
assert_eq!(result, Err(InstructionError::MissingRequiredSignature));
})
@ -1155,7 +1155,7 @@ mod test {
&authorized,
&recent_blockhashes,
&Rent::free(),
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
assert!(verify_nonce_account(
@ -1190,7 +1190,7 @@ mod test {
&authorized,
&recent_blockhashes,
&Rent::free(),
&mut MockInvokeContext::default(),
&MockInvokeContext::new(vec![]),
)
.unwrap();
assert!(!verify_nonce_account(

View File

@ -1,7 +1,7 @@
use solana_sdk::{
account::AccountSharedData,
instruction::{CompiledInstruction, Instruction, InstructionError},
keyed_account::KeyedAccount,
keyed_account::{create_keyed_accounts_unified, KeyedAccount},
message::Message,
pubkey::Pubkey,
};
@ -15,19 +15,46 @@ use std::{cell::RefCell, fmt::Debug, rc::Rc, sync::Arc};
/// invoke_context: Invocation context
pub type LoaderEntrypoint = unsafe extern "C" fn(
program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
instruction_data: &[u8],
invoke_context: &dyn InvokeContext,
) -> Result<(), InstructionError>;
pub type ProcessInstructionWithContext =
fn(&Pubkey, &[KeyedAccount], &[u8], &mut dyn InvokeContext) -> Result<(), InstructionError>;
fn(&Pubkey, &[u8], &mut dyn InvokeContext) -> Result<(), InstructionError>;
pub struct InvokeContextStackFrame<'a> {
pub key: Pubkey,
pub keyed_accounts: Vec<KeyedAccount<'a>>,
pub keyed_accounts_range: std::ops::Range<usize>,
}
impl<'a> InvokeContextStackFrame<'a> {
pub fn new(key: Pubkey, keyed_accounts: Vec<KeyedAccount<'a>>) -> Self {
let keyed_accounts_range = std::ops::Range {
start: 0,
end: keyed_accounts.len(),
};
Self {
key,
keyed_accounts,
keyed_accounts_range,
}
}
}
/// Invocation context passed to loaders
pub trait InvokeContext {
/// Push a program ID on to the invocation stack
fn push(&mut self, key: &Pubkey) -> Result<(), InstructionError>;
/// Pop a program ID off of the invocation stack
/// Push a stack frame onto the invocation stack
///
/// Used in MessageProcessor::process_cross_program_instruction
fn push(
&mut self,
key: &Pubkey,
keyed_accounts: &[(bool, bool, &Pubkey, &RefCell<AccountSharedData>)],
) -> Result<(), InstructionError>;
/// Pop a stack frame from the invocation stack
///
/// Used in MessageProcessor::process_cross_program_instruction
fn pop(&mut self);
/// Current depth of the invocation stake
fn invoke_depth(&self) -> usize;
@ -41,6 +68,10 @@ pub trait InvokeContext {
) -> Result<(), InstructionError>;
/// Get the program ID of the currently executing program
fn get_caller(&self) -> Result<&Pubkey, InstructionError>;
/// Removes the first keyed account
fn remove_first_keyed_account(&mut self) -> Result<(), InstructionError>;
/// Get the list of keyed accounts
fn get_keyed_accounts(&self) -> Result<&[KeyedAccount], InstructionError>;
/// Get a list of built-in programs
fn get_programs(&self) -> &[(Pubkey, ProcessInstructionWithContext)];
/// Get this invocation's logger
@ -238,7 +269,6 @@ pub trait Executor: Debug + Send + Sync {
&self,
loader_id: &Pubkey,
program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
instruction_data: &[u8],
invoke_context: &mut dyn InvokeContext,
use_jit: bool,
@ -276,42 +306,58 @@ impl Logger for MockLogger {
}
}
pub struct MockInvokeContext {
pub key: Pubkey,
pub struct MockInvokeContext<'a> {
pub invoke_stack: Vec<InvokeContextStackFrame<'a>>,
pub logger: MockLogger,
pub bpf_compute_budget: BpfComputeBudget,
pub compute_meter: MockComputeMeter,
pub programs: Vec<(Pubkey, ProcessInstructionWithContext)>,
pub accounts: Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>,
pub invoke_depth: usize,
pub sysvars: Vec<(Pubkey, Option<Rc<Vec<u8>>>)>,
}
impl Default for MockInvokeContext {
fn default() -> Self {
MockInvokeContext {
key: Pubkey::default(),
impl<'a> MockInvokeContext<'a> {
pub fn new(keyed_accounts: Vec<KeyedAccount<'a>>) -> Self {
let bpf_compute_budget = BpfComputeBudget::default();
let mut invoke_context = MockInvokeContext {
invoke_stack: Vec::with_capacity(bpf_compute_budget.max_invoke_depth),
logger: MockLogger::default(),
bpf_compute_budget: BpfComputeBudget::default(),
bpf_compute_budget,
compute_meter: MockComputeMeter {
remaining: std::i64::MAX as u64,
},
programs: vec![],
accounts: vec![],
invoke_depth: 0,
sysvars: vec![],
}
};
invoke_context
.invoke_stack
.push(InvokeContextStackFrame::new(
Pubkey::default(),
keyed_accounts,
));
invoke_context
}
}
impl InvokeContext for MockInvokeContext {
fn push(&mut self, _key: &Pubkey) -> Result<(), InstructionError> {
self.invoke_depth = self.invoke_depth.saturating_add(1);
impl<'a> InvokeContext for MockInvokeContext<'a> {
fn push(
&mut self,
key: &Pubkey,
keyed_accounts: &[(bool, bool, &Pubkey, &RefCell<AccountSharedData>)],
) -> Result<(), InstructionError> {
fn transmute_lifetime<'a, 'b>(value: Vec<KeyedAccount<'a>>) -> Vec<KeyedAccount<'b>> {
unsafe { std::mem::transmute(value) }
}
self.invoke_stack.push(InvokeContextStackFrame::new(
*key,
transmute_lifetime(create_keyed_accounts_unified(keyed_accounts)),
));
Ok(())
}
fn pop(&mut self) {
self.invoke_depth = self.invoke_depth.saturating_sub(1);
self.invoke_stack.pop();
}
fn invoke_depth(&self) -> usize {
self.invoke_depth
self.invoke_stack.len()
}
fn verify_and_update(
&mut self,
@ -323,7 +369,25 @@ impl InvokeContext for MockInvokeContext {
Ok(())
}
fn get_caller(&self) -> Result<&Pubkey, InstructionError> {
Ok(&self.key)
self.invoke_stack
.last()
.map(|frame| &frame.key)
.ok_or(InstructionError::CallDepth)
}
fn remove_first_keyed_account(&mut self) -> Result<(), InstructionError> {
let stack_frame = &mut self
.invoke_stack
.last_mut()
.ok_or(InstructionError::CallDepth)?;
stack_frame.keyed_accounts_range.start =
stack_frame.keyed_accounts_range.start.saturating_add(1);
Ok(())
}
fn get_keyed_accounts(&self) -> Result<&[KeyedAccount], InstructionError> {
self.invoke_stack
.last()
.map(|frame| &frame.keyed_accounts[frame.keyed_accounts_range.clone()])
.ok_or(InstructionError::CallDepth)
}
fn get_programs(&self) -> &[(Pubkey, ProcessInstructionWithContext)] {
&self.programs