From a8543ad99244cbbd75a2f630753903ca812b9432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Tue, 23 Aug 2022 23:55:56 +0200 Subject: [PATCH] Feature: `stop_sibling_instruction_search_at_parent` (#27290) * Adds stop_sibling_instruction_search_at_parent. * Adds test_syscall_sol_get_processed_sibling_instruction(). --- programs/bpf_loader/src/syscalls/mod.rs | 156 +++++++++++++++++++++++- sdk/src/feature_set.rs | 5 + 2 files changed, 158 insertions(+), 3 deletions(-) diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index 2893849a9f..59f64b41a0 100644 --- a/programs/bpf_loader/src/syscalls/mod.rs +++ b/programs/bpf_loader/src/syscalls/mod.rs @@ -36,7 +36,8 @@ use { self, blake3_syscall_enabled, check_physical_overlapping, check_slice_translation_size, curve25519_syscall_enabled, disable_cpi_setting_executable_and_rent_epoch, disable_fees_sysvar, enable_early_verification_of_account_modifications, - libsecp256k1_0_5_upgrade_enabled, limit_secp256k1_recovery_id, syscall_saturated_math, + libsecp256k1_0_5_upgrade_enabled, limit_secp256k1_recovery_id, + stop_sibling_instruction_search_at_parent, syscall_saturated_math, }, hash::{Hasher, HASH_BYTES}, instruction::{ @@ -1708,6 +1709,9 @@ declare_syscall!( .consume(budget.syscall_base_cost), result ); + let stop_sibling_instruction_search_at_parent = invoke_context + .feature_set + .is_active(&stop_sibling_instruction_search_at_parent::id()); // Reverse iterate through the instruction trace, // ignoring anything except instructions on the same level @@ -1725,8 +1729,9 @@ declare_syscall!( .map_err(SyscallError::InstructionError), result ); - if instruction_context.get_stack_height() == TRANSACTION_LEVEL_STACK_HEIGHT - && stack_height > TRANSACTION_LEVEL_STACK_HEIGHT + if (stop_sibling_instruction_search_at_parent + || instruction_context.get_stack_height() == TRANSACTION_LEVEL_STACK_HEIGHT) + && instruction_context.get_stack_height() < stack_height { break; } @@ -3108,6 +3113,151 @@ mod tests { call_program_address_common(seeds, address, &mut syscall) } + #[test] + fn test_syscall_sol_get_processed_sibling_instruction() { + let transaction_accounts = (0..9) + .map(|_| { + ( + Pubkey::new_unique(), + AccountSharedData::new(0, 0, &bpf_loader::id()), + ) + }) + .collect::>(); + let mut transaction_context = TransactionContext::new(transaction_accounts, None, 4, 1); + for (index_in_trace, stack_height) in [1, 2, 3, 2, 2, 3, 4, 3].into_iter().enumerate() { + while stack_height <= transaction_context.get_instruction_context_stack_height() { + transaction_context.pop().unwrap(); + } + if stack_height > transaction_context.get_instruction_context_stack_height() { + let instruction_accounts = [InstructionAccount { + index_in_transaction: index_in_trace.saturating_add(1), + index_in_caller: 0, // This is incorrect / inconsistent but not required + index_in_callee: 0, + is_signer: false, + is_writable: false, + }]; + transaction_context + .push(&[0], &instruction_accounts, &[index_in_trace as u8]) + .unwrap(); + } + } + let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); + + let syscall_base_cost = invoke_context.get_compute_budget().syscall_base_cost; + let mut syscall_get_processed_sibling_instruction = SyscallGetProcessedSiblingInstruction { + invoke_context: Rc::new(RefCell::new(&mut invoke_context)), + }; + const VM_BASE_ADDRESS: u64 = 0x100000000; + const META_OFFSET: usize = 0; + const PROGRAM_ID_OFFSET: usize = + META_OFFSET + std::mem::size_of::(); + const DATA_OFFSET: usize = PROGRAM_ID_OFFSET + std::mem::size_of::(); + const ACCOUNTS_OFFSET: usize = DATA_OFFSET + 0x100; + const END_OFFSET: usize = ACCOUNTS_OFFSET + std::mem::size_of::() * 4; + let mut memory = [0u8; END_OFFSET]; + let config = Config::default(); + let mut memory_mapping = MemoryMapping::new::( + vec![ + MemoryRegion::default(), + MemoryRegion { + host_addr: memory.as_mut_ptr() as u64, + vm_addr: VM_BASE_ADDRESS, + len: END_OFFSET as u64, + vm_gap_shift: 63, + is_writable: true, + }, + ], + &config, + ) + .unwrap(); + let processed_sibling_instruction = translate_type_mut::( + &memory_mapping, + VM_BASE_ADDRESS, + true, + ) + .unwrap(); + processed_sibling_instruction.data_len = 1; + processed_sibling_instruction.accounts_len = 1; + let program_id = translate_type_mut::( + &memory_mapping, + VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64), + true, + ) + .unwrap(); + let data = translate_slice_mut::( + &memory_mapping, + VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64), + processed_sibling_instruction.data_len as u64, + true, + true, + ) + .unwrap(); + let accounts = translate_slice_mut::( + &memory_mapping, + VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64), + processed_sibling_instruction.accounts_len as u64, + true, + true, + ) + .unwrap(); + + syscall_get_processed_sibling_instruction + .invoke_context + .borrow_mut() + .get_compute_meter() + .borrow_mut() + .mock_set_remaining(syscall_base_cost); + let mut result: Result> = Ok(0); + syscall_get_processed_sibling_instruction.call( + 0, + VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64), + VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64), + VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64), + VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64), + &mut memory_mapping, + &mut result, + ); + assert_eq!(result, Ok(1)); + { + let transaction_context = &syscall_get_processed_sibling_instruction + .invoke_context + .borrow() + .transaction_context; + assert_eq!(processed_sibling_instruction.data_len, 1); + assert_eq!(processed_sibling_instruction.accounts_len, 1); + assert_eq!( + program_id, + transaction_context.get_key_of_account_at_index(0).unwrap(), + ); + assert_eq!(data, &[5]); + assert_eq!( + accounts, + &[AccountMeta { + pubkey: *transaction_context.get_key_of_account_at_index(6).unwrap(), + is_signer: false, + is_writable: false + }] + ); + } + + syscall_get_processed_sibling_instruction + .invoke_context + .borrow_mut() + .get_compute_meter() + .borrow_mut() + .mock_set_remaining(syscall_base_cost); + syscall_get_processed_sibling_instruction.call( + 1, + VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64), + VM_BASE_ADDRESS.saturating_add(PROGRAM_ID_OFFSET as u64), + VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64), + VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64), + &mut memory_mapping, + &mut result, + ); + assert_eq!(result, Ok(0)); + } + #[test] fn test_create_program_address() { // These tests duplicate the direct tests in solana_program::pubkey diff --git a/sdk/src/feature_set.rs b/sdk/src/feature_set.rs index a0770e5fa0..0e7bd8c9d7 100644 --- a/sdk/src/feature_set.rs +++ b/sdk/src/feature_set.rs @@ -506,6 +506,10 @@ pub mod relax_authority_signer_check_for_lookup_table_creation { solana_sdk::declare_id!("FKAcEvNgSY79RpqsPNUV5gDyumopH4cEHqUxyfm8b8Ap"); } +pub mod stop_sibling_instruction_search_at_parent { + solana_sdk::declare_id!("EYVpEP7uzH1CoXzbD6PubGhYmnxRXPeq3PPsm1ba3gpo"); +} + lazy_static! { /// Map of feature identifiers to user-visible description pub static ref FEATURE_NAMES: HashMap = [ @@ -627,6 +631,7 @@ lazy_static! { (incremental_snapshot_only_incremental_hash_calculation::id(), "only hash accounts in incremental snapshot during incremental snapshot creation #26799"), (disable_cpi_setting_executable_and_rent_epoch::id(), "disable setting is_executable and_rent_epoch in CPI #26987"), (relax_authority_signer_check_for_lookup_table_creation::id(), "relax authority signer check for lookup table creation #27205"), + (stop_sibling_instruction_search_at_parent::id(), "stop the search in get_processed_sibling_instruction when the parent instruction is reached #27289"), /*************** ADD NEW FEATURES HERE ***************/ ] .iter()