From 9731331be4dd4bfccf85b0443e3d652aec30a1f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Wed, 5 Jul 2023 19:46:21 +0200 Subject: [PATCH] Bump solana_rbpf to v0.6.0 (#32313) --- Cargo.lock | 4 +- Cargo.toml | 2 +- ledger-tool/src/program.rs | 6 +- program-runtime/src/invoke_context.rs | 4 +- programs/bpf_loader/src/lib.rs | 47 ++++++----- programs/bpf_loader/src/syscalls/cpi.rs | 47 ++++++++--- programs/bpf_loader/src/syscalls/mem_ops.rs | 19 ++++- programs/bpf_loader/src/syscalls/mod.rs | 89 +++++++++++++-------- programs/loader-v4/src/lib.rs | 37 +++++---- programs/sbf/Cargo.lock | 4 +- programs/sbf/Cargo.toml | 2 +- programs/sbf/benches/bpf_loader.rs | 26 +++--- 12 files changed, 176 insertions(+), 111 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d0b7111f2c..f5ddc5e4a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7347,9 +7347,9 @@ dependencies = [ [[package]] name = "solana_rbpf" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ae90c406f0a2d4a15f08d16c8b64f37997a57611fec0a89f1277854166996e8" +checksum = "b3082ec3a1d4ef7879eb5b84916d5acde057abd59733eec3647e0ab8885283ef" dependencies = [ "byteorder", "combine", diff --git a/Cargo.toml b/Cargo.toml index 5213461a2c..ca4e669d19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -292,7 +292,7 @@ siphasher = "0.3.10" smpl_jwt = "0.7.1" socket2 = "0.4.9" soketto = "0.7" -solana_rbpf = "=0.5.0" +solana_rbpf = "=0.6.0" solana-account-decoder = { path = "account-decoder", version = "=1.17.0" } solana-address-lookup-table-program = { path = "programs/address-lookup-table", version = "=1.17.0" } solana-banks-client = { path = "banks-client", version = "=1.17.0" } diff --git a/ledger-tool/src/program.rs b/ledger-tool/src/program.rs index fc87881d3b..4248203506 100644 --- a/ledger-tool/src/program.rs +++ b/ledger-tool/src/program.rs @@ -579,17 +579,17 @@ pub fn program(ledger_path: &Path, matches: &ArgMatches<'_>) { if matches.value_of("mode").unwrap() == "debugger" { vm.debug_port = Some(matches.value_of("port").unwrap().parse::().unwrap()); } - let (instruction_count, result) = vm.execute_program(interpreted); + let (instruction_count, result) = vm.execute_program(&verified_executable, interpreted); let duration = Instant::now() - start_time; if matches.occurrences_of("trace") > 0 { // top level trace is stored in syscall_context - if let Some(Some(syscall_context)) = vm.env.context_object_pointer.syscall_context.last() { + if let Some(Some(syscall_context)) = vm.context_object_pointer.syscall_context.last() { let trace = syscall_context.trace_log.as_slice(); output_trace(matches, trace, 0, &mut analysis); } // the remaining traces are saved in InvokeContext when // corresponding syscall_contexts are popped - let traces = vm.env.context_object_pointer.get_traces(); + let traces = vm.context_object_pointer.get_traces(); for (frame, trace) in traces.iter().filter(|t| !t.is_empty()).enumerate() { output_trace(matches, trace, frame + 1, &mut analysis); } diff --git a/program-runtime/src/invoke_context.rs b/program-runtime/src/invoke_context.rs index 7a767e1b9e..c09fc1cb37 100644 --- a/program-runtime/src/invoke_context.rs +++ b/program-runtime/src/invoke_context.rs @@ -13,6 +13,7 @@ use { solana_measure::measure::Measure, solana_rbpf::{ ebpf::MM_HEAP_START, + elf::SBPFVersion, memory_region::MemoryMapping, vm::{BuiltinFunction, Config, ContextObject, ProgramResult}, }, @@ -744,7 +745,8 @@ impl<'a> InvokeContext<'a> { stable_log::program_invoke(&logger, &program_id, self.get_stack_height()); let pre_remaining_units = self.get_remaining(); let mock_config = Config::default(); - let mut mock_memory_mapping = MemoryMapping::new(Vec::new(), &mock_config).unwrap(); + let mut mock_memory_mapping = + MemoryMapping::new(Vec::new(), &mock_config, &SBPFVersion::V2).unwrap(); let mut result = ProgramResult::Ok(0); process_instruction( // Removes lifetime tracking diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 602602b051..1c0cfea02d 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -275,7 +275,7 @@ pub fn create_vm<'a, 'b>( invoke_context: &'a mut InvokeContext<'b>, stack: &mut AlignedMemory, heap: &mut AlignedMemory, -) -> Result>, Box> { +) -> Result>, Box> { let stack_size = stack.len(); let heap_size = heap.len(); let accounts = Arc::clone(invoke_context.transaction_context.accounts()); @@ -309,7 +309,8 @@ pub fn create_vm<'a, 'b>( trace_log: Vec::new(), })?; Ok(EbpfVm::new( - program, + program.get_config(), + program.get_sbpf_version(), invoke_context, memory_mapping, stack_size, @@ -370,7 +371,10 @@ macro_rules! mock_create_vm { solana_rbpf::verifier::TautologyVerifier, InvokeContext, >::from_text_bytes( - &[0x95, 0, 0, 0, 0, 0, 0, 0], loader, function_registry + &[0x95, 0, 0, 0, 0, 0, 0, 0], + loader, + SBPFVersion::V2, + function_registry, ) .unwrap(); let verified_executable = solana_rbpf::elf::Executable::verified(executable).unwrap(); @@ -392,12 +396,13 @@ fn create_memory_mapping<'a, 'b, C: ContextObject>( cow_cb: Option, ) -> Result, Box> { let config = executable.get_config(); + let sbpf_version = executable.get_sbpf_version(); let regions: Vec = vec![ executable.get_ro_region(), MemoryRegion::new_writable_gapped( stack.as_slice_mut(), ebpf::MM_STACK_START, - if !config.dynamic_stack_frames && config.enable_stack_frame_gaps { + if !sbpf_version.dynamic_stack_frames() && config.enable_stack_frame_gaps { config.stack_frame_size as u64 } else { 0 @@ -410,9 +415,9 @@ fn create_memory_mapping<'a, 'b, C: ContextObject>( .collect(); Ok(if let Some(cow_cb) = cow_cb { - MemoryMapping::new_with_cow(regions, cow_cb, config)? + MemoryMapping::new_with_cow(regions, cow_cb, config, sbpf_version)? } else { - MemoryMapping::new(regions, config)? + MemoryMapping::new(regions, config, sbpf_version)? }) } @@ -1544,6 +1549,11 @@ fn execute<'a, 'b: 'a>( executable: &'a Executable>, invoke_context: &'a mut InvokeContext<'b>, ) -> Result<(), Box> { + // We dropped the lifetime tracking in the Executor by setting it to 'static, + // thus we need to reintroduce the correct lifetime of InvokeContext here again. + let executable = unsafe { + mem::transmute::<_, &'a Executable>>(executable) + }; let log_collector = invoke_context.get_log_collector(); let transaction_context = &invoke_context.transaction_context; let instruction_context = transaction_context.get_current_instruction_context()?; @@ -1580,19 +1590,7 @@ fn execute<'a, 'b: 'a>( let mut execute_time; let execution_result = { let compute_meter_prev = invoke_context.get_remaining(); - create_vm!( - vm, - // We dropped the lifetime tracking in the Executor by setting it to 'static, - // thus we need to reintroduce the correct lifetime of InvokeContext here again. - unsafe { - mem::transmute::<_, &'a Executable>>( - executable, - ) - }, - regions, - account_lengths, - invoke_context, - ); + create_vm!(vm, executable, regions, account_lengths, invoke_context,); let mut vm = match vm { Ok(info) => info, Err(e) => { @@ -1603,7 +1601,7 @@ fn execute<'a, 'b: 'a>( create_vm_time.stop(); execute_time = Measure::start("execute"); - let (compute_units_consumed, result) = vm.execute_program(!use_jit); + let (compute_units_consumed, result) = vm.execute_program(executable, !use_jit); drop(vm); ic_logger_msg!( log_collector, @@ -1761,6 +1759,7 @@ mod tests { invoke_context::mock_process_instruction, with_mock_invoke_context, }, solana_rbpf::{ + elf::SBPFVersion, verifier::Verifier, vm::{Config, ContextObject, FunctionRegistry}, }, @@ -1833,7 +1832,13 @@ mod tests { let prog = &[ 0x18, 0x00, 0x00, 0x00, 0x88, 0x77, 0x66, 0x55, // first half of lddw ]; - RequisiteVerifier::verify(prog, &Config::default(), &FunctionRegistry::default()).unwrap(); + RequisiteVerifier::verify( + prog, + &Config::default(), + &SBPFVersion::V2, + &FunctionRegistry::default(), + ) + .unwrap(); } #[test] diff --git a/programs/bpf_loader/src/syscalls/cpi.rs b/programs/bpf_loader/src/syscalls/cpi.rs index a53629e0a7..204dfc541d 100644 --- a/programs/bpf_loader/src/syscalls/cpi.rs +++ b/programs/bpf_loader/src/syscalls/cpi.rs @@ -1267,7 +1267,9 @@ mod tests { super::*, crate::mock_create_vm, solana_program_runtime::with_mock_invoke_context, - solana_rbpf::{ebpf::MM_INPUT_START, memory_region::MemoryRegion, vm::Config}, + solana_rbpf::{ + ebpf::MM_INPUT_START, elf::SBPFVersion, memory_region::MemoryRegion, vm::Config, + }, solana_sdk::{ account::{Account, AccountSharedData}, clock::Epoch, @@ -1366,7 +1368,8 @@ mod tests { aligned_memory_mapping: false, ..Config::default() }; - let mut memory_mapping = MemoryMapping::new(vec![region], &config).unwrap(); + let mut memory_mapping = + MemoryMapping::new(vec![region], &config, &SBPFVersion::V2).unwrap(); let ins = SyscallInvokeSignedRust::translate_instruction( vm_addr, @@ -1402,7 +1405,8 @@ mod tests { aligned_memory_mapping: false, ..Config::default() }; - let mut memory_mapping = MemoryMapping::new(vec![region], &config).unwrap(); + let mut memory_mapping = + MemoryMapping::new(vec![region], &config, &SBPFVersion::V2).unwrap(); let signers = SyscallInvokeSignedRust::translate_signers( &program_id, @@ -1437,7 +1441,7 @@ mod tests { aligned_memory_mapping: false, ..Config::default() }; - let memory_mapping = MemoryMapping::new(vec![region], &config).unwrap(); + let memory_mapping = MemoryMapping::new(vec![region], &config, &SBPFVersion::V2).unwrap(); let account_info = translate_type::(&memory_mapping, vm_addr, false).unwrap(); @@ -1487,8 +1491,12 @@ mod tests { aligned_memory_mapping: false, ..Config::default() }; - let mut memory_mapping = - MemoryMapping::new(mock_caller_account.regions.split_off(0), &config).unwrap(); + let mut memory_mapping = MemoryMapping::new( + mock_caller_account.regions.split_off(0), + &config, + &SBPFVersion::V2, + ) + .unwrap(); let mut caller_account = mock_caller_account.caller_account(); @@ -1541,8 +1549,12 @@ mod tests { aligned_memory_mapping: false, ..Config::default() }; - let mut memory_mapping = - MemoryMapping::new(mock_caller_account.regions.split_off(0), &config).unwrap(); + let mut memory_mapping = MemoryMapping::new( + mock_caller_account.regions.split_off(0), + &config, + &SBPFVersion::V2, + ) + .unwrap(); let data_slice = mock_caller_account.data_slice(); let len_ptr = unsafe { @@ -1662,8 +1674,12 @@ mod tests { aligned_memory_mapping: false, ..Config::default() }; - let mut memory_mapping = - MemoryMapping::new(mock_caller_account.regions.split_off(0), &config).unwrap(); + let mut memory_mapping = MemoryMapping::new( + mock_caller_account.regions.split_off(0), + &config, + &SBPFVersion::V2, + ) + .unwrap(); let data_slice = mock_caller_account.data_slice(); let len_ptr = unsafe { @@ -1829,8 +1845,12 @@ mod tests { aligned_memory_mapping: false, ..Config::default() }; - let mut memory_mapping = - MemoryMapping::new(mock_caller_account.regions.split_off(0), &config).unwrap(); + let mut memory_mapping = MemoryMapping::new( + mock_caller_account.regions.split_off(0), + &config, + &SBPFVersion::V2, + ) + .unwrap(); let mut caller_account = mock_caller_account.caller_account(); @@ -2148,7 +2168,8 @@ mod tests { aligned_memory_mapping: false, ..Config::default() }; - let mut memory_mapping = MemoryMapping::new(vec![region], &config).unwrap(); + let mut memory_mapping = + MemoryMapping::new(vec![region], &config, &SBPFVersion::V2).unwrap(); let accounts = SyscallInvokeSignedRust::translate_accounts( &[ diff --git a/programs/bpf_loader/src/syscalls/mem_ops.rs b/programs/bpf_loader/src/syscalls/mem_ops.rs index 2ecd9a9ad4..d5601edacf 100644 --- a/programs/bpf_loader/src/syscalls/mem_ops.rs +++ b/programs/bpf_loader/src/syscalls/mem_ops.rs @@ -491,7 +491,10 @@ impl<'a> DoubleEndedIterator for MemoryChunkIterator<'a> { #[cfg(test)] #[allow(clippy::indexing_slicing)] mod tests { - use {super::*, solana_rbpf::ebpf::MM_PROGRAM_START}; + use { + super::*, + solana_rbpf::{ebpf::MM_PROGRAM_START, elf::SBPFVersion}, + }; fn to_chunk_vec<'a>( iter: impl Iterator>, @@ -507,7 +510,7 @@ mod tests { aligned_memory_mapping: false, ..Config::default() }; - let memory_mapping = MemoryMapping::new(vec![], &config).unwrap(); + let memory_mapping = MemoryMapping::new(vec![], &config, &SBPFVersion::V2).unwrap(); let mut src_chunk_iter = MemoryChunkIterator::new(&memory_mapping, AccessType::Load, 0, 1).unwrap(); @@ -521,7 +524,7 @@ mod tests { aligned_memory_mapping: false, ..Config::default() }; - let memory_mapping = MemoryMapping::new(vec![], &config).unwrap(); + let memory_mapping = MemoryMapping::new(vec![], &config, &SBPFVersion::V2).unwrap(); let mut src_chunk_iter = MemoryChunkIterator::new(&memory_mapping, AccessType::Load, u64::MAX, 1).unwrap(); @@ -538,6 +541,7 @@ mod tests { let memory_mapping = MemoryMapping::new( vec![MemoryRegion::new_readonly(&mem1, MM_PROGRAM_START)], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -593,6 +597,7 @@ mod tests { let memory_mapping = MemoryMapping::new( vec![MemoryRegion::new_readonly(&mem1, MM_PROGRAM_START)], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -647,6 +652,7 @@ mod tests { MemoryRegion::new_readonly(&mem2, MM_PROGRAM_START + 8), ], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -689,6 +695,7 @@ mod tests { MemoryRegion::new_readonly(&mem2, MM_PROGRAM_START + 8), ], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -738,6 +745,7 @@ mod tests { MemoryRegion::new_readonly(&mem2, MM_PROGRAM_START + 8), ], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -762,6 +770,7 @@ mod tests { MemoryRegion::new_writable(&mut mem4, MM_PROGRAM_START + 6), ], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -795,6 +804,7 @@ mod tests { MemoryRegion::new_writable(&mut mem4, MM_PROGRAM_START + 6), ], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -825,6 +835,7 @@ mod tests { MemoryRegion::new_readonly(&mem2, MM_PROGRAM_START + 8), ], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -852,6 +863,7 @@ mod tests { MemoryRegion::new_writable(&mut mem4, MM_PROGRAM_START + 6), ], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -881,6 +893,7 @@ mod tests { MemoryRegion::new_readonly(&mem3, MM_PROGRAM_START + 9), ], &config, + &SBPFVersion::V2, ) .unwrap(); diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index 1033fb8cf7..1a4aea1564 100644 --- a/programs/bpf_loader/src/syscalls/mod.rs +++ b/programs/bpf_loader/src/syscalls/mod.rs @@ -148,6 +148,17 @@ pub fn create_program_runtime_environment<'a>( reject_deployment_of_broken_elfs: bool, debugging_features: bool, ) -> Result>, Error> { + let enable_alt_bn128_syscall = feature_set.is_active(&enable_alt_bn128_syscall::id()); + let enable_big_mod_exp_syscall = feature_set.is_active(&enable_big_mod_exp_syscall::id()); + let blake3_syscall_enabled = feature_set.is_active(&blake3_syscall_enabled::id()); + let curve25519_syscall_enabled = feature_set.is_active(&curve25519_syscall_enabled::id()); + let disable_fees_sysvar = feature_set.is_active(&disable_fees_sysvar::id()); + let epoch_rewards_syscall_enabled = + feature_set.is_active(&enable_partitioned_epoch_reward::id()); + let disable_deploy_of_alloc_free_syscall = reject_deployment_of_broken_elfs + && feature_set.is_active(&disable_deploy_of_alloc_free_syscall::id()); + let last_restart_slot_syscall_enabled = feature_set.is_active(&last_restart_slot_sysvar::id()); + use rand::Rng; // When adding new features for RBPF, // also add them to `Bank::apply_builtin_program_feature_transitions()`. @@ -170,28 +181,13 @@ pub fn create_program_runtime_environment<'a>( external_internal_function_hash_collision: feature_set .is_active(&error_on_syscall_bpf_function_hash_collisions::id()), reject_callx_r10: feature_set.is_active(&reject_callx_r10::id()), - dynamic_stack_frames: false, - enable_sdiv: false, + enable_sbpf_v1: true, + enable_sbpf_v2: false, optimize_rodata: false, - static_syscalls: false, - enable_elf_vaddr: false, - reject_rodata_stack_overlap: false, new_elf_parser: feature_set.is_active(&switch_to_new_elf_parser::id()), aligned_memory_mapping: !feature_set.is_active(&bpf_account_data_direct_mapping::id()), // Warning, do not use `Config::default()` so that configuration here is explicit. }; - - let enable_alt_bn128_syscall = feature_set.is_active(&enable_alt_bn128_syscall::id()); - let enable_big_mod_exp_syscall = feature_set.is_active(&enable_big_mod_exp_syscall::id()); - let blake3_syscall_enabled = feature_set.is_active(&blake3_syscall_enabled::id()); - let curve25519_syscall_enabled = feature_set.is_active(&curve25519_syscall_enabled::id()); - let disable_fees_sysvar = feature_set.is_active(&disable_fees_sysvar::id()); - let epoch_rewards_syscall_enabled = - feature_set.is_active(&enable_partitioned_epoch_reward::id()); - let disable_deploy_of_alloc_free_syscall = reject_deployment_of_broken_elfs - && feature_set.is_active(&disable_deploy_of_alloc_free_syscall::id()); - let last_restart_slot_syscall_enabled = feature_set.is_active(&last_restart_slot_sysvar::id()); - let mut result = BuiltinProgram::new_loader(config); // Abort @@ -1804,6 +1800,7 @@ mod tests { core::slice, solana_program_runtime::{invoke_context::InvokeContext, with_mock_invoke_context}, solana_rbpf::{ + elf::SBPFVersion, error::EbpfError, memory_region::MemoryRegion, vm::{BuiltinFunction, Config}, @@ -1870,8 +1867,12 @@ mod tests { let data = vec![0u8; LENGTH as usize]; let addr = data.as_ptr() as u64; let config = Config::default(); - let memory_mapping = - MemoryMapping::new(vec![MemoryRegion::new_readonly(&data, START)], &config).unwrap(); + let memory_mapping = MemoryMapping::new( + vec![MemoryRegion::new_readonly(&data, START)], + &config, + &SBPFVersion::V2, + ) + .unwrap(); let cases = vec![ (true, START, 0, addr), @@ -1910,6 +1911,7 @@ mod tests { let memory_mapping = MemoryMapping::new( vec![MemoryRegion::new_readonly(bytes_of(&pubkey), 0x100000000)], &config, + &SBPFVersion::V2, ) .unwrap(); let translated_pubkey = @@ -1924,13 +1926,15 @@ mod tests { ); let instruction = StableInstruction::from(instruction); let memory_region = MemoryRegion::new_readonly(bytes_of(&instruction), 0x100000000); - let memory_mapping = MemoryMapping::new(vec![memory_region], &config).unwrap(); + let memory_mapping = + MemoryMapping::new(vec![memory_region], &config, &SBPFVersion::V2).unwrap(); let translated_instruction = translate_type::(&memory_mapping, 0x100000000, true).unwrap(); assert_eq!(instruction, *translated_instruction); let memory_region = MemoryRegion::new_readonly(&bytes_of(&instruction)[..1], 0x100000000); - let memory_mapping = MemoryMapping::new(vec![memory_region], &config).unwrap(); + let memory_mapping = + MemoryMapping::new(vec![memory_region], &config, &SBPFVersion::V2).unwrap(); assert!(translate_type::(&memory_mapping, 0x100000000, true).is_err()); } @@ -1945,6 +1949,7 @@ mod tests { let memory_mapping = MemoryMapping::new( vec![MemoryRegion::new_readonly(&good_data, 0x100000000)], &config, + &SBPFVersion::V2, ) .unwrap(); let translated_data = @@ -1957,6 +1962,7 @@ mod tests { let memory_mapping = MemoryMapping::new( vec![MemoryRegion::new_readonly(&data, 0x100000000)], &config, + &SBPFVersion::V2, ) .unwrap(); let translated_data = @@ -1987,6 +1993,7 @@ mod tests { 0x100000000, )], &config, + &SBPFVersion::V2, ) .unwrap(); let translated_data = @@ -2009,6 +2016,7 @@ mod tests { 0x100000000, )], &config, + &SBPFVersion::V2, ) .unwrap(); let translated_data = @@ -2026,6 +2034,7 @@ mod tests { let memory_mapping = MemoryMapping::new( vec![MemoryRegion::new_readonly(string.as_bytes(), 0x100000000)], &config, + &SBPFVersion::V2, ) .unwrap(); assert_eq!( @@ -2051,7 +2060,7 @@ mod tests { fn test_syscall_abort() { prepare_mockup!(invoke_context, program_id, bpf_loader::id()); let config = Config::default(); - let mut memory_mapping = MemoryMapping::new(vec![], &config).unwrap(); + let mut memory_mapping = MemoryMapping::new(vec![], &config, &SBPFVersion::V2).unwrap(); let mut result = ProgramResult::Ok(0); SyscallAbort::call( &mut invoke_context, @@ -2076,6 +2085,7 @@ mod tests { let mut memory_mapping = MemoryMapping::new( vec![MemoryRegion::new_readonly(string.as_bytes(), 0x100000000)], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -2120,6 +2130,7 @@ mod tests { let mut memory_mapping = MemoryMapping::new( vec![MemoryRegion::new_readonly(string.as_bytes(), 0x100000000)], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -2194,7 +2205,7 @@ mod tests { invoke_context.mock_set_remaining(cost); let config = Config::default(); - let mut memory_mapping = MemoryMapping::new(vec![], &config).unwrap(); + let mut memory_mapping = MemoryMapping::new(vec![], &config, &SBPFVersion::V2).unwrap(); let mut result = ProgramResult::Ok(0); SyscallLogU64::call( &mut invoke_context, @@ -2228,6 +2239,7 @@ mod tests { let mut memory_mapping = MemoryMapping::new( vec![MemoryRegion::new_readonly(bytes_of(&pubkey), 0x100000000)], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -2292,8 +2304,8 @@ mod tests { prepare_mockup!(invoke_context, program_id, bpf_loader::id()); mock_create_vm!(vm, Vec::new(), Vec::new(), &mut invoke_context); let mut vm = vm.unwrap(); - let invoke_context = &mut vm.env.context_object_pointer; - let memory_mapping = &mut vm.env.memory_mapping; + let invoke_context = &mut vm.context_object_pointer; + let memory_mapping = &mut vm.memory_mapping; let mut result = ProgramResult::Ok(0); SyscallAllocFree::call( invoke_context, @@ -2338,8 +2350,8 @@ mod tests { invoke_context.feature_set = Arc::new(FeatureSet::default()); mock_create_vm!(vm, Vec::new(), Vec::new(), &mut invoke_context); let mut vm = vm.unwrap(); - let invoke_context = &mut vm.env.context_object_pointer; - let memory_mapping = &mut vm.env.memory_mapping; + let invoke_context = &mut vm.context_object_pointer; + let memory_mapping = &mut vm.memory_mapping; for _ in 0..100 { let mut result = ProgramResult::Ok(0); SyscallAllocFree::call(invoke_context, 1, 0, 0, 0, 0, memory_mapping, &mut result); @@ -2364,8 +2376,8 @@ mod tests { prepare_mockup!(invoke_context, program_id, bpf_loader::id()); mock_create_vm!(vm, Vec::new(), Vec::new(), &mut invoke_context); let mut vm = vm.unwrap(); - let invoke_context = &mut vm.env.context_object_pointer; - let memory_mapping = &mut vm.env.memory_mapping; + let invoke_context = &mut vm.context_object_pointer; + let memory_mapping = &mut vm.memory_mapping; for _ in 0..12 { let mut result = ProgramResult::Ok(0); SyscallAllocFree::call(invoke_context, 1, 0, 0, 0, 0, memory_mapping, &mut result); @@ -2391,8 +2403,8 @@ mod tests { prepare_mockup!(invoke_context, program_id, bpf_loader::id()); mock_create_vm!(vm, Vec::new(), Vec::new(), &mut invoke_context); let mut vm = vm.unwrap(); - let invoke_context = &mut vm.env.context_object_pointer; - let memory_mapping = &mut vm.env.memory_mapping; + let invoke_context = &mut vm.context_object_pointer; + let memory_mapping = &mut vm.memory_mapping; let mut result = ProgramResult::Ok(0); SyscallAllocFree::call( invoke_context, @@ -2447,6 +2459,7 @@ mod tests { MemoryRegion::new_readonly(bytes2.as_bytes(), bytes_to_hash[1].vm_addr), ], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -2554,6 +2567,7 @@ mod tests { MemoryRegion::new_readonly(&invalid_bytes, invalid_bytes_va), ], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -2632,6 +2646,7 @@ mod tests { MemoryRegion::new_readonly(&invalid_bytes, invalid_bytes_va), ], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -2726,6 +2741,7 @@ mod tests { MemoryRegion::new_writable(bytes_of_slice_mut(&mut result_point), result_point_va), ], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -2896,6 +2912,7 @@ mod tests { MemoryRegion::new_writable(bytes_of_slice_mut(&mut result_point), result_point_va), ], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -3081,6 +3098,7 @@ mod tests { MemoryRegion::new_writable(bytes_of_slice_mut(&mut result_point), result_point_va), ], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -3235,6 +3253,7 @@ mod tests { got_clock_va, )], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -3272,6 +3291,7 @@ mod tests { got_epochschedule_va, )], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -3310,6 +3330,7 @@ mod tests { got_fees_va, )], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -3343,6 +3364,7 @@ mod tests { got_rent_va, )], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -3378,6 +3400,7 @@ mod tests { got_rewards_va, )], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -3440,7 +3463,7 @@ mod tests { bytes_of_slice(&mock_slices), SEEDS_VA, )); - let mut memory_mapping = MemoryMapping::new(regions, &config).unwrap(); + let mut memory_mapping = MemoryMapping::new(regions, &config, &SBPFVersion::V2).unwrap(); let mut result = ProgramResult::Ok(0); syscall( @@ -3506,6 +3529,7 @@ mod tests { MemoryRegion::new_writable(&mut id_buffer, PROGRAM_ID_VA), ], &config, + &SBPFVersion::V2, ) .unwrap(); @@ -3611,6 +3635,7 @@ mod tests { let mut memory_mapping = MemoryMapping::new( vec![MemoryRegion::new_writable(&mut memory, VM_BASE_ADDRESS)], &config, + &SBPFVersion::V2, ) .unwrap(); let processed_sibling_instruction = translate_type_mut::( diff --git a/programs/loader-v4/src/lib.rs b/programs/loader-v4/src/lib.rs index 94ac70a180..1f2d74d1cb 100644 --- a/programs/loader-v4/src/lib.rs +++ b/programs/loader-v4/src/lib.rs @@ -97,12 +97,9 @@ pub fn load_program_from_account( .unwrap_or(0), external_internal_function_hash_collision: true, reject_callx_r10: true, - dynamic_stack_frames: true, - enable_sdiv: true, + enable_sbpf_v1: false, + enable_sbpf_v2: true, optimize_rodata: true, - static_syscalls: true, - enable_elf_vaddr: true, - reject_rodata_stack_overlap: true, new_elf_parser: true, aligned_memory_mapping: true, // Warning, do not use `Config::default()` so that configuration here is explicit. @@ -144,8 +141,9 @@ fn calculate_heap_cost(heap_size: u64, heap_cost: u64) -> u64 { pub fn create_vm<'a, 'b>( invoke_context: &'a mut InvokeContext<'b>, program: &'a Executable>, -) -> Result>, Box> { +) -> Result>, Box> { let config = program.get_config(); + let sbpf_version = program.get_sbpf_version(); let compute_budget = invoke_context.get_compute_budget(); let heap_size = compute_budget.heap_size.unwrap_or(HEAP_LENGTH); invoke_context.consume_checked(calculate_heap_cost( @@ -163,22 +161,28 @@ pub fn create_vm<'a, 'b>( MemoryRegion::new_writable(heap.as_slice_mut(), ebpf::MM_HEAP_START), ]; let log_collector = invoke_context.get_log_collector(); - let memory_mapping = MemoryMapping::new(regions, config).map_err(|err| { + let memory_mapping = MemoryMapping::new(regions, config, sbpf_version).map_err(|err| { ic_logger_msg!(log_collector, "Failed to create SBF VM: {}", err); Box::new(InstructionError::ProgramEnvironmentSetupFailure) })?; Ok(EbpfVm::new( - program, + config, + sbpf_version, invoke_context, memory_mapping, stack_len, )) } -fn execute( - invoke_context: &mut InvokeContext, - program: &Executable>, +fn execute<'a, 'b: 'a>( + invoke_context: &'a mut InvokeContext<'b>, + executable: &'a Executable>, ) -> Result<(), Box> { + // We dropped the lifetime tracking in the Executor by setting it to 'static, + // thus we need to reintroduce the correct lifetime of InvokeContext here again. + let executable = unsafe { + std::mem::transmute::<_, &'a Executable>>(executable) + }; let log_collector = invoke_context.get_log_collector(); let stack_height = invoke_context.get_stack_height(); let transaction_context = &invoke_context.transaction_context; @@ -187,21 +191,16 @@ fn execute( #[cfg(any(target_os = "windows", not(target_arch = "x86_64")))] let use_jit = false; #[cfg(all(not(target_os = "windows"), target_arch = "x86_64"))] - let use_jit = program.get_compiled_program().is_some(); + let use_jit = executable.get_compiled_program().is_some(); let compute_meter_prev = invoke_context.get_remaining(); let mut create_vm_time = Measure::start("create_vm"); - let mut vm = create_vm( - invoke_context, - // We dropped the lifetime tracking in the Executor by setting it to 'static, - // thus we need to reintroduce the correct lifetime of InvokeContext here again. - unsafe { std::mem::transmute(program) }, - )?; + let mut vm = create_vm(invoke_context, executable)?; create_vm_time.stop(); let mut execute_time = Measure::start("execute"); stable_log::program_invoke(&log_collector, &program_id, stack_height); - let (compute_units_consumed, result) = vm.execute_program(!use_jit); + let (compute_units_consumed, result) = vm.execute_program(executable, !use_jit); drop(vm); ic_logger_msg!( log_collector, diff --git a/programs/sbf/Cargo.lock b/programs/sbf/Cargo.lock index 861425b116..560a2c95c2 100644 --- a/programs/sbf/Cargo.lock +++ b/programs/sbf/Cargo.lock @@ -6355,9 +6355,9 @@ dependencies = [ [[package]] name = "solana_rbpf" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ae90c406f0a2d4a15f08d16c8b64f37997a57611fec0a89f1277854166996e8" +checksum = "b3082ec3a1d4ef7879eb5b84916d5acde057abd59733eec3647e0ab8885283ef" dependencies = [ "byteorder 1.4.3", "combine", diff --git a/programs/sbf/Cargo.toml b/programs/sbf/Cargo.toml index 3821e7d6cb..6e584924fb 100644 --- a/programs/sbf/Cargo.toml +++ b/programs/sbf/Cargo.toml @@ -24,7 +24,7 @@ num-traits = "0.2" rand = "0.7" serde = "1.0.112" serde_json = "1.0.56" -solana_rbpf = "=0.5.0" +solana_rbpf = "=0.6.0" solana-account-decoder = { path = "../../account-decoder", version = "=1.17.0" } solana-address-lookup-table-program = { path = "../../programs/address-lookup-table", version = "=1.17.0" } solana-bpf-loader-program = { path = "../bpf_loader", version = "=1.17.0" } diff --git a/programs/sbf/benches/bpf_loader.rs b/programs/sbf/benches/bpf_loader.rs index c37082eb0f..c72dcd68b9 100644 --- a/programs/sbf/benches/bpf_loader.rs +++ b/programs/sbf/benches/bpf_loader.rs @@ -144,10 +144,9 @@ fn bench_program_alu(bencher: &mut Bencher) { let mut vm = vm.unwrap(); println!("Interpreted:"); - vm.env - .context_object_pointer + vm.context_object_pointer .mock_set_remaining(std::i64::MAX as u64); - let (instructions, result) = vm.execute_program(true); + let (instructions, result) = vm.execute_program(&verified_executable, true); assert_eq!(SUCCESS, result.unwrap()); assert_eq!(ARMSTRONG_LIMIT, LittleEndian::read_u64(&inner_iter)); assert_eq!( @@ -156,10 +155,9 @@ fn bench_program_alu(bencher: &mut Bencher) { ); bencher.iter(|| { - vm.env - .context_object_pointer + vm.context_object_pointer .mock_set_remaining(std::i64::MAX as u64); - vm.execute_program(true).1.unwrap(); + vm.execute_program(&verified_executable, true).1.unwrap(); }); let summary = bencher.bench(|_bencher| Ok(())).unwrap().unwrap(); println!(" {:?} instructions", instructions); @@ -170,7 +168,10 @@ fn bench_program_alu(bencher: &mut Bencher) { println!("{{ \"type\": \"bench\", \"name\": \"bench_program_alu_interpreted_mips\", \"median\": {:?}, \"deviation\": 0 }}", mips); println!("JIT to native:"); - assert_eq!(SUCCESS, vm.execute_program(false).1.unwrap()); + assert_eq!( + SUCCESS, + vm.execute_program(&verified_executable, false).1.unwrap() + ); assert_eq!(ARMSTRONG_LIMIT, LittleEndian::read_u64(&inner_iter)); assert_eq!( ARMSTRONG_EXPECTED, @@ -178,10 +179,9 @@ fn bench_program_alu(bencher: &mut Bencher) { ); bencher.iter(|| { - vm.env - .context_object_pointer + vm.context_object_pointer .mock_set_remaining(std::i64::MAX as u64); - vm.execute_program(false).1.unwrap(); + vm.execute_program(&verified_executable, false).1.unwrap(); }); let summary = bencher.bench(|_bencher| Ok(())).unwrap().unwrap(); println!(" {:?} instructions", instructions); @@ -324,17 +324,17 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) { let mut vm = vm.unwrap(); let mut measure = Measure::start("tune"); - let (instructions, _result) = vm.execute_program(true); + let (instructions, _result) = vm.execute_program(&verified_executable, true); measure.stop(); assert_eq!( 0, - vm.env.context_object_pointer.get_remaining(), + vm.context_object_pointer.get_remaining(), "Tuner must consume the whole budget" ); println!( "{:?} compute units took {:?} us ({:?} instructions)", - BUDGET - vm.env.context_object_pointer.get_remaining(), + BUDGET - vm.context_object_pointer.get_remaining(), measure.as_us(), instructions, );