Refactor: Remove KeyedAccount from program runtime (#22226)

* Makes error handling in BorrowedAccount optional.
Adds BorrowedAccount ::get_rent_epoch().
Exposes InstructionContext::get_index_in_transaction().
Turns accounts and account_keys into pinned boxed slices.

* Introduces "unsafe" to InvokeContext::push().

* Turns &TransactionContext into &mut TransactionContext in InvokeContext.

* Push and pop InstructionContext in InvokeContext.
Makes test_process_cross_program and test_native_invoke symmetric.
Removes the borrow check from test_invoke_context_verify.

* Removes keyed_accounts from prepare_instruction()

* Removes usage of invoke_stack.

* Removes keyed_accounts from program-test.

* Removes caller_write_privileges.

* Removes keyed_accounts from BPF parameter (de-)serialization.
This commit is contained in:
Alexander Meißner
2022-01-03 23:30:56 +01:00
committed by GitHub
parent 672fed04cb
commit 73e6038986
18 changed files with 847 additions and 805 deletions

View File

@ -209,12 +209,9 @@ fn bench_create_vm(bencher: &mut Bencher) {
.mock_set_remaining(BUDGET);
// Serialize account data
let keyed_accounts = invoke_context.get_keyed_accounts().unwrap();
let (mut serialized, account_lengths) = serialize_parameters(
&keyed_accounts[0].unsigned_key(),
&keyed_accounts[1].unsigned_key(),
&keyed_accounts[2..],
&[],
invoke_context.transaction_context,
invoke_context.transaction_context.get_current_instruction_context().unwrap(),
)
.unwrap();
@ -250,12 +247,9 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
.mock_set_remaining(BUDGET);
// Serialize account data
let keyed_accounts = invoke_context.get_keyed_accounts().unwrap();
let (mut serialized, account_lengths) = serialize_parameters(
&keyed_accounts[0].unsigned_key(),
&keyed_accounts[1].unsigned_key(),
&keyed_accounts[2..],
&[],
invoke_context.transaction_context,
invoke_context.transaction_context.get_current_instruction_context().unwrap(),
)
.unwrap();

View File

@ -196,12 +196,9 @@ fn run_program(name: &str) -> u64 {
file.read_to_end(&mut data).unwrap();
let loader_id = bpf_loader::id();
with_mock_invoke_context(loader_id, 0, |invoke_context| {
let keyed_accounts = invoke_context.get_keyed_accounts().unwrap();
let (parameter_bytes, account_lengths) = serialize_parameters(
&keyed_accounts[0].unsigned_key(),
&keyed_accounts[1].unsigned_key(),
&keyed_accounts[2..],
&[],
invoke_context.transaction_context,
invoke_context.transaction_context.get_current_instruction_context().unwrap(),
)
.unwrap();
@ -227,7 +224,7 @@ fn run_program(name: &str) -> u64 {
let mut instruction_count = 0;
let mut tracer = None;
for i in 0..2 {
invoke_context.return_data = (*invoke_context.get_caller().unwrap(), Vec::new());
invoke_context.return_data = (*invoke_context.transaction_context.get_program_key().unwrap(), Vec::new());
let mut parameter_bytes = parameter_bytes.clone();
{
let mut vm = create_vm(
@ -278,10 +275,9 @@ fn run_program(name: &str) -> u64 {
tracer = Some(vm.get_tracer().clone());
}
}
let keyed_accounts = invoke_context.get_keyed_accounts().unwrap();
deserialize_parameters(
&loader_id,
&keyed_accounts[2..],
invoke_context.transaction_context,
invoke_context.transaction_context.get_current_instruction_context().unwrap(),
parameter_bytes.as_slice(),
&account_lengths,
true,

View File

@ -9,136 +9,123 @@ use {
solana_sdk::{
account::{Account, AccountSharedData},
bpf_loader,
keyed_account::KeyedAccount,
pubkey::Pubkey,
transaction_context::{InstructionAccount, TransactionContext},
},
std::cell::RefCell,
test::Bencher,
};
fn create_inputs() -> (
Pubkey,
Vec<Pubkey>,
Vec<RefCell<AccountSharedData>>,
Vec<u8>,
) {
fn create_inputs() -> TransactionContext {
let program_id = solana_sdk::pubkey::new_rand();
let dup_key = solana_sdk::pubkey::new_rand();
let dup_key2 = solana_sdk::pubkey::new_rand();
let keys = vec![
dup_key,
dup_key,
solana_sdk::pubkey::new_rand(),
solana_sdk::pubkey::new_rand(),
dup_key2,
dup_key2,
solana_sdk::pubkey::new_rand(),
solana_sdk::pubkey::new_rand(),
let transaction_accounts = vec![
(
program_id,
AccountSharedData::from(Account {
lamports: 0,
data: vec![],
owner: bpf_loader::id(),
executable: true,
rent_epoch: 0,
}),
),
(
solana_sdk::pubkey::new_rand(),
AccountSharedData::from(Account {
lamports: 1,
data: vec![1u8; 100000],
owner: bpf_loader::id(),
executable: false,
rent_epoch: 100,
}),
),
(
solana_sdk::pubkey::new_rand(),
AccountSharedData::from(Account {
lamports: 2,
data: vec![11u8; 100000],
owner: bpf_loader::id(),
executable: true,
rent_epoch: 200,
}),
),
(
solana_sdk::pubkey::new_rand(),
AccountSharedData::from(Account {
lamports: 3,
data: vec![],
owner: bpf_loader::id(),
executable: false,
rent_epoch: 3100,
}),
),
(
solana_sdk::pubkey::new_rand(),
AccountSharedData::from(Account {
lamports: 4,
data: vec![1u8; 100000],
owner: bpf_loader::id(),
executable: false,
rent_epoch: 100,
}),
),
(
solana_sdk::pubkey::new_rand(),
AccountSharedData::from(Account {
lamports: 5,
data: vec![11u8; 10000],
owner: bpf_loader::id(),
executable: true,
rent_epoch: 200,
}),
),
(
solana_sdk::pubkey::new_rand(),
AccountSharedData::from(Account {
lamports: 6,
data: vec![],
owner: bpf_loader::id(),
executable: false,
rent_epoch: 3100,
}),
),
];
let accounts = vec![
RefCell::new(AccountSharedData::from(Account {
lamports: 1,
data: vec![1u8, 2, 3, 4, 5],
owner: bpf_loader::id(),
executable: false,
rent_epoch: 100,
})),
// dup
RefCell::new(AccountSharedData::from(Account {
lamports: 1,
data: vec![1u8; 100000],
owner: bpf_loader::id(),
executable: false,
rent_epoch: 100,
})),
RefCell::new(AccountSharedData::from(Account {
lamports: 2,
data: vec![11u8; 100000],
owner: bpf_loader::id(),
executable: true,
rent_epoch: 200,
})),
RefCell::new(AccountSharedData::from(Account {
lamports: 3,
data: vec![],
owner: bpf_loader::id(),
executable: false,
rent_epoch: 3100,
})),
RefCell::new(AccountSharedData::from(Account {
lamports: 4,
data: vec![1u8; 100000],
owner: bpf_loader::id(),
executable: false,
rent_epoch: 100,
})),
// dup
RefCell::new(AccountSharedData::from(Account {
lamports: 4,
data: vec![1u8; 1000000],
owner: bpf_loader::id(),
executable: false,
rent_epoch: 100,
})),
RefCell::new(AccountSharedData::from(Account {
lamports: 5,
data: vec![11u8; 10000],
owner: bpf_loader::id(),
executable: true,
rent_epoch: 200,
})),
RefCell::new(AccountSharedData::from(Account {
lamports: 6,
data: vec![],
owner: bpf_loader::id(),
executable: false,
rent_epoch: 3100,
})),
];
let instruction_accounts = [1, 1, 2, 3, 4, 4, 5, 6]
.into_iter()
.enumerate()
.map(
|(index_in_instruction, index_in_transaction)| InstructionAccount {
index_in_caller: 1usize.saturating_add(index_in_instruction),
index_in_transaction,
is_signer: false,
is_writable: index_in_instruction >= 4,
},
)
.collect::<Vec<_>>();
let mut transaction_context = TransactionContext::new(transaction_accounts, 1);
let instruction_data = vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
(program_id, keys, accounts, instruction_data)
transaction_context
.push(&[0], &instruction_accounts, &instruction_data)
.unwrap();
transaction_context
}
#[bench]
fn bench_serialize_unaligned(bencher: &mut Bencher) {
let (program_id, keys, accounts, instruction_data) = create_inputs();
let keyed_accounts: Vec<_> = keys
.iter()
.zip(&accounts)
.enumerate()
.map(|(i, (key, account))| {
if i <= accounts.len() / 2 {
KeyedAccount::new_readonly(key, false, account)
} else {
KeyedAccount::new(key, false, account)
}
})
.collect();
let transaction_context = create_inputs();
let instruction_context = transaction_context
.get_current_instruction_context()
.unwrap();
bencher.iter(|| {
let _ = serialize_parameters_unaligned(&program_id, &keyed_accounts, &instruction_data)
.unwrap();
let _ = serialize_parameters_unaligned(&transaction_context, instruction_context).unwrap();
});
}
#[bench]
fn bench_serialize_aligned(bencher: &mut Bencher) {
let (program_id, keys, accounts, instruction_data) = create_inputs();
let keyed_accounts: Vec<_> = keys
.iter()
.zip(&accounts)
.enumerate()
.map(|(i, (key, account))| {
if i <= accounts.len() / 2 {
KeyedAccount::new_readonly(key, false, account)
} else {
KeyedAccount::new(key, false, account)
}
})
.collect();
let transaction_context = create_inputs();
let instruction_context = transaction_context
.get_current_instruction_context()
.unwrap();
bencher.iter(|| {
let _ =
serialize_parameters_aligned(&program_id, &keyed_accounts, &instruction_data).unwrap();
let _ = serialize_parameters_aligned(&transaction_context, instruction_context).unwrap();
});
}

View File

@ -225,7 +225,7 @@ fn process_instruction_common(
use_jit: bool,
) -> Result<(), InstructionError> {
let log_collector = invoke_context.get_log_collector();
let program_id = invoke_context.get_caller()?;
let program_id = invoke_context.transaction_context.get_program_key()?;
let keyed_accounts = invoke_context.get_keyed_accounts()?;
let first_account = keyed_account_at_index(keyed_accounts, first_instruction_account)?;
@ -301,7 +301,7 @@ fn process_instruction_common(
use_jit,
false,
)?;
let program_id = invoke_context.get_caller()?;
let program_id = invoke_context.transaction_context.get_program_key()?;
invoke_context.add_executor(program_id, executor.clone());
executor
}
@ -342,7 +342,7 @@ fn process_loader_upgradeable_instruction(
use_jit: bool,
) -> Result<(), InstructionError> {
let log_collector = invoke_context.get_log_collector();
let program_id = invoke_context.get_caller()?;
let program_id = invoke_context.transaction_context.get_program_key()?;
let keyed_accounts = invoke_context.get_keyed_accounts()?;
match limited_deserialize(instruction_data)? {
@ -495,7 +495,7 @@ fn process_loader_upgradeable_instruction(
.accounts
.push(AccountMeta::new(*buffer.unsigned_key(), false));
let caller_program_id = invoke_context.get_caller()?;
let caller_program_id = invoke_context.transaction_context.get_program_key()?;
let signers = [&[new_program_id.as_ref(), &[bump_seed]]]
.iter()
.map(|seeds| Pubkey::create_program_address(*seeds, caller_program_id))
@ -892,7 +892,7 @@ fn process_loader_instruction(
invoke_context: &mut InvokeContext,
use_jit: bool,
) -> Result<(), InstructionError> {
let program_id = invoke_context.get_caller()?;
let program_id = invoke_context.transaction_context.get_program_key()?;
let keyed_accounts = invoke_context.get_keyed_accounts()?;
let program = keyed_account_at_index(keyed_accounts, first_instruction_account)?;
if program.owner()? != *program_id {
@ -973,8 +973,8 @@ impl Debug for BpfExecutor {
impl Executor for BpfExecutor {
fn execute<'a, 'b>(
&self,
first_instruction_account: usize,
instruction_data: &[u8],
_first_instruction_account: usize,
_instruction_data: &[u8],
invoke_context: &'a mut InvokeContext<'b>,
use_jit: bool,
) -> Result<(), InstructionError> {
@ -983,15 +983,12 @@ impl Executor for BpfExecutor {
let invoke_depth = invoke_context.invoke_depth();
let mut serialize_time = Measure::start("serialize");
let keyed_accounts = invoke_context.get_keyed_accounts()?;
let program = keyed_account_at_index(keyed_accounts, first_instruction_account)?;
let loader_id = program.owner()?;
let program_id = *program.unsigned_key();
let program_id = *invoke_context.transaction_context.get_program_key()?;
let (mut parameter_bytes, account_lengths) = serialize_parameters(
&loader_id,
&program_id,
&keyed_accounts[first_instruction_account + 1..],
instruction_data,
invoke_context.transaction_context,
invoke_context
.transaction_context
.get_current_instruction_context()?,
)?;
serialize_time.stop();
let mut create_vm_time = Measure::start("create_vm");
@ -1076,10 +1073,11 @@ impl Executor for BpfExecutor {
let mut deserialize_time = Measure::start("deserialize");
let execute_or_deserialize_result = execution_result.and_then(|_| {
let keyed_accounts = invoke_context.get_keyed_accounts()?;
deserialize_parameters(
&loader_id,
&keyed_accounts[first_instruction_account + 1..],
invoke_context.transaction_context,
invoke_context
.transaction_context
.get_current_instruction_context()?,
parameter_bytes.as_slice(),
&account_lengths,
invoke_context

View File

@ -2,58 +2,79 @@ use {
byteorder::{ByteOrder, LittleEndian, WriteBytesExt},
solana_rbpf::{aligned_memory::AlignedMemory, ebpf::HOST_ALIGN},
solana_sdk::{
account::{ReadableAccount, WritableAccount},
bpf_loader_deprecated,
entrypoint::{BPF_ALIGN_OF_U128, MAX_PERMITTED_DATA_INCREASE},
instruction::InstructionError,
keyed_account::KeyedAccount,
pubkey::Pubkey,
system_instruction::MAX_PERMITTED_DATA_LENGTH,
transaction_context::{InstructionContext, TransactionContext},
},
std::{io::prelude::*, mem::size_of},
};
/// Look for a duplicate account and return its position if found
pub fn is_dup(accounts: &[KeyedAccount], keyed_account: &KeyedAccount) -> (bool, usize) {
for (i, account) in accounts.iter().enumerate() {
if account == keyed_account {
return (true, i);
}
}
(false, 0)
pub fn is_duplicate(
instruction_context: &InstructionContext,
index_in_instruction: usize,
) -> Option<usize> {
let index_in_transaction = instruction_context.get_index_in_transaction(index_in_instruction);
(instruction_context.get_number_of_program_accounts()..index_in_instruction).position(
|index_in_instruction| {
instruction_context.get_index_in_transaction(index_in_instruction)
== index_in_transaction
},
)
}
pub fn serialize_parameters(
loader_id: &Pubkey,
program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
data: &[u8],
transaction_context: &TransactionContext,
instruction_context: &InstructionContext,
) -> Result<(AlignedMemory, Vec<usize>), InstructionError> {
if *loader_id == bpf_loader_deprecated::id() {
serialize_parameters_unaligned(program_id, keyed_accounts, data)
let is_loader_deprecated = *instruction_context
.try_borrow_program_account(transaction_context)?
.get_owner()
== bpf_loader_deprecated::id();
if is_loader_deprecated {
serialize_parameters_unaligned(transaction_context, instruction_context)
} else {
serialize_parameters_aligned(program_id, keyed_accounts, data)
serialize_parameters_aligned(transaction_context, instruction_context)
}
.and_then(|buffer| {
let account_lengths = keyed_accounts
.iter()
.map(|keyed_account| keyed_account.data_len())
let account_lengths = (instruction_context.get_number_of_program_accounts()
..instruction_context.get_number_of_accounts())
.map(|index_in_instruction| {
Ok(instruction_context
.try_borrow_account(transaction_context, index_in_instruction)?
.get_data()
.len())
})
.collect::<Result<Vec<usize>, InstructionError>>()?;
Ok((buffer, account_lengths))
})
}
pub fn deserialize_parameters(
loader_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
transaction_context: &TransactionContext,
instruction_context: &InstructionContext,
buffer: &[u8],
account_lengths: &[usize],
do_support_realloc: bool,
) -> Result<(), InstructionError> {
if *loader_id == bpf_loader_deprecated::id() {
deserialize_parameters_unaligned(keyed_accounts, buffer, account_lengths)
let is_loader_deprecated = *instruction_context
.try_borrow_program_account(transaction_context)?
.get_owner()
== bpf_loader_deprecated::id();
if is_loader_deprecated {
deserialize_parameters_unaligned(transaction_context, instruction_context, buffer)
} else {
deserialize_parameters_aligned(keyed_accounts, buffer, account_lengths, do_support_realloc)
deserialize_parameters_aligned(
transaction_context,
instruction_context,
buffer,
account_lengths,
do_support_realloc,
)
}
}
@ -75,90 +96,108 @@ pub fn get_serialized_account_size_unaligned(
}
pub fn serialize_parameters_unaligned(
program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
instruction_data: &[u8],
transaction_context: &TransactionContext,
instruction_context: &InstructionContext,
) -> Result<AlignedMemory, InstructionError> {
// Calculate size in order to alloc once
let mut size = size_of::<u64>();
for (i, keyed_account) in keyed_accounts.iter().enumerate() {
let (is_dup, _) = is_dup(&keyed_accounts[..i], keyed_account);
for index_in_instruction in instruction_context.get_number_of_program_accounts()
..instruction_context.get_number_of_accounts()
{
let duplicate = is_duplicate(instruction_context, index_in_instruction);
size += 1; // dup
if !is_dup {
size += get_serialized_account_size_unaligned(keyed_account)?;
if duplicate.is_none() {
let data_len = instruction_context
.try_borrow_account(transaction_context, index_in_instruction)?
.get_data()
.len();
size += size_of::<u8>() // is_signer
+ size_of::<u8>() // is_writable
+ size_of::<Pubkey>() // key
+ size_of::<u64>() // lamports
+ size_of::<u64>() // data len
+ data_len // data
+ size_of::<Pubkey>() // owner
+ size_of::<u8>() // executable
+ size_of::<u64>(); // rent_epoch
}
}
size += size_of::<u64>() // instruction data len
+ instruction_data.len() // instruction data
+ instruction_context.get_instruction_data().len() // instruction data
+ size_of::<Pubkey>(); // program id
let mut v = AlignedMemory::new(size, HOST_ALIGN);
v.write_u64::<LittleEndian>(keyed_accounts.len() as u64)
v.write_u64::<LittleEndian>(instruction_context.get_number_of_instruction_accounts() as u64)
.map_err(|_| InstructionError::InvalidArgument)?;
for (i, keyed_account) in keyed_accounts.iter().enumerate() {
let (is_dup, position) = is_dup(&keyed_accounts[..i], keyed_account);
if is_dup {
for index_in_instruction in instruction_context.get_number_of_program_accounts()
..instruction_context.get_number_of_accounts()
{
let duplicate = is_duplicate(instruction_context, index_in_instruction);
if let Some(position) = duplicate {
v.write_u8(position as u8)
.map_err(|_| InstructionError::InvalidArgument)?;
} else {
let borrowed_account = instruction_context
.try_borrow_account(transaction_context, index_in_instruction)?;
v.write_u8(std::u8::MAX)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u8(keyed_account.signer_key().is_some() as u8)
v.write_u8(borrowed_account.is_signer() as u8)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u8(keyed_account.is_writable() as u8)
v.write_u8(borrowed_account.is_writable() as u8)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(keyed_account.unsigned_key().as_ref())
v.write_all(borrowed_account.get_key().as_ref())
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u64::<LittleEndian>(keyed_account.lamports()?)
v.write_u64::<LittleEndian>(borrowed_account.get_lamports())
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u64::<LittleEndian>(keyed_account.data_len()? as u64)
v.write_u64::<LittleEndian>(borrowed_account.get_data().len() as u64)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(keyed_account.try_account_ref()?.data())
v.write_all(borrowed_account.get_data())
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(keyed_account.owner()?.as_ref())
v.write_all(borrowed_account.get_owner().as_ref())
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u8(keyed_account.executable()? as u8)
v.write_u8(borrowed_account.is_executable() as u8)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u64::<LittleEndian>(keyed_account.rent_epoch()? as u64)
v.write_u64::<LittleEndian>(borrowed_account.get_rent_epoch() as u64)
.map_err(|_| InstructionError::InvalidArgument)?;
}
}
v.write_u64::<LittleEndian>(instruction_data.len() as u64)
v.write_u64::<LittleEndian>(instruction_context.get_instruction_data().len() as u64)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(instruction_data)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(program_id.as_ref())
v.write_all(instruction_context.get_instruction_data())
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(
instruction_context
.try_borrow_program_account(transaction_context)?
.get_key()
.as_ref(),
)
.map_err(|_| InstructionError::InvalidArgument)?;
Ok(v)
}
pub fn deserialize_parameters_unaligned(
keyed_accounts: &[KeyedAccount],
transaction_context: &TransactionContext,
instruction_context: &InstructionContext,
buffer: &[u8],
account_lengths: &[usize],
) -> Result<(), InstructionError> {
let mut start = size_of::<u64>(); // number of accounts
for (i, (keyed_account, _pre_len)) in keyed_accounts
.iter()
.zip(account_lengths.iter())
.enumerate()
for index_in_instruction in instruction_context.get_number_of_program_accounts()
..instruction_context.get_number_of_accounts()
{
let (is_dup, _) = is_dup(&keyed_accounts[..i], keyed_account);
let duplicate = is_duplicate(instruction_context, index_in_instruction);
start += 1; // is_dup
if !is_dup {
if duplicate.is_none() {
let mut borrowed_account = instruction_context
.try_borrow_account(transaction_context, index_in_instruction)?;
start += size_of::<u8>(); // is_signer
start += size_of::<u8>(); // is_writable
start += size_of::<Pubkey>(); // key
keyed_account
.try_account_ref_mut()?
.set_lamports(LittleEndian::read_u64(&buffer[start..]));
let _ = borrowed_account.set_lamports(LittleEndian::read_u64(&buffer[start..]));
start += size_of::<u64>() // lamports
+ size_of::<u64>(); // data length
let end = start + keyed_account.data_len()?;
keyed_account
.try_account_ref_mut()?
.set_data_from_slice(&buffer[start..end]);
start += keyed_account.data_len()? // data
let end = start + borrowed_account.get_data().len();
let _ = borrowed_account.set_data(&buffer[start..end]);
start += borrowed_account.get_data().len() // data
+ size_of::<Pubkey>() // owner
+ size_of::<u8>() // executable
+ size_of::<u64>(); // rent_epoch
@ -167,77 +206,77 @@ pub fn deserialize_parameters_unaligned(
Ok(())
}
pub fn get_serialized_account_size_aligned(
keyed_account: &KeyedAccount,
) -> Result<usize, InstructionError> {
let data_len = keyed_account.data_len()?;
Ok(
size_of::<u8>() // is_signer
+ size_of::<u8>() // is_writable
+ size_of::<u8>() // executable
+ 4 // padding to 128-bit aligned
+ size_of::<Pubkey>() // key
+ size_of::<Pubkey>() // owner
+ size_of::<u64>() // lamports
+ size_of::<u64>() // data len
+ data_len
+ MAX_PERMITTED_DATA_INCREASE
+ (data_len as *const u8).align_offset(BPF_ALIGN_OF_U128)
+ size_of::<u64>(), // rent epoch
)
}
pub fn serialize_parameters_aligned(
program_id: &Pubkey,
keyed_accounts: &[KeyedAccount],
instruction_data: &[u8],
transaction_context: &TransactionContext,
instruction_context: &InstructionContext,
) -> Result<AlignedMemory, InstructionError> {
// Calculate size in order to alloc once
let mut size = size_of::<u64>();
for (i, keyed_account) in keyed_accounts.iter().enumerate() {
let (is_dup, _) = is_dup(&keyed_accounts[..i], keyed_account);
for index_in_instruction in instruction_context.get_number_of_program_accounts()
..instruction_context.get_number_of_accounts()
{
let duplicate = is_duplicate(instruction_context, index_in_instruction);
size += 1; // dup
if is_dup {
if duplicate.is_some() {
size += 7; // padding to 64-bit aligned
} else {
size += get_serialized_account_size_aligned(keyed_account)?;
let data_len = instruction_context
.try_borrow_account(transaction_context, index_in_instruction)?
.get_data()
.len();
size += size_of::<u8>() // is_signer
+ size_of::<u8>() // is_writable
+ size_of::<u8>() // executable
+ 4 // padding to 128-bit aligned
+ size_of::<Pubkey>() // key
+ size_of::<Pubkey>() // owner
+ size_of::<u64>() // lamports
+ size_of::<u64>() // data len
+ data_len
+ MAX_PERMITTED_DATA_INCREASE
+ (data_len as *const u8).align_offset(BPF_ALIGN_OF_U128)
+ size_of::<u64>(); // rent epoch
}
}
size += size_of::<u64>() // data len
+ instruction_data.len()
+ instruction_context.get_instruction_data().len()
+ size_of::<Pubkey>(); // program id;
let mut v = AlignedMemory::new(size, HOST_ALIGN);
// Serialize into the buffer
v.write_u64::<LittleEndian>(keyed_accounts.len() as u64)
v.write_u64::<LittleEndian>(instruction_context.get_number_of_instruction_accounts() as u64)
.map_err(|_| InstructionError::InvalidArgument)?;
for (i, keyed_account) in keyed_accounts.iter().enumerate() {
let (is_dup, position) = is_dup(&keyed_accounts[..i], keyed_account);
if is_dup {
for index_in_instruction in instruction_context.get_number_of_program_accounts()
..instruction_context.get_number_of_accounts()
{
let duplicate = is_duplicate(instruction_context, index_in_instruction);
if let Some(position) = duplicate {
v.write_u8(position as u8)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(&[0u8, 0, 0, 0, 0, 0, 0])
.map_err(|_| InstructionError::InvalidArgument)?; // 7 bytes of padding to make 64-bit aligned
} else {
let borrowed_account = instruction_context
.try_borrow_account(transaction_context, index_in_instruction)?;
v.write_u8(std::u8::MAX)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u8(keyed_account.signer_key().is_some() as u8)
v.write_u8(borrowed_account.is_signer() as u8)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u8(keyed_account.is_writable() as u8)
v.write_u8(borrowed_account.is_writable() as u8)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u8(keyed_account.executable()? as u8)
v.write_u8(borrowed_account.is_executable() as u8)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(&[0u8, 0, 0, 0])
.map_err(|_| InstructionError::InvalidArgument)?; // 4 bytes of padding to make 128-bit aligned
v.write_all(keyed_account.unsigned_key().as_ref())
v.write_all(borrowed_account.get_key().as_ref())
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(keyed_account.owner()?.as_ref())
v.write_all(borrowed_account.get_owner().as_ref())
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u64::<LittleEndian>(keyed_account.lamports()?)
v.write_u64::<LittleEndian>(borrowed_account.get_lamports())
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u64::<LittleEndian>(keyed_account.data_len()? as u64)
v.write_u64::<LittleEndian>(borrowed_account.get_data().len() as u64)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(keyed_account.try_account_ref()?.data())
v.write_all(borrowed_account.get_data())
.map_err(|_| InstructionError::InvalidArgument)?;
v.resize(
MAX_PERMITTED_DATA_INCREASE
@ -245,45 +284,51 @@ pub fn serialize_parameters_aligned(
0,
)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u64::<LittleEndian>(keyed_account.rent_epoch()? as u64)
v.write_u64::<LittleEndian>(borrowed_account.get_rent_epoch() as u64)
.map_err(|_| InstructionError::InvalidArgument)?;
}
}
v.write_u64::<LittleEndian>(instruction_data.len() as u64)
v.write_u64::<LittleEndian>(instruction_context.get_instruction_data().len() as u64)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(instruction_data)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(program_id.as_ref())
v.write_all(instruction_context.get_instruction_data())
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(
instruction_context
.try_borrow_program_account(transaction_context)?
.get_key()
.as_ref(),
)
.map_err(|_| InstructionError::InvalidArgument)?;
Ok(v)
}
pub fn deserialize_parameters_aligned(
keyed_accounts: &[KeyedAccount],
transaction_context: &TransactionContext,
instruction_context: &InstructionContext,
buffer: &[u8],
account_lengths: &[usize],
do_support_realloc: bool,
) -> Result<(), InstructionError> {
let mut start = size_of::<u64>(); // number of accounts
for (i, (keyed_account, pre_len)) in keyed_accounts
.iter()
for (index_in_instruction, pre_len) in (instruction_context.get_number_of_program_accounts()
..instruction_context.get_number_of_accounts())
.zip(account_lengths.iter())
.enumerate()
{
let (is_dup, _) = is_dup(&keyed_accounts[..i], keyed_account);
let duplicate = is_duplicate(instruction_context, index_in_instruction);
start += size_of::<u8>(); // position
if is_dup {
if duplicate.is_some() {
start += 7; // padding to 64-bit aligned
} else {
let mut account = keyed_account.try_account_ref_mut()?;
let mut borrowed_account = instruction_context
.try_borrow_account(transaction_context, index_in_instruction)?;
start += size_of::<u8>() // is_signer
+ size_of::<u8>() // is_writable
+ size_of::<u8>() // executable
+ 4 // padding to 128-bit aligned
+ size_of::<Pubkey>(); // key
account.copy_into_owner_from_slice(&buffer[start..start + size_of::<Pubkey>()]);
let _ = borrowed_account.set_owner(&buffer[start..start + size_of::<Pubkey>()]);
start += size_of::<Pubkey>(); // owner
account.set_lamports(LittleEndian::read_u64(&buffer[start..]));
let _ = borrowed_account.set_lamports(LittleEndian::read_u64(&buffer[start..]));
start += size_of::<u64>(); // lamports
let post_len = LittleEndian::read_u64(&buffer[start..]) as usize;
start += size_of::<u64>(); // data length
@ -303,7 +348,7 @@ pub fn deserialize_parameters_aligned(
}
data_end
};
account.set_data_from_slice(&buffer[start..data_end]);
let _ = borrowed_account.set_data(&buffer[start..data_end]);
start += *pre_len + MAX_PERMITTED_DATA_INCREASE; // data
start += (start as *const u8).align_offset(BPF_ALIGN_OF_U128);
start += size_of::<u64>(); // rent_epoch
@ -318,12 +363,11 @@ mod tests {
super::*,
solana_program_runtime::invoke_context::{prepare_mock_invoke_context, InvokeContext},
solana_sdk::{
account::{Account, AccountSharedData},
account::{Account, AccountSharedData, ReadableAccount},
account_info::AccountInfo,
bpf_loader,
entrypoint::deserialize,
instruction::AccountMeta,
transaction_context::TransactionContext,
},
std::{
cell::RefCell,
@ -407,71 +451,40 @@ mod tests {
}),
),
];
let instruction_accounts = vec![
AccountMeta {
pubkey: transaction_accounts[1].0,
let instruction_accounts = [1, 1, 2, 3, 4, 4, 5, 6]
.into_iter()
.enumerate()
.map(|(index_in_instruction, index_in_transaction)| AccountMeta {
pubkey: transaction_accounts[index_in_transaction].0,
is_signer: false,
is_writable: false,
},
AccountMeta {
pubkey: transaction_accounts[1].0,
is_signer: false,
is_writable: false,
},
AccountMeta {
pubkey: transaction_accounts[2].0,
is_signer: false,
is_writable: false,
},
AccountMeta {
pubkey: transaction_accounts[3].0,
is_signer: false,
is_writable: false,
},
AccountMeta {
pubkey: transaction_accounts[4].0,
is_signer: false,
is_writable: true,
},
AccountMeta {
pubkey: transaction_accounts[4].0,
is_signer: false,
is_writable: true,
},
AccountMeta {
pubkey: transaction_accounts[5].0,
is_signer: false,
is_writable: true,
},
AccountMeta {
pubkey: transaction_accounts[6].0,
is_signer: false,
is_writable: true,
},
];
is_writable: index_in_instruction >= 4,
})
.collect();
let instruction_data = vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
let program_indices = [0];
let preparation = prepare_mock_invoke_context(
transaction_accounts.clone(),
transaction_accounts,
instruction_accounts,
&program_indices,
);
let transaction_context = TransactionContext::new(preparation.transaction_accounts, 1);
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
let mut transaction_context = TransactionContext::new(preparation.transaction_accounts, 1);
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
invoke_context
.push(&preparation.instruction_accounts, &program_indices)
.push(
&preparation.instruction_accounts,
&program_indices,
&instruction_data,
)
.unwrap();
let instruction_context = invoke_context
.transaction_context
.get_current_instruction_context()
.unwrap();
// check serialize_parameters_aligned
let ser_keyed_accounts = invoke_context.get_keyed_accounts().unwrap();
let (mut serialized, account_lengths) = serialize_parameters(
&bpf_loader::id(),
&program_id,
&ser_keyed_accounts[1..],
&instruction_data,
)
.unwrap();
let (mut serialized, account_lengths) =
serialize_parameters(invoke_context.transaction_context, instruction_context).unwrap();
let (de_program_id, de_accounts, de_instruction_data) =
unsafe { deserialize(&mut serialized.as_slice_mut()[0] as *mut u8) };
@ -483,11 +496,14 @@ mod tests {
0
);
for account_info in de_accounts {
let account = &transaction_accounts
.iter()
.find(|(key, _account)| key == account_info.key)
.unwrap()
.1;
let index_in_transaction = invoke_context
.transaction_context
.find_index_of_account(account_info.key)
.unwrap();
let account = invoke_context
.transaction_context
.get_account_at_index(index_in_transaction)
.borrow();
assert_eq!(account.lamports(), account_info.lamports());
assert_eq!(account.data(), &account_info.data.borrow()[..]);
assert_eq!(account.owner(), account_info.owner);
@ -510,44 +526,51 @@ mod tests {
let de_keyed_accounts = invoke_context.get_keyed_accounts().unwrap();
deserialize_parameters(
&bpf_loader::id(),
&de_keyed_accounts[1..],
invoke_context.transaction_context,
instruction_context,
serialized.as_slice(),
&account_lengths,
true,
)
.unwrap();
for keyed_account in de_keyed_accounts {
let account = &transaction_accounts
.iter()
.find(|(key, _account)| key == keyed_account.unsigned_key())
.unwrap()
.1;
let index_in_transaction = invoke_context
.transaction_context
.find_index_of_account(keyed_account.unsigned_key())
.unwrap();
let account = invoke_context
.transaction_context
.get_account_at_index(index_in_transaction)
.borrow();
assert_eq!(account.executable(), keyed_account.executable().unwrap());
assert_eq!(account.rent_epoch(), keyed_account.rent_epoch().unwrap());
}
// check serialize_parameters_unaligned
let _ = invoke_context
.transaction_context
.get_current_instruction_context()
.unwrap()
.try_borrow_account(invoke_context.transaction_context, 0)
.unwrap()
.set_owner(bpf_loader_deprecated::id().as_ref());
let ser_keyed_accounts = invoke_context.get_keyed_accounts().unwrap();
let (mut serialized, account_lengths) = serialize_parameters(
&bpf_loader_deprecated::id(),
&program_id,
&ser_keyed_accounts[1..],
&instruction_data,
)
.unwrap();
let (mut serialized, account_lengths) =
serialize_parameters(invoke_context.transaction_context, instruction_context).unwrap();
let (de_program_id, de_accounts, de_instruction_data) =
unsafe { deserialize_unaligned(&mut serialized.as_slice_mut()[0] as *mut u8) };
assert_eq!(&program_id, de_program_id);
assert_eq!(instruction_data, de_instruction_data);
for account_info in de_accounts {
let account = &transaction_accounts
.iter()
.find(|(key, _account)| key == account_info.key)
.unwrap()
.1;
let index_in_transaction = invoke_context
.transaction_context
.find_index_of_account(account_info.key)
.unwrap();
let account = invoke_context
.transaction_context
.get_account_at_index(index_in_transaction)
.borrow();
assert_eq!(account.lamports(), account_info.lamports());
assert_eq!(account.data(), &account_info.data.borrow()[..]);
assert_eq!(account.owner(), account_info.owner);
@ -557,19 +580,22 @@ mod tests {
let de_keyed_accounts = invoke_context.get_keyed_accounts().unwrap();
deserialize_parameters(
&bpf_loader_deprecated::id(),
&de_keyed_accounts[1..],
invoke_context.transaction_context,
instruction_context,
serialized.as_slice(),
&account_lengths,
true,
)
.unwrap();
for keyed_account in de_keyed_accounts {
let account = &transaction_accounts
.iter()
.find(|(key, _account)| key == keyed_account.unsigned_key())
.unwrap()
.1;
let index_in_transaction = invoke_context
.transaction_context
.find_index_of_account(keyed_account.unsigned_key())
.unwrap();
let account = invoke_context
.transaction_context
.get_account_at_index(index_in_transaction)
.borrow();
assert_eq!(account.lamports(), keyed_account.lamports().unwrap());
assert_eq!(
account.data(),

View File

@ -246,7 +246,8 @@ pub fn bind_syscall_context_objects<'a, 'b>(
.is_active(&sol_log_data_syscall_enabled::id());
let loader_id = invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError)?;
let invoke_context = Rc::new(RefCell::new(invoke_context));
@ -581,7 +582,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallPanic<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@ -620,7 +622,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallLog<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@ -734,7 +737,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallLogPubkey<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@ -850,7 +854,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallCreateProgramAddress<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@ -909,7 +914,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallTryFindProgramAddress<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@ -983,7 +989,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallSha256<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@ -1064,7 +1071,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallGetClockSysvar<'a, 'b> {
);
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@ -1100,7 +1108,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallGetEpochScheduleSysvar<'a, 'b> {
);
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@ -1137,7 +1146,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallGetFeesSysvar<'a, 'b> {
);
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@ -1173,7 +1183,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallGetRentSysvar<'a, 'b> {
);
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@ -1216,7 +1227,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallKeccak256<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@ -1316,7 +1328,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallMemcpy<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@ -1360,7 +1373,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallMemmove<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@ -1404,7 +1418,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallMemcmp<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@ -1461,7 +1476,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallMemset<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@ -1503,7 +1519,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallSecp256k1Recover<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@ -1608,7 +1625,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallBlake3<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@ -2202,14 +2220,10 @@ fn get_translated_accounts<'a, T, F>(
where
F: Fn(&T, &InvokeContext) -> Result<CallerAccount<'a>, EbpfError<BpfError>>,
{
let keyed_accounts = invoke_context
.get_keyed_accounts()
let instruction_context = invoke_context
.transaction_context
.get_current_instruction_context()
.map_err(SyscallError::InstructionError)?;
let number_of_program_accounts = keyed_accounts.len()
- invoke_context
.get_instruction_keyed_accounts()
.map_err(SyscallError::InstructionError)?
.len();
let mut accounts = Vec::with_capacity(instruction_accounts.len().saturating_add(1));
let program_account_index = program_indices
@ -2245,10 +2259,8 @@ where
let caller_account = if instruction_account.is_writable {
let orig_data_len_index = instruction_account
.index_in_caller
.saturating_sub(number_of_program_accounts);
if keyed_accounts[instruction_account.index_in_caller].unsigned_key() == account_key
&& orig_data_len_index < orig_data_lens.len()
{
.saturating_sub(instruction_context.get_number_of_program_accounts());
if orig_data_len_index < orig_data_lens.len() {
caller_account.original_data_len = orig_data_lens[orig_data_len_index];
} else {
ic_msg!(
@ -2351,7 +2363,8 @@ fn call<'a, 'b: 'a>(
// Translate and verify caller's data
let loader_id = invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError)?;
let instruction = syscall.translate_instruction(
&loader_id,
@ -2360,7 +2373,8 @@ fn call<'a, 'b: 'a>(
*invoke_context,
)?;
let caller_program_id = invoke_context
.get_caller()
.transaction_context
.get_program_key()
.map_err(SyscallError::InstructionError)?;
let signers = syscall.translate_signers(
&loader_id,
@ -2369,7 +2383,7 @@ fn call<'a, 'b: 'a>(
signers_seeds_len,
memory_mapping,
)?;
let (instruction_accounts, caller_write_privileges, program_indices) = invoke_context
let (instruction_accounts, program_indices) = invoke_context
.prepare_instruction(&instruction, &signers)
.map_err(SyscallError::InstructionError)?;
check_authorized_program(&instruction.program_id, &instruction.data, *invoke_context)?;
@ -2389,7 +2403,6 @@ fn call<'a, 'b: 'a>(
.process_instruction(
&instruction.data,
&instruction_accounts,
Some(&caller_write_privileges),
&program_indices,
&mut compute_units_consumed,
)
@ -2476,7 +2489,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallSetReturnData<'a, 'b> {
);
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@ -2506,7 +2520,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallSetReturnData<'a, 'b> {
};
let program_id = question_mark!(
invoke_context
.get_caller()
.transaction_context
.get_program_key()
.map_err(SyscallError::InstructionError),
result
);
@ -2538,7 +2553,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallGetReturnData<'a, 'b> {
);
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@ -2605,7 +2621,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallLogData<'a, 'b> {
);
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@ -2984,12 +3001,12 @@ mod tests {
#[should_panic(expected = "UserError(SyscallError(Panic(\"Gaggablaghblagh!\", 42, 84)))")]
fn test_syscall_sol_panic() {
let program_id = Pubkey::new_unique();
let transaction_context = TransactionContext::new(
let mut 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 invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
invoke_context.push(&[], &[0], &[]).unwrap();
let mut syscall_panic = SyscallPanic {
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
};
@ -3057,12 +3074,12 @@ mod tests {
#[test]
fn test_syscall_sol_log() {
let program_id = Pubkey::new_unique();
let transaction_context = TransactionContext::new(
let mut 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 invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
invoke_context.push(&[], &[0], &[]).unwrap();
let mut syscall_sol_log = SyscallLog {
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
};
@ -3157,12 +3174,12 @@ mod tests {
#[test]
fn test_syscall_sol_log_u64() {
let program_id = Pubkey::new_unique();
let transaction_context = TransactionContext::new(
let mut 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 invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
invoke_context.push(&[], &[0], &[]).unwrap();
let cost = invoke_context.get_compute_budget().log_64_units;
let mut syscall_sol_log_u64 = SyscallLogU64 {
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
@ -3195,12 +3212,12 @@ mod tests {
#[test]
fn test_syscall_sol_pubkey() {
let program_id = Pubkey::new_unique();
let transaction_context = TransactionContext::new(
let mut 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 invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
invoke_context.push(&[], &[0], &[]).unwrap();
let cost = invoke_context.get_compute_budget().log_pubkey_units;
let mut syscall_sol_pubkey = SyscallLogPubkey {
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
@ -3403,15 +3420,15 @@ mod tests {
fn test_syscall_sha256() {
let config = Config::default();
let program_id = Pubkey::new_unique();
let transaction_context = TransactionContext::new(
let mut 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 mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
invoke_context.push(&[], &[0], &[]).unwrap();
let bytes1 = "Gaggablaghblagh!";
let bytes2 = "flurbos";
@ -3570,13 +3587,13 @@ mod tests {
(sysvar::rent::id(), data_rent),
];
let program_id = Pubkey::new_unique();
let transaction_context = TransactionContext::new(
let mut transaction_context = TransactionContext::new(
vec![(program_id, AccountSharedData::new(0, 0, &bpf_loader::id()))],
1,
);
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
invoke_context.sysvars = &sysvars;
invoke_context.push(&[], &[0]).unwrap();
invoke_context.push(&[], &[0], &[]).unwrap();
// Test clock sysvar
{
@ -3820,12 +3837,12 @@ mod tests {
// These tests duplicate the direct tests in solana_program::pubkey
let program_id = Pubkey::new_unique();
let transaction_context = TransactionContext::new(
let mut 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 invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
invoke_context.push(&[], &[0], &[]).unwrap();
let address = bpf_loader_upgradeable::id();
let exceeded_seed = &[127; MAX_SEED_LEN + 1];
@ -3932,12 +3949,12 @@ mod tests {
#[test]
fn test_find_program_address() {
let program_id = Pubkey::new_unique();
let transaction_context = TransactionContext::new(
let mut 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 invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
invoke_context.push(&[], &[0], &[]).unwrap();
let cost = invoke_context
.get_compute_budget()
.create_program_address_units;

View File

@ -4999,8 +4999,8 @@ mod tests {
#[test]
fn test_merge() {
let transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
let mut transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&mut 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();
@ -5110,8 +5110,8 @@ mod tests {
#[test]
fn test_merge_self_fails() {
let transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
let mut transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
let stake_address = Pubkey::new_unique();
let authority_pubkey = Pubkey::new_unique();
let signers = HashSet::from_iter(vec![authority_pubkey]);
@ -5156,8 +5156,8 @@ mod tests {
#[test]
fn test_merge_incorrect_authorized_staker() {
let transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
let mut transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&mut 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();
@ -5226,8 +5226,8 @@ mod tests {
#[test]
fn test_merge_invalid_account_data() {
let transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
let mut transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&mut 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();
@ -5277,8 +5277,8 @@ mod tests {
#[test]
fn test_merge_fake_stake_source() {
let transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
let mut transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&mut 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();
@ -5320,8 +5320,8 @@ mod tests {
#[test]
fn test_merge_active_stake() {
let transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
let mut transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
let base_lamports = 4242424242;
let stake_address = Pubkey::new_unique();
let source_address = Pubkey::new_unique();
@ -5943,8 +5943,8 @@ mod tests {
#[test]
fn test_things_can_merge() {
let transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
let mut transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
let good_stake = Stake {
credits_observed: 4242,
delegation: Delegation {
@ -6042,8 +6042,8 @@ mod tests {
#[test]
fn test_metas_can_merge_pre_v4() {
let transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
let mut transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
// Identical Metas can merge
assert!(MergeKind::metas_can_merge(
&invoke_context,
@ -6129,8 +6129,8 @@ mod tests {
#[test]
fn test_metas_can_merge_v4() {
let transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
let mut transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
// Identical Metas can merge
assert!(MergeKind::metas_can_merge(
&invoke_context,
@ -6276,8 +6276,8 @@ mod tests {
#[test]
fn test_merge_kind_get_if_mergeable() {
let transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
let mut transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
let authority_pubkey = Pubkey::new_unique();
let initial_lamports = 4242424242;
let rent = Rent::default();
@ -6509,8 +6509,8 @@ mod tests {
#[test]
fn test_merge_kind_merge() {
let transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
let mut transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
let lamports = 424242;
let meta = Meta {
rent_exempt_reserve: 42,
@ -6588,8 +6588,8 @@ mod tests {
#[test]
fn test_active_stake_merge() {
let transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
let mut transaction_context = TransactionContext::new(Vec::new(), 1);
let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
let delegation_a = 4_242_424_242u64;
let delegation_b = 6_200_000_000u64;
let credits_a = 124_521_000u64;