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