Feature: TransactionContext, InstructionContext and BorrowedAccount (#21706)
* Adds TransactionContext, InstructionContext and BorrowedAccount. * Redirects the usage of accounts in InvokeContext through TransactionContext. Also use the types declared in transaction_context.rs everywhere. * Adjusts all affected tests.
This commit is contained in:
parent
bb97c8fdcd
commit
a06646631c
|
@ -42,6 +42,7 @@ use {
|
|||
system_instruction::{self, SystemError},
|
||||
system_program,
|
||||
transaction::{Transaction, TransactionError},
|
||||
transaction_context::TransactionContext,
|
||||
},
|
||||
std::{
|
||||
fs::File,
|
||||
|
@ -1990,7 +1991,8 @@ fn read_and_verify_elf(program_location: &str) -> Result<Vec<u8>, Box<dyn std::e
|
|||
let mut program_data = Vec::new();
|
||||
file.read_to_end(&mut program_data)
|
||||
.map_err(|err| format!("Unable to read program file: {}", err))?;
|
||||
let mut invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
|
||||
// Verify the program
|
||||
Executable::<BpfError, ThisInstructionMeter>::from_elf(
|
||||
|
|
|
@ -20,20 +20,11 @@ use {
|
|||
pubkey::Pubkey,
|
||||
rent::Rent,
|
||||
sysvar::Sysvar,
|
||||
transaction_context::{InstructionAccount, TransactionAccount, TransactionContext},
|
||||
},
|
||||
std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc, sync::Arc},
|
||||
};
|
||||
|
||||
pub type TransactionAccountRefCell = (Pubkey, RefCell<AccountSharedData>);
|
||||
pub type TransactionAccountRefCells = Vec<TransactionAccountRefCell>;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct InstructionAccount {
|
||||
pub index: usize,
|
||||
pub is_signer: bool,
|
||||
pub is_writable: bool,
|
||||
}
|
||||
|
||||
pub type ProcessInstructionWithContext =
|
||||
fn(usize, &[u8], &mut InvokeContext) -> Result<(), InstructionError>;
|
||||
|
||||
|
@ -144,10 +135,11 @@ impl<'a> StackFrame<'a> {
|
|||
}
|
||||
|
||||
pub struct InvokeContext<'a> {
|
||||
pub transaction_context: &'a TransactionContext,
|
||||
pub return_data: (Pubkey, Vec<u8>),
|
||||
invoke_stack: Vec<StackFrame<'a>>,
|
||||
rent: Rent,
|
||||
pre_accounts: Vec<PreAccount>,
|
||||
accounts: &'a [TransactionAccountRefCell],
|
||||
builtin_programs: &'a [BuiltinProgram],
|
||||
pub sysvars: &'a [(Pubkey, Vec<u8>)],
|
||||
log_collector: Option<Rc<RefCell<LogCollector>>>,
|
||||
|
@ -160,14 +152,13 @@ pub struct InvokeContext<'a> {
|
|||
pub timings: ExecuteDetailsTimings,
|
||||
pub blockhash: Hash,
|
||||
pub lamports_per_signature: u64,
|
||||
pub return_data: (Pubkey, Vec<u8>),
|
||||
}
|
||||
|
||||
impl<'a> InvokeContext<'a> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
transaction_context: &'a TransactionContext,
|
||||
rent: Rent,
|
||||
accounts: &'a [TransactionAccountRefCell],
|
||||
builtin_programs: &'a [BuiltinProgram],
|
||||
sysvars: &'a [(Pubkey, Vec<u8>)],
|
||||
log_collector: Option<Rc<RefCell<LogCollector>>>,
|
||||
|
@ -179,10 +170,11 @@ impl<'a> InvokeContext<'a> {
|
|||
lamports_per_signature: u64,
|
||||
) -> Self {
|
||||
Self {
|
||||
transaction_context,
|
||||
return_data: (Pubkey::default(), Vec::new()),
|
||||
invoke_stack: Vec::with_capacity(compute_budget.max_invoke_depth),
|
||||
rent,
|
||||
pre_accounts: Vec::new(),
|
||||
accounts,
|
||||
builtin_programs,
|
||||
sysvars,
|
||||
log_collector,
|
||||
|
@ -195,17 +187,16 @@ impl<'a> InvokeContext<'a> {
|
|||
timings: ExecuteDetailsTimings::default(),
|
||||
blockhash,
|
||||
lamports_per_signature,
|
||||
return_data: (Pubkey::default(), Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_mock(
|
||||
accounts: &'a [TransactionAccountRefCell],
|
||||
transaction_context: &'a TransactionContext,
|
||||
builtin_programs: &'a [BuiltinProgram],
|
||||
) -> Self {
|
||||
Self::new(
|
||||
transaction_context,
|
||||
Rent::default(),
|
||||
accounts,
|
||||
builtin_programs,
|
||||
&[],
|
||||
Some(LogCollector::new_ref()),
|
||||
|
@ -228,9 +219,10 @@ impl<'a> InvokeContext<'a> {
|
|||
return Err(InstructionError::CallDepth);
|
||||
}
|
||||
|
||||
let program_id = program_indices
|
||||
.last()
|
||||
.map(|index_of_program_id| &self.accounts[*index_of_program_id].0);
|
||||
let program_id = program_indices.last().map(|account_index| {
|
||||
self.transaction_context
|
||||
.get_key_of_account_at_index(*account_index)
|
||||
});
|
||||
if program_id.is_none()
|
||||
&& self
|
||||
.feature_set
|
||||
|
@ -262,10 +254,17 @@ impl<'a> InvokeContext<'a> {
|
|||
|
||||
self.pre_accounts = Vec::with_capacity(instruction_accounts.len());
|
||||
let mut work = |_index_in_instruction: usize, entry: &InstructionAccount| {
|
||||
if entry.index < self.accounts.len() {
|
||||
let account = self.accounts[entry.index].1.borrow().clone();
|
||||
self.pre_accounts
|
||||
.push(PreAccount::new(&self.accounts[entry.index].0, account));
|
||||
if entry.index < self.transaction_context.get_number_of_accounts() {
|
||||
let account = self
|
||||
.transaction_context
|
||||
.get_account_at_index(entry.index)
|
||||
.borrow()
|
||||
.clone();
|
||||
self.pre_accounts.push(PreAccount::new(
|
||||
self.transaction_context
|
||||
.get_key_of_account_at_index(entry.index),
|
||||
account,
|
||||
));
|
||||
return Ok(());
|
||||
}
|
||||
Err(InstructionError::MissingAccount)
|
||||
|
@ -294,16 +293,20 @@ impl<'a> InvokeContext<'a> {
|
|||
(
|
||||
false,
|
||||
false,
|
||||
&self.accounts[*account_index].0,
|
||||
&self.accounts[*account_index].1 as &RefCell<AccountSharedData>,
|
||||
self.transaction_context
|
||||
.get_key_of_account_at_index(*account_index),
|
||||
self.transaction_context
|
||||
.get_account_at_index(*account_index),
|
||||
)
|
||||
})
|
||||
.chain(instruction_accounts.iter().map(|instruction_account| {
|
||||
(
|
||||
instruction_account.is_signer,
|
||||
instruction_account.is_writable,
|
||||
&self.accounts[instruction_account.index].0,
|
||||
&self.accounts[instruction_account.index].1 as &RefCell<AccountSharedData>,
|
||||
self.transaction_context
|
||||
.get_key_of_account_at_index(instruction_account.index),
|
||||
self.transaction_context
|
||||
.get_account_at_index(instruction_account.index),
|
||||
)
|
||||
}))
|
||||
.collect::<Vec<_>>();
|
||||
|
@ -340,8 +343,8 @@ impl<'a> InvokeContext<'a> {
|
|||
|
||||
// Verify all executable accounts have zero outstanding refs
|
||||
for account_index in program_indices.iter() {
|
||||
self.accounts[*account_index]
|
||||
.1
|
||||
self.transaction_context
|
||||
.get_account_at_index(*account_index)
|
||||
.try_borrow_mut()
|
||||
.map_err(|_| InstructionError::AccountBorrowOutstanding)?;
|
||||
}
|
||||
|
@ -352,14 +355,18 @@ impl<'a> InvokeContext<'a> {
|
|||
let mut work = |_index_in_instruction: usize, instruction_account: &InstructionAccount| {
|
||||
{
|
||||
// Verify account has no outstanding references
|
||||
let _ = self.accounts[instruction_account.index]
|
||||
.1
|
||||
let _ = self
|
||||
.transaction_context
|
||||
.get_account_at_index(instruction_account.index)
|
||||
.try_borrow_mut()
|
||||
.map_err(|_| InstructionError::AccountBorrowOutstanding)?;
|
||||
}
|
||||
let pre_account = &self.pre_accounts[pre_account_index];
|
||||
pre_account_index = pre_account_index.saturating_add(1);
|
||||
let account = self.accounts[instruction_account.index].1.borrow();
|
||||
let account = self
|
||||
.transaction_context
|
||||
.get_account_at_index(instruction_account.index)
|
||||
.borrow();
|
||||
pre_account
|
||||
.verify(
|
||||
program_id,
|
||||
|
@ -410,15 +417,17 @@ impl<'a> InvokeContext<'a> {
|
|||
.ok_or(InstructionError::CallDepth)?;
|
||||
let rent = &self.rent;
|
||||
let log_collector = &self.log_collector;
|
||||
let accounts = &self.accounts;
|
||||
let transaction_context = self.transaction_context;
|
||||
let pre_accounts = &mut self.pre_accounts;
|
||||
let timings = &mut self.timings;
|
||||
|
||||
// Verify the per-account instruction results
|
||||
let (mut pre_sum, mut post_sum) = (0_u128, 0_u128);
|
||||
let mut work = |index_in_instruction: usize, instruction_account: &InstructionAccount| {
|
||||
if instruction_account.index < accounts.len() {
|
||||
let (key, account) = &accounts[instruction_account.index];
|
||||
if instruction_account.index < transaction_context.get_number_of_accounts() {
|
||||
let key =
|
||||
transaction_context.get_key_of_account_at_index(instruction_account.index);
|
||||
let account = transaction_context.get_account_at_index(instruction_account.index);
|
||||
let is_writable = if let Some(caller_write_privileges) = caller_write_privileges {
|
||||
caller_write_privileges[index_in_instruction]
|
||||
} else {
|
||||
|
@ -487,8 +496,9 @@ impl<'a> InvokeContext<'a> {
|
|||
self.prepare_instruction(&instruction, signers)?;
|
||||
let mut prev_account_sizes = Vec::with_capacity(instruction_accounts.len());
|
||||
for instruction_account in instruction_accounts.iter() {
|
||||
let account_length = self.accounts[instruction_account.index]
|
||||
.1
|
||||
let account_length = self
|
||||
.transaction_context
|
||||
.get_account_at_index(instruction_account.index)
|
||||
.borrow()
|
||||
.data()
|
||||
.len();
|
||||
|
@ -506,7 +516,13 @@ impl<'a> InvokeContext<'a> {
|
|||
let do_support_realloc = self.feature_set.is_active(&do_support_realloc::id());
|
||||
for (account_index, prev_size) in prev_account_sizes.into_iter() {
|
||||
if !do_support_realloc
|
||||
&& prev_size != self.accounts[account_index].1.borrow().data().len()
|
||||
&& prev_size
|
||||
!= self
|
||||
.transaction_context
|
||||
.get_account_at_index(account_index)
|
||||
.borrow()
|
||||
.data()
|
||||
.len()
|
||||
&& prev_size != 0
|
||||
{
|
||||
// Only support for `CreateAccount` at this time.
|
||||
|
@ -536,9 +552,8 @@ impl<'a> InvokeContext<'a> {
|
|||
let mut duplicate_indicies = Vec::with_capacity(instruction.accounts.len());
|
||||
for account_meta in instruction.accounts.iter() {
|
||||
let account_index = self
|
||||
.accounts
|
||||
.iter()
|
||||
.position(|(key, _account)| key == &account_meta.pubkey)
|
||||
.transaction_context
|
||||
.find_index_of_account(&account_meta.pubkey)
|
||||
.ok_or_else(|| {
|
||||
ic_msg!(
|
||||
self,
|
||||
|
@ -617,15 +632,17 @@ impl<'a> InvokeContext<'a> {
|
|||
.iter()
|
||||
.find(|keyed_account| &callee_program_id == keyed_account.unsigned_key())
|
||||
.and_then(|_keyed_account| {
|
||||
self.accounts
|
||||
.iter()
|
||||
.rposition(|(key, _account)| key == &callee_program_id)
|
||||
self.transaction_context
|
||||
.find_index_of_program_account(&callee_program_id)
|
||||
})
|
||||
.ok_or_else(|| {
|
||||
ic_msg!(self, "Unknown program {}", callee_program_id);
|
||||
InstructionError::MissingAccount
|
||||
})?;
|
||||
let program_account = self.accounts[program_account_index].1.borrow();
|
||||
let program_account = self
|
||||
.transaction_context
|
||||
.get_account_at_index(program_account_index)
|
||||
.borrow();
|
||||
if !program_account.executable() {
|
||||
ic_msg!(self, "Account {} is not executable", callee_program_id);
|
||||
return Err(InstructionError::AccountNotExecutable);
|
||||
|
@ -637,9 +654,8 @@ impl<'a> InvokeContext<'a> {
|
|||
} = program_account.state()?
|
||||
{
|
||||
if let Some(programdata_account_index) = self
|
||||
.accounts
|
||||
.iter()
|
||||
.rposition(|(key, _account)| key == &programdata_address)
|
||||
.transaction_context
|
||||
.find_index_of_program_account(&programdata_address)
|
||||
{
|
||||
program_indices.push(programdata_account_index);
|
||||
} else {
|
||||
|
@ -678,7 +694,7 @@ impl<'a> InvokeContext<'a> {
|
|||
) -> Result<u64, InstructionError> {
|
||||
let program_id = program_indices
|
||||
.last()
|
||||
.map(|index| self.accounts[*index].0)
|
||||
.map(|index| *self.transaction_context.get_key_of_account_at_index(*index))
|
||||
.unwrap_or_else(native_loader::id);
|
||||
|
||||
let is_lowest_invocation_level = self.invoke_stack.is_empty();
|
||||
|
@ -694,9 +710,8 @@ impl<'a> InvokeContext<'a> {
|
|||
if let Some(instruction_recorder) = &self.instruction_recorder {
|
||||
let compiled_instruction = CompiledInstruction {
|
||||
program_id_index: self
|
||||
.accounts
|
||||
.iter()
|
||||
.position(|(key, _account)| *key == program_id)
|
||||
.transaction_context
|
||||
.find_index_of_account(&program_id)
|
||||
.unwrap_or(0) as u8,
|
||||
data: instruction_data.to_vec(),
|
||||
accounts: instruction_accounts
|
||||
|
@ -852,16 +867,6 @@ impl<'a> InvokeContext<'a> {
|
|||
self.executors.borrow().get(pubkey)
|
||||
}
|
||||
|
||||
/// Returns an account by its account_index
|
||||
pub fn get_account_key_at_index(&self, account_index: usize) -> &Pubkey {
|
||||
&self.accounts[account_index].0
|
||||
}
|
||||
|
||||
/// Returns an account by its account_index
|
||||
pub fn get_account_at_index(&self, account_index: usize) -> &RefCell<AccountSharedData> {
|
||||
&self.accounts[account_index].1
|
||||
}
|
||||
|
||||
/// Get this invocation's compute budget
|
||||
pub fn get_compute_budget(&self) -> &ComputeBudget {
|
||||
&self.current_compute_budget
|
||||
|
@ -886,18 +891,14 @@ impl<'a> InvokeContext<'a> {
|
|||
}
|
||||
|
||||
pub struct MockInvokeContextPreparation {
|
||||
pub transaction_accounts: TransactionAccountRefCells,
|
||||
pub transaction_accounts: Vec<TransactionAccount>,
|
||||
pub instruction_accounts: Vec<InstructionAccount>,
|
||||
}
|
||||
|
||||
pub fn prepare_mock_invoke_context(
|
||||
transaction_accounts: Vec<(Pubkey, AccountSharedData)>,
|
||||
transaction_accounts: Vec<TransactionAccount>,
|
||||
instruction_accounts: Vec<AccountMeta>,
|
||||
) -> MockInvokeContextPreparation {
|
||||
let transaction_accounts: TransactionAccountRefCells = transaction_accounts
|
||||
.into_iter()
|
||||
.map(|(pubkey, account)| (pubkey, RefCell::new(account)))
|
||||
.collect();
|
||||
let instruction_accounts = instruction_accounts
|
||||
.iter()
|
||||
.map(|account_meta| InstructionAccount {
|
||||
|
@ -941,7 +942,11 @@ pub fn with_mock_invoke_context<R, F: FnMut(&mut InvokeContext) -> R>(
|
|||
is_writable: false,
|
||||
}];
|
||||
let preparation = prepare_mock_invoke_context(transaction_accounts, instruction_accounts);
|
||||
let mut invoke_context = InvokeContext::new_mock(&preparation.transaction_accounts, &[]);
|
||||
let transaction_context = TransactionContext::new(
|
||||
preparation.transaction_accounts,
|
||||
ComputeBudget::default().max_invoke_depth,
|
||||
);
|
||||
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
invoke_context
|
||||
.push(&preparation.instruction_accounts, &program_indices)
|
||||
.unwrap();
|
||||
|
@ -952,41 +957,38 @@ pub fn mock_process_instruction_with_sysvars(
|
|||
loader_id: &Pubkey,
|
||||
mut program_indices: Vec<usize>,
|
||||
instruction_data: &[u8],
|
||||
transaction_accounts: Vec<(Pubkey, AccountSharedData)>,
|
||||
transaction_accounts: Vec<TransactionAccount>,
|
||||
instruction_accounts: Vec<AccountMeta>,
|
||||
expected_result: Result<(), InstructionError>,
|
||||
sysvars: &[(Pubkey, Vec<u8>)],
|
||||
process_instruction: ProcessInstructionWithContext,
|
||||
) -> Vec<AccountSharedData> {
|
||||
let mut preparation = prepare_mock_invoke_context(transaction_accounts, instruction_accounts);
|
||||
let processor_account = RefCell::new(AccountSharedData::new(
|
||||
0,
|
||||
0,
|
||||
&solana_sdk::native_loader::id(),
|
||||
));
|
||||
let processor_account = AccountSharedData::new(0, 0, &solana_sdk::native_loader::id());
|
||||
program_indices.insert(0, preparation.transaction_accounts.len());
|
||||
preparation
|
||||
.transaction_accounts
|
||||
.push((*loader_id, processor_account));
|
||||
let mut invoke_context = InvokeContext::new_mock(&preparation.transaction_accounts, &[]);
|
||||
let transaction_context = TransactionContext::new(
|
||||
preparation.transaction_accounts,
|
||||
ComputeBudget::default().max_invoke_depth,
|
||||
);
|
||||
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
invoke_context.sysvars = sysvars;
|
||||
let result = invoke_context
|
||||
.push(&preparation.instruction_accounts, &program_indices)
|
||||
.and_then(|_| process_instruction(1, instruction_data, &mut invoke_context));
|
||||
preparation.transaction_accounts.pop();
|
||||
assert_eq!(result, expected_result);
|
||||
preparation
|
||||
.transaction_accounts
|
||||
.into_iter()
|
||||
.map(|(_key, account)| account.into_inner())
|
||||
.collect()
|
||||
let mut transaction_accounts = transaction_context.deconstruct_without_keys().unwrap();
|
||||
transaction_accounts.pop();
|
||||
transaction_accounts
|
||||
}
|
||||
|
||||
pub fn mock_process_instruction(
|
||||
loader_id: &Pubkey,
|
||||
program_indices: Vec<usize>,
|
||||
instruction_data: &[u8],
|
||||
transaction_accounts: Vec<(Pubkey, AccountSharedData)>,
|
||||
transaction_accounts: Vec<TransactionAccount>,
|
||||
instruction_accounts: Vec<AccountMeta>,
|
||||
expected_result: Result<(), InstructionError>,
|
||||
process_instruction: ProcessInstructionWithContext,
|
||||
|
@ -1166,11 +1168,7 @@ mod tests {
|
|||
invoke_stack.push(solana_sdk::pubkey::new_rand());
|
||||
accounts.push((
|
||||
solana_sdk::pubkey::new_rand(),
|
||||
RefCell::new(AccountSharedData::new(
|
||||
index as u64,
|
||||
1,
|
||||
&invoke_stack[index],
|
||||
)),
|
||||
AccountSharedData::new(index as u64, 1, &invoke_stack[index]),
|
||||
));
|
||||
instruction_accounts.push(InstructionAccount {
|
||||
index,
|
||||
|
@ -1181,11 +1179,7 @@ mod tests {
|
|||
for (index, program_id) in invoke_stack.iter().enumerate() {
|
||||
accounts.push((
|
||||
*program_id,
|
||||
RefCell::new(AccountSharedData::new(
|
||||
1,
|
||||
1,
|
||||
&solana_sdk::pubkey::Pubkey::default(),
|
||||
)),
|
||||
AccountSharedData::new(1, 1, &solana_sdk::pubkey::Pubkey::default()),
|
||||
));
|
||||
instruction_accounts.push(InstructionAccount {
|
||||
index,
|
||||
|
@ -1193,7 +1187,8 @@ mod tests {
|
|||
is_writable: false,
|
||||
});
|
||||
}
|
||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||
let transaction_context = TransactionContext::new(accounts, 1);
|
||||
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
|
||||
// Check call depth increases and has a limit
|
||||
let mut depth_reached = 0;
|
||||
|
@ -1225,8 +1220,10 @@ mod tests {
|
|||
];
|
||||
|
||||
// modify account owned by the program
|
||||
accounts[owned_index].1.borrow_mut().data_as_mut_slice()[0] =
|
||||
(MAX_DEPTH + owned_index) as u8;
|
||||
transaction_context
|
||||
.get_account_at_index(owned_index)
|
||||
.borrow_mut()
|
||||
.data_as_mut_slice()[0] = (MAX_DEPTH + owned_index) as u8;
|
||||
invoke_context
|
||||
.verify_and_update(&instruction_accounts, None)
|
||||
.unwrap();
|
||||
|
@ -1236,15 +1233,23 @@ mod tests {
|
|||
);
|
||||
|
||||
// modify account not owned by the program
|
||||
let data = accounts[not_owned_index].1.borrow_mut().data()[0];
|
||||
accounts[not_owned_index].1.borrow_mut().data_as_mut_slice()[0] =
|
||||
(MAX_DEPTH + not_owned_index) as u8;
|
||||
let data = transaction_context
|
||||
.get_account_at_index(not_owned_index)
|
||||
.borrow_mut()
|
||||
.data()[0];
|
||||
transaction_context
|
||||
.get_account_at_index(not_owned_index)
|
||||
.borrow_mut()
|
||||
.data_as_mut_slice()[0] = (MAX_DEPTH + not_owned_index) as u8;
|
||||
assert_eq!(
|
||||
invoke_context.verify_and_update(&instruction_accounts, None),
|
||||
Err(InstructionError::ExternalAccountDataModified)
|
||||
);
|
||||
assert_eq!(invoke_context.pre_accounts[not_owned_index].data()[0], data);
|
||||
accounts[not_owned_index].1.borrow_mut().data_as_mut_slice()[0] = data;
|
||||
transaction_context
|
||||
.get_account_at_index(not_owned_index)
|
||||
.borrow_mut()
|
||||
.data_as_mut_slice()[0] = data;
|
||||
|
||||
invoke_context.pop();
|
||||
}
|
||||
|
@ -1252,13 +1257,11 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_invoke_context_verify() {
|
||||
let accounts = vec![(
|
||||
solana_sdk::pubkey::new_rand(),
|
||||
RefCell::new(AccountSharedData::default()),
|
||||
)];
|
||||
let accounts = vec![(solana_sdk::pubkey::new_rand(), AccountSharedData::default())];
|
||||
let instruction_accounts = vec![];
|
||||
let program_indices = vec![0];
|
||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||
let transaction_context = TransactionContext::new(accounts, 1);
|
||||
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
invoke_context
|
||||
.push(&instruction_accounts, &program_indices)
|
||||
.unwrap();
|
||||
|
@ -1266,7 +1269,7 @@ mod tests {
|
|||
.verify(&instruction_accounts, &program_indices)
|
||||
.is_ok());
|
||||
|
||||
let mut _borrowed = accounts[0].1.borrow();
|
||||
let mut _borrowed = transaction_context.get_account_at_index(0).borrow();
|
||||
assert_eq!(
|
||||
invoke_context.verify(&instruction_accounts, &program_indices),
|
||||
Err(InstructionError::AccountBorrowOutstanding)
|
||||
|
@ -1277,6 +1280,10 @@ mod tests {
|
|||
fn test_process_cross_program() {
|
||||
let caller_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 not_owned_account = AccountSharedData::new(84, 1, &solana_sdk::pubkey::new_rand());
|
||||
|
@ -1286,17 +1293,11 @@ mod tests {
|
|||
program_account.set_executable(true);
|
||||
|
||||
let accounts = vec![
|
||||
(solana_sdk::pubkey::new_rand(), RefCell::new(owned_account)),
|
||||
(
|
||||
solana_sdk::pubkey::new_rand(),
|
||||
RefCell::new(not_owned_account),
|
||||
),
|
||||
(
|
||||
solana_sdk::pubkey::new_rand(),
|
||||
RefCell::new(readonly_account),
|
||||
),
|
||||
(caller_program_id, RefCell::new(loader_account)),
|
||||
(callee_program_id, RefCell::new(program_account)),
|
||||
(solana_sdk::pubkey::new_rand(), owned_account),
|
||||
(solana_sdk::pubkey::new_rand(), not_owned_account),
|
||||
(solana_sdk::pubkey::new_rand(), readonly_account),
|
||||
(caller_program_id, loader_account),
|
||||
(callee_program_id, program_account),
|
||||
];
|
||||
let program_indices = [3, 4];
|
||||
|
||||
|
@ -1319,17 +1320,17 @@ mod tests {
|
|||
&MockInstruction::NoopSuccess,
|
||||
metas.clone(),
|
||||
);
|
||||
let builtin_programs = &[BuiltinProgram {
|
||||
program_id: callee_program_id,
|
||||
process_instruction: mock_process_instruction,
|
||||
}];
|
||||
let mut invoke_context = InvokeContext::new_mock(&accounts, builtin_programs);
|
||||
let transaction_context = TransactionContext::new(accounts, 1);
|
||||
let mut invoke_context = InvokeContext::new_mock(&transaction_context, builtin_programs);
|
||||
invoke_context
|
||||
.push(&instruction_accounts, &program_indices[..1])
|
||||
.unwrap();
|
||||
|
||||
// not owned account modified by the caller (before the invoke)
|
||||
accounts[0].1.borrow_mut().data_as_mut_slice()[0] = 1;
|
||||
transaction_context
|
||||
.get_account_at_index(1)
|
||||
.borrow_mut()
|
||||
.data_as_mut_slice()[0] = 1;
|
||||
assert_eq!(
|
||||
invoke_context.process_instruction(
|
||||
&instruction.data,
|
||||
|
@ -1339,10 +1340,16 @@ mod tests {
|
|||
),
|
||||
Err(InstructionError::ExternalAccountDataModified)
|
||||
);
|
||||
accounts[0].1.borrow_mut().data_as_mut_slice()[0] = 0;
|
||||
transaction_context
|
||||
.get_account_at_index(1)
|
||||
.borrow_mut()
|
||||
.data_as_mut_slice()[0] = 0;
|
||||
|
||||
// readonly account modified by the invoker
|
||||
accounts[2].1.borrow_mut().data_as_mut_slice()[0] = 1;
|
||||
transaction_context
|
||||
.get_account_at_index(2)
|
||||
.borrow_mut()
|
||||
.data_as_mut_slice()[0] = 1;
|
||||
assert_eq!(
|
||||
invoke_context.process_instruction(
|
||||
&instruction.data,
|
||||
|
@ -1352,7 +1359,10 @@ mod tests {
|
|||
),
|
||||
Err(InstructionError::ReadonlyDataModified)
|
||||
);
|
||||
accounts[2].1.borrow_mut().data_as_mut_slice()[0] = 0;
|
||||
transaction_context
|
||||
.get_account_at_index(2)
|
||||
.borrow_mut()
|
||||
.data_as_mut_slice()[0] = 0;
|
||||
|
||||
invoke_context.pop();
|
||||
|
||||
|
@ -1401,16 +1411,10 @@ mod tests {
|
|||
let mut program_account = AccountSharedData::new(1, 0, &native_loader::id());
|
||||
program_account.set_executable(true);
|
||||
let accounts = vec![
|
||||
(solana_sdk::pubkey::new_rand(), RefCell::new(owned_account)),
|
||||
(
|
||||
solana_sdk::pubkey::new_rand(),
|
||||
RefCell::new(not_owned_account),
|
||||
),
|
||||
(
|
||||
solana_sdk::pubkey::new_rand(),
|
||||
RefCell::new(readonly_account),
|
||||
),
|
||||
(callee_program_id, RefCell::new(program_account)),
|
||||
(solana_sdk::pubkey::new_rand(), owned_account),
|
||||
(solana_sdk::pubkey::new_rand(), not_owned_account),
|
||||
(solana_sdk::pubkey::new_rand(), readonly_account),
|
||||
(callee_program_id, program_account),
|
||||
];
|
||||
let program_indices = [3];
|
||||
|
||||
|
@ -1435,26 +1439,39 @@ mod tests {
|
|||
metas.clone(),
|
||||
);
|
||||
|
||||
let mut invoke_context = InvokeContext::new_mock(&accounts, builtin_programs);
|
||||
let transaction_context = TransactionContext::new(accounts, 1);
|
||||
let mut invoke_context = InvokeContext::new_mock(&transaction_context, builtin_programs);
|
||||
invoke_context
|
||||
.push(&instruction_accounts, &program_indices)
|
||||
.unwrap();
|
||||
|
||||
// not owned account modified by the invoker
|
||||
accounts[1].1.borrow_mut().data_as_mut_slice()[0] = 1;
|
||||
transaction_context
|
||||
.get_account_at_index(1)
|
||||
.borrow_mut()
|
||||
.data_as_mut_slice()[0] = 1;
|
||||
assert_eq!(
|
||||
invoke_context.native_invoke(callee_instruction.clone(), &[]),
|
||||
Err(InstructionError::ExternalAccountDataModified)
|
||||
);
|
||||
accounts[1].1.borrow_mut().data_as_mut_slice()[0] = 0;
|
||||
transaction_context
|
||||
.get_account_at_index(1)
|
||||
.borrow_mut()
|
||||
.data_as_mut_slice()[0] = 0;
|
||||
|
||||
// readonly account modified by the invoker
|
||||
accounts[2].1.borrow_mut().data_as_mut_slice()[0] = 1;
|
||||
transaction_context
|
||||
.get_account_at_index(2)
|
||||
.borrow_mut()
|
||||
.data_as_mut_slice()[0] = 1;
|
||||
assert_eq!(
|
||||
invoke_context.native_invoke(callee_instruction, &[]),
|
||||
Err(InstructionError::ReadonlyDataModified)
|
||||
);
|
||||
accounts[2].1.borrow_mut().data_as_mut_slice()[0] = 0;
|
||||
transaction_context
|
||||
.get_account_at_index(2)
|
||||
.borrow_mut()
|
||||
.data_as_mut_slice()[0] = 0;
|
||||
|
||||
invoke_context.pop();
|
||||
|
||||
|
@ -1492,20 +1509,15 @@ mod tests {
|
|||
#[test]
|
||||
fn test_invoke_context_compute_budget() {
|
||||
let accounts = vec![
|
||||
(
|
||||
solana_sdk::pubkey::new_rand(),
|
||||
RefCell::new(AccountSharedData::default()),
|
||||
),
|
||||
(
|
||||
crate::neon_evm_program::id(),
|
||||
RefCell::new(AccountSharedData::default()),
|
||||
),
|
||||
(solana_sdk::pubkey::new_rand(), AccountSharedData::default()),
|
||||
(crate::neon_evm_program::id(), AccountSharedData::default()),
|
||||
];
|
||||
|
||||
let mut feature_set = FeatureSet::all_enabled();
|
||||
feature_set.deactivate(&tx_wide_compute_cap::id());
|
||||
feature_set.deactivate(&requestable_heap_size::id());
|
||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||
let transaction_context = TransactionContext::new(accounts, 1);
|
||||
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
invoke_context.feature_set = Arc::new(feature_set);
|
||||
|
||||
invoke_context.push(&[], &[0]).unwrap();
|
||||
|
|
|
@ -252,7 +252,9 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
|
|||
// Convert AccountInfos into Accounts
|
||||
let mut accounts = Vec::with_capacity(instruction_accounts.len());
|
||||
for instruction_account in instruction_accounts.iter() {
|
||||
let account_key = invoke_context.get_account_key_at_index(instruction_account.index);
|
||||
let account_key = invoke_context
|
||||
.transaction_context
|
||||
.get_key_of_account_at_index(instruction_account.index);
|
||||
let account_info = account_infos
|
||||
.iter()
|
||||
.find(|account_info| account_info.unsigned_key() == account_key)
|
||||
|
@ -260,6 +262,7 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
|
|||
.unwrap();
|
||||
{
|
||||
let mut account = invoke_context
|
||||
.transaction_context
|
||||
.get_account_at_index(instruction_account.index)
|
||||
.borrow_mut();
|
||||
account.copy_into_owner_from_slice(account_info.owner.as_ref());
|
||||
|
@ -284,7 +287,9 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
|
|||
|
||||
// Copy writeable account modifications back into the caller's AccountInfos
|
||||
for (account_index, account_info) in accounts.into_iter() {
|
||||
let account = invoke_context.get_account_at_index(account_index);
|
||||
let account = invoke_context
|
||||
.transaction_context
|
||||
.get_account_at_index(account_index);
|
||||
let account_borrow = account.borrow();
|
||||
**account_info.try_borrow_mut_lamports().unwrap() = account_borrow.lamports();
|
||||
let mut data = account_info.try_borrow_mut_data()?;
|
||||
|
|
|
@ -323,6 +323,7 @@ mod tests {
|
|||
bpf_loader,
|
||||
entrypoint::deserialize,
|
||||
instruction::AccountMeta,
|
||||
transaction_context::TransactionContext,
|
||||
},
|
||||
std::{
|
||||
cell::RefCell,
|
||||
|
@ -452,7 +453,8 @@ mod tests {
|
|||
let program_indices = [0];
|
||||
let preparation =
|
||||
prepare_mock_invoke_context(transaction_accounts.clone(), instruction_accounts);
|
||||
let mut invoke_context = InvokeContext::new_mock(&preparation.transaction_accounts, &[]);
|
||||
let transaction_context = TransactionContext::new(preparation.transaction_accounts, 1);
|
||||
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
invoke_context
|
||||
.push(&preparation.instruction_accounts, &program_indices)
|
||||
.unwrap();
|
||||
|
|
|
@ -5,7 +5,7 @@ use {
|
|||
alloc::Alloc,
|
||||
solana_program_runtime::{
|
||||
ic_logger_msg, ic_msg,
|
||||
invoke_context::{ComputeMeter, InstructionAccount, InvokeContext},
|
||||
invoke_context::{ComputeMeter, InvokeContext},
|
||||
stable_log,
|
||||
},
|
||||
solana_rbpf::{
|
||||
|
@ -41,6 +41,7 @@ use {
|
|||
Secp256k1RecoverError, SECP256K1_PUBLIC_KEY_LENGTH, SECP256K1_SIGNATURE_LENGTH,
|
||||
},
|
||||
sysvar::{self, Sysvar, SysvarId},
|
||||
transaction_context::InstructionAccount,
|
||||
},
|
||||
std::{
|
||||
alloc::Layout,
|
||||
|
@ -2214,8 +2215,12 @@ where
|
|||
accounts.push((*program_account_index, None));
|
||||
|
||||
for instruction_account in instruction_accounts.iter() {
|
||||
let account = invoke_context.get_account_at_index(instruction_account.index);
|
||||
let account_key = invoke_context.get_account_key_at_index(instruction_account.index);
|
||||
let account = invoke_context
|
||||
.transaction_context
|
||||
.get_account_at_index(instruction_account.index);
|
||||
let account_key = invoke_context
|
||||
.transaction_context
|
||||
.get_key_of_account_at_index(instruction_account.index);
|
||||
if account.borrow().executable() {
|
||||
// Use the known account
|
||||
accounts.push((instruction_account.index, None));
|
||||
|
@ -2396,6 +2401,7 @@ fn call<'a, 'b: 'a>(
|
|||
for (callee_account_index, caller_account) in accounts.iter_mut() {
|
||||
if let Some(caller_account) = caller_account {
|
||||
let callee_account = invoke_context
|
||||
.transaction_context
|
||||
.get_account_at_index(*callee_account_index)
|
||||
.borrow();
|
||||
*caller_account.lamports = callee_account.lamports();
|
||||
|
@ -2669,6 +2675,7 @@ mod tests {
|
|||
},
|
||||
solana_sdk::{
|
||||
account::AccountSharedData, bpf_loader, fee_calculator::FeeCalculator, hash::hashv,
|
||||
transaction_context::TransactionContext,
|
||||
},
|
||||
std::str::FromStr,
|
||||
};
|
||||
|
@ -2979,9 +2986,11 @@ mod tests {
|
|||
#[should_panic(expected = "UserError(SyscallError(Panic(\"Gaggablaghblagh!\", 42, 84)))")]
|
||||
fn test_syscall_sol_panic() {
|
||||
let program_id = Pubkey::new_unique();
|
||||
let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id()));
|
||||
let accounts = [(program_id, program_account)];
|
||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||
let transaction_context = TransactionContext::new(
|
||||
vec![(program_id, AccountSharedData::new(0, 0, &bpf_loader::id()))],
|
||||
1,
|
||||
);
|
||||
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
invoke_context.push(&[], &[0]).unwrap();
|
||||
let mut syscall_panic = SyscallPanic {
|
||||
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
||||
|
@ -3050,9 +3059,11 @@ mod tests {
|
|||
#[test]
|
||||
fn test_syscall_sol_log() {
|
||||
let program_id = Pubkey::new_unique();
|
||||
let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id()));
|
||||
let accounts = [(program_id, program_account)];
|
||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||
let transaction_context = TransactionContext::new(
|
||||
vec![(program_id, AccountSharedData::new(0, 0, &bpf_loader::id()))],
|
||||
1,
|
||||
);
|
||||
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
invoke_context.push(&[], &[0]).unwrap();
|
||||
let mut syscall_sol_log = SyscallLog {
|
||||
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
||||
|
@ -3148,9 +3159,11 @@ mod tests {
|
|||
#[test]
|
||||
fn test_syscall_sol_log_u64() {
|
||||
let program_id = Pubkey::new_unique();
|
||||
let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id()));
|
||||
let accounts = [(program_id, program_account)];
|
||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||
let transaction_context = TransactionContext::new(
|
||||
vec![(program_id, AccountSharedData::new(0, 0, &bpf_loader::id()))],
|
||||
1,
|
||||
);
|
||||
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
invoke_context.push(&[], &[0]).unwrap();
|
||||
let cost = invoke_context.get_compute_budget().log_64_units;
|
||||
let mut syscall_sol_log_u64 = SyscallLogU64 {
|
||||
|
@ -3184,9 +3197,11 @@ mod tests {
|
|||
#[test]
|
||||
fn test_syscall_sol_pubkey() {
|
||||
let program_id = Pubkey::new_unique();
|
||||
let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id()));
|
||||
let accounts = [(program_id, program_account)];
|
||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||
let transaction_context = TransactionContext::new(
|
||||
vec![(program_id, AccountSharedData::new(0, 0, &bpf_loader::id()))],
|
||||
1,
|
||||
);
|
||||
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
invoke_context.push(&[], &[0]).unwrap();
|
||||
let cost = invoke_context.get_compute_budget().log_pubkey_units;
|
||||
let mut syscall_sol_pubkey = SyscallLogPubkey {
|
||||
|
@ -3390,10 +3405,14 @@ mod tests {
|
|||
fn test_syscall_sha256() {
|
||||
let config = Config::default();
|
||||
let program_id = Pubkey::new_unique();
|
||||
let program_account =
|
||||
RefCell::new(AccountSharedData::new(0, 0, &bpf_loader_deprecated::id()));
|
||||
let accounts = [(program_id, program_account)];
|
||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||
let transaction_context = TransactionContext::new(
|
||||
vec![(
|
||||
program_id,
|
||||
AccountSharedData::new(0, 0, &bpf_loader_deprecated::id()),
|
||||
)],
|
||||
1,
|
||||
);
|
||||
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
invoke_context.push(&[], &[0]).unwrap();
|
||||
|
||||
let bytes1 = "Gaggablaghblagh!";
|
||||
|
@ -3511,11 +3530,55 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)]
|
||||
fn test_syscall_get_sysvar() {
|
||||
let config = Config::default();
|
||||
let src_clock = Clock {
|
||||
slot: 1,
|
||||
epoch_start_timestamp: 2,
|
||||
epoch: 3,
|
||||
leader_schedule_epoch: 4,
|
||||
unix_timestamp: 5,
|
||||
};
|
||||
let mut data_clock = vec![];
|
||||
bincode::serialize_into(&mut data_clock, &src_clock).unwrap();
|
||||
let src_epochschedule = EpochSchedule {
|
||||
slots_per_epoch: 1,
|
||||
leader_schedule_slot_offset: 2,
|
||||
warmup: false,
|
||||
first_normal_epoch: 3,
|
||||
first_normal_slot: 4,
|
||||
};
|
||||
let mut data_epochschedule = vec![];
|
||||
bincode::serialize_into(&mut data_epochschedule, &src_epochschedule).unwrap();
|
||||
let src_fees = Fees {
|
||||
fee_calculator: FeeCalculator {
|
||||
lamports_per_signature: 1,
|
||||
},
|
||||
};
|
||||
let mut data_fees = vec![];
|
||||
bincode::serialize_into(&mut data_fees, &src_fees).unwrap();
|
||||
let src_rent = Rent {
|
||||
lamports_per_byte_year: 1,
|
||||
exemption_threshold: 2.0,
|
||||
burn_percent: 3,
|
||||
};
|
||||
let mut data_rent = vec![];
|
||||
bincode::serialize_into(&mut data_rent, &src_rent).unwrap();
|
||||
let sysvars = [
|
||||
(sysvar::clock::id(), data_clock),
|
||||
(sysvar::epoch_schedule::id(), data_epochschedule),
|
||||
(sysvar::fees::id(), data_fees),
|
||||
(sysvar::rent::id(), data_rent),
|
||||
];
|
||||
let program_id = Pubkey::new_unique();
|
||||
let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id()));
|
||||
let accounts = [(program_id, program_account)];
|
||||
let transaction_context = TransactionContext::new(
|
||||
vec![(program_id, AccountSharedData::new(0, 0, &bpf_loader::id()))],
|
||||
1,
|
||||
);
|
||||
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
invoke_context.sysvars = &sysvars;
|
||||
invoke_context.push(&[], &[0]).unwrap();
|
||||
|
||||
// Test clock sysvar
|
||||
{
|
||||
|
@ -3536,20 +3599,6 @@ mod tests {
|
|||
&config,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let src_clock = Clock {
|
||||
slot: 1,
|
||||
epoch_start_timestamp: 2,
|
||||
epoch: 3,
|
||||
leader_schedule_epoch: 4,
|
||||
unix_timestamp: 5,
|
||||
};
|
||||
let mut data = vec![];
|
||||
bincode::serialize_into(&mut data, &src_clock).unwrap();
|
||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||
let sysvars = [(sysvar::clock::id(), data)];
|
||||
invoke_context.sysvars = &sysvars;
|
||||
invoke_context.push(&[], &[0]).unwrap();
|
||||
let mut syscall = SyscallGetClockSysvar {
|
||||
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
||||
};
|
||||
|
@ -3579,20 +3628,6 @@ mod tests {
|
|||
&config,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let src_epochschedule = EpochSchedule {
|
||||
slots_per_epoch: 1,
|
||||
leader_schedule_slot_offset: 2,
|
||||
warmup: false,
|
||||
first_normal_epoch: 3,
|
||||
first_normal_slot: 4,
|
||||
};
|
||||
let mut data = vec![];
|
||||
bincode::serialize_into(&mut data, &src_epochschedule).unwrap();
|
||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||
let sysvars = [(sysvar::epoch_schedule::id(), data)];
|
||||
invoke_context.sysvars = &sysvars;
|
||||
invoke_context.push(&[], &[0]).unwrap();
|
||||
let mut syscall = SyscallGetEpochScheduleSysvar {
|
||||
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
||||
};
|
||||
|
@ -3612,7 +3647,6 @@ mod tests {
|
|||
}
|
||||
|
||||
// Test fees sysvar
|
||||
#[allow(deprecated)]
|
||||
{
|
||||
let got_fees = Fees::default();
|
||||
let got_fees_va = 0x100000000;
|
||||
|
@ -3631,18 +3665,6 @@ mod tests {
|
|||
&config,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let src_fees = Fees {
|
||||
fee_calculator: FeeCalculator {
|
||||
lamports_per_signature: 1,
|
||||
},
|
||||
};
|
||||
let mut data = vec![];
|
||||
bincode::serialize_into(&mut data, &src_fees).unwrap();
|
||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||
let sysvars = [(sysvar::fees::id(), data)];
|
||||
invoke_context.sysvars = &sysvars;
|
||||
invoke_context.push(&[], &[0]).unwrap();
|
||||
let mut syscall = SyscallGetFeesSysvar {
|
||||
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
||||
};
|
||||
|
@ -3672,18 +3694,6 @@ mod tests {
|
|||
&config,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let src_rent = Rent {
|
||||
lamports_per_byte_year: 1,
|
||||
exemption_threshold: 2.0,
|
||||
burn_percent: 3,
|
||||
};
|
||||
let mut data = vec![];
|
||||
bincode::serialize_into(&mut data, &src_rent).unwrap();
|
||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||
let sysvars = [(sysvar::rent::id(), data)];
|
||||
invoke_context.sysvars = &sysvars;
|
||||
invoke_context.push(&[], &[0]).unwrap();
|
||||
let mut syscall = SyscallGetRentSysvar {
|
||||
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
||||
};
|
||||
|
@ -3812,9 +3822,11 @@ mod tests {
|
|||
// These tests duplicate the direct tests in solana_program::pubkey
|
||||
|
||||
let program_id = Pubkey::new_unique();
|
||||
let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id()));
|
||||
let accounts = [(program_id, program_account)];
|
||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||
let transaction_context = TransactionContext::new(
|
||||
vec![(program_id, AccountSharedData::new(0, 0, &bpf_loader::id()))],
|
||||
1,
|
||||
);
|
||||
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
invoke_context.push(&[], &[0]).unwrap();
|
||||
let address = bpf_loader_upgradeable::id();
|
||||
|
||||
|
@ -3922,9 +3934,11 @@ mod tests {
|
|||
#[test]
|
||||
fn test_find_program_address() {
|
||||
let program_id = Pubkey::new_unique();
|
||||
let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id()));
|
||||
let accounts = [(program_id, program_account)];
|
||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||
let transaction_context = TransactionContext::new(
|
||||
vec![(program_id, AccountSharedData::new(0, 0, &bpf_loader::id()))],
|
||||
1,
|
||||
);
|
||||
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
invoke_context.push(&[], &[0]).unwrap();
|
||||
let cost = invoke_context
|
||||
.get_compute_budget()
|
||||
|
|
|
@ -1308,6 +1308,7 @@ mod tests {
|
|||
native_token,
|
||||
pubkey::Pubkey,
|
||||
system_program,
|
||||
transaction_context::TransactionContext,
|
||||
},
|
||||
solana_vote_program::vote_state,
|
||||
std::{cell::RefCell, iter::FromIterator},
|
||||
|
@ -4998,7 +4999,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_merge() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
let stake_pubkey = solana_sdk::pubkey::new_rand();
|
||||
let source_stake_pubkey = solana_sdk::pubkey::new_rand();
|
||||
let authorized_pubkey = solana_sdk::pubkey::new_rand();
|
||||
|
@ -5108,7 +5110,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_merge_self_fails() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
let stake_address = Pubkey::new_unique();
|
||||
let authority_pubkey = Pubkey::new_unique();
|
||||
let signers = HashSet::from_iter(vec![authority_pubkey]);
|
||||
|
@ -5153,7 +5156,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_merge_incorrect_authorized_staker() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
let stake_pubkey = solana_sdk::pubkey::new_rand();
|
||||
let source_stake_pubkey = solana_sdk::pubkey::new_rand();
|
||||
let authorized_pubkey = solana_sdk::pubkey::new_rand();
|
||||
|
@ -5222,7 +5226,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_merge_invalid_account_data() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
let stake_pubkey = solana_sdk::pubkey::new_rand();
|
||||
let source_stake_pubkey = solana_sdk::pubkey::new_rand();
|
||||
let authorized_pubkey = solana_sdk::pubkey::new_rand();
|
||||
|
@ -5272,7 +5277,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_merge_fake_stake_source() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
let stake_pubkey = solana_sdk::pubkey::new_rand();
|
||||
let source_stake_pubkey = solana_sdk::pubkey::new_rand();
|
||||
let authorized_pubkey = solana_sdk::pubkey::new_rand();
|
||||
|
@ -5314,7 +5320,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_merge_active_stake() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
let base_lamports = 4242424242;
|
||||
let stake_address = Pubkey::new_unique();
|
||||
let source_address = Pubkey::new_unique();
|
||||
|
@ -5936,7 +5943,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_things_can_merge() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
let good_stake = Stake {
|
||||
credits_observed: 4242,
|
||||
delegation: Delegation {
|
||||
|
@ -6034,7 +6042,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_metas_can_merge_pre_v4() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
// Identical Metas can merge
|
||||
assert!(MergeKind::metas_can_merge(
|
||||
&invoke_context,
|
||||
|
@ -6120,7 +6129,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_metas_can_merge_v4() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
// Identical Metas can merge
|
||||
assert!(MergeKind::metas_can_merge(
|
||||
&invoke_context,
|
||||
|
@ -6266,7 +6276,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_merge_kind_get_if_mergeable() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
let authority_pubkey = Pubkey::new_unique();
|
||||
let initial_lamports = 4242424242;
|
||||
let rent = Rent::default();
|
||||
|
@ -6498,7 +6509,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_merge_kind_merge() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
let lamports = 424242;
|
||||
let meta = Meta {
|
||||
rent_exempt_reserve: 42,
|
||||
|
@ -6576,7 +6588,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_active_stake_merge() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
let delegation_a = 4_242_424_242u64;
|
||||
let delegation_b = 6_200_000_000u64;
|
||||
let credits_a = 124_521_000u64;
|
||||
|
|
|
@ -16,6 +16,7 @@ use {
|
|||
},
|
||||
solana_sdk::{
|
||||
account::AccountSharedData, bpf_loader, instruction::AccountMeta, pubkey::Pubkey,
|
||||
transaction_context::TransactionContext,
|
||||
},
|
||||
std::{
|
||||
fs::File,
|
||||
|
@ -210,7 +211,8 @@ native machine code before execting it in the virtual machine.",
|
|||
};
|
||||
let preparation = prepare_mock_invoke_context(transaction_accounts, instruction_accounts);
|
||||
let program_indices = [0, 1];
|
||||
let mut invoke_context = InvokeContext::new_mock(&preparation.transaction_accounts, &[]);
|
||||
let transaction_context = TransactionContext::new(preparation.transaction_accounts, 1);
|
||||
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
invoke_context
|
||||
.push(&preparation.instruction_accounts, &program_indices)
|
||||
.unwrap();
|
||||
|
|
|
@ -37,6 +37,7 @@ use {
|
|||
system_program,
|
||||
sysvar::{self, instructions::construct_instructions_data},
|
||||
transaction::{Result, SanitizedTransaction, TransactionError},
|
||||
transaction_context::TransactionAccount,
|
||||
},
|
||||
std::{
|
||||
cmp::Reverse,
|
||||
|
@ -105,12 +106,11 @@ pub struct Accounts {
|
|||
}
|
||||
|
||||
// for the load instructions
|
||||
pub type TransactionAccounts = Vec<(Pubkey, AccountSharedData)>;
|
||||
pub type TransactionRent = u64;
|
||||
pub type TransactionProgramIndices = Vec<Vec<usize>>;
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub struct LoadedTransaction {
|
||||
pub accounts: TransactionAccounts,
|
||||
pub accounts: Vec<TransactionAccount>,
|
||||
pub program_indices: TransactionProgramIndices,
|
||||
pub rent: TransactionRent,
|
||||
pub rent_debits: RentDebits,
|
||||
|
@ -385,7 +385,7 @@ impl Accounts {
|
|||
fn load_executable_accounts(
|
||||
&self,
|
||||
ancestors: &Ancestors,
|
||||
accounts: &mut Vec<(Pubkey, AccountSharedData)>,
|
||||
accounts: &mut Vec<TransactionAccount>,
|
||||
mut program_account_index: usize,
|
||||
error_counters: &mut ErrorCounters,
|
||||
) -> Result<Vec<usize>> {
|
||||
|
@ -606,7 +606,7 @@ impl Accounts {
|
|||
&self,
|
||||
slot: Slot,
|
||||
program_id: Option<&Pubkey>,
|
||||
) -> Vec<(Pubkey, AccountSharedData)> {
|
||||
) -> Vec<TransactionAccount> {
|
||||
self.scan_slot(slot, |stored_account| {
|
||||
let hit = match program_id {
|
||||
None => true,
|
||||
|
@ -721,7 +721,7 @@ impl Accounts {
|
|||
}
|
||||
|
||||
fn load_while_filtering<F: Fn(&AccountSharedData) -> bool>(
|
||||
collector: &mut Vec<(Pubkey, AccountSharedData)>,
|
||||
collector: &mut Vec<TransactionAccount>,
|
||||
some_account_tuple: Option<(&Pubkey, AccountSharedData, Slot)>,
|
||||
filter: F,
|
||||
) {
|
||||
|
@ -739,11 +739,11 @@ impl Accounts {
|
|||
bank_id: BankId,
|
||||
program_id: &Pubkey,
|
||||
config: &ScanConfig,
|
||||
) -> ScanResult<Vec<(Pubkey, AccountSharedData)>> {
|
||||
) -> ScanResult<Vec<TransactionAccount>> {
|
||||
self.accounts_db.scan_accounts(
|
||||
ancestors,
|
||||
bank_id,
|
||||
|collector: &mut Vec<(Pubkey, AccountSharedData)>, some_account_tuple| {
|
||||
|collector: &mut Vec<TransactionAccount>, some_account_tuple| {
|
||||
Self::load_while_filtering(collector, some_account_tuple, |account| {
|
||||
account.owner() == program_id
|
||||
})
|
||||
|
@ -759,11 +759,11 @@ impl Accounts {
|
|||
program_id: &Pubkey,
|
||||
filter: F,
|
||||
config: &ScanConfig,
|
||||
) -> ScanResult<Vec<(Pubkey, AccountSharedData)>> {
|
||||
) -> ScanResult<Vec<TransactionAccount>> {
|
||||
self.accounts_db.scan_accounts(
|
||||
ancestors,
|
||||
bank_id,
|
||||
|collector: &mut Vec<(Pubkey, AccountSharedData)>, some_account_tuple| {
|
||||
|collector: &mut Vec<TransactionAccount>, some_account_tuple| {
|
||||
Self::load_while_filtering(collector, some_account_tuple, |account| {
|
||||
account.owner() == program_id && filter(account)
|
||||
})
|
||||
|
@ -796,9 +796,9 @@ impl Accounts {
|
|||
}
|
||||
|
||||
fn maybe_abort_scan(
|
||||
result: ScanResult<Vec<(Pubkey, AccountSharedData)>>,
|
||||
result: ScanResult<Vec<TransactionAccount>>,
|
||||
config: &ScanConfig,
|
||||
) -> ScanResult<Vec<(Pubkey, AccountSharedData)>> {
|
||||
) -> ScanResult<Vec<TransactionAccount>> {
|
||||
if config.is_aborted() {
|
||||
ScanResult::Err(ScanError::Aborted(
|
||||
"The accumulated scan results exceeded the limit".to_string(),
|
||||
|
@ -816,7 +816,7 @@ impl Accounts {
|
|||
filter: F,
|
||||
config: &ScanConfig,
|
||||
byte_limit_for_scan: Option<usize>,
|
||||
) -> ScanResult<Vec<(Pubkey, AccountSharedData)>> {
|
||||
) -> ScanResult<Vec<TransactionAccount>> {
|
||||
let sum = AtomicUsize::default();
|
||||
let config = config.recreate_with_abort();
|
||||
let result = self
|
||||
|
@ -825,7 +825,7 @@ impl Accounts {
|
|||
ancestors,
|
||||
bank_id,
|
||||
*index_key,
|
||||
|collector: &mut Vec<(Pubkey, AccountSharedData)>, some_account_tuple| {
|
||||
|collector: &mut Vec<TransactionAccount>, some_account_tuple| {
|
||||
Self::load_while_filtering(collector, some_account_tuple, |account| {
|
||||
let use_account = filter(account);
|
||||
if use_account
|
||||
|
@ -887,13 +887,13 @@ impl Accounts {
|
|||
&self,
|
||||
ancestors: &Ancestors,
|
||||
range: R,
|
||||
) -> Vec<(Pubkey, AccountSharedData)> {
|
||||
) -> Vec<TransactionAccount> {
|
||||
self.accounts_db.range_scan_accounts(
|
||||
"load_to_collect_rent_eagerly_scan_elapsed",
|
||||
ancestors,
|
||||
range,
|
||||
&ScanConfig::new(true),
|
||||
|collector: &mut Vec<(Pubkey, AccountSharedData)>, option| {
|
||||
|collector: &mut Vec<TransactionAccount>, option| {
|
||||
Self::load_while_filtering(collector, option, |_| true)
|
||||
},
|
||||
)
|
||||
|
@ -1277,7 +1277,7 @@ mod tests {
|
|||
|
||||
fn load_accounts_with_fee_and_rent(
|
||||
tx: Transaction,
|
||||
ka: &[(Pubkey, AccountSharedData)],
|
||||
ka: &[TransactionAccount],
|
||||
lamports_per_signature: u64,
|
||||
rent_collector: &RentCollector,
|
||||
error_counters: &mut ErrorCounters,
|
||||
|
@ -1310,7 +1310,7 @@ mod tests {
|
|||
|
||||
fn load_accounts_with_fee(
|
||||
tx: Transaction,
|
||||
ka: &[(Pubkey, AccountSharedData)],
|
||||
ka: &[TransactionAccount],
|
||||
lamports_per_signature: u64,
|
||||
error_counters: &mut ErrorCounters,
|
||||
) -> Vec<TransactionLoadResult> {
|
||||
|
@ -1325,7 +1325,7 @@ mod tests {
|
|||
|
||||
fn load_accounts(
|
||||
tx: Transaction,
|
||||
ka: &[(Pubkey, AccountSharedData)],
|
||||
ka: &[TransactionAccount],
|
||||
error_counters: &mut ErrorCounters,
|
||||
) -> Vec<TransactionLoadResult> {
|
||||
load_accounts_with_fee(tx, ka, 0, error_counters)
|
||||
|
@ -1390,7 +1390,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_load_accounts_no_account_0_exists() {
|
||||
let accounts: Vec<(Pubkey, AccountSharedData)> = Vec::new();
|
||||
let accounts: Vec<TransactionAccount> = Vec::new();
|
||||
let mut error_counters = ErrorCounters::default();
|
||||
|
||||
let keypair = Keypair::new();
|
||||
|
@ -1416,7 +1416,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_load_accounts_unknown_program_id() {
|
||||
let mut accounts: Vec<(Pubkey, AccountSharedData)> = Vec::new();
|
||||
let mut accounts: Vec<TransactionAccount> = Vec::new();
|
||||
let mut error_counters = ErrorCounters::default();
|
||||
|
||||
let keypair = Keypair::new();
|
||||
|
@ -1450,7 +1450,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_load_accounts_insufficient_funds() {
|
||||
let mut accounts: Vec<(Pubkey, AccountSharedData)> = Vec::new();
|
||||
let mut accounts: Vec<TransactionAccount> = Vec::new();
|
||||
let mut error_counters = ErrorCounters::default();
|
||||
|
||||
let keypair = Keypair::new();
|
||||
|
@ -1486,7 +1486,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_load_accounts_invalid_account_for_fee() {
|
||||
let mut accounts: Vec<(Pubkey, AccountSharedData)> = Vec::new();
|
||||
let mut accounts: Vec<TransactionAccount> = Vec::new();
|
||||
let mut error_counters = ErrorCounters::default();
|
||||
|
||||
let keypair = Keypair::new();
|
||||
|
@ -1588,7 +1588,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_load_accounts_no_loaders() {
|
||||
let mut accounts: Vec<(Pubkey, AccountSharedData)> = Vec::new();
|
||||
let mut accounts: Vec<TransactionAccount> = Vec::new();
|
||||
let mut error_counters = ErrorCounters::default();
|
||||
|
||||
let keypair = Keypair::new();
|
||||
|
@ -1629,7 +1629,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_load_accounts_max_call_depth() {
|
||||
let mut accounts: Vec<(Pubkey, AccountSharedData)> = Vec::new();
|
||||
let mut accounts: Vec<TransactionAccount> = Vec::new();
|
||||
let mut error_counters = ErrorCounters::default();
|
||||
|
||||
let keypair = Keypair::new();
|
||||
|
@ -1695,7 +1695,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_load_accounts_bad_owner() {
|
||||
let mut accounts: Vec<(Pubkey, AccountSharedData)> = Vec::new();
|
||||
let mut accounts: Vec<TransactionAccount> = Vec::new();
|
||||
let mut error_counters = ErrorCounters::default();
|
||||
|
||||
let keypair = Keypair::new();
|
||||
|
@ -1730,7 +1730,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_load_accounts_not_executable() {
|
||||
let mut accounts: Vec<(Pubkey, AccountSharedData)> = Vec::new();
|
||||
let mut accounts: Vec<TransactionAccount> = Vec::new();
|
||||
let mut error_counters = ErrorCounters::default();
|
||||
|
||||
let keypair = Keypair::new();
|
||||
|
@ -1764,7 +1764,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_load_accounts_multiple_loaders() {
|
||||
let mut accounts: Vec<(Pubkey, AccountSharedData)> = Vec::new();
|
||||
let mut accounts: Vec<TransactionAccount> = Vec::new();
|
||||
let mut error_counters = ErrorCounters::default();
|
||||
|
||||
let keypair = Keypair::new();
|
||||
|
@ -1860,7 +1860,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_load_accounts_executable_with_write_lock() {
|
||||
let mut accounts: Vec<(Pubkey, AccountSharedData)> = Vec::new();
|
||||
let mut accounts: Vec<TransactionAccount> = Vec::new();
|
||||
let mut error_counters = ErrorCounters::default();
|
||||
|
||||
let keypair = Keypair::new();
|
||||
|
@ -1916,7 +1916,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_load_accounts_upgradeable_with_write_lock() {
|
||||
let mut accounts: Vec<(Pubkey, AccountSharedData)> = Vec::new();
|
||||
let mut accounts: Vec<TransactionAccount> = Vec::new();
|
||||
let mut error_counters = ErrorCounters::default();
|
||||
|
||||
let keypair = Keypair::new();
|
||||
|
@ -2013,7 +2013,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_load_accounts_programdata_with_write_lock() {
|
||||
let mut accounts: Vec<(Pubkey, AccountSharedData)> = Vec::new();
|
||||
let mut accounts: Vec<TransactionAccount> = Vec::new();
|
||||
let mut error_counters = ErrorCounters::default();
|
||||
|
||||
let keypair = Keypair::new();
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
use solana_sdk::recent_blockhashes_account;
|
||||
use {
|
||||
crate::{
|
||||
accounts::{AccountAddressFilter, Accounts, TransactionAccounts, TransactionLoadResult},
|
||||
accounts::{AccountAddressFilter, Accounts, TransactionLoadResult},
|
||||
accounts_db::{
|
||||
AccountShrinkThreshold, AccountsDbConfig, ErrorCounters, SnapshotStorages,
|
||||
ACCOUNTS_DB_CONFIG_FOR_BENCHMARKS, ACCOUNTS_DB_CONFIG_FOR_TESTING,
|
||||
|
@ -74,10 +74,7 @@ use {
|
|||
solana_metrics::{inc_new_counter_debug, inc_new_counter_info},
|
||||
solana_program_runtime::{
|
||||
instruction_recorder::InstructionRecorder,
|
||||
invoke_context::{
|
||||
BuiltinProgram, Executor, Executors, ProcessInstructionWithContext,
|
||||
TransactionAccountRefCells,
|
||||
},
|
||||
invoke_context::{BuiltinProgram, Executor, Executors, ProcessInstructionWithContext},
|
||||
log_collector::LogCollector,
|
||||
timings::ExecuteDetailsTimings,
|
||||
},
|
||||
|
@ -127,6 +124,7 @@ use {
|
|||
Result, SanitizedTransaction, Transaction, TransactionError,
|
||||
TransactionVerificationMode, VersionedTransaction,
|
||||
},
|
||||
transaction_context::{TransactionAccount, TransactionContext},
|
||||
},
|
||||
solana_stake_program::stake_state::{
|
||||
self, InflationPointCalculationEvent, PointValue, StakeState,
|
||||
|
@ -515,7 +513,7 @@ pub struct TransactionResults {
|
|||
pub struct TransactionSimulationResult {
|
||||
pub result: Result<()>,
|
||||
pub logs: TransactionLogMessages,
|
||||
pub post_simulation_accounts: Vec<(Pubkey, AccountSharedData)>,
|
||||
pub post_simulation_accounts: Vec<TransactionAccount>,
|
||||
pub units_consumed: u64,
|
||||
}
|
||||
pub struct TransactionBalancesSet {
|
||||
|
@ -654,7 +652,7 @@ impl NonceFull {
|
|||
pub fn from_partial(
|
||||
partial: NoncePartial,
|
||||
message: &SanitizedMessage,
|
||||
accounts: &[(Pubkey, AccountSharedData)],
|
||||
accounts: &[TransactionAccount],
|
||||
rent_debits: &RentDebits,
|
||||
) -> Result<Self> {
|
||||
let fee_payer = (0..message.account_keys_len()).find_map(|i| {
|
||||
|
@ -3287,7 +3285,7 @@ impl Bank {
|
|||
pub fn check_transaction_for_nonce(
|
||||
&self,
|
||||
tx: &SanitizedTransaction,
|
||||
) -> Option<(Pubkey, AccountSharedData)> {
|
||||
) -> Option<TransactionAccount> {
|
||||
tx.get_durable_nonce(self.feature_set.is_active(&nonce_must_be_writable::id()))
|
||||
.and_then(|nonce_address| {
|
||||
self.get_account_with_fixed_root(nonce_address)
|
||||
|
@ -3404,31 +3402,11 @@ impl Bank {
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts Accounts into RefCell<AccountSharedData>, this involves moving
|
||||
/// ownership by draining the source
|
||||
fn accounts_to_refcells(accounts: &mut TransactionAccounts) -> TransactionAccountRefCells {
|
||||
accounts
|
||||
.drain(..)
|
||||
.map(|(pubkey, account)| (pubkey, RefCell::new(account)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Converts back from RefCell<AccountSharedData> to AccountSharedData, this involves moving
|
||||
/// ownership by draining the sources
|
||||
fn refcells_to_accounts(
|
||||
accounts: &mut TransactionAccounts,
|
||||
mut account_refcells: TransactionAccountRefCells,
|
||||
) {
|
||||
for (pubkey, account_refcell) in account_refcells.drain(..) {
|
||||
accounts.push((pubkey, account_refcell.into_inner()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Get any cached executors needed by the transaction
|
||||
fn get_executors(
|
||||
&self,
|
||||
message: &SanitizedMessage,
|
||||
accounts: &[(Pubkey, AccountSharedData)],
|
||||
accounts: &[TransactionAccount],
|
||||
program_indices: &[Vec<usize>],
|
||||
) -> Rc<RefCell<Executors>> {
|
||||
let mut num_executors = message.account_keys_len();
|
||||
|
@ -3573,8 +3551,12 @@ impl Bank {
|
|||
&loaded_transaction.program_indices,
|
||||
);
|
||||
|
||||
let account_refcells =
|
||||
Self::accounts_to_refcells(&mut loaded_transaction.accounts);
|
||||
let mut transaction_accounts = Vec::new();
|
||||
std::mem::swap(&mut loaded_transaction.accounts, &mut transaction_accounts);
|
||||
let transaction_context = TransactionContext::new(
|
||||
transaction_accounts,
|
||||
compute_budget.max_invoke_depth,
|
||||
);
|
||||
|
||||
let instruction_recorder = if enable_cpi_recording {
|
||||
Some(InstructionRecorder::new_ref(
|
||||
|
@ -3598,7 +3580,7 @@ impl Bank {
|
|||
&self.builtin_programs.vec,
|
||||
legacy_message,
|
||||
&loaded_transaction.program_indices,
|
||||
&account_refcells,
|
||||
&transaction_context,
|
||||
self.rent_collector.rent,
|
||||
log_collector.clone(),
|
||||
executors.clone(),
|
||||
|
@ -3637,10 +3619,7 @@ impl Bank {
|
|||
}),
|
||||
);
|
||||
|
||||
Self::refcells_to_accounts(
|
||||
&mut loaded_transaction.accounts,
|
||||
account_refcells,
|
||||
);
|
||||
loaded_transaction.accounts = transaction_context.deconstruct();
|
||||
|
||||
if process_result.is_ok() {
|
||||
self.update_executors(executors);
|
||||
|
@ -4993,7 +4972,7 @@ impl Bank {
|
|||
&self,
|
||||
program_id: &Pubkey,
|
||||
config: &ScanConfig,
|
||||
) -> ScanResult<Vec<(Pubkey, AccountSharedData)>> {
|
||||
) -> ScanResult<Vec<TransactionAccount>> {
|
||||
self.rc
|
||||
.accounts
|
||||
.load_by_program(&self.ancestors, self.bank_id, program_id, config)
|
||||
|
@ -5004,7 +4983,7 @@ impl Bank {
|
|||
program_id: &Pubkey,
|
||||
filter: F,
|
||||
config: &ScanConfig,
|
||||
) -> ScanResult<Vec<(Pubkey, AccountSharedData)>> {
|
||||
) -> ScanResult<Vec<TransactionAccount>> {
|
||||
self.rc.accounts.load_by_program_with_filter(
|
||||
&self.ancestors,
|
||||
self.bank_id,
|
||||
|
@ -5020,7 +4999,7 @@ impl Bank {
|
|||
filter: F,
|
||||
config: &ScanConfig,
|
||||
byte_limit_for_scan: Option<usize>,
|
||||
) -> ScanResult<Vec<(Pubkey, AccountSharedData)>> {
|
||||
) -> ScanResult<Vec<TransactionAccount>> {
|
||||
self.rc.accounts.load_by_index_key_with_filter(
|
||||
&self.ancestors,
|
||||
self.bank_id,
|
||||
|
@ -5044,7 +5023,7 @@ impl Bank {
|
|||
pub fn get_program_accounts_modified_since_parent(
|
||||
&self,
|
||||
program_id: &Pubkey,
|
||||
) -> Vec<(Pubkey, AccountSharedData)> {
|
||||
) -> Vec<TransactionAccount> {
|
||||
self.rc
|
||||
.accounts
|
||||
.load_by_program_slot(self.slot(), Some(program_id))
|
||||
|
@ -5060,7 +5039,7 @@ impl Bank {
|
|||
.get_logs_for_address(address)
|
||||
}
|
||||
|
||||
pub fn get_all_accounts_modified_since_parent(&self) -> Vec<(Pubkey, AccountSharedData)> {
|
||||
pub fn get_all_accounts_modified_since_parent(&self) -> Vec<TransactionAccount> {
|
||||
self.rc.accounts.load_by_program_slot(self.slot(), None)
|
||||
}
|
||||
|
||||
|
@ -6722,8 +6701,7 @@ pub(crate) mod tests {
|
|||
mock_program_id: Pubkey,
|
||||
generic_rent_due_for_system_account: u64,
|
||||
) {
|
||||
let mut account_pairs: Vec<(Pubkey, AccountSharedData)> =
|
||||
Vec::with_capacity(keypairs.len() - 1);
|
||||
let mut account_pairs: Vec<TransactionAccount> = Vec::with_capacity(keypairs.len() - 1);
|
||||
account_pairs.push((
|
||||
keypairs[0].pubkey(),
|
||||
AccountSharedData::new(
|
||||
|
|
|
@ -3,9 +3,7 @@ use {
|
|||
solana_measure::measure::Measure,
|
||||
solana_program_runtime::{
|
||||
instruction_recorder::InstructionRecorder,
|
||||
invoke_context::{
|
||||
BuiltinProgram, Executors, InstructionAccount, InvokeContext, TransactionAccountRefCell,
|
||||
},
|
||||
invoke_context::{BuiltinProgram, Executors, InvokeContext},
|
||||
log_collector::LogCollector,
|
||||
timings::ExecuteDetailsTimings,
|
||||
},
|
||||
|
@ -20,6 +18,7 @@ use {
|
|||
rent::Rent,
|
||||
sysvar::instructions,
|
||||
transaction::TransactionError,
|
||||
transaction_context::{InstructionAccount, TransactionContext},
|
||||
},
|
||||
std::{cell::RefCell, rc::Rc, sync::Arc},
|
||||
};
|
||||
|
@ -54,7 +53,7 @@ impl MessageProcessor {
|
|||
builtin_programs: &[BuiltinProgram],
|
||||
message: &Message,
|
||||
program_indices: &[Vec<usize>],
|
||||
accounts: &[TransactionAccountRefCell],
|
||||
transaction_context: &TransactionContext,
|
||||
rent: Rent,
|
||||
log_collector: Option<Rc<RefCell<LogCollector>>>,
|
||||
executors: Rc<RefCell<Executors>>,
|
||||
|
@ -67,8 +66,8 @@ impl MessageProcessor {
|
|||
lamports_per_signature: u64,
|
||||
) -> Result<ProcessedMessageInfo, TransactionError> {
|
||||
let mut invoke_context = InvokeContext::new(
|
||||
transaction_context,
|
||||
rent,
|
||||
accounts,
|
||||
builtin_programs,
|
||||
sysvars,
|
||||
log_collector,
|
||||
|
@ -99,15 +98,18 @@ impl MessageProcessor {
|
|||
|
||||
// Fixup the special instructions key if present
|
||||
// before the account pre-values are taken care of
|
||||
for (pubkey, account) in accounts.iter().take(message.account_keys.len()) {
|
||||
if instructions::check_id(pubkey) {
|
||||
let mut mut_account_ref = account.borrow_mut();
|
||||
instructions::store_current_index(
|
||||
mut_account_ref.data_as_mut_slice(),
|
||||
instruction_index as u16,
|
||||
);
|
||||
break;
|
||||
}
|
||||
if let Some(account_index) = invoke_context
|
||||
.transaction_context
|
||||
.find_index_of_account(&instructions::id())
|
||||
{
|
||||
let mut mut_account_ref = invoke_context
|
||||
.transaction_context
|
||||
.get_account_at_index(account_index)
|
||||
.borrow_mut();
|
||||
instructions::store_current_index(
|
||||
mut_account_ref.data_as_mut_slice(),
|
||||
instruction_index as u16,
|
||||
);
|
||||
}
|
||||
|
||||
let instruction_accounts = instruction
|
||||
|
@ -221,39 +223,38 @@ mod tests {
|
|||
let accounts = vec![
|
||||
(
|
||||
solana_sdk::pubkey::new_rand(),
|
||||
RefCell::new(AccountSharedData::new(100, 1, &mock_system_program_id)),
|
||||
AccountSharedData::new(100, 1, &mock_system_program_id),
|
||||
),
|
||||
(
|
||||
solana_sdk::pubkey::new_rand(),
|
||||
RefCell::new(AccountSharedData::new(0, 1, &mock_system_program_id)),
|
||||
AccountSharedData::new(0, 1, &mock_system_program_id),
|
||||
),
|
||||
(
|
||||
mock_system_program_id,
|
||||
RefCell::new(create_loadable_account_for_test("mock_system_program")),
|
||||
create_loadable_account_for_test("mock_system_program"),
|
||||
),
|
||||
];
|
||||
let transaction_context = TransactionContext::new(accounts, 1);
|
||||
let program_indices = vec![vec![2]];
|
||||
|
||||
let executors = Rc::new(RefCell::new(Executors::default()));
|
||||
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(accounts[0].0, true),
|
||||
AccountMeta::new_readonly(accounts[1].0, false),
|
||||
AccountMeta::new(*transaction_context.get_key_of_account_at_index(0), true),
|
||||
AccountMeta::new_readonly(*transaction_context.get_key_of_account_at_index(1), false),
|
||||
];
|
||||
|
||||
let message = Message::new(
|
||||
&[Instruction::new_with_bincode(
|
||||
mock_system_program_id,
|
||||
&MockSystemInstruction::Correct,
|
||||
account_metas.clone(),
|
||||
)],
|
||||
Some(&accounts[0].0),
|
||||
Some(transaction_context.get_key_of_account_at_index(0)),
|
||||
);
|
||||
|
||||
let result = MessageProcessor::process_message(
|
||||
builtin_programs,
|
||||
&message,
|
||||
&program_indices,
|
||||
&accounts,
|
||||
&transaction_context,
|
||||
rent_collector.rent,
|
||||
None,
|
||||
executors.clone(),
|
||||
|
@ -266,8 +267,20 @@ mod tests {
|
|||
0,
|
||||
);
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(accounts[0].1.borrow().lamports(), 100);
|
||||
assert_eq!(accounts[1].1.borrow().lamports(), 0);
|
||||
assert_eq!(
|
||||
transaction_context
|
||||
.get_account_at_index(0)
|
||||
.borrow()
|
||||
.lamports(),
|
||||
100
|
||||
);
|
||||
assert_eq!(
|
||||
transaction_context
|
||||
.get_account_at_index(1)
|
||||
.borrow()
|
||||
.lamports(),
|
||||
0
|
||||
);
|
||||
|
||||
let message = Message::new(
|
||||
&[Instruction::new_with_bincode(
|
||||
|
@ -275,14 +288,13 @@ mod tests {
|
|||
&MockSystemInstruction::AttemptCredit { lamports: 50 },
|
||||
account_metas.clone(),
|
||||
)],
|
||||
Some(&accounts[0].0),
|
||||
Some(transaction_context.get_key_of_account_at_index(0)),
|
||||
);
|
||||
|
||||
let result = MessageProcessor::process_message(
|
||||
builtin_programs,
|
||||
&message,
|
||||
&program_indices,
|
||||
&accounts,
|
||||
&transaction_context,
|
||||
rent_collector.rent,
|
||||
None,
|
||||
executors.clone(),
|
||||
|
@ -308,14 +320,13 @@ mod tests {
|
|||
&MockSystemInstruction::AttemptDataChange { data: 50 },
|
||||
account_metas,
|
||||
)],
|
||||
Some(&accounts[0].0),
|
||||
Some(transaction_context.get_key_of_account_at_index(0)),
|
||||
);
|
||||
|
||||
let result = MessageProcessor::process_message(
|
||||
builtin_programs,
|
||||
&message,
|
||||
&program_indices,
|
||||
&accounts,
|
||||
&transaction_context,
|
||||
rent_collector.rent,
|
||||
None,
|
||||
executors,
|
||||
|
@ -425,25 +436,24 @@ mod tests {
|
|||
let accounts = vec![
|
||||
(
|
||||
solana_sdk::pubkey::new_rand(),
|
||||
RefCell::new(AccountSharedData::new(100, 1, &mock_program_id)),
|
||||
AccountSharedData::new(100, 1, &mock_program_id),
|
||||
),
|
||||
(
|
||||
solana_sdk::pubkey::new_rand(),
|
||||
RefCell::new(AccountSharedData::new(0, 1, &mock_program_id)),
|
||||
AccountSharedData::new(0, 1, &mock_program_id),
|
||||
),
|
||||
(
|
||||
mock_program_id,
|
||||
RefCell::new(create_loadable_account_for_test("mock_system_program")),
|
||||
create_loadable_account_for_test("mock_system_program"),
|
||||
),
|
||||
];
|
||||
let transaction_context = TransactionContext::new(accounts, 1);
|
||||
let program_indices = vec![vec![2]];
|
||||
|
||||
let executors = Rc::new(RefCell::new(Executors::default()));
|
||||
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(accounts[0].0, true),
|
||||
AccountMeta::new(accounts[1].0, false),
|
||||
AccountMeta::new(accounts[0].0, false),
|
||||
AccountMeta::new(*transaction_context.get_key_of_account_at_index(0), true),
|
||||
AccountMeta::new(*transaction_context.get_key_of_account_at_index(1), false),
|
||||
AccountMeta::new(*transaction_context.get_key_of_account_at_index(0), false),
|
||||
];
|
||||
|
||||
// Try to borrow mut the same account
|
||||
|
@ -453,13 +463,13 @@ mod tests {
|
|||
&MockSystemInstruction::BorrowFail,
|
||||
account_metas.clone(),
|
||||
)],
|
||||
Some(&accounts[0].0),
|
||||
Some(transaction_context.get_key_of_account_at_index(0)),
|
||||
);
|
||||
let result = MessageProcessor::process_message(
|
||||
builtin_programs,
|
||||
&message,
|
||||
&program_indices,
|
||||
&accounts,
|
||||
&transaction_context,
|
||||
rent_collector.rent,
|
||||
None,
|
||||
executors.clone(),
|
||||
|
@ -486,13 +496,13 @@ mod tests {
|
|||
&MockSystemInstruction::MultiBorrowMut,
|
||||
account_metas.clone(),
|
||||
)],
|
||||
Some(&accounts[0].0),
|
||||
Some(transaction_context.get_key_of_account_at_index(0)),
|
||||
);
|
||||
let result = MessageProcessor::process_message(
|
||||
builtin_programs,
|
||||
&message,
|
||||
&program_indices,
|
||||
&accounts,
|
||||
&transaction_context,
|
||||
rent_collector.rent,
|
||||
None,
|
||||
executors.clone(),
|
||||
|
@ -516,13 +526,13 @@ mod tests {
|
|||
},
|
||||
account_metas,
|
||||
)],
|
||||
Some(&accounts[0].0),
|
||||
Some(transaction_context.get_key_of_account_at_index(0)),
|
||||
);
|
||||
let result = MessageProcessor::process_message(
|
||||
builtin_programs,
|
||||
&message,
|
||||
&program_indices,
|
||||
&accounts,
|
||||
&transaction_context,
|
||||
rent_collector.rent,
|
||||
None,
|
||||
executors,
|
||||
|
@ -535,9 +545,24 @@ mod tests {
|
|||
0,
|
||||
);
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(accounts[0].1.borrow().lamports(), 80);
|
||||
assert_eq!(accounts[1].1.borrow().lamports(), 20);
|
||||
assert_eq!(accounts[0].1.borrow().data(), &vec![42]);
|
||||
assert_eq!(
|
||||
transaction_context
|
||||
.get_account_at_index(0)
|
||||
.borrow()
|
||||
.lamports(),
|
||||
80
|
||||
);
|
||||
assert_eq!(
|
||||
transaction_context
|
||||
.get_account_at_index(1)
|
||||
.borrow()
|
||||
.lamports(),
|
||||
20
|
||||
);
|
||||
assert_eq!(
|
||||
transaction_context.get_account_at_index(0).borrow().data(),
|
||||
&vec![42]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -560,9 +585,10 @@ mod tests {
|
|||
let mut mock_program_account = AccountSharedData::new(1, 0, &native_loader::id());
|
||||
mock_program_account.set_executable(true);
|
||||
let accounts = vec![
|
||||
(secp256k1_program::id(), RefCell::new(secp256k1_account)),
|
||||
(mock_program_id, RefCell::new(mock_program_account)),
|
||||
(secp256k1_program::id(), secp256k1_account),
|
||||
(mock_program_id, mock_program_account),
|
||||
];
|
||||
let transaction_context = TransactionContext::new(accounts, 1);
|
||||
|
||||
let message = Message::new(
|
||||
&[
|
||||
|
@ -574,12 +600,11 @@ mod tests {
|
|||
],
|
||||
None,
|
||||
);
|
||||
|
||||
let result = MessageProcessor::process_message(
|
||||
builtin_programs,
|
||||
&message,
|
||||
&[vec![0], vec![1]],
|
||||
&accounts,
|
||||
&transaction_context,
|
||||
RentCollector::default().rent,
|
||||
None,
|
||||
Rc::new(RefCell::new(Executors::default())),
|
||||
|
|
|
@ -326,32 +326,25 @@ mod test {
|
|||
nonce::{self, State},
|
||||
nonce_account::{create_account, verify_nonce_account},
|
||||
system_instruction::SystemError,
|
||||
transaction_context::TransactionContext,
|
||||
},
|
||||
};
|
||||
|
||||
fn with_test_keyed_account<F>(lamports: u64, signer: bool, f: F)
|
||||
fn with_mockup<F>(lamports: u64, signer: bool, mut f: F)
|
||||
where
|
||||
F: Fn(&KeyedAccount),
|
||||
F: FnMut(&mut InvokeContext, &KeyedAccount),
|
||||
{
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
let pubkey = Pubkey::new_unique();
|
||||
let account = create_account(lamports);
|
||||
let keyed_account = KeyedAccount::new(&pubkey, signer, &account);
|
||||
f(&keyed_account)
|
||||
f(&mut invoke_context, &keyed_account)
|
||||
}
|
||||
|
||||
fn create_test_blockhash(seed: usize) -> (Hash, u64) {
|
||||
(
|
||||
hash(&bincode::serialize(&seed).unwrap()),
|
||||
(seed as u64).saturating_mul(100),
|
||||
)
|
||||
}
|
||||
|
||||
fn create_invoke_context_with_blockhash<'a>(seed: usize) -> InvokeContext<'a> {
|
||||
let mut invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let (blockhash, lamports_per_signature) = create_test_blockhash(seed);
|
||||
invoke_context.blockhash = blockhash;
|
||||
invoke_context.lamports_per_signature = lamports_per_signature;
|
||||
invoke_context
|
||||
fn set_invoke_context_blockhash(invoke_context: &mut InvokeContext, seed: usize) {
|
||||
invoke_context.blockhash = hash(&bincode::serialize(&seed).unwrap());
|
||||
invoke_context.lamports_per_signature = (seed as u64).saturating_mul(100);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -366,7 +359,7 @@ mod test {
|
|||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(State::size());
|
||||
with_test_keyed_account(min_lamports + 42, true, |keyed_account| {
|
||||
with_mockup(min_lamports + 42, true, |invoke_context, keyed_account| {
|
||||
let data = nonce::state::Data {
|
||||
authority: *keyed_account.unsigned_key(),
|
||||
..nonce::state::Data::default()
|
||||
|
@ -378,10 +371,10 @@ mod test {
|
|||
.convert_to_current();
|
||||
// New is in Uninitialzed state
|
||||
assert_eq!(state, State::Uninitialized);
|
||||
let invoke_context = create_invoke_context_with_blockhash(95);
|
||||
set_invoke_context_blockhash(invoke_context, 95);
|
||||
let authorized = keyed_account.unsigned_key();
|
||||
keyed_account
|
||||
.initialize_nonce_account(authorized, &rent, &invoke_context)
|
||||
.initialize_nonce_account(authorized, &rent, invoke_context)
|
||||
.unwrap();
|
||||
let state = AccountUtilsState::<Versions>::state(keyed_account)
|
||||
.unwrap()
|
||||
|
@ -393,9 +386,9 @@ mod test {
|
|||
);
|
||||
// First nonce instruction drives state from Uninitialized to Initialized
|
||||
assert_eq!(state, State::Initialized(data.clone()));
|
||||
let invoke_context = create_invoke_context_with_blockhash(63);
|
||||
set_invoke_context_blockhash(invoke_context, 63);
|
||||
keyed_account
|
||||
.advance_nonce_account(&signers, &invoke_context)
|
||||
.advance_nonce_account(&signers, invoke_context)
|
||||
.unwrap();
|
||||
let state = AccountUtilsState::<Versions>::state(keyed_account)
|
||||
.unwrap()
|
||||
|
@ -407,9 +400,9 @@ mod test {
|
|||
);
|
||||
// Second nonce instruction consumes and replaces stored nonce
|
||||
assert_eq!(state, State::Initialized(data.clone()));
|
||||
let invoke_context = create_invoke_context_with_blockhash(31);
|
||||
set_invoke_context_blockhash(invoke_context, 31);
|
||||
keyed_account
|
||||
.advance_nonce_account(&signers, &invoke_context)
|
||||
.advance_nonce_account(&signers, invoke_context)
|
||||
.unwrap();
|
||||
let state = AccountUtilsState::<Versions>::state(keyed_account)
|
||||
.unwrap()
|
||||
|
@ -421,8 +414,8 @@ mod test {
|
|||
);
|
||||
// Third nonce instruction for fun and profit
|
||||
assert_eq!(state, State::Initialized(data));
|
||||
with_test_keyed_account(42, false, |to_keyed| {
|
||||
let invoke_context = create_invoke_context_with_blockhash(0);
|
||||
with_mockup(42, false, |_invoke_context, to_keyed| {
|
||||
set_invoke_context_blockhash(invoke_context, 0);
|
||||
let withdraw_lamports = keyed_account.account.borrow().lamports();
|
||||
let expect_nonce_lamports =
|
||||
keyed_account.account.borrow().lamports() - withdraw_lamports;
|
||||
|
@ -433,7 +426,7 @@ mod test {
|
|||
to_keyed,
|
||||
&rent,
|
||||
&signers,
|
||||
&invoke_context,
|
||||
invoke_context,
|
||||
)
|
||||
.unwrap();
|
||||
// Empties Account balance
|
||||
|
@ -459,11 +452,11 @@ mod test {
|
|||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(State::size());
|
||||
with_test_keyed_account(min_lamports + 42, true, |nonce_account| {
|
||||
let invoke_context = create_invoke_context_with_blockhash(31);
|
||||
with_mockup(min_lamports + 42, true, |invoke_context, nonce_account| {
|
||||
set_invoke_context_blockhash(invoke_context, 31);
|
||||
let authority = *nonce_account.unsigned_key();
|
||||
nonce_account
|
||||
.initialize_nonce_account(&authority, &rent, &invoke_context)
|
||||
.initialize_nonce_account(&authority, &rent, invoke_context)
|
||||
.unwrap();
|
||||
let pubkey = *nonce_account.account.borrow().owner();
|
||||
let nonce_account = KeyedAccount::new(&pubkey, false, nonce_account.account);
|
||||
|
@ -477,9 +470,9 @@ mod test {
|
|||
);
|
||||
assert_eq!(state, State::Initialized(data));
|
||||
let signers = HashSet::new();
|
||||
let invoke_context = create_invoke_context_with_blockhash(0);
|
||||
set_invoke_context_blockhash(invoke_context, 0);
|
||||
|
||||
let result = nonce_account.advance_nonce_account(&signers, &invoke_context);
|
||||
let result = nonce_account.advance_nonce_account(&signers, invoke_context);
|
||||
assert_eq!(result, Err(InstructionError::MissingRequiredSignature),);
|
||||
})
|
||||
}
|
||||
|
@ -491,15 +484,15 @@ mod test {
|
|||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(State::size());
|
||||
with_test_keyed_account(min_lamports + 42, true, |keyed_account| {
|
||||
with_mockup(min_lamports + 42, true, |invoke_context, keyed_account| {
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(*keyed_account.signer_key().unwrap());
|
||||
let invoke_context = create_invoke_context_with_blockhash(63);
|
||||
set_invoke_context_blockhash(invoke_context, 63);
|
||||
let authorized = *keyed_account.unsigned_key();
|
||||
keyed_account
|
||||
.initialize_nonce_account(&authorized, &rent, &invoke_context)
|
||||
.initialize_nonce_account(&authorized, &rent, invoke_context)
|
||||
.unwrap();
|
||||
let result = keyed_account.advance_nonce_account(&signers, &invoke_context);
|
||||
let result = keyed_account.advance_nonce_account(&signers, invoke_context);
|
||||
assert_eq!(result, Err(SystemError::NonceBlockhashNotExpired.into()));
|
||||
})
|
||||
}
|
||||
|
@ -511,11 +504,11 @@ mod test {
|
|||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(State::size());
|
||||
with_test_keyed_account(min_lamports + 42, true, |keyed_account| {
|
||||
with_mockup(min_lamports + 42, true, |invoke_context, keyed_account| {
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(*keyed_account.signer_key().unwrap());
|
||||
let invoke_context = create_invoke_context_with_blockhash(63);
|
||||
let result = keyed_account.advance_nonce_account(&signers, &invoke_context);
|
||||
set_invoke_context_blockhash(invoke_context, 63);
|
||||
let result = keyed_account.advance_nonce_account(&signers, invoke_context);
|
||||
assert_eq!(result, Err(InstructionError::InvalidAccountData));
|
||||
})
|
||||
}
|
||||
|
@ -527,19 +520,19 @@ mod test {
|
|||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(State::size());
|
||||
with_test_keyed_account(min_lamports + 42, true, |nonce_account| {
|
||||
with_test_keyed_account(42, true, |nonce_authority| {
|
||||
with_mockup(min_lamports + 42, true, |invoke_context, nonce_account| {
|
||||
with_mockup(42, true, |_invoke_context, nonce_authority| {
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(*nonce_account.signer_key().unwrap());
|
||||
let invoke_context = create_invoke_context_with_blockhash(63);
|
||||
set_invoke_context_blockhash(invoke_context, 63);
|
||||
let authorized = *nonce_authority.unsigned_key();
|
||||
nonce_account
|
||||
.initialize_nonce_account(&authorized, &rent, &invoke_context)
|
||||
.initialize_nonce_account(&authorized, &rent, invoke_context)
|
||||
.unwrap();
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(*nonce_authority.signer_key().unwrap());
|
||||
let invoke_context = create_invoke_context_with_blockhash(31);
|
||||
let result = nonce_account.advance_nonce_account(&signers, &invoke_context);
|
||||
set_invoke_context_blockhash(invoke_context, 31);
|
||||
let result = nonce_account.advance_nonce_account(&signers, invoke_context);
|
||||
assert_eq!(result, Ok(()));
|
||||
});
|
||||
});
|
||||
|
@ -552,16 +545,16 @@ mod test {
|
|||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(State::size());
|
||||
with_test_keyed_account(min_lamports + 42, true, |nonce_account| {
|
||||
with_test_keyed_account(42, false, |nonce_authority| {
|
||||
with_mockup(min_lamports + 42, true, |invoke_context, nonce_account| {
|
||||
with_mockup(42, false, |_invoke_context, nonce_authority| {
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(*nonce_account.signer_key().unwrap());
|
||||
let invoke_context = create_invoke_context_with_blockhash(63);
|
||||
set_invoke_context_blockhash(invoke_context, 63);
|
||||
let authorized = *nonce_authority.unsigned_key();
|
||||
nonce_account
|
||||
.initialize_nonce_account(&authorized, &rent, &invoke_context)
|
||||
.initialize_nonce_account(&authorized, &rent, invoke_context)
|
||||
.unwrap();
|
||||
let result = nonce_account.advance_nonce_account(&signers, &invoke_context);
|
||||
let result = nonce_account.advance_nonce_account(&signers, invoke_context);
|
||||
assert_eq!(result, Err(InstructionError::MissingRequiredSignature),);
|
||||
});
|
||||
});
|
||||
|
@ -574,15 +567,15 @@ mod test {
|
|||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(State::size());
|
||||
with_test_keyed_account(min_lamports + 42, true, |nonce_keyed| {
|
||||
with_mockup(min_lamports + 42, true, |invoke_context, nonce_keyed| {
|
||||
let state = AccountUtilsState::<Versions>::state(nonce_keyed)
|
||||
.unwrap()
|
||||
.convert_to_current();
|
||||
assert_eq!(state, State::Uninitialized);
|
||||
with_test_keyed_account(42, false, |to_keyed| {
|
||||
with_mockup(42, false, |_invoke_context, to_keyed| {
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(*nonce_keyed.signer_key().unwrap());
|
||||
let invoke_context = create_invoke_context_with_blockhash(0);
|
||||
set_invoke_context_blockhash(invoke_context, 0);
|
||||
let withdraw_lamports = nonce_keyed.account.borrow().lamports();
|
||||
let expect_nonce_lamports =
|
||||
nonce_keyed.account.borrow().lamports() - withdraw_lamports;
|
||||
|
@ -593,7 +586,7 @@ mod test {
|
|||
to_keyed,
|
||||
&rent,
|
||||
&signers,
|
||||
&invoke_context,
|
||||
invoke_context,
|
||||
)
|
||||
.unwrap();
|
||||
let state = AccountUtilsState::<Versions>::state(nonce_keyed)
|
||||
|
@ -620,21 +613,21 @@ mod test {
|
|||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(State::size());
|
||||
with_test_keyed_account(min_lamports + 42, false, |nonce_keyed| {
|
||||
with_mockup(min_lamports + 42, false, |invoke_context, nonce_keyed| {
|
||||
let state = AccountUtilsState::<Versions>::state(nonce_keyed)
|
||||
.unwrap()
|
||||
.convert_to_current();
|
||||
assert_eq!(state, State::Uninitialized);
|
||||
with_test_keyed_account(42, false, |to_keyed| {
|
||||
with_mockup(42, false, |_invoke_context, to_keyed| {
|
||||
let signers = HashSet::new();
|
||||
let invoke_context = create_invoke_context_with_blockhash(0);
|
||||
set_invoke_context_blockhash(invoke_context, 0);
|
||||
let lamports = nonce_keyed.account.borrow().lamports();
|
||||
let result = nonce_keyed.withdraw_nonce_account(
|
||||
lamports,
|
||||
to_keyed,
|
||||
&rent,
|
||||
&signers,
|
||||
&invoke_context,
|
||||
invoke_context,
|
||||
);
|
||||
assert_eq!(result, Err(InstructionError::MissingRequiredSignature),);
|
||||
})
|
||||
|
@ -648,22 +641,22 @@ mod test {
|
|||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(State::size());
|
||||
with_test_keyed_account(min_lamports + 42, true, |nonce_keyed| {
|
||||
with_mockup(min_lamports + 42, true, |invoke_context, nonce_keyed| {
|
||||
let state = AccountUtilsState::<Versions>::state(nonce_keyed)
|
||||
.unwrap()
|
||||
.convert_to_current();
|
||||
assert_eq!(state, State::Uninitialized);
|
||||
with_test_keyed_account(42, false, |to_keyed| {
|
||||
with_mockup(42, false, |_invoke_context, to_keyed| {
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(*nonce_keyed.signer_key().unwrap());
|
||||
let invoke_context = create_invoke_context_with_blockhash(0);
|
||||
set_invoke_context_blockhash(invoke_context, 0);
|
||||
let lamports = nonce_keyed.account.borrow().lamports() + 1;
|
||||
let result = nonce_keyed.withdraw_nonce_account(
|
||||
lamports,
|
||||
to_keyed,
|
||||
&rent,
|
||||
&signers,
|
||||
&invoke_context,
|
||||
invoke_context,
|
||||
);
|
||||
assert_eq!(result, Err(InstructionError::InsufficientFunds));
|
||||
})
|
||||
|
@ -677,11 +670,11 @@ mod test {
|
|||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(State::size());
|
||||
with_test_keyed_account(min_lamports + 42, true, |nonce_keyed| {
|
||||
with_test_keyed_account(42, false, |to_keyed| {
|
||||
with_mockup(min_lamports + 42, true, |invoke_context, nonce_keyed| {
|
||||
with_mockup(42, false, |_invoke_context, to_keyed| {
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(*nonce_keyed.signer_key().unwrap());
|
||||
let invoke_context = create_invoke_context_with_blockhash(0);
|
||||
set_invoke_context_blockhash(invoke_context, 0);
|
||||
let withdraw_lamports = nonce_keyed.account.borrow().lamports() / 2;
|
||||
let nonce_expect_lamports =
|
||||
nonce_keyed.account.borrow().lamports() - withdraw_lamports;
|
||||
|
@ -692,7 +685,7 @@ mod test {
|
|||
to_keyed,
|
||||
&rent,
|
||||
&signers,
|
||||
&invoke_context,
|
||||
invoke_context,
|
||||
)
|
||||
.unwrap();
|
||||
let state = AccountUtilsState::<Versions>::state(nonce_keyed)
|
||||
|
@ -714,7 +707,7 @@ mod test {
|
|||
to_keyed,
|
||||
&rent,
|
||||
&signers,
|
||||
&invoke_context,
|
||||
invoke_context,
|
||||
)
|
||||
.unwrap();
|
||||
let state = AccountUtilsState::<Versions>::state(nonce_keyed)
|
||||
|
@ -737,13 +730,13 @@ mod test {
|
|||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(State::size());
|
||||
with_test_keyed_account(min_lamports + 42, true, |nonce_keyed| {
|
||||
with_mockup(min_lamports + 42, true, |invoke_context, nonce_keyed| {
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(*nonce_keyed.signer_key().unwrap());
|
||||
let invoke_context = create_invoke_context_with_blockhash(31);
|
||||
set_invoke_context_blockhash(invoke_context, 31);
|
||||
let authority = *nonce_keyed.unsigned_key();
|
||||
nonce_keyed
|
||||
.initialize_nonce_account(&authority, &rent, &invoke_context)
|
||||
.initialize_nonce_account(&authority, &rent, invoke_context)
|
||||
.unwrap();
|
||||
let state = AccountUtilsState::<Versions>::state(nonce_keyed)
|
||||
.unwrap()
|
||||
|
@ -754,7 +747,7 @@ mod test {
|
|||
invoke_context.lamports_per_signature,
|
||||
);
|
||||
assert_eq!(state, State::Initialized(data.clone()));
|
||||
with_test_keyed_account(42, false, |to_keyed| {
|
||||
with_mockup(42, false, |_invoke_context, to_keyed| {
|
||||
let withdraw_lamports = nonce_keyed.account.borrow().lamports() - min_lamports;
|
||||
let nonce_expect_lamports =
|
||||
nonce_keyed.account.borrow().lamports() - withdraw_lamports;
|
||||
|
@ -765,7 +758,7 @@ mod test {
|
|||
to_keyed,
|
||||
&rent,
|
||||
&signers,
|
||||
&invoke_context,
|
||||
invoke_context,
|
||||
)
|
||||
.unwrap();
|
||||
let state = AccountUtilsState::<Versions>::state(nonce_keyed)
|
||||
|
@ -782,7 +775,7 @@ mod test {
|
|||
nonce_expect_lamports
|
||||
);
|
||||
assert_eq!(to_keyed.account.borrow().lamports(), to_expect_lamports);
|
||||
let invoke_context = create_invoke_context_with_blockhash(0);
|
||||
set_invoke_context_blockhash(invoke_context, 0);
|
||||
let withdraw_lamports = nonce_keyed.account.borrow().lamports();
|
||||
let nonce_expect_lamports =
|
||||
nonce_keyed.account.borrow().lamports() - withdraw_lamports;
|
||||
|
@ -793,7 +786,7 @@ mod test {
|
|||
to_keyed,
|
||||
&rent,
|
||||
&signers,
|
||||
&invoke_context,
|
||||
invoke_context,
|
||||
)
|
||||
.unwrap();
|
||||
let state = AccountUtilsState::<Versions>::state(nonce_keyed)
|
||||
|
@ -816,13 +809,13 @@ mod test {
|
|||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(State::size());
|
||||
with_test_keyed_account(min_lamports + 42, true, |nonce_keyed| {
|
||||
let invoke_context = create_invoke_context_with_blockhash(0);
|
||||
with_mockup(min_lamports + 42, true, |invoke_context, nonce_keyed| {
|
||||
set_invoke_context_blockhash(invoke_context, 0);
|
||||
let authorized = *nonce_keyed.unsigned_key();
|
||||
nonce_keyed
|
||||
.initialize_nonce_account(&authorized, &rent, &invoke_context)
|
||||
.initialize_nonce_account(&authorized, &rent, invoke_context)
|
||||
.unwrap();
|
||||
with_test_keyed_account(42, false, |to_keyed| {
|
||||
with_mockup(42, false, |_invoke_context, to_keyed| {
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(*nonce_keyed.signer_key().unwrap());
|
||||
let withdraw_lamports = nonce_keyed.account.borrow().lamports();
|
||||
|
@ -831,7 +824,7 @@ mod test {
|
|||
to_keyed,
|
||||
&rent,
|
||||
&signers,
|
||||
&invoke_context,
|
||||
invoke_context,
|
||||
);
|
||||
assert_eq!(result, Err(SystemError::NonceBlockhashNotExpired.into()));
|
||||
})
|
||||
|
@ -845,14 +838,14 @@ mod test {
|
|||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(State::size());
|
||||
with_test_keyed_account(min_lamports + 42, true, |nonce_keyed| {
|
||||
let invoke_context = create_invoke_context_with_blockhash(95);
|
||||
with_mockup(min_lamports + 42, true, |invoke_context, nonce_keyed| {
|
||||
set_invoke_context_blockhash(invoke_context, 95);
|
||||
let authorized = *nonce_keyed.unsigned_key();
|
||||
nonce_keyed
|
||||
.initialize_nonce_account(&authorized, &rent, &invoke_context)
|
||||
.initialize_nonce_account(&authorized, &rent, invoke_context)
|
||||
.unwrap();
|
||||
with_test_keyed_account(42, false, |to_keyed| {
|
||||
let invoke_context = create_invoke_context_with_blockhash(63);
|
||||
with_mockup(42, false, |_invoke_context, to_keyed| {
|
||||
set_invoke_context_blockhash(invoke_context, 63);
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(*nonce_keyed.signer_key().unwrap());
|
||||
let withdraw_lamports = nonce_keyed.account.borrow().lamports() + 1;
|
||||
|
@ -861,7 +854,7 @@ mod test {
|
|||
to_keyed,
|
||||
&rent,
|
||||
&signers,
|
||||
&invoke_context,
|
||||
invoke_context,
|
||||
);
|
||||
assert_eq!(result, Err(InstructionError::InsufficientFunds));
|
||||
})
|
||||
|
@ -875,14 +868,14 @@ mod test {
|
|||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(State::size());
|
||||
with_test_keyed_account(min_lamports + 42, true, |nonce_keyed| {
|
||||
let invoke_context = create_invoke_context_with_blockhash(95);
|
||||
with_mockup(min_lamports + 42, true, |invoke_context, nonce_keyed| {
|
||||
set_invoke_context_blockhash(invoke_context, 95);
|
||||
let authorized = *nonce_keyed.unsigned_key();
|
||||
nonce_keyed
|
||||
.initialize_nonce_account(&authorized, &rent, &invoke_context)
|
||||
.initialize_nonce_account(&authorized, &rent, invoke_context)
|
||||
.unwrap();
|
||||
with_test_keyed_account(42, false, |to_keyed| {
|
||||
let invoke_context = create_invoke_context_with_blockhash(63);
|
||||
with_mockup(42, false, |_invoke_context, to_keyed| {
|
||||
set_invoke_context_blockhash(invoke_context, 63);
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(*nonce_keyed.signer_key().unwrap());
|
||||
let withdraw_lamports = nonce_keyed.account.borrow().lamports() - min_lamports + 1;
|
||||
|
@ -891,7 +884,7 @@ mod test {
|
|||
to_keyed,
|
||||
&rent,
|
||||
&signers,
|
||||
&invoke_context,
|
||||
invoke_context,
|
||||
);
|
||||
assert_eq!(result, Err(InstructionError::InsufficientFunds));
|
||||
})
|
||||
|
@ -905,14 +898,14 @@ mod test {
|
|||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(State::size());
|
||||
with_test_keyed_account(min_lamports + 42, true, |nonce_keyed| {
|
||||
let invoke_context = create_invoke_context_with_blockhash(95);
|
||||
with_mockup(min_lamports + 42, true, |invoke_context, nonce_keyed| {
|
||||
set_invoke_context_blockhash(invoke_context, 95);
|
||||
let authorized = *nonce_keyed.unsigned_key();
|
||||
nonce_keyed
|
||||
.initialize_nonce_account(&authorized, &rent, &invoke_context)
|
||||
.initialize_nonce_account(&authorized, &rent, invoke_context)
|
||||
.unwrap();
|
||||
with_test_keyed_account(55, false, |to_keyed| {
|
||||
let invoke_context = create_invoke_context_with_blockhash(63);
|
||||
with_mockup(55, false, |_invoke_context, to_keyed| {
|
||||
set_invoke_context_blockhash(invoke_context, 63);
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(*nonce_keyed.signer_key().unwrap());
|
||||
let withdraw_lamports = u64::MAX - 54;
|
||||
|
@ -921,7 +914,7 @@ mod test {
|
|||
to_keyed,
|
||||
&rent,
|
||||
&signers,
|
||||
&invoke_context,
|
||||
invoke_context,
|
||||
);
|
||||
assert_eq!(result, Err(InstructionError::InsufficientFunds));
|
||||
})
|
||||
|
@ -935,16 +928,16 @@ mod test {
|
|||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(State::size());
|
||||
with_test_keyed_account(min_lamports + 42, true, |keyed_account| {
|
||||
with_mockup(min_lamports + 42, true, |invoke_context, keyed_account| {
|
||||
let state = AccountUtilsState::<Versions>::state(keyed_account)
|
||||
.unwrap()
|
||||
.convert_to_current();
|
||||
assert_eq!(state, State::Uninitialized);
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(*keyed_account.signer_key().unwrap());
|
||||
let invoke_context = create_invoke_context_with_blockhash(0);
|
||||
set_invoke_context_blockhash(invoke_context, 0);
|
||||
let authority = *keyed_account.unsigned_key();
|
||||
let result = keyed_account.initialize_nonce_account(&authority, &rent, &invoke_context);
|
||||
let result = keyed_account.initialize_nonce_account(&authority, &rent, invoke_context);
|
||||
let data = nonce::state::Data::new(
|
||||
authority,
|
||||
invoke_context.blockhash,
|
||||
|
@ -965,15 +958,14 @@ mod test {
|
|||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(State::size());
|
||||
with_test_keyed_account(min_lamports + 42, true, |keyed_account| {
|
||||
let invoke_context = create_invoke_context_with_blockhash(31);
|
||||
with_mockup(min_lamports + 42, true, |invoke_context, keyed_account| {
|
||||
set_invoke_context_blockhash(invoke_context, 31);
|
||||
let authorized = *keyed_account.unsigned_key();
|
||||
keyed_account
|
||||
.initialize_nonce_account(&authorized, &rent, &invoke_context)
|
||||
.initialize_nonce_account(&authorized, &rent, invoke_context)
|
||||
.unwrap();
|
||||
let invoke_context = create_invoke_context_with_blockhash(0);
|
||||
let result =
|
||||
keyed_account.initialize_nonce_account(&authorized, &rent, &invoke_context);
|
||||
set_invoke_context_blockhash(invoke_context, 0);
|
||||
let result = keyed_account.initialize_nonce_account(&authorized, &rent, invoke_context);
|
||||
assert_eq!(result, Err(InstructionError::InvalidAccountData));
|
||||
})
|
||||
}
|
||||
|
@ -985,11 +977,10 @@ mod test {
|
|||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(State::size());
|
||||
with_test_keyed_account(min_lamports - 42, true, |keyed_account| {
|
||||
let invoke_context = create_invoke_context_with_blockhash(63);
|
||||
with_mockup(min_lamports - 42, true, |invoke_context, keyed_account| {
|
||||
set_invoke_context_blockhash(invoke_context, 63);
|
||||
let authorized = *keyed_account.unsigned_key();
|
||||
let result =
|
||||
keyed_account.initialize_nonce_account(&authorized, &rent, &invoke_context);
|
||||
let result = keyed_account.initialize_nonce_account(&authorized, &rent, invoke_context);
|
||||
assert_eq!(result, Err(InstructionError::InsufficientFunds));
|
||||
})
|
||||
}
|
||||
|
@ -1001,13 +992,13 @@ mod test {
|
|||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(State::size());
|
||||
with_test_keyed_account(min_lamports + 42, true, |nonce_account| {
|
||||
with_mockup(min_lamports + 42, true, |invoke_context, nonce_account| {
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(*nonce_account.signer_key().unwrap());
|
||||
let invoke_context = create_invoke_context_with_blockhash(31);
|
||||
set_invoke_context_blockhash(invoke_context, 31);
|
||||
let authorized = *nonce_account.unsigned_key();
|
||||
nonce_account
|
||||
.initialize_nonce_account(&authorized, &rent, &invoke_context)
|
||||
.initialize_nonce_account(&authorized, &rent, invoke_context)
|
||||
.unwrap();
|
||||
let authority = Pubkey::default();
|
||||
let data = nonce::state::Data::new(
|
||||
|
@ -1015,11 +1006,8 @@ mod test {
|
|||
invoke_context.blockhash,
|
||||
invoke_context.lamports_per_signature,
|
||||
);
|
||||
let result = nonce_account.authorize_nonce_account(
|
||||
&Pubkey::default(),
|
||||
&signers,
|
||||
&invoke_context,
|
||||
);
|
||||
let result =
|
||||
nonce_account.authorize_nonce_account(&Pubkey::default(), &signers, invoke_context);
|
||||
assert_eq!(result, Ok(()));
|
||||
let state = AccountUtilsState::<Versions>::state(nonce_account)
|
||||
.unwrap()
|
||||
|
@ -1035,14 +1023,11 @@ mod test {
|
|||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(State::size());
|
||||
with_test_keyed_account(min_lamports + 42, true, |nonce_account| {
|
||||
with_mockup(min_lamports + 42, true, |invoke_context, nonce_account| {
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(*nonce_account.signer_key().unwrap());
|
||||
let result = nonce_account.authorize_nonce_account(
|
||||
&Pubkey::default(),
|
||||
&signers,
|
||||
&InvokeContext::new_mock(&[], &[]),
|
||||
);
|
||||
let result =
|
||||
nonce_account.authorize_nonce_account(&Pubkey::default(), &signers, invoke_context);
|
||||
assert_eq!(result, Err(InstructionError::InvalidAccountData));
|
||||
})
|
||||
}
|
||||
|
@ -1054,35 +1039,32 @@ mod test {
|
|||
..Rent::default()
|
||||
};
|
||||
let min_lamports = rent.minimum_balance(State::size());
|
||||
with_test_keyed_account(min_lamports + 42, true, |nonce_account| {
|
||||
with_mockup(min_lamports + 42, true, |invoke_context, nonce_account| {
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(*nonce_account.signer_key().unwrap());
|
||||
let invoke_context = create_invoke_context_with_blockhash(31);
|
||||
set_invoke_context_blockhash(invoke_context, 31);
|
||||
let authorized = &Pubkey::default().clone();
|
||||
nonce_account
|
||||
.initialize_nonce_account(authorized, &rent, &invoke_context)
|
||||
.initialize_nonce_account(authorized, &rent, invoke_context)
|
||||
.unwrap();
|
||||
let result = nonce_account.authorize_nonce_account(
|
||||
&Pubkey::default(),
|
||||
&signers,
|
||||
&invoke_context,
|
||||
);
|
||||
let result =
|
||||
nonce_account.authorize_nonce_account(&Pubkey::default(), &signers, invoke_context);
|
||||
assert_eq!(result, Err(InstructionError::MissingRequiredSignature));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_nonce_ok() {
|
||||
with_test_keyed_account(42, true, |nonce_account| {
|
||||
with_mockup(42, true, |invoke_context, nonce_account| {
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(nonce_account.signer_key().unwrap());
|
||||
let state: State = nonce_account.state().unwrap();
|
||||
// New is in Uninitialzed state
|
||||
assert_eq!(state, State::Uninitialized);
|
||||
let invoke_context = create_invoke_context_with_blockhash(0);
|
||||
set_invoke_context_blockhash(invoke_context, 0);
|
||||
let authorized = nonce_account.unsigned_key();
|
||||
nonce_account
|
||||
.initialize_nonce_account(authorized, &Rent::free(), &invoke_context)
|
||||
.initialize_nonce_account(authorized, &Rent::free(), invoke_context)
|
||||
.unwrap();
|
||||
assert!(verify_nonce_account(
|
||||
&nonce_account.account.borrow(),
|
||||
|
@ -1093,7 +1075,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn verify_nonce_bad_acc_state_fail() {
|
||||
with_test_keyed_account(42, true, |nonce_account| {
|
||||
with_mockup(42, true, |_invoke_context, nonce_account| {
|
||||
assert!(!verify_nonce_account(
|
||||
&nonce_account.account.borrow(),
|
||||
&Hash::default()
|
||||
|
@ -1103,18 +1085,18 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn verify_nonce_bad_query_hash_fail() {
|
||||
with_test_keyed_account(42, true, |nonce_account| {
|
||||
with_mockup(42, true, |invoke_context, nonce_account| {
|
||||
let mut signers = HashSet::new();
|
||||
signers.insert(nonce_account.signer_key().unwrap());
|
||||
let state: State = nonce_account.state().unwrap();
|
||||
// New is in Uninitialzed state
|
||||
assert_eq!(state, State::Uninitialized);
|
||||
let invoke_context = create_invoke_context_with_blockhash(0);
|
||||
set_invoke_context_blockhash(invoke_context, 0);
|
||||
let authorized = nonce_account.unsigned_key();
|
||||
nonce_account
|
||||
.initialize_nonce_account(authorized, &Rent::free(), &invoke_context)
|
||||
.initialize_nonce_account(authorized, &Rent::free(), invoke_context)
|
||||
.unwrap();
|
||||
let invoke_context = create_invoke_context_with_blockhash(1);
|
||||
set_invoke_context_blockhash(invoke_context, 1);
|
||||
assert!(!verify_nonce_account(
|
||||
&nonce_account.account.borrow(),
|
||||
&invoke_context.blockhash,
|
||||
|
|
|
@ -502,6 +502,7 @@ mod tests {
|
|||
system_instruction, system_program, sysvar,
|
||||
sysvar::recent_blockhashes::IterItem,
|
||||
transaction::TransactionError,
|
||||
transaction_context::TransactionContext,
|
||||
};
|
||||
use {
|
||||
super::*,
|
||||
|
@ -674,7 +675,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_address_create_with_seed_mismatch() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
let from = Pubkey::new_unique();
|
||||
let seed = "dull boy";
|
||||
let to = Pubkey::new_unique();
|
||||
|
@ -688,7 +690,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_create_account_with_seed_missing_sig() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
let new_owner = Pubkey::new(&[9; 32]);
|
||||
let from = Pubkey::new_unique();
|
||||
let seed = "dull boy";
|
||||
|
@ -718,7 +721,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_create_with_zero_lamports() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
// create account with zero lamports transferred
|
||||
let new_owner = Pubkey::new(&[9; 32]);
|
||||
let from = Pubkey::new_unique();
|
||||
|
@ -752,7 +756,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_create_negative_lamports() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
// Attempt to create account with more lamports than remaining in from_account
|
||||
let new_owner = Pubkey::new(&[9; 32]);
|
||||
let from = Pubkey::new_unique();
|
||||
|
@ -776,7 +781,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_request_more_than_allowed_data_length() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
let from_account = RefCell::new(AccountSharedData::new(100, 0, &system_program::id()));
|
||||
let from = Pubkey::new_unique();
|
||||
let to_account = RefCell::new(AccountSharedData::new(0, 0, &system_program::id()));
|
||||
|
@ -823,7 +829,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_create_already_in_use() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
// Attempt to create system account in account already owned by another program
|
||||
let new_owner = Pubkey::new(&[9; 32]);
|
||||
let from = Pubkey::new_unique();
|
||||
|
@ -891,7 +898,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_create_unsigned() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
// Attempt to create an account without signing the transfer
|
||||
let new_owner = Pubkey::new(&[9; 32]);
|
||||
let from = Pubkey::new_unique();
|
||||
|
@ -946,7 +954,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_create_sysvar_invalid_id_with_feature() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
// Attempt to create system account in account already owned by another program
|
||||
let from = Pubkey::new_unique();
|
||||
let from_account = RefCell::new(AccountSharedData::new(100, 0, &system_program::id()));
|
||||
|
@ -980,7 +989,8 @@ mod tests {
|
|||
feature_set
|
||||
.inactive
|
||||
.insert(feature_set::rent_for_sysvars::id());
|
||||
let mut invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
invoke_context.feature_set = Arc::new(feature_set);
|
||||
// Attempt to create system account in account already owned by another program
|
||||
let from = Pubkey::new_unique();
|
||||
|
@ -1007,7 +1017,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_create_data_populated() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
// Attempt to create system account in account with populated data
|
||||
let new_owner = Pubkey::new(&[9; 32]);
|
||||
let from = Pubkey::new_unique();
|
||||
|
@ -1040,7 +1051,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_create_from_account_is_nonce_fail() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
let nonce = Pubkey::new_unique();
|
||||
let nonce_account = RefCell::new(
|
||||
AccountSharedData::new_data(
|
||||
|
@ -1078,7 +1090,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_assign() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
let new_owner = Pubkey::new(&[9; 32]);
|
||||
let pubkey = Pubkey::new_unique();
|
||||
let mut account = AccountSharedData::new(100, 0, &system_program::id());
|
||||
|
@ -1120,7 +1133,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_assign_to_sysvar_with_feature() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
let new_owner = sysvar::id();
|
||||
let from = Pubkey::new_unique();
|
||||
let mut from_account = AccountSharedData::new(100, 0, &system_program::id());
|
||||
|
@ -1146,7 +1160,8 @@ mod tests {
|
|||
feature_set
|
||||
.inactive
|
||||
.insert(feature_set::rent_for_sysvars::id());
|
||||
let mut invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
invoke_context.feature_set = Arc::new(feature_set);
|
||||
let new_owner = sysvar::id();
|
||||
let from = Pubkey::new_unique();
|
||||
|
@ -1197,7 +1212,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_transfer_lamports() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
let from = Pubkey::new_unique();
|
||||
let from_account = RefCell::new(AccountSharedData::new(100, 0, &Pubkey::new(&[2; 32]))); // account owner should not matter
|
||||
let to = Pubkey::new(&[3; 32]);
|
||||
|
@ -1235,7 +1251,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_transfer_with_seed() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
let base = Pubkey::new_unique();
|
||||
let base_account = RefCell::new(AccountSharedData::new(100, 0, &Pubkey::new(&[2; 32]))); // account owner should not matter
|
||||
let from_base_keyed_account = KeyedAccount::new(&base, true, &base_account);
|
||||
|
@ -1295,7 +1312,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_transfer_lamports_from_nonce_account_fail() {
|
||||
let invoke_context = InvokeContext::new_mock(&[], &[]);
|
||||
let transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
|
||||
let from = Pubkey::new_unique();
|
||||
let from_account = RefCell::new(
|
||||
AccountSharedData::new_data(
|
||||
|
|
|
@ -46,6 +46,7 @@ pub mod signer;
|
|||
pub mod system_transaction;
|
||||
pub mod timing;
|
||||
pub mod transaction;
|
||||
pub mod transaction_context;
|
||||
pub mod transport;
|
||||
pub mod wasm;
|
||||
|
||||
|
|
|
@ -0,0 +1,342 @@
|
|||
//! Successors of instruction_context_context::StackFrame, KeyedAccount and AccountInfo
|
||||
|
||||
use crate::{
|
||||
account::{AccountSharedData, ReadableAccount, WritableAccount},
|
||||
instruction::InstructionError,
|
||||
pubkey::Pubkey,
|
||||
};
|
||||
use std::cell::{RefCell, RefMut};
|
||||
|
||||
pub type TransactionAccount = (Pubkey, AccountSharedData);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct InstructionAccount {
|
||||
pub index: usize,
|
||||
pub is_signer: bool,
|
||||
pub is_writable: bool,
|
||||
}
|
||||
|
||||
/// Loaded transaction shared between runtime and programs.
|
||||
///
|
||||
/// This context is valid for the entire duration of a transaction being processed.
|
||||
pub struct TransactionContext {
|
||||
account_keys: Vec<Pubkey>,
|
||||
accounts: Vec<RefCell<AccountSharedData>>,
|
||||
instruction_context_capacity: usize,
|
||||
instruction_context_stack: Vec<InstructionContext>,
|
||||
return_data: (Pubkey, Vec<u8>),
|
||||
}
|
||||
|
||||
impl TransactionContext {
|
||||
/// Constructs a new TransactionContext
|
||||
pub fn new(
|
||||
transaction_accounts: Vec<TransactionAccount>,
|
||||
instruction_context_capacity: usize,
|
||||
) -> Self {
|
||||
let (account_keys, accounts) = transaction_accounts
|
||||
.into_iter()
|
||||
.map(|(key, account)| (key, RefCell::new(account)))
|
||||
.unzip();
|
||||
Self {
|
||||
account_keys,
|
||||
accounts,
|
||||
instruction_context_capacity,
|
||||
instruction_context_stack: Vec::with_capacity(instruction_context_capacity),
|
||||
return_data: (Pubkey::default(), Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Used by the bank in the runtime to write back the processed accounts
|
||||
pub fn deconstruct(self) -> Vec<TransactionAccount> {
|
||||
self.account_keys
|
||||
.into_iter()
|
||||
.zip(
|
||||
self.accounts
|
||||
.into_iter()
|
||||
.map(|account| account.into_inner()),
|
||||
)
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Used in mock_process_instruction
|
||||
pub fn deconstruct_without_keys(self) -> Result<Vec<AccountSharedData>, InstructionError> {
|
||||
if !self.instruction_context_stack.is_empty() {
|
||||
return Err(InstructionError::CallDepth);
|
||||
}
|
||||
Ok(self
|
||||
.accounts
|
||||
.into_iter()
|
||||
.map(|account| account.into_inner())
|
||||
.collect())
|
||||
}
|
||||
|
||||
/// Returns the total number of accounts loaded in this Transaction
|
||||
pub fn get_number_of_accounts(&self) -> usize {
|
||||
self.accounts.len()
|
||||
}
|
||||
|
||||
/// Searches for an account by its key
|
||||
pub fn get_key_of_account_at_index(&self, index_in_transaction: usize) -> &Pubkey {
|
||||
&self.account_keys[index_in_transaction]
|
||||
}
|
||||
|
||||
/// Searches for an account by its key
|
||||
pub fn get_account_at_index(&self, index_in_transaction: usize) -> &RefCell<AccountSharedData> {
|
||||
&self.accounts[index_in_transaction]
|
||||
}
|
||||
|
||||
/// Searches for an account by its key
|
||||
pub fn find_index_of_account(&self, pubkey: &Pubkey) -> Option<usize> {
|
||||
self.account_keys.iter().position(|key| key == pubkey)
|
||||
}
|
||||
|
||||
/// Searches for a program account by its key
|
||||
pub fn find_index_of_program_account(&self, pubkey: &Pubkey) -> Option<usize> {
|
||||
self.account_keys.iter().rposition(|key| key == pubkey)
|
||||
}
|
||||
|
||||
/// Gets an InstructionContext by its height in the stack
|
||||
pub fn get_instruction_context_at(
|
||||
&self,
|
||||
instruction_context_height: usize,
|
||||
) -> Result<&InstructionContext, InstructionError> {
|
||||
if instruction_context_height >= self.instruction_context_stack.len() {
|
||||
return Err(InstructionError::CallDepth);
|
||||
}
|
||||
Ok(&self.instruction_context_stack[instruction_context_height])
|
||||
}
|
||||
|
||||
/// Gets the max height of the InstructionContext stack
|
||||
pub fn get_instruction_context_capacity(&self) -> usize {
|
||||
self.instruction_context_capacity
|
||||
}
|
||||
|
||||
/// Gets the height of the current InstructionContext
|
||||
pub fn get_instruction_context_height(&self) -> usize {
|
||||
self.instruction_context_stack.len().saturating_sub(1)
|
||||
}
|
||||
|
||||
/// Returns the current InstructionContext
|
||||
pub fn get_current_instruction_context(&self) -> Result<&InstructionContext, InstructionError> {
|
||||
self.get_instruction_context_at(self.get_instruction_context_height())
|
||||
}
|
||||
|
||||
/// Gets the last program account of the current InstructionContext
|
||||
pub fn try_borrow_program_account(&self) -> Result<BorrowedAccount, InstructionError> {
|
||||
let instruction_context = self.get_current_instruction_context()?;
|
||||
instruction_context.try_borrow_account(
|
||||
self,
|
||||
instruction_context
|
||||
.number_of_program_accounts
|
||||
.saturating_sub(1),
|
||||
)
|
||||
}
|
||||
|
||||
/// Gets an instruction account of the current InstructionContext
|
||||
pub fn try_borrow_instruction_account(
|
||||
&self,
|
||||
index_in_instruction: usize,
|
||||
) -> Result<BorrowedAccount, InstructionError> {
|
||||
let instruction_context = self.get_current_instruction_context()?;
|
||||
instruction_context.try_borrow_account(
|
||||
self,
|
||||
instruction_context
|
||||
.number_of_program_accounts
|
||||
.saturating_add(index_in_instruction),
|
||||
)
|
||||
}
|
||||
|
||||
/// Pushes a new InstructionContext
|
||||
pub fn push(
|
||||
&mut self,
|
||||
number_of_program_accounts: usize,
|
||||
instruction_accounts: &[InstructionAccount],
|
||||
instruction_data: Vec<u8>,
|
||||
) -> Result<(), InstructionError> {
|
||||
if self.instruction_context_stack.len() >= self.instruction_context_capacity {
|
||||
return Err(InstructionError::CallDepth);
|
||||
}
|
||||
let mut result = InstructionContext {
|
||||
instruction_data,
|
||||
number_of_program_accounts,
|
||||
account_indices: Vec::with_capacity(instruction_accounts.len()),
|
||||
account_is_signer: Vec::with_capacity(instruction_accounts.len()),
|
||||
account_is_writable: Vec::with_capacity(instruction_accounts.len()),
|
||||
};
|
||||
for instruction_account in instruction_accounts.iter() {
|
||||
result.account_indices.push(instruction_account.index);
|
||||
result.account_is_signer.push(instruction_account.is_signer);
|
||||
result
|
||||
.account_is_writable
|
||||
.push(instruction_account.is_writable);
|
||||
}
|
||||
self.instruction_context_stack.push(result);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Pops the current InstructionContext
|
||||
pub fn pop(&mut self) -> Result<(), InstructionError> {
|
||||
if self.instruction_context_stack.is_empty() {
|
||||
return Err(InstructionError::CallDepth);
|
||||
}
|
||||
self.instruction_context_stack.pop();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Gets the return data of the current InstructionContext or any above
|
||||
pub fn get_return_data(&self) -> (&Pubkey, &[u8]) {
|
||||
(&self.return_data.0, &self.return_data.1)
|
||||
}
|
||||
|
||||
/// Set the return data of the current InstructionContext
|
||||
pub fn set_return_data(&mut self, data: Vec<u8>) -> Result<(), InstructionError> {
|
||||
let pubkey = *self.try_borrow_program_account()?.get_key();
|
||||
self.return_data = (pubkey, data);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Loaded instruction shared between runtime and programs.
|
||||
///
|
||||
/// This context is valid for the entire duration of a (possibly cross program) instruction being processed.
|
||||
pub struct InstructionContext {
|
||||
number_of_program_accounts: usize,
|
||||
account_indices: Vec<usize>,
|
||||
account_is_signer: Vec<bool>,
|
||||
account_is_writable: Vec<bool>,
|
||||
instruction_data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl InstructionContext {
|
||||
/// Number of program accounts
|
||||
pub fn get_number_of_program_accounts(&self) -> usize {
|
||||
self.number_of_program_accounts
|
||||
}
|
||||
|
||||
/// Number of accounts in this Instruction (without program accounts)
|
||||
pub fn get_number_of_instruction_accounts(&self) -> usize {
|
||||
self.account_indices
|
||||
.len()
|
||||
.saturating_sub(self.number_of_program_accounts)
|
||||
}
|
||||
|
||||
/// Total number of accounts in this Instruction (with program accounts)
|
||||
pub fn get_total_number_of_accounts(&self) -> usize {
|
||||
self.account_indices.len()
|
||||
}
|
||||
|
||||
/// Data parameter for the programs `process_instruction` handler
|
||||
pub fn get_instruction_data(&self) -> &[u8] {
|
||||
&self.instruction_data
|
||||
}
|
||||
|
||||
/// Tries to borrow an account from this Instruction
|
||||
pub fn try_borrow_account<'a, 'b: 'a>(
|
||||
&'a self,
|
||||
transaction_context: &'b TransactionContext,
|
||||
index_in_instruction: usize,
|
||||
) -> Result<BorrowedAccount<'a>, InstructionError> {
|
||||
if index_in_instruction >= self.account_indices.len() {
|
||||
return Err(InstructionError::NotEnoughAccountKeys);
|
||||
}
|
||||
let index_in_transaction = self.account_indices[index_in_instruction];
|
||||
if index_in_transaction >= transaction_context.accounts.len() {
|
||||
return Err(InstructionError::MissingAccount);
|
||||
}
|
||||
let account = transaction_context.accounts[index_in_transaction]
|
||||
.try_borrow_mut()
|
||||
.map_err(|_| InstructionError::AccountBorrowFailed)?;
|
||||
Ok(BorrowedAccount {
|
||||
transaction_context,
|
||||
instruction_context: self,
|
||||
index_in_transaction,
|
||||
index_in_instruction,
|
||||
account,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Shared account borrowed from the TransactionContext and an InstructionContext.
|
||||
pub struct BorrowedAccount<'a> {
|
||||
transaction_context: &'a TransactionContext,
|
||||
instruction_context: &'a InstructionContext,
|
||||
index_in_transaction: usize,
|
||||
index_in_instruction: usize,
|
||||
account: RefMut<'a, AccountSharedData>,
|
||||
}
|
||||
|
||||
impl<'a> BorrowedAccount<'a> {
|
||||
/// Returns the public key of this account (transaction wide)
|
||||
pub fn get_key(&self) -> &Pubkey {
|
||||
&self.transaction_context.account_keys[self.index_in_transaction]
|
||||
}
|
||||
|
||||
/// Returns the owner of this account (transaction wide)
|
||||
pub fn get_owner(&self) -> &Pubkey {
|
||||
self.account.owner()
|
||||
}
|
||||
|
||||
/// Assignes the owner of this account (transaction wide)
|
||||
pub fn set_owner(&mut self, pubkey: Pubkey) -> Result<(), InstructionError> {
|
||||
if !self.is_writable() {
|
||||
return Err(InstructionError::Immutable);
|
||||
}
|
||||
self.account.set_owner(pubkey);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the number of lamports of this account (transaction wide)
|
||||
pub fn get_lamports(&self) -> u64 {
|
||||
self.account.lamports()
|
||||
}
|
||||
|
||||
/// Overwrites the number of lamports of this account (transaction wide)
|
||||
pub fn set_lamports(&mut self, lamports: u64) -> Result<(), InstructionError> {
|
||||
if !self.is_writable() {
|
||||
return Err(InstructionError::Immutable);
|
||||
}
|
||||
self.account.set_lamports(lamports);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns a read-only slice of the account data (transaction wide)
|
||||
pub fn get_data(&self) -> &[u8] {
|
||||
self.account.data()
|
||||
}
|
||||
|
||||
/// Returns a writable slice of the account data (transaction wide)
|
||||
pub fn get_data_mut(&mut self) -> Result<&mut [u8], InstructionError> {
|
||||
if !self.is_writable() {
|
||||
return Err(InstructionError::Immutable);
|
||||
}
|
||||
Ok(self.account.data_as_mut_slice())
|
||||
}
|
||||
|
||||
/*pub fn realloc(&self, new_len: usize, zero_init: bool) {
|
||||
// TODO
|
||||
}*/
|
||||
|
||||
/// Returns whether this account is executable (transaction wide)
|
||||
pub fn is_executable(&self) -> bool {
|
||||
self.account.executable()
|
||||
}
|
||||
|
||||
/// Configures whether this account is executable (transaction wide)
|
||||
pub fn set_executable(&mut self, is_executable: bool) -> Result<(), InstructionError> {
|
||||
if !self.is_writable() {
|
||||
return Err(InstructionError::Immutable);
|
||||
}
|
||||
self.account.set_executable(is_executable);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns whether this account is a signer (instruction wide)
|
||||
pub fn is_signer(&self) -> bool {
|
||||
self.instruction_context.account_is_signer[self.index_in_instruction]
|
||||
}
|
||||
|
||||
/// Returns whether this account is writable (instruction wide)
|
||||
pub fn is_writable(&self) -> bool {
|
||||
self.instruction_context.account_is_writable[self.index_in_instruction]
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue