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:
committed by
GitHub
parent
015bc034a5
commit
9dfcb921cf
@ -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> {
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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(¬_owned_key, ¬_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> {
|
||||
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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(()),
|
||||
|
Reference in New Issue
Block a user