From 280200fb573abff3814bc7082b82e3464fb6a3b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Thu, 16 Sep 2021 16:24:07 +0200 Subject: [PATCH] Explicitly routes the serialized account lengths to enable sharing of existing account structures. --- programs/bpf/benches/bpf_loader.rs | 2 +- programs/bpf/tests/programs.rs | 3 +- programs/bpf_loader/src/lib.rs | 9 ++++- programs/bpf_loader/src/serialization.rs | 51 +++++++++++++++++------- rbpf-cli/src/main.rs | 3 +- 5 files changed, 49 insertions(+), 19 deletions(-) diff --git a/programs/bpf/benches/bpf_loader.rs b/programs/bpf/benches/bpf_loader.rs index d0a7601c27880d..980f1f433c9dce 100644 --- a/programs/bpf/benches/bpf_loader.rs +++ b/programs/bpf/benches/bpf_loader.rs @@ -220,7 +220,7 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) { // Serialize account data let keyed_accounts = invoke_context.get_keyed_accounts().unwrap(); - let mut serialized = serialize_parameters( + let (mut serialized, _account_lengths) = serialize_parameters( &bpf_loader::id(), &solana_sdk::pubkey::new_rand(), keyed_accounts, diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 1f3f82a04766f8..38c4439139e2e7 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -198,7 +198,7 @@ fn run_program( let mut data = vec![]; file.read_to_end(&mut data).unwrap(); let loader_id = bpf_loader::id(); - let parameter_bytes = serialize_parameters( + let (parameter_bytes, account_lengths) = serialize_parameters( &bpf_loader::id(), program_id, ¶meter_accounts, @@ -282,6 +282,7 @@ fn run_program( &bpf_loader::id(), parameter_accounts, parameter_bytes.as_slice(), + &account_lengths, ) .unwrap(); } diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 6d14393c1e0a74..7aa679024ab72f 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -872,7 +872,7 @@ impl Executor for BpfExecutor { let mut serialize_time = Measure::start("serialize"); let keyed_accounts = invoke_context.get_keyed_accounts()?; - let mut parameter_bytes = + let (mut parameter_bytes, account_lengths) = serialize_parameters(loader_id, program_id, keyed_accounts, instruction_data)?; serialize_time.stop(); let mut create_vm_time = Measure::start("create_vm"); @@ -955,7 +955,12 @@ impl Executor for BpfExecutor { } let mut deserialize_time = Measure::start("deserialize"); let keyed_accounts = invoke_context.get_keyed_accounts()?; - deserialize_parameters(loader_id, keyed_accounts, parameter_bytes.as_slice())?; + deserialize_parameters( + loader_id, + keyed_accounts, + parameter_bytes.as_slice(), + &account_lengths, + )?; deserialize_time.stop(); invoke_context.update_timing( serialize_time.as_us(), diff --git a/programs/bpf_loader/src/serialization.rs b/programs/bpf_loader/src/serialization.rs index 4f842abebb36d7..0d5f222303e15a 100644 --- a/programs/bpf_loader/src/serialization.rs +++ b/programs/bpf_loader/src/serialization.rs @@ -28,23 +28,31 @@ pub fn serialize_parameters( program_id: &Pubkey, keyed_accounts: &[KeyedAccount], data: &[u8], -) -> Result { +) -> Result<(AlignedMemory, Vec), InstructionError> { if *loader_id == bpf_loader_deprecated::id() { serialize_parameters_unaligned(program_id, keyed_accounts, data) } else { serialize_parameters_aligned(program_id, keyed_accounts, data) } + .and_then(|buffer| { + let account_lengths = keyed_accounts + .iter() + .map(|keyed_account| keyed_account.data_len()) + .collect::, InstructionError>>()?; + Ok((buffer, account_lengths)) + }) } pub fn deserialize_parameters( loader_id: &Pubkey, keyed_accounts: &[KeyedAccount], buffer: &[u8], + account_lengths: &[usize], ) -> Result<(), InstructionError> { if *loader_id == bpf_loader_deprecated::id() { - deserialize_parameters_unaligned(keyed_accounts, buffer) + deserialize_parameters_unaligned(keyed_accounts, buffer, account_lengths) } else { - deserialize_parameters_aligned(keyed_accounts, buffer) + deserialize_parameters_aligned(keyed_accounts, buffer, account_lengths) } } @@ -126,9 +134,14 @@ pub fn serialize_parameters_unaligned( pub fn deserialize_parameters_unaligned( keyed_accounts: &[KeyedAccount], buffer: &[u8], + account_lengths: &[usize], ) -> Result<(), InstructionError> { let mut start = size_of::(); // number of accounts - for (i, keyed_account) in keyed_accounts.iter().enumerate() { + for (i, (keyed_account, _pre_len)) in keyed_accounts + .iter() + .zip(account_lengths.iter()) + .enumerate() + { let (is_dup, _) = is_dup(&keyed_accounts[..i], keyed_account); start += 1; // is_dup if !is_dup { @@ -247,9 +260,14 @@ pub fn serialize_parameters_aligned( pub fn deserialize_parameters_aligned( keyed_accounts: &[KeyedAccount], buffer: &[u8], + account_lengths: &[usize], ) -> Result<(), InstructionError> { let mut start = size_of::(); // number of accounts - for (i, keyed_account) in keyed_accounts.iter().enumerate() { + for (i, (keyed_account, pre_len)) in keyed_accounts + .iter() + .zip(account_lengths.iter()) + .enumerate() + { let (is_dup, _) = is_dup(&keyed_accounts[..i], keyed_account); start += size_of::(); // position if is_dup { @@ -265,18 +283,17 @@ pub fn deserialize_parameters_aligned( start += size_of::(); // owner account.set_lamports(LittleEndian::read_u64(&buffer[start..])); start += size_of::(); // lamports - let pre_len = account.data().len(); let post_len = LittleEndian::read_u64(&buffer[start..]) as usize; start += size_of::(); // data length - let mut data_end = start + pre_len; - if post_len != pre_len - && (post_len.saturating_sub(pre_len)) <= MAX_PERMITTED_DATA_INCREASE + let mut data_end = start + *pre_len; + if post_len != *pre_len + && (post_len.saturating_sub(*pre_len)) <= MAX_PERMITTED_DATA_INCREASE { data_end = start + post_len; } account.set_data_from_slice(&buffer[start..data_end]); - start += pre_len + MAX_PERMITTED_DATA_INCREASE; // data + start += *pre_len + MAX_PERMITTED_DATA_INCREASE; // data start += (start as *const u8).align_offset(align_of::()); start += size_of::(); // rent_epoch } @@ -392,7 +409,7 @@ mod tests { // check serialize_parameters_aligned - let mut serialized = serialize_parameters( + let (mut serialized, account_lengths) = serialize_parameters( &bpf_loader::id(), &program_id, &keyed_accounts, @@ -445,8 +462,13 @@ mod tests { } }) .collect(); - deserialize_parameters(&bpf_loader::id(), &de_keyed_accounts, serialized.as_slice()) - .unwrap(); + deserialize_parameters( + &bpf_loader::id(), + &de_keyed_accounts, + serialized.as_slice(), + &account_lengths, + ) + .unwrap(); for ((account, de_keyed_account), key) in accounts.iter().zip(de_keyed_accounts).zip(keys.clone()) { @@ -458,7 +480,7 @@ mod tests { // check serialize_parameters_unaligned - let mut serialized = serialize_parameters( + let (mut serialized, account_lengths) = serialize_parameters( &bpf_loader_deprecated::id(), &program_id, &keyed_accounts, @@ -497,6 +519,7 @@ mod tests { &bpf_loader_deprecated::id(), &de_keyed_accounts, serialized.as_slice(), + &account_lengths, ) .unwrap(); for ((account, de_keyed_account), key) in diff --git a/rbpf-cli/src/main.rs b/rbpf-cli/src/main.rs index b8f4ed4e1f64c7..12006e4a816338 100644 --- a/rbpf-cli/src/main.rs +++ b/rbpf-cli/src/main.rs @@ -170,7 +170,8 @@ native machine code before execting it in the virtual machine.", } let lid = bpf_loader::id(); let pid = Pubkey::new(&[0u8; 32]); - let mut bytes = serialize_parameters(&lid, &pid, &accounts, &input.insndata).unwrap(); + let (mut bytes, _account_lenghts) = + serialize_parameters(&lid, &pid, &accounts, &input.insndata).unwrap(); Vec::from(bytes.as_slice_mut()) } };