Cleanup - mock InvokeContext (#31007)
* Turns with_mock_invoke_context() into a macro. * Removes prepare_mock_invoke_context(). * Replaces InvokeContext::new_mock() with with_mock_invoke_context(). * Removes InvokeContext::new_mock(). * Removes Cow from InvokeContext::sysvar_cache. * Removes override parameters from mock_process_instruction(). * cargo fmt
This commit is contained in:
parent
9219a16c42
commit
a0c7fde90e
|
@ -37,6 +37,7 @@ use {
|
|||
account_utils::StateMut,
|
||||
bpf_loader, bpf_loader_deprecated,
|
||||
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
|
||||
feature_set::FeatureSet,
|
||||
instruction::{Instruction, InstructionError},
|
||||
loader_instruction,
|
||||
message::Message,
|
||||
|
@ -46,9 +47,7 @@ use {
|
|||
signature::{keypair_from_seed, read_keypair_file, Keypair, Signature, Signer},
|
||||
system_instruction::{self, SystemError},
|
||||
system_program,
|
||||
sysvar::rent::Rent,
|
||||
transaction::{Transaction, TransactionError},
|
||||
transaction_context::TransactionContext,
|
||||
},
|
||||
std::{
|
||||
fs::File,
|
||||
|
@ -2018,12 +2017,10 @@ fn read_and_verify_elf(program_location: &str) -> Result<Vec<u8>, Box<dyn std::e
|
|||
let mut program_data = Vec::new();
|
||||
file.read_to_end(&mut program_data)
|
||||
.map_err(|err| format!("Unable to read program file: {err}"))?;
|
||||
let mut transaction_context = TransactionContext::new(Vec::new(), Some(Rent::default()), 1, 1);
|
||||
let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
|
||||
|
||||
// Verify the program
|
||||
let loader = create_loader(
|
||||
&invoke_context.feature_set,
|
||||
&FeatureSet::default(),
|
||||
&ComputeBudget::default(),
|
||||
true,
|
||||
true,
|
||||
|
|
|
@ -31,7 +31,6 @@ use {
|
|||
},
|
||||
std::{
|
||||
alloc::Layout,
|
||||
borrow::Cow,
|
||||
cell::RefCell,
|
||||
fmt::{self, Debug},
|
||||
rc::Rc,
|
||||
|
@ -116,7 +115,7 @@ pub struct InvokeContext<'a> {
|
|||
rent: Rent,
|
||||
pre_accounts: Vec<PreAccount>,
|
||||
builtin_programs: &'a [BuiltinProgram],
|
||||
pub sysvar_cache: Cow<'a, SysvarCache>,
|
||||
sysvar_cache: &'a SysvarCache,
|
||||
pub trace_log_stack: Vec<TraceLogStackFrame>,
|
||||
log_collector: Option<Rc<RefCell<LogCollector>>>,
|
||||
compute_budget: ComputeBudget,
|
||||
|
@ -138,7 +137,7 @@ impl<'a> InvokeContext<'a> {
|
|||
transaction_context: &'a mut TransactionContext,
|
||||
rent: Rent,
|
||||
builtin_programs: &'a [BuiltinProgram],
|
||||
sysvar_cache: Cow<'a, SysvarCache>,
|
||||
sysvar_cache: &'a SysvarCache,
|
||||
log_collector: Option<Rc<RefCell<LogCollector>>>,
|
||||
compute_budget: ComputeBudget,
|
||||
tx_executor_cache: Rc<RefCell<TransactionExecutorCache>>,
|
||||
|
@ -169,43 +168,6 @@ impl<'a> InvokeContext<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new_mock(
|
||||
transaction_context: &'a mut TransactionContext,
|
||||
builtin_programs: &'a [BuiltinProgram],
|
||||
) -> Self {
|
||||
let mut sysvar_cache = SysvarCache::default();
|
||||
sysvar_cache.fill_missing_entries(|pubkey, callback| {
|
||||
for index in 0..transaction_context.get_number_of_accounts() {
|
||||
if transaction_context
|
||||
.get_key_of_account_at_index(index)
|
||||
.unwrap()
|
||||
== pubkey
|
||||
{
|
||||
callback(
|
||||
transaction_context
|
||||
.get_account_at_index(index)
|
||||
.unwrap()
|
||||
.borrow()
|
||||
.data(),
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
Self::new(
|
||||
transaction_context,
|
||||
Rent::default(),
|
||||
builtin_programs,
|
||||
Cow::Owned(sysvar_cache),
|
||||
Some(LogCollector::new_ref()),
|
||||
ComputeBudget::default(),
|
||||
Rc::new(RefCell::new(TransactionExecutorCache::default())),
|
||||
Arc::new(FeatureSet::all_enabled()),
|
||||
Hash::default(),
|
||||
0,
|
||||
0,
|
||||
)
|
||||
}
|
||||
|
||||
/// Push a stack frame onto the invocation stack
|
||||
pub fn push(&mut self) -> Result<(), InstructionError> {
|
||||
let instruction_context = self
|
||||
|
@ -807,7 +769,7 @@ impl<'a> InvokeContext<'a> {
|
|||
|
||||
/// Get cached sysvars
|
||||
pub fn get_sysvar_cache(&self) -> &SysvarCache {
|
||||
&self.sysvar_cache
|
||||
self.sysvar_cache
|
||||
}
|
||||
|
||||
// Set this instruction syscall context
|
||||
|
@ -881,16 +843,73 @@ impl<'a> InvokeContext<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct MockInvokeContextPreparation {
|
||||
pub transaction_accounts: Vec<TransactionAccount>,
|
||||
pub instruction_accounts: Vec<InstructionAccount>,
|
||||
#[macro_export]
|
||||
macro_rules! with_mock_invoke_context {
|
||||
($invoke_context:ident, $transaction_context:ident, $transaction_accounts:expr) => {
|
||||
use {
|
||||
solana_sdk::{
|
||||
account::ReadableAccount, feature_set::FeatureSet, hash::Hash, sysvar::rent::Rent,
|
||||
transaction_context::TransactionContext,
|
||||
},
|
||||
std::{cell::RefCell, rc::Rc, sync::Arc},
|
||||
$crate::{
|
||||
compute_budget::ComputeBudget, executor_cache::TransactionExecutorCache,
|
||||
invoke_context::InvokeContext, log_collector::LogCollector,
|
||||
sysvar_cache::SysvarCache,
|
||||
},
|
||||
};
|
||||
let compute_budget = ComputeBudget::default();
|
||||
let mut $transaction_context = TransactionContext::new(
|
||||
$transaction_accounts,
|
||||
Some(Rent::default()),
|
||||
compute_budget.max_invoke_stack_height,
|
||||
compute_budget.max_instruction_trace_length,
|
||||
);
|
||||
$transaction_context.enable_cap_accounts_data_allocations_per_transaction();
|
||||
let mut sysvar_cache = SysvarCache::default();
|
||||
sysvar_cache.fill_missing_entries(|pubkey, callback| {
|
||||
for index in 0..$transaction_context.get_number_of_accounts() {
|
||||
if $transaction_context
|
||||
.get_key_of_account_at_index(index)
|
||||
.unwrap()
|
||||
== pubkey
|
||||
{
|
||||
callback(
|
||||
$transaction_context
|
||||
.get_account_at_index(index)
|
||||
.unwrap()
|
||||
.borrow()
|
||||
.data(),
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
let mut $invoke_context = InvokeContext::new(
|
||||
&mut $transaction_context,
|
||||
Rent::default(),
|
||||
&[],
|
||||
&sysvar_cache,
|
||||
Some(LogCollector::new_ref()),
|
||||
compute_budget,
|
||||
Rc::new(RefCell::new(TransactionExecutorCache::default())),
|
||||
Arc::new(FeatureSet::all_enabled()),
|
||||
Hash::default(),
|
||||
0,
|
||||
0,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
pub fn prepare_mock_invoke_context(
|
||||
transaction_accounts: Vec<TransactionAccount>,
|
||||
pub fn mock_process_instruction<F: FnMut(&mut InvokeContext)>(
|
||||
loader_id: &Pubkey,
|
||||
mut program_indices: Vec<IndexOfAccount>,
|
||||
instruction_data: &[u8],
|
||||
mut transaction_accounts: Vec<TransactionAccount>,
|
||||
instruction_account_metas: Vec<AccountMeta>,
|
||||
_program_indices: &[IndexOfAccount],
|
||||
) -> MockInvokeContextPreparation {
|
||||
expected_result: Result<(), InstructionError>,
|
||||
process_instruction: ProcessInstructionWithContext,
|
||||
mut pre_adjustments: F,
|
||||
) -> Vec<AccountSharedData> {
|
||||
let mut instruction_accounts: Vec<InstructionAccount> =
|
||||
Vec::with_capacity(instruction_account_metas.len());
|
||||
for (instruction_account_index, account_meta) in instruction_account_metas.iter().enumerate() {
|
||||
|
@ -915,97 +934,19 @@ pub fn prepare_mock_invoke_context(
|
|||
is_writable: account_meta.is_writable,
|
||||
});
|
||||
}
|
||||
MockInvokeContextPreparation {
|
||||
transaction_accounts,
|
||||
instruction_accounts,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_mock_invoke_context<R, F: FnMut(&mut InvokeContext) -> R>(
|
||||
loader_id: Pubkey,
|
||||
account_size: usize,
|
||||
is_writable: bool,
|
||||
mut callback: F,
|
||||
) -> R {
|
||||
let program_indices = vec![0, 1];
|
||||
let program_key = Pubkey::new_unique();
|
||||
let transaction_accounts = vec![
|
||||
(
|
||||
loader_id,
|
||||
AccountSharedData::new(0, 0, &native_loader::id()),
|
||||
),
|
||||
(program_key, AccountSharedData::new(1, 0, &loader_id)),
|
||||
(
|
||||
Pubkey::new_unique(),
|
||||
AccountSharedData::new(2, account_size, &program_key),
|
||||
),
|
||||
];
|
||||
let instruction_accounts = vec![AccountMeta {
|
||||
pubkey: transaction_accounts.get(2).unwrap().0,
|
||||
is_signer: false,
|
||||
is_writable,
|
||||
}];
|
||||
let preparation =
|
||||
prepare_mock_invoke_context(transaction_accounts, instruction_accounts, &program_indices);
|
||||
let compute_budget = ComputeBudget::default();
|
||||
let mut transaction_context = TransactionContext::new(
|
||||
preparation.transaction_accounts,
|
||||
Some(Rent::default()),
|
||||
compute_budget.max_invoke_stack_height,
|
||||
compute_budget.max_instruction_trace_length,
|
||||
);
|
||||
transaction_context.enable_cap_accounts_data_allocations_per_transaction();
|
||||
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
|
||||
invoke_context
|
||||
.transaction_context
|
||||
.get_next_instruction_context()
|
||||
.unwrap()
|
||||
.configure(&program_indices, &preparation.instruction_accounts, &[]);
|
||||
invoke_context.push().unwrap();
|
||||
callback(&mut invoke_context)
|
||||
}
|
||||
|
||||
pub fn mock_process_instruction(
|
||||
loader_id: &Pubkey,
|
||||
mut program_indices: Vec<IndexOfAccount>,
|
||||
instruction_data: &[u8],
|
||||
transaction_accounts: Vec<TransactionAccount>,
|
||||
instruction_accounts: Vec<AccountMeta>,
|
||||
sysvar_cache_override: Option<&SysvarCache>,
|
||||
feature_set_override: Option<Arc<FeatureSet>>,
|
||||
expected_result: Result<(), InstructionError>,
|
||||
process_instruction: ProcessInstructionWithContext,
|
||||
) -> Vec<AccountSharedData> {
|
||||
program_indices.insert(0, transaction_accounts.len() as IndexOfAccount);
|
||||
let mut preparation =
|
||||
prepare_mock_invoke_context(transaction_accounts, instruction_accounts, &program_indices);
|
||||
let processor_account = AccountSharedData::new(0, 0, &native_loader::id());
|
||||
preparation
|
||||
.transaction_accounts
|
||||
.push((*loader_id, processor_account));
|
||||
let compute_budget = ComputeBudget::default();
|
||||
let mut transaction_context = TransactionContext::new(
|
||||
preparation.transaction_accounts,
|
||||
Some(Rent::default()),
|
||||
compute_budget.max_invoke_stack_height,
|
||||
compute_budget.max_instruction_trace_length,
|
||||
);
|
||||
transaction_context.enable_cap_accounts_data_allocations_per_transaction();
|
||||
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
|
||||
if let Some(sysvar_cache) = sysvar_cache_override {
|
||||
invoke_context.sysvar_cache = Cow::Borrowed(sysvar_cache);
|
||||
}
|
||||
if let Some(feature_set) = feature_set_override {
|
||||
invoke_context.feature_set = feature_set;
|
||||
}
|
||||
transaction_accounts.push((*loader_id, processor_account));
|
||||
with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
|
||||
let builtin_programs = &[BuiltinProgram {
|
||||
program_id: *loader_id,
|
||||
process_instruction,
|
||||
}];
|
||||
invoke_context.builtin_programs = builtin_programs;
|
||||
pre_adjustments(&mut invoke_context);
|
||||
let result = invoke_context.process_instruction(
|
||||
instruction_data,
|
||||
&preparation.instruction_accounts,
|
||||
&instruction_accounts,
|
||||
&program_indices,
|
||||
&mut 0,
|
||||
&mut ExecuteTimings::default(),
|
||||
|
@ -1171,13 +1112,15 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_instruction_stack_height() {
|
||||
const MAX_DEPTH: usize = 10;
|
||||
let one_more_than_max_depth = ComputeBudget::default()
|
||||
.max_invoke_stack_height
|
||||
.saturating_add(1);
|
||||
let mut invoke_stack = vec![];
|
||||
let mut accounts = vec![];
|
||||
let mut transaction_accounts = vec![];
|
||||
let mut instruction_accounts = vec![];
|
||||
for index in 0..MAX_DEPTH {
|
||||
for index in 0..one_more_than_max_depth {
|
||||
invoke_stack.push(solana_sdk::pubkey::new_rand());
|
||||
accounts.push((
|
||||
transaction_accounts.push((
|
||||
solana_sdk::pubkey::new_rand(),
|
||||
AccountSharedData::new(index as u64, 1, invoke_stack.get(index).unwrap()),
|
||||
));
|
||||
|
@ -1190,7 +1133,7 @@ mod tests {
|
|||
});
|
||||
}
|
||||
for (index, program_id) in invoke_stack.iter().enumerate() {
|
||||
accounts.push((
|
||||
transaction_accounts.push((
|
||||
*program_id,
|
||||
AccountSharedData::new(1, 1, &solana_sdk::pubkey::Pubkey::default()),
|
||||
));
|
||||
|
@ -1202,13 +1145,7 @@ mod tests {
|
|||
is_writable: false,
|
||||
});
|
||||
}
|
||||
let mut transaction_context = TransactionContext::new(
|
||||
accounts,
|
||||
Some(Rent::default()),
|
||||
ComputeBudget::default().max_invoke_stack_height,
|
||||
MAX_DEPTH,
|
||||
);
|
||||
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
|
||||
with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
|
||||
|
||||
// Check call depth increases and has a limit
|
||||
let mut depth_reached = 0;
|
||||
|
@ -1218,17 +1155,17 @@ mod tests {
|
|||
.get_next_instruction_context()
|
||||
.unwrap()
|
||||
.configure(
|
||||
&[(MAX_DEPTH + depth_reached) as IndexOfAccount],
|
||||
&[one_more_than_max_depth.saturating_add(depth_reached) as IndexOfAccount],
|
||||
&instruction_accounts,
|
||||
&[],
|
||||
);
|
||||
if Err(InstructionError::CallDepth) == invoke_context.push() {
|
||||
break;
|
||||
}
|
||||
depth_reached += 1;
|
||||
depth_reached = depth_reached.saturating_add(1);
|
||||
}
|
||||
assert_ne!(depth_reached, 0);
|
||||
assert!(depth_reached < MAX_DEPTH);
|
||||
assert!(depth_reached < one_more_than_max_depth);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1249,18 +1186,13 @@ mod tests {
|
|||
#[test]
|
||||
fn test_process_instruction() {
|
||||
let callee_program_id = solana_sdk::pubkey::new_rand();
|
||||
let builtin_programs = &[BuiltinProgram {
|
||||
program_id: callee_program_id,
|
||||
process_instruction: mock_process_instruction,
|
||||
}];
|
||||
|
||||
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, &solana_sdk::pubkey::new_rand());
|
||||
let loader_account = AccountSharedData::new(0, 0, &native_loader::id());
|
||||
let mut program_account = AccountSharedData::new(1, 0, &native_loader::id());
|
||||
program_account.set_executable(true);
|
||||
let accounts = vec![
|
||||
let transaction_accounts = vec![
|
||||
(solana_sdk::pubkey::new_rand(), owned_account),
|
||||
(solana_sdk::pubkey::new_rand(), not_owned_account),
|
||||
(solana_sdk::pubkey::new_rand(), readonly_account),
|
||||
|
@ -1268,9 +1200,9 @@ mod tests {
|
|||
(solana_sdk::pubkey::new_rand(), loader_account),
|
||||
];
|
||||
let metas = vec![
|
||||
AccountMeta::new(accounts.get(0).unwrap().0, false),
|
||||
AccountMeta::new(accounts.get(1).unwrap().0, false),
|
||||
AccountMeta::new_readonly(accounts.get(2).unwrap().0, false),
|
||||
AccountMeta::new(transaction_accounts.get(0).unwrap().0, false),
|
||||
AccountMeta::new(transaction_accounts.get(1).unwrap().0, false),
|
||||
AccountMeta::new_readonly(transaction_accounts.get(2).unwrap().0, false),
|
||||
];
|
||||
let instruction_accounts = (0..4)
|
||||
.map(|instruction_account_index| InstructionAccount {
|
||||
|
@ -1281,10 +1213,12 @@ mod tests {
|
|||
is_writable: instruction_account_index < 2,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let mut transaction_context =
|
||||
TransactionContext::new(accounts, Some(Rent::default()), 2, 18);
|
||||
let mut invoke_context =
|
||||
InvokeContext::new_mock(&mut transaction_context, builtin_programs);
|
||||
with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
|
||||
let builtin_programs = &[BuiltinProgram {
|
||||
program_id: callee_program_id,
|
||||
process_instruction: mock_process_instruction,
|
||||
}];
|
||||
invoke_context.builtin_programs = builtin_programs;
|
||||
|
||||
// Account modification tests
|
||||
let cases = vec![
|
||||
|
@ -1364,7 +1298,7 @@ mod tests {
|
|||
assert!(compute_units_consumed > 0);
|
||||
assert_eq!(
|
||||
compute_units_consumed,
|
||||
compute_units_to_consume + MOCK_BUILTIN_COMPUTE_UNIT_COST
|
||||
compute_units_to_consume.saturating_add(MOCK_BUILTIN_COMPUTE_UNIT_COST),
|
||||
);
|
||||
assert_eq!(result, expected_result);
|
||||
|
||||
|
@ -1374,11 +1308,10 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_invoke_context_compute_budget() {
|
||||
let accounts = vec![(solana_sdk::pubkey::new_rand(), AccountSharedData::default())];
|
||||
let transaction_accounts =
|
||||
vec![(solana_sdk::pubkey::new_rand(), AccountSharedData::default())];
|
||||
|
||||
let mut transaction_context =
|
||||
TransactionContext::new(accounts, Some(Rent::default()), 1, 1);
|
||||
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
|
||||
with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
|
||||
invoke_context.compute_budget =
|
||||
ComputeBudget::new(compute_budget::DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT as u64);
|
||||
|
||||
|
@ -1404,22 +1337,11 @@ mod tests {
|
|||
let dummy_account = AccountSharedData::new(10, 0, &program_key);
|
||||
let mut program_account = AccountSharedData::new(500, 500, &native_loader::id());
|
||||
program_account.set_executable(true);
|
||||
let accounts = vec![
|
||||
let transaction_accounts = vec![
|
||||
(Pubkey::new_unique(), user_account),
|
||||
(Pubkey::new_unique(), dummy_account),
|
||||
(program_key, program_account),
|
||||
];
|
||||
|
||||
let builtin_programs = [BuiltinProgram {
|
||||
program_id: program_key,
|
||||
process_instruction: mock_process_instruction,
|
||||
}];
|
||||
|
||||
let mut transaction_context =
|
||||
TransactionContext::new(accounts, Some(Rent::default()), 1, 3);
|
||||
let mut invoke_context =
|
||||
InvokeContext::new_mock(&mut transaction_context, &builtin_programs);
|
||||
|
||||
let instruction_accounts = [
|
||||
InstructionAccount {
|
||||
index_in_transaction: 0,
|
||||
|
@ -1436,11 +1358,17 @@ mod tests {
|
|||
is_writable: false,
|
||||
},
|
||||
];
|
||||
with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
|
||||
let builtin_programs = &[BuiltinProgram {
|
||||
program_id: program_key,
|
||||
process_instruction: mock_process_instruction,
|
||||
}];
|
||||
invoke_context.builtin_programs = builtin_programs;
|
||||
|
||||
// Test: Resize the account to *the same size*, so not consuming any additional size; this must succeed
|
||||
{
|
||||
let resize_delta: i64 = 0;
|
||||
let new_len = (user_account_data_len as i64 + resize_delta) as u64;
|
||||
let new_len = (user_account_data_len as i64).saturating_add(resize_delta) as u64;
|
||||
let instruction_data =
|
||||
bincode::serialize(&MockInstruction::Resize { new_len }).unwrap();
|
||||
|
||||
|
@ -1465,7 +1393,7 @@ mod tests {
|
|||
// Test: Resize the account larger; this must succeed
|
||||
{
|
||||
let resize_delta: i64 = 1;
|
||||
let new_len = (user_account_data_len as i64 + resize_delta) as u64;
|
||||
let new_len = (user_account_data_len as i64).saturating_add(resize_delta) as u64;
|
||||
let instruction_data =
|
||||
bincode::serialize(&MockInstruction::Resize { new_len }).unwrap();
|
||||
|
||||
|
@ -1490,7 +1418,7 @@ mod tests {
|
|||
// Test: Resize the account smaller; this must succeed
|
||||
{
|
||||
let resize_delta: i64 = -1;
|
||||
let new_len = (user_account_data_len as i64 + resize_delta) as u64;
|
||||
let new_len = (user_account_data_len as i64).saturating_add(resize_delta) as u64;
|
||||
let instruction_data =
|
||||
bincode::serialize(&MockInstruction::Resize { new_len }).unwrap();
|
||||
|
||||
|
|
|
@ -1725,10 +1725,9 @@ mod tests {
|
|||
instruction_data,
|
||||
transaction_accounts,
|
||||
instruction_accounts,
|
||||
None,
|
||||
None,
|
||||
expected_result,
|
||||
super::process_instruction,
|
||||
|_invoke_context| {},
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -2011,12 +2010,10 @@ mod tests {
|
|||
&[],
|
||||
vec![(program_id, program_account.clone())],
|
||||
Vec::new(),
|
||||
None,
|
||||
None,
|
||||
Err(InstructionError::ProgramFailedToComplete),
|
||||
|invoke_context: &mut InvokeContext| {
|
||||
super::process_instruction,
|
||||
|invoke_context| {
|
||||
invoke_context.mock_set_remaining(0);
|
||||
super::process_instruction(invoke_context)
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -2557,10 +2554,9 @@ mod tests {
|
|||
&instruction_data,
|
||||
transaction_accounts,
|
||||
instruction_accounts,
|
||||
None,
|
||||
None,
|
||||
expected_result,
|
||||
super::process_instruction,
|
||||
|_invoke_context| {},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -447,14 +447,14 @@ pub fn deserialize_parameters_aligned(
|
|||
mod tests {
|
||||
use {
|
||||
super::*,
|
||||
solana_program_runtime::invoke_context::{prepare_mock_invoke_context, InvokeContext},
|
||||
solana_program_runtime::with_mock_invoke_context,
|
||||
solana_sdk::{
|
||||
account::{Account, AccountSharedData, ReadableAccount, WritableAccount},
|
||||
account::{Account, AccountSharedData, WritableAccount},
|
||||
account_info::AccountInfo,
|
||||
bpf_loader,
|
||||
entrypoint::deserialize,
|
||||
instruction::AccountMeta,
|
||||
sysvar::rent::Rent,
|
||||
transaction_context::InstructionAccount,
|
||||
},
|
||||
std::{
|
||||
cell::RefCell,
|
||||
|
@ -537,13 +537,9 @@ mod tests {
|
|||
rent_epoch: 0,
|
||||
}),
|
||||
)];
|
||||
|
||||
let instruction_account_keys: Vec<Pubkey> =
|
||||
(0..num_ix_accounts).map(|_| Pubkey::new_unique()).collect();
|
||||
|
||||
for key in &instruction_account_keys {
|
||||
for _ in 0..num_ix_accounts {
|
||||
transaction_accounts.push((
|
||||
*key,
|
||||
Pubkey::new_unique(),
|
||||
AccountSharedData::from(Account {
|
||||
lamports: 0,
|
||||
data: vec![],
|
||||
|
@ -553,22 +549,19 @@ mod tests {
|
|||
}),
|
||||
));
|
||||
}
|
||||
|
||||
let mut instruction_account_metas: Vec<_> = instruction_account_keys
|
||||
.iter()
|
||||
.map(|key| AccountMeta::new_readonly(*key, false))
|
||||
let mut instruction_accounts: Vec<_> = (0..num_ix_accounts as IndexOfAccount)
|
||||
.map(|index_in_callee| InstructionAccount {
|
||||
index_in_transaction: index_in_callee + 1,
|
||||
index_in_caller: index_in_callee + 1,
|
||||
index_in_callee,
|
||||
is_signer: false,
|
||||
is_writable: false,
|
||||
})
|
||||
.collect();
|
||||
if append_dup_account {
|
||||
instruction_account_metas.push(instruction_account_metas.last().cloned().unwrap());
|
||||
instruction_accounts.push(instruction_accounts.last().cloned().unwrap());
|
||||
}
|
||||
|
||||
let program_indices = [0];
|
||||
let instruction_accounts = prepare_mock_invoke_context(
|
||||
transaction_accounts.clone(),
|
||||
instruction_account_metas,
|
||||
&program_indices,
|
||||
)
|
||||
.instruction_accounts;
|
||||
let instruction_data = vec![];
|
||||
|
||||
let mut transaction_context =
|
||||
|
@ -693,41 +686,28 @@ mod tests {
|
|||
}),
|
||||
),
|
||||
];
|
||||
let instruction_accounts = [1, 1, 2, 3, 4, 4, 5, 6]
|
||||
let instruction_accounts: Vec<InstructionAccount> = [1, 1, 2, 3, 4, 4, 5, 6]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(
|
||||
|(instruction_account_index, index_in_transaction)| AccountMeta {
|
||||
pubkey: transaction_accounts.get(index_in_transaction).unwrap().0,
|
||||
|(index_in_instruction, index_in_transaction)| InstructionAccount {
|
||||
index_in_transaction,
|
||||
index_in_caller: index_in_transaction,
|
||||
index_in_callee: index_in_transaction - 1,
|
||||
is_signer: false,
|
||||
is_writable: instruction_account_index >= 4,
|
||||
is_writable: index_in_instruction >= 4,
|
||||
},
|
||||
)
|
||||
.collect();
|
||||
let instruction_data = vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
|
||||
let program_indices = [0];
|
||||
let mut original_accounts = transaction_accounts.clone();
|
||||
let preparation = prepare_mock_invoke_context(
|
||||
transaction_accounts,
|
||||
instruction_accounts,
|
||||
&program_indices,
|
||||
);
|
||||
let mut transaction_context = TransactionContext::new(
|
||||
preparation.transaction_accounts,
|
||||
Some(Rent::default()),
|
||||
1,
|
||||
1,
|
||||
);
|
||||
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
|
||||
with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
|
||||
invoke_context
|
||||
.transaction_context
|
||||
.get_next_instruction_context()
|
||||
.unwrap()
|
||||
.configure(
|
||||
&program_indices,
|
||||
&preparation.instruction_accounts,
|
||||
&instruction_data,
|
||||
);
|
||||
.configure(&program_indices, &instruction_accounts, &instruction_data);
|
||||
invoke_context.push().unwrap();
|
||||
let instruction_context = invoke_context
|
||||
.transaction_context
|
||||
|
|
|
@ -1123,6 +1123,7 @@ mod tests {
|
|||
use {
|
||||
super::*,
|
||||
crate::allocator_bump::BpfAllocator,
|
||||
solana_program_runtime::with_mock_invoke_context,
|
||||
solana_rbpf::{
|
||||
aligned_memory::AlignedMemory, ebpf::MM_INPUT_START, memory_region::MemoryRegion,
|
||||
vm::Config,
|
||||
|
@ -1131,8 +1132,7 @@ mod tests {
|
|||
account::{Account, AccountSharedData},
|
||||
clock::Epoch,
|
||||
instruction::Instruction,
|
||||
rent::Rent,
|
||||
transaction_context::{TransactionAccount, TransactionContext},
|
||||
transaction_context::TransactionAccount,
|
||||
},
|
||||
std::{
|
||||
cell::{Cell, RefCell},
|
||||
|
@ -1168,12 +1168,7 @@ mod tests {
|
|||
.into_iter()
|
||||
.map(|a| (a.0, a.1))
|
||||
.collect::<Vec<TransactionAccount>>();
|
||||
|
||||
let program_accounts = program_accounts;
|
||||
let mut $transaction_context =
|
||||
TransactionContext::new(transaction_accounts, Some(Rent::default()), 1, 1);
|
||||
|
||||
let mut $invoke_context = InvokeContext::new_mock(&mut $transaction_context, &[]);
|
||||
with_mock_invoke_context!($invoke_context, transaction_context, transaction_accounts);
|
||||
$invoke_context
|
||||
.transaction_context
|
||||
.get_next_instruction_context()
|
||||
|
|
|
@ -1812,7 +1812,7 @@ mod tests {
|
|||
super::*,
|
||||
crate::BpfAllocator,
|
||||
core::slice,
|
||||
solana_program_runtime::{invoke_context::InvokeContext, sysvar_cache::SysvarCache},
|
||||
solana_program_runtime::{invoke_context::InvokeContext, with_mock_invoke_context},
|
||||
solana_rbpf::{
|
||||
aligned_memory::AlignedMemory,
|
||||
ebpf::{self, HOST_ALIGN},
|
||||
|
@ -1820,17 +1820,16 @@ mod tests {
|
|||
vm::{BuiltInFunction, Config},
|
||||
},
|
||||
solana_sdk::{
|
||||
account::AccountSharedData,
|
||||
account::{create_account_shared_data_for_test, AccountSharedData},
|
||||
bpf_loader,
|
||||
fee_calculator::FeeCalculator,
|
||||
hash::hashv,
|
||||
instruction::Instruction,
|
||||
program::check_type_assumptions,
|
||||
stable_layout::stable_instruction::StableInstruction,
|
||||
sysvar::{clock::Clock, epoch_schedule::EpochSchedule, rent::Rent},
|
||||
transaction_context::TransactionContext,
|
||||
sysvar::{self, clock::Clock, epoch_schedule::EpochSchedule},
|
||||
},
|
||||
std::{borrow::Cow, cell::RefCell, mem, rc::Rc, str::FromStr},
|
||||
std::{mem, str::FromStr},
|
||||
};
|
||||
|
||||
macro_rules! assert_access_violation {
|
||||
|
@ -1847,7 +1846,6 @@ mod tests {
|
|||
|
||||
macro_rules! prepare_mockup {
|
||||
($invoke_context:ident,
|
||||
$transaction_context:ident,
|
||||
$program_key:ident,
|
||||
$loader_key:expr $(,)?) => {
|
||||
let $program_key = Pubkey::new_unique();
|
||||
|
@ -1858,9 +1856,7 @@ mod tests {
|
|||
),
|
||||
($program_key, AccountSharedData::new(0, 0, &$loader_key)),
|
||||
];
|
||||
let mut $transaction_context =
|
||||
TransactionContext::new(transaction_accounts, Some(Rent::default()), 1, 1);
|
||||
let mut $invoke_context = InvokeContext::new_mock(&mut $transaction_context, &[]);
|
||||
with_mock_invoke_context!($invoke_context, transaction_context, transaction_accounts);
|
||||
$invoke_context
|
||||
.transaction_context
|
||||
.get_next_instruction_context()
|
||||
|
@ -2062,12 +2058,7 @@ mod tests {
|
|||
#[test]
|
||||
#[should_panic(expected = "UserError(SyscallError(Abort))")]
|
||||
fn test_syscall_abort() {
|
||||
prepare_mockup!(
|
||||
invoke_context,
|
||||
transaction_context,
|
||||
program_id,
|
||||
bpf_loader::id(),
|
||||
);
|
||||
prepare_mockup!(invoke_context, program_id, bpf_loader::id());
|
||||
let config = Config::default();
|
||||
let mut memory_mapping = MemoryMapping::new(vec![], &config).unwrap();
|
||||
let mut result = ProgramResult::Ok(0);
|
||||
|
@ -2087,12 +2078,7 @@ mod tests {
|
|||
#[test]
|
||||
#[should_panic(expected = "UserError(SyscallError(Panic(\"Gaggablaghblagh!\", 42, 84)))")]
|
||||
fn test_syscall_sol_panic() {
|
||||
prepare_mockup!(
|
||||
invoke_context,
|
||||
transaction_context,
|
||||
program_id,
|
||||
bpf_loader::id(),
|
||||
);
|
||||
prepare_mockup!(invoke_context, program_id, bpf_loader::id());
|
||||
|
||||
let string = "Gaggablaghblagh!";
|
||||
let config = Config::default();
|
||||
|
@ -2138,12 +2124,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_syscall_sol_log() {
|
||||
prepare_mockup!(
|
||||
invoke_context,
|
||||
transaction_context,
|
||||
program_id,
|
||||
bpf_loader::id(),
|
||||
);
|
||||
prepare_mockup!(invoke_context, program_id, bpf_loader::id());
|
||||
|
||||
let string = "Gaggablaghblagh!";
|
||||
let config = Config::default();
|
||||
|
@ -2221,12 +2202,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_syscall_sol_log_u64() {
|
||||
prepare_mockup!(
|
||||
invoke_context,
|
||||
transaction_context,
|
||||
program_id,
|
||||
bpf_loader::id(),
|
||||
);
|
||||
prepare_mockup!(invoke_context, program_id, bpf_loader::id());
|
||||
let cost = invoke_context.get_compute_budget().log_64_units;
|
||||
|
||||
invoke_context.mock_set_remaining(cost);
|
||||
|
@ -2257,12 +2233,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_syscall_sol_pubkey() {
|
||||
prepare_mockup!(
|
||||
invoke_context,
|
||||
transaction_context,
|
||||
program_id,
|
||||
bpf_loader::id(),
|
||||
);
|
||||
prepare_mockup!(invoke_context, program_id, bpf_loader::id());
|
||||
let cost = invoke_context.get_compute_budget().log_pubkey_units;
|
||||
|
||||
let pubkey = Pubkey::from_str("MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN").unwrap();
|
||||
|
@ -2335,12 +2306,7 @@ mod tests {
|
|||
|
||||
// large alloc
|
||||
{
|
||||
prepare_mockup!(
|
||||
invoke_context,
|
||||
transaction_context,
|
||||
program_id,
|
||||
bpf_loader::id(),
|
||||
);
|
||||
prepare_mockup!(invoke_context, program_id, bpf_loader::id());
|
||||
let mut heap = AlignedMemory::<HOST_ALIGN>::zero_filled(100);
|
||||
let mut memory_mapping = MemoryMapping::new(
|
||||
vec![
|
||||
|
@ -2400,12 +2366,7 @@ mod tests {
|
|||
|
||||
// many small unaligned allocs
|
||||
{
|
||||
prepare_mockup!(
|
||||
invoke_context,
|
||||
transaction_context,
|
||||
program_id,
|
||||
bpf_loader::id(),
|
||||
);
|
||||
prepare_mockup!(invoke_context, program_id, bpf_loader::id());
|
||||
let mut heap = AlignedMemory::<HOST_ALIGN>::zero_filled(100);
|
||||
let mut memory_mapping = MemoryMapping::new(
|
||||
vec![
|
||||
|
@ -2455,12 +2416,7 @@ mod tests {
|
|||
|
||||
// many small aligned allocs
|
||||
{
|
||||
prepare_mockup!(
|
||||
invoke_context,
|
||||
transaction_context,
|
||||
program_id,
|
||||
bpf_loader::id(),
|
||||
);
|
||||
prepare_mockup!(invoke_context, program_id, bpf_loader::id());
|
||||
let mut heap = AlignedMemory::<HOST_ALIGN>::zero_filled(100);
|
||||
let mut memory_mapping = MemoryMapping::new(
|
||||
vec![
|
||||
|
@ -2511,12 +2467,7 @@ mod tests {
|
|||
// aligned allocs
|
||||
|
||||
fn aligned<T>() {
|
||||
prepare_mockup!(
|
||||
invoke_context,
|
||||
transaction_context,
|
||||
program_id,
|
||||
bpf_loader::id(),
|
||||
);
|
||||
prepare_mockup!(invoke_context, program_id, bpf_loader::id());
|
||||
let mut heap = AlignedMemory::<HOST_ALIGN>::zero_filled(100);
|
||||
let config = Config::default();
|
||||
let mut memory_mapping = MemoryMapping::new(
|
||||
|
@ -2565,12 +2516,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_syscall_sha256() {
|
||||
let config = Config::default();
|
||||
prepare_mockup!(
|
||||
invoke_context,
|
||||
transaction_context,
|
||||
program_id,
|
||||
bpf_loader_deprecated::id(),
|
||||
);
|
||||
prepare_mockup!(invoke_context, program_id, bpf_loader_deprecated::id());
|
||||
|
||||
let bytes1 = "Gaggablaghblagh!";
|
||||
let bytes2 = "flurbos";
|
||||
|
@ -2685,12 +2631,7 @@ mod tests {
|
|||
use solana_zk_token_sdk::curve25519::curve_syscall_traits::CURVE25519_EDWARDS;
|
||||
|
||||
let config = Config::default();
|
||||
prepare_mockup!(
|
||||
invoke_context,
|
||||
transaction_context,
|
||||
program_id,
|
||||
bpf_loader::id(),
|
||||
);
|
||||
prepare_mockup!(invoke_context, program_id, bpf_loader::id());
|
||||
|
||||
let valid_bytes: [u8; 32] = [
|
||||
201, 179, 241, 122, 180, 185, 239, 50, 183, 52, 221, 0, 153, 195, 43, 18, 22, 38, 187,
|
||||
|
@ -2770,12 +2711,7 @@ mod tests {
|
|||
use solana_zk_token_sdk::curve25519::curve_syscall_traits::CURVE25519_RISTRETTO;
|
||||
|
||||
let config = Config::default();
|
||||
prepare_mockup!(
|
||||
invoke_context,
|
||||
transaction_context,
|
||||
program_id,
|
||||
bpf_loader::id(),
|
||||
);
|
||||
prepare_mockup!(invoke_context, program_id, bpf_loader::id());
|
||||
|
||||
let valid_bytes: [u8; 32] = [
|
||||
226, 242, 174, 10, 106, 188, 78, 113, 168, 132, 169, 97, 197, 0, 81, 95, 88, 227, 11,
|
||||
|
@ -2857,12 +2793,7 @@ mod tests {
|
|||
};
|
||||
|
||||
let config = Config::default();
|
||||
prepare_mockup!(
|
||||
invoke_context,
|
||||
transaction_context,
|
||||
program_id,
|
||||
bpf_loader::id(),
|
||||
);
|
||||
prepare_mockup!(invoke_context, program_id, bpf_loader::id());
|
||||
|
||||
let left_point: [u8; 32] = [
|
||||
33, 124, 71, 170, 117, 69, 151, 247, 59, 12, 95, 125, 133, 166, 64, 5, 2, 27, 90, 27,
|
||||
|
@ -3034,12 +2965,7 @@ mod tests {
|
|||
};
|
||||
|
||||
let config = Config::default();
|
||||
prepare_mockup!(
|
||||
invoke_context,
|
||||
transaction_context,
|
||||
program_id,
|
||||
bpf_loader::id(),
|
||||
);
|
||||
prepare_mockup!(invoke_context, program_id, bpf_loader::id());
|
||||
|
||||
let left_point: [u8; 32] = [
|
||||
208, 165, 125, 204, 2, 100, 218, 17, 170, 194, 23, 9, 102, 156, 134, 136, 217, 190, 98,
|
||||
|
@ -3213,12 +3139,7 @@ mod tests {
|
|||
};
|
||||
|
||||
let config = Config::default();
|
||||
prepare_mockup!(
|
||||
invoke_context,
|
||||
transaction_context,
|
||||
program_id,
|
||||
bpf_loader::id(),
|
||||
);
|
||||
prepare_mockup!(invoke_context, program_id, bpf_loader::id());
|
||||
|
||||
let scalar_a: [u8; 32] = [
|
||||
254, 198, 23, 138, 67, 243, 184, 110, 236, 115, 236, 205, 205, 215, 79, 114, 45, 250,
|
||||
|
@ -3378,13 +3299,25 @@ mod tests {
|
|||
sysvar_cache.set_fees(src_fees.clone());
|
||||
sysvar_cache.set_rent(src_rent);
|
||||
|
||||
prepare_mockup!(
|
||||
invoke_context,
|
||||
transaction_context,
|
||||
program_id,
|
||||
bpf_loader::id(),
|
||||
);
|
||||
invoke_context.sysvar_cache = Cow::Owned(sysvar_cache);
|
||||
let transaction_accounts = vec![
|
||||
(
|
||||
sysvar::clock::id(),
|
||||
create_account_shared_data_for_test(&src_clock),
|
||||
),
|
||||
(
|
||||
sysvar::epoch_schedule::id(),
|
||||
create_account_shared_data_for_test(&src_epochschedule),
|
||||
),
|
||||
(
|
||||
sysvar::fees::id(),
|
||||
create_account_shared_data_for_test(&src_fees),
|
||||
),
|
||||
(
|
||||
sysvar::rent::id(),
|
||||
create_account_shared_data_for_test(&src_rent),
|
||||
),
|
||||
];
|
||||
with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
|
||||
|
||||
// Test clock sysvar
|
||||
{
|
||||
|
@ -3635,12 +3568,7 @@ mod tests {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
prepare_mockup!(
|
||||
invoke_context,
|
||||
transaction_context,
|
||||
program_id,
|
||||
bpf_loader::id(),
|
||||
);
|
||||
prepare_mockup!(invoke_context, program_id, bpf_loader::id());
|
||||
|
||||
let mut result = ProgramResult::Ok(0);
|
||||
SyscallSetReturnData::call(
|
||||
|
@ -3700,13 +3628,20 @@ mod tests {
|
|||
})
|
||||
.collect::<Vec<_>>();
|
||||
let instruction_trace = [1, 2, 3, 2, 2, 3, 4, 3];
|
||||
let mut transaction_context =
|
||||
TransactionContext::new(transaction_accounts, None, 4, instruction_trace.len());
|
||||
with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
|
||||
for (index_in_trace, stack_height) in instruction_trace.into_iter().enumerate() {
|
||||
while stack_height <= transaction_context.get_instruction_context_stack_height() {
|
||||
transaction_context.pop().unwrap();
|
||||
while stack_height
|
||||
<= invoke_context
|
||||
.transaction_context
|
||||
.get_instruction_context_stack_height()
|
||||
{
|
||||
invoke_context.transaction_context.pop().unwrap();
|
||||
}
|
||||
if stack_height > transaction_context.get_instruction_context_stack_height() {
|
||||
if stack_height
|
||||
> invoke_context
|
||||
.transaction_context
|
||||
.get_instruction_context_stack_height()
|
||||
{
|
||||
let instruction_accounts = [InstructionAccount {
|
||||
index_in_transaction: index_in_trace.saturating_add(1) as IndexOfAccount,
|
||||
index_in_caller: 0, // This is incorrect / inconsistent but not required
|
||||
|
@ -3714,14 +3649,14 @@ mod tests {
|
|||
is_signer: false,
|
||||
is_writable: false,
|
||||
}];
|
||||
transaction_context
|
||||
invoke_context
|
||||
.transaction_context
|
||||
.get_next_instruction_context()
|
||||
.unwrap()
|
||||
.configure(&[0], &instruction_accounts, &[index_in_trace as u8]);
|
||||
transaction_context.push().unwrap();
|
||||
invoke_context.transaction_context.push().unwrap();
|
||||
}
|
||||
}
|
||||
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
|
||||
|
||||
let syscall_base_cost = invoke_context.get_compute_budget().syscall_base_cost;
|
||||
|
||||
|
@ -3840,12 +3775,7 @@ mod tests {
|
|||
fn test_create_program_address() {
|
||||
// These tests duplicate the direct tests in solana_program::pubkey
|
||||
|
||||
prepare_mockup!(
|
||||
invoke_context,
|
||||
transaction_context,
|
||||
program_id,
|
||||
bpf_loader::id(),
|
||||
);
|
||||
prepare_mockup!(invoke_context, program_id, bpf_loader::id());
|
||||
let address = bpf_loader_upgradeable::id();
|
||||
|
||||
let exceeded_seed = &[127; MAX_SEED_LEN + 1];
|
||||
|
@ -3954,12 +3884,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_find_program_address() {
|
||||
prepare_mockup!(
|
||||
invoke_context,
|
||||
transaction_context,
|
||||
program_id,
|
||||
bpf_loader::id(),
|
||||
);
|
||||
prepare_mockup!(invoke_context, program_id, bpf_loader::id());
|
||||
let cost = invoke_context
|
||||
.get_compute_budget()
|
||||
.create_program_address_units;
|
||||
|
|
|
@ -170,10 +170,9 @@ mod tests {
|
|||
instruction_data,
|
||||
transaction_accounts,
|
||||
instruction_accounts,
|
||||
None,
|
||||
None,
|
||||
expected_result,
|
||||
super::process_instruction,
|
||||
|_invoke_context| {},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -642,10 +642,9 @@ mod tests {
|
|||
instruction_data,
|
||||
transaction_accounts,
|
||||
instruction_accounts,
|
||||
None,
|
||||
None,
|
||||
expected_result,
|
||||
super::process_instruction,
|
||||
|_invoke_context| {},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -15,10 +15,7 @@ use {
|
|||
create_ebpf_vm, create_vm, serialization::serialize_parameters, syscalls::create_loader,
|
||||
},
|
||||
solana_measure::measure::Measure,
|
||||
solana_program_runtime::{
|
||||
compute_budget::ComputeBudget,
|
||||
invoke_context::{with_mock_invoke_context, InvokeContext},
|
||||
},
|
||||
solana_program_runtime::{compute_budget::ComputeBudget, invoke_context::InvokeContext},
|
||||
solana_rbpf::{
|
||||
ebpf::MM_INPUT_START,
|
||||
elf::Executable,
|
||||
|
@ -33,13 +30,17 @@ use {
|
|||
loader_utils::{load_program, load_program_from_file},
|
||||
},
|
||||
solana_sdk::{
|
||||
account::AccountSharedData,
|
||||
bpf_loader,
|
||||
client::SyncClient,
|
||||
entrypoint::SUCCESS,
|
||||
feature_set::FeatureSet,
|
||||
instruction::{AccountMeta, Instruction},
|
||||
message::Message,
|
||||
native_loader,
|
||||
pubkey::Pubkey,
|
||||
signature::Signer,
|
||||
transaction_context::InstructionAccount,
|
||||
},
|
||||
std::{mem, sync::Arc},
|
||||
test::Bencher,
|
||||
|
@ -48,6 +49,41 @@ use {
|
|||
const ARMSTRONG_LIMIT: u64 = 500;
|
||||
const ARMSTRONG_EXPECTED: u64 = 5;
|
||||
|
||||
macro_rules! with_mock_invoke_context {
|
||||
($invoke_context:ident, $loader_id:expr, $account_size:expr) => {
|
||||
let program_key = Pubkey::new_unique();
|
||||
let transaction_accounts = vec![
|
||||
(
|
||||
$loader_id,
|
||||
AccountSharedData::new(0, 0, &native_loader::id()),
|
||||
),
|
||||
(program_key, AccountSharedData::new(1, 0, &$loader_id)),
|
||||
(
|
||||
Pubkey::new_unique(),
|
||||
AccountSharedData::new(2, $account_size, &program_key),
|
||||
),
|
||||
];
|
||||
let instruction_accounts = vec![InstructionAccount {
|
||||
index_in_transaction: 2,
|
||||
index_in_caller: 2,
|
||||
index_in_callee: 0,
|
||||
is_signer: false,
|
||||
is_writable: false,
|
||||
}];
|
||||
solana_program_runtime::with_mock_invoke_context!(
|
||||
$invoke_context,
|
||||
transaction_context,
|
||||
transaction_accounts
|
||||
);
|
||||
$invoke_context
|
||||
.transaction_context
|
||||
.get_next_instruction_context()
|
||||
.unwrap()
|
||||
.configure(&[0, 1], &instruction_accounts, &[]);
|
||||
$invoke_context.push().unwrap();
|
||||
};
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_program_create_executable(bencher: &mut Bencher) {
|
||||
let elf = load_program_from_file("bench_alu");
|
||||
|
@ -75,82 +111,81 @@ fn bench_program_alu(bencher: &mut Bencher) {
|
|||
.unwrap();
|
||||
inner_iter.write_u64::<LittleEndian>(0).unwrap();
|
||||
let elf = load_program_from_file("bench_alu");
|
||||
let loader_id = bpf_loader::id();
|
||||
with_mock_invoke_context(loader_id, 10000001, false, |invoke_context| {
|
||||
let loader = create_loader(
|
||||
&invoke_context.feature_set,
|
||||
&ComputeBudget::default(),
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
let executable = Executable::<InvokeContext>::from_elf(&elf, loader).unwrap();
|
||||
with_mock_invoke_context!(invoke_context, bpf_loader::id(), 10000001);
|
||||
|
||||
let mut verified_executable =
|
||||
VerifiedExecutable::<RequisiteVerifier, InvokeContext>::from_executable(executable)
|
||||
.unwrap();
|
||||
let loader = create_loader(
|
||||
&invoke_context.feature_set,
|
||||
&ComputeBudget::default(),
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
let executable = Executable::<InvokeContext>::from_elf(&elf, loader).unwrap();
|
||||
|
||||
verified_executable.jit_compile().unwrap();
|
||||
create_vm!(
|
||||
vm,
|
||||
&verified_executable,
|
||||
stack,
|
||||
heap,
|
||||
vec![MemoryRegion::new_writable(&mut inner_iter, MM_INPUT_START)],
|
||||
vec![],
|
||||
invoke_context
|
||||
);
|
||||
let mut vm = vm.unwrap();
|
||||
let mut verified_executable =
|
||||
VerifiedExecutable::<RequisiteVerifier, InvokeContext>::from_executable(executable)
|
||||
.unwrap();
|
||||
|
||||
println!("Interpreted:");
|
||||
verified_executable.jit_compile().unwrap();
|
||||
create_vm!(
|
||||
vm,
|
||||
&verified_executable,
|
||||
stack,
|
||||
heap,
|
||||
vec![MemoryRegion::new_writable(&mut inner_iter, MM_INPUT_START)],
|
||||
vec![],
|
||||
&mut invoke_context
|
||||
);
|
||||
let mut vm = vm.unwrap();
|
||||
|
||||
println!("Interpreted:");
|
||||
vm.env
|
||||
.context_object_pointer
|
||||
.mock_set_remaining(std::i64::MAX as u64);
|
||||
let (instructions, result) = vm.execute_program(true);
|
||||
assert_eq!(SUCCESS, result.unwrap());
|
||||
assert_eq!(ARMSTRONG_LIMIT, LittleEndian::read_u64(&inner_iter));
|
||||
assert_eq!(
|
||||
ARMSTRONG_EXPECTED,
|
||||
LittleEndian::read_u64(&inner_iter[mem::size_of::<u64>()..])
|
||||
);
|
||||
|
||||
bencher.iter(|| {
|
||||
vm.env
|
||||
.context_object_pointer
|
||||
.mock_set_remaining(std::i64::MAX as u64);
|
||||
let (instructions, result) = vm.execute_program(true);
|
||||
assert_eq!(SUCCESS, result.unwrap());
|
||||
assert_eq!(ARMSTRONG_LIMIT, LittleEndian::read_u64(&inner_iter));
|
||||
assert_eq!(
|
||||
ARMSTRONG_EXPECTED,
|
||||
LittleEndian::read_u64(&inner_iter[mem::size_of::<u64>()..])
|
||||
);
|
||||
|
||||
bencher.iter(|| {
|
||||
vm.env
|
||||
.context_object_pointer
|
||||
.mock_set_remaining(std::i64::MAX as u64);
|
||||
vm.execute_program(true).1.unwrap();
|
||||
});
|
||||
let summary = bencher.bench(|_bencher| Ok(())).unwrap().unwrap();
|
||||
println!(" {:?} instructions", instructions);
|
||||
println!(" {:?} ns/iter median", summary.median as u64);
|
||||
assert!(0f64 != summary.median);
|
||||
let mips = (instructions * (ns_per_s / summary.median as u64)) / one_million;
|
||||
println!(" {:?} MIPS", mips);
|
||||
println!("{{ \"type\": \"bench\", \"name\": \"bench_program_alu_interpreted_mips\", \"median\": {:?}, \"deviation\": 0 }}", mips);
|
||||
|
||||
println!("JIT to native:");
|
||||
assert_eq!(SUCCESS, vm.execute_program(false).1.unwrap());
|
||||
assert_eq!(ARMSTRONG_LIMIT, LittleEndian::read_u64(&inner_iter));
|
||||
assert_eq!(
|
||||
ARMSTRONG_EXPECTED,
|
||||
LittleEndian::read_u64(&inner_iter[mem::size_of::<u64>()..])
|
||||
);
|
||||
|
||||
bencher.iter(|| {
|
||||
vm.env
|
||||
.context_object_pointer
|
||||
.mock_set_remaining(std::i64::MAX as u64);
|
||||
vm.execute_program(false).1.unwrap();
|
||||
});
|
||||
let summary = bencher.bench(|_bencher| Ok(())).unwrap().unwrap();
|
||||
println!(" {:?} instructions", instructions);
|
||||
println!(" {:?} ns/iter median", summary.median as u64);
|
||||
assert!(0f64 != summary.median);
|
||||
let mips = (instructions * (ns_per_s / summary.median as u64)) / one_million;
|
||||
println!(" {:?} MIPS", mips);
|
||||
println!("{{ \"type\": \"bench\", \"name\": \"bench_program_alu_jit_to_native_mips\", \"median\": {:?}, \"deviation\": 0 }}", mips);
|
||||
vm.execute_program(true).1.unwrap();
|
||||
});
|
||||
let summary = bencher.bench(|_bencher| Ok(())).unwrap().unwrap();
|
||||
println!(" {:?} instructions", instructions);
|
||||
println!(" {:?} ns/iter median", summary.median as u64);
|
||||
assert!(0f64 != summary.median);
|
||||
let mips = (instructions * (ns_per_s / summary.median as u64)) / one_million;
|
||||
println!(" {:?} MIPS", mips);
|
||||
println!("{{ \"type\": \"bench\", \"name\": \"bench_program_alu_interpreted_mips\", \"median\": {:?}, \"deviation\": 0 }}", mips);
|
||||
|
||||
println!("JIT to native:");
|
||||
assert_eq!(SUCCESS, vm.execute_program(false).1.unwrap());
|
||||
assert_eq!(ARMSTRONG_LIMIT, LittleEndian::read_u64(&inner_iter));
|
||||
assert_eq!(
|
||||
ARMSTRONG_EXPECTED,
|
||||
LittleEndian::read_u64(&inner_iter[mem::size_of::<u64>()..])
|
||||
);
|
||||
|
||||
bencher.iter(|| {
|
||||
vm.env
|
||||
.context_object_pointer
|
||||
.mock_set_remaining(std::i64::MAX as u64);
|
||||
vm.execute_program(false).1.unwrap();
|
||||
});
|
||||
let summary = bencher.bench(|_bencher| Ok(())).unwrap().unwrap();
|
||||
println!(" {:?} instructions", instructions);
|
||||
println!(" {:?} ns/iter median", summary.median as u64);
|
||||
assert!(0f64 != summary.median);
|
||||
let mips = (instructions * (ns_per_s / summary.median as u64)) / one_million;
|
||||
println!(" {:?} MIPS", mips);
|
||||
println!("{{ \"type\": \"bench\", \"name\": \"bench_program_alu_jit_to_native_mips\", \"median\": {:?}, \"deviation\": 0 }}", mips);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
|
@ -190,111 +225,107 @@ fn bench_program_execute_noop(bencher: &mut Bencher) {
|
|||
#[bench]
|
||||
fn bench_create_vm(bencher: &mut Bencher) {
|
||||
let elf = load_program_from_file("noop");
|
||||
let loader_id = bpf_loader::id();
|
||||
with_mock_invoke_context(loader_id, 10000001, false, |invoke_context| {
|
||||
const BUDGET: u64 = 200_000;
|
||||
invoke_context.mock_set_remaining(BUDGET);
|
||||
with_mock_invoke_context!(invoke_context, bpf_loader::id(), 10000001);
|
||||
const BUDGET: u64 = 200_000;
|
||||
invoke_context.mock_set_remaining(BUDGET);
|
||||
|
||||
let loader = create_loader(
|
||||
&invoke_context.feature_set,
|
||||
&ComputeBudget::default(),
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
let executable = Executable::<InvokeContext>::from_elf(&elf, loader).unwrap();
|
||||
let loader = create_loader(
|
||||
&invoke_context.feature_set,
|
||||
&ComputeBudget::default(),
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
let executable = Executable::<InvokeContext>::from_elf(&elf, loader).unwrap();
|
||||
|
||||
let verified_executable =
|
||||
VerifiedExecutable::<RequisiteVerifier, InvokeContext>::from_executable(executable)
|
||||
.unwrap();
|
||||
let verified_executable =
|
||||
VerifiedExecutable::<RequisiteVerifier, InvokeContext>::from_executable(executable)
|
||||
.unwrap();
|
||||
|
||||
// Serialize account data
|
||||
let (_serialized, regions, account_lengths) = serialize_parameters(
|
||||
invoke_context.transaction_context,
|
||||
invoke_context
|
||||
.transaction_context
|
||||
.get_current_instruction_context()
|
||||
.unwrap(),
|
||||
true, // should_cap_ix_accounts
|
||||
)
|
||||
.unwrap();
|
||||
// Serialize account data
|
||||
let (_serialized, regions, account_lengths) = serialize_parameters(
|
||||
invoke_context.transaction_context,
|
||||
invoke_context
|
||||
.transaction_context
|
||||
.get_current_instruction_context()
|
||||
.unwrap(),
|
||||
true, // should_cap_ix_accounts
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
bencher.iter(|| {
|
||||
create_vm!(
|
||||
vm,
|
||||
&verified_executable,
|
||||
stack,
|
||||
heap,
|
||||
clone_regions(®ions),
|
||||
account_lengths.clone(),
|
||||
invoke_context
|
||||
);
|
||||
let _ = vm.unwrap();
|
||||
});
|
||||
bencher.iter(|| {
|
||||
create_vm!(
|
||||
vm,
|
||||
&verified_executable,
|
||||
stack,
|
||||
heap,
|
||||
clone_regions(®ions),
|
||||
account_lengths.clone(),
|
||||
&mut invoke_context
|
||||
);
|
||||
let _ = vm.unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
|
||||
let elf = load_program_from_file("tuner");
|
||||
let loader_id = bpf_loader::id();
|
||||
with_mock_invoke_context(loader_id, 10000001, true, |invoke_context| {
|
||||
const BUDGET: u64 = 200_000;
|
||||
invoke_context.mock_set_remaining(BUDGET);
|
||||
with_mock_invoke_context!(invoke_context, bpf_loader::id(), 10000001);
|
||||
const BUDGET: u64 = 200_000;
|
||||
invoke_context.mock_set_remaining(BUDGET);
|
||||
|
||||
// Serialize account data
|
||||
let (_serialized, regions, account_lengths) = serialize_parameters(
|
||||
invoke_context.transaction_context,
|
||||
invoke_context
|
||||
.transaction_context
|
||||
.get_current_instruction_context()
|
||||
.unwrap(),
|
||||
true, // should_cap_ix_accounts
|
||||
)
|
||||
.unwrap();
|
||||
// Serialize account data
|
||||
let (_serialized, regions, account_lengths) = serialize_parameters(
|
||||
invoke_context.transaction_context,
|
||||
invoke_context
|
||||
.transaction_context
|
||||
.get_current_instruction_context()
|
||||
.unwrap(),
|
||||
true, // should_cap_ix_accounts
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let loader = create_loader(
|
||||
&invoke_context.feature_set,
|
||||
&ComputeBudget::default(),
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
let executable = Executable::<InvokeContext>::from_elf(&elf, loader).unwrap();
|
||||
let loader = create_loader(
|
||||
&invoke_context.feature_set,
|
||||
&ComputeBudget::default(),
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
let executable = Executable::<InvokeContext>::from_elf(&elf, loader).unwrap();
|
||||
|
||||
let verified_executable =
|
||||
VerifiedExecutable::<RequisiteVerifier, InvokeContext>::from_executable(executable)
|
||||
.unwrap();
|
||||
let verified_executable =
|
||||
VerifiedExecutable::<RequisiteVerifier, InvokeContext>::from_executable(executable)
|
||||
.unwrap();
|
||||
|
||||
create_vm!(
|
||||
vm,
|
||||
&verified_executable,
|
||||
stack,
|
||||
heap,
|
||||
regions,
|
||||
account_lengths,
|
||||
invoke_context
|
||||
);
|
||||
let mut vm = vm.unwrap();
|
||||
create_vm!(
|
||||
vm,
|
||||
&verified_executable,
|
||||
stack,
|
||||
heap,
|
||||
regions,
|
||||
account_lengths,
|
||||
&mut invoke_context
|
||||
);
|
||||
let mut vm = vm.unwrap();
|
||||
|
||||
let mut measure = Measure::start("tune");
|
||||
let (instructions, _result) = vm.execute_program(true);
|
||||
measure.stop();
|
||||
let mut measure = Measure::start("tune");
|
||||
let (instructions, _result) = vm.execute_program(true);
|
||||
measure.stop();
|
||||
|
||||
assert_eq!(
|
||||
0,
|
||||
vm.env.context_object_pointer.get_remaining(),
|
||||
"Tuner must consume the whole budget"
|
||||
);
|
||||
println!(
|
||||
"{:?} compute units took {:?} us ({:?} instructions)",
|
||||
BUDGET - vm.env.context_object_pointer.get_remaining(),
|
||||
measure.as_us(),
|
||||
instructions,
|
||||
);
|
||||
});
|
||||
assert_eq!(
|
||||
0,
|
||||
vm.env.context_object_pointer.get_remaining(),
|
||||
"Tuner must consume the whole budget"
|
||||
);
|
||||
println!(
|
||||
"{:?} compute units took {:?} us ({:?} instructions)",
|
||||
BUDGET - vm.env.context_object_pointer.get_remaining(),
|
||||
measure.as_us(),
|
||||
instructions,
|
||||
);
|
||||
}
|
||||
|
||||
fn clone_regions(regions: &[MemoryRegion]) -> Vec<MemoryRegion> {
|
||||
|
|
|
@ -22,6 +22,7 @@ use {
|
|||
solana_program_runtime::{
|
||||
compute_budget::ComputeBudget, invoke_context::InvokeContext, timings::ExecuteTimings,
|
||||
},
|
||||
solana_rbpf::vm::ContextObject,
|
||||
solana_runtime::{
|
||||
bank::{
|
||||
DurableNonceFee, InnerInstruction, TransactionBalancesSet, TransactionExecutionDetails,
|
||||
|
@ -60,13 +61,7 @@ use {
|
|||
std::collections::HashMap,
|
||||
};
|
||||
use {
|
||||
solana_bpf_loader_program::{
|
||||
create_ebpf_vm, create_vm,
|
||||
serialization::{deserialize_parameters, serialize_parameters},
|
||||
syscalls::create_loader,
|
||||
},
|
||||
solana_program_runtime::invoke_context::with_mock_invoke_context,
|
||||
solana_rbpf::{elf::Executable, verifier::RequisiteVerifier, vm::VerifiedExecutable},
|
||||
solana_program_runtime::invoke_context::mock_process_instruction,
|
||||
solana_runtime::{
|
||||
bank::Bank,
|
||||
bank_client::BankClient,
|
||||
|
@ -80,7 +75,6 @@ use {
|
|||
bpf_loader, bpf_loader_deprecated,
|
||||
client::SyncClient,
|
||||
clock::UnixTimestamp,
|
||||
entrypoint::SUCCESS,
|
||||
fee_calculator::FeeRateGovernor,
|
||||
genesis_config::ClusterType,
|
||||
hash::Hash,
|
||||
|
@ -95,131 +89,6 @@ use {
|
|||
std::{str::FromStr, sync::Arc, time::Duration},
|
||||
};
|
||||
|
||||
fn run_program(name: &str) -> u64 {
|
||||
let elf = load_program_from_file(name);
|
||||
let loader_id = bpf_loader::id();
|
||||
with_mock_invoke_context(loader_id, 0, false, |invoke_context| {
|
||||
let loader = create_loader(
|
||||
&invoke_context.feature_set,
|
||||
&ComputeBudget::default(),
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
)
|
||||
.unwrap();
|
||||
let executable = Executable::<InvokeContext>::from_elf(&elf, loader).unwrap();
|
||||
|
||||
#[allow(unused_mut)]
|
||||
let mut verified_executable =
|
||||
VerifiedExecutable::<RequisiteVerifier, InvokeContext>::from_executable(executable)
|
||||
.unwrap();
|
||||
|
||||
let run_program_iterations = {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
verified_executable.jit_compile().unwrap();
|
||||
2
|
||||
}
|
||||
#[cfg(not(target_arch = "x86_64"))]
|
||||
1
|
||||
};
|
||||
|
||||
let mut instruction_count = 0;
|
||||
let mut trace_log = None;
|
||||
for i in 0..run_program_iterations {
|
||||
let transaction_context = &mut invoke_context.transaction_context;
|
||||
let instruction_context = transaction_context
|
||||
.get_current_instruction_context()
|
||||
.unwrap();
|
||||
let caller = *instruction_context
|
||||
.get_last_program_key(transaction_context)
|
||||
.unwrap();
|
||||
transaction_context
|
||||
.set_return_data(caller, Vec::new())
|
||||
.unwrap();
|
||||
|
||||
let (parameter_bytes, regions, account_lengths) = serialize_parameters(
|
||||
invoke_context.transaction_context,
|
||||
invoke_context
|
||||
.transaction_context
|
||||
.get_current_instruction_context()
|
||||
.unwrap(),
|
||||
true, // should_cap_ix_accounts
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
{
|
||||
create_vm!(
|
||||
vm,
|
||||
&verified_executable,
|
||||
stack,
|
||||
heap,
|
||||
regions,
|
||||
account_lengths.clone(),
|
||||
invoke_context
|
||||
);
|
||||
let mut vm = vm.unwrap();
|
||||
let (compute_units_consumed, result) = vm.execute_program(i == 0);
|
||||
assert_eq!(SUCCESS, result.unwrap());
|
||||
if i == 1 {
|
||||
assert_eq!(instruction_count, compute_units_consumed);
|
||||
}
|
||||
instruction_count = compute_units_consumed;
|
||||
if i == 0 {
|
||||
trace_log = Some(
|
||||
vm.env
|
||||
.context_object_pointer
|
||||
.trace_log_stack
|
||||
.last()
|
||||
.expect("Inconsistent trace log stack")
|
||||
.trace_log
|
||||
.clone(),
|
||||
);
|
||||
} else {
|
||||
let interpreter = trace_log.as_ref().unwrap().as_slice();
|
||||
let mut jit = vm
|
||||
.env
|
||||
.context_object_pointer
|
||||
.trace_log_stack
|
||||
.last()
|
||||
.expect("Inconsistent trace log stack")
|
||||
.trace_log
|
||||
.as_slice();
|
||||
if jit.len() > interpreter.len() {
|
||||
jit = &jit[0..interpreter.len()];
|
||||
}
|
||||
assert_eq!(interpreter, jit);
|
||||
trace_log = None;
|
||||
}
|
||||
}
|
||||
assert!(match deserialize_parameters(
|
||||
invoke_context.transaction_context,
|
||||
invoke_context
|
||||
.transaction_context
|
||||
.get_current_instruction_context()
|
||||
.unwrap(),
|
||||
parameter_bytes.as_slice(),
|
||||
&account_lengths,
|
||||
) {
|
||||
Ok(()) => true,
|
||||
Err(InstructionError::ModifiedProgramId) => true,
|
||||
Err(InstructionError::ExternalAccountLamportSpend) => true,
|
||||
Err(InstructionError::ReadonlyLamportChange) => true,
|
||||
Err(InstructionError::ExecutableLamportChange) => true,
|
||||
Err(InstructionError::ExecutableAccountNotRentExempt) => true,
|
||||
Err(InstructionError::ExecutableModified) => true,
|
||||
Err(InstructionError::AccountDataSizeChanged) => true,
|
||||
Err(InstructionError::InvalidRealloc) => true,
|
||||
Err(InstructionError::ExecutableDataModified) => true,
|
||||
Err(InstructionError::ReadonlyDataModified) => true,
|
||||
Err(InstructionError::ExternalAccountDataModified) => true,
|
||||
_ => false,
|
||||
});
|
||||
}
|
||||
instruction_count
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "sbf_rust")]
|
||||
fn process_transaction_and_record_inner(
|
||||
bank: &Bank,
|
||||
|
@ -1503,8 +1372,8 @@ fn assert_instruction_count() {
|
|||
("noop++", 5),
|
||||
("relative_call", 210),
|
||||
("return_data", 980),
|
||||
("sanity", 2377),
|
||||
("sanity++", 2277),
|
||||
("sanity", 3259),
|
||||
("sanity++", 3159),
|
||||
("secp256k1_recover", 25383),
|
||||
("sha", 1355),
|
||||
("struct_pass", 108),
|
||||
|
@ -1526,30 +1395,70 @@ fn assert_instruction_count() {
|
|||
("solana_sbf_rust_noop", 275),
|
||||
("solana_sbf_rust_param_passing", 146),
|
||||
("solana_sbf_rust_rand", 378),
|
||||
("solana_sbf_rust_sanity", 51931),
|
||||
("solana_sbf_rust_sanity", 10759),
|
||||
("solana_sbf_rust_secp256k1_recover", 91185),
|
||||
("solana_sbf_rust_sha", 24059),
|
||||
]);
|
||||
}
|
||||
|
||||
let mut passed = true;
|
||||
println!("\n {:36} expected actual diff", "SBF program");
|
||||
for program in programs.iter() {
|
||||
let count = run_program(program.0);
|
||||
let diff: i64 = count as i64 - program.1 as i64;
|
||||
println!(
|
||||
" {:36} {:8} {:6} {:+5} ({:+3.0}%)",
|
||||
program.0,
|
||||
program.1,
|
||||
count,
|
||||
diff,
|
||||
100.0_f64 * count as f64 / program.1 as f64 - 100.0_f64,
|
||||
for (program_name, expected_consumption) in programs.iter() {
|
||||
let loader_id = bpf_loader::id();
|
||||
let program_key = Pubkey::new_unique();
|
||||
let mut transaction_accounts = vec![
|
||||
(program_key, AccountSharedData::new(0, 0, &loader_id)),
|
||||
(
|
||||
Pubkey::new_unique(),
|
||||
AccountSharedData::new(0, 8, &program_key),
|
||||
),
|
||||
];
|
||||
let instruction_accounts = vec![AccountMeta {
|
||||
pubkey: transaction_accounts[1].0,
|
||||
is_signer: false,
|
||||
is_writable: false,
|
||||
}];
|
||||
transaction_accounts[0]
|
||||
.1
|
||||
.set_data_from_slice(&load_program_from_file(program_name));
|
||||
transaction_accounts[0].1.set_executable(true);
|
||||
transaction_accounts[1]
|
||||
.1
|
||||
.set_state(expected_consumption)
|
||||
.unwrap();
|
||||
|
||||
print!(" {:36} {:8}", program_name, *expected_consumption);
|
||||
mock_process_instruction(
|
||||
&loader_id,
|
||||
vec![0],
|
||||
&[],
|
||||
transaction_accounts,
|
||||
instruction_accounts,
|
||||
Ok(()),
|
||||
|invoke_context: &mut InvokeContext| {
|
||||
let expected_consumption: u64 = invoke_context
|
||||
.transaction_context
|
||||
.get_current_instruction_context()
|
||||
.unwrap()
|
||||
.try_borrow_instruction_account(&invoke_context.transaction_context, 0)
|
||||
.unwrap()
|
||||
.get_state()
|
||||
.unwrap();
|
||||
let prev_compute_meter = invoke_context.get_remaining();
|
||||
let _result = solana_bpf_loader_program::process_instruction(invoke_context);
|
||||
let consumption = prev_compute_meter.saturating_sub(invoke_context.get_remaining());
|
||||
let diff: i64 = consumption as i64 - expected_consumption as i64;
|
||||
println!(
|
||||
"{:6} {:+5} ({:+3.0}%)",
|
||||
consumption,
|
||||
diff,
|
||||
100.0_f64 * consumption as f64 / expected_consumption as f64 - 100.0_f64,
|
||||
);
|
||||
assert_eq!(consumption, expected_consumption);
|
||||
Ok(())
|
||||
},
|
||||
|_invoke_context| {},
|
||||
);
|
||||
if count > program.1 {
|
||||
passed = false;
|
||||
}
|
||||
}
|
||||
assert!(passed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1779,13 +1779,12 @@ mod tests {
|
|||
use {
|
||||
super::*,
|
||||
proptest::prelude::*,
|
||||
solana_program_runtime::invoke_context::InvokeContext,
|
||||
solana_program_runtime::with_mock_invoke_context,
|
||||
solana_sdk::{
|
||||
account::{create_account_shared_data_for_test, AccountSharedData},
|
||||
native_token,
|
||||
pubkey::Pubkey,
|
||||
sysvar::SysvarId,
|
||||
transaction_context::TransactionContext,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -2916,18 +2915,6 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
fn create_mock_tx_context() -> TransactionContext {
|
||||
TransactionContext::new(
|
||||
vec![(
|
||||
Rent::id(),
|
||||
create_account_shared_data_for_test(&Rent::default()),
|
||||
)],
|
||||
Some(Rent::default()),
|
||||
1,
|
||||
1,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lockup_is_expired() {
|
||||
let custodian = solana_sdk::pubkey::new_rand();
|
||||
|
@ -3034,9 +3021,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_things_can_merge() {
|
||||
let mut transaction_context =
|
||||
TransactionContext::new(Vec::new(), Some(Rent::default()), 1, 1);
|
||||
let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
|
||||
with_mock_invoke_context!(invoke_context, transaction_context, Vec::new());
|
||||
let good_stake = Stake {
|
||||
credits_observed: 4242,
|
||||
delegation: Delegation {
|
||||
|
@ -3134,9 +3119,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_metas_can_merge() {
|
||||
let mut transaction_context =
|
||||
TransactionContext::new(Vec::new(), Some(Rent::default()), 1, 1);
|
||||
let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
|
||||
with_mock_invoke_context!(invoke_context, transaction_context, Vec::new());
|
||||
// Identical Metas can merge
|
||||
assert!(MergeKind::metas_can_merge(
|
||||
&invoke_context,
|
||||
|
@ -3282,9 +3265,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_merge_kind_get_if_mergeable() {
|
||||
let mut transaction_context =
|
||||
TransactionContext::new(Vec::new(), Some(Rent::default()), 1, 1);
|
||||
let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
|
||||
with_mock_invoke_context!(invoke_context, transaction_context, Vec::new());
|
||||
let authority_pubkey = Pubkey::new_unique();
|
||||
let initial_lamports = 4242424242;
|
||||
let rent = Rent::default();
|
||||
|
@ -3522,9 +3503,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_merge_kind_merge() {
|
||||
let mut transaction_context =
|
||||
TransactionContext::new(Vec::new(), Some(Rent::default()), 1, 1);
|
||||
let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
|
||||
with_mock_invoke_context!(invoke_context, transaction_context, Vec::new());
|
||||
let clock = Clock::default();
|
||||
let lamports = 424242;
|
||||
let meta = Meta {
|
||||
|
@ -3603,8 +3582,11 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_active_stake_merge() {
|
||||
let mut transaction_context = create_mock_tx_context();
|
||||
let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
|
||||
let transaction_accounts = vec![(
|
||||
Rent::id(),
|
||||
create_account_shared_data_for_test(&Rent::default()),
|
||||
)];
|
||||
with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
|
||||
let clock = Clock::default();
|
||||
let delegation_a = 4_242_424_242u64;
|
||||
let delegation_b = 6_200_000_000u64;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
extern crate test;
|
||||
|
||||
use {
|
||||
solana_program_runtime::invoke_context::InvokeContext,
|
||||
solana_program_runtime::with_mock_invoke_context,
|
||||
solana_sdk::{
|
||||
account::{create_account_for_test, Account, AccountSharedData},
|
||||
clock::{Clock, Slot},
|
||||
|
@ -11,9 +11,7 @@ use {
|
|||
pubkey::Pubkey,
|
||||
slot_hashes::{SlotHashes, MAX_ENTRIES},
|
||||
sysvar,
|
||||
transaction_context::{
|
||||
IndexOfAccount, InstructionAccount, TransactionAccount, TransactionContext,
|
||||
},
|
||||
transaction_context::{IndexOfAccount, InstructionAccount, TransactionAccount},
|
||||
},
|
||||
solana_vote_program::{
|
||||
vote_instruction::VoteInstruction,
|
||||
|
@ -109,13 +107,8 @@ fn bench_process_vote_instruction(
|
|||
instruction_data: Vec<u8>,
|
||||
) {
|
||||
bencher.iter(|| {
|
||||
let mut transaction_context = TransactionContext::new(
|
||||
transaction_accounts.clone(),
|
||||
Some(sysvar::rent::Rent::default()),
|
||||
1,
|
||||
1,
|
||||
);
|
||||
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
|
||||
let transaction_accounts = transaction_accounts.clone();
|
||||
with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
|
||||
invoke_context
|
||||
.transaction_context
|
||||
.get_next_instruction_context()
|
||||
|
|
|
@ -326,10 +326,9 @@ mod tests {
|
|||
instruction_data,
|
||||
transaction_accounts,
|
||||
instruction_accounts,
|
||||
None,
|
||||
None,
|
||||
expected_result,
|
||||
super::process_instruction,
|
||||
|_invoke_context| {},
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -345,10 +344,11 @@ mod tests {
|
|||
instruction_data,
|
||||
transaction_accounts,
|
||||
instruction_accounts,
|
||||
None,
|
||||
Some(std::sync::Arc::new(FeatureSet::default())),
|
||||
expected_result,
|
||||
super::process_instruction,
|
||||
|invoke_context| {
|
||||
invoke_context.feature_set = std::sync::Arc::new(FeatureSet::default());
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -5,17 +5,16 @@ use {
|
|||
solana_bpf_loader_program::{
|
||||
create_ebpf_vm, create_vm, serialization::serialize_parameters, syscalls::create_loader,
|
||||
},
|
||||
solana_program_runtime::{
|
||||
compute_budget::ComputeBudget,
|
||||
invoke_context::{prepare_mock_invoke_context, InvokeContext},
|
||||
},
|
||||
solana_program_runtime::{invoke_context::InvokeContext, with_mock_invoke_context},
|
||||
solana_rbpf::{
|
||||
assembler::assemble, elf::Executable, static_analysis::Analysis,
|
||||
verifier::RequisiteVerifier, vm::VerifiedExecutable,
|
||||
},
|
||||
solana_sdk::{
|
||||
account::AccountSharedData, bpf_loader, instruction::AccountMeta, pubkey::Pubkey,
|
||||
sysvar::rent::Rent, transaction_context::TransactionContext,
|
||||
account::AccountSharedData,
|
||||
bpf_loader,
|
||||
pubkey::Pubkey,
|
||||
transaction_context::{IndexOfAccount, InstructionAccount},
|
||||
},
|
||||
std::{
|
||||
fmt::{Debug, Formatter},
|
||||
|
@ -186,8 +185,10 @@ before execting it in the virtual machine.",
|
|||
pubkey,
|
||||
AccountSharedData::new(0, allocation_size, &Pubkey::new_unique()),
|
||||
));
|
||||
instruction_accounts.push(AccountMeta {
|
||||
pubkey,
|
||||
instruction_accounts.push(InstructionAccount {
|
||||
index_in_transaction: 0,
|
||||
index_in_caller: 0,
|
||||
index_in_callee: 0,
|
||||
is_signer: false,
|
||||
is_writable: true,
|
||||
});
|
||||
|
@ -195,43 +196,32 @@ before execting it in the virtual machine.",
|
|||
}
|
||||
Err(_) => {
|
||||
let input = load_accounts(Path::new(matches.value_of("input").unwrap())).unwrap();
|
||||
for account_info in input.accounts {
|
||||
for (index, account_info) in input.accounts.into_iter().enumerate() {
|
||||
let mut account = AccountSharedData::new(
|
||||
account_info.lamports,
|
||||
account_info.data.len(),
|
||||
&account_info.owner,
|
||||
);
|
||||
account.set_data(account_info.data);
|
||||
instruction_accounts.push(AccountMeta {
|
||||
pubkey: account_info.key,
|
||||
transaction_accounts.push((account_info.key, account));
|
||||
instruction_accounts.push(InstructionAccount {
|
||||
index_in_transaction: index as IndexOfAccount,
|
||||
index_in_caller: index as IndexOfAccount,
|
||||
index_in_callee: index as IndexOfAccount,
|
||||
is_signer: account_info.is_signer,
|
||||
is_writable: account_info.is_writable,
|
||||
});
|
||||
transaction_accounts.push((account_info.key, account));
|
||||
}
|
||||
input.instruction_data
|
||||
}
|
||||
};
|
||||
let program_indices = [0, 1];
|
||||
let preparation =
|
||||
prepare_mock_invoke_context(transaction_accounts, instruction_accounts, &program_indices);
|
||||
let mut transaction_context = TransactionContext::new(
|
||||
preparation.transaction_accounts,
|
||||
Some(Rent::default()),
|
||||
1,
|
||||
1,
|
||||
);
|
||||
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
|
||||
with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
|
||||
invoke_context.enable_instruction_tracing = true;
|
||||
invoke_context
|
||||
.transaction_context
|
||||
.get_next_instruction_context()
|
||||
.unwrap()
|
||||
.configure(
|
||||
&program_indices,
|
||||
&preparation.instruction_accounts,
|
||||
&instruction_data,
|
||||
);
|
||||
.configure(&[0, 1], &instruction_accounts, &instruction_data);
|
||||
invoke_context.push().unwrap();
|
||||
let (_parameter_bytes, regions, account_lengths) = serialize_parameters(
|
||||
invoke_context.transaction_context,
|
||||
|
|
|
@ -8050,10 +8050,9 @@ fn test_bpf_loader_upgradeable_deploy_with_max_len() {
|
|||
(program_keypair.pubkey(), post_program_account),
|
||||
],
|
||||
Vec::new(),
|
||||
None,
|
||||
None,
|
||||
Ok(()),
|
||||
solana_bpf_loader_program::process_instruction,
|
||||
|_invoke_context| {},
|
||||
);
|
||||
|
||||
// Test initialized program account
|
||||
|
|
|
@ -21,7 +21,7 @@ use {
|
|||
transaction::TransactionError,
|
||||
transaction_context::{IndexOfAccount, InstructionAccount, TransactionContext},
|
||||
},
|
||||
std::{borrow::Cow, cell::RefCell, rc::Rc, sync::Arc},
|
||||
std::{cell::RefCell, rc::Rc, sync::Arc},
|
||||
};
|
||||
|
||||
#[derive(Debug, Default, Clone, Deserialize, Serialize)]
|
||||
|
@ -71,7 +71,7 @@ impl MessageProcessor {
|
|||
transaction_context,
|
||||
rent,
|
||||
builtin_programs,
|
||||
Cow::Borrowed(sysvar_cache),
|
||||
sysvar_cache,
|
||||
log_collector,
|
||||
compute_budget,
|
||||
tx_executor_cache,
|
||||
|
|
|
@ -272,15 +272,15 @@ mod test {
|
|||
use {
|
||||
super::*,
|
||||
assert_matches::assert_matches,
|
||||
solana_program_runtime::invoke_context::InvokeContext,
|
||||
solana_program_runtime::with_mock_invoke_context,
|
||||
solana_sdk::{
|
||||
account::AccountSharedData,
|
||||
hash::{hash, Hash},
|
||||
hash::hash,
|
||||
nonce::{self, State},
|
||||
nonce_account::{create_account, verify_nonce_account},
|
||||
system_instruction::SystemError,
|
||||
system_program,
|
||||
transaction_context::{InstructionAccount, TransactionContext},
|
||||
transaction_context::InstructionAccount,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -309,7 +309,7 @@ mod test {
|
|||
..Rent::default()
|
||||
};
|
||||
let from_lamports = $rent.minimum_balance(State::size()) + 42;
|
||||
let accounts = vec![
|
||||
let transaction_accounts = vec![
|
||||
(
|
||||
Pubkey::new_unique(),
|
||||
create_account(from_lamports).into_inner(),
|
||||
|
@ -333,9 +333,7 @@ mod test {
|
|||
is_writable: true,
|
||||
},
|
||||
];
|
||||
let mut transaction_context =
|
||||
TransactionContext::new(accounts, Some(Rent::default()), 1, 1);
|
||||
let mut $invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
|
||||
with_mock_invoke_context!($invoke_context, transaction_context, transaction_accounts);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -612,14 +612,14 @@ mod tests {
|
|||
system_instruction, system_program,
|
||||
sysvar::{self, recent_blockhashes::IterItem, rent::Rent},
|
||||
transaction::TransactionError,
|
||||
transaction_context::TransactionContext,
|
||||
};
|
||||
use {
|
||||
super::*,
|
||||
crate::{bank::Bank, bank_client::BankClient},
|
||||
bincode::serialize,
|
||||
solana_program_runtime::invoke_context::{
|
||||
mock_process_instruction, InvokeContext, ProcessInstructionWithContext,
|
||||
solana_program_runtime::{
|
||||
invoke_context::{mock_process_instruction, ProcessInstructionWithContext},
|
||||
with_mock_invoke_context,
|
||||
},
|
||||
std::sync::Arc,
|
||||
};
|
||||
|
@ -646,10 +646,9 @@ mod tests {
|
|||
instruction_data,
|
||||
transaction_accounts,
|
||||
instruction_accounts,
|
||||
None,
|
||||
None,
|
||||
expected_result,
|
||||
process_instruction,
|
||||
|_invoke_context| {},
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -793,9 +792,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_address_create_with_seed_mismatch() {
|
||||
let mut transaction_context =
|
||||
TransactionContext::new(Vec::new(), Some(Rent::default()), 1, 1);
|
||||
let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
|
||||
with_mock_invoke_context!(invoke_context, transaction_context, Vec::new());
|
||||
let from = Pubkey::new_unique();
|
||||
let seed = "dull boy";
|
||||
let to = Pubkey::new_unique();
|
||||
|
|
Loading…
Reference in New Issue