Serialization refactor (#28251)

* Use infallible, unchecked methods to write into the serialization buffer

We serialize in two steps: first we compute the size of the buffer, then
we write into it. Therefore there's no need to check if each individual
write fits the buffer - we know it does we just computed the required
size.

* serialize_parameters: remove extra loop/borrows

Remove one extra loop over accounts to gather account lengths. Also
gather all accounts at once and avoid temporary borrows.

* Move creating MemoryRegions for serialized parameters from create_vm to serialize_parameters

This is in preparation of using multiple MemoryRegions once we land direct account mapping.

* bpf_loader: introduce internal API to build serialization buffer/regions

This is prep work for landing the direct_mapping feature, which maps account
data in their own memory regions.

* serialization: fix after API changes
This commit is contained in:
Alessandro Decina 2022-10-07 07:45:05 +01:00 committed by GitHub
parent a400178744
commit f6fee4ac3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 249 additions and 174 deletions

View File

@ -118,7 +118,7 @@ pub fn builtin_process_instruction(
let deduplicated_indices: HashSet<IndexOfAccount> = instruction_account_indices.collect();
// Serialize entrypoint parameters with BPF ABI
let (mut parameter_bytes, _account_lengths) = serialize_parameters(
let (mut parameter_bytes, _regions, _account_lengths) = serialize_parameters(
invoke_context.transaction_context,
invoke_context
.transaction_context

View File

@ -14,7 +14,9 @@ use {
solana_measure::measure::Measure,
solana_program_runtime::invoke_context::with_mock_invoke_context,
solana_rbpf::{
ebpf::MM_INPUT_START,
elf::Executable,
memory_region::MemoryRegion,
verifier::RequisiteVerifier,
vm::{Config, InstructionMeter, SyscallRegistry, VerifiedExecutable},
},
@ -31,7 +33,6 @@ use {
instruction::{AccountMeta, Instruction},
message::Message,
pubkey::Pubkey,
rent::Rent,
signature::{Keypair, Signer},
},
std::{env, fs::File, io::Read, mem, path::PathBuf, sync::Arc},
@ -124,7 +125,7 @@ fn bench_program_alu(bencher: &mut Bencher) {
let mut instruction_meter = ThisInstructionMeter { compute_meter };
let mut vm = create_vm(
&verified_executable,
&mut inner_iter,
vec![MemoryRegion::new_writable(&mut inner_iter, MM_INPUT_START)],
vec![],
invoke_context,
)
@ -224,7 +225,7 @@ fn bench_create_vm(bencher: &mut Bencher) {
.mock_set_remaining(BUDGET);
// Serialize account data
let (mut serialized, account_lengths) = serialize_parameters(
let (_serialized, regions, account_lengths) = serialize_parameters(
invoke_context.transaction_context,
invoke_context
.transaction_context
@ -250,7 +251,7 @@ fn bench_create_vm(bencher: &mut Bencher) {
bencher.iter(|| {
let _ = create_vm(
&verified_executable,
serialized.as_slice_mut(),
regions.clone(),
account_lengths.clone(),
invoke_context,
)
@ -271,7 +272,7 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
.mock_set_remaining(BUDGET);
// Serialize account data
let (mut serialized, account_lengths) = serialize_parameters(
let (_serialized, regions, account_lengths) = serialize_parameters(
invoke_context.transaction_context,
invoke_context
.transaction_context
@ -298,7 +299,7 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
let mut instruction_meter = ThisInstructionMeter { compute_meter };
let mut vm = create_vm(
&verified_executable,
serialized.as_slice_mut(),
regions,
account_lengths,
invoke_context,
)

View File

@ -224,16 +224,6 @@ 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, false, |invoke_context| {
let (parameter_bytes, account_lengths) = serialize_parameters(
invoke_context.transaction_context,
invoke_context
.transaction_context
.get_current_instruction_context()
.unwrap(),
true, // should_cap_ix_accounts
)
.unwrap();
let compute_meter = invoke_context.get_compute_meter();
let mut instruction_meter = ThisInstructionMeter { compute_meter };
let config = Config {
@ -278,11 +268,21 @@ fn run_program(name: &str) -> u64 {
transaction_context
.set_return_data(caller, Vec::new())
.unwrap();
let mut parameter_bytes = parameter_bytes.clone();
let (parameter_bytes, regions, account_lengths) = serialize_parameters(
invoke_context.transaction_context,
invoke_context
.transaction_context
.get_current_instruction_context()
.unwrap(),
true, // should_cap_ix_accounts
)
.unwrap();
{
let mut vm = create_vm(
&verified_executable,
parameter_bytes.as_slice_mut(),
regions,
account_lengths.clone(),
invoke_context,
)

View File

@ -29,7 +29,7 @@ use {
},
solana_rbpf::{
aligned_memory::AlignedMemory,
ebpf::{HOST_ALIGN, MM_HEAP_START, MM_INPUT_START},
ebpf::{HOST_ALIGN, MM_HEAP_START},
elf::Executable,
error::{EbpfError, UserDefinedError},
memory_region::MemoryRegion,
@ -290,7 +290,7 @@ fn check_loader_id(id: &Pubkey) -> bool {
/// Create the BPF virtual machine
pub fn create_vm<'a, 'b>(
program: &'a VerifiedExecutable<RequisiteVerifier, ThisInstructionMeter>,
parameter_bytes: &mut [u8],
regions: Vec<MemoryRegion>,
orig_account_lengths: Vec<usize>,
invoke_context: &'a mut InvokeContext<'b>,
) -> Result<EbpfVm<'a, RequisiteVerifier, ThisInstructionMeter>, EbpfError> {
@ -303,13 +303,8 @@ pub fn create_vm<'a, 'b>(
);
let mut heap =
AlignedMemory::<HOST_ALIGN>::zero_filled(compute_budget.heap_size.unwrap_or(HEAP_LENGTH));
let parameter_region = MemoryRegion::new_writable(parameter_bytes, MM_INPUT_START);
let vm = EbpfVm::new(
program,
invoke_context,
heap.as_slice_mut(),
vec![parameter_region],
)?;
let vm = EbpfVm::new(program, invoke_context, heap.as_slice_mut(), regions)?;
let check_aligned = bpf_loader_deprecated::id()
!= invoke_context
.transaction_context
@ -1331,7 +1326,7 @@ impl Executor for BpfExecutor {
let program_id = *instruction_context.get_last_program_key(transaction_context)?;
let mut serialize_time = Measure::start("serialize");
let (mut parameter_bytes, account_lengths) = serialize_parameters(
let (parameter_bytes, regions, account_lengths) = serialize_parameters(
invoke_context.transaction_context,
instruction_context,
invoke_context
@ -1345,7 +1340,7 @@ impl Executor for BpfExecutor {
let execution_result = {
let mut vm = match create_vm(
&self.verified_executable,
parameter_bytes.as_slice_mut(),
regions,
account_lengths,
invoke_context,
) {
@ -1480,7 +1475,7 @@ mod tests {
super::*,
rand::Rng,
solana_program_runtime::invoke_context::mock_process_instruction,
solana_rbpf::{verifier::Verifier, vm::SyscallRegistry},
solana_rbpf::{ebpf::MM_INPUT_START, verifier::Verifier, vm::SyscallRegistry},
solana_runtime::{bank::Bank, bank_client::BankClient},
solana_sdk::{
account::{

View File

@ -1,53 +1,166 @@
#![allow(clippy::integer_arithmetic)]
use {
byteorder::{ByteOrder, LittleEndian, WriteBytesExt},
solana_rbpf::{aligned_memory::AlignedMemory, ebpf::HOST_ALIGN},
byteorder::{ByteOrder, LittleEndian},
solana_rbpf::{
aligned_memory::{AlignedMemory, Pod},
ebpf::{HOST_ALIGN, MM_INPUT_START},
memory_region::MemoryRegion,
},
solana_sdk::{
bpf_loader_deprecated,
entrypoint::{BPF_ALIGN_OF_U128, MAX_PERMITTED_DATA_INCREASE, NON_DUP_MARKER},
instruction::InstructionError,
pubkey::Pubkey,
system_instruction::MAX_PERMITTED_DATA_LENGTH,
transaction_context::{IndexOfAccount, InstructionContext, TransactionContext},
transaction_context::{
BorrowedAccount, IndexOfAccount, InstructionContext, TransactionContext,
},
},
std::{io::prelude::*, mem::size_of},
std::{mem, mem::size_of},
};
/// Maximum number of instruction accounts that can be serialized into the
/// BPF VM.
const MAX_INSTRUCTION_ACCOUNTS: u8 = NON_DUP_MARKER;
enum SerializeAccount<'a> {
Account(IndexOfAccount, BorrowedAccount<'a>),
Duplicate(IndexOfAccount),
}
struct Serializer {
pub buffer: AlignedMemory<HOST_ALIGN>,
regions: Vec<MemoryRegion>,
vaddr: u64,
region_start: usize,
aligned: bool,
}
impl Serializer {
fn new(size: usize, start_addr: u64, aligned: bool) -> Serializer {
Serializer {
buffer: AlignedMemory::with_capacity(size),
regions: Vec::new(),
region_start: 0,
vaddr: start_addr,
aligned,
}
}
fn fill_write(&mut self, num: usize, value: u8) -> std::io::Result<()> {
self.buffer.fill_write(num, value)
}
pub fn write<T: Pod>(&mut self, value: T) {
self.debug_assert_alignment::<T>();
// Safety:
// in serialize_parameters_(aligned|unaligned) first we compute the
// required size then we write into the newly allocated buffer. There's
// no need to check bounds at every write.
//
// AlignedMemory::write_unchecked _does_ debug_assert!() that the capacity
// is enough, so in the unlikely case we introduce a bug in the size
// computation, tests will abort.
unsafe {
self.buffer.write_unchecked(value);
}
}
fn write_all(&mut self, value: &[u8]) {
// Safety:
// see write() - the buffer is guaranteed to be large enough
unsafe {
self.buffer.write_all_unchecked(value);
}
}
fn write_account(&mut self, account: &BorrowedAccount<'_>) -> Result<(), InstructionError> {
self.write_all(account.get_data());
if self.aligned {
let align_offset =
(account.get_data().len() as *const u8).align_offset(BPF_ALIGN_OF_U128);
self.fill_write(MAX_PERMITTED_DATA_INCREASE + align_offset, 0)
.map_err(|_| InstructionError::InvalidArgument)?;
}
Ok(())
}
fn push_region(&mut self) {
let range = self.region_start..self.buffer.len();
let region = MemoryRegion::new_writable(
self.buffer.as_slice_mut().get_mut(range.clone()).unwrap(),
self.vaddr,
);
self.regions.push(region);
self.region_start = range.end;
self.vaddr += range.len() as u64;
}
fn finish(mut self) -> (AlignedMemory<HOST_ALIGN>, Vec<MemoryRegion>) {
self.push_region();
debug_assert_eq!(self.region_start, self.buffer.len());
(self.buffer, self.regions)
}
fn debug_assert_alignment<T>(&self) {
debug_assert!(
!self.aligned
|| self
.buffer
.as_slice()
.as_ptr_range()
.end
.align_offset(mem::align_of::<T>())
== 0
);
}
}
pub fn serialize_parameters(
transaction_context: &TransactionContext,
instruction_context: &InstructionContext,
should_cap_ix_accounts: bool,
) -> Result<(AlignedMemory<HOST_ALIGN>, Vec<usize>), InstructionError> {
) -> Result<(AlignedMemory<HOST_ALIGN>, Vec<MemoryRegion>, Vec<usize>), InstructionError> {
let num_ix_accounts = instruction_context.get_number_of_instruction_accounts();
if should_cap_ix_accounts && num_ix_accounts > MAX_INSTRUCTION_ACCOUNTS as IndexOfAccount {
return Err(InstructionError::MaxAccountsExceeded);
}
let is_loader_deprecated = *instruction_context
.try_borrow_last_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(transaction_context, instruction_context)
let num_accounts = instruction_context.get_number_of_instruction_accounts() as usize;
let mut accounts = Vec::with_capacity(num_accounts);
let mut account_lengths: Vec<usize> = Vec::with_capacity(num_accounts);
for instruction_account_index in 0..instruction_context.get_number_of_instruction_accounts() {
if let Some(index) =
instruction_context.is_instruction_account_duplicate(instruction_account_index)?
{
accounts.push(SerializeAccount::Duplicate(index));
// unwrap here is safe: if an account is a duplicate, we must have
// seen the original already
account_lengths.push(*account_lengths.get(index as usize).unwrap());
} else {
let account = instruction_context
.try_borrow_instruction_account(transaction_context, instruction_account_index)?;
account_lengths.push(account.get_data().len());
accounts.push(SerializeAccount::Account(
instruction_account_index,
account,
));
};
}
.and_then(|buffer| {
let account_lengths = (0..instruction_context.get_number_of_instruction_accounts())
.map(|instruction_account_index| {
Ok(instruction_context
.try_borrow_instruction_account(transaction_context, instruction_account_index)?
.get_data()
.len())
})
.collect::<Result<Vec<usize>, InstructionError>>()?;
Ok((buffer, account_lengths))
})
if is_loader_deprecated {
serialize_parameters_unaligned(transaction_context, instruction_context, accounts)
} else {
serialize_parameters_aligned(transaction_context, instruction_context, accounts)
}
.map(|(buffer, regions)| (buffer, regions, account_lengths))
}
pub fn deserialize_parameters(
@ -77,82 +190,65 @@ pub fn deserialize_parameters(
}
}
pub fn serialize_parameters_unaligned(
fn serialize_parameters_unaligned(
transaction_context: &TransactionContext,
instruction_context: &InstructionContext,
) -> Result<AlignedMemory<HOST_ALIGN>, InstructionError> {
accounts: Vec<SerializeAccount>,
) -> Result<(AlignedMemory<HOST_ALIGN>, Vec<MemoryRegion>), InstructionError> {
// Calculate size in order to alloc once
let mut size = size_of::<u64>();
for instruction_account_index in 0..instruction_context.get_number_of_instruction_accounts() {
let duplicate =
instruction_context.is_instruction_account_duplicate(instruction_account_index)?;
for account in &accounts {
size += 1; // dup
if duplicate.is_none() {
let data_len = instruction_context
.try_borrow_instruction_account(transaction_context, instruction_account_index)?
.get_data()
.len();
size += size_of::<u8>() // is_signer
match account {
SerializeAccount::Duplicate(_) => {}
SerializeAccount::Account(_, account) => {
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
+ account.get_data().len() // data
+ size_of::<Pubkey>() // owner
+ size_of::<u8>() // executable
+ size_of::<u64>(); // rent_epoch
}
}
}
size += size_of::<u64>() // instruction data len
+ instruction_context.get_instruction_data().len() // instruction data
+ size_of::<Pubkey>(); // program id
let mut v = AlignedMemory::<HOST_ALIGN>::with_capacity(size);
v.write_u64::<LittleEndian>(instruction_context.get_number_of_instruction_accounts() as u64)
.map_err(|_| InstructionError::InvalidArgument)?;
for instruction_account_index in 0..instruction_context.get_number_of_instruction_accounts() {
let duplicate =
instruction_context.is_instruction_account_duplicate(instruction_account_index)?;
if let Some(position) = duplicate {
v.write_u8(position as u8)
.map_err(|_| InstructionError::InvalidArgument)?;
} else {
let borrowed_account = instruction_context
.try_borrow_instruction_account(transaction_context, instruction_account_index)?;
v.write_u8(NON_DUP_MARKER)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u8(borrowed_account.is_signer() as u8)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u8(borrowed_account.is_writable() as u8)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(borrowed_account.get_key().as_ref())
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u64::<LittleEndian>(borrowed_account.get_lamports())
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u64::<LittleEndian>(borrowed_account.get_data().len() as u64)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(borrowed_account.get_data())
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(borrowed_account.get_owner().as_ref())
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u8(borrowed_account.is_executable() as u8)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u64::<LittleEndian>(borrowed_account.get_rent_epoch() as u64)
.map_err(|_| InstructionError::InvalidArgument)?;
}
let mut s = Serializer::new(size, MM_INPUT_START, false);
s.write::<u64>((accounts.len() as u64).to_le());
for account in accounts {
match account {
SerializeAccount::Duplicate(position) => s.write(position as u8),
SerializeAccount::Account(_, account) => {
s.write::<u8>(NON_DUP_MARKER);
s.write::<u8>(account.is_signer() as u8);
s.write::<u8>(account.is_writable() as u8);
s.write_all(account.get_key().as_ref());
s.write::<u64>(account.get_lamports().to_le());
s.write::<u64>((account.get_data().len() as u64).to_le());
s.write_account(&account)
.map_err(|_| InstructionError::InvalidArgument)?;
s.write_all(account.get_owner().as_ref());
s.write::<u8>(account.is_executable() as u8);
s.write::<u64>((account.get_rent_epoch() as u64).to_le());
}
};
}
v.write_u64::<LittleEndian>(instruction_context.get_instruction_data().len() as u64)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(instruction_context.get_instruction_data())
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(
s.write::<u64>((instruction_context.get_instruction_data().len() as u64).to_le());
s.write_all(instruction_context.get_instruction_data());
s.write_all(
instruction_context
.try_borrow_last_program_account(transaction_context)?
.get_key()
.as_ref(),
)
.map_err(|_| InstructionError::InvalidArgument)?;
Ok(v)
);
Ok(s.finish())
}
pub fn deserialize_parameters_unaligned(
@ -205,24 +301,20 @@ pub fn deserialize_parameters_unaligned(
Ok(())
}
pub fn serialize_parameters_aligned(
fn serialize_parameters_aligned(
transaction_context: &TransactionContext,
instruction_context: &InstructionContext,
) -> Result<AlignedMemory<HOST_ALIGN>, InstructionError> {
accounts: Vec<SerializeAccount>,
) -> Result<(AlignedMemory<HOST_ALIGN>, Vec<MemoryRegion>), InstructionError> {
// Calculate size in order to alloc once
let mut size = size_of::<u64>();
for instruction_account_index in 0..instruction_context.get_number_of_instruction_accounts() {
let duplicate =
instruction_context.is_instruction_account_duplicate(instruction_account_index)?;
for account in &accounts {
size += 1; // dup
if duplicate.is_some() {
size += 7; // padding to 64-bit aligned
} else {
let data_len = instruction_context
.try_borrow_instruction_account(transaction_context, instruction_account_index)?
.get_data()
.len();
size += size_of::<u8>() // is_signer
match account {
SerializeAccount::Duplicate(_) => size += 7, // padding to 64-bit aligned
SerializeAccount::Account(_, account) => {
let data_len = account.get_data().len();
size += size_of::<u8>() // is_signer
+ size_of::<u8>() // is_writable
+ size_of::<u8>() // executable
+ size_of::<u32>() // original_data_len
@ -234,69 +326,49 @@ pub fn serialize_parameters_aligned(
+ 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_context.get_instruction_data().len()
+ size_of::<Pubkey>(); // program id;
let mut v = AlignedMemory::<HOST_ALIGN>::with_capacity(size);
let mut s = Serializer::new(size, MM_INPUT_START, true);
// Serialize into the buffer
v.write_u64::<LittleEndian>(instruction_context.get_number_of_instruction_accounts() as u64)
.map_err(|_| InstructionError::InvalidArgument)?;
for instruction_account_index in 0..instruction_context.get_number_of_instruction_accounts() {
let duplicate =
instruction_context.is_instruction_account_duplicate(instruction_account_index)?;
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_instruction_account(transaction_context, instruction_account_index)?;
v.write_u8(NON_DUP_MARKER)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u8(borrowed_account.is_signer() as u8)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u8(borrowed_account.is_writable() as u8)
.map_err(|_| InstructionError::InvalidArgument)?;
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(borrowed_account.get_key().as_ref())
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(borrowed_account.get_owner().as_ref())
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u64::<LittleEndian>(borrowed_account.get_lamports())
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u64::<LittleEndian>(borrowed_account.get_data().len() as u64)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(borrowed_account.get_data())
.map_err(|_| InstructionError::InvalidArgument)?;
v.fill_write(
MAX_PERMITTED_DATA_INCREASE
+ (v.write_index() as *const u8).align_offset(BPF_ALIGN_OF_U128),
0,
)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u64::<LittleEndian>(borrowed_account.get_rent_epoch() as u64)
.map_err(|_| InstructionError::InvalidArgument)?;
}
s.write::<u64>((accounts.len() as u64).to_le());
for account in accounts {
match account {
SerializeAccount::Account(_, borrowed_account) => {
s.write::<u8>(NON_DUP_MARKER);
s.write::<u8>(borrowed_account.is_signer() as u8);
s.write::<u8>(borrowed_account.is_writable() as u8);
s.write::<u8>(borrowed_account.is_executable() as u8);
s.write_all(&[0u8, 0, 0, 0]);
s.write_all(borrowed_account.get_key().as_ref());
s.write_all(borrowed_account.get_owner().as_ref());
s.write::<u64>(borrowed_account.get_lamports().to_le());
s.write::<u64>((borrowed_account.get_data().len() as u64).to_le());
s.write_account(&borrowed_account)
.map_err(|_| InstructionError::InvalidArgument)?;
s.write::<u64>((borrowed_account.get_rent_epoch() as u64).to_le());
}
SerializeAccount::Duplicate(position) => {
s.write::<u8>(position as u8);
s.write_all(&[0u8, 0, 0, 0, 0, 0, 0]);
}
};
}
v.write_u64::<LittleEndian>(instruction_context.get_instruction_data().len() as u64)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(instruction_context.get_instruction_data())
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(
s.write::<u64>((instruction_context.get_instruction_data().len() as u64).to_le());
s.write_all(instruction_context.get_instruction_data());
s.write_all(
instruction_context
.try_borrow_last_program_account(transaction_context)?
.get_key()
.as_ref(),
)
.map_err(|_| InstructionError::InvalidArgument)?;
Ok(v)
);
Ok(s.finish())
}
pub fn deserialize_parameters_aligned(
@ -525,7 +597,7 @@ mod tests {
continue;
}
let (mut serialized, _account_lengths) = serialization_result.unwrap();
let (mut serialized, _regions, _account_lengths) = serialization_result.unwrap();
let (de_program_id, de_accounts, de_instruction_data) =
unsafe { deserialize(serialized.as_slice_mut().first_mut().unwrap() as *mut u8) };
assert_eq!(de_program_id, &program_id);
@ -665,7 +737,7 @@ mod tests {
// check serialize_parameters_aligned
let (mut serialized, account_lengths) = serialize_parameters(
let (mut serialized, _regions, account_lengths) = serialize_parameters(
invoke_context.transaction_context,
instruction_context,
true,
@ -741,7 +813,7 @@ mod tests {
.borrow_mut()
.set_owner(bpf_loader_deprecated::id());
let (mut serialized, account_lengths) = serialize_parameters(
let (mut serialized, _regions, account_lengths) = serialize_parameters(
invoke_context.transaction_context,
instruction_context,
true,

View File

@ -233,7 +233,7 @@ native machine code before execting it in the virtual machine.",
&instruction_data,
);
invoke_context.push().unwrap();
let (mut parameter_bytes, account_lengths) = serialize_parameters(
let (_parameter_bytes, regions, account_lengths) = serialize_parameters(
invoke_context.transaction_context,
invoke_context
.transaction_context
@ -292,7 +292,7 @@ native machine code before execting it in the virtual machine.",
let mut vm = create_vm(
&verified_executable,
parameter_bytes.as_slice_mut(),
regions,
account_lengths,
&mut invoke_context,
)

View File

@ -700,11 +700,13 @@ pub struct BorrowedAccount<'a> {
impl<'a> BorrowedAccount<'a> {
/// Returns the index of this account (transaction wide)
#[inline]
pub fn get_index_in_transaction(&self) -> IndexOfAccount {
self.index_in_transaction
}
/// Returns the public key of this account (transaction wide)
#[inline]
pub fn get_key(&self) -> &Pubkey {
self.transaction_context
.get_key_of_account_at_index(self.index_in_transaction)
@ -712,6 +714,7 @@ impl<'a> BorrowedAccount<'a> {
}
/// Returns the owner of this account (transaction wide)
#[inline]
pub fn get_owner(&self) -> &Pubkey {
self.account.owner()
}
@ -760,6 +763,7 @@ impl<'a> BorrowedAccount<'a> {
}
/// Returns the number of lamports of this account (transaction wide)
#[inline]
pub fn get_lamports(&self) -> u64 {
self.account.lamports()
}
@ -824,6 +828,7 @@ impl<'a> BorrowedAccount<'a> {
}
/// Returns a read-only slice of the account data (transaction wide)
#[inline]
pub fn get_data(&self) -> &[u8] {
self.account.data()
}
@ -936,6 +941,7 @@ impl<'a> BorrowedAccount<'a> {
}
/// Returns whether this account is executable (transaction wide)
#[inline]
pub fn is_executable(&self) -> bool {
self.account.executable()
}
@ -982,6 +988,7 @@ impl<'a> BorrowedAccount<'a> {
/// Returns the rent epoch of this account (transaction wide)
#[cfg(not(target_os = "solana"))]
#[inline]
pub fn get_rent_epoch(&self) -> u64 {
self.account.rent_epoch()
}