Refactor: Remove `Message` and `CompiledInstruction` from `InvokeContext` interfaces (#22102)
* Introduces InstructionAccount which is like AccountMeta but uses an index instead of a Pubkey * Renames InvokeContext::create_message() to InvokeContext::prepare_instruction() * Removes Message and CompiledInstruction from InvokeContext interfaces. * Resolves TODOs of sol_invoke_signed() in program-test. * Moves CompiledInstruction::visit_each_account() into invoke_context.rs
This commit is contained in:
parent
214b561a28
commit
2ab4f34c02
File diff suppressed because it is too large
Load Diff
|
@ -231,30 +231,19 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
|
||||||
account_infos: &[AccountInfo],
|
account_infos: &[AccountInfo],
|
||||||
signers_seeds: &[&[&[u8]]],
|
signers_seeds: &[&[&[u8]]],
|
||||||
) -> ProgramResult {
|
) -> ProgramResult {
|
||||||
//
|
|
||||||
// TODO: Merge the business logic below with the BPF invoke path in
|
|
||||||
// programs/bpf_loader/src/syscalls.rs
|
|
||||||
//
|
|
||||||
|
|
||||||
let invoke_context = get_invoke_context();
|
let invoke_context = get_invoke_context();
|
||||||
let log_collector = invoke_context.get_log_collector();
|
let log_collector = invoke_context.get_log_collector();
|
||||||
|
|
||||||
let caller = *invoke_context.get_caller().expect("get_caller");
|
let caller = *invoke_context.get_caller().expect("get_caller");
|
||||||
let message = Message::new(&[instruction.clone()], None);
|
let message = Message::new(&[instruction.clone()], None);
|
||||||
let program_id_index = message.instructions[0].program_id_index as usize;
|
|
||||||
let program_id = message.account_keys[program_id_index];
|
|
||||||
// TODO don't have the caller's keyed_accounts so can't validate writer or signer escalation or deescalation yet
|
|
||||||
let caller_privileges = message
|
|
||||||
.account_keys
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(i, _)| message.is_writable(i))
|
|
||||||
.collect::<Vec<bool>>();
|
|
||||||
|
|
||||||
stable_log::program_invoke(&log_collector, &program_id, invoke_context.invoke_depth());
|
stable_log::program_invoke(
|
||||||
|
&log_collector,
|
||||||
|
&instruction.program_id,
|
||||||
|
invoke_context.invoke_depth(),
|
||||||
|
);
|
||||||
|
|
||||||
// Convert AccountInfos into Accounts
|
// Convert AccountInfos into Accounts
|
||||||
let mut account_indices = Vec::with_capacity(message.account_keys.len());
|
|
||||||
let mut accounts = Vec::with_capacity(message.account_keys.len());
|
let mut accounts = Vec::with_capacity(message.account_keys.len());
|
||||||
for (i, account_key) in message.account_keys.iter().enumerate() {
|
for (i, account_key) in message.account_keys.iter().enumerate() {
|
||||||
let (account_index, account_info) = invoke_context
|
let (account_index, account_info) = invoke_context
|
||||||
|
@ -281,47 +270,26 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
account_indices.push(account_index);
|
|
||||||
accounts.push((account_index, account_info));
|
accounts.push((account_index, account_info));
|
||||||
}
|
}
|
||||||
let program_account_index = invoke_context.find_index_of_account(&program_id).unwrap();
|
|
||||||
let program_indices = vec![program_account_index];
|
|
||||||
|
|
||||||
// Check Signers
|
let signers = signers_seeds
|
||||||
for account_info in account_infos {
|
.iter()
|
||||||
for instruction_account in &instruction.accounts {
|
.map(|seeds| Pubkey::create_program_address(seeds, &caller).unwrap())
|
||||||
if *account_info.unsigned_key() == instruction_account.pubkey
|
.collect::<Vec<_>>();
|
||||||
&& instruction_account.is_signer
|
let (instruction_accounts, caller_write_privileges, program_indices) = invoke_context
|
||||||
&& !account_info.is_signer
|
.prepare_instruction(instruction, &signers)
|
||||||
{
|
.unwrap();
|
||||||
let mut program_signer = false;
|
|
||||||
for seeds in signers_seeds.iter() {
|
|
||||||
let signer = Pubkey::create_program_address(seeds, &caller).unwrap();
|
|
||||||
if instruction_account.pubkey == signer {
|
|
||||||
program_signer = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert!(
|
|
||||||
program_signer,
|
|
||||||
"Missing signer for {}",
|
|
||||||
instruction_account.pubkey
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(instruction_recorder) = &invoke_context.instruction_recorder {
|
if let Some(instruction_recorder) = &invoke_context.instruction_recorder {
|
||||||
instruction_recorder.record_instruction(instruction.clone());
|
instruction_recorder.record_instruction(instruction.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
invoke_context
|
invoke_context
|
||||||
.process_instruction(
|
.process_instruction(
|
||||||
&message,
|
&instruction.data,
|
||||||
&message.instructions[0],
|
&instruction_accounts,
|
||||||
|
Some(&caller_write_privileges),
|
||||||
&program_indices,
|
&program_indices,
|
||||||
&account_indices,
|
|
||||||
&caller_privileges,
|
|
||||||
)
|
)
|
||||||
.map_err(|err| ProgramError::try_from(err).unwrap_or_else(|err| panic!("{}", err)))?;
|
.map_err(|err| ProgramError::try_from(err).unwrap_or_else(|err| panic!("{}", err)))?;
|
||||||
|
|
||||||
|
@ -353,7 +321,7 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stable_log::program_success(&log_collector, &program_id);
|
stable_log::program_success(&log_collector, &instruction.program_id);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -450,20 +450,11 @@ mod tests {
|
||||||
];
|
];
|
||||||
let instruction_data = vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
|
let instruction_data = vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
|
||||||
let program_indices = [0];
|
let program_indices = [0];
|
||||||
let preparation = prepare_mock_invoke_context(
|
let preparation =
|
||||||
&program_indices,
|
prepare_mock_invoke_context(transaction_accounts.clone(), instruction_accounts);
|
||||||
&instruction_data,
|
let mut invoke_context = InvokeContext::new_mock(&preparation.transaction_accounts, &[]);
|
||||||
transaction_accounts.clone(),
|
|
||||||
instruction_accounts,
|
|
||||||
);
|
|
||||||
let mut invoke_context = InvokeContext::new_mock(&preparation.accounts, &[]);
|
|
||||||
invoke_context
|
invoke_context
|
||||||
.push(
|
.push(&preparation.instruction_accounts, &program_indices)
|
||||||
&preparation.message,
|
|
||||||
&preparation.message.instructions[0],
|
|
||||||
&program_indices,
|
|
||||||
&preparation.account_indices,
|
|
||||||
)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// check serialize_parameters_aligned
|
// check serialize_parameters_aligned
|
||||||
|
|
|
@ -5,7 +5,7 @@ use {
|
||||||
alloc::Alloc,
|
alloc::Alloc,
|
||||||
solana_program_runtime::{
|
solana_program_runtime::{
|
||||||
ic_logger_msg, ic_msg,
|
ic_logger_msg, ic_msg,
|
||||||
invoke_context::{ComputeMeter, InvokeContext},
|
invoke_context::{ComputeMeter, InstructionAccount, InvokeContext},
|
||||||
stable_log,
|
stable_log,
|
||||||
},
|
},
|
||||||
solana_rbpf::{
|
solana_rbpf::{
|
||||||
|
@ -31,9 +31,7 @@ use {
|
||||||
},
|
},
|
||||||
hash::{Hasher, HASH_BYTES},
|
hash::{Hasher, HASH_BYTES},
|
||||||
instruction::{AccountMeta, Instruction, InstructionError},
|
instruction::{AccountMeta, Instruction, InstructionError},
|
||||||
keccak,
|
keccak, native_loader,
|
||||||
message::Message,
|
|
||||||
native_loader,
|
|
||||||
precompiles::is_precompile,
|
precompiles::is_precompile,
|
||||||
program::MAX_RETURN_DATA,
|
program::MAX_RETURN_DATA,
|
||||||
program_stubs::is_nonoverlapping,
|
program_stubs::is_nonoverlapping,
|
||||||
|
@ -1666,7 +1664,7 @@ struct CallerAccount<'a> {
|
||||||
executable: bool,
|
executable: bool,
|
||||||
rent_epoch: u64,
|
rent_epoch: u64,
|
||||||
}
|
}
|
||||||
type TranslatedAccounts<'a> = (Vec<usize>, Vec<(usize, Option<CallerAccount<'a>>)>);
|
type TranslatedAccounts<'a> = Vec<(usize, Option<CallerAccount<'a>>)>;
|
||||||
|
|
||||||
/// Implemented by language specific data structure translators
|
/// Implemented by language specific data structure translators
|
||||||
trait SyscallInvokeSigned<'a, 'b> {
|
trait SyscallInvokeSigned<'a, 'b> {
|
||||||
|
@ -1681,7 +1679,8 @@ trait SyscallInvokeSigned<'a, 'b> {
|
||||||
fn translate_accounts<'c>(
|
fn translate_accounts<'c>(
|
||||||
&'c self,
|
&'c self,
|
||||||
loader_id: &Pubkey,
|
loader_id: &Pubkey,
|
||||||
message: &Message,
|
instruction_accounts: &[InstructionAccount],
|
||||||
|
program_indices: &[usize],
|
||||||
account_infos_addr: u64,
|
account_infos_addr: u64,
|
||||||
account_infos_len: u64,
|
account_infos_len: u64,
|
||||||
memory_mapping: &MemoryMapping,
|
memory_mapping: &MemoryMapping,
|
||||||
|
@ -1744,7 +1743,8 @@ impl<'a, 'b> SyscallInvokeSigned<'a, 'b> for SyscallInvokeSignedRust<'a, 'b> {
|
||||||
fn translate_accounts<'c>(
|
fn translate_accounts<'c>(
|
||||||
&'c self,
|
&'c self,
|
||||||
loader_id: &Pubkey,
|
loader_id: &Pubkey,
|
||||||
message: &Message,
|
instruction_accounts: &[InstructionAccount],
|
||||||
|
program_indices: &[usize],
|
||||||
account_infos_addr: u64,
|
account_infos_addr: u64,
|
||||||
account_infos_len: u64,
|
account_infos_len: u64,
|
||||||
memory_mapping: &MemoryMapping,
|
memory_mapping: &MemoryMapping,
|
||||||
|
@ -1839,7 +1839,8 @@ impl<'a, 'b> SyscallInvokeSigned<'a, 'b> for SyscallInvokeSignedRust<'a, 'b> {
|
||||||
};
|
};
|
||||||
|
|
||||||
get_translated_accounts(
|
get_translated_accounts(
|
||||||
message,
|
instruction_accounts,
|
||||||
|
program_indices,
|
||||||
&account_info_keys,
|
&account_info_keys,
|
||||||
account_infos,
|
account_infos,
|
||||||
invoke_context,
|
invoke_context,
|
||||||
|
@ -2033,7 +2034,8 @@ impl<'a, 'b> SyscallInvokeSigned<'a, 'b> for SyscallInvokeSignedC<'a, 'b> {
|
||||||
fn translate_accounts<'c>(
|
fn translate_accounts<'c>(
|
||||||
&'c self,
|
&'c self,
|
||||||
loader_id: &Pubkey,
|
loader_id: &Pubkey,
|
||||||
message: &Message,
|
instruction_accounts: &[InstructionAccount],
|
||||||
|
program_indices: &[usize],
|
||||||
account_infos_addr: u64,
|
account_infos_addr: u64,
|
||||||
account_infos_len: u64,
|
account_infos_len: u64,
|
||||||
memory_mapping: &MemoryMapping,
|
memory_mapping: &MemoryMapping,
|
||||||
|
@ -2106,7 +2108,8 @@ impl<'a, 'b> SyscallInvokeSigned<'a, 'b> for SyscallInvokeSignedC<'a, 'b> {
|
||||||
};
|
};
|
||||||
|
|
||||||
get_translated_accounts(
|
get_translated_accounts(
|
||||||
message,
|
instruction_accounts,
|
||||||
|
program_indices,
|
||||||
&account_info_keys,
|
&account_info_keys,
|
||||||
account_infos,
|
account_infos,
|
||||||
invoke_context,
|
invoke_context,
|
||||||
|
@ -2187,7 +2190,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallInvokeSignedC<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_translated_accounts<'a, T, F>(
|
fn get_translated_accounts<'a, T, F>(
|
||||||
message: &Message,
|
instruction_accounts: &[InstructionAccount],
|
||||||
|
program_indices: &[usize],
|
||||||
account_info_keys: &[&Pubkey],
|
account_info_keys: &[&Pubkey],
|
||||||
account_infos: &[T],
|
account_infos: &[T],
|
||||||
invoke_context: &mut InvokeContext,
|
invoke_context: &mut InvokeContext,
|
||||||
|
@ -2200,78 +2204,78 @@ where
|
||||||
let keyed_accounts = invoke_context
|
let keyed_accounts = invoke_context
|
||||||
.get_instruction_keyed_accounts()
|
.get_instruction_keyed_accounts()
|
||||||
.map_err(SyscallError::InstructionError)?;
|
.map_err(SyscallError::InstructionError)?;
|
||||||
let mut account_indices = Vec::with_capacity(message.account_keys.len());
|
let mut accounts = Vec::with_capacity(instruction_accounts.len().saturating_add(1));
|
||||||
let mut accounts = Vec::with_capacity(message.account_keys.len());
|
|
||||||
for (i, account_key) in message.account_keys.iter().enumerate() {
|
|
||||||
if let Some(account_index) = invoke_context.find_index_of_account(account_key) {
|
|
||||||
let account = invoke_context.get_account_at_index(account_index);
|
|
||||||
if i == message.instructions[0].program_id_index as usize
|
|
||||||
|| account.borrow().executable()
|
|
||||||
{
|
|
||||||
// Use the known account
|
|
||||||
account_indices.push(account_index);
|
|
||||||
accounts.push((account_index, None));
|
|
||||||
continue;
|
|
||||||
} else if let Some(caller_account_index) =
|
|
||||||
account_info_keys.iter().position(|key| *key == account_key)
|
|
||||||
{
|
|
||||||
let mut caller_account =
|
|
||||||
do_translate(&account_infos[caller_account_index], invoke_context)?;
|
|
||||||
{
|
|
||||||
let mut account = account.borrow_mut();
|
|
||||||
account.copy_into_owner_from_slice(caller_account.owner.as_ref());
|
|
||||||
account.set_data_from_slice(caller_account.data);
|
|
||||||
account.set_lamports(*caller_account.lamports);
|
|
||||||
account.set_executable(caller_account.executable);
|
|
||||||
account.set_rent_epoch(caller_account.rent_epoch);
|
|
||||||
}
|
|
||||||
let caller_account = if message.is_writable(i) {
|
|
||||||
if let Some(orig_data_len_index) = keyed_accounts
|
|
||||||
.iter()
|
|
||||||
.position(|keyed_account| keyed_account.unsigned_key() == account_key)
|
|
||||||
.map(|index| {
|
|
||||||
// index starts at first instruction account
|
|
||||||
index - keyed_accounts.len().saturating_sub(orig_data_lens.len())
|
|
||||||
})
|
|
||||||
.and_then(|index| {
|
|
||||||
if index >= orig_data_lens.len() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(index)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
{
|
|
||||||
caller_account.original_data_len = orig_data_lens[orig_data_len_index];
|
|
||||||
} else {
|
|
||||||
ic_msg!(
|
|
||||||
invoke_context,
|
|
||||||
"Internal error: index mismatch for account {}",
|
|
||||||
account_key
|
|
||||||
);
|
|
||||||
return Err(SyscallError::InstructionError(
|
|
||||||
InstructionError::MissingAccount,
|
|
||||||
)
|
|
||||||
.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(caller_account)
|
let program_account_index = program_indices
|
||||||
} else {
|
.last()
|
||||||
None
|
.ok_or(SyscallError::InstructionError(
|
||||||
};
|
InstructionError::MissingAccount,
|
||||||
account_indices.push(account_index);
|
))?;
|
||||||
accounts.push((account_index, caller_account));
|
accounts.push((*program_account_index, None));
|
||||||
continue;
|
|
||||||
|
for instruction_account in instruction_accounts.iter() {
|
||||||
|
let account = invoke_context.get_account_at_index(instruction_account.index);
|
||||||
|
let account_key = invoke_context.get_account_key_at_index(instruction_account.index);
|
||||||
|
if account.borrow().executable() {
|
||||||
|
// Use the known account
|
||||||
|
accounts.push((instruction_account.index, None));
|
||||||
|
} else if let Some(caller_account_index) =
|
||||||
|
account_info_keys.iter().position(|key| *key == account_key)
|
||||||
|
{
|
||||||
|
let mut caller_account =
|
||||||
|
do_translate(&account_infos[caller_account_index], invoke_context)?;
|
||||||
|
{
|
||||||
|
let mut account = account.borrow_mut();
|
||||||
|
account.copy_into_owner_from_slice(caller_account.owner.as_ref());
|
||||||
|
account.set_data_from_slice(caller_account.data);
|
||||||
|
account.set_lamports(*caller_account.lamports);
|
||||||
|
account.set_executable(caller_account.executable);
|
||||||
|
account.set_rent_epoch(caller_account.rent_epoch);
|
||||||
}
|
}
|
||||||
|
let caller_account = if instruction_account.is_writable {
|
||||||
|
if let Some(orig_data_len_index) = keyed_accounts
|
||||||
|
.iter()
|
||||||
|
.position(|keyed_account| keyed_account.unsigned_key() == account_key)
|
||||||
|
.map(|index| {
|
||||||
|
// index starts at first instruction account
|
||||||
|
index - keyed_accounts.len().saturating_sub(orig_data_lens.len())
|
||||||
|
})
|
||||||
|
.and_then(|index| {
|
||||||
|
if index >= orig_data_lens.len() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(index)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
{
|
||||||
|
caller_account.original_data_len = orig_data_lens[orig_data_len_index];
|
||||||
|
} else {
|
||||||
|
ic_msg!(
|
||||||
|
invoke_context,
|
||||||
|
"Internal error: index mismatch for account {}",
|
||||||
|
account_key
|
||||||
|
);
|
||||||
|
return Err(
|
||||||
|
SyscallError::InstructionError(InstructionError::MissingAccount).into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(caller_account)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
accounts.push((instruction_account.index, caller_account));
|
||||||
|
} else {
|
||||||
|
ic_msg!(
|
||||||
|
invoke_context,
|
||||||
|
"Instruction references an unknown account {}",
|
||||||
|
account_key
|
||||||
|
);
|
||||||
|
return Err(SyscallError::InstructionError(InstructionError::MissingAccount).into());
|
||||||
}
|
}
|
||||||
ic_msg!(
|
|
||||||
invoke_context,
|
|
||||||
"Instruction references an unknown account {}",
|
|
||||||
account_key
|
|
||||||
);
|
|
||||||
return Err(SyscallError::InstructionError(InstructionError::MissingAccount).into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((account_indices, accounts))
|
Ok(accounts)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_instruction_size(
|
fn check_instruction_size(
|
||||||
|
@ -2364,13 +2368,14 @@ fn call<'a, 'b: 'a>(
|
||||||
signers_seeds_len,
|
signers_seeds_len,
|
||||||
memory_mapping,
|
memory_mapping,
|
||||||
)?;
|
)?;
|
||||||
let (message, caller_write_privileges, program_indices) = invoke_context
|
let (instruction_accounts, caller_write_privileges, program_indices) = invoke_context
|
||||||
.create_message(&instruction, &signers)
|
.prepare_instruction(&instruction, &signers)
|
||||||
.map_err(SyscallError::InstructionError)?;
|
.map_err(SyscallError::InstructionError)?;
|
||||||
check_authorized_program(&instruction.program_id, &instruction.data, *invoke_context)?;
|
check_authorized_program(&instruction.program_id, &instruction.data, *invoke_context)?;
|
||||||
let (account_indices, mut accounts) = syscall.translate_accounts(
|
let mut accounts = syscall.translate_accounts(
|
||||||
&loader_id,
|
&loader_id,
|
||||||
&message,
|
&instruction_accounts,
|
||||||
|
&program_indices,
|
||||||
account_infos_addr,
|
account_infos_addr,
|
||||||
account_infos_len,
|
account_infos_len,
|
||||||
memory_mapping,
|
memory_mapping,
|
||||||
|
@ -2379,17 +2384,16 @@ fn call<'a, 'b: 'a>(
|
||||||
|
|
||||||
// Record the instruction
|
// Record the instruction
|
||||||
if let Some(instruction_recorder) = &invoke_context.instruction_recorder {
|
if let Some(instruction_recorder) = &invoke_context.instruction_recorder {
|
||||||
instruction_recorder.record_instruction(instruction);
|
instruction_recorder.record_instruction(instruction.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process instruction
|
// Process instruction
|
||||||
invoke_context
|
invoke_context
|
||||||
.process_instruction(
|
.process_instruction(
|
||||||
&message,
|
&instruction.data,
|
||||||
&message.instructions[0],
|
&instruction_accounts,
|
||||||
|
Some(&caller_write_privileges),
|
||||||
&program_indices,
|
&program_indices,
|
||||||
&account_indices,
|
|
||||||
&caller_write_privileges,
|
|
||||||
)
|
)
|
||||||
.map_err(SyscallError::InstructionError)?;
|
.map_err(SyscallError::InstructionError)?;
|
||||||
|
|
||||||
|
@ -2982,14 +2986,8 @@ mod tests {
|
||||||
let program_id = Pubkey::new_unique();
|
let program_id = Pubkey::new_unique();
|
||||||
let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id()));
|
let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id()));
|
||||||
let accounts = [(program_id, program_account)];
|
let accounts = [(program_id, program_account)];
|
||||||
let message = Message::new(
|
|
||||||
&[Instruction::new_with_bytes(program_id, &[], vec![])],
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||||
invoke_context
|
invoke_context.push(&[], &[0]).unwrap();
|
||||||
.push(&message, &message.instructions[0], &[0], &[])
|
|
||||||
.unwrap();
|
|
||||||
let mut syscall_panic = SyscallPanic {
|
let mut syscall_panic = SyscallPanic {
|
||||||
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
||||||
};
|
};
|
||||||
|
@ -3059,14 +3057,8 @@ mod tests {
|
||||||
let program_id = Pubkey::new_unique();
|
let program_id = Pubkey::new_unique();
|
||||||
let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id()));
|
let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id()));
|
||||||
let accounts = [(program_id, program_account)];
|
let accounts = [(program_id, program_account)];
|
||||||
let message = Message::new(
|
|
||||||
&[Instruction::new_with_bytes(program_id, &[], vec![])],
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||||
invoke_context
|
invoke_context.push(&[], &[0]).unwrap();
|
||||||
.push(&message, &message.instructions[0], &[0], &[])
|
|
||||||
.unwrap();
|
|
||||||
let mut syscall_sol_log = SyscallLog {
|
let mut syscall_sol_log = SyscallLog {
|
||||||
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
||||||
};
|
};
|
||||||
|
@ -3163,14 +3155,8 @@ mod tests {
|
||||||
let program_id = Pubkey::new_unique();
|
let program_id = Pubkey::new_unique();
|
||||||
let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id()));
|
let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id()));
|
||||||
let accounts = [(program_id, program_account)];
|
let accounts = [(program_id, program_account)];
|
||||||
let message = Message::new(
|
|
||||||
&[Instruction::new_with_bytes(program_id, &[], vec![])],
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||||
invoke_context
|
invoke_context.push(&[], &[0]).unwrap();
|
||||||
.push(&message, &message.instructions[0], &[0], &[])
|
|
||||||
.unwrap();
|
|
||||||
let cost = invoke_context.get_compute_budget().log_64_units;
|
let cost = invoke_context.get_compute_budget().log_64_units;
|
||||||
let mut syscall_sol_log_u64 = SyscallLogU64 {
|
let mut syscall_sol_log_u64 = SyscallLogU64 {
|
||||||
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
||||||
|
@ -3205,14 +3191,8 @@ mod tests {
|
||||||
let program_id = Pubkey::new_unique();
|
let program_id = Pubkey::new_unique();
|
||||||
let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id()));
|
let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id()));
|
||||||
let accounts = [(program_id, program_account)];
|
let accounts = [(program_id, program_account)];
|
||||||
let message = Message::new(
|
|
||||||
&[Instruction::new_with_bytes(program_id, &[], vec![])],
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||||
invoke_context
|
invoke_context.push(&[], &[0]).unwrap();
|
||||||
.push(&message, &message.instructions[0], &[0], &[])
|
|
||||||
.unwrap();
|
|
||||||
let cost = invoke_context.get_compute_budget().log_pubkey_units;
|
let cost = invoke_context.get_compute_budget().log_pubkey_units;
|
||||||
let mut syscall_sol_pubkey = SyscallLogPubkey {
|
let mut syscall_sol_pubkey = SyscallLogPubkey {
|
||||||
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
||||||
|
@ -3418,10 +3398,8 @@ mod tests {
|
||||||
let program_account =
|
let program_account =
|
||||||
RefCell::new(AccountSharedData::new(0, 0, &bpf_loader_deprecated::id()));
|
RefCell::new(AccountSharedData::new(0, 0, &bpf_loader_deprecated::id()));
|
||||||
let accounts = [(program_id, program_account)];
|
let accounts = [(program_id, program_account)];
|
||||||
let message = Message::new(
|
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||||
&[Instruction::new_with_bytes(program_id, &[], vec![])],
|
invoke_context.push(&[], &[0]).unwrap();
|
||||||
None,
|
|
||||||
);
|
|
||||||
|
|
||||||
let bytes1 = "Gaggablaghblagh!";
|
let bytes1 = "Gaggablaghblagh!";
|
||||||
let bytes2 = "flurbos";
|
let bytes2 = "flurbos";
|
||||||
|
@ -3475,7 +3453,6 @@ mod tests {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
|
||||||
invoke_context
|
invoke_context
|
||||||
.get_compute_meter()
|
.get_compute_meter()
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
|
@ -3485,9 +3462,6 @@ mod tests {
|
||||||
* invoke_context.get_compute_budget().sha256_byte_cost)
|
* invoke_context.get_compute_budget().sha256_byte_cost)
|
||||||
* 4,
|
* 4,
|
||||||
);
|
);
|
||||||
invoke_context
|
|
||||||
.push(&message, &message.instructions[0], &[0], &[])
|
|
||||||
.unwrap();
|
|
||||||
let mut syscall = SyscallSha256 {
|
let mut syscall = SyscallSha256 {
|
||||||
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
||||||
};
|
};
|
||||||
|
@ -3547,10 +3521,6 @@ mod tests {
|
||||||
let program_id = Pubkey::new_unique();
|
let program_id = Pubkey::new_unique();
|
||||||
let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id()));
|
let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id()));
|
||||||
let accounts = [(program_id, program_account)];
|
let accounts = [(program_id, program_account)];
|
||||||
let message = Message::new(
|
|
||||||
&[Instruction::new_with_bytes(program_id, &[], vec![])],
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Test clock sysvar
|
// Test clock sysvar
|
||||||
{
|
{
|
||||||
|
@ -3584,9 +3554,7 @@ mod tests {
|
||||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||||
let sysvars = [(sysvar::clock::id(), data)];
|
let sysvars = [(sysvar::clock::id(), data)];
|
||||||
invoke_context.sysvars = &sysvars;
|
invoke_context.sysvars = &sysvars;
|
||||||
invoke_context
|
invoke_context.push(&[], &[0]).unwrap();
|
||||||
.push(&message, &message.instructions[0], &[0], &[])
|
|
||||||
.unwrap();
|
|
||||||
let mut syscall = SyscallGetClockSysvar {
|
let mut syscall = SyscallGetClockSysvar {
|
||||||
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
||||||
};
|
};
|
||||||
|
@ -3629,9 +3597,7 @@ mod tests {
|
||||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||||
let sysvars = [(sysvar::epoch_schedule::id(), data)];
|
let sysvars = [(sysvar::epoch_schedule::id(), data)];
|
||||||
invoke_context.sysvars = &sysvars;
|
invoke_context.sysvars = &sysvars;
|
||||||
invoke_context
|
invoke_context.push(&[], &[0]).unwrap();
|
||||||
.push(&message, &message.instructions[0], &[0], &[])
|
|
||||||
.unwrap();
|
|
||||||
let mut syscall = SyscallGetEpochScheduleSysvar {
|
let mut syscall = SyscallGetEpochScheduleSysvar {
|
||||||
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
||||||
};
|
};
|
||||||
|
@ -3681,9 +3647,7 @@ mod tests {
|
||||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||||
let sysvars = [(sysvar::fees::id(), data)];
|
let sysvars = [(sysvar::fees::id(), data)];
|
||||||
invoke_context.sysvars = &sysvars;
|
invoke_context.sysvars = &sysvars;
|
||||||
invoke_context
|
invoke_context.push(&[], &[0]).unwrap();
|
||||||
.push(&message, &message.instructions[0], &[0], &[])
|
|
||||||
.unwrap();
|
|
||||||
let mut syscall = SyscallGetFeesSysvar {
|
let mut syscall = SyscallGetFeesSysvar {
|
||||||
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
||||||
};
|
};
|
||||||
|
@ -3724,9 +3688,7 @@ mod tests {
|
||||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||||
let sysvars = [(sysvar::rent::id(), data)];
|
let sysvars = [(sysvar::rent::id(), data)];
|
||||||
invoke_context.sysvars = &sysvars;
|
invoke_context.sysvars = &sysvars;
|
||||||
invoke_context
|
invoke_context.push(&[], &[0]).unwrap();
|
||||||
.push(&message, &message.instructions[0], &[0], &[])
|
|
||||||
.unwrap();
|
|
||||||
let mut syscall = SyscallGetRentSysvar {
|
let mut syscall = SyscallGetRentSysvar {
|
||||||
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
||||||
};
|
};
|
||||||
|
@ -3857,14 +3819,8 @@ mod tests {
|
||||||
let program_id = Pubkey::new_unique();
|
let program_id = Pubkey::new_unique();
|
||||||
let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id()));
|
let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id()));
|
||||||
let accounts = [(program_id, program_account)];
|
let accounts = [(program_id, program_account)];
|
||||||
let message = Message::new(
|
|
||||||
&[Instruction::new_with_bytes(program_id, &[], vec![])],
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||||
invoke_context
|
invoke_context.push(&[], &[0]).unwrap();
|
||||||
.push(&message, &message.instructions[0], &[0], &[])
|
|
||||||
.unwrap();
|
|
||||||
let address = bpf_loader_upgradeable::id();
|
let address = bpf_loader_upgradeable::id();
|
||||||
|
|
||||||
let exceeded_seed = &[127; MAX_SEED_LEN + 1];
|
let exceeded_seed = &[127; MAX_SEED_LEN + 1];
|
||||||
|
@ -3973,14 +3929,8 @@ mod tests {
|
||||||
let program_id = Pubkey::new_unique();
|
let program_id = Pubkey::new_unique();
|
||||||
let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id()));
|
let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id()));
|
||||||
let accounts = [(program_id, program_account)];
|
let accounts = [(program_id, program_account)];
|
||||||
let message = Message::new(
|
|
||||||
&[Instruction::new_with_bytes(program_id, &[], vec![])],
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||||
invoke_context
|
invoke_context.push(&[], &[0]).unwrap();
|
||||||
.push(&message, &message.instructions[0], &[0], &[])
|
|
||||||
.unwrap();
|
|
||||||
let cost = invoke_context
|
let cost = invoke_context
|
||||||
.get_compute_budget()
|
.get_compute_budget()
|
||||||
.create_program_address_units;
|
.create_program_address_units;
|
||||||
|
|
|
@ -208,21 +208,11 @@ native machine code before execting it in the virtual machine.",
|
||||||
input.instruction_data
|
input.instruction_data
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let preparation = prepare_mock_invoke_context(transaction_accounts, instruction_accounts);
|
||||||
let program_indices = [0, 1];
|
let program_indices = [0, 1];
|
||||||
let preparation = prepare_mock_invoke_context(
|
let mut invoke_context = InvokeContext::new_mock(&preparation.transaction_accounts, &[]);
|
||||||
&program_indices,
|
|
||||||
&[],
|
|
||||||
transaction_accounts,
|
|
||||||
instruction_accounts,
|
|
||||||
);
|
|
||||||
let mut invoke_context = InvokeContext::new_mock(&preparation.accounts, &[]);
|
|
||||||
invoke_context
|
invoke_context
|
||||||
.push(
|
.push(&preparation.instruction_accounts, &program_indices)
|
||||||
&preparation.message,
|
|
||||||
&preparation.message.instructions[0],
|
|
||||||
&program_indices,
|
|
||||||
&preparation.account_indices,
|
|
||||||
)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let keyed_accounts = invoke_context.get_keyed_accounts().unwrap();
|
let keyed_accounts = invoke_context.get_keyed_accounts().unwrap();
|
||||||
let (mut parameter_bytes, account_lengths) = serialize_parameters(
|
let (mut parameter_bytes, account_lengths) = serialize_parameters(
|
||||||
|
|
|
@ -3,7 +3,9 @@ use {
|
||||||
solana_measure::measure::Measure,
|
solana_measure::measure::Measure,
|
||||||
solana_program_runtime::{
|
solana_program_runtime::{
|
||||||
instruction_recorder::InstructionRecorder,
|
instruction_recorder::InstructionRecorder,
|
||||||
invoke_context::{BuiltinProgram, Executors, InvokeContext, TransactionAccountRefCell},
|
invoke_context::{
|
||||||
|
BuiltinProgram, Executors, InstructionAccount, InvokeContext, TransactionAccountRefCell,
|
||||||
|
},
|
||||||
log_collector::LogCollector,
|
log_collector::LogCollector,
|
||||||
timings::ExecuteDetailsTimings,
|
timings::ExecuteDetailsTimings,
|
||||||
},
|
},
|
||||||
|
@ -111,9 +113,26 @@ impl MessageProcessor {
|
||||||
invoke_context.instruction_recorder =
|
invoke_context.instruction_recorder =
|
||||||
Some(&instruction_recorders[instruction_index]);
|
Some(&instruction_recorders[instruction_index]);
|
||||||
}
|
}
|
||||||
|
let instruction_accounts = instruction
|
||||||
|
.accounts
|
||||||
|
.iter()
|
||||||
|
.map(|account_index| {
|
||||||
|
let account_index = *account_index as usize;
|
||||||
|
InstructionAccount {
|
||||||
|
index: account_index,
|
||||||
|
is_signer: message.is_signer(account_index),
|
||||||
|
is_writable: message.is_writable(account_index),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
let mut time = Measure::start("execute_instruction");
|
let mut time = Measure::start("execute_instruction");
|
||||||
let compute_meter_consumption = invoke_context
|
let compute_meter_consumption = invoke_context
|
||||||
.process_instruction(message, instruction, program_indices, &[], &[])
|
.process_instruction(
|
||||||
|
&instruction.data,
|
||||||
|
&instruction_accounts,
|
||||||
|
None,
|
||||||
|
program_indices,
|
||||||
|
)
|
||||||
.map_err(|err| TransactionError::InstructionError(instruction_index as u8, err))?;
|
.map_err(|err| TransactionError::InstructionError(instruction_index as u8, err))?;
|
||||||
time.stop();
|
time.stop();
|
||||||
timings.accumulate_program(
|
timings.accumulate_program(
|
||||||
|
|
|
@ -639,52 +639,4 @@ impl CompiledInstruction {
|
||||||
pub fn program_id<'a>(&self, program_ids: &'a [Pubkey]) -> &'a Pubkey {
|
pub fn program_id<'a>(&self, program_ids: &'a [Pubkey]) -> &'a Pubkey {
|
||||||
&program_ids[self.program_id_index as usize]
|
&program_ids[self.program_id_index as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Visit each unique instruction account index once
|
|
||||||
pub fn visit_each_account(
|
|
||||||
&self,
|
|
||||||
work: &mut dyn FnMut(usize, usize) -> Result<(), InstructionError>,
|
|
||||||
) -> Result<(), InstructionError> {
|
|
||||||
let mut unique_index = 0;
|
|
||||||
'root: for (i, account_index) in self.accounts.iter().enumerate() {
|
|
||||||
// Note: This is an O(n^2) algorithm,
|
|
||||||
// but performed on a very small slice and requires no heap allocations
|
|
||||||
for account_index_before in self.accounts[..i].iter() {
|
|
||||||
if account_index_before == account_index {
|
|
||||||
continue 'root; // skip dups
|
|
||||||
}
|
|
||||||
}
|
|
||||||
work(unique_index, *account_index as usize)?;
|
|
||||||
unique_index += 1;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_visit_each_account() {
|
|
||||||
let do_work = |accounts: &[u8]| -> (usize, usize) {
|
|
||||||
let mut unique_total = 0;
|
|
||||||
let mut account_total = 0;
|
|
||||||
let mut work = |unique_index: usize, account_index: usize| {
|
|
||||||
unique_total += unique_index;
|
|
||||||
account_total += account_index;
|
|
||||||
Ok(())
|
|
||||||
};
|
|
||||||
let instruction = CompiledInstruction::new(0, &[0], accounts.to_vec());
|
|
||||||
instruction.visit_each_account(&mut work).unwrap();
|
|
||||||
|
|
||||||
(unique_total, account_total)
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!((6, 6), do_work(&[0, 1, 2, 3]));
|
|
||||||
assert_eq!((6, 6), do_work(&[0, 1, 1, 2, 3]));
|
|
||||||
assert_eq!((6, 6), do_work(&[0, 1, 2, 3, 3]));
|
|
||||||
assert_eq!((6, 6), do_work(&[0, 0, 1, 1, 2, 2, 3, 3]));
|
|
||||||
assert_eq!((0, 2), do_work(&[2, 2]));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue