diff --git a/programs/bpf/benches/bpf_loader.rs b/programs/bpf/benches/bpf_loader.rs index 63513f6a77f1ef..859cf171d3c42b 100644 --- a/programs/bpf/benches/bpf_loader.rs +++ b/programs/bpf/benches/bpf_loader.rs @@ -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(); diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 186fcc5a903976..5d61c6d3d5e03b 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -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(); @@ -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, diff --git a/programs/bpf_loader/benches/serialization.rs b/programs/bpf_loader/benches/serialization.rs index 1287f518ee0757..900f39df8ebb06 100644 --- a/programs/bpf_loader/benches/serialization.rs +++ b/programs/bpf_loader/benches/serialization.rs @@ -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, - Vec>, - Vec, -) { +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::>(); + 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(); }); } diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 82c537a999381e..118f71657f7f74 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -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 diff --git a/programs/bpf_loader/src/serialization.rs b/programs/bpf_loader/src/serialization.rs index 75f4f2c5253c24..cc4c7969939648 100644 --- a/programs/bpf_loader/src/serialization.rs +++ b/programs/bpf_loader/src/serialization.rs @@ -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 { + 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), 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::, 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 { // Calculate size in order to alloc once let mut size = size_of::(); - 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::() // is_signer + + size_of::() // is_writable + + size_of::() // key + + size_of::() // lamports + + size_of::() // data len + + data_len // data + + size_of::() // owner + + size_of::() // executable + + size_of::(); // rent_epoch } } size += size_of::() // instruction data len - + instruction_data.len() // instruction data + + instruction_context.get_instruction_data().len() // instruction data + size_of::(); // program id let mut v = AlignedMemory::new(size, HOST_ALIGN); - v.write_u64::(keyed_accounts.len() as u64) + v.write_u64::(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::(keyed_account.lamports()?) + v.write_u64::(borrowed_account.get_lamports()) .map_err(|_| InstructionError::InvalidArgument)?; - v.write_u64::(keyed_account.data_len()? as u64) + v.write_u64::(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::(keyed_account.rent_epoch()? as u64) + v.write_u64::(borrowed_account.get_rent_epoch() as u64) .map_err(|_| InstructionError::InvalidArgument)?; } } - v.write_u64::(instruction_data.len() as u64) - .map_err(|_| InstructionError::InvalidArgument)?; - v.write_all(instruction_data) + v.write_u64::(instruction_context.get_instruction_data().len() as u64) .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::(); // 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::(); // is_signer start += size_of::(); // is_writable start += size_of::(); // 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::() // lamports + size_of::(); // 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::() // owner + size_of::() // executable + size_of::(); // rent_epoch @@ -167,77 +206,77 @@ pub fn deserialize_parameters_unaligned( Ok(()) } -pub fn get_serialized_account_size_aligned( - keyed_account: &KeyedAccount, -) -> Result { - let data_len = keyed_account.data_len()?; - Ok( - size_of::() // is_signer - + size_of::() // is_writable - + size_of::() // executable - + 4 // padding to 128-bit aligned - + size_of::() // key - + size_of::() // owner - + size_of::() // lamports - + size_of::() // data len - + data_len - + MAX_PERMITTED_DATA_INCREASE - + (data_len as *const u8).align_offset(BPF_ALIGN_OF_U128) - + size_of::(), // rent epoch - ) -} - pub fn serialize_parameters_aligned( - program_id: &Pubkey, - keyed_accounts: &[KeyedAccount], - instruction_data: &[u8], + transaction_context: &TransactionContext, + instruction_context: &InstructionContext, ) -> Result { // Calculate size in order to alloc once let mut size = size_of::(); - 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::() // is_signer + + size_of::() // is_writable + + size_of::() // executable + + 4 // padding to 128-bit aligned + + size_of::() // key + + size_of::() // owner + + size_of::() // lamports + + size_of::() // data len + + data_len + + 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_data.len() + + instruction_context.get_instruction_data().len() + size_of::(); // program id; let mut v = AlignedMemory::new(size, HOST_ALIGN); // Serialize into the buffer - v.write_u64::(keyed_accounts.len() as u64) + v.write_u64::(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::(keyed_account.lamports()?) + v.write_u64::(borrowed_account.get_lamports()) .map_err(|_| InstructionError::InvalidArgument)?; - v.write_u64::(keyed_account.data_len()? as u64) + v.write_u64::(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::(keyed_account.rent_epoch()? as u64) + v.write_u64::(borrowed_account.get_rent_epoch() as u64) .map_err(|_| InstructionError::InvalidArgument)?; } } - v.write_u64::(instruction_data.len() as u64) + v.write_u64::(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::(); // 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::(); // 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::() // is_signer + size_of::() // is_writable + size_of::() // executable + 4 // padding to 128-bit aligned + size_of::(); // key - account.copy_into_owner_from_slice(&buffer[start..start + size_of::()]); + let _ = borrowed_account.set_owner(&buffer[start..start + size_of::()]); start += size_of::(); // owner - account.set_lamports(LittleEndian::read_u64(&buffer[start..])); + let _ = borrowed_account.set_lamports(LittleEndian::read_u64(&buffer[start..])); start += size_of::(); // lamports let post_len = LittleEndian::read_u64(&buffer[start..]) as usize; start += size_of::(); // 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::(); // 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,52 +451,19 @@ mod tests { }), ), ]; - let instruction_accounts = vec![ - AccountMeta { - pubkey: transaction_accounts[1].0, - is_signer: false, - is_writable: false, - }, - 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[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, ); @@ -465,17 +476,15 @@ mod tests { &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) }; @@ -487,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); @@ -514,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); @@ -561,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(), diff --git a/rbpf-cli/src/main.rs b/rbpf-cli/src/main.rs index d7e564e8080580..ed9575198aa467 100644 --- a/rbpf-cli/src/main.rs +++ b/rbpf-cli/src/main.rs @@ -221,12 +221,12 @@ native machine code before execting it in the virtual machine.", &instruction_data, ) .unwrap(); - let keyed_accounts = invoke_context.get_keyed_accounts().unwrap(); let (mut parameter_bytes, account_lengths) = serialize_parameters( - keyed_accounts[0].unsigned_key(), - keyed_accounts[1].unsigned_key(), - &keyed_accounts[2..], - &instruction_data, + invoke_context.transaction_context, + invoke_context + .transaction_context + .get_current_instruction_context() + .unwrap(), ) .unwrap(); let compute_meter = invoke_context.get_compute_meter();