2020-06-06 10:18:28 -07:00
|
|
|
use crate::{
|
2021-05-19 09:50:34 -07:00
|
|
|
accounts::Accounts, ancestors::Ancestors, instruction_recorder::InstructionRecorder,
|
2021-08-26 17:30:36 -07:00
|
|
|
log_collector::LogCollector, rent_collector::RentCollector,
|
2020-06-06 10:18:28 -07:00
|
|
|
};
|
|
|
|
use log::*;
|
2019-05-30 21:31:35 -07:00
|
|
|
use serde::{Deserialize, Serialize};
|
2021-06-04 07:04:31 -07:00
|
|
|
use solana_measure::measure::Measure;
|
2021-08-26 17:30:36 -07:00
|
|
|
use solana_program_runtime::{ExecuteDetailsTimings, Executors, InstructionProcessor, PreAccount};
|
2020-01-28 17:03:20 -08:00
|
|
|
use solana_sdk::{
|
2021-03-10 13:28:03 -08:00
|
|
|
account::{AccountSharedData, ReadableAccount, WritableAccount},
|
2021-07-22 10:18:51 -07:00
|
|
|
compute_budget::ComputeBudget,
|
2021-07-08 10:43:34 -07:00
|
|
|
feature_set::{
|
2021-09-17 09:46:49 -07:00
|
|
|
demote_program_write_locks, neon_evm_compute_budget, tx_wide_compute_cap, FeatureSet,
|
2021-07-08 10:43:34 -07:00
|
|
|
},
|
2021-07-29 01:50:20 -07:00
|
|
|
fee_calculator::FeeCalculator,
|
|
|
|
hash::Hash,
|
2021-08-26 17:30:36 -07:00
|
|
|
ic_logger_msg,
|
2020-09-24 07:36:22 -07:00
|
|
|
instruction::{CompiledInstruction, Instruction, InstructionError},
|
2021-08-26 17:30:36 -07:00
|
|
|
keyed_account::{create_keyed_accounts_unified, KeyedAccount},
|
2020-01-28 17:03:20 -08:00
|
|
|
message::Message,
|
2020-10-28 20:21:50 -07:00
|
|
|
process_instruction::{
|
2021-07-22 10:18:51 -07:00
|
|
|
ComputeMeter, Executor, InvokeContext, InvokeContextStackFrame, Logger,
|
2020-10-28 13:16:13 -07:00
|
|
|
ProcessInstructionWithContext,
|
2020-10-28 20:21:50 -07:00
|
|
|
},
|
2020-01-28 17:03:20 -08:00
|
|
|
pubkey::Pubkey,
|
2020-04-28 14:33:56 -07:00
|
|
|
rent::Rent,
|
2021-04-06 00:08:03 -07:00
|
|
|
sysvar::instructions,
|
2020-01-28 17:03:20 -08:00
|
|
|
transaction::TransactionError,
|
|
|
|
};
|
2021-08-26 17:30:36 -07:00
|
|
|
use std::{cell::RefCell, rc::Rc, sync::Arc};
|
2019-02-18 22:26:22 -08:00
|
|
|
|
2020-08-21 15:31:19 -07:00
|
|
|
pub struct ThisComputeMeter {
|
|
|
|
remaining: u64,
|
|
|
|
}
|
|
|
|
impl ComputeMeter for ThisComputeMeter {
|
|
|
|
fn consume(&mut self, amount: u64) -> Result<(), InstructionError> {
|
2020-09-25 11:08:10 -07:00
|
|
|
let exceeded = self.remaining < amount;
|
2020-08-21 15:31:19 -07:00
|
|
|
self.remaining = self.remaining.saturating_sub(amount);
|
2020-09-25 11:08:10 -07:00
|
|
|
if exceeded {
|
2020-08-21 15:31:19 -07:00
|
|
|
return Err(InstructionError::ComputationalBudgetExceeded);
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
fn get_remaining(&self) -> u64 {
|
|
|
|
self.remaining
|
|
|
|
}
|
|
|
|
}
|
2020-10-29 09:57:14 -07:00
|
|
|
pub struct ThisInvokeContext<'a> {
|
2021-04-19 09:48:48 -07:00
|
|
|
invoke_stack: Vec<InvokeContextStackFrame<'a>>,
|
2020-06-13 13:20:08 -07:00
|
|
|
rent: Rent,
|
|
|
|
pre_accounts: Vec<PreAccount>,
|
2021-07-05 04:49:37 -07:00
|
|
|
accounts: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
|
2020-10-29 09:57:14 -07:00
|
|
|
programs: &'a [(Pubkey, ProcessInstructionWithContext)],
|
2020-06-13 13:20:08 -07:00
|
|
|
logger: Rc<RefCell<dyn Logger>>,
|
2021-07-22 10:18:51 -07:00
|
|
|
compute_budget: ComputeBudget,
|
|
|
|
#[allow(deprecated)]
|
|
|
|
bpf_compute_budget: solana_sdk::process_instruction::BpfComputeBudget,
|
2020-08-21 15:31:19 -07:00
|
|
|
compute_meter: Rc<RefCell<dyn ComputeMeter>>,
|
2020-09-14 17:42:37 -07:00
|
|
|
executors: Rc<RefCell<Executors>>,
|
2020-09-24 07:36:22 -07:00
|
|
|
instruction_recorder: Option<InstructionRecorder>,
|
2020-09-29 14:36:30 -07:00
|
|
|
feature_set: Arc<FeatureSet>,
|
2021-03-03 15:07:45 -08:00
|
|
|
pub timings: ExecuteDetailsTimings,
|
2021-04-12 16:04:57 -07:00
|
|
|
account_db: Arc<Accounts>,
|
|
|
|
ancestors: &'a Ancestors,
|
2021-05-20 14:00:50 -07:00
|
|
|
#[allow(clippy::type_complexity)]
|
|
|
|
sysvars: RefCell<Vec<(Pubkey, Option<Rc<Vec<u8>>>)>>,
|
2021-07-29 01:50:20 -07:00
|
|
|
blockhash: &'a Hash,
|
|
|
|
fee_calculator: &'a FeeCalculator,
|
2021-09-01 02:14:01 -07:00
|
|
|
// return data and program_id that set it
|
|
|
|
return_data: Option<(Pubkey, Vec<u8>)>,
|
2020-04-28 14:33:56 -07:00
|
|
|
}
|
2020-10-29 09:57:14 -07:00
|
|
|
impl<'a> ThisInvokeContext<'a> {
|
2020-12-22 09:26:55 -08:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2020-06-03 12:48:19 -07:00
|
|
|
pub fn new(
|
|
|
|
program_id: &Pubkey,
|
|
|
|
rent: Rent,
|
2021-04-19 09:48:48 -07:00
|
|
|
message: &'a Message,
|
|
|
|
instruction: &'a CompiledInstruction,
|
2021-09-09 23:36:21 -07:00
|
|
|
program_indices: &[usize],
|
2021-07-05 04:49:37 -07:00
|
|
|
accounts: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
|
2020-10-29 09:57:14 -07:00
|
|
|
programs: &'a [(Pubkey, ProcessInstructionWithContext)],
|
2020-06-13 13:20:08 -07:00
|
|
|
log_collector: Option<Rc<LogCollector>>,
|
2021-07-22 10:18:51 -07:00
|
|
|
compute_budget: ComputeBudget,
|
2021-07-16 00:31:22 -07:00
|
|
|
compute_meter: Rc<RefCell<dyn ComputeMeter>>,
|
2020-09-14 17:42:37 -07:00
|
|
|
executors: Rc<RefCell<Executors>>,
|
2020-09-24 07:36:22 -07:00
|
|
|
instruction_recorder: Option<InstructionRecorder>,
|
2020-09-29 14:36:30 -07:00
|
|
|
feature_set: Arc<FeatureSet>,
|
2021-04-12 16:04:57 -07:00
|
|
|
account_db: Arc<Accounts>,
|
|
|
|
ancestors: &'a Ancestors,
|
2021-07-29 01:50:20 -07:00
|
|
|
blockhash: &'a Hash,
|
|
|
|
fee_calculator: &'a FeeCalculator,
|
2021-09-09 23:36:21 -07:00
|
|
|
) -> Result<Self, InstructionError> {
|
2021-04-19 09:48:48 -07:00
|
|
|
let pre_accounts = MessageProcessor::create_pre_accounts(message, instruction, accounts);
|
2021-07-16 00:31:22 -07:00
|
|
|
let compute_meter = if feature_set.is_active(&tx_wide_compute_cap::id()) {
|
|
|
|
compute_meter
|
|
|
|
} else {
|
|
|
|
Rc::new(RefCell::new(ThisComputeMeter {
|
2021-07-22 10:18:51 -07:00
|
|
|
remaining: compute_budget.max_units,
|
2021-07-16 00:31:22 -07:00
|
|
|
}))
|
|
|
|
};
|
2021-04-19 09:48:48 -07:00
|
|
|
let mut invoke_context = Self {
|
2021-07-22 10:18:51 -07:00
|
|
|
invoke_stack: Vec::with_capacity(compute_budget.max_invoke_depth),
|
2020-04-28 14:33:56 -07:00
|
|
|
rent,
|
|
|
|
pre_accounts,
|
2021-07-05 04:49:37 -07:00
|
|
|
accounts,
|
2020-06-03 12:48:19 -07:00
|
|
|
programs,
|
2020-06-13 13:20:08 -07:00
|
|
|
logger: Rc::new(RefCell::new(ThisLogger { log_collector })),
|
2021-07-22 10:18:51 -07:00
|
|
|
compute_budget,
|
|
|
|
bpf_compute_budget: compute_budget.into(),
|
2021-07-16 00:31:22 -07:00
|
|
|
compute_meter,
|
2020-09-14 17:42:37 -07:00
|
|
|
executors,
|
2020-09-24 07:36:22 -07:00
|
|
|
instruction_recorder,
|
2020-09-29 14:36:30 -07:00
|
|
|
feature_set,
|
2021-03-03 15:07:45 -08:00
|
|
|
timings: ExecuteDetailsTimings::default(),
|
2021-04-12 16:04:57 -07:00
|
|
|
account_db,
|
|
|
|
ancestors,
|
2021-05-20 14:00:50 -07:00
|
|
|
sysvars: RefCell::new(vec![]),
|
2021-07-29 01:50:20 -07:00
|
|
|
blockhash,
|
|
|
|
fee_calculator,
|
2021-09-01 02:14:01 -07:00
|
|
|
return_data: None,
|
2021-04-19 09:48:48 -07:00
|
|
|
};
|
2021-09-21 05:41:02 -07:00
|
|
|
let account_indices = (0..accounts.len()).collect::<Vec<usize>>();
|
|
|
|
invoke_context.push(
|
|
|
|
program_id,
|
|
|
|
message,
|
|
|
|
instruction,
|
|
|
|
program_indices,
|
|
|
|
&account_indices,
|
|
|
|
)?;
|
2021-09-09 23:36:21 -07:00
|
|
|
Ok(invoke_context)
|
2020-04-28 14:33:56 -07:00
|
|
|
}
|
|
|
|
}
|
2020-10-29 09:57:14 -07:00
|
|
|
impl<'a> InvokeContext for ThisInvokeContext<'a> {
|
2021-04-19 09:48:48 -07:00
|
|
|
fn push(
|
|
|
|
&mut self,
|
|
|
|
key: &Pubkey,
|
2021-09-09 23:36:21 -07:00
|
|
|
message: &Message,
|
|
|
|
instruction: &CompiledInstruction,
|
|
|
|
program_indices: &[usize],
|
2021-09-21 05:41:02 -07:00
|
|
|
account_indices: &[usize],
|
2021-04-19 09:48:48 -07:00
|
|
|
) -> Result<(), InstructionError> {
|
2021-07-22 10:18:51 -07:00
|
|
|
if self.invoke_stack.len() > self.compute_budget.max_invoke_depth {
|
2020-04-28 14:33:56 -07:00
|
|
|
return Err(InstructionError::CallDepth);
|
|
|
|
}
|
2021-06-02 02:15:19 -07:00
|
|
|
|
|
|
|
let contains = self.invoke_stack.iter().any(|frame| frame.key == *key);
|
|
|
|
let is_last = if let Some(last_frame) = self.invoke_stack.last() {
|
|
|
|
last_frame.key == *key
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
};
|
|
|
|
if contains && !is_last {
|
2020-04-28 14:33:56 -07:00
|
|
|
// Reentrancy not allowed unless caller is calling itself
|
|
|
|
return Err(InstructionError::ReentrancyNotAllowed);
|
|
|
|
}
|
2021-06-02 02:15:19 -07:00
|
|
|
|
2021-09-09 23:36:21 -07:00
|
|
|
// Create the KeyedAccounts that will be passed to the program
|
|
|
|
let demote_program_write_locks = self
|
|
|
|
.feature_set
|
|
|
|
.is_active(&demote_program_write_locks::id());
|
|
|
|
let keyed_accounts = program_indices
|
|
|
|
.iter()
|
|
|
|
.map(|account_index| {
|
|
|
|
(
|
|
|
|
false,
|
|
|
|
false,
|
|
|
|
&self.accounts[*account_index].0,
|
|
|
|
&self.accounts[*account_index].1 as &RefCell<AccountSharedData>,
|
|
|
|
)
|
|
|
|
})
|
2021-09-21 05:41:02 -07:00
|
|
|
.chain(instruction.accounts.iter().map(|index_in_instruction| {
|
|
|
|
let index_in_instruction = *index_in_instruction as usize;
|
|
|
|
let account_index = account_indices[index_in_instruction];
|
2021-09-09 23:36:21 -07:00
|
|
|
(
|
2021-09-21 05:41:02 -07:00
|
|
|
message.is_signer(index_in_instruction),
|
|
|
|
message.is_writable(index_in_instruction, demote_program_write_locks),
|
|
|
|
&self.accounts[account_index].0,
|
|
|
|
&self.accounts[account_index].1 as &RefCell<AccountSharedData>,
|
2021-09-09 23:36:21 -07:00
|
|
|
)
|
|
|
|
}))
|
|
|
|
.collect::<Vec<_>>();
|
2021-04-19 09:48:48 -07:00
|
|
|
self.invoke_stack.push(InvokeContextStackFrame::new(
|
|
|
|
*key,
|
|
|
|
create_keyed_accounts_unified(keyed_accounts.as_slice()),
|
|
|
|
));
|
2020-04-28 14:33:56 -07:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
fn pop(&mut self) {
|
2021-04-19 09:48:48 -07:00
|
|
|
self.invoke_stack.pop();
|
2020-04-28 14:33:56 -07:00
|
|
|
}
|
2020-11-12 12:44:37 -08:00
|
|
|
fn invoke_depth(&self) -> usize {
|
2021-04-19 09:48:48 -07:00
|
|
|
self.invoke_stack.len()
|
2020-11-12 12:44:37 -08:00
|
|
|
}
|
2020-04-28 14:33:56 -07:00
|
|
|
fn verify_and_update(
|
|
|
|
&mut self,
|
|
|
|
instruction: &CompiledInstruction,
|
2021-09-21 05:41:02 -07:00
|
|
|
account_indices: &[usize],
|
2021-07-07 07:14:00 -07:00
|
|
|
write_privileges: &[bool],
|
2020-04-28 14:33:56 -07:00
|
|
|
) -> Result<(), InstructionError> {
|
2021-04-19 09:48:48 -07:00
|
|
|
let stack_frame = self
|
|
|
|
.invoke_stack
|
|
|
|
.last()
|
|
|
|
.ok_or(InstructionError::CallDepth)?;
|
2021-09-21 05:41:02 -07:00
|
|
|
let program_id = &stack_frame.key;
|
|
|
|
let rent = &self.rent;
|
2021-06-09 16:27:00 -07:00
|
|
|
let logger = self.get_logger();
|
2021-09-21 05:41:02 -07:00
|
|
|
let accounts = &self.accounts;
|
|
|
|
let pre_accounts = &mut self.pre_accounts;
|
|
|
|
let timings = &mut self.timings;
|
|
|
|
|
|
|
|
// Verify the per-account instruction results
|
|
|
|
let (mut pre_sum, mut post_sum) = (0_u128, 0_u128);
|
|
|
|
let mut work = |_unique_index: usize, index_in_instruction: usize| {
|
|
|
|
if index_in_instruction < write_privileges.len()
|
|
|
|
&& index_in_instruction < account_indices.len()
|
|
|
|
{
|
|
|
|
let account_index = account_indices[index_in_instruction];
|
|
|
|
let (key, account) = &accounts[account_index];
|
|
|
|
let is_writable = write_privileges[index_in_instruction];
|
|
|
|
// Find the matching PreAccount
|
|
|
|
for pre_account in pre_accounts.iter_mut() {
|
|
|
|
if key == pre_account.key() {
|
|
|
|
{
|
|
|
|
// Verify account has no outstanding references
|
|
|
|
let _ = account
|
|
|
|
.try_borrow_mut()
|
|
|
|
.map_err(|_| InstructionError::AccountBorrowOutstanding)?;
|
|
|
|
}
|
|
|
|
let account = account.borrow();
|
|
|
|
pre_account
|
|
|
|
.verify(program_id, is_writable, rent, &account, timings, false)
|
|
|
|
.map_err(|err| {
|
|
|
|
ic_logger_msg!(logger, "failed to verify account {}: {}", key, err);
|
|
|
|
err
|
|
|
|
})?;
|
|
|
|
pre_sum += u128::from(pre_account.lamports());
|
|
|
|
post_sum += u128::from(account.lamports());
|
|
|
|
if is_writable && !pre_account.executable() {
|
|
|
|
pre_account.update(&account);
|
|
|
|
}
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(InstructionError::MissingAccount)
|
|
|
|
};
|
|
|
|
instruction.visit_each_account(&mut work)?;
|
|
|
|
|
|
|
|
// Verify that the total sum of all the lamports did not change
|
|
|
|
if pre_sum != post_sum {
|
|
|
|
return Err(InstructionError::UnbalancedInstruction);
|
|
|
|
}
|
|
|
|
Ok(())
|
2020-04-28 14:33:56 -07:00
|
|
|
}
|
2020-05-08 12:24:36 -07:00
|
|
|
fn get_caller(&self) -> Result<&Pubkey, InstructionError> {
|
2021-04-19 09:48:48 -07:00
|
|
|
self.invoke_stack
|
2020-05-08 12:24:36 -07:00
|
|
|
.last()
|
2021-04-19 09:48:48 -07:00
|
|
|
.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)
|
2020-05-08 12:24:36 -07:00
|
|
|
}
|
2020-10-28 20:21:50 -07:00
|
|
|
fn get_programs(&self) -> &[(Pubkey, ProcessInstructionWithContext)] {
|
2020-10-29 09:57:14 -07:00
|
|
|
self.programs
|
2020-06-03 12:48:19 -07:00
|
|
|
}
|
2020-06-13 13:20:08 -07:00
|
|
|
fn get_logger(&self) -> Rc<RefCell<dyn Logger>> {
|
|
|
|
self.logger.clone()
|
|
|
|
}
|
2021-07-22 10:18:51 -07:00
|
|
|
#[allow(deprecated)]
|
|
|
|
fn get_bpf_compute_budget(&self) -> &solana_sdk::process_instruction::BpfComputeBudget {
|
2020-10-28 13:16:13 -07:00
|
|
|
&self.bpf_compute_budget
|
2020-08-26 14:48:51 -07:00
|
|
|
}
|
2020-08-21 15:31:19 -07:00
|
|
|
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>> {
|
|
|
|
self.compute_meter.clone()
|
|
|
|
}
|
2020-10-29 23:43:10 -07:00
|
|
|
fn add_executor(&self, pubkey: &Pubkey, executor: Arc<dyn Executor>) {
|
2020-09-14 17:42:37 -07:00
|
|
|
self.executors.borrow_mut().insert(*pubkey, executor);
|
|
|
|
}
|
2020-10-29 23:43:10 -07:00
|
|
|
fn get_executor(&self, pubkey: &Pubkey) -> Option<Arc<dyn Executor>> {
|
2021-06-18 06:34:46 -07:00
|
|
|
self.executors.borrow().get(pubkey)
|
2020-09-14 17:42:37 -07:00
|
|
|
}
|
2020-09-24 07:36:22 -07:00
|
|
|
fn record_instruction(&self, instruction: &Instruction) {
|
|
|
|
if let Some(recorder) = &self.instruction_recorder {
|
|
|
|
recorder.record_instruction(instruction.clone());
|
|
|
|
}
|
|
|
|
}
|
2020-09-29 14:36:30 -07:00
|
|
|
fn is_feature_active(&self, feature_id: &Pubkey) -> bool {
|
|
|
|
self.feature_set.is_active(feature_id)
|
|
|
|
}
|
2021-09-09 23:36:21 -07:00
|
|
|
fn get_account(&self, pubkey: &Pubkey) -> Option<(usize, Rc<RefCell<AccountSharedData>>)> {
|
|
|
|
for (index, (key, account)) in self.accounts.iter().enumerate().rev() {
|
2021-05-28 09:50:25 -07:00
|
|
|
if key == pubkey {
|
2021-09-09 23:36:21 -07:00
|
|
|
return Some((index, account.clone()));
|
2021-05-28 09:50:25 -07:00
|
|
|
}
|
2021-09-09 23:36:21 -07:00
|
|
|
}
|
|
|
|
None
|
2020-12-17 15:39:49 -08:00
|
|
|
}
|
2021-03-03 15:07:45 -08:00
|
|
|
fn update_timing(
|
|
|
|
&mut self,
|
|
|
|
serialize_us: u64,
|
|
|
|
create_vm_us: u64,
|
|
|
|
execute_us: u64,
|
|
|
|
deserialize_us: u64,
|
|
|
|
) {
|
|
|
|
self.timings.serialize_us += serialize_us;
|
|
|
|
self.timings.create_vm_us += create_vm_us;
|
|
|
|
self.timings.execute_us += execute_us;
|
|
|
|
self.timings.deserialize_us += deserialize_us;
|
|
|
|
}
|
2021-05-20 14:00:50 -07:00
|
|
|
fn get_sysvar_data(&self, id: &Pubkey) -> Option<Rc<Vec<u8>>> {
|
|
|
|
if let Ok(mut sysvars) = self.sysvars.try_borrow_mut() {
|
|
|
|
// Try share from cache
|
|
|
|
let mut result = sysvars
|
2021-04-12 16:04:57 -07:00
|
|
|
.iter()
|
|
|
|
.find_map(|(key, sysvar)| if id == key { sysvar.clone() } else { None });
|
2021-05-20 14:00:50 -07:00
|
|
|
if result.is_none() {
|
|
|
|
// Load it
|
|
|
|
result = self
|
|
|
|
.account_db
|
|
|
|
.load_with_fixed_root(self.ancestors, id)
|
|
|
|
.map(|(account, _)| Rc::new(account.data().to_vec()));
|
|
|
|
// Cache it
|
|
|
|
sysvars.push((*id, result.clone()));
|
|
|
|
}
|
|
|
|
result
|
|
|
|
} else {
|
|
|
|
None
|
2021-04-12 16:04:57 -07:00
|
|
|
}
|
|
|
|
}
|
2021-07-22 10:18:51 -07:00
|
|
|
fn get_compute_budget(&self) -> &ComputeBudget {
|
|
|
|
&self.compute_budget
|
|
|
|
}
|
2021-07-29 01:50:20 -07:00
|
|
|
fn get_blockhash(&self) -> &Hash {
|
|
|
|
self.blockhash
|
|
|
|
}
|
|
|
|
fn get_fee_calculator(&self) -> &FeeCalculator {
|
|
|
|
self.fee_calculator
|
|
|
|
}
|
2021-09-01 02:14:01 -07:00
|
|
|
fn set_return_data(&mut self, return_data: Option<(Pubkey, Vec<u8>)>) {
|
|
|
|
self.return_data = return_data;
|
|
|
|
}
|
|
|
|
fn get_return_data(&self) -> &Option<(Pubkey, Vec<u8>)> {
|
|
|
|
&self.return_data
|
|
|
|
}
|
2020-06-13 13:20:08 -07:00
|
|
|
}
|
|
|
|
pub struct ThisLogger {
|
|
|
|
log_collector: Option<Rc<LogCollector>>,
|
|
|
|
}
|
|
|
|
impl Logger for ThisLogger {
|
2020-06-06 10:18:28 -07:00
|
|
|
fn log_enabled(&self) -> bool {
|
|
|
|
log_enabled!(log::Level::Info) || self.log_collector.is_some()
|
|
|
|
}
|
2020-10-29 23:43:10 -07:00
|
|
|
fn log(&self, message: &str) {
|
2020-11-12 12:44:37 -08:00
|
|
|
debug!("{}", message);
|
2020-06-13 13:20:08 -07:00
|
|
|
if let Some(log_collector) = &self.log_collector {
|
2020-06-06 10:18:28 -07:00
|
|
|
log_collector.log(message);
|
|
|
|
}
|
|
|
|
}
|
2020-04-28 14:33:56 -07:00
|
|
|
}
|
|
|
|
|
2021-08-26 17:30:36 -07:00
|
|
|
#[derive(Debug, Default, Clone, Deserialize, Serialize)]
|
2019-04-02 08:35:38 -07:00
|
|
|
pub struct MessageProcessor {
|
2019-05-30 21:31:35 -07:00
|
|
|
#[serde(skip)]
|
2021-08-26 17:30:36 -07:00
|
|
|
instruction_processor: InstructionProcessor,
|
2019-03-15 19:48:11 -07:00
|
|
|
}
|
2020-07-06 04:22:23 -07:00
|
|
|
|
|
|
|
#[cfg(RUSTC_WITH_SPECIALIZATION)]
|
2020-10-19 21:07:46 -07:00
|
|
|
impl ::solana_frozen_abi::abi_example::AbiExample for MessageProcessor {
|
2020-07-06 04:22:23 -07:00
|
|
|
fn example() -> Self {
|
|
|
|
// MessageProcessor's fields are #[serde(skip)]-ed and not Serialize
|
|
|
|
// so, just rely on Default anyway.
|
|
|
|
MessageProcessor::default()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-02 08:35:38 -07:00
|
|
|
impl MessageProcessor {
|
2019-07-31 14:28:14 -07:00
|
|
|
/// Add a static entrypoint to intercept instructions before the dynamic loader.
|
2020-10-28 20:21:50 -07:00
|
|
|
pub fn add_program(
|
|
|
|
&mut self,
|
|
|
|
program_id: Pubkey,
|
|
|
|
process_instruction: ProcessInstructionWithContext,
|
|
|
|
) {
|
2021-08-26 17:30:36 -07:00
|
|
|
self.instruction_processor
|
|
|
|
.add_program(program_id, process_instruction);
|
2020-04-28 14:33:56 -07:00
|
|
|
}
|
|
|
|
|
2020-03-05 16:17:31 -08:00
|
|
|
/// Record the initial state of the accounts so that they can be compared
|
|
|
|
/// after the instruction is processed
|
|
|
|
pub fn create_pre_accounts(
|
|
|
|
message: &Message,
|
|
|
|
instruction: &CompiledInstruction,
|
2021-07-05 04:49:37 -07:00
|
|
|
accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
|
2020-03-05 16:17:31 -08:00
|
|
|
) -> Vec<PreAccount> {
|
2021-02-18 07:37:24 -08:00
|
|
|
let mut pre_accounts = Vec::with_capacity(instruction.accounts.len());
|
2020-03-05 16:17:31 -08:00
|
|
|
{
|
|
|
|
let mut work = |_unique_index: usize, account_index: usize| {
|
2021-07-05 04:49:37 -07:00
|
|
|
if account_index < message.account_keys.len() && account_index < accounts.len() {
|
|
|
|
let account = accounts[account_index].1.borrow();
|
|
|
|
pre_accounts.push(PreAccount::new(&accounts[account_index].0, &account));
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
Err(InstructionError::MissingAccount)
|
2020-03-05 16:17:31 -08:00
|
|
|
};
|
2020-03-12 09:08:39 -07:00
|
|
|
let _ = instruction.visit_each_account(&mut work);
|
2020-02-21 13:28:35 -08:00
|
|
|
}
|
|
|
|
pre_accounts
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Verify there are no outstanding borrows
|
2020-01-22 09:11:56 -08:00
|
|
|
pub fn verify_account_references(
|
2021-03-10 23:04:00 -08:00
|
|
|
accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
|
2021-09-09 23:36:21 -07:00
|
|
|
program_indices: &[usize],
|
2020-01-22 09:11:56 -08:00
|
|
|
) -> Result<(), InstructionError> {
|
2021-09-09 23:36:21 -07:00
|
|
|
for account_index in program_indices.iter() {
|
|
|
|
accounts[*account_index]
|
|
|
|
.1
|
2020-01-22 09:11:56 -08:00
|
|
|
.try_borrow_mut()
|
|
|
|
.map_err(|_| InstructionError::AccountBorrowOutstanding)?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-02-21 13:28:35 -08:00
|
|
|
/// Verify the results of an instruction
|
2021-09-03 20:05:30 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2020-02-21 11:30:00 -08:00
|
|
|
pub fn verify(
|
2020-02-21 13:28:35 -08:00
|
|
|
message: &Message,
|
|
|
|
instruction: &CompiledInstruction,
|
2020-03-05 16:17:31 -08:00
|
|
|
pre_accounts: &[PreAccount],
|
2021-09-09 23:36:21 -07:00
|
|
|
program_indices: &[usize],
|
2021-07-05 04:49:37 -07:00
|
|
|
accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
|
2020-05-26 01:02:31 -07:00
|
|
|
rent: &Rent,
|
2021-03-03 15:07:45 -08:00
|
|
|
timings: &mut ExecuteDetailsTimings,
|
2021-06-09 16:27:00 -07:00
|
|
|
logger: Rc<RefCell<dyn Logger>>,
|
2021-09-03 20:05:30 -07:00
|
|
|
demote_program_write_locks: bool,
|
2020-02-21 11:30:00 -08:00
|
|
|
) -> Result<(), InstructionError> {
|
2020-04-28 14:33:56 -07:00
|
|
|
// Verify all executable accounts have zero outstanding refs
|
2021-09-09 23:36:21 -07:00
|
|
|
Self::verify_account_references(accounts, program_indices)?;
|
2020-02-21 11:30:00 -08:00
|
|
|
|
|
|
|
// Verify the per-account instruction results
|
|
|
|
let (mut pre_sum, mut post_sum) = (0_u128, 0_u128);
|
2020-03-05 16:17:31 -08:00
|
|
|
{
|
|
|
|
let program_id = instruction.program_id(&message.account_keys);
|
|
|
|
let mut work = |unique_index: usize, account_index: usize| {
|
2021-03-10 23:04:00 -08:00
|
|
|
{
|
|
|
|
// Verify account has no outstanding references
|
|
|
|
let _ = accounts[account_index]
|
2021-07-05 04:49:37 -07:00
|
|
|
.1
|
2021-03-10 23:04:00 -08:00
|
|
|
.try_borrow_mut()
|
|
|
|
.map_err(|_| InstructionError::AccountBorrowOutstanding)?;
|
|
|
|
}
|
2021-07-05 04:49:37 -07:00
|
|
|
let account = accounts[account_index].1.borrow();
|
2021-06-09 16:27:00 -07:00
|
|
|
pre_accounts[unique_index]
|
|
|
|
.verify(
|
2021-06-18 06:34:46 -07:00
|
|
|
program_id,
|
2021-09-03 20:05:30 -07:00
|
|
|
message.is_writable(account_index, demote_program_write_locks),
|
2021-06-09 16:27:00 -07:00
|
|
|
rent,
|
|
|
|
&account,
|
|
|
|
timings,
|
|
|
|
true,
|
|
|
|
)
|
|
|
|
.map_err(|err| {
|
|
|
|
ic_logger_msg!(
|
|
|
|
logger,
|
|
|
|
"failed to verify account {}: {}",
|
2021-08-26 17:30:36 -07:00
|
|
|
pre_accounts[unique_index].key(),
|
2021-06-09 16:27:00 -07:00
|
|
|
err
|
|
|
|
);
|
|
|
|
err
|
|
|
|
})?;
|
2020-04-28 14:33:56 -07:00
|
|
|
pre_sum += u128::from(pre_accounts[unique_index].lamports());
|
2021-04-29 08:44:46 -07:00
|
|
|
post_sum += u128::from(account.lamports());
|
2020-03-05 16:17:31 -08:00
|
|
|
Ok(())
|
|
|
|
};
|
2020-03-12 09:08:39 -07:00
|
|
|
instruction.visit_each_account(&mut work)?;
|
2020-02-21 11:30:00 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Verify that the total sum of all the lamports did not change
|
|
|
|
if pre_sum != post_sum {
|
|
|
|
return Err(InstructionError::UnbalancedInstruction);
|
|
|
|
}
|
|
|
|
Ok(())
|
2019-11-05 10:57:32 -08:00
|
|
|
}
|
|
|
|
|
2019-03-15 19:48:11 -07:00
|
|
|
/// Execute an instruction
|
|
|
|
/// This method calls the instruction's program entrypoint method and verifies that the result of
|
|
|
|
/// the call does not violate the bank's accounting rules.
|
|
|
|
/// The accounts are committed back to the bank only if this function returns Ok(_).
|
2020-09-20 10:58:12 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2019-03-15 19:48:11 -07:00
|
|
|
fn execute_instruction(
|
|
|
|
&self,
|
2019-03-29 09:05:06 -07:00
|
|
|
message: &Message,
|
2019-04-02 15:02:57 -07:00
|
|
|
instruction: &CompiledInstruction,
|
2021-09-09 23:36:21 -07:00
|
|
|
program_indices: &[usize],
|
2021-07-05 04:49:37 -07:00
|
|
|
accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
|
2020-03-31 10:07:38 -07:00
|
|
|
rent_collector: &RentCollector,
|
2020-06-13 13:20:08 -07:00
|
|
|
log_collector: Option<Rc<LogCollector>>,
|
2020-09-14 17:42:37 -07:00
|
|
|
executors: Rc<RefCell<Executors>>,
|
2020-09-24 07:36:22 -07:00
|
|
|
instruction_recorder: Option<InstructionRecorder>,
|
2020-09-19 12:17:46 -07:00
|
|
|
instruction_index: usize,
|
2020-09-29 14:36:30 -07:00
|
|
|
feature_set: Arc<FeatureSet>,
|
2021-07-22 10:18:51 -07:00
|
|
|
compute_budget: ComputeBudget,
|
2021-07-16 00:31:22 -07:00
|
|
|
compute_meter: Rc<RefCell<dyn ComputeMeter>>,
|
2021-03-03 15:07:45 -08:00
|
|
|
timings: &mut ExecuteDetailsTimings,
|
2021-04-12 16:04:57 -07:00
|
|
|
account_db: Arc<Accounts>,
|
|
|
|
ancestors: &Ancestors,
|
2021-07-29 01:50:20 -07:00
|
|
|
blockhash: &Hash,
|
|
|
|
fee_calculator: &FeeCalculator,
|
2019-03-15 19:48:11 -07:00
|
|
|
) -> Result<(), InstructionError> {
|
2020-09-19 12:17:46 -07:00
|
|
|
// Fixup the special instructions key if present
|
|
|
|
// before the account pre-values are taken care of
|
2021-08-31 14:51:26 -07:00
|
|
|
for (pubkey, accont) in accounts.iter().take(message.account_keys.len()) {
|
|
|
|
if instructions::check_id(pubkey) {
|
|
|
|
let mut mut_account_ref = accont.borrow_mut();
|
|
|
|
instructions::store_current_index(
|
|
|
|
mut_account_ref.data_as_mut_slice(),
|
|
|
|
instruction_index as u16,
|
|
|
|
);
|
|
|
|
break;
|
2020-09-19 12:17:46 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-23 19:04:48 -08:00
|
|
|
let program_id = instruction.program_id(&message.account_keys);
|
2021-07-08 10:43:34 -07:00
|
|
|
|
2021-07-22 10:18:51 -07:00
|
|
|
let mut compute_budget = compute_budget;
|
2021-07-08 10:43:34 -07:00
|
|
|
if feature_set.is_active(&neon_evm_compute_budget::id())
|
|
|
|
&& *program_id == crate::neon_evm_program::id()
|
|
|
|
{
|
|
|
|
// Bump the compute budget for neon_evm
|
2021-07-22 10:18:51 -07:00
|
|
|
compute_budget.max_units = compute_budget.max_units.max(500_000);
|
|
|
|
compute_budget.heap_size = Some(256 * 1024);
|
2021-07-08 10:43:34 -07:00
|
|
|
}
|
|
|
|
|
2021-08-26 17:30:36 -07:00
|
|
|
let programs = self.instruction_processor.programs();
|
2020-04-28 14:33:56 -07:00
|
|
|
let mut invoke_context = ThisInvokeContext::new(
|
2020-12-23 19:04:48 -08:00
|
|
|
program_id,
|
2020-04-28 14:33:56 -07:00
|
|
|
rent_collector.rent,
|
2021-04-19 09:48:48 -07:00
|
|
|
message,
|
|
|
|
instruction,
|
2021-09-09 23:36:21 -07:00
|
|
|
program_indices,
|
2021-04-19 09:48:48 -07:00
|
|
|
accounts,
|
2021-08-26 17:30:36 -07:00
|
|
|
programs,
|
2020-06-06 10:18:28 -07:00
|
|
|
log_collector,
|
2021-07-22 10:18:51 -07:00
|
|
|
compute_budget,
|
2021-07-16 00:31:22 -07:00
|
|
|
compute_meter,
|
2020-09-14 17:42:37 -07:00
|
|
|
executors,
|
2020-09-24 07:36:22 -07:00
|
|
|
instruction_recorder,
|
2020-09-29 14:36:30 -07:00
|
|
|
feature_set,
|
2021-04-12 16:04:57 -07:00
|
|
|
account_db,
|
|
|
|
ancestors,
|
2021-07-29 01:50:20 -07:00
|
|
|
blockhash,
|
|
|
|
fee_calculator,
|
2021-09-09 23:36:21 -07:00
|
|
|
)?;
|
2021-08-26 17:30:36 -07:00
|
|
|
|
|
|
|
self.instruction_processor.process_instruction(
|
|
|
|
program_id,
|
|
|
|
&instruction.data,
|
|
|
|
&mut invoke_context,
|
|
|
|
)?;
|
2020-02-21 11:30:00 -08:00
|
|
|
Self::verify(
|
2020-02-21 13:28:35 -08:00
|
|
|
message,
|
|
|
|
instruction,
|
2020-04-28 14:33:56 -07:00
|
|
|
&invoke_context.pre_accounts,
|
2021-09-09 23:36:21 -07:00
|
|
|
program_indices,
|
2020-03-05 16:17:31 -08:00
|
|
|
accounts,
|
2020-05-26 01:02:31 -07:00
|
|
|
&rent_collector.rent,
|
2021-03-03 15:07:45 -08:00
|
|
|
timings,
|
2021-06-09 16:27:00 -07:00
|
|
|
invoke_context.get_logger(),
|
2021-09-03 20:05:30 -07:00
|
|
|
invoke_context.is_feature_active(&demote_program_write_locks::id()),
|
2020-02-21 11:30:00 -08:00
|
|
|
)?;
|
2021-03-03 15:07:45 -08:00
|
|
|
|
|
|
|
timings.accumulate(&invoke_context.timings);
|
|
|
|
|
2019-03-15 19:48:11 -07:00
|
|
|
Ok(())
|
2019-03-07 09:35:28 -08:00
|
|
|
}
|
|
|
|
|
2019-03-29 09:05:06 -07:00
|
|
|
/// Process a message.
|
|
|
|
/// This method calls each instruction in the message over the set of loaded Accounts
|
2019-03-15 19:48:11 -07:00
|
|
|
/// The accounts are committed back to the bank only if every instruction succeeds
|
2020-09-24 07:36:22 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2021-03-10 23:04:00 -08:00
|
|
|
#[allow(clippy::type_complexity)]
|
2019-03-29 09:05:06 -07:00
|
|
|
pub fn process_message(
|
2019-03-15 19:48:11 -07:00
|
|
|
&self,
|
2019-03-29 09:05:06 -07:00
|
|
|
message: &Message,
|
2021-09-09 23:36:21 -07:00
|
|
|
program_indices: &[Vec<usize>],
|
2021-07-05 04:49:37 -07:00
|
|
|
accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
|
2020-03-31 10:07:38 -07:00
|
|
|
rent_collector: &RentCollector,
|
2020-06-13 13:20:08 -07:00
|
|
|
log_collector: Option<Rc<LogCollector>>,
|
2020-09-14 17:42:37 -07:00
|
|
|
executors: Rc<RefCell<Executors>>,
|
2020-09-25 05:42:28 -07:00
|
|
|
instruction_recorders: Option<&[InstructionRecorder]>,
|
2020-09-29 14:36:30 -07:00
|
|
|
feature_set: Arc<FeatureSet>,
|
2021-07-22 10:18:51 -07:00
|
|
|
compute_budget: ComputeBudget,
|
2021-07-16 00:31:22 -07:00
|
|
|
compute_meter: Rc<RefCell<dyn ComputeMeter>>,
|
2021-03-03 15:07:45 -08:00
|
|
|
timings: &mut ExecuteDetailsTimings,
|
2021-04-12 16:04:57 -07:00
|
|
|
account_db: Arc<Accounts>,
|
|
|
|
ancestors: &Ancestors,
|
2021-07-29 01:50:20 -07:00
|
|
|
blockhash: Hash,
|
|
|
|
fee_calculator: FeeCalculator,
|
2019-03-15 19:48:11 -07:00
|
|
|
) -> Result<(), TransactionError> {
|
2019-03-29 09:05:06 -07:00
|
|
|
for (instruction_index, instruction) in message.instructions.iter().enumerate() {
|
2021-06-04 07:04:31 -07:00
|
|
|
let mut time = Measure::start("execute_instruction");
|
2021-07-16 12:40:12 -07:00
|
|
|
let pre_remaining_units = compute_meter.borrow().get_remaining();
|
2020-09-25 05:42:28 -07:00
|
|
|
let instruction_recorder = instruction_recorders
|
|
|
|
.as_ref()
|
|
|
|
.map(|recorders| recorders[instruction_index].clone());
|
2021-06-04 07:04:31 -07:00
|
|
|
let err = self
|
|
|
|
.execute_instruction(
|
|
|
|
message,
|
|
|
|
instruction,
|
2021-09-09 23:36:21 -07:00
|
|
|
&program_indices[instruction_index],
|
2021-06-04 07:04:31 -07:00
|
|
|
accounts,
|
|
|
|
rent_collector,
|
|
|
|
log_collector.clone(),
|
|
|
|
executors.clone(),
|
|
|
|
instruction_recorder,
|
|
|
|
instruction_index,
|
|
|
|
feature_set.clone(),
|
2021-07-22 10:18:51 -07:00
|
|
|
compute_budget,
|
2021-07-16 00:31:22 -07:00
|
|
|
compute_meter.clone(),
|
2021-06-04 07:04:31 -07:00
|
|
|
timings,
|
|
|
|
account_db.clone(),
|
|
|
|
ancestors,
|
2021-07-29 01:50:20 -07:00
|
|
|
&blockhash,
|
|
|
|
&fee_calculator,
|
2021-06-04 07:04:31 -07:00
|
|
|
)
|
|
|
|
.map_err(|err| TransactionError::InstructionError(instruction_index as u8, err));
|
|
|
|
time.stop();
|
2021-07-16 12:40:12 -07:00
|
|
|
let post_remaining_units = compute_meter.borrow().get_remaining();
|
2021-06-04 07:04:31 -07:00
|
|
|
|
2021-07-19 11:05:10 -07:00
|
|
|
timings.accumulate_program(
|
|
|
|
instruction.program_id(&message.account_keys),
|
|
|
|
time.as_us(),
|
|
|
|
pre_remaining_units - post_remaining_units,
|
|
|
|
);
|
2021-06-04 07:04:31 -07:00
|
|
|
|
|
|
|
err?;
|
2019-03-11 15:35:25 -07:00
|
|
|
}
|
2019-03-15 19:48:11 -07:00
|
|
|
Ok(())
|
|
|
|
}
|
2019-03-11 15:35:25 -07:00
|
|
|
}
|
|
|
|
|
2019-02-18 22:26:22 -08:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
2020-01-28 17:03:20 -08:00
|
|
|
use solana_sdk::{
|
|
|
|
instruction::{AccountMeta, Instruction, InstructionError},
|
|
|
|
message::Message,
|
2021-08-26 17:30:36 -07:00
|
|
|
native_loader::{self, create_loadable_account_for_test},
|
2021-07-16 00:31:22 -07:00
|
|
|
process_instruction::MockComputeMeter,
|
2020-01-28 17:03:20 -08:00
|
|
|
};
|
2019-02-18 22:26:22 -08:00
|
|
|
|
2020-04-28 14:33:56 -07:00
|
|
|
#[test]
|
|
|
|
fn test_invoke_context() {
|
|
|
|
const MAX_DEPTH: usize = 10;
|
2021-04-19 09:48:48 -07:00
|
|
|
let mut invoke_stack = vec![];
|
2020-04-28 14:33:56 -07:00
|
|
|
let mut accounts = vec![];
|
2021-04-19 09:48:48 -07:00
|
|
|
let mut metas = vec![];
|
2020-04-28 14:33:56 -07:00
|
|
|
for i in 0..MAX_DEPTH {
|
2021-04-19 09:48:48 -07:00
|
|
|
invoke_stack.push(solana_sdk::pubkey::new_rand());
|
2021-07-05 04:49:37 -07:00
|
|
|
accounts.push((
|
|
|
|
solana_sdk::pubkey::new_rand(),
|
|
|
|
Rc::new(RefCell::new(AccountSharedData::new(
|
|
|
|
i as u64,
|
|
|
|
1,
|
|
|
|
&invoke_stack[i],
|
|
|
|
))),
|
|
|
|
));
|
|
|
|
metas.push(AccountMeta::new(accounts[i].0, false));
|
2020-04-28 14:33:56 -07:00
|
|
|
}
|
2021-04-19 09:48:48 -07:00
|
|
|
for program_id in invoke_stack.iter() {
|
2021-07-05 04:49:37 -07:00
|
|
|
accounts.push((
|
|
|
|
*program_id,
|
|
|
|
Rc::new(RefCell::new(AccountSharedData::new(
|
|
|
|
1,
|
|
|
|
1,
|
|
|
|
&solana_sdk::pubkey::Pubkey::default(),
|
|
|
|
))),
|
|
|
|
));
|
2021-04-19 09:48:48 -07:00
|
|
|
metas.push(AccountMeta::new(*program_id, false));
|
2020-11-29 02:06:43 -08:00
|
|
|
}
|
2021-09-21 05:41:02 -07:00
|
|
|
let account_indices = (0..accounts.len()).collect::<Vec<usize>>();
|
2020-11-29 02:06:43 -08:00
|
|
|
|
2021-04-19 09:48:48 -07:00
|
|
|
let message = Message::new(
|
|
|
|
&[Instruction::new_with_bytes(invoke_stack[0], &[0], metas)],
|
|
|
|
None,
|
|
|
|
);
|
2021-04-12 16:04:57 -07:00
|
|
|
let ancestors = Ancestors::default();
|
2021-07-29 01:50:20 -07:00
|
|
|
let blockhash = Hash::default();
|
|
|
|
let fee_calculator = FeeCalculator::default();
|
2020-07-29 15:29:52 -07:00
|
|
|
let mut invoke_context = ThisInvokeContext::new(
|
2021-04-19 09:48:48 -07:00
|
|
|
&invoke_stack[0],
|
2020-07-29 15:29:52 -07:00
|
|
|
Rent::default(),
|
2021-04-19 09:48:48 -07:00
|
|
|
&message,
|
|
|
|
&message.instructions[0],
|
2020-10-29 09:57:14 -07:00
|
|
|
&[],
|
2021-04-19 09:48:48 -07:00
|
|
|
&accounts,
|
2020-12-22 09:26:55 -08:00
|
|
|
&[],
|
2020-07-29 15:29:52 -07:00
|
|
|
None,
|
2021-07-22 10:18:51 -07:00
|
|
|
ComputeBudget::default(),
|
2021-07-16 00:31:22 -07:00
|
|
|
Rc::new(RefCell::new(MockComputeMeter::default())),
|
2020-09-14 17:42:37 -07:00
|
|
|
Rc::new(RefCell::new(Executors::default())),
|
2020-09-24 07:36:22 -07:00
|
|
|
None,
|
2020-09-29 20:18:28 -07:00
|
|
|
Arc::new(FeatureSet::all_enabled()),
|
2021-08-06 13:52:27 -07:00
|
|
|
Arc::new(Accounts::default_for_tests()),
|
2021-04-12 16:04:57 -07:00
|
|
|
&ancestors,
|
2021-07-29 01:50:20 -07:00
|
|
|
&blockhash,
|
|
|
|
&fee_calculator,
|
2021-09-09 23:36:21 -07:00
|
|
|
)
|
|
|
|
.unwrap();
|
2020-04-28 14:33:56 -07:00
|
|
|
|
|
|
|
// Check call depth increases and has a limit
|
|
|
|
let mut depth_reached = 1;
|
2021-04-19 09:48:48 -07:00
|
|
|
for program_id in invoke_stack.iter().skip(1) {
|
2021-09-09 23:36:21 -07:00
|
|
|
if Err(InstructionError::CallDepth)
|
|
|
|
== invoke_context.push(
|
|
|
|
program_id,
|
|
|
|
&message,
|
|
|
|
&message.instructions[0],
|
|
|
|
&[],
|
2021-09-21 05:41:02 -07:00
|
|
|
&account_indices,
|
2021-09-09 23:36:21 -07:00
|
|
|
)
|
|
|
|
{
|
2020-04-28 14:33:56 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
depth_reached += 1;
|
|
|
|
}
|
|
|
|
assert_ne!(depth_reached, 0);
|
|
|
|
assert!(depth_reached < MAX_DEPTH);
|
|
|
|
|
|
|
|
// Mock each invocation
|
|
|
|
for owned_index in (1..depth_reached).rev() {
|
|
|
|
let not_owned_index = owned_index - 1;
|
|
|
|
let metas = vec![
|
2021-07-05 04:49:37 -07:00
|
|
|
AccountMeta::new(accounts[not_owned_index].0, false),
|
|
|
|
AccountMeta::new(accounts[owned_index].0, false),
|
2020-04-28 14:33:56 -07:00
|
|
|
];
|
2020-06-24 13:52:38 -07:00
|
|
|
let message = Message::new(
|
2021-03-03 21:46:48 -08:00
|
|
|
&[Instruction::new_with_bytes(
|
2021-04-19 09:48:48 -07:00
|
|
|
invoke_stack[owned_index],
|
2021-03-03 21:46:48 -08:00
|
|
|
&[0],
|
|
|
|
metas,
|
|
|
|
)],
|
2020-05-15 12:23:09 -07:00
|
|
|
None,
|
|
|
|
);
|
2021-09-21 05:41:02 -07:00
|
|
|
let write_privileges: Vec<bool> = (0..message.account_keys.len())
|
|
|
|
.map(|i| message.is_writable(i, /*demote_program_write_locks=*/ true))
|
|
|
|
.collect();
|
2020-04-28 14:33:56 -07:00
|
|
|
|
|
|
|
// modify account owned by the program
|
2021-07-05 04:49:37 -07:00
|
|
|
accounts[owned_index].1.borrow_mut().data_as_mut_slice()[0] =
|
2021-03-10 13:28:03 -08:00
|
|
|
(MAX_DEPTH + owned_index) as u8;
|
2020-04-28 14:33:56 -07:00
|
|
|
invoke_context
|
2021-09-21 05:41:02 -07:00
|
|
|
.verify_and_update(
|
|
|
|
&message.instructions[0],
|
|
|
|
&account_indices[not_owned_index..owned_index + 1],
|
|
|
|
&write_privileges,
|
|
|
|
)
|
2020-04-28 14:33:56 -07:00
|
|
|
.unwrap();
|
|
|
|
assert_eq!(
|
2021-08-26 17:30:36 -07:00
|
|
|
invoke_context.pre_accounts[owned_index].data()[0],
|
2020-04-28 14:33:56 -07:00
|
|
|
(MAX_DEPTH + owned_index) as u8
|
|
|
|
);
|
|
|
|
|
|
|
|
// modify account not owned by the program
|
2021-07-05 04:49:37 -07:00
|
|
|
let data = accounts[not_owned_index].1.borrow_mut().data()[0];
|
|
|
|
accounts[not_owned_index].1.borrow_mut().data_as_mut_slice()[0] =
|
2021-03-10 13:28:03 -08:00
|
|
|
(MAX_DEPTH + not_owned_index) as u8;
|
2020-04-28 14:33:56 -07:00
|
|
|
assert_eq!(
|
|
|
|
invoke_context.verify_and_update(
|
|
|
|
&message.instructions[0],
|
2021-09-21 05:41:02 -07:00
|
|
|
&account_indices[not_owned_index..owned_index + 1],
|
2021-07-07 07:14:00 -07:00
|
|
|
&write_privileges,
|
2020-04-28 14:33:56 -07:00
|
|
|
),
|
|
|
|
Err(InstructionError::ExternalAccountDataModified)
|
|
|
|
);
|
2021-08-26 17:30:36 -07:00
|
|
|
assert_eq!(invoke_context.pre_accounts[not_owned_index].data()[0], data);
|
2021-07-05 04:49:37 -07:00
|
|
|
accounts[not_owned_index].1.borrow_mut().data_as_mut_slice()[0] = data;
|
2020-04-28 14:33:56 -07:00
|
|
|
|
|
|
|
invoke_context.pop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-18 22:26:22 -08:00
|
|
|
#[test]
|
2020-01-22 09:11:56 -08:00
|
|
|
fn test_verify_account_references() {
|
2020-10-19 12:23:14 -07:00
|
|
|
let accounts = vec![(
|
|
|
|
solana_sdk::pubkey::new_rand(),
|
2021-03-10 23:04:00 -08:00
|
|
|
Rc::new(RefCell::new(AccountSharedData::default())),
|
2020-10-19 12:23:14 -07:00
|
|
|
)];
|
2020-01-22 09:11:56 -08:00
|
|
|
|
2021-09-09 23:36:21 -07:00
|
|
|
assert!(MessageProcessor::verify_account_references(&accounts, &[0]).is_ok());
|
2020-01-22 09:11:56 -08:00
|
|
|
|
2020-04-28 14:33:56 -07:00
|
|
|
let mut _borrowed = accounts[0].1.borrow();
|
2020-01-22 17:54:06 -08:00
|
|
|
assert_eq!(
|
2021-09-09 23:36:21 -07:00
|
|
|
MessageProcessor::verify_account_references(&accounts, &[0]),
|
2020-01-22 17:54:06 -08:00
|
|
|
Err(InstructionError::AccountBorrowOutstanding)
|
|
|
|
);
|
2019-02-18 22:26:22 -08:00
|
|
|
}
|
|
|
|
|
2019-06-10 19:50:02 -07:00
|
|
|
#[test]
|
2019-11-05 08:38:35 -08:00
|
|
|
fn test_process_message_readonly_handling() {
|
2019-06-10 19:50:02 -07:00
|
|
|
#[derive(Serialize, Deserialize)]
|
|
|
|
enum MockSystemInstruction {
|
2019-11-05 08:38:35 -08:00
|
|
|
Correct,
|
|
|
|
AttemptCredit { lamports: u64 },
|
|
|
|
AttemptDataChange { data: u8 },
|
2019-06-10 19:50:02 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn mock_system_process_instruction(
|
|
|
|
_program_id: &Pubkey,
|
|
|
|
data: &[u8],
|
2021-04-19 09:48:48 -07:00
|
|
|
invoke_context: &mut dyn InvokeContext,
|
2019-06-10 19:50:02 -07:00
|
|
|
) -> Result<(), InstructionError> {
|
2021-04-19 09:48:48 -07:00
|
|
|
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
2019-06-10 19:50:02 -07:00
|
|
|
if let Ok(instruction) = bincode::deserialize(data) {
|
|
|
|
match instruction {
|
2019-11-05 08:38:35 -08:00
|
|
|
MockSystemInstruction::Correct => Ok(()),
|
|
|
|
MockSystemInstruction::AttemptCredit { lamports } => {
|
2021-05-03 08:45:15 -07:00
|
|
|
keyed_accounts[0]
|
|
|
|
.account
|
|
|
|
.borrow_mut()
|
|
|
|
.checked_sub_lamports(lamports)?;
|
2021-04-27 07:56:18 -07:00
|
|
|
keyed_accounts[1]
|
|
|
|
.account
|
|
|
|
.borrow_mut()
|
|
|
|
.checked_add_lamports(lamports)?;
|
2019-06-10 19:50:02 -07:00
|
|
|
Ok(())
|
|
|
|
}
|
2019-11-05 08:38:35 -08:00
|
|
|
// Change data in a read-only account
|
|
|
|
MockSystemInstruction::AttemptDataChange { data } => {
|
2021-03-11 14:40:45 -08:00
|
|
|
keyed_accounts[1].account.borrow_mut().set_data(vec![data]);
|
2019-06-10 19:50:02 -07:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Err(InstructionError::InvalidInstructionData)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let mock_system_program_id = Pubkey::new(&[2u8; 32]);
|
2020-03-31 10:07:38 -07:00
|
|
|
let rent_collector = RentCollector::default();
|
2019-06-10 19:50:02 -07:00
|
|
|
let mut message_processor = MessageProcessor::default();
|
2020-05-19 19:45:30 -07:00
|
|
|
message_processor.add_program(mock_system_program_id, mock_system_process_instruction);
|
2019-06-10 19:50:02 -07:00
|
|
|
|
2021-09-09 23:36:21 -07:00
|
|
|
let program_account = Rc::new(RefCell::new(create_loadable_account_for_test(
|
|
|
|
"mock_system_program",
|
|
|
|
)));
|
2021-07-05 04:49:37 -07:00
|
|
|
let accounts = vec![
|
|
|
|
(
|
|
|
|
solana_sdk::pubkey::new_rand(),
|
|
|
|
AccountSharedData::new_ref(100, 1, &mock_system_program_id),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
solana_sdk::pubkey::new_rand(),
|
|
|
|
AccountSharedData::new_ref(0, 1, &mock_system_program_id),
|
|
|
|
),
|
2021-09-09 23:36:21 -07:00
|
|
|
(mock_system_program_id, program_account),
|
2021-07-05 04:49:37 -07:00
|
|
|
];
|
2021-09-09 23:36:21 -07:00
|
|
|
let program_indices = vec![vec![2]];
|
2019-06-10 19:50:02 -07:00
|
|
|
|
2020-09-14 17:42:37 -07:00
|
|
|
let executors = Rc::new(RefCell::new(Executors::default()));
|
2021-04-12 16:04:57 -07:00
|
|
|
let ancestors = Ancestors::default();
|
2020-09-14 17:42:37 -07:00
|
|
|
|
2019-06-10 19:50:02 -07:00
|
|
|
let account_metas = vec![
|
2021-07-05 04:49:37 -07:00
|
|
|
AccountMeta::new(accounts[0].0, true),
|
|
|
|
AccountMeta::new_readonly(accounts[1].0, false),
|
2019-06-10 19:50:02 -07:00
|
|
|
];
|
2020-06-24 13:52:38 -07:00
|
|
|
let message = Message::new(
|
2021-03-03 21:46:48 -08:00
|
|
|
&[Instruction::new_with_bincode(
|
2020-06-24 13:52:38 -07:00
|
|
|
mock_system_program_id,
|
|
|
|
&MockSystemInstruction::Correct,
|
|
|
|
account_metas.clone(),
|
|
|
|
)],
|
2021-07-05 04:49:37 -07:00
|
|
|
Some(&accounts[0].0),
|
2020-06-24 13:52:38 -07:00
|
|
|
);
|
2019-06-10 19:50:02 -07:00
|
|
|
|
2020-09-14 17:42:37 -07:00
|
|
|
let result = message_processor.process_message(
|
|
|
|
&message,
|
2021-09-09 23:36:21 -07:00
|
|
|
&program_indices,
|
2020-09-14 17:42:37 -07:00
|
|
|
&accounts,
|
|
|
|
&rent_collector,
|
|
|
|
None,
|
|
|
|
executors.clone(),
|
2020-09-24 07:36:22 -07:00
|
|
|
None,
|
2020-09-29 20:18:28 -07:00
|
|
|
Arc::new(FeatureSet::all_enabled()),
|
2021-07-22 10:18:51 -07:00
|
|
|
ComputeBudget::new(),
|
2021-07-16 00:31:22 -07:00
|
|
|
Rc::new(RefCell::new(MockComputeMeter::default())),
|
2021-03-03 15:07:45 -08:00
|
|
|
&mut ExecuteDetailsTimings::default(),
|
2021-08-06 13:52:27 -07:00
|
|
|
Arc::new(Accounts::default_for_tests()),
|
2021-04-12 16:04:57 -07:00
|
|
|
&ancestors,
|
2021-07-29 01:50:20 -07:00
|
|
|
Hash::default(),
|
|
|
|
FeeCalculator::default(),
|
2020-09-14 17:42:37 -07:00
|
|
|
);
|
2019-06-10 19:50:02 -07:00
|
|
|
assert_eq!(result, Ok(()));
|
2021-07-05 04:49:37 -07:00
|
|
|
assert_eq!(accounts[0].1.borrow().lamports(), 100);
|
|
|
|
assert_eq!(accounts[1].1.borrow().lamports(), 0);
|
2019-06-10 19:50:02 -07:00
|
|
|
|
2020-06-24 13:52:38 -07:00
|
|
|
let message = Message::new(
|
2021-03-03 21:46:48 -08:00
|
|
|
&[Instruction::new_with_bincode(
|
2020-06-24 13:52:38 -07:00
|
|
|
mock_system_program_id,
|
|
|
|
&MockSystemInstruction::AttemptCredit { lamports: 50 },
|
|
|
|
account_metas.clone(),
|
|
|
|
)],
|
2021-07-05 04:49:37 -07:00
|
|
|
Some(&accounts[0].0),
|
2020-06-24 13:52:38 -07:00
|
|
|
);
|
2019-06-10 19:50:02 -07:00
|
|
|
|
2020-09-14 17:42:37 -07:00
|
|
|
let result = message_processor.process_message(
|
|
|
|
&message,
|
2021-09-09 23:36:21 -07:00
|
|
|
&program_indices,
|
2020-09-14 17:42:37 -07:00
|
|
|
&accounts,
|
|
|
|
&rent_collector,
|
|
|
|
None,
|
|
|
|
executors.clone(),
|
2020-09-24 07:36:22 -07:00
|
|
|
None,
|
2020-09-29 20:18:28 -07:00
|
|
|
Arc::new(FeatureSet::all_enabled()),
|
2021-07-22 10:18:51 -07:00
|
|
|
ComputeBudget::new(),
|
2021-07-16 00:31:22 -07:00
|
|
|
Rc::new(RefCell::new(MockComputeMeter::default())),
|
2021-03-03 15:07:45 -08:00
|
|
|
&mut ExecuteDetailsTimings::default(),
|
2021-08-06 13:52:27 -07:00
|
|
|
Arc::new(Accounts::default_for_tests()),
|
2021-04-12 16:04:57 -07:00
|
|
|
&ancestors,
|
2021-07-29 01:50:20 -07:00
|
|
|
Hash::default(),
|
|
|
|
FeeCalculator::default(),
|
2020-09-14 17:42:37 -07:00
|
|
|
);
|
2019-06-10 19:50:02 -07:00
|
|
|
assert_eq!(
|
|
|
|
result,
|
|
|
|
Err(TransactionError::InstructionError(
|
|
|
|
0,
|
2019-11-05 08:38:35 -08:00
|
|
|
InstructionError::ReadonlyLamportChange
|
2019-06-10 19:50:02 -07:00
|
|
|
))
|
|
|
|
);
|
|
|
|
|
2020-06-24 13:52:38 -07:00
|
|
|
let message = Message::new(
|
2021-03-03 21:46:48 -08:00
|
|
|
&[Instruction::new_with_bincode(
|
2020-06-24 13:52:38 -07:00
|
|
|
mock_system_program_id,
|
|
|
|
&MockSystemInstruction::AttemptDataChange { data: 50 },
|
|
|
|
account_metas,
|
|
|
|
)],
|
2021-07-05 04:49:37 -07:00
|
|
|
Some(&accounts[0].0),
|
2020-06-24 13:52:38 -07:00
|
|
|
);
|
2019-06-10 19:50:02 -07:00
|
|
|
|
2020-09-14 17:42:37 -07:00
|
|
|
let result = message_processor.process_message(
|
|
|
|
&message,
|
2021-09-09 23:36:21 -07:00
|
|
|
&program_indices,
|
2020-09-14 17:42:37 -07:00
|
|
|
&accounts,
|
|
|
|
&rent_collector,
|
|
|
|
None,
|
|
|
|
executors,
|
2020-09-24 07:36:22 -07:00
|
|
|
None,
|
2020-09-29 20:18:28 -07:00
|
|
|
Arc::new(FeatureSet::all_enabled()),
|
2021-07-22 10:18:51 -07:00
|
|
|
ComputeBudget::new(),
|
2021-07-16 00:31:22 -07:00
|
|
|
Rc::new(RefCell::new(MockComputeMeter::default())),
|
2021-03-03 15:07:45 -08:00
|
|
|
&mut ExecuteDetailsTimings::default(),
|
2021-08-06 13:52:27 -07:00
|
|
|
Arc::new(Accounts::default_for_tests()),
|
2021-04-12 16:04:57 -07:00
|
|
|
&ancestors,
|
2021-07-29 01:50:20 -07:00
|
|
|
Hash::default(),
|
|
|
|
FeeCalculator::default(),
|
2020-09-14 17:42:37 -07:00
|
|
|
);
|
2019-06-10 19:50:02 -07:00
|
|
|
assert_eq!(
|
|
|
|
result,
|
|
|
|
Err(TransactionError::InstructionError(
|
|
|
|
0,
|
2019-11-05 08:38:35 -08:00
|
|
|
InstructionError::ReadonlyDataModified
|
2019-06-10 19:50:02 -07:00
|
|
|
))
|
|
|
|
);
|
2019-02-22 12:08:54 -08:00
|
|
|
}
|
2020-01-22 09:11:56 -08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_process_message_duplicate_accounts() {
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
|
|
enum MockSystemInstruction {
|
|
|
|
BorrowFail,
|
|
|
|
MultiBorrowMut,
|
|
|
|
DoWork { lamports: u64, data: u8 },
|
|
|
|
}
|
|
|
|
|
|
|
|
fn mock_system_process_instruction(
|
|
|
|
_program_id: &Pubkey,
|
|
|
|
data: &[u8],
|
2021-04-19 09:48:48 -07:00
|
|
|
invoke_context: &mut dyn InvokeContext,
|
2020-01-22 09:11:56 -08:00
|
|
|
) -> Result<(), InstructionError> {
|
2021-04-19 09:48:48 -07:00
|
|
|
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
2020-01-22 09:11:56 -08:00
|
|
|
if let Ok(instruction) = bincode::deserialize(data) {
|
|
|
|
match instruction {
|
|
|
|
MockSystemInstruction::BorrowFail => {
|
|
|
|
let from_account = keyed_accounts[0].try_account_ref_mut()?;
|
|
|
|
let dup_account = keyed_accounts[2].try_account_ref_mut()?;
|
2021-04-22 13:04:55 -07:00
|
|
|
if from_account.lamports() != dup_account.lamports() {
|
2020-01-22 09:11:56 -08:00
|
|
|
return Err(InstructionError::InvalidArgument);
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
MockSystemInstruction::MultiBorrowMut => {
|
|
|
|
let from_lamports = {
|
|
|
|
let from_account = keyed_accounts[0].try_account_ref_mut()?;
|
2021-05-03 08:45:54 -07:00
|
|
|
from_account.lamports()
|
2020-01-22 09:11:56 -08:00
|
|
|
};
|
|
|
|
let dup_lamports = {
|
|
|
|
let dup_account = keyed_accounts[2].try_account_ref_mut()?;
|
2021-05-03 08:45:54 -07:00
|
|
|
dup_account.lamports()
|
2020-01-22 09:11:56 -08:00
|
|
|
};
|
|
|
|
if from_lamports != dup_lamports {
|
|
|
|
return Err(InstructionError::InvalidArgument);
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
MockSystemInstruction::DoWork { lamports, data } => {
|
|
|
|
{
|
|
|
|
let mut to_account = keyed_accounts[1].try_account_ref_mut()?;
|
|
|
|
let mut dup_account = keyed_accounts[2].try_account_ref_mut()?;
|
2021-05-03 08:45:15 -07:00
|
|
|
dup_account.checked_sub_lamports(lamports)?;
|
2021-04-27 07:56:18 -07:00
|
|
|
to_account.checked_add_lamports(lamports)?;
|
2021-03-11 14:40:45 -08:00
|
|
|
dup_account.set_data(vec![data]);
|
2020-01-22 09:11:56 -08:00
|
|
|
}
|
2021-05-03 08:45:15 -07:00
|
|
|
keyed_accounts[0]
|
|
|
|
.try_account_ref_mut()?
|
|
|
|
.checked_sub_lamports(lamports)?;
|
2021-04-27 07:56:18 -07:00
|
|
|
keyed_accounts[1]
|
|
|
|
.try_account_ref_mut()?
|
|
|
|
.checked_add_lamports(lamports)?;
|
2020-01-22 09:11:56 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Err(InstructionError::InvalidInstructionData)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let mock_program_id = Pubkey::new(&[2u8; 32]);
|
2020-03-31 10:07:38 -07:00
|
|
|
let rent_collector = RentCollector::default();
|
2020-01-22 09:11:56 -08:00
|
|
|
let mut message_processor = MessageProcessor::default();
|
2020-05-19 19:45:30 -07:00
|
|
|
message_processor.add_program(mock_program_id, mock_system_process_instruction);
|
2020-01-22 09:11:56 -08:00
|
|
|
|
2021-09-09 23:36:21 -07:00
|
|
|
let program_account = Rc::new(RefCell::new(create_loadable_account_for_test(
|
|
|
|
"mock_system_program",
|
|
|
|
)));
|
2021-07-05 04:49:37 -07:00
|
|
|
let accounts = vec![
|
|
|
|
(
|
|
|
|
solana_sdk::pubkey::new_rand(),
|
|
|
|
AccountSharedData::new_ref(100, 1, &mock_program_id),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
solana_sdk::pubkey::new_rand(),
|
|
|
|
AccountSharedData::new_ref(0, 1, &mock_program_id),
|
|
|
|
),
|
2021-09-09 23:36:21 -07:00
|
|
|
(mock_program_id, program_account),
|
2021-07-05 04:49:37 -07:00
|
|
|
];
|
2021-09-09 23:36:21 -07:00
|
|
|
let program_indices = vec![vec![2]];
|
2020-01-22 09:11:56 -08:00
|
|
|
|
2020-09-14 17:42:37 -07:00
|
|
|
let executors = Rc::new(RefCell::new(Executors::default()));
|
2021-04-12 16:04:57 -07:00
|
|
|
let ancestors = Ancestors::default();
|
2020-09-14 17:42:37 -07:00
|
|
|
|
2020-01-22 09:11:56 -08:00
|
|
|
let account_metas = vec![
|
2021-07-05 04:49:37 -07:00
|
|
|
AccountMeta::new(accounts[0].0, true),
|
|
|
|
AccountMeta::new(accounts[1].0, false),
|
|
|
|
AccountMeta::new(accounts[0].0, false),
|
2020-01-22 09:11:56 -08:00
|
|
|
];
|
|
|
|
|
|
|
|
// Try to borrow mut the same account
|
2020-06-24 13:52:38 -07:00
|
|
|
let message = Message::new(
|
2021-03-03 21:46:48 -08:00
|
|
|
&[Instruction::new_with_bincode(
|
2020-06-24 13:52:38 -07:00
|
|
|
mock_program_id,
|
|
|
|
&MockSystemInstruction::BorrowFail,
|
|
|
|
account_metas.clone(),
|
|
|
|
)],
|
2021-07-05 04:49:37 -07:00
|
|
|
Some(&accounts[0].0),
|
2020-06-24 13:52:38 -07:00
|
|
|
);
|
2020-09-14 17:42:37 -07:00
|
|
|
let result = message_processor.process_message(
|
|
|
|
&message,
|
2021-09-09 23:36:21 -07:00
|
|
|
&program_indices,
|
2020-09-14 17:42:37 -07:00
|
|
|
&accounts,
|
|
|
|
&rent_collector,
|
|
|
|
None,
|
|
|
|
executors.clone(),
|
2020-09-24 07:36:22 -07:00
|
|
|
None,
|
2020-09-29 20:18:28 -07:00
|
|
|
Arc::new(FeatureSet::all_enabled()),
|
2021-07-22 10:18:51 -07:00
|
|
|
ComputeBudget::new(),
|
2021-07-16 00:31:22 -07:00
|
|
|
Rc::new(RefCell::new(MockComputeMeter::default())),
|
2021-03-03 15:07:45 -08:00
|
|
|
&mut ExecuteDetailsTimings::default(),
|
2021-08-06 13:52:27 -07:00
|
|
|
Arc::new(Accounts::default_for_tests()),
|
2021-04-12 16:04:57 -07:00
|
|
|
&ancestors,
|
2021-07-29 01:50:20 -07:00
|
|
|
Hash::default(),
|
|
|
|
FeeCalculator::default(),
|
2020-09-14 17:42:37 -07:00
|
|
|
);
|
2020-01-22 09:11:56 -08:00
|
|
|
assert_eq!(
|
|
|
|
result,
|
|
|
|
Err(TransactionError::InstructionError(
|
|
|
|
0,
|
|
|
|
InstructionError::AccountBorrowFailed
|
|
|
|
))
|
|
|
|
);
|
|
|
|
|
|
|
|
// Try to borrow mut the same account in a safe way
|
2020-06-24 13:52:38 -07:00
|
|
|
let message = Message::new(
|
2021-03-03 21:46:48 -08:00
|
|
|
&[Instruction::new_with_bincode(
|
2020-06-24 13:52:38 -07:00
|
|
|
mock_program_id,
|
|
|
|
&MockSystemInstruction::MultiBorrowMut,
|
|
|
|
account_metas.clone(),
|
|
|
|
)],
|
2021-07-05 04:49:37 -07:00
|
|
|
Some(&accounts[0].0),
|
2020-06-24 13:52:38 -07:00
|
|
|
);
|
2020-09-14 17:42:37 -07:00
|
|
|
let result = message_processor.process_message(
|
|
|
|
&message,
|
2021-09-09 23:36:21 -07:00
|
|
|
&program_indices,
|
2020-09-14 17:42:37 -07:00
|
|
|
&accounts,
|
|
|
|
&rent_collector,
|
|
|
|
None,
|
|
|
|
executors.clone(),
|
2020-09-24 07:36:22 -07:00
|
|
|
None,
|
2020-09-29 20:18:28 -07:00
|
|
|
Arc::new(FeatureSet::all_enabled()),
|
2021-07-22 10:18:51 -07:00
|
|
|
ComputeBudget::new(),
|
2021-07-16 00:31:22 -07:00
|
|
|
Rc::new(RefCell::new(MockComputeMeter::default())),
|
2021-03-03 15:07:45 -08:00
|
|
|
&mut ExecuteDetailsTimings::default(),
|
2021-08-06 13:52:27 -07:00
|
|
|
Arc::new(Accounts::default_for_tests()),
|
2021-04-12 16:04:57 -07:00
|
|
|
&ancestors,
|
2021-07-29 01:50:20 -07:00
|
|
|
Hash::default(),
|
|
|
|
FeeCalculator::default(),
|
2020-09-14 17:42:37 -07:00
|
|
|
);
|
2020-01-22 09:11:56 -08:00
|
|
|
assert_eq!(result, Ok(()));
|
|
|
|
|
|
|
|
// Do work on the same account but at different location in keyed_accounts[]
|
2020-06-24 13:52:38 -07:00
|
|
|
let message = Message::new(
|
2021-03-03 21:46:48 -08:00
|
|
|
&[Instruction::new_with_bincode(
|
2020-06-24 13:52:38 -07:00
|
|
|
mock_program_id,
|
|
|
|
&MockSystemInstruction::DoWork {
|
|
|
|
lamports: 10,
|
|
|
|
data: 42,
|
|
|
|
},
|
|
|
|
account_metas,
|
|
|
|
)],
|
2021-07-05 04:49:37 -07:00
|
|
|
Some(&accounts[0].0),
|
2020-06-24 13:52:38 -07:00
|
|
|
);
|
2021-04-12 16:04:57 -07:00
|
|
|
let ancestors = Ancestors::default();
|
2020-09-14 17:42:37 -07:00
|
|
|
let result = message_processor.process_message(
|
|
|
|
&message,
|
2021-09-09 23:36:21 -07:00
|
|
|
&program_indices,
|
2020-09-14 17:42:37 -07:00
|
|
|
&accounts,
|
|
|
|
&rent_collector,
|
|
|
|
None,
|
|
|
|
executors,
|
2020-09-24 07:36:22 -07:00
|
|
|
None,
|
2020-09-29 20:18:28 -07:00
|
|
|
Arc::new(FeatureSet::all_enabled()),
|
2021-07-22 10:18:51 -07:00
|
|
|
ComputeBudget::new(),
|
2021-07-16 00:31:22 -07:00
|
|
|
Rc::new(RefCell::new(MockComputeMeter::default())),
|
2021-03-03 15:07:45 -08:00
|
|
|
&mut ExecuteDetailsTimings::default(),
|
2021-08-06 13:52:27 -07:00
|
|
|
Arc::new(Accounts::default_for_tests()),
|
2021-04-12 16:04:57 -07:00
|
|
|
&ancestors,
|
2021-07-29 01:50:20 -07:00
|
|
|
Hash::default(),
|
|
|
|
FeeCalculator::default(),
|
2020-09-14 17:42:37 -07:00
|
|
|
);
|
2020-01-22 09:11:56 -08:00
|
|
|
assert_eq!(result, Ok(()));
|
2021-07-05 04:49:37 -07:00
|
|
|
assert_eq!(accounts[0].1.borrow().lamports(), 80);
|
|
|
|
assert_eq!(accounts[1].1.borrow().lamports(), 20);
|
|
|
|
assert_eq!(accounts[0].1.borrow().data(), &vec![42]);
|
2020-01-22 09:11:56 -08:00
|
|
|
}
|
2020-04-28 14:33:56 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_process_cross_program() {
|
2021-01-22 15:28:01 -08:00
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
2020-04-28 14:33:56 -07:00
|
|
|
enum MockInstruction {
|
|
|
|
NoopSuccess,
|
|
|
|
NoopFail,
|
|
|
|
ModifyOwned,
|
|
|
|
ModifyNotOwned,
|
2021-09-13 22:57:37 -07:00
|
|
|
ModifyReadonly,
|
2020-04-28 14:33:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn mock_process_instruction(
|
|
|
|
program_id: &Pubkey,
|
|
|
|
data: &[u8],
|
2021-04-19 09:48:48 -07:00
|
|
|
invoke_context: &mut dyn InvokeContext,
|
2020-04-28 14:33:56 -07:00
|
|
|
) -> Result<(), InstructionError> {
|
2021-04-19 09:48:48 -07:00
|
|
|
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
2020-04-28 14:33:56 -07:00
|
|
|
assert_eq!(*program_id, keyed_accounts[0].owner()?);
|
|
|
|
assert_ne!(
|
2020-05-20 09:24:57 -07:00
|
|
|
keyed_accounts[1].owner()?,
|
2020-04-28 14:33:56 -07:00
|
|
|
*keyed_accounts[0].unsigned_key()
|
|
|
|
);
|
|
|
|
|
|
|
|
if let Ok(instruction) = bincode::deserialize(data) {
|
|
|
|
match instruction {
|
|
|
|
MockInstruction::NoopSuccess => (),
|
|
|
|
MockInstruction::NoopFail => return Err(InstructionError::GenericError),
|
|
|
|
MockInstruction::ModifyOwned => {
|
2021-03-10 13:28:03 -08:00
|
|
|
keyed_accounts[0].try_account_ref_mut()?.data_as_mut_slice()[0] = 1
|
2020-04-28 14:33:56 -07:00
|
|
|
}
|
|
|
|
MockInstruction::ModifyNotOwned => {
|
2021-03-10 13:28:03 -08:00
|
|
|
keyed_accounts[1].try_account_ref_mut()?.data_as_mut_slice()[0] = 1
|
2020-04-28 14:33:56 -07:00
|
|
|
}
|
2021-09-13 22:57:37 -07:00
|
|
|
MockInstruction::ModifyReadonly => {
|
|
|
|
keyed_accounts[2].try_account_ref_mut()?.data_as_mut_slice()[0] = 1
|
|
|
|
}
|
2020-04-28 14:33:56 -07:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return Err(InstructionError::InvalidInstructionData);
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-10-19 12:12:08 -07:00
|
|
|
let caller_program_id = solana_sdk::pubkey::new_rand();
|
|
|
|
let callee_program_id = solana_sdk::pubkey::new_rand();
|
2020-05-20 09:24:57 -07:00
|
|
|
|
2021-03-09 13:06:07 -08:00
|
|
|
let owned_account = AccountSharedData::new(42, 1, &callee_program_id);
|
|
|
|
let not_owned_account = AccountSharedData::new(84, 1, &solana_sdk::pubkey::new_rand());
|
2021-09-13 22:57:37 -07:00
|
|
|
let readonly_account = AccountSharedData::new(168, 1, &caller_program_id);
|
|
|
|
let mut program_account = AccountSharedData::new(1, 0, &native_loader::id());
|
|
|
|
program_account.set_executable(true);
|
2020-04-28 14:33:56 -07:00
|
|
|
|
2020-07-10 13:02:55 -07:00
|
|
|
#[allow(unused_mut)]
|
2021-07-05 04:49:37 -07:00
|
|
|
let accounts = vec![
|
|
|
|
(
|
|
|
|
solana_sdk::pubkey::new_rand(),
|
|
|
|
Rc::new(RefCell::new(owned_account)),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
solana_sdk::pubkey::new_rand(),
|
|
|
|
Rc::new(RefCell::new(not_owned_account)),
|
|
|
|
),
|
2021-09-09 23:36:21 -07:00
|
|
|
(
|
2021-09-13 22:57:37 -07:00
|
|
|
solana_sdk::pubkey::new_rand(),
|
|
|
|
Rc::new(RefCell::new(readonly_account)),
|
2021-09-09 23:36:21 -07:00
|
|
|
),
|
2021-09-13 22:57:37 -07:00
|
|
|
(callee_program_id, Rc::new(RefCell::new(program_account))),
|
2020-04-28 14:33:56 -07:00
|
|
|
];
|
2021-09-21 05:41:02 -07:00
|
|
|
let account_indices = [0, 1, 2];
|
2021-09-13 22:57:37 -07:00
|
|
|
let program_indices = vec![3];
|
2021-04-19 09:48:48 -07:00
|
|
|
|
2020-10-30 01:10:13 -07:00
|
|
|
let programs: Vec<(_, ProcessInstructionWithContext)> =
|
|
|
|
vec![(callee_program_id, mock_process_instruction)];
|
2021-04-19 09:48:48 -07:00
|
|
|
let metas = vec![
|
2021-07-05 04:49:37 -07:00
|
|
|
AccountMeta::new(accounts[0].0, false),
|
|
|
|
AccountMeta::new(accounts[1].0, false),
|
2021-09-13 22:57:37 -07:00
|
|
|
AccountMeta::new_readonly(accounts[2].0, false),
|
2021-04-19 09:48:48 -07:00
|
|
|
];
|
|
|
|
|
2021-09-13 22:57:37 -07:00
|
|
|
let caller_instruction = CompiledInstruction::new(2, &(), vec![0, 1, 2, 3]);
|
|
|
|
let callee_instruction = Instruction::new_with_bincode(
|
2021-04-19 09:48:48 -07:00
|
|
|
callee_program_id,
|
|
|
|
&MockInstruction::NoopSuccess,
|
|
|
|
metas.clone(),
|
|
|
|
);
|
2021-09-13 22:57:37 -07:00
|
|
|
let message = Message::new(&[callee_instruction], None);
|
|
|
|
|
2021-09-03 20:05:30 -07:00
|
|
|
let feature_set = FeatureSet::all_enabled();
|
|
|
|
let demote_program_write_locks = feature_set.is_active(&demote_program_write_locks::id());
|
2021-04-19 09:48:48 -07:00
|
|
|
|
2021-04-12 16:04:57 -07:00
|
|
|
let ancestors = Ancestors::default();
|
2021-07-29 01:50:20 -07:00
|
|
|
let blockhash = Hash::default();
|
|
|
|
let fee_calculator = FeeCalculator::default();
|
2020-04-28 14:33:56 -07:00
|
|
|
let mut invoke_context = ThisInvokeContext::new(
|
|
|
|
&caller_program_id,
|
|
|
|
Rent::default(),
|
2021-04-19 09:48:48 -07:00
|
|
|
&message,
|
2021-09-13 22:57:37 -07:00
|
|
|
&caller_instruction,
|
2021-09-09 23:36:21 -07:00
|
|
|
&program_indices,
|
2021-04-19 09:48:48 -07:00
|
|
|
&accounts,
|
2020-10-30 01:10:13 -07:00
|
|
|
programs.as_slice(),
|
2020-06-06 10:18:28 -07:00
|
|
|
None,
|
2021-07-22 10:18:51 -07:00
|
|
|
ComputeBudget::default(),
|
2021-07-16 00:31:22 -07:00
|
|
|
Rc::new(RefCell::new(MockComputeMeter::default())),
|
2020-09-14 17:42:37 -07:00
|
|
|
Rc::new(RefCell::new(Executors::default())),
|
2020-09-24 07:36:22 -07:00
|
|
|
None,
|
2021-09-03 20:05:30 -07:00
|
|
|
Arc::new(feature_set),
|
2021-08-06 13:52:27 -07:00
|
|
|
Arc::new(Accounts::default_for_tests()),
|
2021-04-12 16:04:57 -07:00
|
|
|
&ancestors,
|
2021-07-29 01:50:20 -07:00
|
|
|
&blockhash,
|
|
|
|
&fee_calculator,
|
2021-09-09 23:36:21 -07:00
|
|
|
)
|
|
|
|
.unwrap();
|
2020-04-28 14:33:56 -07:00
|
|
|
|
|
|
|
// not owned account modified by the caller (before the invoke)
|
2021-03-10 23:04:00 -08:00
|
|
|
let caller_write_privileges = message
|
2021-01-22 15:28:01 -08:00
|
|
|
.account_keys
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
2021-09-03 20:05:30 -07:00
|
|
|
.map(|(i, _)| message.is_writable(i, demote_program_write_locks))
|
2021-01-22 15:28:01 -08:00
|
|
|
.collect::<Vec<bool>>();
|
2021-07-05 04:49:37 -07:00
|
|
|
accounts[0].1.borrow_mut().data_as_mut_slice()[0] = 1;
|
2020-04-28 14:33:56 -07:00
|
|
|
assert_eq!(
|
2021-08-26 17:30:36 -07:00
|
|
|
InstructionProcessor::process_cross_program_instruction(
|
2020-04-28 14:33:56 -07:00
|
|
|
&message,
|
2021-09-09 23:36:21 -07:00
|
|
|
&program_indices,
|
2021-09-21 05:41:02 -07:00
|
|
|
&account_indices,
|
2021-03-10 23:04:00 -08:00
|
|
|
&caller_write_privileges,
|
2020-04-28 14:33:56 -07:00
|
|
|
&mut invoke_context,
|
|
|
|
),
|
|
|
|
Err(InstructionError::ExternalAccountDataModified)
|
|
|
|
);
|
2021-07-05 04:49:37 -07:00
|
|
|
accounts[0].1.borrow_mut().data_as_mut_slice()[0] = 0;
|
2020-04-28 14:33:56 -07:00
|
|
|
|
2021-09-13 22:57:37 -07:00
|
|
|
// readonly account modified by the invoker
|
|
|
|
accounts[2].1.borrow_mut().data_as_mut_slice()[0] = 1;
|
|
|
|
assert_eq!(
|
|
|
|
InstructionProcessor::process_cross_program_instruction(
|
|
|
|
&message,
|
|
|
|
&program_indices,
|
2021-09-21 05:41:02 -07:00
|
|
|
&account_indices,
|
2021-09-13 22:57:37 -07:00
|
|
|
&caller_write_privileges,
|
|
|
|
&mut invoke_context,
|
|
|
|
),
|
|
|
|
Err(InstructionError::ReadonlyDataModified)
|
|
|
|
);
|
|
|
|
accounts[2].1.borrow_mut().data_as_mut_slice()[0] = 0;
|
|
|
|
|
2020-04-28 14:33:56 -07:00
|
|
|
let cases = vec![
|
|
|
|
(MockInstruction::NoopSuccess, Ok(())),
|
|
|
|
(
|
|
|
|
MockInstruction::NoopFail,
|
|
|
|
Err(InstructionError::GenericError),
|
|
|
|
),
|
|
|
|
(MockInstruction::ModifyOwned, Ok(())),
|
|
|
|
(
|
|
|
|
MockInstruction::ModifyNotOwned,
|
|
|
|
Err(InstructionError::ExternalAccountDataModified),
|
|
|
|
),
|
|
|
|
];
|
|
|
|
|
|
|
|
for case in cases {
|
2021-09-13 22:57:37 -07:00
|
|
|
let callee_instruction =
|
2021-03-03 21:46:48 -08:00
|
|
|
Instruction::new_with_bincode(callee_program_id, &case.0, metas.clone());
|
2021-09-13 22:57:37 -07:00
|
|
|
let message = Message::new(&[callee_instruction], None);
|
2021-04-19 09:48:48 -07:00
|
|
|
|
|
|
|
let ancestors = Ancestors::default();
|
2021-07-29 01:50:20 -07:00
|
|
|
let blockhash = Hash::default();
|
|
|
|
let fee_calculator = FeeCalculator::default();
|
2021-04-19 09:48:48 -07:00
|
|
|
let mut invoke_context = ThisInvokeContext::new(
|
|
|
|
&caller_program_id,
|
|
|
|
Rent::default(),
|
|
|
|
&message,
|
2021-09-13 22:57:37 -07:00
|
|
|
&caller_instruction,
|
2021-09-09 23:36:21 -07:00
|
|
|
&program_indices,
|
2021-04-19 09:48:48 -07:00
|
|
|
&accounts,
|
|
|
|
programs.as_slice(),
|
|
|
|
None,
|
2021-07-22 10:18:51 -07:00
|
|
|
ComputeBudget::default(),
|
2021-07-16 00:31:22 -07:00
|
|
|
Rc::new(RefCell::new(MockComputeMeter::default())),
|
2021-04-19 09:48:48 -07:00
|
|
|
Rc::new(RefCell::new(Executors::default())),
|
|
|
|
None,
|
|
|
|
Arc::new(FeatureSet::all_enabled()),
|
2021-08-06 13:52:27 -07:00
|
|
|
Arc::new(Accounts::default_for_tests()),
|
2021-04-19 09:48:48 -07:00
|
|
|
&ancestors,
|
2021-07-29 01:50:20 -07:00
|
|
|
&blockhash,
|
|
|
|
&fee_calculator,
|
2021-09-09 23:36:21 -07:00
|
|
|
)
|
|
|
|
.unwrap();
|
2021-04-19 09:48:48 -07:00
|
|
|
|
2021-03-10 23:04:00 -08:00
|
|
|
let caller_write_privileges = message
|
2021-01-22 15:28:01 -08:00
|
|
|
.account_keys
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
2021-09-03 20:05:30 -07:00
|
|
|
.map(|(i, _)| message.is_writable(i, demote_program_write_locks))
|
2021-01-22 15:28:01 -08:00
|
|
|
.collect::<Vec<bool>>();
|
2020-04-28 14:33:56 -07:00
|
|
|
assert_eq!(
|
2021-08-26 17:30:36 -07:00
|
|
|
InstructionProcessor::process_cross_program_instruction(
|
2020-04-28 14:33:56 -07:00
|
|
|
&message,
|
2021-09-09 23:36:21 -07:00
|
|
|
&program_indices,
|
2021-09-21 05:41:02 -07:00
|
|
|
&account_indices,
|
2021-03-10 23:04:00 -08:00
|
|
|
&caller_write_privileges,
|
2020-04-28 14:33:56 -07:00
|
|
|
&mut invoke_context,
|
|
|
|
),
|
|
|
|
case.1
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2021-09-13 22:57:37 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_native_invoke() {
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
|
|
enum MockInstruction {
|
|
|
|
NoopSuccess,
|
|
|
|
NoopFail,
|
|
|
|
ModifyOwned,
|
|
|
|
ModifyNotOwned,
|
|
|
|
ModifyReadonly,
|
|
|
|
}
|
|
|
|
|
|
|
|
fn mock_process_instruction(
|
|
|
|
program_id: &Pubkey,
|
|
|
|
data: &[u8],
|
|
|
|
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()?,
|
|
|
|
*keyed_accounts[0].unsigned_key()
|
|
|
|
);
|
|
|
|
|
|
|
|
if let Ok(instruction) = bincode::deserialize(data) {
|
|
|
|
match instruction {
|
|
|
|
MockInstruction::NoopSuccess => (),
|
|
|
|
MockInstruction::NoopFail => return Err(InstructionError::GenericError),
|
|
|
|
MockInstruction::ModifyOwned => {
|
|
|
|
keyed_accounts[0].try_account_ref_mut()?.data_as_mut_slice()[0] = 1
|
|
|
|
}
|
|
|
|
MockInstruction::ModifyNotOwned => {
|
|
|
|
keyed_accounts[1].try_account_ref_mut()?.data_as_mut_slice()[0] = 1
|
|
|
|
}
|
|
|
|
MockInstruction::ModifyReadonly => {
|
|
|
|
keyed_accounts[2].try_account_ref_mut()?.data_as_mut_slice()[0] = 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return Err(InstructionError::InvalidInstructionData);
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
let caller_program_id = solana_sdk::pubkey::new_rand();
|
|
|
|
let callee_program_id = solana_sdk::pubkey::new_rand();
|
|
|
|
|
|
|
|
let owned_account = AccountSharedData::new(42, 1, &callee_program_id);
|
|
|
|
let not_owned_account = AccountSharedData::new(84, 1, &solana_sdk::pubkey::new_rand());
|
|
|
|
let readonly_account = AccountSharedData::new(168, 1, &caller_program_id);
|
|
|
|
let mut program_account = AccountSharedData::new(1, 0, &native_loader::id());
|
|
|
|
program_account.set_executable(true);
|
|
|
|
|
|
|
|
#[allow(unused_mut)]
|
|
|
|
let accounts = vec![
|
|
|
|
(
|
|
|
|
solana_sdk::pubkey::new_rand(),
|
|
|
|
Rc::new(RefCell::new(owned_account)),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
solana_sdk::pubkey::new_rand(),
|
|
|
|
Rc::new(RefCell::new(not_owned_account)),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
solana_sdk::pubkey::new_rand(),
|
|
|
|
Rc::new(RefCell::new(readonly_account)),
|
|
|
|
),
|
|
|
|
(callee_program_id, Rc::new(RefCell::new(program_account))),
|
|
|
|
];
|
|
|
|
let program_indices = vec![3];
|
|
|
|
let programs: Vec<(_, ProcessInstructionWithContext)> =
|
|
|
|
vec![(callee_program_id, mock_process_instruction)];
|
|
|
|
let metas = vec![
|
|
|
|
AccountMeta::new(accounts[0].0, false),
|
|
|
|
AccountMeta::new(accounts[1].0, false),
|
|
|
|
AccountMeta::new_readonly(accounts[2].0, false),
|
|
|
|
];
|
|
|
|
|
|
|
|
let caller_instruction = CompiledInstruction::new(2, &(), vec![0, 1, 2, 3]);
|
|
|
|
let callee_instruction = Instruction::new_with_bincode(
|
|
|
|
callee_program_id,
|
|
|
|
&MockInstruction::NoopSuccess,
|
|
|
|
metas.clone(),
|
|
|
|
);
|
|
|
|
let message = Message::new(&[callee_instruction.clone()], None);
|
|
|
|
|
|
|
|
let feature_set = FeatureSet::all_enabled();
|
|
|
|
let ancestors = Ancestors::default();
|
|
|
|
let blockhash = Hash::default();
|
|
|
|
let fee_calculator = FeeCalculator::default();
|
|
|
|
let mut invoke_context = ThisInvokeContext::new(
|
|
|
|
&caller_program_id,
|
|
|
|
Rent::default(),
|
|
|
|
&message,
|
|
|
|
&caller_instruction,
|
|
|
|
&program_indices,
|
|
|
|
&accounts,
|
|
|
|
programs.as_slice(),
|
|
|
|
None,
|
|
|
|
ComputeBudget::default(),
|
|
|
|
Rc::new(RefCell::new(MockComputeMeter::default())),
|
|
|
|
Rc::new(RefCell::new(Executors::default())),
|
|
|
|
None,
|
|
|
|
Arc::new(feature_set),
|
|
|
|
Arc::new(Accounts::default_for_tests()),
|
|
|
|
&ancestors,
|
|
|
|
&blockhash,
|
|
|
|
&fee_calculator,
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
// not owned account modified by the invoker
|
|
|
|
accounts[0].1.borrow_mut().data_as_mut_slice()[0] = 1;
|
|
|
|
assert_eq!(
|
|
|
|
InstructionProcessor::native_invoke(
|
|
|
|
&mut invoke_context,
|
|
|
|
callee_instruction.clone(),
|
|
|
|
&[0, 1, 2, 3],
|
|
|
|
&[]
|
|
|
|
),
|
|
|
|
Err(InstructionError::ExternalAccountDataModified)
|
|
|
|
);
|
|
|
|
accounts[0].1.borrow_mut().data_as_mut_slice()[0] = 0;
|
|
|
|
|
|
|
|
// readonly account modified by the invoker
|
|
|
|
accounts[2].1.borrow_mut().data_as_mut_slice()[0] = 1;
|
|
|
|
assert_eq!(
|
|
|
|
InstructionProcessor::native_invoke(
|
|
|
|
&mut invoke_context,
|
|
|
|
callee_instruction,
|
|
|
|
&[0, 1, 2, 3],
|
|
|
|
&[]
|
|
|
|
),
|
|
|
|
Err(InstructionError::ReadonlyDataModified)
|
|
|
|
);
|
|
|
|
accounts[2].1.borrow_mut().data_as_mut_slice()[0] = 0;
|
|
|
|
|
|
|
|
// Other test cases
|
|
|
|
let cases = vec![
|
|
|
|
(MockInstruction::NoopSuccess, Ok(())),
|
|
|
|
(
|
|
|
|
MockInstruction::NoopFail,
|
|
|
|
Err(InstructionError::GenericError),
|
|
|
|
),
|
|
|
|
(MockInstruction::ModifyOwned, Ok(())),
|
|
|
|
(
|
|
|
|
MockInstruction::ModifyNotOwned,
|
|
|
|
Err(InstructionError::ExternalAccountDataModified),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
MockInstruction::ModifyReadonly,
|
|
|
|
Err(InstructionError::ReadonlyDataModified),
|
|
|
|
),
|
|
|
|
];
|
|
|
|
for case in cases {
|
|
|
|
let callee_instruction =
|
|
|
|
Instruction::new_with_bincode(callee_program_id, &case.0, metas.clone());
|
|
|
|
let message = Message::new(&[callee_instruction.clone()], None);
|
|
|
|
|
|
|
|
let ancestors = Ancestors::default();
|
|
|
|
let blockhash = Hash::default();
|
|
|
|
let fee_calculator = FeeCalculator::default();
|
|
|
|
let mut invoke_context = ThisInvokeContext::new(
|
|
|
|
&caller_program_id,
|
|
|
|
Rent::default(),
|
|
|
|
&message,
|
|
|
|
&caller_instruction,
|
|
|
|
&program_indices,
|
|
|
|
&accounts,
|
|
|
|
programs.as_slice(),
|
|
|
|
None,
|
|
|
|
ComputeBudget::default(),
|
|
|
|
Rc::new(RefCell::new(MockComputeMeter::default())),
|
|
|
|
Rc::new(RefCell::new(Executors::default())),
|
|
|
|
None,
|
|
|
|
Arc::new(FeatureSet::all_enabled()),
|
|
|
|
Arc::new(Accounts::default_for_tests()),
|
|
|
|
&ancestors,
|
|
|
|
&blockhash,
|
|
|
|
&fee_calculator,
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
InstructionProcessor::native_invoke(
|
|
|
|
&mut invoke_context,
|
|
|
|
callee_instruction,
|
|
|
|
&[0, 1, 2, 3],
|
|
|
|
&[]
|
|
|
|
),
|
|
|
|
case.1
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2019-02-18 22:26:22 -08:00
|
|
|
}
|