diff --git a/program-runtime/src/invoke_context.rs b/program-runtime/src/invoke_context.rs index 7ee931b138..addcaaf031 100644 --- a/program-runtime/src/invoke_context.rs +++ b/program-runtime/src/invoke_context.rs @@ -92,19 +92,25 @@ impl ComputeMeter { pub fn get_remaining(&self) -> u64 { self.remaining } + /// Set compute units + /// + /// Only use for tests and benchmarks + pub fn mock_set_remaining(&mut self, remaining: u64) { + self.remaining = remaining; + } /// Construct a new one with the given remaining units pub fn new_ref(remaining: u64) -> Rc> { Rc::new(RefCell::new(Self { remaining })) } } -pub struct InvokeContextStackFrame<'a> { +pub struct StackFrame<'a> { pub number_of_program_accounts: usize, pub keyed_accounts: Vec>, pub keyed_accounts_range: std::ops::Range, } -impl<'a> InvokeContextStackFrame<'a> { +impl<'a> StackFrame<'a> { pub fn new(number_of_program_accounts: usize, keyed_accounts: Vec>) -> Self { let keyed_accounts_range = std::ops::Range { start: 0, @@ -126,7 +132,7 @@ impl<'a> InvokeContextStackFrame<'a> { pub struct ThisInvokeContext<'a> { instruction_index: usize, - invoke_stack: Vec>, + invoke_stack: Vec>, rent: Rent, pre_accounts: Vec, accounts: &'a [(Pubkey, Rc>)], @@ -193,7 +199,7 @@ impl<'a> ThisInvokeContext<'a> { accounts, builtin_programs, sysvars, - None, + Some(LogCollector::new_ref()), ComputeBudget::default(), ComputeMeter::new_ref(std::i64::MAX as u64), Rc::new(RefCell::new(Executors::default())), @@ -269,6 +275,8 @@ pub trait InvokeContext { fn process_instruction(&mut self, instruction_data: &[u8]) -> Result<(), InstructionError>; /// Get the program ID of the currently executing program fn get_caller(&self) -> Result<&Pubkey, InstructionError>; + /// Get the owner of the currently executing program + fn get_loader(&self) -> Result; /// Removes the first keyed account #[deprecated( since = "1.9.0", @@ -416,7 +424,7 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> { })) .collect::>(); - self.invoke_stack.push(InvokeContextStackFrame::new( + self.invoke_stack.push(StackFrame::new( program_indices.len(), create_keyed_accounts_unified(keyed_accounts.as_slice()), )); @@ -800,6 +808,11 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> { .and_then(|frame| frame.program_id()) .ok_or(InstructionError::CallDepth) } + fn get_loader(&self) -> Result { + self.get_instruction_keyed_accounts() + .and_then(|keyed_accounts| keyed_accounts.first().ok_or(InstructionError::CallDepth)) + .and_then(|keyed_account| keyed_account.owner()) + } fn remove_first_keyed_account(&mut self) -> Result<(), InstructionError> { if !self.is_feature_active(&remove_native_loader::id()) { let stack_frame = &mut self diff --git a/program-runtime/src/log_collector.rs b/program-runtime/src/log_collector.rs index f5eaea48e1..0618291db2 100644 --- a/program-runtime/src/log_collector.rs +++ b/program-runtime/src/log_collector.rs @@ -24,6 +24,10 @@ impl LogCollector { } } + pub fn get_recorded_content(&self) -> &[String] { + self.messages.as_slice() + } + pub fn new_ref() -> Rc> { Rc::new(RefCell::new(Self::default())) } diff --git a/programs/bpf/benches/bpf_loader.rs b/programs/bpf/benches/bpf_loader.rs index c1c52efec6..abc1f24b18 100644 --- a/programs/bpf/benches/bpf_loader.rs +++ b/programs/bpf/benches/bpf_loader.rs @@ -12,7 +12,10 @@ use solana_bpf_loader_program::{ }; use solana_measure::measure::Measure; use solana_program_runtime::invoke_context::{with_mock_invoke_context, InvokeContext}; -use solana_rbpf::{elf::Executable, vm::{Config, InstructionMeter, SyscallRegistry}}; +use solana_rbpf::{ + elf::Executable, + vm::{Config, InstructionMeter, SyscallRegistry}, +}; use solana_runtime::{ bank::Bank, bank_client::BankClient, @@ -107,7 +110,6 @@ fn bench_program_alu(bencher: &mut Bencher) { let compute_meter = invoke_context.get_compute_meter(); let mut instruction_meter = ThisInstructionMeter { compute_meter }; let mut vm = create_vm( - &loader_id, &executable, &mut inner_iter, invoke_context, @@ -203,12 +205,7 @@ fn bench_create_vm(bencher: &mut Bencher) { let loader_id = bpf_loader::id(); with_mock_invoke_context(loader_id, 10000001, |invoke_context| { const BUDGET: u64 = 200_000; - let compute_meter = invoke_context.get_compute_meter(); - { - let mut compute_meter = compute_meter.borrow_mut(); - let to_consume = compute_meter.get_remaining() - BUDGET; - compute_meter.consume(to_consume).unwrap(); - } + invoke_context.get_compute_meter().borrow_mut().mock_set_remaining(BUDGET); // Serialize account data let keyed_accounts = invoke_context.get_keyed_accounts().unwrap(); @@ -230,7 +227,6 @@ fn bench_create_vm(bencher: &mut Bencher) { bencher.iter(|| { let _ = create_vm( - &loader_id, &executable, serialized.as_slice_mut(), invoke_context, @@ -247,12 +243,7 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) { let loader_id = bpf_loader::id(); with_mock_invoke_context(loader_id, 10000001, |invoke_context| { const BUDGET: u64 = 200_000; - let compute_meter = invoke_context.get_compute_meter(); - { - let mut compute_meter = compute_meter.borrow_mut(); - let to_consume = compute_meter.get_remaining() - BUDGET; - compute_meter.consume(to_consume).unwrap(); - } + invoke_context.get_compute_meter().borrow_mut().mock_set_remaining(BUDGET); // Serialize account data let keyed_accounts = invoke_context.get_keyed_accounts().unwrap(); @@ -271,9 +262,9 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) { register_syscalls(invoke_context).unwrap(), ) .unwrap(); + let compute_meter = invoke_context.get_compute_meter(); let mut instruction_meter = ThisInstructionMeter { compute_meter }; let mut vm = create_vm( - &loader_id, &executable, serialized.as_slice_mut(), invoke_context, diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 2603672d5f..78b6d98185 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -227,7 +227,6 @@ fn run_program(name: &str) -> u64 { let mut parameter_bytes = parameter_bytes.clone(); { let mut vm = create_vm( - &loader_id, &executable, parameter_bytes.as_slice_mut(), invoke_context, diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 509160cf44..324e6f0a5e 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -151,7 +151,6 @@ fn check_loader_id(id: &Pubkey) -> bool { /// Create the BPF virtual machine pub fn create_vm<'a>( - loader_id: &'a Pubkey, program: &'a Executable, parameter_bytes: &mut [u8], invoke_context: &'a mut dyn InvokeContext, @@ -168,13 +167,7 @@ pub fn create_vm<'a>( let mut heap = AlignedMemory::new_with_size(compute_budget.heap_size.unwrap_or(HEAP_LENGTH), HOST_ALIGN); let mut vm = EbpfVm::new(program, heap.as_slice_mut(), parameter_bytes)?; - syscalls::bind_syscall_context_objects( - loader_id, - &mut vm, - invoke_context, - heap, - orig_data_lens, - )?; + syscalls::bind_syscall_context_objects(&mut vm, invoke_context, heap, orig_data_lens)?; Ok(vm) } @@ -984,7 +977,6 @@ impl Executor for BpfExecutor { let program_id = &invoke_context.get_caller()?.clone(); let compute_meter = invoke_context.get_compute_meter(); let mut vm = match create_vm( - loader_id, &self.executable, parameter_bytes.as_slice_mut(), invoke_context, diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 3aa5c6326b..b4fa651f71 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -3,7 +3,6 @@ use alloc::Alloc; use solana_program_runtime::{ ic_logger_msg, ic_msg, invoke_context::{ComputeMeter, InvokeContext}, - log_collector::LogCollector, stable_log, }; use solana_rbpf::{ @@ -208,153 +207,14 @@ macro_rules! bind_feature_gated_syscall_context_object { } pub fn bind_syscall_context_objects<'a>( - loader_id: &'a Pubkey, vm: &mut EbpfVm<'a, BpfError, crate::ThisInstructionMeter>, invoke_context: &'a mut dyn InvokeContext, heap: AlignedMemory, orig_data_lens: &'a [usize], ) -> Result<(), EbpfError> { - let compute_budget = invoke_context.get_compute_budget(); - - // Syscall functions common across languages - - vm.bind_syscall_context_object(Box::new(SyscallAbort {}), None)?; - vm.bind_syscall_context_object( - Box::new(SyscallPanic { - compute_meter: invoke_context.get_compute_meter(), - loader_id, - }), - None, - )?; - vm.bind_syscall_context_object( - Box::new(SyscallLog { - compute_meter: invoke_context.get_compute_meter(), - log_collector: invoke_context.get_log_collector(), - loader_id, - }), - None, - )?; - vm.bind_syscall_context_object( - Box::new(SyscallLogU64 { - cost: compute_budget.log_64_units, - compute_meter: invoke_context.get_compute_meter(), - log_collector: invoke_context.get_log_collector(), - }), - None, - )?; - - vm.bind_syscall_context_object( - Box::new(SyscallLogBpfComputeUnits { - cost: 0, - compute_meter: invoke_context.get_compute_meter(), - log_collector: invoke_context.get_log_collector(), - }), - None, - )?; - - vm.bind_syscall_context_object( - Box::new(SyscallLogPubkey { - cost: compute_budget.log_pubkey_units, - compute_meter: invoke_context.get_compute_meter(), - log_collector: invoke_context.get_log_collector(), - loader_id, - }), - None, - )?; - - vm.bind_syscall_context_object( - Box::new(SyscallCreateProgramAddress { - cost: compute_budget.create_program_address_units, - compute_meter: invoke_context.get_compute_meter(), - loader_id, - }), - None, - )?; - vm.bind_syscall_context_object( - Box::new(SyscallTryFindProgramAddress { - cost: compute_budget.create_program_address_units, - compute_meter: invoke_context.get_compute_meter(), - loader_id, - }), - None, - )?; - - vm.bind_syscall_context_object( - Box::new(SyscallSha256 { - sha256_base_cost: compute_budget.sha256_base_cost, - sha256_byte_cost: compute_budget.sha256_byte_cost, - compute_meter: invoke_context.get_compute_meter(), - loader_id, - }), - None, - )?; - - vm.bind_syscall_context_object( - Box::new(SyscallKeccak256 { - base_cost: compute_budget.sha256_base_cost, - byte_cost: compute_budget.sha256_byte_cost, - compute_meter: invoke_context.get_compute_meter(), - loader_id, - }), - None, - )?; - - vm.bind_syscall_context_object( - Box::new(SyscallMemcpy { - cost: invoke_context.get_compute_budget().cpi_bytes_per_unit, - compute_meter: invoke_context.get_compute_meter(), - loader_id, - }), - None, - )?; - vm.bind_syscall_context_object( - Box::new(SyscallMemmove { - cost: invoke_context.get_compute_budget().cpi_bytes_per_unit, - compute_meter: invoke_context.get_compute_meter(), - loader_id, - }), - None, - )?; - vm.bind_syscall_context_object( - Box::new(SyscallMemcmp { - cost: invoke_context.get_compute_budget().cpi_bytes_per_unit, - compute_meter: invoke_context.get_compute_meter(), - loader_id, - }), - None, - )?; - vm.bind_syscall_context_object( - Box::new(SyscallMemset { - cost: invoke_context.get_compute_budget().cpi_bytes_per_unit, - compute_meter: invoke_context.get_compute_meter(), - loader_id, - }), - None, - )?; - - bind_feature_gated_syscall_context_object!( - vm, - invoke_context.is_feature_active(&blake3_syscall_enabled::id()), - Box::new(SyscallBlake3 { - base_cost: compute_budget.sha256_base_cost, - byte_cost: compute_budget.sha256_byte_cost, - compute_meter: invoke_context.get_compute_meter(), - loader_id, - }), - ); - - bind_feature_gated_syscall_context_object!( - vm, - invoke_context.is_feature_active(&secp256k1_recover_syscall_enabled::id()), - Box::new(SyscallSecp256k1Recover { - cost: compute_budget.secp256k1_recover_cost, - compute_meter: invoke_context.get_compute_meter(), - loader_id, - libsecp256k1_0_5_upgrade_enabled: invoke_context - .is_feature_active(&libsecp256k1_0_5_upgrade_enabled::id()), - }), - ); - + let is_blake3_syscall_active = invoke_context.is_feature_active(&blake3_syscall_enabled::id()); + let is_secp256k1_recover_syscall_active = + invoke_context.is_feature_active(&secp256k1_recover_syscall_enabled::id()); let is_fee_sysvar_via_syscall_active = !invoke_context.is_feature_active(&disable_fees_sysvar::id()); let is_return_data_syscall_active = @@ -362,19 +222,121 @@ pub fn bind_syscall_context_objects<'a>( let is_sol_log_data_syscall_active = invoke_context.is_feature_active(&sol_log_data_syscall_enabled::id()); + let loader_id = invoke_context + .get_loader() + .map_err(SyscallError::InstructionError)?; let invoke_context = Rc::new(RefCell::new(invoke_context)); + // Syscall functions common across languages + + vm.bind_syscall_context_object(Box::new(SyscallAbort {}), None)?; + vm.bind_syscall_context_object( + Box::new(SyscallPanic { + invoke_context: invoke_context.clone(), + }), + None, + )?; + vm.bind_syscall_context_object( + Box::new(SyscallLog { + invoke_context: invoke_context.clone(), + }), + None, + )?; + vm.bind_syscall_context_object( + Box::new(SyscallLogU64 { + invoke_context: invoke_context.clone(), + }), + None, + )?; + + vm.bind_syscall_context_object( + Box::new(SyscallLogBpfComputeUnits { + invoke_context: invoke_context.clone(), + }), + None, + )?; + vm.bind_syscall_context_object( + Box::new(SyscallLogPubkey { + invoke_context: invoke_context.clone(), + }), + None, + )?; + + vm.bind_syscall_context_object( + Box::new(SyscallCreateProgramAddress { + invoke_context: invoke_context.clone(), + }), + None, + )?; + vm.bind_syscall_context_object( + Box::new(SyscallTryFindProgramAddress { + invoke_context: invoke_context.clone(), + }), + None, + )?; + + vm.bind_syscall_context_object( + Box::new(SyscallSha256 { + invoke_context: invoke_context.clone(), + }), + None, + )?; + vm.bind_syscall_context_object( + Box::new(SyscallKeccak256 { + invoke_context: invoke_context.clone(), + }), + None, + )?; + + vm.bind_syscall_context_object( + Box::new(SyscallMemcpy { + invoke_context: invoke_context.clone(), + }), + None, + )?; + vm.bind_syscall_context_object( + Box::new(SyscallMemmove { + invoke_context: invoke_context.clone(), + }), + None, + )?; + vm.bind_syscall_context_object( + Box::new(SyscallMemcmp { + invoke_context: invoke_context.clone(), + }), + None, + )?; + vm.bind_syscall_context_object( + Box::new(SyscallMemset { + invoke_context: invoke_context.clone(), + }), + None, + )?; + + bind_feature_gated_syscall_context_object!( + vm, + is_secp256k1_recover_syscall_active, + Box::new(SyscallSecp256k1Recover { + invoke_context: invoke_context.clone(), + }), + ); + bind_feature_gated_syscall_context_object!( + vm, + is_blake3_syscall_active, + Box::new(SyscallBlake3 { + invoke_context: invoke_context.clone(), + }), + ); + vm.bind_syscall_context_object( Box::new(SyscallGetClockSysvar { invoke_context: invoke_context.clone(), - loader_id, }), None, )?; vm.bind_syscall_context_object( Box::new(SyscallGetEpochScheduleSysvar { invoke_context: invoke_context.clone(), - loader_id, }), None, )?; @@ -383,13 +345,11 @@ pub fn bind_syscall_context_objects<'a>( is_fee_sysvar_via_syscall_active, Box::new(SyscallGetFeesSysvar { invoke_context: invoke_context.clone(), - loader_id, }), ); vm.bind_syscall_context_object( Box::new(SyscallGetRentSysvar { invoke_context: invoke_context.clone(), - loader_id, }), None, )?; @@ -400,7 +360,6 @@ pub fn bind_syscall_context_objects<'a>( is_return_data_syscall_active, Box::new(SyscallSetReturnData { invoke_context: invoke_context.clone(), - loader_id, }), ); @@ -409,7 +368,6 @@ pub fn bind_syscall_context_objects<'a>( is_return_data_syscall_active, Box::new(SyscallGetReturnData { invoke_context: invoke_context.clone(), - loader_id, }), ); @@ -419,7 +377,6 @@ pub fn bind_syscall_context_objects<'a>( is_sol_log_data_syscall_active, Box::new(SyscallLogData { invoke_context: invoke_context.clone(), - loader_id, }), ); @@ -428,7 +385,6 @@ pub fn bind_syscall_context_objects<'a>( Box::new(SyscallInvokeSignedC { invoke_context: invoke_context.clone(), orig_data_lens, - loader_id, }), None, )?; @@ -436,7 +392,6 @@ pub fn bind_syscall_context_objects<'a>( Box::new(SyscallInvokeSignedRust { invoke_context: invoke_context.clone(), orig_data_lens, - loader_id, }), None, )?; @@ -444,7 +399,7 @@ pub fn bind_syscall_context_objects<'a>( // Memory allocator vm.bind_syscall_context_object( Box::new(SyscallAllocFree { - aligned: *loader_id != bpf_loader_deprecated::id(), + aligned: loader_id != bpf_loader_deprecated::id(), allocator: BpfAllocator::new(heap, ebpf::MM_HEAP_START), }), None, @@ -580,8 +535,7 @@ impl SyscallObject for SyscallAbort { /// Causes the BPF program to be halted immediately /// Log a user's info message pub struct SyscallPanic<'a> { - compute_meter: Rc>, - loader_id: &'a Pubkey, + invoke_context: Rc>, } impl<'a> SyscallObject for SyscallPanic<'a> { fn call( @@ -594,12 +548,25 @@ impl<'a> SyscallObject for SyscallPanic<'a> { memory_mapping: &MemoryMapping, result: &mut Result>, ) { - question_mark!(self.compute_meter.consume(len), result); + let invoke_context = question_mark!( + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed), + result + ); + question_mark!(invoke_context.get_compute_meter().consume(len), result); + + let loader_id = question_mark!( + invoke_context + .get_loader() + .map_err(SyscallError::InstructionError), + result + ); *result = translate_string_and_do( memory_mapping, file, len, - self.loader_id, + &loader_id, &mut |string: &str| Err(SyscallError::Panic(string.to_string(), line, column).into()), ); } @@ -607,9 +574,7 @@ impl<'a> SyscallObject for SyscallPanic<'a> { /// Log a user's info message pub struct SyscallLog<'a> { - compute_meter: Rc>, - log_collector: Option>>, - loader_id: &'a Pubkey, + invoke_context: Rc>, } impl<'a> SyscallObject for SyscallLog<'a> { fn call( @@ -622,15 +587,28 @@ impl<'a> SyscallObject for SyscallLog<'a> { memory_mapping: &MemoryMapping, result: &mut Result>, ) { - question_mark!(self.compute_meter.consume(len), result); + let invoke_context = question_mark!( + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed), + result + ); + question_mark!(invoke_context.get_compute_meter().consume(len), result); + + let loader_id = question_mark!( + invoke_context + .get_loader() + .map_err(SyscallError::InstructionError), + result + ); question_mark!( translate_string_and_do( memory_mapping, addr, len, - self.loader_id, + &loader_id, &mut |string: &str| { - stable_log::program_log(&self.log_collector, string); + stable_log::program_log(&invoke_context.get_log_collector(), string); Ok(0) }, ), @@ -641,12 +619,10 @@ impl<'a> SyscallObject for SyscallLog<'a> { } /// Log 5 64-bit values -pub struct SyscallLogU64 { - cost: u64, - compute_meter: Rc>, - log_collector: Option>>, +pub struct SyscallLogU64<'a> { + invoke_context: Rc>, } -impl SyscallObject for SyscallLogU64 { +impl<'a> SyscallObject for SyscallLogU64<'a> { fn call( &mut self, arg1: u64, @@ -657,9 +633,17 @@ impl SyscallObject for SyscallLogU64 { _memory_mapping: &MemoryMapping, result: &mut Result>, ) { - question_mark!(self.compute_meter.consume(self.cost), result); + let invoke_context = question_mark!( + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed), + result + ); + let cost = invoke_context.get_compute_budget().log_64_units; + question_mark!(invoke_context.get_compute_meter().consume(cost), result); + stable_log::program_log( - &self.log_collector, + &invoke_context.get_log_collector(), &format!( "{:#x}, {:#x}, {:#x}, {:#x}, {:#x}", arg1, arg2, arg3, arg4, arg5 @@ -670,12 +654,10 @@ impl SyscallObject for SyscallLogU64 { } /// Log current compute consumption -pub struct SyscallLogBpfComputeUnits { - cost: u64, - compute_meter: Rc>, - log_collector: Option>>, +pub struct SyscallLogBpfComputeUnits<'a> { + invoke_context: Rc>, } -impl SyscallObject for SyscallLogBpfComputeUnits { +impl<'a> SyscallObject for SyscallLogBpfComputeUnits<'a> { fn call( &mut self, _arg1: u64, @@ -686,11 +668,18 @@ impl SyscallObject for SyscallLogBpfComputeUnits { _memory_mapping: &MemoryMapping, result: &mut Result>, ) { - question_mark!(self.compute_meter.consume(self.cost), result); + let invoke_context = question_mark!( + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed), + result + ); + question_mark!(invoke_context.get_compute_meter().consume(0), result); + ic_logger_msg!( - self.log_collector, + invoke_context.get_log_collector(), "Program consumption: {} units remaining", - self.compute_meter.borrow().get_remaining() + invoke_context.get_compute_meter().borrow().get_remaining() ); *result = Ok(0); } @@ -698,10 +687,7 @@ impl SyscallObject for SyscallLogBpfComputeUnits { /// Log 5 64-bit values pub struct SyscallLogPubkey<'a> { - cost: u64, - compute_meter: Rc>, - log_collector: Option>>, - loader_id: &'a Pubkey, + invoke_context: Rc>, } impl<'a> SyscallObject for SyscallLogPubkey<'a> { fn call( @@ -714,12 +700,26 @@ impl<'a> SyscallObject for SyscallLogPubkey<'a> { memory_mapping: &MemoryMapping, result: &mut Result>, ) { - question_mark!(self.compute_meter.consume(self.cost), result); - let pubkey = question_mark!( - translate_type::(memory_mapping, pubkey_addr, self.loader_id,), + let invoke_context = question_mark!( + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed), result ); - stable_log::program_log(&self.log_collector, &pubkey.to_string()); + let cost = invoke_context.get_compute_budget().log_pubkey_units; + question_mark!(invoke_context.get_compute_meter().consume(cost), result); + + let loader_id = question_mark!( + invoke_context + .get_loader() + .map_err(SyscallError::InstructionError), + result + ); + let pubkey = question_mark!( + translate_type::(memory_mapping, pubkey_addr, &loader_id), + result + ); + stable_log::program_log(&invoke_context.get_log_collector(), &pubkey.to_string()); *result = Ok(0); } } @@ -801,9 +801,7 @@ fn translate_and_check_program_address_inputs<'a>( /// Create a program address struct SyscallCreateProgramAddress<'a> { - cost: u64, - compute_meter: Rc>, - loader_id: &'a Pubkey, + invoke_context: Rc>, } impl<'a> SyscallObject for SyscallCreateProgramAddress<'a> { fn call( @@ -816,15 +814,30 @@ impl<'a> SyscallObject for SyscallCreateProgramAddress<'a> { memory_mapping: &MemoryMapping, result: &mut Result>, ) { - question_mark!(self.compute_meter.consume(self.cost), result); + let invoke_context = question_mark!( + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed), + result + ); + let cost = invoke_context + .get_compute_budget() + .create_program_address_units; + question_mark!(invoke_context.get_compute_meter().consume(cost), result); + let loader_id = question_mark!( + invoke_context + .get_loader() + .map_err(SyscallError::InstructionError), + result + ); let (seeds, program_id) = question_mark!( translate_and_check_program_address_inputs( seeds_addr, seeds_len, program_id_addr, memory_mapping, - self.loader_id, + &loader_id, ), result ); @@ -837,7 +850,7 @@ impl<'a> SyscallObject for SyscallCreateProgramAddress<'a> { } }; let address = question_mark!( - translate_slice_mut::(memory_mapping, address_addr, 32, self.loader_id,), + translate_slice_mut::(memory_mapping, address_addr, 32, &loader_id), result ); address.copy_from_slice(new_address.as_ref()); @@ -847,9 +860,7 @@ impl<'a> SyscallObject for SyscallCreateProgramAddress<'a> { /// Create a program address struct SyscallTryFindProgramAddress<'a> { - cost: u64, - compute_meter: Rc>, - loader_id: &'a Pubkey, + invoke_context: Rc>, } impl<'a> SyscallObject for SyscallTryFindProgramAddress<'a> { fn call( @@ -862,15 +873,30 @@ impl<'a> SyscallObject for SyscallTryFindProgramAddress<'a> { memory_mapping: &MemoryMapping, result: &mut Result>, ) { - question_mark!(self.compute_meter.consume(self.cost), result); + let invoke_context = question_mark!( + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed), + result + ); + let cost = invoke_context + .get_compute_budget() + .create_program_address_units; + question_mark!(invoke_context.get_compute_meter().consume(cost), result); + let loader_id = question_mark!( + invoke_context + .get_loader() + .map_err(SyscallError::InstructionError), + result + ); let (seeds, program_id) = question_mark!( translate_and_check_program_address_inputs( seeds_addr, seeds_len, program_id_addr, memory_mapping, - self.loader_id, + &loader_id, ), result ); @@ -885,11 +911,11 @@ impl<'a> SyscallObject for SyscallTryFindProgramAddress<'a> { Pubkey::create_program_address(&seeds_with_bump, program_id) { let bump_seed_ref = question_mark!( - translate_type_mut::(memory_mapping, bump_seed_addr, self.loader_id,), + translate_type_mut::(memory_mapping, bump_seed_addr, &loader_id), result ); let address = question_mark!( - translate_slice_mut::(memory_mapping, address_addr, 32, self.loader_id,), + translate_slice_mut::(memory_mapping, address_addr, 32, &loader_id), result ); *bump_seed_ref = bump_seed[0]; @@ -899,7 +925,7 @@ impl<'a> SyscallObject for SyscallTryFindProgramAddress<'a> { } } bump_seed[0] -= 1; - question_mark!(self.compute_meter.consume(self.cost), result); + question_mark!(invoke_context.get_compute_meter().consume(cost), result); } *result = Ok(1); } @@ -907,10 +933,7 @@ impl<'a> SyscallObject for SyscallTryFindProgramAddress<'a> { /// SHA256 pub struct SyscallSha256<'a> { - sha256_base_cost: u64, - sha256_byte_cost: u64, - compute_meter: Rc>, - loader_id: &'a Pubkey, + invoke_context: Rc>, } impl<'a> SyscallObject for SyscallSha256<'a> { fn call( @@ -923,20 +946,32 @@ impl<'a> SyscallObject for SyscallSha256<'a> { memory_mapping: &MemoryMapping, result: &mut Result>, ) { - question_mark!(self.compute_meter.consume(self.sha256_base_cost), result); + let invoke_context = question_mark!( + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed), + result + ); + let base_cost = invoke_context.get_compute_budget().sha256_base_cost; + question_mark!( + invoke_context.get_compute_meter().consume(base_cost), + result + ); + + let loader_id = question_mark!( + invoke_context + .get_loader() + .map_err(SyscallError::InstructionError), + result + ); let hash_result = question_mark!( - translate_slice_mut::( - memory_mapping, - result_addr, - HASH_BYTES as u64, - self.loader_id, - ), + translate_slice_mut::(memory_mapping, result_addr, HASH_BYTES as u64, &loader_id), result ); let mut hasher = Hasher::default(); if vals_len > 0 { let vals = question_mark!( - translate_slice::<&[u8]>(memory_mapping, vals_addr, vals_len, self.loader_id,), + translate_slice::<&[u8]>(memory_mapping, vals_addr, vals_len, &loader_id), result ); for val in vals.iter() { @@ -945,13 +980,15 @@ impl<'a> SyscallObject for SyscallSha256<'a> { memory_mapping, val.as_ptr() as u64, val.len() as u64, - self.loader_id, + &loader_id, ), result ); + let byte_cost = invoke_context.get_compute_budget().sha256_byte_cost; question_mark!( - self.compute_meter - .consume(self.sha256_byte_cost * (val.len() as u64 / 2)), + invoke_context + .get_compute_meter() + .consume(byte_cost * (val.len() as u64 / 2)), result ); hasher.hash(bytes); @@ -987,7 +1024,6 @@ fn get_sysvar( /// Get a Clock sysvar struct SyscallGetClockSysvar<'a> { invoke_context: Rc>, - loader_id: &'a Pubkey, } impl<'a> SyscallObject for SyscallGetClockSysvar<'a> { fn call( @@ -1000,10 +1036,22 @@ impl<'a> SyscallObject for SyscallGetClockSysvar<'a> { memory_mapping: &MemoryMapping, result: &mut Result>, ) { + let invoke_context = question_mark!( + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed), + result + ); + let loader_id = question_mark!( + invoke_context + .get_loader() + .map_err(SyscallError::InstructionError), + result + ); *result = get_sysvar::( &sysvar::clock::id(), var_addr, - self.loader_id, + &loader_id, memory_mapping, self.invoke_context.clone(), ); @@ -1012,7 +1060,6 @@ impl<'a> SyscallObject for SyscallGetClockSysvar<'a> { /// Get a EpochSchedule sysvar struct SyscallGetEpochScheduleSysvar<'a> { invoke_context: Rc>, - loader_id: &'a Pubkey, } impl<'a> SyscallObject for SyscallGetEpochScheduleSysvar<'a> { fn call( @@ -1025,10 +1072,22 @@ impl<'a> SyscallObject for SyscallGetEpochScheduleSysvar<'a> { memory_mapping: &MemoryMapping, result: &mut Result>, ) { + let invoke_context = question_mark!( + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed), + result + ); + let loader_id = question_mark!( + invoke_context + .get_loader() + .map_err(SyscallError::InstructionError), + result + ); *result = get_sysvar::( &sysvar::epoch_schedule::id(), var_addr, - self.loader_id, + &loader_id, memory_mapping, self.invoke_context.clone(), ); @@ -1037,7 +1096,6 @@ impl<'a> SyscallObject for SyscallGetEpochScheduleSysvar<'a> { /// Get a Fees sysvar struct SyscallGetFeesSysvar<'a> { invoke_context: Rc>, - loader_id: &'a Pubkey, } #[allow(deprecated)] impl<'a> SyscallObject for SyscallGetFeesSysvar<'a> { @@ -1051,10 +1109,22 @@ impl<'a> SyscallObject for SyscallGetFeesSysvar<'a> { memory_mapping: &MemoryMapping, result: &mut Result>, ) { + let invoke_context = question_mark!( + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed), + result + ); + let loader_id = question_mark!( + invoke_context + .get_loader() + .map_err(SyscallError::InstructionError), + result + ); *result = get_sysvar::( &sysvar::fees::id(), var_addr, - self.loader_id, + &loader_id, memory_mapping, self.invoke_context.clone(), ); @@ -1063,7 +1133,6 @@ impl<'a> SyscallObject for SyscallGetFeesSysvar<'a> { /// Get a Rent sysvar struct SyscallGetRentSysvar<'a> { invoke_context: Rc>, - loader_id: &'a Pubkey, } impl<'a> SyscallObject for SyscallGetRentSysvar<'a> { fn call( @@ -1076,10 +1145,22 @@ impl<'a> SyscallObject for SyscallGetRentSysvar<'a> { memory_mapping: &MemoryMapping, result: &mut Result>, ) { + let invoke_context = question_mark!( + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed), + result + ); + let loader_id = question_mark!( + invoke_context + .get_loader() + .map_err(SyscallError::InstructionError), + result + ); *result = get_sysvar::( &sysvar::rent::id(), var_addr, - self.loader_id, + &loader_id, memory_mapping, self.invoke_context.clone(), ); @@ -1088,10 +1169,7 @@ impl<'a> SyscallObject for SyscallGetRentSysvar<'a> { // Keccak256 pub struct SyscallKeccak256<'a> { - base_cost: u64, - byte_cost: u64, - compute_meter: Rc>, - loader_id: &'a Pubkey, + invoke_context: Rc>, } impl<'a> SyscallObject for SyscallKeccak256<'a> { fn call( @@ -1104,20 +1182,37 @@ impl<'a> SyscallObject for SyscallKeccak256<'a> { memory_mapping: &MemoryMapping, result: &mut Result>, ) { - question_mark!(self.compute_meter.consume(self.base_cost), result); + let invoke_context = question_mark!( + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed), + result + ); + let base_cost = invoke_context.get_compute_budget().sha256_base_cost; + question_mark!( + invoke_context.get_compute_meter().consume(base_cost), + result + ); + + let loader_id = question_mark!( + invoke_context + .get_loader() + .map_err(SyscallError::InstructionError), + result + ); let hash_result = question_mark!( translate_slice_mut::( memory_mapping, result_addr, keccak::HASH_BYTES as u64, - self.loader_id, + &loader_id, ), result ); let mut hasher = keccak::Hasher::default(); if vals_len > 0 { let vals = question_mark!( - translate_slice::<&[u8]>(memory_mapping, vals_addr, vals_len, self.loader_id), + translate_slice::<&[u8]>(memory_mapping, vals_addr, vals_len, &loader_id), result ); for val in vals.iter() { @@ -1126,13 +1221,15 @@ impl<'a> SyscallObject for SyscallKeccak256<'a> { memory_mapping, val.as_ptr() as u64, val.len() as u64, - self.loader_id, + &loader_id, ), result ); + let byte_cost = invoke_context.get_compute_budget().sha256_byte_cost; question_mark!( - self.compute_meter - .consume(self.byte_cost * (val.len() as u64 / 2)), + invoke_context + .get_compute_meter() + .consume(byte_cost * (val.len() as u64 / 2)), result ); hasher.hash(bytes); @@ -1150,9 +1247,7 @@ fn check_overlapping(src_addr: u64, dst_addr: u64, n: u64) -> bool { /// memcpy pub struct SyscallMemcpy<'a> { - cost: u64, - compute_meter: Rc>, - loader_id: &'a Pubkey, + invoke_context: Rc>, } impl<'a> SyscallObject for SyscallMemcpy<'a> { fn call( @@ -1170,13 +1265,27 @@ impl<'a> SyscallObject for SyscallMemcpy<'a> { return; } - question_mark!(self.compute_meter.consume(n / self.cost), result); + let invoke_context = question_mark!( + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed), + result + ); + let cost = invoke_context.get_compute_budget().cpi_bytes_per_unit; + question_mark!(invoke_context.get_compute_meter().consume(n / cost), result); + + let loader_id = question_mark!( + invoke_context + .get_loader() + .map_err(SyscallError::InstructionError), + result + ); let dst = question_mark!( - translate_slice_mut::(memory_mapping, dst_addr, n, self.loader_id), + translate_slice_mut::(memory_mapping, dst_addr, n, &loader_id), result ); let src = question_mark!( - translate_slice::(memory_mapping, src_addr, n, self.loader_id), + translate_slice::(memory_mapping, src_addr, n, &loader_id), result ); unsafe { @@ -1187,9 +1296,7 @@ impl<'a> SyscallObject for SyscallMemcpy<'a> { } /// memmove pub struct SyscallMemmove<'a> { - cost: u64, - compute_meter: Rc>, - loader_id: &'a Pubkey, + invoke_context: Rc>, } impl<'a> SyscallObject for SyscallMemmove<'a> { fn call( @@ -1202,13 +1309,27 @@ impl<'a> SyscallObject for SyscallMemmove<'a> { memory_mapping: &MemoryMapping, result: &mut Result>, ) { - question_mark!(self.compute_meter.consume(n / self.cost), result); + let invoke_context = question_mark!( + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed), + result + ); + let cost = invoke_context.get_compute_budget().cpi_bytes_per_unit; + question_mark!(invoke_context.get_compute_meter().consume(n / cost), result); + + let loader_id = question_mark!( + invoke_context + .get_loader() + .map_err(SyscallError::InstructionError), + result + ); let dst = question_mark!( - translate_slice_mut::(memory_mapping, dst_addr, n, self.loader_id), + translate_slice_mut::(memory_mapping, dst_addr, n, &loader_id), result ); let src = question_mark!( - translate_slice::(memory_mapping, src_addr, n, self.loader_id), + translate_slice::(memory_mapping, src_addr, n, &loader_id), result ); unsafe { @@ -1219,9 +1340,7 @@ impl<'a> SyscallObject for SyscallMemmove<'a> { } /// memcmp pub struct SyscallMemcmp<'a> { - cost: u64, - compute_meter: Rc>, - loader_id: &'a Pubkey, + invoke_context: Rc>, } impl<'a> SyscallObject for SyscallMemcmp<'a> { fn call( @@ -1234,17 +1353,31 @@ impl<'a> SyscallObject for SyscallMemcmp<'a> { memory_mapping: &MemoryMapping, result: &mut Result>, ) { - question_mark!(self.compute_meter.consume(n / self.cost), result); + let invoke_context = question_mark!( + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed), + result + ); + let cost = invoke_context.get_compute_budget().cpi_bytes_per_unit; + question_mark!(invoke_context.get_compute_meter().consume(n / cost), result); + + let loader_id = question_mark!( + invoke_context + .get_loader() + .map_err(SyscallError::InstructionError), + result + ); let s1 = question_mark!( - translate_slice::(memory_mapping, s1_addr, n, self.loader_id), + translate_slice::(memory_mapping, s1_addr, n, &loader_id), result ); let s2 = question_mark!( - translate_slice::(memory_mapping, s2_addr, n, self.loader_id), + translate_slice::(memory_mapping, s2_addr, n, &loader_id), result ); let cmp_result = question_mark!( - translate_type_mut::(memory_mapping, cmp_result_addr, self.loader_id), + translate_type_mut::(memory_mapping, cmp_result_addr, &loader_id), result ); let mut i = 0; @@ -1264,9 +1397,7 @@ impl<'a> SyscallObject for SyscallMemcmp<'a> { } /// memset pub struct SyscallMemset<'a> { - cost: u64, - compute_meter: Rc>, - loader_id: &'a Pubkey, + invoke_context: Rc>, } impl<'a> SyscallObject for SyscallMemset<'a> { fn call( @@ -1279,9 +1410,23 @@ impl<'a> SyscallObject for SyscallMemset<'a> { memory_mapping: &MemoryMapping, result: &mut Result>, ) { - question_mark!(self.compute_meter.consume(n / self.cost), result); + let invoke_context = question_mark!( + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed), + result + ); + let cost = invoke_context.get_compute_budget().cpi_bytes_per_unit; + question_mark!(invoke_context.get_compute_meter().consume(n / cost), result); + + let loader_id = question_mark!( + invoke_context + .get_loader() + .map_err(SyscallError::InstructionError), + result + ); let s = question_mark!( - translate_slice_mut::(memory_mapping, s_addr, n, self.loader_id), + translate_slice_mut::(memory_mapping, s_addr, n, &loader_id), result ); for val in s.iter_mut().take(n as usize) { @@ -1293,10 +1438,7 @@ impl<'a> SyscallObject for SyscallMemset<'a> { /// secp256k1_recover pub struct SyscallSecp256k1Recover<'a> { - cost: u64, - compute_meter: Rc>, - loader_id: &'a Pubkey, - libsecp256k1_0_5_upgrade_enabled: bool, + invoke_context: Rc>, } impl<'a> SyscallObject for SyscallSecp256k1Recover<'a> { @@ -1310,14 +1452,27 @@ impl<'a> SyscallObject for SyscallSecp256k1Recover<'a> { memory_mapping: &MemoryMapping, result: &mut Result>, ) { - question_mark!(self.compute_meter.consume(self.cost), result); + let invoke_context = question_mark!( + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed), + result + ); + let cost = invoke_context.get_compute_budget().secp256k1_recover_cost; + question_mark!(invoke_context.get_compute_meter().consume(cost), result); + let loader_id = question_mark!( + invoke_context + .get_loader() + .map_err(SyscallError::InstructionError), + result + ); let hash = question_mark!( translate_slice::( memory_mapping, hash_addr, keccak::HASH_BYTES as u64, - self.loader_id, + &loader_id, ), result ); @@ -1326,7 +1481,7 @@ impl<'a> SyscallObject for SyscallSecp256k1Recover<'a> { memory_mapping, signature_addr, SECP256K1_SIGNATURE_LENGTH as u64, - self.loader_id, + &loader_id, ), result ); @@ -1335,7 +1490,7 @@ impl<'a> SyscallObject for SyscallSecp256k1Recover<'a> { memory_mapping, result_addr, SECP256K1_PUBLIC_KEY_LENGTH as u64, - self.loader_id, + &loader_id, ), result ); @@ -1354,11 +1509,12 @@ impl<'a> SyscallObject for SyscallSecp256k1Recover<'a> { return; } }; - let sig_parse_result = if self.libsecp256k1_0_5_upgrade_enabled { - libsecp256k1::Signature::parse_standard_slice(signature) - } else { - libsecp256k1::Signature::parse_overflowing_slice(signature) - }; + let sig_parse_result = + if invoke_context.is_feature_active(&libsecp256k1_0_5_upgrade_enabled::id()) { + libsecp256k1::Signature::parse_standard_slice(signature) + } else { + libsecp256k1::Signature::parse_overflowing_slice(signature) + }; let signature = match sig_parse_result { Ok(sig) => sig, @@ -1383,10 +1539,7 @@ impl<'a> SyscallObject for SyscallSecp256k1Recover<'a> { // Blake3 pub struct SyscallBlake3<'a> { - base_cost: u64, - byte_cost: u64, - compute_meter: Rc>, - loader_id: &'a Pubkey, + invoke_context: Rc>, } impl<'a> SyscallObject for SyscallBlake3<'a> { fn call( @@ -1399,20 +1552,37 @@ impl<'a> SyscallObject for SyscallBlake3<'a> { memory_mapping: &MemoryMapping, result: &mut Result>, ) { - question_mark!(self.compute_meter.consume(self.base_cost), result); + let invoke_context = question_mark!( + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed), + result + ); + let base_cost = invoke_context.get_compute_budget().sha256_base_cost; + question_mark!( + invoke_context.get_compute_meter().consume(base_cost), + result + ); + + let loader_id = question_mark!( + invoke_context + .get_loader() + .map_err(SyscallError::InstructionError), + result + ); let hash_result = question_mark!( translate_slice_mut::( memory_mapping, result_addr, blake3::HASH_BYTES as u64, - self.loader_id, + &loader_id, ), result ); let mut hasher = blake3::Hasher::default(); if vals_len > 0 { let vals = question_mark!( - translate_slice::<&[u8]>(memory_mapping, vals_addr, vals_len, self.loader_id), + translate_slice::<&[u8]>(memory_mapping, vals_addr, vals_len, &loader_id), result ); for val in vals.iter() { @@ -1421,13 +1591,15 @@ impl<'a> SyscallObject for SyscallBlake3<'a> { memory_mapping, val.as_ptr() as u64, val.len() as u64, - self.loader_id, + &loader_id, ), result ); + let byte_cost = invoke_context.get_compute_budget().sha256_byte_cost; question_mark!( - self.compute_meter - .consume(self.byte_cost * (val.len() as u64 / 2)), + invoke_context + .get_compute_meter() + .consume(byte_cost * (val.len() as u64 / 2)), result ); hasher.hash(bytes); @@ -1462,12 +1634,14 @@ trait SyscallInvokeSigned<'a> { fn get_context(&self) -> Result, EbpfError>; fn translate_instruction( &self, + loader_id: &Pubkey, addr: u64, memory_mapping: &MemoryMapping, invoke_context: &mut dyn InvokeContext, ) -> Result>; fn translate_accounts( &self, + loader_id: &Pubkey, message: &Message, account_infos_addr: u64, account_infos_len: u64, @@ -1476,6 +1650,7 @@ trait SyscallInvokeSigned<'a> { ) -> Result, EbpfError>; fn translate_signers( &self, + loader_id: &Pubkey, program_id: &Pubkey, signers_seeds_addr: u64, signers_seeds_len: u64, @@ -1487,7 +1662,6 @@ trait SyscallInvokeSigned<'a> { pub struct SyscallInvokeSignedRust<'a> { invoke_context: Rc>, orig_data_lens: &'a [usize], - loader_id: &'a Pubkey, } impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { fn get_context_mut(&self) -> Result, EbpfError> { @@ -1502,11 +1676,12 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { } fn translate_instruction( &self, + loader_id: &Pubkey, addr: u64, memory_mapping: &MemoryMapping, invoke_context: &mut dyn InvokeContext, ) -> Result> { - let ix = translate_type::(memory_mapping, addr, self.loader_id)?; + let ix = translate_type::(memory_mapping, addr, loader_id)?; check_instruction_size(ix.accounts.len(), ix.data.len(), invoke_context)?; @@ -1514,14 +1689,14 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { memory_mapping, ix.accounts.as_ptr() as u64, ix.accounts.len() as u64, - self.loader_id, + loader_id, )? .to_vec(); let data = translate_slice::( memory_mapping, ix.data.as_ptr() as u64, ix.data.len() as u64, - self.loader_id, + loader_id, )? .to_vec(); Ok(Instruction { @@ -1533,6 +1708,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { fn translate_accounts( &self, + loader_id: &Pubkey, message: &Message, account_infos_addr: u64, account_infos_len: u64, @@ -1543,7 +1719,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { memory_mapping, account_infos_addr, account_infos_len, - self.loader_id, + loader_id, )?; check_account_infos(account_infos.len(), invoke_context)?; let account_info_keys = account_infos @@ -1552,7 +1728,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { translate_type::( memory_mapping, account_info.key as *const _ as u64, - self.loader_id, + loader_id, ) }) .collect::, EbpfError>>()?; @@ -1565,14 +1741,14 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { let ptr = translate_type::( memory_mapping, account_info.lamports.as_ptr() as u64, - self.loader_id, + loader_id, )?; - translate_type_mut::(memory_mapping, *ptr, self.loader_id)? + translate_type_mut::(memory_mapping, *ptr, loader_id)? }; let owner = translate_type_mut::( memory_mapping, account_info.owner as *const _ as u64, - self.loader_id, + loader_id, )?; let (data, vm_data_addr, ref_to_len_in_vm, serialized_len_ptr) = { @@ -1580,7 +1756,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { let data = *translate_type::<&[u8]>( memory_mapping, account_info.data.as_ptr() as *const _ as u64, - self.loader_id, + loader_id, )?; invoke_context.get_compute_meter().consume( @@ -1598,7 +1774,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { let serialized_len_ptr = translate_type_mut::( memory_mapping, ref_of_len_in_input_buffer as *const _ as u64, - self.loader_id, + loader_id, )?; let vm_data_addr = data.as_ptr() as u64; ( @@ -1606,7 +1782,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { memory_mapping, vm_data_addr, data.len() as u64, - self.loader_id, + loader_id, )?, vm_data_addr, ref_to_len_in_vm, @@ -1639,6 +1815,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { fn translate_signers( &self, + loader_id: &Pubkey, program_id: &Pubkey, signers_seeds_addr: u64, signers_seeds_len: u64, @@ -1650,7 +1827,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { memory_mapping, signers_seeds_addr, signers_seeds_len, - self.loader_id, + loader_id, )?; if signers_seeds.len() > MAX_SIGNERS { return Err(SyscallError::TooManySigners.into()); @@ -1660,7 +1837,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { memory_mapping, signer_seeds.as_ptr() as *const _ as u64, signer_seeds.len() as u64, - self.loader_id, + loader_id, )?; if untranslated_seeds.len() > MAX_SEEDS { return Err(SyscallError::InstructionError( @@ -1675,7 +1852,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { memory_mapping, untranslated_seed.as_ptr() as *const _ as u64, untranslated_seed.len() as u64, - self.loader_id, + loader_id, ) }) .collect::, EbpfError>>()?; @@ -1766,7 +1943,6 @@ struct SolSignerSeedsC { pub struct SyscallInvokeSignedC<'a> { invoke_context: Rc>, orig_data_lens: &'a [usize], - loader_id: &'a Pubkey, } impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> { fn get_context_mut(&self) -> Result, EbpfError> { @@ -1782,33 +1958,33 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> { fn translate_instruction( &self, + loader_id: &Pubkey, addr: u64, memory_mapping: &MemoryMapping, invoke_context: &mut dyn InvokeContext, ) -> Result> { - let ix_c = translate_type::(memory_mapping, addr, self.loader_id)?; + let ix_c = translate_type::(memory_mapping, addr, loader_id)?; check_instruction_size(ix_c.accounts_len, ix_c.data_len, invoke_context)?; - let program_id = - translate_type::(memory_mapping, ix_c.program_id_addr, self.loader_id)?; + let program_id = translate_type::(memory_mapping, ix_c.program_id_addr, loader_id)?; let meta_cs = translate_slice::( memory_mapping, ix_c.accounts_addr, ix_c.accounts_len as u64, - self.loader_id, + loader_id, )?; let data = translate_slice::( memory_mapping, ix_c.data_addr, ix_c.data_len as u64, - self.loader_id, + loader_id, )? .to_vec(); let accounts = meta_cs .iter() .map(|meta_c| { let pubkey = - translate_type::(memory_mapping, meta_c.pubkey_addr, self.loader_id)?; + translate_type::(memory_mapping, meta_c.pubkey_addr, loader_id)?; Ok(AccountMeta { pubkey: *pubkey, is_signer: meta_c.is_signer, @@ -1826,6 +2002,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> { fn translate_accounts( &self, + loader_id: &Pubkey, message: &Message, account_infos_addr: u64, account_infos_len: u64, @@ -1836,29 +2013,23 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> { memory_mapping, account_infos_addr, account_infos_len, - self.loader_id, + loader_id, )?; check_account_infos(account_infos.len(), invoke_context)?; let account_info_keys = account_infos .iter() .map(|account_info| { - translate_type::(memory_mapping, account_info.key_addr, self.loader_id) + translate_type::(memory_mapping, account_info.key_addr, loader_id) }) .collect::, EbpfError>>()?; let translate = |account_info: &SolAccountInfo, invoke_context: &dyn InvokeContext| { // Translate the account from user space - let lamports = translate_type_mut::( - memory_mapping, - account_info.lamports_addr, - self.loader_id, - )?; - let owner = translate_type_mut::( - memory_mapping, - account_info.owner_addr, - self.loader_id, - )?; + let lamports = + translate_type_mut::(memory_mapping, account_info.lamports_addr, loader_id)?; + let owner = + translate_type_mut::(memory_mapping, account_info.owner_addr, loader_id)?; let vm_data_addr = account_info.data_addr; invoke_context.get_compute_meter().consume( @@ -1869,7 +2040,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> { memory_mapping, vm_data_addr, account_info.data_len, - self.loader_id, + loader_id, )?; let first_info_addr = &account_infos[0] as *const _ as u64; @@ -1888,7 +2059,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> { let serialized_len_ptr = translate_type_mut::( memory_mapping, ref_of_len_in_input_buffer as *const _ as u64, - self.loader_id, + loader_id, )?; Ok(CallerAccount { @@ -1916,6 +2087,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> { fn translate_signers( &self, + loader_id: &Pubkey, program_id: &Pubkey, signers_seeds_addr: u64, signers_seeds_len: u64, @@ -1926,7 +2098,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> { memory_mapping, signers_seeds_addr, signers_seeds_len, - self.loader_id, + loader_id, )?; if signers_seeds.len() > MAX_SIGNERS { return Err(SyscallError::TooManySigners.into()); @@ -1938,7 +2110,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> { memory_mapping, signer_seeds.addr, signer_seeds.len, - self.loader_id, + loader_id, )?; if seeds.len() > MAX_SEEDS { return Err(SyscallError::InstructionError( @@ -1949,12 +2121,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> { let seeds_bytes = seeds .iter() .map(|seed| { - translate_slice::( - memory_mapping, - seed.addr, - seed.len, - self.loader_id, - ) + translate_slice::(memory_mapping, seed.addr, seed.len, loader_id) }) .collect::, EbpfError>>()?; Pubkey::create_program_address(&seeds_bytes, program_id) @@ -2145,12 +2312,20 @@ fn call<'a>( let do_support_realloc = invoke_context.is_feature_active(&do_support_realloc::id()); // Translate and verify caller's data - let instruction = - syscall.translate_instruction(instruction_addr, memory_mapping, *invoke_context)?; + let loader_id = invoke_context + .get_loader() + .map_err(SyscallError::InstructionError)?; + let instruction = syscall.translate_instruction( + &loader_id, + instruction_addr, + memory_mapping, + *invoke_context, + )?; let caller_program_id = invoke_context .get_caller() .map_err(SyscallError::InstructionError)?; let signers = syscall.translate_signers( + &loader_id, caller_program_id, signers_seeds_addr, signers_seeds_len, @@ -2161,6 +2336,7 @@ fn call<'a>( .map_err(SyscallError::InstructionError)?; check_authorized_program(&instruction.program_id, &instruction.data, *invoke_context)?; let (account_indices, mut accounts) = syscall.translate_accounts( + &loader_id, &message, account_infos_addr, account_infos_len, @@ -2239,7 +2415,6 @@ fn call<'a>( // Return data handling pub struct SyscallSetReturnData<'a> { invoke_context: Rc>, - loader_id: &'a Pubkey, } impl<'a> SyscallObject for SyscallSetReturnData<'a> { fn call( @@ -2258,6 +2433,12 @@ impl<'a> SyscallObject for SyscallSetReturnData<'a> { .map_err(|_| SyscallError::InvokeContextBorrowFailed), result ); + let loader_id = question_mark!( + invoke_context + .get_loader() + .map_err(SyscallError::InstructionError), + result + ); let budget = invoke_context.get_compute_budget(); @@ -2277,7 +2458,7 @@ impl<'a> SyscallObject for SyscallSetReturnData<'a> { Vec::new() } else { question_mark!( - translate_slice::(memory_mapping, addr, len, self.loader_id), + translate_slice::(memory_mapping, addr, len, &loader_id), result ) .to_vec() @@ -2295,7 +2476,6 @@ impl<'a> SyscallObject for SyscallSetReturnData<'a> { pub struct SyscallGetReturnData<'a> { invoke_context: Rc>, - loader_id: &'a Pubkey, } impl<'a> SyscallObject for SyscallGetReturnData<'a> { fn call( @@ -2314,6 +2494,12 @@ impl<'a> SyscallObject for SyscallGetReturnData<'a> { .map_err(|_| SyscallError::InvokeContextBorrowFailed), result ); + let loader_id = question_mark!( + invoke_context + .get_loader() + .map_err(SyscallError::InstructionError), + result + ); let budget = invoke_context.get_compute_budget(); @@ -2335,14 +2521,14 @@ impl<'a> SyscallObject for SyscallGetReturnData<'a> { ); let return_data_result = question_mark!( - translate_slice_mut::(memory_mapping, return_data_addr, length, self.loader_id,), + translate_slice_mut::(memory_mapping, return_data_addr, length, &loader_id), result ); return_data_result.copy_from_slice(&return_data[..length as usize]); let program_id_result = question_mark!( - translate_slice_mut::(memory_mapping, program_id_addr, 1, self.loader_id,), + translate_slice_mut::(memory_mapping, program_id_addr, 1, &loader_id), result ); @@ -2357,7 +2543,6 @@ impl<'a> SyscallObject for SyscallGetReturnData<'a> { // Log data handling pub struct SyscallLogData<'a> { invoke_context: Rc>, - loader_id: &'a Pubkey, } impl<'a> SyscallObject for SyscallLogData<'a> { fn call( @@ -2376,6 +2561,12 @@ impl<'a> SyscallObject for SyscallLogData<'a> { .map_err(|_| SyscallError::InvokeContextBorrowFailed), result ); + let loader_id = question_mark!( + invoke_context + .get_loader() + .map_err(SyscallError::InstructionError), + result + ); let budget = invoke_context.get_compute_budget(); @@ -2387,7 +2578,7 @@ impl<'a> SyscallObject for SyscallLogData<'a> { ); let untranslated_fields = question_mark!( - translate_slice::<&[u8]>(memory_mapping, addr, len, self.loader_id), + translate_slice::<&[u8]>(memory_mapping, addr, len, &loader_id), result ); @@ -2416,7 +2607,7 @@ impl<'a> SyscallObject for SyscallLogData<'a> { memory_mapping, untranslated_field.as_ptr() as *const _ as u64, untranslated_field.len() as u64, - self.loader_id, + &loader_id, ), result )); @@ -2433,10 +2624,7 @@ impl<'a> SyscallObject for SyscallLogData<'a> { #[cfg(test)] mod tests { use super::*; - use solana_program_runtime::{ - invoke_context::{ComputeMeter, ThisInvokeContext}, - log_collector::LogCollector, - }; + use solana_program_runtime::invoke_context::ThisInvokeContext; use solana_rbpf::{ ebpf::HOST_ALIGN, memory_region::MemoryRegion, user_error::UserError, vm::Config, }; @@ -2556,8 +2744,7 @@ mod tests { assert_eq!(instruction, *translated_instruction); memory_mapping.resize_region::(1, 1).unwrap(); assert!( - translate_type::(&memory_mapping, 0x100000000, &bpf_loader::id(),) - .is_err() + translate_type::(&memory_mapping, 0x100000000, &bpf_loader::id()).is_err() ); } @@ -2660,7 +2847,7 @@ mod tests { data[0] = 10; assert_eq!(data, translated_data); assert!( - translate_slice::(&memory_mapping, 0x100000000, u64::MAX, &bpf_loader::id(),) + translate_slice::(&memory_mapping, 0x100000000, u64::MAX, &bpf_loader::id()) .is_err() ); @@ -2751,6 +2938,21 @@ mod tests { #[test] #[should_panic(expected = "UserError(SyscallError(Panic(\"Gaggablaghblagh!\", 42, 84)))")] fn test_syscall_sol_panic() { + let program_id = Pubkey::new_unique(); + let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader::id()); + let accounts = [(program_id, program_account)]; + let message = Message::new( + &[Instruction::new_with_bytes(program_id, &[], vec![])], + None, + ); + let mut invoke_context = ThisInvokeContext::new_mock(&accounts, &[]); + invoke_context + .push(&message, &message.instructions[0], &[0], None) + .unwrap(); + let mut syscall_panic = SyscallPanic { + invoke_context: Rc::new(RefCell::new(&mut invoke_context)), + }; + let string = "Gaggablaghblagh!"; let addr = string.as_ptr() as *const _ as u64; let config = Config::default(); @@ -2769,11 +2971,12 @@ mod tests { ) .unwrap(); - let compute_meter = ComputeMeter::new_ref(string.len() as u64 - 1); - let mut syscall_panic = SyscallPanic { - compute_meter, - loader_id: &bpf_loader::id(), - }; + syscall_panic + .invoke_context + .borrow_mut() + .get_compute_meter() + .borrow_mut() + .mock_set_remaining(string.len() as u64 - 1); let mut result: Result> = Ok(0); syscall_panic.call( 0x100000000, @@ -2791,11 +2994,12 @@ mod tests { result ); - let compute_meter = ComputeMeter::new_ref(string.len() as u64); - let mut syscall_panic = SyscallPanic { - compute_meter, - loader_id: &bpf_loader::id(), - }; + syscall_panic + .invoke_context + .borrow_mut() + .get_compute_meter() + .borrow_mut() + .mock_set_remaining(string.len() as u64); let mut result: Result> = Ok(0); syscall_panic.call( 0x100000000, @@ -2811,6 +3015,21 @@ mod tests { #[test] fn test_syscall_sol_log() { + let program_id = Pubkey::new_unique(); + let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader::id()); + let accounts = [(program_id, program_account)]; + let message = Message::new( + &[Instruction::new_with_bytes(program_id, &[], vec![])], + None, + ); + let mut invoke_context = ThisInvokeContext::new_mock(&accounts, &[]); + invoke_context + .push(&message, &message.instructions[0], &[0], None) + .unwrap(); + let mut syscall_sol_log = SyscallLog { + invoke_context: Rc::new(RefCell::new(&mut invoke_context)), + }; + let string = "Gaggablaghblagh!"; let addr = string.as_ptr() as *const _ as u64; let config = Config::default(); @@ -2828,39 +3047,13 @@ mod tests { &config, ) .unwrap(); - let log = LogCollector::new_ref(); - { - let mut syscall_sol_log = SyscallLog { - compute_meter: ComputeMeter::new_ref(string.len() as u64), - log_collector: Some(log.clone()), - loader_id: &bpf_loader::id(), - }; - let mut result: Result> = Ok(0); - syscall_sol_log.call( - 0x100000000, - string.len() as u64, - 0, - 0, - 0, - &memory_mapping, - &mut result, - ); - result.unwrap(); - } - - let log: Vec = match Rc::try_unwrap(log) { - Ok(log) => log.into_inner().into(), - Err(_) => panic!("Unwrap failed"), - }; - assert_eq!(log.len(), 1); - assert_eq!(log[0], "Program log: Gaggablaghblagh!"); - - let mut syscall_sol_log = SyscallLog { - compute_meter: ComputeMeter::new_ref(string.len() as u64 * 3), - log_collector: None, - loader_id: &bpf_loader::id(), - }; + syscall_sol_log + .invoke_context + .borrow_mut() + .get_compute_meter() + .borrow_mut() + .mock_set_remaining((string.len() as u64 * 5) - 1); let mut result: Result> = Ok(0); syscall_sol_log.call( 0x100000001, // AccessViolation @@ -2883,22 +3076,7 @@ mod tests { &mut result, ); assert_access_violation!(result, 0x100000000, string.len() as u64 * 2); - let mut result: Result> = Ok(0); - syscall_sol_log.call( - 0x100000000, - string.len() as u64, - 0, - 0, - 0, - &memory_mapping, - &mut result, - ); - let mut syscall_sol_log = SyscallLog { - compute_meter: ComputeMeter::new_ref((string.len() as u64 * 2) - 1), - log_collector: None, - loader_id: &bpf_loader::id(), - }; let mut result: Result> = Ok(0); syscall_sol_log.call( 0x100000000, @@ -2926,35 +3104,79 @@ mod tests { ))), result ); + + assert_eq!( + syscall_sol_log + .invoke_context + .borrow() + .get_log_collector() + .unwrap() + .borrow() + .get_recorded_content(), + &["Program log: Gaggablaghblagh!".to_string()] + ); } #[test] fn test_syscall_sol_log_u64() { - let log = LogCollector::new_ref(); - - { - let mut syscall_sol_log_u64 = SyscallLogU64 { - cost: 0, - compute_meter: ComputeMeter::new_ref(std::u64::MAX), - log_collector: Some(log.clone()), - }; - let config = Config::default(); - let memory_mapping = MemoryMapping::new::(vec![], &config).unwrap(); - let mut result: Result> = Ok(0); - syscall_sol_log_u64.call(1, 2, 3, 4, 5, &memory_mapping, &mut result); - result.unwrap(); - } - - let log: Vec = match Rc::try_unwrap(log) { - Ok(log) => log.into_inner().into(), - Err(_) => panic!("Unwrap failed"), + let program_id = Pubkey::new_unique(); + let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader::id()); + let accounts = [(program_id, program_account)]; + let message = Message::new( + &[Instruction::new_with_bytes(program_id, &[], vec![])], + None, + ); + let mut invoke_context = ThisInvokeContext::new_mock(&accounts, &[]); + invoke_context + .push(&message, &message.instructions[0], &[0], None) + .unwrap(); + let cost = invoke_context.get_compute_budget().log_64_units; + let mut syscall_sol_log_u64 = SyscallLogU64 { + invoke_context: Rc::new(RefCell::new(&mut invoke_context)), }; - assert_eq!(log.len(), 1); - assert_eq!(log[0], "Program log: 0x1, 0x2, 0x3, 0x4, 0x5"); + + syscall_sol_log_u64 + .invoke_context + .borrow_mut() + .get_compute_meter() + .borrow_mut() + .mock_set_remaining(cost); + let config = Config::default(); + let memory_mapping = MemoryMapping::new::(vec![], &config).unwrap(); + let mut result: Result> = Ok(0); + syscall_sol_log_u64.call(1, 2, 3, 4, 5, &memory_mapping, &mut result); + result.unwrap(); + + assert_eq!( + syscall_sol_log_u64 + .invoke_context + .borrow() + .get_log_collector() + .unwrap() + .borrow() + .get_recorded_content(), + &["Program log: 0x1, 0x2, 0x3, 0x4, 0x5".to_string()] + ); } #[test] fn test_syscall_sol_pubkey() { + let program_id = Pubkey::new_unique(); + let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader::id()); + let accounts = [(program_id, program_account)]; + let message = Message::new( + &[Instruction::new_with_bytes(program_id, &[], vec![])], + None, + ); + let mut invoke_context = ThisInvokeContext::new_mock(&accounts, &[]); + invoke_context + .push(&message, &message.instructions[0], &[0], None) + .unwrap(); + let cost = invoke_context.get_compute_budget().log_pubkey_units; + let mut syscall_sol_pubkey = SyscallLogPubkey { + invoke_context: Rc::new(RefCell::new(&mut invoke_context)), + }; + let pubkey = Pubkey::from_str("MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN").unwrap(); let addr = &pubkey.as_ref()[0] as *const _ as u64; let config = Config::default(); @@ -2972,36 +3194,7 @@ mod tests { &config, ) .unwrap(); - let log = LogCollector::new_ref(); - { - let mut syscall_sol_pubkey = SyscallLogPubkey { - cost: 1, - compute_meter: ComputeMeter::new_ref(1), - log_collector: Some(log.clone()), - loader_id: &bpf_loader::id(), - }; - let mut result: Result> = Ok(0); - syscall_sol_pubkey.call(0x100000000, 0, 0, 0, 0, &memory_mapping, &mut result); - result.unwrap(); - } - - let log: Vec = match Rc::try_unwrap(log) { - Ok(log) => log.into_inner().into(), - Err(_) => panic!("Unwrap failed"), - }; - assert_eq!(log.len(), 1); - assert_eq!( - log[0], - "Program log: MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN" - ); - - let mut syscall_sol_pubkey = SyscallLogPubkey { - cost: 1, - compute_meter: ComputeMeter::new_ref(1), - log_collector: None, - loader_id: &bpf_loader::id(), - }; let mut result: Result> = Ok(0); syscall_sol_pubkey.call( 0x100000001, // AccessViolation @@ -3013,6 +3206,13 @@ mod tests { &mut result, ); assert_access_violation!(result, 0x100000001, 32); + + syscall_sol_pubkey + .invoke_context + .borrow_mut() + .get_compute_meter() + .borrow_mut() + .mock_set_remaining(1); let mut result: Result> = Ok(0); syscall_sol_pubkey.call(100, 32, 0, 0, 0, &memory_mapping, &mut result); assert_eq!( @@ -3021,6 +3221,27 @@ mod tests { ))), result ); + + syscall_sol_pubkey + .invoke_context + .borrow_mut() + .get_compute_meter() + .borrow_mut() + .mock_set_remaining(cost); + let mut result: Result> = Ok(0); + syscall_sol_pubkey.call(0x100000000, 0, 0, 0, 0, &memory_mapping, &mut result); + result.unwrap(); + + assert_eq!( + syscall_sol_pubkey + .invoke_context + .borrow() + .get_log_collector() + .unwrap() + .borrow() + .get_recorded_content(), + &["Program log: MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN".to_string()] + ); } #[test] @@ -3151,6 +3372,15 @@ mod tests { #[test] fn test_syscall_sha256() { + let config = Config::default(); + let program_id = Pubkey::new_unique(); + let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader_deprecated::id()); + let accounts = [(program_id, program_account)]; + let message = Message::new( + &[Instruction::new_with_bytes(program_id, &[], vec![])], + None, + ); + let bytes1 = "Gaggablaghblagh!"; let bytes2 = "flurbos"; @@ -3167,7 +3397,6 @@ mod tests { let ro_len = bytes_to_hash.len() as u64; let ro_va = 0x100000000; let rw_va = 0x200000000; - let config = Config::default(); let memory_mapping = MemoryMapping::new::( vec![ MemoryRegion::default(), @@ -3203,12 +3432,22 @@ mod tests { &config, ) .unwrap(); - let compute_meter = ComputeMeter::new_ref((bytes1.len() + bytes2.len()) as u64); + + let mut invoke_context = ThisInvokeContext::new_mock(&accounts, &[]); + invoke_context + .get_compute_meter() + .borrow_mut() + .mock_set_remaining( + (invoke_context.get_compute_budget().sha256_base_cost + + (bytes1.len() + bytes2.len()) as u64 + * invoke_context.get_compute_budget().sha256_byte_cost) + * 4, + ); + invoke_context + .push(&message, &message.instructions[0], &[0], None) + .unwrap(); let mut syscall = SyscallSha256 { - sha256_base_cost: 0, - sha256_byte_cost: 2, - compute_meter, - loader_id: &bpf_loader_deprecated::id(), + invoke_context: Rc::new(RefCell::new(&mut invoke_context)), }; let mut result: Result> = Ok(0); @@ -3263,6 +3502,14 @@ mod tests { #[test] fn test_syscall_get_sysvar() { let config = Config::default(); + let program_id = Pubkey::new_unique(); + let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader::id()); + let accounts = [(program_id, program_account)]; + let message = Message::new( + &[Instruction::new_with_bytes(program_id, &[], vec![])], + None, + ); + // Test clock sysvar { let got_clock = Clock::default(); @@ -3294,18 +3541,19 @@ mod tests { bincode::serialize_into(&mut data, &src_clock).unwrap(); let sysvars = [(sysvar::clock::id(), data)]; let mut invoke_context = ThisInvokeContext::new_mock_with_sysvars_and_features( - &[], + &accounts, &[], &sysvars, Arc::new(FeatureSet::all_enabled()), ); - + invoke_context + .push(&message, &message.instructions[0], &[0], None) + .unwrap(); let mut syscall = SyscallGetClockSysvar { invoke_context: Rc::new(RefCell::new(&mut invoke_context)), - loader_id: &bpf_loader::id(), }; - let mut result: Result> = Ok(0); + let mut result: Result> = Ok(0); syscall.call(got_clock_va, 0, 0, 0, 0, &memory_mapping, &mut result); result.unwrap(); assert_eq!(got_clock, src_clock); @@ -3342,18 +3590,19 @@ mod tests { bincode::serialize_into(&mut data, &src_epochschedule).unwrap(); let sysvars = [(sysvar::epoch_schedule::id(), data)]; let mut invoke_context = ThisInvokeContext::new_mock_with_sysvars_and_features( - &[], + &accounts, &[], &sysvars, Arc::new(FeatureSet::all_enabled()), ); - + invoke_context + .push(&message, &message.instructions[0], &[0], None) + .unwrap(); let mut syscall = SyscallGetEpochScheduleSysvar { invoke_context: Rc::new(RefCell::new(&mut invoke_context)), - loader_id: &bpf_loader::id(), }; - let mut result: Result> = Ok(0); + let mut result: Result> = Ok(0); syscall.call( got_epochschedule_va, 0, @@ -3397,18 +3646,19 @@ mod tests { bincode::serialize_into(&mut data, &src_fees).unwrap(); let sysvars = [(sysvar::fees::id(), data)]; let mut invoke_context = ThisInvokeContext::new_mock_with_sysvars_and_features( - &[], + &accounts, &[], &sysvars, Arc::new(FeatureSet::all_enabled()), ); - + invoke_context + .push(&message, &message.instructions[0], &[0], None) + .unwrap(); let mut syscall = SyscallGetFeesSysvar { invoke_context: Rc::new(RefCell::new(&mut invoke_context)), - loader_id: &bpf_loader::id(), }; - let mut result: Result> = Ok(0); + let mut result: Result> = Ok(0); syscall.call(got_fees_va, 0, 0, 0, 0, &memory_mapping, &mut result); result.unwrap(); assert_eq!(got_fees, src_fees); @@ -3443,18 +3693,19 @@ mod tests { bincode::serialize_into(&mut data, &src_rent).unwrap(); let sysvars = [(sysvar::rent::id(), data)]; let mut invoke_context = ThisInvokeContext::new_mock_with_sysvars_and_features( - &[], + &accounts, &[], &sysvars, Arc::new(FeatureSet::all_enabled()), ); - + invoke_context + .push(&message, &message.instructions[0], &[0], None) + .unwrap(); let mut syscall = SyscallGetRentSysvar { invoke_context: Rc::new(RefCell::new(&mut invoke_context)), - loader_id: &bpf_loader::id(), }; - let mut result: Result> = Ok(0); + let mut result: Result> = Ok(0); syscall.call(got_rent_va, 0, 0, 0, 0, &memory_mapping, &mut result); result.unwrap(); assert_eq!(got_rent, src_rent); @@ -3551,50 +3802,61 @@ mod tests { } fn create_program_address( + invoke_context: &mut dyn InvokeContext, seeds: &[&[u8]], - program_id: &Pubkey, - remaining: u64, + address: &Pubkey, ) -> Result> { let mut syscall = SyscallCreateProgramAddress { - cost: 1, - compute_meter: ComputeMeter::new_ref(remaining), - loader_id: &bpf_loader::id(), + invoke_context: Rc::new(RefCell::new(invoke_context)), }; - let (address, _) = call_program_address_common(seeds, program_id, &mut syscall)?; + let (address, _) = call_program_address_common(seeds, address, &mut syscall)?; Ok(address) } fn try_find_program_address( + invoke_context: &mut dyn InvokeContext, seeds: &[&[u8]], - program_id: &Pubkey, - remaining: u64, + address: &Pubkey, ) -> Result<(Pubkey, u8), EbpfError> { let mut syscall = SyscallTryFindProgramAddress { - cost: 1, - compute_meter: ComputeMeter::new_ref(remaining), - loader_id: &bpf_loader::id(), + invoke_context: Rc::new(RefCell::new(invoke_context)), }; - call_program_address_common(seeds, program_id, &mut syscall) + call_program_address_common(seeds, address, &mut syscall) } #[test] fn test_create_program_address() { // These tests duplicate the direct tests in solana_program::pubkey - let program_id = Pubkey::from_str("BPFLoaderUpgradeab1e11111111111111111111111").unwrap(); + let program_id = Pubkey::new_unique(); + let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader::id()); + let accounts = [(program_id, program_account)]; + let message = Message::new( + &[Instruction::new_with_bytes(program_id, &[], vec![])], + None, + ); + let mut invoke_context = ThisInvokeContext::new_mock(&accounts, &[]); + invoke_context + .push(&message, &message.instructions[0], &[0], None) + .unwrap(); + let address = bpf_loader_upgradeable::id(); let exceeded_seed = &[127; MAX_SEED_LEN + 1]; - let result = create_program_address(&[exceeded_seed], &program_id, 1); + let result = create_program_address(&mut invoke_context, &[exceeded_seed], &address); assert_eq!( result, Err(SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded).into()) ); assert_eq!( - create_program_address(&[b"short_seed", exceeded_seed], &program_id, 1), + create_program_address( + &mut invoke_context, + &[b"short_seed", exceeded_seed], + &address, + ), Err(SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded).into()) ); let max_seed = &[0; MAX_SEED_LEN]; - assert!(create_program_address(&[max_seed], &program_id, 1).is_ok()); + assert!(create_program_address(&mut invoke_context, &[max_seed], &address).is_ok()); let exceeded_seeds: &[&[u8]] = &[ &[1], &[2], @@ -3613,7 +3875,7 @@ mod tests { &[15], &[16], ]; - assert!(create_program_address(exceeded_seeds, &program_id, 1).is_ok()); + assert!(create_program_address(&mut invoke_context, exceeded_seeds, &address).is_ok()); let max_seeds: &[&[u8]] = &[ &[1], &[2], @@ -3634,75 +3896,118 @@ mod tests { &[17], ]; assert_eq!( - create_program_address(max_seeds, &program_id, 1), + create_program_address(&mut invoke_context, max_seeds, &address), Err(SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded).into()) ); assert_eq!( - create_program_address(&[b"", &[1]], &program_id, 0), - Err( - SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded) - .into() - ) - ); - assert_eq!( - create_program_address(&[b"", &[1]], &program_id, 1), + create_program_address(&mut invoke_context, &[b"", &[1]], &address), Ok("BwqrghZA2htAcqq8dzP1WDAhTXYTYWj7CHxF5j7TDBAe" .parse() .unwrap()) ); assert_eq!( - create_program_address(&["☉".as_ref(), &[0]], &program_id, 1), + create_program_address(&mut invoke_context, &["☉".as_ref(), &[0]], &address), Ok("13yWmRpaTR4r5nAktwLqMpRNr28tnVUZw26rTvPSSB19" .parse() .unwrap()) ); assert_eq!( - create_program_address(&[b"Talking", b"Squirrels"], &program_id, 1), + create_program_address(&mut invoke_context, &[b"Talking", b"Squirrels"], &address), Ok("2fnQrngrQT4SeLcdToJAD96phoEjNL2man2kfRLCASVk" .parse() .unwrap()) ); let public_key = Pubkey::from_str("SeedPubey1111111111111111111111111111111111").unwrap(); assert_eq!( - create_program_address(&[public_key.as_ref(), &[1]], &program_id, 1), + create_program_address(&mut invoke_context, &[public_key.as_ref(), &[1]], &address), Ok("976ymqVnfE32QFe6NfGDctSvVa36LWnvYxhU6G2232YL" .parse() .unwrap()) ); assert_ne!( - create_program_address(&[b"Talking", b"Squirrels"], &program_id, 1).unwrap(), - create_program_address(&[b"Talking"], &program_id, 1).unwrap(), + create_program_address(&mut invoke_context, &[b"Talking", b"Squirrels"], &address) + .unwrap(), + create_program_address(&mut invoke_context, &[b"Talking"], &address).unwrap(), ); - } - - #[test] - fn test_find_program_address() { - for _ in 0..1_000 { - let program_id = Pubkey::new_unique(); - let (address, bump_seed) = - try_find_program_address(&[b"Lil'", b"Bits"], &program_id, 100).unwrap(); - assert_eq!( - address, - create_program_address(&[b"Lil'", b"Bits", &[bump_seed]], &program_id, 1).unwrap() - ); - } - - let program_id = Pubkey::from_str("BPFLoaderUpgradeab1e11111111111111111111111").unwrap(); - let max_tries = 256; // one per seed - let seeds: &[&[u8]] = &[b""]; - let (_, bump_seed) = try_find_program_address(seeds, &program_id, max_tries).unwrap(); - let remaining = 256 - bump_seed as u64; - let _ = try_find_program_address(seeds, &program_id, remaining).unwrap(); + invoke_context + .get_compute_meter() + .borrow_mut() + .mock_set_remaining(0); assert_eq!( - try_find_program_address(seeds, &program_id, remaining - 1), + create_program_address(&mut invoke_context, &[b"", &[1]], &address), Err( SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded) .into() ) ); - let exceeded_seed = &[127; MAX_SEED_LEN + 1]; + } + + #[test] + fn test_find_program_address() { + let program_id = Pubkey::new_unique(); + let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader::id()); + let accounts = [(program_id, program_account)]; + let message = Message::new( + &[Instruction::new_with_bytes(program_id, &[], vec![])], + None, + ); + let mut invoke_context = ThisInvokeContext::new_mock(&accounts, &[]); + invoke_context + .push(&message, &message.instructions[0], &[0], None) + .unwrap(); + let cost = invoke_context + .get_compute_budget() + .create_program_address_units; + let address = bpf_loader_upgradeable::id(); + + for _ in 0..1_000 { + let address = Pubkey::new_unique(); + let (found_address, bump_seed) = + try_find_program_address(&mut invoke_context, &[b"Lil'", b"Bits"], &address) + .unwrap(); + assert_eq!( + found_address, + create_program_address( + &mut invoke_context, + &[b"Lil'", b"Bits", &[bump_seed]], + &address, + ) + .unwrap() + ); + } + + let max_tries = 256; // one per seed + let seeds: &[&[u8]] = &[b""]; + invoke_context + .get_compute_meter() + .borrow_mut() + .mock_set_remaining(cost * max_tries); + let (_, bump_seed) = + try_find_program_address(&mut invoke_context, seeds, &address).unwrap(); + invoke_context + .get_compute_meter() + .borrow_mut() + .mock_set_remaining(cost * (max_tries - bump_seed as u64)); + try_find_program_address(&mut invoke_context, seeds, &address).unwrap(); + invoke_context + .get_compute_meter() + .borrow_mut() + .mock_set_remaining(cost * (max_tries - bump_seed as u64 - 1)); assert_eq!( - try_find_program_address(&[exceeded_seed], &program_id, max_tries - 1), + try_find_program_address(&mut invoke_context, seeds, &address), + Err( + SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded) + .into() + ) + ); + + let exceeded_seed = &[127; MAX_SEED_LEN + 1]; + invoke_context + .get_compute_meter() + .borrow_mut() + .mock_set_remaining(cost * (max_tries - 1)); + assert_eq!( + try_find_program_address(&mut invoke_context, &[exceeded_seed], &address), Err(SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded).into()) ); let exceeded_seeds: &[&[u8]] = &[ @@ -3724,8 +4029,12 @@ mod tests { &[16], &[17], ]; + invoke_context + .get_compute_meter() + .borrow_mut() + .mock_set_remaining(cost * (max_tries - 1)); assert_eq!( - try_find_program_address(exceeded_seeds, &program_id, max_tries - 1), + try_find_program_address(&mut invoke_context, exceeded_seeds, &address), Err(SyscallError::BadSeeds(PubkeyError::MaxSeedLengthExceeded).into()) ); } diff --git a/rbpf-cli/src/main.rs b/rbpf-cli/src/main.rs index 96b32c58fc..77ae7961ee 100644 --- a/rbpf-cli/src/main.rs +++ b/rbpf-cli/src/main.rs @@ -269,9 +269,7 @@ native machine code before execting it in the virtual machine.", _ => {} } - let id = bpf_loader::id(); let mut vm = create_vm( - &id, &executable, parameter_bytes.as_slice_mut(), &mut invoke_context,