diff --git a/program-test/src/lib.rs b/program-test/src/lib.rs index 6ecf34642..03ed0ef39 100644 --- a/program-test/src/lib.rs +++ b/program-test/src/lib.rs @@ -118,7 +118,7 @@ pub fn builtin_process_instruction( let deduplicated_indices: HashSet = 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 diff --git a/programs/bpf/benches/bpf_loader.rs b/programs/bpf/benches/bpf_loader.rs index c0137b0b0..a848cdc1c 100644 --- a/programs/bpf/benches/bpf_loader.rs +++ b/programs/bpf/benches/bpf_loader.rs @@ -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, ) diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index aa7511ca7..0a50fb812 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -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, ) diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index e99b62adb..b97263823 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -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, - parameter_bytes: &mut [u8], + regions: Vec, orig_account_lengths: Vec, invoke_context: &'a mut InvokeContext<'b>, ) -> Result, EbpfError> { @@ -303,13 +303,8 @@ pub fn create_vm<'a, 'b>( ); let mut heap = AlignedMemory::::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::{ diff --git a/programs/bpf_loader/src/serialization.rs b/programs/bpf_loader/src/serialization.rs index 7b60c8a10..94283520f 100644 --- a/programs/bpf_loader/src/serialization.rs +++ b/programs/bpf_loader/src/serialization.rs @@ -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, + regions: Vec, + 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(&mut self, value: T) { + self.debug_assert_alignment::(); + // 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, Vec) { + self.push_region(); + debug_assert_eq!(self.region_start, self.buffer.len()); + (self.buffer, self.regions) + } + + fn debug_assert_alignment(&self) { + debug_assert!( + !self.aligned + || self + .buffer + .as_slice() + .as_ptr_range() + .end + .align_offset(mem::align_of::()) + == 0 + ); + } +} + pub fn serialize_parameters( transaction_context: &TransactionContext, instruction_context: &InstructionContext, should_cap_ix_accounts: bool, -) -> Result<(AlignedMemory, Vec), InstructionError> { +) -> Result<(AlignedMemory, Vec, Vec), 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 = 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::, 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, InstructionError> { + accounts: Vec, +) -> Result<(AlignedMemory, Vec), InstructionError> { // Calculate size in order to alloc once let mut size = size_of::(); - 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::() // is_signer + match account { + SerializeAccount::Duplicate(_) => {} + SerializeAccount::Account(_, account) => { + size += size_of::() // is_signer + size_of::() // is_writable + size_of::() // key + size_of::() // lamports + size_of::() // data len - + data_len // data + + account.get_data().len() // data + size_of::() // owner + size_of::() // executable + size_of::(); // rent_epoch + } } } size += size_of::() // instruction data len + instruction_context.get_instruction_data().len() // instruction data + size_of::(); // program id - let mut v = AlignedMemory::::with_capacity(size); - v.write_u64::(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::(borrowed_account.get_lamports()) - .map_err(|_| InstructionError::InvalidArgument)?; - v.write_u64::(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::(borrowed_account.get_rent_epoch() as u64) - .map_err(|_| InstructionError::InvalidArgument)?; - } + let mut s = Serializer::new(size, MM_INPUT_START, false); + + s.write::((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::(NON_DUP_MARKER); + s.write::(account.is_signer() as u8); + s.write::(account.is_writable() as u8); + s.write_all(account.get_key().as_ref()); + s.write::(account.get_lamports().to_le()); + s.write::((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::(account.is_executable() as u8); + s.write::((account.get_rent_epoch() as u64).to_le()); + } + }; } - v.write_u64::(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::((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, InstructionError> { + accounts: Vec, +) -> Result<(AlignedMemory, Vec), InstructionError> { // Calculate size in order to alloc once let mut size = size_of::(); - 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::() // 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::() // is_signer + size_of::() // is_writable + size_of::() // executable + size_of::() // 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::(); // rent epoch + } } } size += size_of::() // data len + instruction_context.get_instruction_data().len() + size_of::(); // program id; - let mut v = AlignedMemory::::with_capacity(size); + + let mut s = Serializer::new(size, MM_INPUT_START, true); // Serialize into the buffer - v.write_u64::(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::(borrowed_account.get_lamports()) - .map_err(|_| InstructionError::InvalidArgument)?; - v.write_u64::(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::(borrowed_account.get_rent_epoch() as u64) - .map_err(|_| InstructionError::InvalidArgument)?; - } + s.write::((accounts.len() as u64).to_le()); + for account in accounts { + match account { + SerializeAccount::Account(_, borrowed_account) => { + s.write::(NON_DUP_MARKER); + s.write::(borrowed_account.is_signer() as u8); + s.write::(borrowed_account.is_writable() as u8); + s.write::(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::(borrowed_account.get_lamports().to_le()); + s.write::((borrowed_account.get_data().len() as u64).to_le()); + s.write_account(&borrowed_account) + .map_err(|_| InstructionError::InvalidArgument)?; + s.write::((borrowed_account.get_rent_epoch() as u64).to_le()); + } + SerializeAccount::Duplicate(position) => { + s.write::(position as u8); + s.write_all(&[0u8, 0, 0, 0, 0, 0, 0]); + } + }; } - v.write_u64::(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::((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, diff --git a/rbpf-cli/src/main.rs b/rbpf-cli/src/main.rs index 3486339d7..fcc97ae25 100644 --- a/rbpf-cli/src/main.rs +++ b/rbpf-cli/src/main.rs @@ -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, ) diff --git a/sdk/src/transaction_context.rs b/sdk/src/transaction_context.rs index e27bf27ff..02db1c2de 100644 --- a/sdk/src/transaction_context.rs +++ b/sdk/src/transaction_context.rs @@ -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() }