From a5c7c999e2060971d9369bde13e05247c9ddd415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Fri, 20 Oct 2023 21:39:50 +0200 Subject: [PATCH] Bump solana_rbpf to v0.8.0 (#33679) * Bumps solana_rbpf to v0.8.0 * Adjustments: Replaces declare_syscall!() with declare_builtin_function!(). Removes Config::encrypt_runtime_environment. Simplifies error propagation. --- Cargo.lock | 5 +- Cargo.toml | 2 +- ledger/src/blockstore_processor.rs | 8 +- program-runtime/src/invoke_context.rs | 125 +-- program-runtime/src/loaded_programs.rs | 13 +- program-runtime/src/message_processor.rs | 12 +- program-runtime/src/stable_log.rs | 4 +- program-test/Cargo.toml | 1 + program-test/src/lib.rs | 56 +- .../tests/common.rs | 7 +- .../tests/create_lookup_table_ix.rs | 7 +- .../address-lookup-table/src/processor.rs | 38 +- programs/bpf-loader-tests/tests/common.rs | 3 +- programs/bpf_loader/src/lib.rs | 61 +- programs/bpf_loader/src/syscalls/cpi.rs | 12 +- programs/bpf_loader/src/syscalls/logging.rs | 22 +- programs/bpf_loader/src/syscalls/mem_ops.rs | 59 +- programs/bpf_loader/src/syscalls/mod.rs | 545 +++++-------- programs/bpf_loader/src/syscalls/sysvar.rs | 26 +- programs/compute-budget/src/lib.rs | 12 +- programs/config/src/config_processor.rs | 230 +++--- programs/loader-v4/src/lib.rs | 43 +- programs/sbf/Cargo.lock | 5 +- programs/sbf/Cargo.toml | 2 +- programs/sbf/tests/programs.rs | 6 +- programs/stake/src/stake_instruction.rs | 722 +++++++++--------- programs/system/src/system_processor.rs | 460 ++++++----- programs/vote/benches/process_vote.rs | 2 +- programs/vote/src/vote_processor.rs | 363 +++++---- programs/zk-token-proof/src/lib.rs | 2 +- runtime/benches/bank.rs | 4 +- runtime/src/bank.rs | 6 +- runtime/src/bank/tests.rs | 90 +-- runtime/src/builtins.rs | 30 +- 34 files changed, 1387 insertions(+), 1596 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9a425d81d3..6de911a6b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6640,6 +6640,7 @@ dependencies = [ "solana-sdk", "solana-stake-program", "solana-vote-program", + "solana_rbpf", "test-case", "thiserror", "tokio", @@ -7625,9 +7626,9 @@ dependencies = [ [[package]] name = "solana_rbpf" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "103318aa365ff7caa8cf534f2246b5eb7e5b34668736d52b1266b143f7a21196" +checksum = "3d457cc2ba742c120492a64b7fa60e22c575e891f6b55039f4d736568fb112a3" dependencies = [ "byteorder", "combine", diff --git a/Cargo.toml b/Cargo.toml index abb304ca6d..c17d544402 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -378,7 +378,7 @@ solana-wen-restart = { path = "wen-restart", version = "=1.18.0" } solana-zk-keygen = { path = "zk-keygen", version = "=1.18.0" } solana-zk-token-proof-program = { path = "programs/zk-token-proof", version = "=1.18.0" } solana-zk-token-sdk = { path = "zk-token-sdk", version = "=1.18.0" } -solana_rbpf = "=0.7.2" +solana_rbpf = "=0.8.0" spl-associated-token-account = "=2.2.0" spl-instruction-padding = "0.1" spl-memo = "=4.0.0" diff --git a/ledger/src/blockstore_processor.rs b/ledger/src/blockstore_processor.rs index 10ff57a120..e17bc52a88 100644 --- a/ledger/src/blockstore_processor.rs +++ b/ledger/src/blockstore_processor.rs @@ -2994,7 +2994,7 @@ pub mod tests { ] } - declare_process_instruction!(mock_processor_ok, 1, |_invoke_context| { + declare_process_instruction!(MockBuiltinOk, 1, |_invoke_context| { // Always succeeds Ok(()) }); @@ -3002,7 +3002,7 @@ pub mod tests { let mock_program_id = solana_sdk::pubkey::new_rand(); let mut bank = Bank::new_for_tests(&genesis_config); - bank.add_mockup_builtin(mock_program_id, mock_processor_ok); + bank.add_mockup_builtin(mock_program_id, MockBuiltinOk::vm); let tx = Transaction::new_signed_with_payer( &[Instruction::new_with_bincode( @@ -3023,7 +3023,7 @@ pub mod tests { let bankhash_ok = bank.hash(); assert!(result.is_ok()); - declare_process_instruction!(mock_processor_err, 1, |invoke_context| { + declare_process_instruction!(MockBuiltinErr, 1, |invoke_context| { let instruction_errors = get_instruction_errors(); let err = invoke_context @@ -3043,7 +3043,7 @@ pub mod tests { (0..get_instruction_errors().len()).for_each(|err| { let mut bank = Bank::new_for_tests(&genesis_config); - bank.add_mockup_builtin(mock_program_id, mock_processor_err); + bank.add_mockup_builtin(mock_program_id, MockBuiltinErr::vm); let tx = Transaction::new_signed_with_payer( &[Instruction::new_with_bincode( diff --git a/program-runtime/src/invoke_context.rs b/program-runtime/src/invoke_context.rs index 9fbe42d8d4..be95fca637 100644 --- a/program-runtime/src/invoke_context.rs +++ b/program-runtime/src/invoke_context.rs @@ -12,9 +12,10 @@ use { solana_measure::measure::Measure, solana_rbpf::{ ebpf::MM_HEAP_START, - elf::SBPFVersion, + error::{EbpfError, ProgramResult}, memory_region::MemoryMapping, - vm::{BuiltinFunction, Config, ContextObject, ProgramResult}, + program::{BuiltinFunction, SBPFVersion}, + vm::{Config, ContextObject, EbpfVm}, }, solana_sdk::{ account::AccountSharedData, @@ -39,44 +40,46 @@ use { }, }; -pub type ProcessInstructionWithContext = BuiltinFunction>; +pub type BuiltinFunctionWithContext = BuiltinFunction>; /// Adapter so we can unify the interfaces of built-in programs and syscalls #[macro_export] macro_rules! declare_process_instruction { ($process_instruction:ident, $cu_to_consume:expr, |$invoke_context:ident| $inner:tt) => { - pub fn $process_instruction( - invoke_context: &mut $crate::invoke_context::InvokeContext, - _arg0: u64, - _arg1: u64, - _arg2: u64, - _arg3: u64, - _arg4: u64, - _memory_mapping: &mut $crate::solana_rbpf::memory_region::MemoryMapping, - result: &mut $crate::solana_rbpf::vm::ProgramResult, - ) { - fn process_instruction_inner( - $invoke_context: &mut $crate::invoke_context::InvokeContext, - ) -> std::result::Result<(), solana_sdk::instruction::InstructionError> { - $inner + $crate::solana_rbpf::declare_builtin_function!( + $process_instruction, + fn rust( + invoke_context: &mut $crate::invoke_context::InvokeContext, + _arg0: u64, + _arg1: u64, + _arg2: u64, + _arg3: u64, + _arg4: u64, + _memory_mapping: &mut $crate::solana_rbpf::memory_region::MemoryMapping, + ) -> std::result::Result> { + fn process_instruction_inner( + $invoke_context: &mut $crate::invoke_context::InvokeContext, + ) -> std::result::Result<(), solana_sdk::instruction::InstructionError> { + $inner + } + let consumption_result = if $cu_to_consume > 0 + && invoke_context + .feature_set + .is_active(&solana_sdk::feature_set::native_programs_consume_cu::id()) + { + invoke_context.consume_checked($cu_to_consume) + } else { + Ok(()) + }; + consumption_result + .and_then(|_| { + process_instruction_inner(invoke_context) + .map(|_| 0) + .map_err(|err| Box::new(err) as Box) + }) + .into() } - let consumption_result = if $cu_to_consume > 0 - && invoke_context - .feature_set - .is_active(&solana_sdk::feature_set::native_programs_consume_cu::id()) - { - invoke_context.consume_checked($cu_to_consume) - } else { - Ok(()) - }; - *result = consumption_result - .and_then(|_| { - process_instruction_inner(invoke_context) - .map(|_| 0) - .map_err(|err| Box::new(err) as Box) - }) - .into(); - } + ); }; } @@ -468,11 +471,11 @@ impl<'a> InvokeContext<'a> { .programs_loaded_for_tx_batch .find(&builtin_id) .ok_or(InstructionError::UnsupportedProgramId)?; - let process_instruction = match &entry.program { + let function = match &entry.program { LoadedProgramType::Builtin(program) => program .get_function_registry() .lookup_by_key(ENTRYPOINT_KEY) - .map(|(_name, process_instruction)| process_instruction), + .map(|(_name, function)| function), _ => None, } .ok_or(InstructionError::UnsupportedProgramId)?; @@ -484,31 +487,41 @@ impl<'a> InvokeContext<'a> { let logger = self.get_log_collector(); stable_log::program_invoke(&logger, &program_id, self.get_stack_height()); let pre_remaining_units = self.get_remaining(); + // In program-runtime v2 we will create this VM instance only once per transaction. + // `program_runtime_environment_v2.get_config()` will be used instead of `mock_config`. + // For now, only built-ins are invoked from here, so the VM and its Config are irrelevant. let mock_config = Config::default(); - let mut mock_memory_mapping = - MemoryMapping::new(Vec::new(), &mock_config, &SBPFVersion::V2).unwrap(); - let mut result = ProgramResult::Ok(0); - process_instruction( + let empty_memory_mapping = + MemoryMapping::new(Vec::new(), &mock_config, &SBPFVersion::V1).unwrap(); + let mut vm = EbpfVm::new( + self.programs_loaded_for_tx_batch + .environments + .program_runtime_v2 + .clone(), + &SBPFVersion::V1, // Removes lifetime tracking unsafe { std::mem::transmute::<&mut InvokeContext, &mut InvokeContext>(self) }, + empty_memory_mapping, 0, - 0, - 0, - 0, - 0, - &mut mock_memory_mapping, - &mut result, ); - let result = match result { + vm.invoke_function(function); + let result = match vm.program_result { ProgramResult::Ok(_) => { stable_log::program_success(&logger, &program_id); Ok(()) } - ProgramResult::Err(err) => { - stable_log::program_failure(&logger, &program_id, err.as_ref()); - if let Some(err) = err.downcast_ref::() { - Err(err.clone()) + ProgramResult::Err(ref err) => { + if let EbpfError::SyscallError(syscall_error) = err { + if let Some(instruction_err) = syscall_error.downcast_ref::() + { + stable_log::program_failure(&logger, &program_id, instruction_err); + Err(instruction_err.clone()) + } else { + stable_log::program_failure(&logger, &program_id, syscall_error); + Err(InstructionError::ProgramFailedToComplete) + } } else { + stable_log::program_failure(&logger, &program_id, err); Err(InstructionError::ProgramFailedToComplete) } } @@ -699,7 +712,7 @@ pub fn mock_process_instruction, instruction_account_metas: Vec, expected_result: Result<(), InstructionError>, - process_instruction: ProcessInstructionWithContext, + builtin_function: BuiltinFunctionWithContext, mut pre_adjustments: F, mut post_adjustments: G, ) -> Vec { @@ -734,7 +747,7 @@ pub fn mock_process_instruction Self { let mut function_registry = FunctionRegistry::default(); function_registry - .register_function_hashed(*b"entrypoint", entrypoint) + .register_function_hashed(*b"entrypoint", builtin_function) .unwrap(); Self { deployment_slot, @@ -949,7 +950,7 @@ mod tests { }, assert_matches::assert_matches, percentage::Percentage, - solana_rbpf::vm::BuiltinProgram, + solana_rbpf::program::BuiltinProgram, solana_sdk::{ clock::{Epoch, Slot}, pubkey::Pubkey, diff --git a/program-runtime/src/message_processor.rs b/program-runtime/src/message_processor.rs index 6b3727e6a8..e3a0dabd8d 100644 --- a/program-runtime/src/message_processor.rs +++ b/program-runtime/src/message_processor.rs @@ -220,7 +220,7 @@ mod tests { ChangeData { data: u8 }, } - declare_process_instruction!(process_instruction, 1, |invoke_context| { + declare_process_instruction!(MockBuiltin, 1, |invoke_context| { let transaction_context = &invoke_context.transaction_context; let instruction_context = transaction_context.get_current_instruction_context()?; let instruction_data = instruction_context.get_instruction_data(); @@ -271,7 +271,7 @@ mod tests { let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default(); programs_loaded_for_tx_batch.replenish( mock_system_program_id, - Arc::new(LoadedProgram::new_builtin(0, 0, process_instruction)), + Arc::new(LoadedProgram::new_builtin(0, 0, MockBuiltin::vm)), ); let account_keys = (0..transaction_context.get_number_of_accounts()) .map(|index| { @@ -432,7 +432,7 @@ mod tests { DoWork { lamports: u64, data: u8 }, } - declare_process_instruction!(process_instruction, 1, |invoke_context| { + declare_process_instruction!(MockBuiltin, 1, |invoke_context| { let transaction_context = &invoke_context.transaction_context; let instruction_context = transaction_context.get_current_instruction_context()?; let instruction_data = instruction_context.get_instruction_data(); @@ -500,7 +500,7 @@ mod tests { let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default(); programs_loaded_for_tx_batch.replenish( mock_program_id, - Arc::new(LoadedProgram::new_builtin(0, 0, process_instruction)), + Arc::new(LoadedProgram::new_builtin(0, 0, MockBuiltin::vm)), ); let account_metas = vec![ AccountMeta::new( @@ -645,7 +645,7 @@ mod tests { #[test] fn test_precompile() { let mock_program_id = Pubkey::new_unique(); - declare_process_instruction!(process_instruction, 1, |_invoke_context| { + declare_process_instruction!(MockBuiltin, 1, |_invoke_context| { Err(InstructionError::Custom(0xbabb1e)) }); @@ -684,7 +684,7 @@ mod tests { let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default(); programs_loaded_for_tx_batch.replenish( mock_program_id, - Arc::new(LoadedProgram::new_builtin(0, 0, process_instruction)), + Arc::new(LoadedProgram::new_builtin(0, 0, MockBuiltin::vm)), ); let mut programs_modified_by_tx = LoadedProgramsForTxBatch::default(); let mut programs_updated_only_for_global_cache = LoadedProgramsForTxBatch::default(); diff --git a/program-runtime/src/stable_log.rs b/program-runtime/src/stable_log.rs index 9ba7542e9c..748c4d7639 100644 --- a/program-runtime/src/stable_log.rs +++ b/program-runtime/src/stable_log.rs @@ -101,10 +101,10 @@ pub fn program_success(log_collector: &Option>>, progra /// ```notrust /// "Program
failed: " /// ``` -pub fn program_failure( +pub fn program_failure( log_collector: &Option>>, program_id: &Pubkey, - err: &dyn std::error::Error, + err: &E, ) { ic_logger_msg!(log_collector, "Program {} failed: {}", program_id, err); } diff --git a/program-test/Cargo.toml b/program-test/Cargo.toml index 87a9c88487..c4ab4507b2 100644 --- a/program-test/Cargo.toml +++ b/program-test/Cargo.toml @@ -27,6 +27,7 @@ solana-program-runtime = { workspace = true } solana-runtime = { workspace = true } solana-sdk = { workspace = true } solana-vote-program = { workspace = true } +solana_rbpf = { workspace = true } test-case = { workspace = true } thiserror = { workspace = true } tokio = { workspace = true, features = ["full"] } diff --git a/program-test/src/lib.rs b/program-test/src/lib.rs index 3c26ac25da..95b9e6103d 100644 --- a/program-test/src/lib.rs +++ b/program-test/src/lib.rs @@ -13,7 +13,7 @@ use { solana_banks_server::banks_server::start_local_server, solana_bpf_loader_program::serialization::serialize_parameters, solana_program_runtime::{ - compute_budget::ComputeBudget, ic_msg, invoke_context::ProcessInstructionWithContext, + compute_budget::ComputeBudget, ic_msg, invoke_context::BuiltinFunctionWithContext, loaded_programs::LoadedProgram, stable_log, timings::ExecuteTimings, }, solana_runtime::{ @@ -66,6 +66,10 @@ pub use { solana_banks_client::{BanksClient, BanksClientError}, solana_banks_interface::BanksTransactionResultWithMetadata, solana_program_runtime::invoke_context::InvokeContext, + solana_rbpf::{ + error::EbpfError, + vm::{get_runtime_environment_key, EbpfVm}, + }, solana_sdk::transaction_context::IndexOfAccount, }; @@ -94,10 +98,10 @@ fn get_invoke_context<'a, 'b>() -> &'a mut InvokeContext<'b> { unsafe { transmute::(ptr) } } -pub fn builtin_process_instruction( - process_instruction: solana_sdk::entrypoint::ProcessInstruction, +pub fn invoke_builtin_function( + builtin_function: solana_sdk::entrypoint::ProcessInstruction, invoke_context: &mut InvokeContext, -) -> Result<(), Box> { +) -> Result> { set_invoke_context(invoke_context); let transaction_context = &invoke_context.transaction_context; @@ -130,9 +134,10 @@ pub fn builtin_process_instruction( unsafe { deserialize(&mut parameter_bytes.as_slice_mut()[0] as *mut u8) }; // Execute the program - process_instruction(program_id, &account_infos, instruction_data).map_err(|err| { - let err: Box = Box::new(InstructionError::from(u64::from(err))); - stable_log::program_failure(&log_collector, program_id, err.as_ref()); + builtin_function(program_id, &account_infos, instruction_data).map_err(|err| { + let err = InstructionError::from(u64::from(err)); + stable_log::program_failure(&log_collector, program_id, &err); + let err: Box = Box::new(err); err })?; stable_log::program_success(&log_collector, program_id); @@ -169,21 +174,24 @@ pub fn builtin_process_instruction( } } - Ok(()) + Ok(0) } /// Converts a `solana-program`-style entrypoint into the runtime's entrypoint style, for /// use with `ProgramTest::add_program` #[macro_export] macro_rules! processor { - ($process_instruction:expr) => { - Some( - |invoke_context, _arg0, _arg1, _arg2, _arg3, _arg4, _memory_mapping, result| { - *result = $crate::builtin_process_instruction($process_instruction, invoke_context) - .map(|_| 0) + ($builtin_function:expr) => { + Some(|vm, _arg0, _arg1, _arg2, _arg3, _arg4| { + let vm = unsafe { + &mut *((vm as *mut u64).offset(-($crate::get_runtime_environment_key() as isize)) + as *mut $crate::EbpfVm<$crate::InvokeContext>) + }; + vm.program_result = + $crate::invoke_builtin_function($builtin_function, vm.context_object_pointer) + .map_err(|err| $crate::EbpfError::SyscallError(err)) .into(); - }, - ) + }) }; } @@ -506,10 +514,10 @@ impl ProgramTest { pub fn new( program_name: &str, program_id: Pubkey, - process_instruction: Option, + builtin_function: Option, ) -> Self { let mut me = Self::default(); - me.add_program(program_name, program_id, process_instruction); + me.add_program(program_name, program_id, builtin_function); me } @@ -600,13 +608,13 @@ impl ProgramTest { /// `program_name` will also be used to locate the SBF shared object in the current or fixtures /// directory. /// - /// If `process_instruction` is provided, the natively built-program may be used instead of the + /// If `builtin_function` is provided, the natively built-program may be used instead of the /// SBF shared object depending on the `BPF_OUT_DIR` environment variable. pub fn add_program( &mut self, program_name: &str, program_id: Pubkey, - process_instruction: Option, + builtin_function: Option, ) { let add_bpf = |this: &mut ProgramTest, program_file: PathBuf| { let data = read_file(&program_file); @@ -680,7 +688,7 @@ impl ProgramTest { }; let program_file = find_file(&format!("{program_name}.so")); - match (self.prefer_bpf, program_file, process_instruction) { + match (self.prefer_bpf, program_file, builtin_function) { // If SBF is preferred (i.e., `test-sbf` is invoked) and a BPF shared object exists, // use that as the program data. (true, Some(file), _) => add_bpf(self, file), @@ -689,8 +697,8 @@ impl ProgramTest { // processor function as is. // // TODO: figure out why tests hang if a processor panics when running native code. - (false, _, Some(process)) => { - self.add_builtin_program(program_name, program_id, process) + (false, _, Some(builtin_function)) => { + self.add_builtin_program(program_name, program_id, builtin_function) } // Invalid: `test-sbf` invocation with no matching SBF shared object. @@ -713,13 +721,13 @@ impl ProgramTest { &mut self, program_name: &str, program_id: Pubkey, - process_instruction: ProcessInstructionWithContext, + builtin_function: BuiltinFunctionWithContext, ) { info!("\"{}\" builtin program", program_name); self.builtin_programs.push(( program_id, program_name.to_string(), - LoadedProgram::new_builtin(0, program_name.len(), process_instruction), + LoadedProgram::new_builtin(0, program_name.len(), builtin_function), )); } diff --git a/programs/address-lookup-table-tests/tests/common.rs b/programs/address-lookup-table-tests/tests/common.rs index 48b8019931..064244858c 100644 --- a/programs/address-lookup-table-tests/tests/common.rs +++ b/programs/address-lookup-table-tests/tests/common.rs @@ -1,6 +1,5 @@ #![allow(dead_code)] use { - solana_address_lookup_table_program::processor::process_instruction, solana_program_test::*, solana_sdk::{ account::AccountSharedData, @@ -20,7 +19,11 @@ use { }; pub async fn setup_test_context() -> ProgramTestContext { - let program_test = ProgramTest::new("", id(), Some(process_instruction)); + let program_test = ProgramTest::new( + "", + id(), + Some(solana_address_lookup_table_program::processor::Entrypoint::vm), + ); program_test.start_with_context().await } diff --git a/programs/address-lookup-table-tests/tests/create_lookup_table_ix.rs b/programs/address-lookup-table-tests/tests/create_lookup_table_ix.rs index 183de53e31..39ff9aea66 100644 --- a/programs/address-lookup-table-tests/tests/create_lookup_table_ix.rs +++ b/programs/address-lookup-table-tests/tests/create_lookup_table_ix.rs @@ -1,7 +1,6 @@ use { assert_matches::assert_matches, common::{assert_ix_error, overwrite_slot_hashes_with_slots, setup_test_context}, - solana_address_lookup_table_program::processor::process_instruction, solana_program_test::*, solana_sdk::{ address_lookup_table::{ @@ -23,7 +22,11 @@ use { mod common; pub async fn setup_test_context_without_authority_feature() -> ProgramTestContext { - let mut program_test = ProgramTest::new("", id(), Some(process_instruction)); + let mut program_test = ProgramTest::new( + "", + id(), + Some(solana_address_lookup_table_program::processor::Entrypoint::vm), + ); program_test.deactivate_feature( feature_set::relax_authority_signer_check_for_lookup_table_creation::id(), ); diff --git a/programs/address-lookup-table/src/processor.rs b/programs/address-lookup-table/src/processor.rs index 6f71b293d0..4db568c71a 100644 --- a/programs/address-lookup-table/src/processor.rs +++ b/programs/address-lookup-table/src/processor.rs @@ -21,29 +21,25 @@ use { pub const DEFAULT_COMPUTE_UNITS: u64 = 750; -declare_process_instruction!( - process_instruction, - DEFAULT_COMPUTE_UNITS, - |invoke_context| { - let transaction_context = &invoke_context.transaction_context; - let instruction_context = transaction_context.get_current_instruction_context()?; - let instruction_data = instruction_context.get_instruction_data(); - match limited_deserialize(instruction_data)? { - ProgramInstruction::CreateLookupTable { - recent_slot, - bump_seed, - } => Processor::create_lookup_table(invoke_context, recent_slot, bump_seed), - ProgramInstruction::FreezeLookupTable => Processor::freeze_lookup_table(invoke_context), - ProgramInstruction::ExtendLookupTable { new_addresses } => { - Processor::extend_lookup_table(invoke_context, new_addresses) - } - ProgramInstruction::DeactivateLookupTable => { - Processor::deactivate_lookup_table(invoke_context) - } - ProgramInstruction::CloseLookupTable => Processor::close_lookup_table(invoke_context), +declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| { + let transaction_context = &invoke_context.transaction_context; + let instruction_context = transaction_context.get_current_instruction_context()?; + let instruction_data = instruction_context.get_instruction_data(); + match limited_deserialize(instruction_data)? { + ProgramInstruction::CreateLookupTable { + recent_slot, + bump_seed, + } => Processor::create_lookup_table(invoke_context, recent_slot, bump_seed), + ProgramInstruction::FreezeLookupTable => Processor::freeze_lookup_table(invoke_context), + ProgramInstruction::ExtendLookupTable { new_addresses } => { + Processor::extend_lookup_table(invoke_context, new_addresses) } + ProgramInstruction::DeactivateLookupTable => { + Processor::deactivate_lookup_table(invoke_context) + } + ProgramInstruction::CloseLookupTable => Processor::close_lookup_table(invoke_context), } -); +}); fn checked_add(a: usize, b: usize) -> Result { a.checked_add(b).ok_or(InstructionError::ArithmeticOverflow) diff --git a/programs/bpf-loader-tests/tests/common.rs b/programs/bpf-loader-tests/tests/common.rs index eeaf957a7e..99cae212c7 100644 --- a/programs/bpf-loader-tests/tests/common.rs +++ b/programs/bpf-loader-tests/tests/common.rs @@ -1,7 +1,6 @@ #![allow(dead_code)] use { - solana_bpf_loader_program::process_instruction, solana_program_test::*, solana_sdk::{ account::AccountSharedData, @@ -15,7 +14,7 @@ use { }; pub async fn setup_test_context() -> ProgramTestContext { - let program_test = ProgramTest::new("", id(), Some(process_instruction)); + let program_test = ProgramTest::new("", id(), Some(solana_bpf_loader_program::Entrypoint::vm)); program_test.start_with_context().await } diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 8e4ead1bf3..dd944b7c8a 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -18,12 +18,14 @@ use { }, solana_rbpf::{ aligned_memory::AlignedMemory, + declare_builtin_function, ebpf::{self, HOST_ALIGN, MM_HEAP_START}, elf::Executable, - error::EbpfError, + error::{EbpfError, ProgramResult}, memory_region::{AccessType, MemoryCowCallback, MemoryMapping, MemoryRegion}, + program::BuiltinProgram, verifier::RequisiteVerifier, - vm::{BuiltinProgram, ContextObject, EbpfVm, ProgramResult}, + vm::{ContextObject, EbpfVm}, }, solana_sdk::{ account::WritableAccount, @@ -265,7 +267,7 @@ pub fn create_vm<'a, 'b>( trace_log: Vec::new(), })?; Ok(EbpfVm::new( - program.get_config(), + program.get_loader().clone(), program.get_sbpf_version(), invoke_context, memory_mapping, @@ -317,7 +319,7 @@ macro_rules! create_vm { macro_rules! mock_create_vm { ($vm:ident, $additional_regions:expr, $accounts_metadata:expr, $invoke_context:expr $(,)?) => { let loader = std::sync::Arc::new(BuiltinProgram::new_mock()); - let function_registry = solana_rbpf::elf::FunctionRegistry::default(); + let function_registry = solana_rbpf::program::FunctionRegistry::default(); let executable = solana_rbpf::elf::Executable::::from_text_bytes( &[0x95, 0, 0, 0, 0, 0, 0, 0], loader, @@ -371,20 +373,22 @@ fn create_memory_mapping<'a, 'b, C: ContextObject>( }) } -pub fn process_instruction( - invoke_context: &mut InvokeContext, - _arg0: u64, - _arg1: u64, - _arg2: u64, - _arg3: u64, - _arg4: u64, - _memory_mapping: &mut MemoryMapping, - result: &mut ProgramResult, -) { - *result = process_instruction_inner(invoke_context).into(); -} +declare_builtin_function!( + Entrypoint, + fn rust( + invoke_context: &mut InvokeContext, + _arg0: u64, + _arg1: u64, + _arg2: u64, + _arg3: u64, + _arg4: u64, + _memory_mapping: &mut MemoryMapping, + ) -> Result> { + process_instruction_inner(invoke_context) + } +); -fn process_instruction_inner( +pub fn process_instruction_inner( invoke_context: &mut InvokeContext, ) -> Result> { let log_collector = invoke_context.get_log_collector(); @@ -1607,13 +1611,12 @@ fn execute<'a, 'b: 'a>( } ProgramResult::Err(mut error) => { if direct_mapping { - if let Some(EbpfError::AccessViolation( - _pc, + if let EbpfError::AccessViolation( AccessType::Store, address, _size, _section_name, - )) = error.downcast_ref() + ) = error { // If direct_mapping is enabled and a program tries to write to a readonly // region we'll get a memory access violation. Map it to a more specific @@ -1621,7 +1624,7 @@ fn execute<'a, 'b: 'a>( if let Some((instruction_account_index, _)) = account_region_addrs .iter() .enumerate() - .find(|(_, vm_region)| vm_region.contains(address)) + .find(|(_, vm_region)| vm_region.contains(&address)) { let transaction_context = &invoke_context.transaction_context; let instruction_context = @@ -1632,17 +1635,21 @@ fn execute<'a, 'b: 'a>( instruction_account_index as IndexOfAccount, )?; - error = Box::new(if account.is_executable() { + error = EbpfError::SyscallError(Box::new(if account.is_executable() { InstructionError::ExecutableDataModified } else if account.is_writable() { InstructionError::ExternalAccountDataModified } else { InstructionError::ReadonlyDataModified - }) + })); } } } - Err(error) + Err(if let EbpfError::SyscallError(err) = error { + err + } else { + error.into() + }) } _ => Ok(()), } @@ -1790,7 +1797,7 @@ mod tests { transaction_accounts, instruction_accounts, expected_result, - super::process_instruction, + Entrypoint::vm, |invoke_context| { test_utils::load_all_invoked_programs(invoke_context); }, @@ -2009,7 +2016,7 @@ mod tests { vec![(program_id, program_account.clone())], Vec::new(), Err(InstructionError::ProgramFailedToComplete), - super::process_instruction, + Entrypoint::vm, |invoke_context| { invoke_context.mock_set_remaining(0); test_utils::load_all_invoked_programs(invoke_context); @@ -2555,7 +2562,7 @@ mod tests { transaction_accounts, instruction_accounts, expected_result, - super::process_instruction, + Entrypoint::vm, |_invoke_context| {}, |_invoke_context| {}, ) diff --git a/programs/bpf_loader/src/syscalls/cpi.rs b/programs/bpf_loader/src/syscalls/cpi.rs index 79fc52c6ca..c2264b95c2 100644 --- a/programs/bpf_loader/src/syscalls/cpi.rs +++ b/programs/bpf_loader/src/syscalls/cpi.rs @@ -1,6 +1,6 @@ use { super::*, - crate::{declare_syscall, serialization::account_data_region_memory_state}, + crate::serialization::account_data_region_memory_state, scopeguard::defer, solana_program_runtime::invoke_context::SerializedAccountMetadata, solana_rbpf::{ @@ -455,10 +455,10 @@ trait SyscallInvokeSigned { ) -> Result, Error>; } -declare_syscall!( +declare_builtin_function!( /// Cross-program invocation called from Rust SyscallInvokeSignedRust, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, instruction_addr: u64, account_infos_addr: u64, @@ -689,10 +689,10 @@ struct SolSignerSeedsC { len: u64, } -declare_syscall!( +declare_builtin_function!( /// Cross-program invocation called from C SyscallInvokeSignedC, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, instruction_addr: u64, account_infos_addr: u64, @@ -1730,7 +1730,7 @@ mod tests { invoke_context::SerializedAccountMetadata, with_mock_invoke_context, }, solana_rbpf::{ - ebpf::MM_INPUT_START, elf::SBPFVersion, memory_region::MemoryRegion, vm::Config, + ebpf::MM_INPUT_START, memory_region::MemoryRegion, program::SBPFVersion, vm::Config, }, solana_sdk::{ account::{Account, AccountSharedData}, diff --git a/programs/bpf_loader/src/syscalls/logging.rs b/programs/bpf_loader/src/syscalls/logging.rs index f6d69153d2..c5faf0a105 100644 --- a/programs/bpf_loader/src/syscalls/logging.rs +++ b/programs/bpf_loader/src/syscalls/logging.rs @@ -1,9 +1,9 @@ -use {super::*, crate::declare_syscall, solana_rbpf::vm::ContextObject}; +use {super::*, solana_rbpf::vm::ContextObject}; -declare_syscall!( +declare_builtin_function!( /// Log a user's info message SyscallLog, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, addr: u64, len: u64, @@ -36,10 +36,10 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// Log 5 64-bit values SyscallLogU64, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, arg1: u64, arg2: u64, @@ -59,10 +59,10 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// Log current compute consumption SyscallLogBpfComputeUnits, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, _arg1: u64, _arg2: u64, @@ -83,10 +83,10 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// Log 5 64-bit values SyscallLogPubkey, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, pubkey_addr: u64, _arg2: u64, @@ -108,10 +108,10 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// Log data handling SyscallLogData, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, addr: u64, len: u64, diff --git a/programs/bpf_loader/src/syscalls/mem_ops.rs b/programs/bpf_loader/src/syscalls/mem_ops.rs index 93d5b69cec..9354270ac2 100644 --- a/programs/bpf_loader/src/syscalls/mem_ops.rs +++ b/programs/bpf_loader/src/syscalls/mem_ops.rs @@ -1,6 +1,5 @@ use { super::*, - crate::declare_syscall, solana_rbpf::{error::EbpfError, memory_region::MemoryRegion}, std::slice, }; @@ -14,10 +13,10 @@ fn mem_op_consume(invoke_context: &mut InvokeContext, n: u64) -> Result<(), Erro consume_compute_meter(invoke_context, cost) } -declare_syscall!( +declare_builtin_function!( /// memcpy SyscallMemcpy, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, dst_addr: u64, src_addr: u64, @@ -37,10 +36,10 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// memmove SyscallMemmove, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, dst_addr: u64, src_addr: u64, @@ -55,10 +54,10 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// memcmp SyscallMemcmp, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, s1_addr: u64, s2_addr: u64, @@ -113,10 +112,10 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// memset SyscallMemset, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, dst_addr: u64, c: u64, @@ -375,7 +374,6 @@ impl<'a> MemoryChunkIterator<'a> { len: u64, ) -> Result, EbpfError> { let vm_addr_end = vm_addr.checked_add(len).ok_or(EbpfError::AccessViolation( - 0, access_type, vm_addr, len, @@ -394,26 +392,19 @@ impl<'a> MemoryChunkIterator<'a> { fn region(&mut self, vm_addr: u64) -> Result<&'a MemoryRegion, Error> { match self.memory_mapping.region(self.access_type, vm_addr) { Ok(region) => Ok(region), - Err(error) => match error.downcast_ref() { - Some(EbpfError::AccessViolation(pc, access_type, _vm_addr, _len, name)) => { - Err(Box::new(EbpfError::AccessViolation( - *pc, - *access_type, - self.initial_vm_addr, - self.len, - name, - ))) - } - Some(EbpfError::StackAccessViolation(pc, access_type, _vm_addr, _len, frame)) => { + Err(error) => match error { + EbpfError::AccessViolation(access_type, _vm_addr, _len, name) => Err(Box::new( + EbpfError::AccessViolation(access_type, self.initial_vm_addr, self.len, name), + )), + EbpfError::StackAccessViolation(access_type, _vm_addr, _len, frame) => { Err(Box::new(EbpfError::StackAccessViolation( - *pc, - *access_type, + access_type, self.initial_vm_addr, self.len, - *frame, + frame, ))) } - _ => Err(error), + _ => Err(error.into()), }, } } @@ -489,7 +480,7 @@ mod tests { use { super::*, assert_matches::assert_matches, - solana_rbpf::{ebpf::MM_PROGRAM_START, elf::SBPFVersion}, + solana_rbpf::{ebpf::MM_PROGRAM_START, program::SBPFVersion}, }; fn to_chunk_vec<'a>( @@ -547,7 +538,7 @@ mod tests { .unwrap(); assert_matches!( src_chunk_iter.next().unwrap().unwrap_err().downcast_ref().unwrap(), - EbpfError::AccessViolation(0, AccessType::Load, addr, 42, "unknown") if *addr == MM_PROGRAM_START - 1 + EbpfError::AccessViolation(AccessType::Load, addr, 42, "unknown") if *addr == MM_PROGRAM_START - 1 ); // check oob at the upper bound. Since the memory mapping isn't empty, @@ -558,7 +549,7 @@ mod tests { assert!(src_chunk_iter.next().unwrap().is_ok()); assert_matches!( src_chunk_iter.next().unwrap().unwrap_err().downcast_ref().unwrap(), - EbpfError::AccessViolation(0, AccessType::Load, addr, 43, "program") if *addr == MM_PROGRAM_START + EbpfError::AccessViolation(AccessType::Load, addr, 43, "program") if *addr == MM_PROGRAM_START ); // check oob at the upper bound on the first next_back() @@ -568,7 +559,7 @@ mod tests { .rev(); assert_matches!( src_chunk_iter.next().unwrap().unwrap_err().downcast_ref().unwrap(), - EbpfError::AccessViolation(0, AccessType::Load, addr, 43, "program") if *addr == MM_PROGRAM_START + EbpfError::AccessViolation(AccessType::Load, addr, 43, "program") if *addr == MM_PROGRAM_START ); // check oob at the upper bound on the 2nd next_back() @@ -579,7 +570,7 @@ mod tests { assert!(src_chunk_iter.next().unwrap().is_ok()); assert_matches!( src_chunk_iter.next().unwrap().unwrap_err().downcast_ref().unwrap(), - EbpfError::AccessViolation(0, AccessType::Load, addr, 43, "unknown") if *addr == MM_PROGRAM_START - 1 + EbpfError::AccessViolation(AccessType::Load, addr, 43, "unknown") if *addr == MM_PROGRAM_START - 1 ); } @@ -707,7 +698,7 @@ mod tests { false, |_src, _dst, _len| Ok::<_, Error>(0), ).unwrap_err().downcast_ref().unwrap(), - EbpfError::AccessViolation(0, AccessType::Load, addr, 8, "program") if *addr == MM_PROGRAM_START + 8 + EbpfError::AccessViolation(AccessType::Load, addr, 8, "program") if *addr == MM_PROGRAM_START + 8 ); // src is shorter than dst @@ -722,12 +713,12 @@ mod tests { false, |_src, _dst, _len| Ok::<_, Error>(0), ).unwrap_err().downcast_ref().unwrap(), - EbpfError::AccessViolation(0, AccessType::Load, addr, 3, "program") if *addr == MM_PROGRAM_START + 10 + EbpfError::AccessViolation(AccessType::Load, addr, 3, "program") if *addr == MM_PROGRAM_START + 10 ); } #[test] - #[should_panic(expected = "AccessViolation(0, Store, 4294967296, 4")] + #[should_panic(expected = "AccessViolation(Store, 4294967296, 4")] fn test_memmove_non_contiguous_readonly() { let config = Config { aligned_memory_mapping: false, @@ -817,7 +808,7 @@ mod tests { } #[test] - #[should_panic(expected = "AccessViolation(0, Store, 4294967296, 9")] + #[should_panic(expected = "AccessViolation(Store, 4294967296, 9")] fn test_memset_non_contiguous_readonly() { let config = Config { aligned_memory_mapping: false, diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index 4193b9fcfc..5519ed3aa5 100644 --- a/programs/bpf_loader/src/syscalls/mod.rs +++ b/programs/bpf_loader/src/syscalls/mod.rs @@ -16,9 +16,10 @@ use { stable_log, timings::ExecuteTimings, }, solana_rbpf::{ - elf::FunctionRegistry, + declare_builtin_function, memory_region::{AccessType, MemoryMapping}, - vm::{BuiltinFunction, BuiltinProgram, Config, ProgramResult}, + program::{BuiltinFunction, BuiltinProgram, FunctionRegistry}, + vm::Config, }, solana_sdk::{ account::ReadableAccount, @@ -281,7 +282,6 @@ pub fn create_program_runtime_environment_v1<'a>( reject_broken_elfs: reject_deployment_of_broken_elfs, noop_instruction_rate: 256, sanitize_user_provided_values: true, - encrypt_runtime_environment: true, 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()), @@ -295,42 +295,42 @@ pub fn create_program_runtime_environment_v1<'a>( let mut result = FunctionRegistry::>::default(); // Abort - result.register_function_hashed(*b"abort", SyscallAbort::call)?; + result.register_function_hashed(*b"abort", SyscallAbort::vm)?; // Panic - result.register_function_hashed(*b"sol_panic_", SyscallPanic::call)?; + result.register_function_hashed(*b"sol_panic_", SyscallPanic::vm)?; // Logging - result.register_function_hashed(*b"sol_log_", SyscallLog::call)?; - result.register_function_hashed(*b"sol_log_64_", SyscallLogU64::call)?; - result.register_function_hashed(*b"sol_log_compute_units_", SyscallLogBpfComputeUnits::call)?; - result.register_function_hashed(*b"sol_log_pubkey", SyscallLogPubkey::call)?; + result.register_function_hashed(*b"sol_log_", SyscallLog::vm)?; + result.register_function_hashed(*b"sol_log_64_", SyscallLogU64::vm)?; + result.register_function_hashed(*b"sol_log_compute_units_", SyscallLogBpfComputeUnits::vm)?; + result.register_function_hashed(*b"sol_log_pubkey", SyscallLogPubkey::vm)?; // Program defined addresses (PDA) result.register_function_hashed( *b"sol_create_program_address", - SyscallCreateProgramAddress::call, + SyscallCreateProgramAddress::vm, )?; result.register_function_hashed( *b"sol_try_find_program_address", - SyscallTryFindProgramAddress::call, + SyscallTryFindProgramAddress::vm, )?; // Sha256 - result.register_function_hashed(*b"sol_sha256", SyscallHash::call::)?; + result.register_function_hashed(*b"sol_sha256", SyscallHash::vm::)?; // Keccak256 - result.register_function_hashed(*b"sol_keccak256", SyscallHash::call::)?; + result.register_function_hashed(*b"sol_keccak256", SyscallHash::vm::)?; // Secp256k1 Recover - result.register_function_hashed(*b"sol_secp256k1_recover", SyscallSecp256k1Recover::call)?; + result.register_function_hashed(*b"sol_secp256k1_recover", SyscallSecp256k1Recover::vm)?; // Blake3 register_feature_gated_function!( result, blake3_syscall_enabled, *b"sol_blake3", - SyscallHash::call::, + SyscallHash::vm::, )?; // Elliptic Curve Operations @@ -338,78 +338,78 @@ pub fn create_program_runtime_environment_v1<'a>( result, curve25519_syscall_enabled, *b"sol_curve_validate_point", - SyscallCurvePointValidation::call, + SyscallCurvePointValidation::vm, )?; register_feature_gated_function!( result, curve25519_syscall_enabled, *b"sol_curve_group_op", - SyscallCurveGroupOps::call, + SyscallCurveGroupOps::vm, )?; register_feature_gated_function!( result, curve25519_syscall_enabled, *b"sol_curve_multiscalar_mul", - SyscallCurveMultiscalarMultiplication::call, + SyscallCurveMultiscalarMultiplication::vm, )?; // Sysvars - result.register_function_hashed(*b"sol_get_clock_sysvar", SyscallGetClockSysvar::call)?; + result.register_function_hashed(*b"sol_get_clock_sysvar", SyscallGetClockSysvar::vm)?; result.register_function_hashed( *b"sol_get_epoch_schedule_sysvar", - SyscallGetEpochScheduleSysvar::call, + SyscallGetEpochScheduleSysvar::vm, )?; register_feature_gated_function!( result, !disable_fees_sysvar, *b"sol_get_fees_sysvar", - SyscallGetFeesSysvar::call, + SyscallGetFeesSysvar::vm, )?; - result.register_function_hashed(*b"sol_get_rent_sysvar", SyscallGetRentSysvar::call)?; + result.register_function_hashed(*b"sol_get_rent_sysvar", SyscallGetRentSysvar::vm)?; register_feature_gated_function!( result, last_restart_slot_syscall_enabled, *b"sol_get_last_restart_slot", - SyscallGetLastRestartSlotSysvar::call, + SyscallGetLastRestartSlotSysvar::vm, )?; register_feature_gated_function!( result, epoch_rewards_syscall_enabled, *b"sol_get_epoch_rewards_sysvar", - SyscallGetEpochRewardsSysvar::call, + SyscallGetEpochRewardsSysvar::vm, )?; // Memory ops - result.register_function_hashed(*b"sol_memcpy_", SyscallMemcpy::call)?; - result.register_function_hashed(*b"sol_memmove_", SyscallMemmove::call)?; - result.register_function_hashed(*b"sol_memcmp_", SyscallMemcmp::call)?; - result.register_function_hashed(*b"sol_memset_", SyscallMemset::call)?; + result.register_function_hashed(*b"sol_memcpy_", SyscallMemcpy::vm)?; + result.register_function_hashed(*b"sol_memmove_", SyscallMemmove::vm)?; + result.register_function_hashed(*b"sol_memcmp_", SyscallMemcmp::vm)?; + result.register_function_hashed(*b"sol_memset_", SyscallMemset::vm)?; // Processed sibling instructions result.register_function_hashed( *b"sol_get_processed_sibling_instruction", - SyscallGetProcessedSiblingInstruction::call, + SyscallGetProcessedSiblingInstruction::vm, )?; // Stack height - result.register_function_hashed(*b"sol_get_stack_height", SyscallGetStackHeight::call)?; + result.register_function_hashed(*b"sol_get_stack_height", SyscallGetStackHeight::vm)?; // Return data - result.register_function_hashed(*b"sol_set_return_data", SyscallSetReturnData::call)?; - result.register_function_hashed(*b"sol_get_return_data", SyscallGetReturnData::call)?; + result.register_function_hashed(*b"sol_set_return_data", SyscallSetReturnData::vm)?; + result.register_function_hashed(*b"sol_get_return_data", SyscallGetReturnData::vm)?; // Cross-program invocation - result.register_function_hashed(*b"sol_invoke_signed_c", SyscallInvokeSignedC::call)?; - result.register_function_hashed(*b"sol_invoke_signed_rust", SyscallInvokeSignedRust::call)?; + result.register_function_hashed(*b"sol_invoke_signed_c", SyscallInvokeSignedC::vm)?; + result.register_function_hashed(*b"sol_invoke_signed_rust", SyscallInvokeSignedRust::vm)?; // Memory allocator register_feature_gated_function!( result, !disable_deploy_of_alloc_free_syscall, *b"sol_alloc_free_", - SyscallAllocFree::call, + SyscallAllocFree::vm, )?; // Alt_bn128 @@ -417,7 +417,7 @@ pub fn create_program_runtime_environment_v1<'a>( result, enable_alt_bn128_syscall, *b"sol_alt_bn128_group_op", - SyscallAltBn128::call, + SyscallAltBn128::vm, )?; // Big_mod_exp @@ -425,7 +425,7 @@ pub fn create_program_runtime_environment_v1<'a>( result, enable_big_mod_exp_syscall, *b"sol_big_mod_exp", - SyscallBigModExp::call, + SyscallBigModExp::vm, )?; // Poseidon @@ -433,7 +433,7 @@ pub fn create_program_runtime_environment_v1<'a>( result, enable_poseidon_syscall, *b"sol_poseidon", - SyscallPoseidon::call, + SyscallPoseidon::vm, )?; // Accessing remaining compute units @@ -441,7 +441,7 @@ pub fn create_program_runtime_environment_v1<'a>( result, remaining_compute_units_syscall_enabled, *b"sol_remaining_compute_units", - SyscallRemainingComputeUnits::call + SyscallRemainingComputeUnits::vm )?; // Alt_bn128_compression @@ -449,11 +449,11 @@ pub fn create_program_runtime_environment_v1<'a>( result, enable_alt_bn128_compression_syscall, *b"sol_alt_bn128_compression", - SyscallAltBn128Compression::call, + SyscallAltBn128Compression::vm, )?; // Log data - result.register_function_hashed(*b"sol_log_data", SyscallLogData::call)?; + result.register_function_hashed(*b"sol_log_data", SyscallLogData::vm)?; Ok(BuiltinProgram::new_loader(config, result)) } @@ -471,7 +471,10 @@ fn translate( vm_addr: u64, len: u64, ) -> Result { - memory_mapping.map(access_type, vm_addr, len, 0).into() + memory_mapping + .map(access_type, vm_addr, len) + .map_err(|err| err.into()) + .into() } fn translate_type_inner<'a, T>( @@ -590,65 +593,13 @@ fn translate_string_and_do( } } -#[macro_export] -macro_rules! declare_syscall { - ($(#[$attr:meta])* $name:ident, $inner_call:item) => { - $(#[$attr])* - pub struct $name {} - impl $name { - $inner_call - pub fn call( - invoke_context: &mut InvokeContext, - arg_a: u64, - arg_b: u64, - arg_c: u64, - arg_d: u64, - arg_e: u64, - memory_mapping: &mut MemoryMapping, - result: &mut ProgramResult, - ) { - let converted_result: ProgramResult = Self::inner_call( - invoke_context, arg_a, arg_b, arg_c, arg_d, arg_e, memory_mapping, - ).into(); - *result = converted_result; - } - } - }; -} - -#[macro_export] -macro_rules! declare_syscallhash { - ($(#[$attr:meta])* $name:ident, $inner_call:item) => { - $(#[$attr])* - pub struct $name {} - impl $name { - $inner_call - pub fn call( - invoke_context: &mut InvokeContext, - arg_a: u64, - arg_b: u64, - arg_c: u64, - arg_d: u64, - arg_e: u64, - memory_mapping: &mut MemoryMapping, - result: &mut ProgramResult, - ) { - let converted_result: ProgramResult = Self::inner_call::( - invoke_context, arg_a, arg_b, arg_c, arg_d, arg_e, memory_mapping, - ).into(); - *result = converted_result; - } - } - }; -} - -declare_syscall!( +declare_builtin_function!( /// Abort syscall functions, called when the SBF program calls `abort()` /// LLVM will insert calls to `abort()` if it detects an untenable situation, /// `abort()` is not intended to be called explicitly by the program. /// Causes the SBF program to be halted immediately SyscallAbort, - fn inner_call( + fn rust( _invoke_context: &mut InvokeContext, _arg1: u64, _arg2: u64, @@ -661,11 +612,11 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// Panic syscall function, called when the SBF program calls 'sol_panic_()` /// Causes the SBF program to be halted immediately SyscallPanic, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, file: u64, len: u64, @@ -690,7 +641,7 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// Dynamic memory allocation syscall called when the SBF program calls /// `sol_alloc_free_()`. The allocator is expected to allocate/free /// from/to a given chunk of memory and enforce size restrictions. The @@ -698,7 +649,7 @@ declare_syscall!( /// information about that memory (start address and size) is passed /// to the VM to use for enforcement. SyscallAllocFree, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, size: u64, free_addr: u64, @@ -765,10 +716,10 @@ fn translate_and_check_program_address_inputs<'a>( Ok((seeds, program_id)) } -declare_syscall!( +declare_builtin_function!( /// Create a program address SyscallCreateProgramAddress, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, seeds_addr: u64, seeds_len: u64, @@ -806,10 +757,10 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// Create a program address SyscallTryFindProgramAddress, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, seeds_addr: u64, seeds_len: u64, @@ -873,10 +824,10 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// secp256k1_recover SyscallSecp256k1Recover, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, hash_addr: u64, recovery_id_val: u64, @@ -944,12 +895,12 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( // Elliptic Curve Point Validation // // Currently, only curve25519 Edwards and Ristretto representations are supported SyscallCurvePointValidation, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, curve_id: u64, point_addr: u64, @@ -1001,12 +952,12 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( // Elliptic Curve Group Operations // // Currently, only curve25519 Edwards and Ristretto representations are supported SyscallCurveGroupOps, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, curve_id: u64, group_op: u64, @@ -1202,12 +1153,12 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( // Elliptic Curve Multiscalar Multiplication // // Currently, only curve25519 Edwards and Ristretto representations are supported SyscallCurveMultiscalarMultiplication, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, curve_id: u64, scalars_addr: u64, @@ -1307,10 +1258,10 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// Set return data SyscallSetReturnData, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, addr: u64, len: u64, @@ -1356,13 +1307,13 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// Get return data SyscallGetReturnData, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, return_data_addr: u64, - mut length: u64, + length: u64, program_id_addr: u64, _arg4: u64, _arg5: u64, @@ -1373,7 +1324,7 @@ declare_syscall!( consume_compute_meter(invoke_context, budget.syscall_base_cost)?; let (program_id, return_data) = invoke_context.transaction_context.get_return_data(); - length = length.min(return_data.len() as u64); + let length = length.min(return_data.len() as u64); if length != 0 { let cost = length .saturating_add(size_of::() as u64) @@ -1421,10 +1372,10 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// Get a processed sigling instruction SyscallGetProcessedSiblingInstruction, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, index: u64, meta_addr: u64, @@ -1567,10 +1518,10 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// Get current call stack height SyscallGetStackHeight, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, _arg1: u64, _arg2: u64, @@ -1587,10 +1538,10 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// alt_bn128 group operations SyscallAltBn128, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, group_op: u64, input_addr: u64, @@ -1674,10 +1625,10 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// Big integer modular exponentiation SyscallBigModExp, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, params: u64, return_value: u64, @@ -1753,10 +1704,10 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( // Poseidon SyscallPoseidon, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, parameters: u64, endianness: u64, @@ -1825,10 +1776,10 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// Read remaining compute units SyscallRemainingComputeUnits, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, _arg1: u64, _arg2: u64, @@ -1845,10 +1796,10 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// alt_bn128 g1 and g2 compression and decompression SyscallAltBn128Compression, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, op: u64, input_addr: u64, @@ -1948,10 +1899,10 @@ declare_syscall!( } ); -declare_syscallhash!( +declare_builtin_function!( // Generic Hashing Syscall - SyscallHash, - fn inner_call( + SyscallHash, + fn rust( invoke_context: &mut InvokeContext, vals_addr: u64, vals_len: u64, @@ -2030,10 +1981,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}, + error::EbpfError, memory_region::MemoryRegion, program::SBPFVersion, vm::Config, }, solana_sdk::{ account::{create_account_shared_data_for_test, AccountSharedData}, @@ -2053,9 +2001,8 @@ mod tests { macro_rules! assert_access_violation { ($result:expr, $va:expr, $len:expr) => { match $result.unwrap_err().downcast_ref::().unwrap() { - EbpfError::AccessViolation(_, _, va, len, _) if $va == *va && $len == *len => {} - EbpfError::StackAccessViolation(_, _, va, len, _) if $va == *va && $len == *len => { - } + EbpfError::AccessViolation(_, va, len, _) if $va == *va && $len == *len => {} + EbpfError::StackAccessViolation(_, va, len, _) if $va == *va && $len == *len => {} _ => panic!(), } }; @@ -2291,17 +2238,7 @@ mod tests { prepare_mockup!(invoke_context, program_id, bpf_loader::id()); let config = Config::default(); let mut memory_mapping = MemoryMapping::new(vec![], &config, &SBPFVersion::V2).unwrap(); - let mut result = ProgramResult::Ok(0); - SyscallAbort::call( - &mut invoke_context, - 0, - 0, - 0, - 0, - 0, - &mut memory_mapping, - &mut result, - ); + let result = SyscallAbort::rust(&mut invoke_context, 0, 0, 0, 0, 0, &mut memory_mapping); result.unwrap(); } @@ -2320,8 +2257,7 @@ mod tests { .unwrap(); invoke_context.mock_set_remaining(string.len() as u64 - 1); - let mut result = ProgramResult::Ok(0); - SyscallPanic::call( + let result = SyscallPanic::rust( &mut invoke_context, 0x100000000, string.len() as u64, @@ -2329,16 +2265,14 @@ mod tests { 84, 0, &mut memory_mapping, - &mut result, ); assert_matches!( result, - ProgramResult::Err(error) if error.downcast_ref::().unwrap() == &InstructionError::ComputationalBudgetExceeded + Result::Err(error) if error.downcast_ref::().unwrap() == &InstructionError::ComputationalBudgetExceeded ); invoke_context.mock_set_remaining(string.len() as u64); - let mut result = ProgramResult::Ok(0); - SyscallPanic::call( + let result = SyscallPanic::rust( &mut invoke_context, 0x100000000, string.len() as u64, @@ -2346,7 +2280,6 @@ mod tests { 84, 0, &mut memory_mapping, - &mut result, ); result.unwrap(); } @@ -2365,8 +2298,7 @@ mod tests { .unwrap(); invoke_context.mock_set_remaining(400 - 1); - let mut result = ProgramResult::Ok(0); - SyscallLog::call( + let result = SyscallLog::rust( &mut invoke_context, 0x100000001, // AccessViolation string.len() as u64, @@ -2374,11 +2306,9 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); assert_access_violation!(result, 0x100000001, string.len() as u64); - let mut result = ProgramResult::Ok(0); - SyscallLog::call( + let result = SyscallLog::rust( &mut invoke_context, 0x100000000, string.len() as u64 * 2, // AccessViolation @@ -2386,12 +2316,10 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); assert_access_violation!(result, 0x100000000, string.len() as u64 * 2); - let mut result = ProgramResult::Ok(0); - SyscallLog::call( + let result = SyscallLog::rust( &mut invoke_context, 0x100000000, string.len() as u64, @@ -2399,11 +2327,9 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); result.unwrap(); - let mut result = ProgramResult::Ok(0); - SyscallLog::call( + let result = SyscallLog::rust( &mut invoke_context, 0x100000000, string.len() as u64, @@ -2411,11 +2337,10 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); assert_matches!( result, - ProgramResult::Err(error) if error.downcast_ref::().unwrap() == &InstructionError::ComputationalBudgetExceeded + Result::Err(error) if error.downcast_ref::().unwrap() == &InstructionError::ComputationalBudgetExceeded ); assert_eq!( @@ -2436,17 +2361,7 @@ mod tests { invoke_context.mock_set_remaining(cost); let config = Config::default(); let mut memory_mapping = MemoryMapping::new(vec![], &config, &SBPFVersion::V2).unwrap(); - let mut result = ProgramResult::Ok(0); - SyscallLogU64::call( - &mut invoke_context, - 1, - 2, - 3, - 4, - 5, - &mut memory_mapping, - &mut result, - ); + let result = SyscallLogU64::rust(&mut invoke_context, 1, 2, 3, 4, 5, &mut memory_mapping); result.unwrap(); assert_eq!( @@ -2473,8 +2388,7 @@ mod tests { ) .unwrap(); - let mut result = ProgramResult::Ok(0); - SyscallLogPubkey::call( + let result = SyscallLogPubkey::rust( &mut invoke_context, 0x100000001, // AccessViolation 32, @@ -2482,30 +2396,19 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); assert_access_violation!(result, 0x100000001, 32); invoke_context.mock_set_remaining(1); - let mut result = ProgramResult::Ok(0); - SyscallLogPubkey::call( - &mut invoke_context, - 100, - 32, - 0, - 0, - 0, - &mut memory_mapping, - &mut result, - ); + let result = + SyscallLogPubkey::rust(&mut invoke_context, 100, 32, 0, 0, 0, &mut memory_mapping); assert_matches!( result, - ProgramResult::Err(error) if error.downcast_ref::().unwrap() == &InstructionError::ComputationalBudgetExceeded + Result::Err(error) if error.downcast_ref::().unwrap() == &InstructionError::ComputationalBudgetExceeded ); invoke_context.mock_set_remaining(cost); - let mut result = ProgramResult::Ok(0); - SyscallLogPubkey::call( + let result = SyscallLogPubkey::rust( &mut invoke_context, 0x100000000, 0, @@ -2513,7 +2416,6 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); result.unwrap(); @@ -2536,8 +2438,7 @@ mod tests { let mut vm = vm.unwrap(); let invoke_context = &mut vm.context_object_pointer; let memory_mapping = &mut vm.memory_mapping; - let mut result = ProgramResult::Ok(0); - SyscallAllocFree::call( + let result = SyscallAllocFree::rust( invoke_context, solana_sdk::entrypoint::HEAP_LENGTH as u64, 0, @@ -2545,11 +2446,9 @@ mod tests { 0, 0, memory_mapping, - &mut result, ); assert_ne!(result.unwrap(), 0); - let mut result = ProgramResult::Ok(0); - SyscallAllocFree::call( + let result = SyscallAllocFree::rust( invoke_context, solana_sdk::entrypoint::HEAP_LENGTH as u64, 0, @@ -2557,20 +2456,10 @@ mod tests { 0, 0, memory_mapping, - &mut result, ); assert_eq!(result.unwrap(), 0); - let mut result = ProgramResult::Ok(0); - SyscallAllocFree::call( - invoke_context, - u64::MAX, - 0, - 0, - 0, - 0, - memory_mapping, - &mut result, - ); + let result = + SyscallAllocFree::rust(invoke_context, u64::MAX, 0, 0, 0, 0, memory_mapping); assert_eq!(result.unwrap(), 0); } @@ -2583,12 +2472,10 @@ mod tests { 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); + let result = SyscallAllocFree::rust(invoke_context, 1, 0, 0, 0, 0, memory_mapping); assert_ne!(result.unwrap(), 0); } - let mut result = ProgramResult::Ok(0); - SyscallAllocFree::call( + let result = SyscallAllocFree::rust( invoke_context, solana_sdk::entrypoint::HEAP_LENGTH as u64, 0, @@ -2596,7 +2483,6 @@ mod tests { 0, 0, memory_mapping, - &mut result, ); assert_eq!(result.unwrap(), 0); } @@ -2609,12 +2495,10 @@ mod tests { 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); + let result = SyscallAllocFree::rust(invoke_context, 1, 0, 0, 0, 0, memory_mapping); assert_ne!(result.unwrap(), 0); } - let mut result = ProgramResult::Ok(0); - SyscallAllocFree::call( + let result = SyscallAllocFree::rust( invoke_context, solana_sdk::entrypoint::HEAP_LENGTH as u64, 0, @@ -2622,7 +2506,6 @@ mod tests { 0, 0, memory_mapping, - &mut result, ); assert_eq!(result.unwrap(), 0); } @@ -2635,8 +2518,7 @@ mod tests { let mut vm = vm.unwrap(); let invoke_context = &mut vm.context_object_pointer; let memory_mapping = &mut vm.memory_mapping; - let mut result = ProgramResult::Ok(0); - SyscallAllocFree::call( + let result = SyscallAllocFree::rust( invoke_context, size_of::() as u64, 0, @@ -2644,7 +2526,6 @@ mod tests { 0, 0, memory_mapping, - &mut result, ); let address = result.unwrap(); assert_ne!(address, 0); @@ -2701,8 +2582,7 @@ mod tests { * 4, ); - let mut result = ProgramResult::Ok(0); - SyscallHash::call::( + let result = SyscallHash::rust::( &mut invoke_context, ro_va, ro_len, @@ -2710,14 +2590,12 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); result.unwrap(); let hash_local = hashv(&[bytes1.as_ref(), bytes2.as_ref()]).to_bytes(); assert_eq!(hash_result, hash_local); - let mut result = ProgramResult::Ok(0); - SyscallHash::call::( + let result = SyscallHash::rust::( &mut invoke_context, ro_va - 1, // AccessViolation ro_len, @@ -2725,11 +2603,9 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); assert_access_violation!(result, ro_va - 1, 32); - let mut result = ProgramResult::Ok(0); - SyscallHash::call::( + let result = SyscallHash::rust::( &mut invoke_context, ro_va, ro_len + 1, // AccessViolation @@ -2737,11 +2613,9 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); assert_access_violation!(result, ro_va, 48); - let mut result = ProgramResult::Ok(0); - SyscallHash::call::( + let result = SyscallHash::rust::( &mut invoke_context, ro_va, ro_len, @@ -2749,11 +2623,9 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); assert_access_violation!(result, rw_va - 1, HASH_BYTES as u64); - let mut result = ProgramResult::Ok(0); - SyscallHash::call::( + let result = SyscallHash::rust::( &mut invoke_context, ro_va, ro_len, @@ -2761,11 +2633,10 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); assert_matches!( result, - ProgramResult::Err(error) if error.downcast_ref::().unwrap() == &InstructionError::ComputationalBudgetExceeded + Result::Err(error) if error.downcast_ref::().unwrap() == &InstructionError::ComputationalBudgetExceeded ); } @@ -2805,8 +2676,7 @@ mod tests { * 2, ); - let mut result = ProgramResult::Ok(0); - SyscallCurvePointValidation::call( + let result = SyscallCurvePointValidation::rust( &mut invoke_context, CURVE25519_EDWARDS, valid_bytes_va, @@ -2814,12 +2684,10 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); assert_eq!(0, result.unwrap()); - let mut result = ProgramResult::Ok(0); - SyscallCurvePointValidation::call( + let result = SyscallCurvePointValidation::rust( &mut invoke_context, CURVE25519_EDWARDS, invalid_bytes_va, @@ -2827,12 +2695,10 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); assert_eq!(1, result.unwrap()); - let mut result = ProgramResult::Ok(0); - SyscallCurvePointValidation::call( + let result = SyscallCurvePointValidation::rust( &mut invoke_context, CURVE25519_EDWARDS, valid_bytes_va, @@ -2840,11 +2706,10 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); assert_matches!( result, - ProgramResult::Err(error) if error.downcast_ref::().unwrap() == &InstructionError::ComputationalBudgetExceeded + Result::Err(error) if error.downcast_ref::().unwrap() == &InstructionError::ComputationalBudgetExceeded ); } @@ -2884,8 +2749,7 @@ mod tests { * 2, ); - let mut result = ProgramResult::Ok(0); - SyscallCurvePointValidation::call( + let result = SyscallCurvePointValidation::rust( &mut invoke_context, CURVE25519_RISTRETTO, valid_bytes_va, @@ -2893,12 +2757,10 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); assert_eq!(0, result.unwrap()); - let mut result = ProgramResult::Ok(0); - SyscallCurvePointValidation::call( + let result = SyscallCurvePointValidation::rust( &mut invoke_context, CURVE25519_RISTRETTO, invalid_bytes_va, @@ -2906,12 +2768,10 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); assert_eq!(1, result.unwrap()); - let mut result = ProgramResult::Ok(0); - SyscallCurvePointValidation::call( + let result = SyscallCurvePointValidation::rust( &mut invoke_context, CURVE25519_RISTRETTO, valid_bytes_va, @@ -2919,11 +2779,10 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); assert_matches!( result, - ProgramResult::Err(error) if error.downcast_ref::().unwrap() == &InstructionError::ComputationalBudgetExceeded + Result::Err(error) if error.downcast_ref::().unwrap() == &InstructionError::ComputationalBudgetExceeded ); } @@ -2985,8 +2844,7 @@ mod tests { * 2, ); - let mut result = ProgramResult::Ok(0); - SyscallCurveGroupOps::call( + let result = SyscallCurveGroupOps::rust( &mut invoke_context, CURVE25519_EDWARDS, ADD, @@ -2994,7 +2852,6 @@ mod tests { right_point_va, result_point_va, &mut memory_mapping, - &mut result, ); assert_eq!(0, result.unwrap()); @@ -3004,8 +2861,7 @@ mod tests { ]; assert_eq!(expected_sum, result_point); - let mut result = ProgramResult::Ok(0); - SyscallCurveGroupOps::call( + let result = SyscallCurveGroupOps::rust( &mut invoke_context, CURVE25519_EDWARDS, ADD, @@ -3013,12 +2869,10 @@ mod tests { right_point_va, result_point_va, &mut memory_mapping, - &mut result, ); assert_eq!(1, result.unwrap()); - let mut result = ProgramResult::Ok(0); - SyscallCurveGroupOps::call( + let result = SyscallCurveGroupOps::rust( &mut invoke_context, CURVE25519_EDWARDS, SUB, @@ -3026,7 +2880,6 @@ mod tests { right_point_va, result_point_va, &mut memory_mapping, - &mut result, ); assert_eq!(0, result.unwrap()); @@ -3036,8 +2889,7 @@ mod tests { ]; assert_eq!(expected_difference, result_point); - let mut result = ProgramResult::Ok(0); - SyscallCurveGroupOps::call( + let result = SyscallCurveGroupOps::rust( &mut invoke_context, CURVE25519_EDWARDS, SUB, @@ -3045,12 +2897,10 @@ mod tests { right_point_va, result_point_va, &mut memory_mapping, - &mut result, ); assert_eq!(1, result.unwrap()); - let mut result = ProgramResult::Ok(0); - SyscallCurveGroupOps::call( + let result = SyscallCurveGroupOps::rust( &mut invoke_context, CURVE25519_EDWARDS, MUL, @@ -3058,7 +2908,6 @@ mod tests { right_point_va, result_point_va, &mut memory_mapping, - &mut result, ); result.unwrap(); @@ -3068,8 +2917,7 @@ mod tests { ]; assert_eq!(expected_product, result_point); - let mut result = ProgramResult::Ok(0); - SyscallCurveGroupOps::call( + let result = SyscallCurveGroupOps::rust( &mut invoke_context, CURVE25519_EDWARDS, MUL, @@ -3077,12 +2925,10 @@ mod tests { invalid_point_va, result_point_va, &mut memory_mapping, - &mut result, ); assert_eq!(1, result.unwrap()); - let mut result = ProgramResult::Ok(0); - SyscallCurveGroupOps::call( + let result = SyscallCurveGroupOps::rust( &mut invoke_context, CURVE25519_EDWARDS, MUL, @@ -3090,11 +2936,10 @@ mod tests { invalid_point_va, result_point_va, &mut memory_mapping, - &mut result, ); assert_matches!( result, - ProgramResult::Err(error) if error.downcast_ref::().unwrap() == &InstructionError::ComputationalBudgetExceeded + Result::Err(error) if error.downcast_ref::().unwrap() == &InstructionError::ComputationalBudgetExceeded ); } @@ -3156,8 +3001,7 @@ mod tests { * 2, ); - let mut result = ProgramResult::Ok(0); - SyscallCurveGroupOps::call( + let result = SyscallCurveGroupOps::rust( &mut invoke_context, CURVE25519_RISTRETTO, ADD, @@ -3165,7 +3009,6 @@ mod tests { right_point_va, result_point_va, &mut memory_mapping, - &mut result, ); assert_eq!(0, result.unwrap()); @@ -3175,8 +3018,7 @@ mod tests { ]; assert_eq!(expected_sum, result_point); - let mut result = ProgramResult::Ok(0); - SyscallCurveGroupOps::call( + let result = SyscallCurveGroupOps::rust( &mut invoke_context, CURVE25519_RISTRETTO, ADD, @@ -3184,12 +3026,10 @@ mod tests { right_point_va, result_point_va, &mut memory_mapping, - &mut result, ); assert_eq!(1, result.unwrap()); - let mut result = ProgramResult::Ok(0); - SyscallCurveGroupOps::call( + let result = SyscallCurveGroupOps::rust( &mut invoke_context, CURVE25519_RISTRETTO, SUB, @@ -3197,7 +3037,6 @@ mod tests { right_point_va, result_point_va, &mut memory_mapping, - &mut result, ); assert_eq!(0, result.unwrap()); @@ -3207,8 +3046,7 @@ mod tests { ]; assert_eq!(expected_difference, result_point); - let mut result = ProgramResult::Ok(0); - SyscallCurveGroupOps::call( + let result = SyscallCurveGroupOps::rust( &mut invoke_context, CURVE25519_RISTRETTO, SUB, @@ -3216,13 +3054,11 @@ mod tests { right_point_va, result_point_va, &mut memory_mapping, - &mut result, ); assert_eq!(1, result.unwrap()); - let mut result = ProgramResult::Ok(0); - SyscallCurveGroupOps::call( + let result = SyscallCurveGroupOps::rust( &mut invoke_context, CURVE25519_RISTRETTO, MUL, @@ -3230,7 +3066,6 @@ mod tests { right_point_va, result_point_va, &mut memory_mapping, - &mut result, ); result.unwrap(); @@ -3240,8 +3075,7 @@ mod tests { ]; assert_eq!(expected_product, result_point); - let mut result = ProgramResult::Ok(0); - SyscallCurveGroupOps::call( + let result = SyscallCurveGroupOps::rust( &mut invoke_context, CURVE25519_RISTRETTO, MUL, @@ -3249,13 +3083,11 @@ mod tests { invalid_point_va, result_point_va, &mut memory_mapping, - &mut result, ); assert_eq!(1, result.unwrap()); - let mut result = ProgramResult::Ok(0); - SyscallCurveGroupOps::call( + let result = SyscallCurveGroupOps::rust( &mut invoke_context, CURVE25519_RISTRETTO, MUL, @@ -3263,11 +3095,10 @@ mod tests { invalid_point_va, result_point_va, &mut memory_mapping, - &mut result, ); assert_matches!( result, - ProgramResult::Err(error) if error.downcast_ref::().unwrap() == &InstructionError::ComputationalBudgetExceeded + Result::Err(error) if error.downcast_ref::().unwrap() == &InstructionError::ComputationalBudgetExceeded ); } @@ -3344,8 +3175,7 @@ mod tests { .curve25519_ristretto_msm_incremental_cost, ); - let mut result = ProgramResult::Ok(0); - SyscallCurveMultiscalarMultiplication::call( + let result = SyscallCurveMultiscalarMultiplication::rust( &mut invoke_context, CURVE25519_EDWARDS, scalars_va, @@ -3353,7 +3183,6 @@ mod tests { 2, result_point_va, &mut memory_mapping, - &mut result, ); assert_eq!(0, result.unwrap()); @@ -3363,8 +3192,7 @@ mod tests { ]; assert_eq!(expected_product, result_point); - let mut result = ProgramResult::Ok(0); - SyscallCurveMultiscalarMultiplication::call( + let result = SyscallCurveMultiscalarMultiplication::rust( &mut invoke_context, CURVE25519_RISTRETTO, scalars_va, @@ -3372,7 +3200,6 @@ mod tests { 2, result_point_va, &mut memory_mapping, - &mut result, ); assert_eq!(0, result.unwrap()); @@ -3484,8 +3311,7 @@ mod tests { ) .unwrap(); - let mut result = ProgramResult::Ok(0); - SyscallGetClockSysvar::call( + let result = SyscallGetClockSysvar::rust( &mut invoke_context, got_clock_va, 0, @@ -3493,7 +3319,6 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); result.unwrap(); assert_eq!(got_clock, src_clock); @@ -3522,8 +3347,7 @@ mod tests { ) .unwrap(); - let mut result = ProgramResult::Ok(0); - SyscallGetEpochScheduleSysvar::call( + let result = SyscallGetEpochScheduleSysvar::rust( &mut invoke_context, got_epochschedule_va, 0, @@ -3531,7 +3355,6 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); result.unwrap(); assert_eq!(got_epochschedule, src_epochschedule); @@ -3561,8 +3384,7 @@ mod tests { ) .unwrap(); - let mut result = ProgramResult::Ok(0); - SyscallGetFeesSysvar::call( + let result = SyscallGetFeesSysvar::rust( &mut invoke_context, got_fees_va, 0, @@ -3570,7 +3392,6 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); result.unwrap(); assert_eq!(got_fees, src_fees); @@ -3595,8 +3416,7 @@ mod tests { ) .unwrap(); - let mut result = ProgramResult::Ok(0); - SyscallGetRentSysvar::call( + let result = SyscallGetRentSysvar::rust( &mut invoke_context, got_rent_va, 0, @@ -3604,7 +3424,6 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); result.unwrap(); assert_eq!(got_rent, src_rent); @@ -3631,8 +3450,7 @@ mod tests { ) .unwrap(); - let mut result = ProgramResult::Ok(0); - SyscallGetEpochRewardsSysvar::call( + let result = SyscallGetEpochRewardsSysvar::rust( &mut invoke_context, got_rewards_va, 0, @@ -3640,7 +3458,6 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); result.unwrap(); assert_eq!(got_rewards, src_rewards); @@ -3654,12 +3471,22 @@ mod tests { } } + type BuiltinFunctionRustInterface<'a> = fn( + &mut InvokeContext<'a>, + u64, + u64, + u64, + u64, + u64, + &mut MemoryMapping, + ) -> Result>; + fn call_program_address_common<'a, 'b: 'a>( invoke_context: &'a mut InvokeContext<'b>, seeds: &[&[u8]], program_id: &Pubkey, overlap_outputs: bool, - syscall: BuiltinFunction>, + syscall: BuiltinFunctionRustInterface<'b>, ) -> Result<(Pubkey, u8), Error> { const SEEDS_VA: u64 = 0x100000000; const PROGRAM_ID_VA: u64 = 0x200000000; @@ -3692,8 +3519,7 @@ mod tests { )); let mut memory_mapping = MemoryMapping::new(regions, &config, &SBPFVersion::V2).unwrap(); - let mut result = ProgramResult::Ok(0); - syscall( + let result = syscall( invoke_context, SEEDS_VA, seeds.len() as u64, @@ -3705,9 +3531,8 @@ mod tests { BUMP_SEED_VA }, &mut memory_mapping, - &mut result, ); - Result::::from(result).map(|_| (address, bump_seed)) + result.map(|_| (address, bump_seed)) } fn create_program_address( @@ -3720,7 +3545,7 @@ mod tests { seeds, address, false, - SyscallCreateProgramAddress::call, + SyscallCreateProgramAddress::rust, )?; Ok(address) } @@ -3735,7 +3560,7 @@ mod tests { seeds, address, false, - SyscallTryFindProgramAddress::call, + SyscallTryFindProgramAddress::rust, ) } @@ -3762,8 +3587,7 @@ mod tests { prepare_mockup!(invoke_context, program_id, bpf_loader::id()); - let mut result = ProgramResult::Ok(0); - SyscallSetReturnData::call( + let result = SyscallSetReturnData::rust( &mut invoke_context, SRC_VA, data.len() as u64, @@ -3771,12 +3595,10 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); assert_eq!(result.unwrap(), 0); - let mut result = ProgramResult::Ok(0); - SyscallGetReturnData::call( + let result = SyscallGetReturnData::rust( &mut invoke_context, DST_VA, data_buffer.len() as u64, @@ -3784,14 +3606,12 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); assert_eq!(result.unwrap() as usize, data.len()); assert_eq!(data.get(0..data_buffer.len()).unwrap(), data_buffer); assert_eq!(id_buffer, program_id.to_bytes()); - let mut result = ProgramResult::Ok(0); - SyscallGetReturnData::call( + let result = SyscallGetReturnData::rust( &mut invoke_context, PROGRAM_ID_VA, data_buffer.len() as u64, @@ -3799,11 +3619,10 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); assert_matches!( result, - ProgramResult::Err(error) if error.downcast_ref::().unwrap() == &SyscallError::CopyOverlapping + Result::Err(error) if error.downcast_ref::().unwrap() == &SyscallError::CopyOverlapping ); } @@ -3897,8 +3716,7 @@ mod tests { .unwrap(); invoke_context.mock_set_remaining(syscall_base_cost); - let mut result = ProgramResult::Ok(0); - SyscallGetProcessedSiblingInstruction::call( + let result = SyscallGetProcessedSiblingInstruction::rust( &mut invoke_context, 0, VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64), @@ -3906,7 +3724,6 @@ mod tests { VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64), VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64), &mut memory_mapping, - &mut result, ); assert_eq!(result.unwrap(), 1); { @@ -3929,8 +3746,7 @@ mod tests { } invoke_context.mock_set_remaining(syscall_base_cost); - let mut result = ProgramResult::Ok(0); - SyscallGetProcessedSiblingInstruction::call( + let result = SyscallGetProcessedSiblingInstruction::rust( &mut invoke_context, 1, VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64), @@ -3938,13 +3754,11 @@ mod tests { VM_BASE_ADDRESS.saturating_add(DATA_OFFSET as u64), VM_BASE_ADDRESS.saturating_add(ACCOUNTS_OFFSET as u64), &mut memory_mapping, - &mut result, ); assert_eq!(result.unwrap(), 0); invoke_context.mock_set_remaining(syscall_base_cost); - let mut result = ProgramResult::Ok(0); - SyscallGetProcessedSiblingInstruction::call( + let result = SyscallGetProcessedSiblingInstruction::rust( &mut invoke_context, 0, VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64), @@ -3952,11 +3766,10 @@ mod tests { VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64), VM_BASE_ADDRESS.saturating_add(META_OFFSET as u64), &mut memory_mapping, - &mut result, ); assert_matches!( result, - ProgramResult::Err(error) if error.downcast_ref::().unwrap() == &SyscallError::CopyOverlapping + Result::Err(error) if error.downcast_ref::().unwrap() == &SyscallError::CopyOverlapping ); } @@ -4138,7 +3951,7 @@ mod tests { seeds, &address, true, - SyscallTryFindProgramAddress::call, + SyscallTryFindProgramAddress::rust, ), Result::Err(error) if error.downcast_ref::().unwrap() == &SyscallError::CopyOverlapping ); @@ -4186,8 +3999,7 @@ mod tests { + (MAX_LEN * MAX_LEN) / budget.big_modular_exponentiation_cost, ); - let mut result = ProgramResult::Ok(0); - SyscallBigModExp::call( + let result = SyscallBigModExp::rust( &mut invoke_context, VADDR_PARAMS, VADDR_OUT, @@ -4195,7 +4007,6 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); assert_eq!(result.unwrap(), 0); @@ -4229,8 +4040,7 @@ mod tests { + (INV_LEN * INV_LEN) / budget.big_modular_exponentiation_cost, ); - let mut result = ProgramResult::Ok(0); - SyscallBigModExp::call( + let result = SyscallBigModExp::rust( &mut invoke_context, VADDR_PARAMS, VADDR_OUT, @@ -4238,12 +4048,11 @@ mod tests { 0, 0, &mut memory_mapping, - &mut result, ); assert_matches!( result, - ProgramResult::Err(error) if error.downcast_ref::().unwrap() == &SyscallError::InvalidLength + Result::Err(error) if error.downcast_ref::().unwrap() == &SyscallError::InvalidLength ); } } diff --git a/programs/bpf_loader/src/syscalls/sysvar.rs b/programs/bpf_loader/src/syscalls/sysvar.rs index d86402b340..e8777569ce 100644 --- a/programs/bpf_loader/src/syscalls/sysvar.rs +++ b/programs/bpf_loader/src/syscalls/sysvar.rs @@ -1,4 +1,4 @@ -use {super::*, crate::declare_syscall}; +use super::*; fn get_sysvar( sysvar: Result, InstructionError>, @@ -22,10 +22,10 @@ fn get_sysvar( Ok(SUCCESS) } -declare_syscall!( +declare_builtin_function!( /// Get a Clock sysvar SyscallGetClockSysvar, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, var_addr: u64, _arg2: u64, @@ -44,10 +44,10 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// Get a EpochSchedule sysvar SyscallGetEpochScheduleSysvar, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, var_addr: u64, _arg2: u64, @@ -66,10 +66,10 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// Get a EpochRewards sysvar SyscallGetEpochRewardsSysvar, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, var_addr: u64, _arg2: u64, @@ -88,10 +88,10 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// Get a Fees sysvar SyscallGetFeesSysvar, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, var_addr: u64, _arg2: u64, @@ -113,10 +113,10 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// Get a Rent sysvar SyscallGetRentSysvar, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, var_addr: u64, _arg2: u64, @@ -135,10 +135,10 @@ declare_syscall!( } ); -declare_syscall!( +declare_builtin_function!( /// Get a Last Restart Slot sysvar SyscallGetLastRestartSlotSysvar, - fn inner_call( + fn rust( invoke_context: &mut InvokeContext, var_addr: u64, _arg2: u64, diff --git a/programs/compute-budget/src/lib.rs b/programs/compute-budget/src/lib.rs index e296ca3a2f..01bbd7a8b4 100644 --- a/programs/compute-budget/src/lib.rs +++ b/programs/compute-budget/src/lib.rs @@ -2,11 +2,7 @@ use solana_program_runtime::declare_process_instruction; pub const DEFAULT_COMPUTE_UNITS: u64 = 150; -declare_process_instruction!( - process_instruction, - DEFAULT_COMPUTE_UNITS, - |_invoke_context| { - // Do nothing, compute budget instructions handled by the runtime - Ok(()) - } -); +declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |_invoke_context| { + // Do nothing, compute budget instructions handled by the runtime + Ok(()) +}); diff --git a/programs/config/src/config_processor.rs b/programs/config/src/config_processor.rs index 628e77cb93..d053405698 100644 --- a/programs/config/src/config_processor.rs +++ b/programs/config/src/config_processor.rs @@ -13,131 +13,127 @@ use { pub const DEFAULT_COMPUTE_UNITS: u64 = 450; -declare_process_instruction!( - process_instruction, - DEFAULT_COMPUTE_UNITS, - |invoke_context| { - let transaction_context = &invoke_context.transaction_context; - let instruction_context = transaction_context.get_current_instruction_context()?; - let data = instruction_context.get_instruction_data(); +declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| { + let transaction_context = &invoke_context.transaction_context; + let instruction_context = transaction_context.get_current_instruction_context()?; + let data = instruction_context.get_instruction_data(); - let key_list: ConfigKeys = limited_deserialize(data)?; - let config_account_key = transaction_context.get_key_of_account_at_index( - instruction_context.get_index_of_instruction_account_in_transaction(0)?, - )?; - let config_account = - instruction_context.try_borrow_instruction_account(transaction_context, 0)?; - let is_config_account_signer = config_account.is_signer(); - let current_data: ConfigKeys = { - if config_account.get_owner() != &crate::id() { - return Err(InstructionError::InvalidAccountOwner); - } - - deserialize(config_account.get_data()).map_err(|err| { - ic_msg!( - invoke_context, - "Unable to deserialize config account: {}", - err - ); - InstructionError::InvalidAccountData - })? - }; - drop(config_account); - - let current_signer_keys: Vec = current_data - .keys - .iter() - .filter(|(_, is_signer)| *is_signer) - .map(|(pubkey, _)| *pubkey) - .collect(); - if current_signer_keys.is_empty() { - // Config account keypair must be a signer on account initialization, - // or when no signers specified in Config data - if !is_config_account_signer { - return Err(InstructionError::MissingRequiredSignature); - } + let key_list: ConfigKeys = limited_deserialize(data)?; + let config_account_key = transaction_context.get_key_of_account_at_index( + instruction_context.get_index_of_instruction_account_in_transaction(0)?, + )?; + let config_account = + instruction_context.try_borrow_instruction_account(transaction_context, 0)?; + let is_config_account_signer = config_account.is_signer(); + let current_data: ConfigKeys = { + if config_account.get_owner() != &crate::id() { + return Err(InstructionError::InvalidAccountOwner); } - let mut counter = 0; - for (signer, _) in key_list.keys.iter().filter(|(_, is_signer)| *is_signer) { - counter += 1; - if signer != config_account_key { - let signer_account = instruction_context - .try_borrow_instruction_account(transaction_context, counter as IndexOfAccount) - .map_err(|_| { - ic_msg!( - invoke_context, - "account {:?} is not in account list", - signer, - ); - InstructionError::MissingRequiredSignature - })?; - if !signer_account.is_signer() { - ic_msg!( - invoke_context, - "account {:?} signer_key().is_none()", - signer - ); - return Err(InstructionError::MissingRequiredSignature); - } - if signer_account.get_key() != signer { - ic_msg!( - invoke_context, - "account[{:?}].signer_key() does not match Config data)", - counter + 1 - ); - return Err(InstructionError::MissingRequiredSignature); - } - // If Config account is already initialized, update signatures must match Config data - if !current_data.keys.is_empty() - && !current_signer_keys.iter().any(|pubkey| pubkey == signer) - { - ic_msg!( - invoke_context, - "account {:?} is not in stored signer list", - signer - ); - return Err(InstructionError::MissingRequiredSignature); - } - } else if !is_config_account_signer { - ic_msg!(invoke_context, "account[0].signer_key().is_none()"); - return Err(InstructionError::MissingRequiredSignature); - } - } - - if invoke_context - .feature_set - .is_active(&feature_set::dedupe_config_program_signers::id()) - { - let total_new_keys = key_list.keys.len(); - let unique_new_keys = key_list.keys.into_iter().collect::>(); - if unique_new_keys.len() != total_new_keys { - ic_msg!(invoke_context, "new config contains duplicate keys"); - return Err(InstructionError::InvalidArgument); - } - } - - // Check for Config data signers not present in incoming account update - if current_signer_keys.len() > counter { + deserialize(config_account.get_data()).map_err(|err| { ic_msg!( invoke_context, - "too few signers: {:?}; expected: {:?}", - counter, - current_signer_keys.len() + "Unable to deserialize config account: {}", + err ); + InstructionError::InvalidAccountData + })? + }; + drop(config_account); + + let current_signer_keys: Vec = current_data + .keys + .iter() + .filter(|(_, is_signer)| *is_signer) + .map(|(pubkey, _)| *pubkey) + .collect(); + if current_signer_keys.is_empty() { + // Config account keypair must be a signer on account initialization, + // or when no signers specified in Config data + if !is_config_account_signer { return Err(InstructionError::MissingRequiredSignature); } - - let mut config_account = - instruction_context.try_borrow_instruction_account(transaction_context, 0)?; - if config_account.get_data().len() < data.len() { - ic_msg!(invoke_context, "instruction data too large"); - return Err(InstructionError::InvalidInstructionData); - } - config_account.get_data_mut()?[..data.len()].copy_from_slice(data); - Ok(()) } -); + + let mut counter = 0; + for (signer, _) in key_list.keys.iter().filter(|(_, is_signer)| *is_signer) { + counter += 1; + if signer != config_account_key { + let signer_account = instruction_context + .try_borrow_instruction_account(transaction_context, counter as IndexOfAccount) + .map_err(|_| { + ic_msg!( + invoke_context, + "account {:?} is not in account list", + signer, + ); + InstructionError::MissingRequiredSignature + })?; + if !signer_account.is_signer() { + ic_msg!( + invoke_context, + "account {:?} signer_key().is_none()", + signer + ); + return Err(InstructionError::MissingRequiredSignature); + } + if signer_account.get_key() != signer { + ic_msg!( + invoke_context, + "account[{:?}].signer_key() does not match Config data)", + counter + 1 + ); + return Err(InstructionError::MissingRequiredSignature); + } + // If Config account is already initialized, update signatures must match Config data + if !current_data.keys.is_empty() + && !current_signer_keys.iter().any(|pubkey| pubkey == signer) + { + ic_msg!( + invoke_context, + "account {:?} is not in stored signer list", + signer + ); + return Err(InstructionError::MissingRequiredSignature); + } + } else if !is_config_account_signer { + ic_msg!(invoke_context, "account[0].signer_key().is_none()"); + return Err(InstructionError::MissingRequiredSignature); + } + } + + if invoke_context + .feature_set + .is_active(&feature_set::dedupe_config_program_signers::id()) + { + let total_new_keys = key_list.keys.len(); + let unique_new_keys = key_list.keys.into_iter().collect::>(); + if unique_new_keys.len() != total_new_keys { + ic_msg!(invoke_context, "new config contains duplicate keys"); + return Err(InstructionError::InvalidArgument); + } + } + + // Check for Config data signers not present in incoming account update + if current_signer_keys.len() > counter { + ic_msg!( + invoke_context, + "too few signers: {:?}; expected: {:?}", + counter, + current_signer_keys.len() + ); + return Err(InstructionError::MissingRequiredSignature); + } + + let mut config_account = + instruction_context.try_borrow_instruction_account(transaction_context, 0)?; + if config_account.get_data().len() < data.len() { + ic_msg!(invoke_context, "instruction data too large"); + return Err(InstructionError::InvalidInstructionData); + } + config_account.get_data_mut()?[..data.len()].copy_from_slice(data); + Ok(()) +}); #[cfg(test)] mod tests { @@ -169,7 +165,7 @@ mod tests { transaction_accounts, instruction_accounts, expected_result, - super::process_instruction, + Entrypoint::vm, |_invoke_context| {}, |_invoke_context| {}, ) diff --git a/programs/loader-v4/src/lib.rs b/programs/loader-v4/src/lib.rs index 6f15096ecc..5372975e18 100644 --- a/programs/loader-v4/src/lib.rs +++ b/programs/loader-v4/src/lib.rs @@ -12,10 +12,12 @@ use { }, solana_rbpf::{ aligned_memory::AlignedMemory, - ebpf, - elf::{Executable, FunctionRegistry}, + declare_builtin_function, ebpf, + elf::Executable, + error::ProgramResult, memory_region::{MemoryMapping, MemoryRegion}, - vm::{BuiltinProgram, Config, ContextObject, EbpfVm, ProgramResult}, + program::{BuiltinProgram, FunctionRegistry}, + vm::{Config, ContextObject, EbpfVm}, }, solana_sdk::{ entrypoint::SUCCESS, @@ -81,7 +83,6 @@ pub fn create_program_runtime_environment_v2<'a>( reject_broken_elfs: true, noop_instruction_rate: 256, sanitize_user_provided_values: true, - encrypt_runtime_environment: true, external_internal_function_hash_collision: true, reject_callx_r10: true, enable_sbpf_v1: false, @@ -131,7 +132,7 @@ pub fn create_vm<'a, 'b>( Box::new(InstructionError::ProgramEnvironmentSetupFailure) })?; Ok(EbpfVm::new( - config, + program.get_loader().clone(), sbpf_version, invoke_context, memory_mapping, @@ -182,9 +183,9 @@ fn execute<'a, 'b: 'a>( match result { ProgramResult::Ok(status) if status != SUCCESS => { let error: InstructionError = status.into(); - Err(Box::new(error) as Box) + Err(error.into()) } - ProgramResult::Err(error) => Err(error), + ProgramResult::Err(error) => Err(error.into()), _ => Ok(()), } } @@ -527,18 +528,20 @@ pub fn process_instruction_transfer_authority( Ok(()) } -pub fn process_instruction( - invoke_context: &mut InvokeContext, - _arg0: u64, - _arg1: u64, - _arg2: u64, - _arg3: u64, - _arg4: u64, - _memory_mapping: &mut MemoryMapping, - result: &mut ProgramResult, -) { - *result = process_instruction_inner(invoke_context).into(); -} +declare_builtin_function!( + Entrypoint, + fn rust( + invoke_context: &mut InvokeContext, + _arg0: u64, + _arg1: u64, + _arg2: u64, + _arg3: u64, + _arg4: u64, + _memory_mapping: &mut MemoryMapping, + ) -> Result> { + process_instruction_inner(invoke_context) + } +); pub fn process_instruction_inner( invoke_context: &mut InvokeContext, @@ -700,7 +703,7 @@ mod tests { transaction_accounts, instruction_accounts, expected_result, - super::process_instruction, + Entrypoint::vm, |invoke_context| { invoke_context .programs_modified_by_tx diff --git a/programs/sbf/Cargo.lock b/programs/sbf/Cargo.lock index e4117582ab..edb3ba7529 100644 --- a/programs/sbf/Cargo.lock +++ b/programs/sbf/Cargo.lock @@ -5341,6 +5341,7 @@ dependencies = [ "solana-runtime", "solana-sdk", "solana-vote-program", + "solana_rbpf", "test-case", "thiserror", "tokio", @@ -6514,9 +6515,9 @@ dependencies = [ [[package]] name = "solana_rbpf" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "103318aa365ff7caa8cf534f2246b5eb7e5b34668736d52b1266b143f7a21196" +checksum = "3d457cc2ba742c120492a64b7fa60e22c575e891f6b55039f4d736568fb112a3" dependencies = [ "byteorder 1.5.0", "combine", diff --git a/programs/sbf/Cargo.toml b/programs/sbf/Cargo.toml index 507bf01385..6f069a3f5b 100644 --- a/programs/sbf/Cargo.toml +++ b/programs/sbf/Cargo.toml @@ -48,7 +48,7 @@ solana-sdk = { path = "../../sdk", version = "=1.18.0" } solana-transaction-status = { path = "../../transaction-status", version = "=1.18.0" } solana-validator = { path = "../../validator", version = "=1.18.0" } solana-zk-token-sdk = { path = "../../zk-token-sdk", version = "=1.18.0" } -solana_rbpf = "=0.7.2" +solana_rbpf = "=0.8.0" static_assertions = "1.1.0" thiserror = "1.0" diff --git a/programs/sbf/tests/programs.rs b/programs/sbf/tests/programs.rs index f6b680b105..8a7cfb693a 100644 --- a/programs/sbf/tests/programs.rs +++ b/programs/sbf/tests/programs.rs @@ -1449,7 +1449,7 @@ fn assert_instruction_count() { transaction_accounts, instruction_accounts, Ok(()), - solana_bpf_loader_program::process_instruction, + solana_bpf_loader_program::Entrypoint::vm, |invoke_context| { *prev_compute_meter.borrow_mut() = invoke_context.get_remaining(); solana_bpf_loader_program::test_utils::load_all_invoked_programs(invoke_context); @@ -4397,7 +4397,7 @@ fn test_cpi_change_account_data_memory_allocation() { let feature_set = FeatureSet::all_enabled(); bank.feature_set = Arc::new(feature_set); - declare_process_instruction!(process_instruction, 42, |invoke_context| { + declare_process_instruction!(MockBuiltin, 42, |invoke_context| { let transaction_context = &invoke_context.transaction_context; let instruction_context = transaction_context.get_current_instruction_context()?; let instruction_data = instruction_context.get_instruction_data(); @@ -4428,7 +4428,7 @@ fn test_cpi_change_account_data_memory_allocation() { bank.add_builtin( builtin_program_id, "test_cpi_change_account_data_memory_allocation_builtin".to_string(), - LoadedProgram::new_builtin(0, 42, process_instruction), + LoadedProgram::new_builtin(0, 42, MockBuiltin::vm), ); let bank = Arc::new(bank); diff --git a/programs/stake/src/stake_instruction.rs b/programs/stake/src/stake_instruction.rs index 20b6c9e0eb..cd0b59e825 100644 --- a/programs/stake/src/stake_instruction.rs +++ b/programs/stake/src/stake_instruction.rs @@ -54,411 +54,391 @@ fn get_optional_pubkey<'a>( pub const DEFAULT_COMPUTE_UNITS: u64 = 750; -declare_process_instruction!( - process_instruction, - DEFAULT_COMPUTE_UNITS, - |invoke_context| { - let transaction_context = &invoke_context.transaction_context; - let instruction_context = transaction_context.get_current_instruction_context()?; - let data = instruction_context.get_instruction_data(); +declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| { + let transaction_context = &invoke_context.transaction_context; + let instruction_context = transaction_context.get_current_instruction_context()?; + let data = instruction_context.get_instruction_data(); - trace!("process_instruction: {:?}", data); + trace!("process_instruction: {:?}", data); - let get_stake_account = || { - let me = instruction_context.try_borrow_instruction_account(transaction_context, 0)?; - if *me.get_owner() != id() { - return Err(InstructionError::InvalidAccountOwner); + let get_stake_account = || { + let me = instruction_context.try_borrow_instruction_account(transaction_context, 0)?; + if *me.get_owner() != id() { + return Err(InstructionError::InvalidAccountOwner); + } + Ok(me) + }; + + let signers = instruction_context.get_signers(transaction_context)?; + match limited_deserialize(data) { + Ok(StakeInstruction::Initialize(authorized, lockup)) => { + let mut me = get_stake_account()?; + let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 1)?; + initialize(&mut me, &authorized, &lockup, &rent) + } + Ok(StakeInstruction::Authorize(authorized_pubkey, stake_authorize)) => { + let mut me = get_stake_account()?; + let require_custodian_for_locked_stake_authorize = invoke_context + .feature_set + .is_active(&feature_set::require_custodian_for_locked_stake_authorize::id()); + + if require_custodian_for_locked_stake_authorize { + let clock = + get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?; + instruction_context.check_number_of_instruction_accounts(3)?; + let custodian_pubkey = + get_optional_pubkey(transaction_context, instruction_context, 3, false)?; + + authorize( + &mut me, + &signers, + &authorized_pubkey, + stake_authorize, + require_custodian_for_locked_stake_authorize, + &clock, + custodian_pubkey, + ) + } else { + authorize( + &mut me, + &signers, + &authorized_pubkey, + stake_authorize, + require_custodian_for_locked_stake_authorize, + &Clock::default(), + None, + ) } - Ok(me) - }; + } + Ok(StakeInstruction::AuthorizeWithSeed(args)) => { + let mut me = get_stake_account()?; + instruction_context.check_number_of_instruction_accounts(2)?; + let require_custodian_for_locked_stake_authorize = invoke_context + .feature_set + .is_active(&feature_set::require_custodian_for_locked_stake_authorize::id()); + if require_custodian_for_locked_stake_authorize { + let clock = + get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?; + let custodian_pubkey = + get_optional_pubkey(transaction_context, instruction_context, 3, false)?; + + authorize_with_seed( + transaction_context, + instruction_context, + &mut me, + 1, + &args.authority_seed, + &args.authority_owner, + &args.new_authorized_pubkey, + args.stake_authorize, + require_custodian_for_locked_stake_authorize, + &clock, + custodian_pubkey, + ) + } else { + authorize_with_seed( + transaction_context, + instruction_context, + &mut me, + 1, + &args.authority_seed, + &args.authority_owner, + &args.new_authorized_pubkey, + args.stake_authorize, + require_custodian_for_locked_stake_authorize, + &Clock::default(), + None, + ) + } + } + Ok(StakeInstruction::DelegateStake) => { + let me = get_stake_account()?; + instruction_context.check_number_of_instruction_accounts(2)?; + let clock = + get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?; + let stake_history = get_sysvar_with_account_check::stake_history( + invoke_context, + instruction_context, + 3, + )?; + instruction_context.check_number_of_instruction_accounts(5)?; + drop(me); + if !invoke_context + .feature_set + .is_active(&feature_set::reduce_stake_warmup_cooldown::id()) + { + // Post feature activation, remove both the feature gate code and the config completely in the interface + let config_account = + instruction_context.try_borrow_instruction_account(transaction_context, 4)?; + #[allow(deprecated)] + if !config::check_id(config_account.get_key()) { + return Err(InstructionError::InvalidArgument); + } + config::from(&config_account).ok_or(InstructionError::InvalidArgument)?; + } + delegate( + invoke_context, + transaction_context, + instruction_context, + 0, + 1, + &clock, + &stake_history, + &signers, + &invoke_context.feature_set, + ) + } + Ok(StakeInstruction::Split(lamports)) => { + let me = get_stake_account()?; + instruction_context.check_number_of_instruction_accounts(2)?; + drop(me); + split( + invoke_context, + transaction_context, + instruction_context, + 0, + lamports, + 1, + &signers, + ) + } + Ok(StakeInstruction::Merge) => { + let me = get_stake_account()?; + instruction_context.check_number_of_instruction_accounts(2)?; + let clock = + get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?; + let stake_history = get_sysvar_with_account_check::stake_history( + invoke_context, + instruction_context, + 3, + )?; + drop(me); + merge( + invoke_context, + transaction_context, + instruction_context, + 0, + 1, + &clock, + &stake_history, + &signers, + ) + } + Ok(StakeInstruction::Withdraw(lamports)) => { + let me = get_stake_account()?; + instruction_context.check_number_of_instruction_accounts(2)?; + let clock = + get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?; + let stake_history = get_sysvar_with_account_check::stake_history( + invoke_context, + instruction_context, + 3, + )?; + instruction_context.check_number_of_instruction_accounts(5)?; + drop(me); + withdraw( + transaction_context, + instruction_context, + 0, + lamports, + 1, + &clock, + &stake_history, + 4, + if instruction_context.get_number_of_instruction_accounts() >= 6 { + Some(5) + } else { + None + }, + new_warmup_cooldown_rate_epoch(invoke_context), + ) + } + Ok(StakeInstruction::Deactivate) => { + let mut me = get_stake_account()?; + let clock = + get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?; + deactivate(invoke_context, &mut me, &clock, &signers) + } + Ok(StakeInstruction::SetLockup(lockup)) => { + let mut me = get_stake_account()?; + let clock = invoke_context.get_sysvar_cache().get_clock()?; + set_lockup(&mut me, &lockup, &signers, &clock) + } + Ok(StakeInstruction::InitializeChecked) => { + let mut me = get_stake_account()?; + if invoke_context + .feature_set + .is_active(&feature_set::vote_stake_checked_instructions::id()) + { + instruction_context.check_number_of_instruction_accounts(4)?; + let staker_pubkey = transaction_context.get_key_of_account_at_index( + instruction_context.get_index_of_instruction_account_in_transaction(2)?, + )?; + let withdrawer_pubkey = transaction_context.get_key_of_account_at_index( + instruction_context.get_index_of_instruction_account_in_transaction(3)?, + )?; + if !instruction_context.is_instruction_account_signer(3)? { + return Err(InstructionError::MissingRequiredSignature); + } + + let authorized = Authorized { + staker: *staker_pubkey, + withdrawer: *withdrawer_pubkey, + }; - let signers = instruction_context.get_signers(transaction_context)?; - match limited_deserialize(data) { - Ok(StakeInstruction::Initialize(authorized, lockup)) => { - let mut me = get_stake_account()?; let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 1)?; - initialize(&mut me, &authorized, &lockup, &rent) + initialize(&mut me, &authorized, &Lockup::default(), &rent) + } else { + Err(InstructionError::InvalidInstructionData) } - Ok(StakeInstruction::Authorize(authorized_pubkey, stake_authorize)) => { - let mut me = get_stake_account()?; - let require_custodian_for_locked_stake_authorize = invoke_context - .feature_set - .is_active(&feature_set::require_custodian_for_locked_stake_authorize::id()); - - if require_custodian_for_locked_stake_authorize { - let clock = get_sysvar_with_account_check::clock( - invoke_context, - instruction_context, - 1, - )?; - instruction_context.check_number_of_instruction_accounts(3)?; - let custodian_pubkey = - get_optional_pubkey(transaction_context, instruction_context, 3, false)?; - - authorize( - &mut me, - &signers, - &authorized_pubkey, - stake_authorize, - require_custodian_for_locked_stake_authorize, - &clock, - custodian_pubkey, - ) - } else { - authorize( - &mut me, - &signers, - &authorized_pubkey, - stake_authorize, - require_custodian_for_locked_stake_authorize, - &Clock::default(), - None, - ) + } + Ok(StakeInstruction::AuthorizeChecked(stake_authorize)) => { + let mut me = get_stake_account()?; + if invoke_context + .feature_set + .is_active(&feature_set::vote_stake_checked_instructions::id()) + { + let clock = + get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?; + instruction_context.check_number_of_instruction_accounts(4)?; + let authorized_pubkey = transaction_context.get_key_of_account_at_index( + instruction_context.get_index_of_instruction_account_in_transaction(3)?, + )?; + if !instruction_context.is_instruction_account_signer(3)? { + return Err(InstructionError::MissingRequiredSignature); } - } - Ok(StakeInstruction::AuthorizeWithSeed(args)) => { - let mut me = get_stake_account()?; - instruction_context.check_number_of_instruction_accounts(2)?; - let require_custodian_for_locked_stake_authorize = invoke_context - .feature_set - .is_active(&feature_set::require_custodian_for_locked_stake_authorize::id()); - if require_custodian_for_locked_stake_authorize { - let clock = get_sysvar_with_account_check::clock( - invoke_context, - instruction_context, - 2, - )?; - let custodian_pubkey = - get_optional_pubkey(transaction_context, instruction_context, 3, false)?; + let custodian_pubkey = + get_optional_pubkey(transaction_context, instruction_context, 4, false)?; - authorize_with_seed( - transaction_context, - instruction_context, - &mut me, - 1, - &args.authority_seed, - &args.authority_owner, - &args.new_authorized_pubkey, - args.stake_authorize, - require_custodian_for_locked_stake_authorize, - &clock, - custodian_pubkey, - ) - } else { - authorize_with_seed( - transaction_context, - instruction_context, - &mut me, - 1, - &args.authority_seed, - &args.authority_owner, - &args.new_authorized_pubkey, - args.stake_authorize, - require_custodian_for_locked_stake_authorize, - &Clock::default(), - None, - ) - } + authorize( + &mut me, + &signers, + authorized_pubkey, + stake_authorize, + true, + &clock, + custodian_pubkey, + ) + } else { + Err(InstructionError::InvalidInstructionData) } - Ok(StakeInstruction::DelegateStake) => { - let me = get_stake_account()?; + } + Ok(StakeInstruction::AuthorizeCheckedWithSeed(args)) => { + let mut me = get_stake_account()?; + if invoke_context + .feature_set + .is_active(&feature_set::vote_stake_checked_instructions::id()) + { instruction_context.check_number_of_instruction_accounts(2)?; let clock = get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?; - let stake_history = get_sysvar_with_account_check::stake_history( - invoke_context, - instruction_context, - 3, + instruction_context.check_number_of_instruction_accounts(4)?; + let authorized_pubkey = transaction_context.get_key_of_account_at_index( + instruction_context.get_index_of_instruction_account_in_transaction(3)?, )?; - instruction_context.check_number_of_instruction_accounts(5)?; - drop(me); + if !instruction_context.is_instruction_account_signer(3)? { + return Err(InstructionError::MissingRequiredSignature); + } + let custodian_pubkey = + get_optional_pubkey(transaction_context, instruction_context, 4, false)?; + + authorize_with_seed( + transaction_context, + instruction_context, + &mut me, + 1, + &args.authority_seed, + &args.authority_owner, + authorized_pubkey, + args.stake_authorize, + true, + &clock, + custodian_pubkey, + ) + } else { + Err(InstructionError::InvalidInstructionData) + } + } + Ok(StakeInstruction::SetLockupChecked(lockup_checked)) => { + let mut me = get_stake_account()?; + if invoke_context + .feature_set + .is_active(&feature_set::vote_stake_checked_instructions::id()) + { + let custodian_pubkey = + get_optional_pubkey(transaction_context, instruction_context, 2, true)?; + + let lockup = LockupArgs { + unix_timestamp: lockup_checked.unix_timestamp, + epoch: lockup_checked.epoch, + custodian: custodian_pubkey.cloned(), + }; + let clock = invoke_context.get_sysvar_cache().get_clock()?; + set_lockup(&mut me, &lockup, &signers, &clock) + } else { + Err(InstructionError::InvalidInstructionData) + } + } + Ok(StakeInstruction::GetMinimumDelegation) => { + let feature_set = invoke_context.feature_set.as_ref(); + let minimum_delegation = crate::get_minimum_delegation(feature_set); + let minimum_delegation = Vec::from(minimum_delegation.to_le_bytes()); + invoke_context + .transaction_context + .set_return_data(id(), minimum_delegation) + } + Ok(StakeInstruction::DeactivateDelinquent) => { + let mut me = get_stake_account()?; + instruction_context.check_number_of_instruction_accounts(3)?; + + let clock = invoke_context.get_sysvar_cache().get_clock()?; + deactivate_delinquent( + invoke_context, + transaction_context, + instruction_context, + &mut me, + 1, + 2, + clock.epoch, + ) + } + Ok(StakeInstruction::Redelegate) => { + let mut me = get_stake_account()?; + if invoke_context + .feature_set + .is_active(&feature_set::stake_redelegate_instruction::id()) + { + instruction_context.check_number_of_instruction_accounts(3)?; if !invoke_context .feature_set .is_active(&feature_set::reduce_stake_warmup_cooldown::id()) { // Post feature activation, remove both the feature gate code and the config completely in the interface let config_account = instruction_context - .try_borrow_instruction_account(transaction_context, 4)?; + .try_borrow_instruction_account(transaction_context, 3)?; #[allow(deprecated)] if !config::check_id(config_account.get_key()) { return Err(InstructionError::InvalidArgument); } config::from(&config_account).ok_or(InstructionError::InvalidArgument)?; } - delegate( - invoke_context, - transaction_context, - instruction_context, - 0, - 1, - &clock, - &stake_history, - &signers, - &invoke_context.feature_set, - ) - } - Ok(StakeInstruction::Split(lamports)) => { - let me = get_stake_account()?; - instruction_context.check_number_of_instruction_accounts(2)?; - drop(me); - split( - invoke_context, - transaction_context, - instruction_context, - 0, - lamports, - 1, - &signers, - ) - } - Ok(StakeInstruction::Merge) => { - let me = get_stake_account()?; - instruction_context.check_number_of_instruction_accounts(2)?; - let clock = - get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?; - let stake_history = get_sysvar_with_account_check::stake_history( - invoke_context, - instruction_context, - 3, - )?; - drop(me); - merge( - invoke_context, - transaction_context, - instruction_context, - 0, - 1, - &clock, - &stake_history, - &signers, - ) - } - Ok(StakeInstruction::Withdraw(lamports)) => { - let me = get_stake_account()?; - instruction_context.check_number_of_instruction_accounts(2)?; - let clock = - get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?; - let stake_history = get_sysvar_with_account_check::stake_history( - invoke_context, - instruction_context, - 3, - )?; - instruction_context.check_number_of_instruction_accounts(5)?; - drop(me); - withdraw( - transaction_context, - instruction_context, - 0, - lamports, - 1, - &clock, - &stake_history, - 4, - if instruction_context.get_number_of_instruction_accounts() >= 6 { - Some(5) - } else { - None - }, - new_warmup_cooldown_rate_epoch(invoke_context), - ) - } - Ok(StakeInstruction::Deactivate) => { - let mut me = get_stake_account()?; - let clock = - get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?; - deactivate(invoke_context, &mut me, &clock, &signers) - } - Ok(StakeInstruction::SetLockup(lockup)) => { - let mut me = get_stake_account()?; - let clock = invoke_context.get_sysvar_cache().get_clock()?; - set_lockup(&mut me, &lockup, &signers, &clock) - } - Ok(StakeInstruction::InitializeChecked) => { - let mut me = get_stake_account()?; - if invoke_context - .feature_set - .is_active(&feature_set::vote_stake_checked_instructions::id()) - { - instruction_context.check_number_of_instruction_accounts(4)?; - let staker_pubkey = transaction_context.get_key_of_account_at_index( - instruction_context.get_index_of_instruction_account_in_transaction(2)?, - )?; - let withdrawer_pubkey = transaction_context.get_key_of_account_at_index( - instruction_context.get_index_of_instruction_account_in_transaction(3)?, - )?; - if !instruction_context.is_instruction_account_signer(3)? { - return Err(InstructionError::MissingRequiredSignature); - } - - let authorized = Authorized { - staker: *staker_pubkey, - withdrawer: *withdrawer_pubkey, - }; - - let rent = get_sysvar_with_account_check::rent( - invoke_context, - instruction_context, - 1, - )?; - initialize(&mut me, &authorized, &Lockup::default(), &rent) - } else { - Err(InstructionError::InvalidInstructionData) - } - } - Ok(StakeInstruction::AuthorizeChecked(stake_authorize)) => { - let mut me = get_stake_account()?; - if invoke_context - .feature_set - .is_active(&feature_set::vote_stake_checked_instructions::id()) - { - let clock = get_sysvar_with_account_check::clock( - invoke_context, - instruction_context, - 1, - )?; - instruction_context.check_number_of_instruction_accounts(4)?; - let authorized_pubkey = transaction_context.get_key_of_account_at_index( - instruction_context.get_index_of_instruction_account_in_transaction(3)?, - )?; - if !instruction_context.is_instruction_account_signer(3)? { - return Err(InstructionError::MissingRequiredSignature); - } - let custodian_pubkey = - get_optional_pubkey(transaction_context, instruction_context, 4, false)?; - - authorize( - &mut me, - &signers, - authorized_pubkey, - stake_authorize, - true, - &clock, - custodian_pubkey, - ) - } else { - Err(InstructionError::InvalidInstructionData) - } - } - Ok(StakeInstruction::AuthorizeCheckedWithSeed(args)) => { - let mut me = get_stake_account()?; - if invoke_context - .feature_set - .is_active(&feature_set::vote_stake_checked_instructions::id()) - { - instruction_context.check_number_of_instruction_accounts(2)?; - let clock = get_sysvar_with_account_check::clock( - invoke_context, - instruction_context, - 2, - )?; - instruction_context.check_number_of_instruction_accounts(4)?; - let authorized_pubkey = transaction_context.get_key_of_account_at_index( - instruction_context.get_index_of_instruction_account_in_transaction(3)?, - )?; - if !instruction_context.is_instruction_account_signer(3)? { - return Err(InstructionError::MissingRequiredSignature); - } - let custodian_pubkey = - get_optional_pubkey(transaction_context, instruction_context, 4, false)?; - - authorize_with_seed( - transaction_context, - instruction_context, - &mut me, - 1, - &args.authority_seed, - &args.authority_owner, - authorized_pubkey, - args.stake_authorize, - true, - &clock, - custodian_pubkey, - ) - } else { - Err(InstructionError::InvalidInstructionData) - } - } - Ok(StakeInstruction::SetLockupChecked(lockup_checked)) => { - let mut me = get_stake_account()?; - if invoke_context - .feature_set - .is_active(&feature_set::vote_stake_checked_instructions::id()) - { - let custodian_pubkey = - get_optional_pubkey(transaction_context, instruction_context, 2, true)?; - - let lockup = LockupArgs { - unix_timestamp: lockup_checked.unix_timestamp, - epoch: lockup_checked.epoch, - custodian: custodian_pubkey.cloned(), - }; - let clock = invoke_context.get_sysvar_cache().get_clock()?; - set_lockup(&mut me, &lockup, &signers, &clock) - } else { - Err(InstructionError::InvalidInstructionData) - } - } - Ok(StakeInstruction::GetMinimumDelegation) => { - let feature_set = invoke_context.feature_set.as_ref(); - let minimum_delegation = crate::get_minimum_delegation(feature_set); - let minimum_delegation = Vec::from(minimum_delegation.to_le_bytes()); - invoke_context - .transaction_context - .set_return_data(id(), minimum_delegation) - } - Ok(StakeInstruction::DeactivateDelinquent) => { - let mut me = get_stake_account()?; - instruction_context.check_number_of_instruction_accounts(3)?; - - let clock = invoke_context.get_sysvar_cache().get_clock()?; - deactivate_delinquent( + redelegate( invoke_context, transaction_context, instruction_context, &mut me, 1, 2, - clock.epoch, + &signers, ) + } else { + Err(InstructionError::InvalidInstructionData) } - Ok(StakeInstruction::Redelegate) => { - let mut me = get_stake_account()?; - if invoke_context - .feature_set - .is_active(&feature_set::stake_redelegate_instruction::id()) - { - instruction_context.check_number_of_instruction_accounts(3)?; - if !invoke_context - .feature_set - .is_active(&feature_set::reduce_stake_warmup_cooldown::id()) - { - // Post feature activation, remove both the feature gate code and the config completely in the interface - let config_account = instruction_context - .try_borrow_instruction_account(transaction_context, 3)?; - #[allow(deprecated)] - if !config::check_id(config_account.get_key()) { - return Err(InstructionError::InvalidArgument); - } - config::from(&config_account).ok_or(InstructionError::InvalidArgument)?; - } - redelegate( - invoke_context, - transaction_context, - instruction_context, - &mut me, - 1, - 2, - &signers, - ) - } else { - Err(InstructionError::InvalidInstructionData) - } - } - Err(err) => Err(err), } + Err(err) => Err(err), } -); +}); #[cfg(test)] mod tests { @@ -572,7 +552,7 @@ mod tests { transaction_accounts, instruction_accounts, expected_result, - super::process_instruction, + Entrypoint::vm, |invoke_context| { invoke_context.feature_set = Arc::clone(&feature_set); }, @@ -7046,7 +7026,7 @@ mod tests { transaction_accounts, instruction_accounts, Ok(()), - super::process_instruction, + Entrypoint::vm, |invoke_context| { invoke_context.feature_set = Arc::clone(&feature_set); }, diff --git a/programs/system/src/system_processor.rs b/programs/system/src/system_processor.rs index dc6c1e3dbe..b224997dc6 100644 --- a/programs/system/src/system_processor.rs +++ b/programs/system/src/system_processor.rs @@ -314,252 +314,246 @@ fn transfer_with_seed( pub const DEFAULT_COMPUTE_UNITS: u64 = 150; -declare_process_instruction!( - process_instruction, - DEFAULT_COMPUTE_UNITS, - |invoke_context| { - let transaction_context = &invoke_context.transaction_context; - let instruction_context = transaction_context.get_current_instruction_context()?; - let instruction_data = instruction_context.get_instruction_data(); - let instruction = limited_deserialize(instruction_data)?; +declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| { + let transaction_context = &invoke_context.transaction_context; + let instruction_context = transaction_context.get_current_instruction_context()?; + let instruction_data = instruction_context.get_instruction_data(); + let instruction = limited_deserialize(instruction_data)?; - trace!("process_instruction: {:?}", instruction); + trace!("process_instruction: {:?}", instruction); - let signers = instruction_context.get_signers(transaction_context)?; - match instruction { - SystemInstruction::CreateAccount { + let signers = instruction_context.get_signers(transaction_context)?; + match instruction { + SystemInstruction::CreateAccount { + lamports, + space, + owner, + } => { + instruction_context.check_number_of_instruction_accounts(2)?; + let to_address = Address::create( + transaction_context.get_key_of_account_at_index( + instruction_context.get_index_of_instruction_account_in_transaction(1)?, + )?, + None, + invoke_context, + )?; + create_account( + 0, + 1, + &to_address, lamports, space, - owner, - } => { - instruction_context.check_number_of_instruction_accounts(2)?; - let to_address = Address::create( - transaction_context.get_key_of_account_at_index( - instruction_context.get_index_of_instruction_account_in_transaction(1)?, - )?, - None, - invoke_context, - )?; - create_account( - 0, - 1, - &to_address, - lamports, - space, - &owner, - &signers, - invoke_context, - transaction_context, - instruction_context, - ) - } - SystemInstruction::CreateAccountWithSeed { - base, - seed, + &owner, + &signers, + invoke_context, + transaction_context, + instruction_context, + ) + } + SystemInstruction::CreateAccountWithSeed { + base, + seed, + lamports, + space, + owner, + } => { + instruction_context.check_number_of_instruction_accounts(2)?; + let to_address = Address::create( + transaction_context.get_key_of_account_at_index( + instruction_context.get_index_of_instruction_account_in_transaction(1)?, + )?, + Some((&base, &seed, &owner)), + invoke_context, + )?; + create_account( + 0, + 1, + &to_address, lamports, space, - owner, - } => { - instruction_context.check_number_of_instruction_accounts(2)?; - let to_address = Address::create( - transaction_context.get_key_of_account_at_index( - instruction_context.get_index_of_instruction_account_in_transaction(1)?, - )?, - Some((&base, &seed, &owner)), - invoke_context, - )?; - create_account( - 0, - 1, - &to_address, - lamports, - space, - &owner, - &signers, - invoke_context, - transaction_context, - instruction_context, - ) - } - SystemInstruction::Assign { owner } => { - instruction_context.check_number_of_instruction_accounts(1)?; - let mut account = - instruction_context.try_borrow_instruction_account(transaction_context, 0)?; - let address = Address::create( - transaction_context.get_key_of_account_at_index( - instruction_context.get_index_of_instruction_account_in_transaction(0)?, - )?, - None, - invoke_context, - )?; - assign(&mut account, &address, &owner, &signers, invoke_context) - } - SystemInstruction::Transfer { lamports } => { - instruction_context.check_number_of_instruction_accounts(2)?; - transfer( - 0, - 1, - lamports, - invoke_context, - transaction_context, - instruction_context, - ) - } - SystemInstruction::TransferWithSeed { + &owner, + &signers, + invoke_context, + transaction_context, + instruction_context, + ) + } + SystemInstruction::Assign { owner } => { + instruction_context.check_number_of_instruction_accounts(1)?; + let mut account = + instruction_context.try_borrow_instruction_account(transaction_context, 0)?; + let address = Address::create( + transaction_context.get_key_of_account_at_index( + instruction_context.get_index_of_instruction_account_in_transaction(0)?, + )?, + None, + invoke_context, + )?; + assign(&mut account, &address, &owner, &signers, invoke_context) + } + SystemInstruction::Transfer { lamports } => { + instruction_context.check_number_of_instruction_accounts(2)?; + transfer( + 0, + 1, lamports, - from_seed, - from_owner, - } => { - instruction_context.check_number_of_instruction_accounts(3)?; - transfer_with_seed( - 0, - 1, - &from_seed, - &from_owner, - 2, - lamports, + invoke_context, + transaction_context, + instruction_context, + ) + } + SystemInstruction::TransferWithSeed { + lamports, + from_seed, + from_owner, + } => { + instruction_context.check_number_of_instruction_accounts(3)?; + transfer_with_seed( + 0, + 1, + &from_seed, + &from_owner, + 2, + lamports, + invoke_context, + transaction_context, + instruction_context, + ) + } + SystemInstruction::AdvanceNonceAccount => { + instruction_context.check_number_of_instruction_accounts(1)?; + let mut me = + instruction_context.try_borrow_instruction_account(transaction_context, 0)?; + #[allow(deprecated)] + let recent_blockhashes = get_sysvar_with_account_check::recent_blockhashes( + invoke_context, + instruction_context, + 1, + )?; + if recent_blockhashes.is_empty() { + ic_msg!( invoke_context, - transaction_context, - instruction_context, - ) + "Advance nonce account: recent blockhash list is empty", + ); + return Err(SystemError::NonceNoRecentBlockhashes.into()); } - SystemInstruction::AdvanceNonceAccount => { - instruction_context.check_number_of_instruction_accounts(1)?; - let mut me = - instruction_context.try_borrow_instruction_account(transaction_context, 0)?; - #[allow(deprecated)] - let recent_blockhashes = get_sysvar_with_account_check::recent_blockhashes( + advance_nonce_account(&mut me, &signers, invoke_context) + } + SystemInstruction::WithdrawNonceAccount(lamports) => { + instruction_context.check_number_of_instruction_accounts(2)?; + #[allow(deprecated)] + let _recent_blockhashes = get_sysvar_with_account_check::recent_blockhashes( + invoke_context, + instruction_context, + 2, + )?; + let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 3)?; + withdraw_nonce_account( + 0, + lamports, + 1, + &rent, + &signers, + invoke_context, + transaction_context, + instruction_context, + ) + } + SystemInstruction::InitializeNonceAccount(authorized) => { + instruction_context.check_number_of_instruction_accounts(1)?; + let mut me = + instruction_context.try_borrow_instruction_account(transaction_context, 0)?; + #[allow(deprecated)] + let recent_blockhashes = get_sysvar_with_account_check::recent_blockhashes( + invoke_context, + instruction_context, + 1, + )?; + if recent_blockhashes.is_empty() { + ic_msg!( invoke_context, - instruction_context, - 1, - )?; - if recent_blockhashes.is_empty() { - ic_msg!( - invoke_context, - "Advance nonce account: recent blockhash list is empty", - ); - return Err(SystemError::NonceNoRecentBlockhashes.into()); - } - advance_nonce_account(&mut me, &signers, invoke_context) + "Initialize nonce account: recent blockhash list is empty", + ); + return Err(SystemError::NonceNoRecentBlockhashes.into()); } - SystemInstruction::WithdrawNonceAccount(lamports) => { - instruction_context.check_number_of_instruction_accounts(2)?; - #[allow(deprecated)] - let _recent_blockhashes = get_sysvar_with_account_check::recent_blockhashes( - invoke_context, - instruction_context, - 2, - )?; - let rent = - get_sysvar_with_account_check::rent(invoke_context, instruction_context, 3)?; - withdraw_nonce_account( - 0, - lamports, - 1, - &rent, - &signers, - invoke_context, - transaction_context, - instruction_context, - ) + let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 2)?; + initialize_nonce_account(&mut me, &authorized, &rent, invoke_context) + } + SystemInstruction::AuthorizeNonceAccount(nonce_authority) => { + instruction_context.check_number_of_instruction_accounts(1)?; + let mut me = + instruction_context.try_borrow_instruction_account(transaction_context, 0)?; + authorize_nonce_account(&mut me, &nonce_authority, &signers, invoke_context) + } + SystemInstruction::UpgradeNonceAccount => { + instruction_context.check_number_of_instruction_accounts(1)?; + let mut nonce_account = + instruction_context.try_borrow_instruction_account(transaction_context, 0)?; + if !system_program::check_id(nonce_account.get_owner()) { + return Err(InstructionError::InvalidAccountOwner); } - SystemInstruction::InitializeNonceAccount(authorized) => { - instruction_context.check_number_of_instruction_accounts(1)?; - let mut me = - instruction_context.try_borrow_instruction_account(transaction_context, 0)?; - #[allow(deprecated)] - let recent_blockhashes = get_sysvar_with_account_check::recent_blockhashes( - invoke_context, - instruction_context, - 1, - )?; - if recent_blockhashes.is_empty() { - ic_msg!( - invoke_context, - "Initialize nonce account: recent blockhash list is empty", - ); - return Err(SystemError::NonceNoRecentBlockhashes.into()); - } - let rent = - get_sysvar_with_account_check::rent(invoke_context, instruction_context, 2)?; - initialize_nonce_account(&mut me, &authorized, &rent, invoke_context) + if !nonce_account.is_writable() { + return Err(InstructionError::InvalidArgument); } - SystemInstruction::AuthorizeNonceAccount(nonce_authority) => { - instruction_context.check_number_of_instruction_accounts(1)?; - let mut me = - instruction_context.try_borrow_instruction_account(transaction_context, 0)?; - authorize_nonce_account(&mut me, &nonce_authority, &signers, invoke_context) - } - SystemInstruction::UpgradeNonceAccount => { - instruction_context.check_number_of_instruction_accounts(1)?; - let mut nonce_account = - instruction_context.try_borrow_instruction_account(transaction_context, 0)?; - if !system_program::check_id(nonce_account.get_owner()) { - return Err(InstructionError::InvalidAccountOwner); - } - if !nonce_account.is_writable() { - return Err(InstructionError::InvalidArgument); - } - let nonce_versions: nonce::state::Versions = nonce_account.get_state()?; - match nonce_versions.upgrade() { - None => Err(InstructionError::InvalidArgument), - Some(nonce_versions) => nonce_account.set_state(&nonce_versions), - } - } - SystemInstruction::Allocate { space } => { - instruction_context.check_number_of_instruction_accounts(1)?; - let mut account = - instruction_context.try_borrow_instruction_account(transaction_context, 0)?; - let address = Address::create( - transaction_context.get_key_of_account_at_index( - instruction_context.get_index_of_instruction_account_in_transaction(0)?, - )?, - None, - invoke_context, - )?; - allocate(&mut account, &address, space, &signers, invoke_context) - } - SystemInstruction::AllocateWithSeed { - base, - seed, - space, - owner, - } => { - instruction_context.check_number_of_instruction_accounts(1)?; - let mut account = - instruction_context.try_borrow_instruction_account(transaction_context, 0)?; - let address = Address::create( - transaction_context.get_key_of_account_at_index( - instruction_context.get_index_of_instruction_account_in_transaction(0)?, - )?, - Some((&base, &seed, &owner)), - invoke_context, - )?; - allocate_and_assign( - &mut account, - &address, - space, - &owner, - &signers, - invoke_context, - ) - } - SystemInstruction::AssignWithSeed { base, seed, owner } => { - instruction_context.check_number_of_instruction_accounts(1)?; - let mut account = - instruction_context.try_borrow_instruction_account(transaction_context, 0)?; - let address = Address::create( - transaction_context.get_key_of_account_at_index( - instruction_context.get_index_of_instruction_account_in_transaction(0)?, - )?, - Some((&base, &seed, &owner)), - invoke_context, - )?; - assign(&mut account, &address, &owner, &signers, invoke_context) + let nonce_versions: nonce::state::Versions = nonce_account.get_state()?; + match nonce_versions.upgrade() { + None => Err(InstructionError::InvalidArgument), + Some(nonce_versions) => nonce_account.set_state(&nonce_versions), } } + SystemInstruction::Allocate { space } => { + instruction_context.check_number_of_instruction_accounts(1)?; + let mut account = + instruction_context.try_borrow_instruction_account(transaction_context, 0)?; + let address = Address::create( + transaction_context.get_key_of_account_at_index( + instruction_context.get_index_of_instruction_account_in_transaction(0)?, + )?, + None, + invoke_context, + )?; + allocate(&mut account, &address, space, &signers, invoke_context) + } + SystemInstruction::AllocateWithSeed { + base, + seed, + space, + owner, + } => { + instruction_context.check_number_of_instruction_accounts(1)?; + let mut account = + instruction_context.try_borrow_instruction_account(transaction_context, 0)?; + let address = Address::create( + transaction_context.get_key_of_account_at_index( + instruction_context.get_index_of_instruction_account_in_transaction(0)?, + )?, + Some((&base, &seed, &owner)), + invoke_context, + )?; + allocate_and_assign( + &mut account, + &address, + space, + &owner, + &signers, + invoke_context, + ) + } + SystemInstruction::AssignWithSeed { base, seed, owner } => { + instruction_context.check_number_of_instruction_accounts(1)?; + let mut account = + instruction_context.try_borrow_instruction_account(transaction_context, 0)?; + let address = Address::create( + transaction_context.get_key_of_account_at_index( + instruction_context.get_index_of_instruction_account_in_transaction(0)?, + )?, + Some((&base, &seed, &owner)), + invoke_context, + )?; + assign(&mut account, &address, &owner, &signers, invoke_context) + } } -); +}); #[cfg(test)] mod tests { @@ -609,7 +603,7 @@ mod tests { transaction_accounts, instruction_accounts, expected_result, - super::process_instruction, + Entrypoint::vm, |_invoke_context| {}, |_invoke_context| {}, ) @@ -1599,7 +1593,7 @@ mod tests { }, ], Ok(()), - super::process_instruction, + Entrypoint::vm, |invoke_context: &mut InvokeContext| { invoke_context.blockhash = hash(&serialize(&0).unwrap()); }, @@ -1946,7 +1940,7 @@ mod tests { }, ], Err(SystemError::NonceNoRecentBlockhashes.into()), - super::process_instruction, + Entrypoint::vm, |invoke_context: &mut InvokeContext| { invoke_context.blockhash = hash(&serialize(&0).unwrap()); }, diff --git a/programs/vote/benches/process_vote.rs b/programs/vote/benches/process_vote.rs index 6c9cb979c9..9008971f08 100644 --- a/programs/vote/benches/process_vote.rs +++ b/programs/vote/benches/process_vote.rs @@ -108,7 +108,7 @@ fn bench_process_vote_instruction( transaction_accounts.clone(), instruction_account_metas.clone(), Ok(()), - solana_vote_program::vote_processor::process_instruction, + solana_vote_program::vote_processor::Entrypoint::vm, |_invoke_context| {}, |_invoke_context| {}, ); diff --git a/programs/vote/src/vote_processor.rs b/programs/vote/src/vote_processor.rs index 423193f5d3..d09309ddc8 100644 --- a/programs/vote/src/vote_processor.rs +++ b/programs/vote/src/vote_processor.rs @@ -54,209 +54,198 @@ fn process_authorize_with_seed_instruction( // units; can consume based on instructions in the future like `bpf_loader` does. pub const DEFAULT_COMPUTE_UNITS: u64 = 2_100; -declare_process_instruction!( - process_instruction, - DEFAULT_COMPUTE_UNITS, - |invoke_context| { - let transaction_context = &invoke_context.transaction_context; - let instruction_context = transaction_context.get_current_instruction_context()?; - let data = instruction_context.get_instruction_data(); +declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| { + let transaction_context = &invoke_context.transaction_context; + let instruction_context = transaction_context.get_current_instruction_context()?; + let data = instruction_context.get_instruction_data(); - trace!("process_instruction: {:?}", data); + trace!("process_instruction: {:?}", data); - let mut me = instruction_context.try_borrow_instruction_account(transaction_context, 0)?; - if *me.get_owner() != id() { - return Err(InstructionError::InvalidAccountOwner); + let mut me = instruction_context.try_borrow_instruction_account(transaction_context, 0)?; + if *me.get_owner() != id() { + return Err(InstructionError::InvalidAccountOwner); + } + + let signers = instruction_context.get_signers(transaction_context)?; + match limited_deserialize(data)? { + VoteInstruction::InitializeAccount(vote_init) => { + let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 1)?; + if !rent.is_exempt(me.get_lamports(), me.get_data().len()) { + return Err(InstructionError::InsufficientFunds); + } + let clock = + get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?; + vote_state::initialize_account( + &mut me, + &vote_init, + &signers, + &clock, + &invoke_context.feature_set, + ) + } + VoteInstruction::Authorize(voter_pubkey, vote_authorize) => { + let clock = + get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?; + vote_state::authorize( + &mut me, + &voter_pubkey, + vote_authorize, + &signers, + &clock, + &invoke_context.feature_set, + ) + } + VoteInstruction::AuthorizeWithSeed(args) => { + instruction_context.check_number_of_instruction_accounts(3)?; + process_authorize_with_seed_instruction( + invoke_context, + instruction_context, + transaction_context, + &mut me, + &args.new_authority, + args.authorization_type, + &args.current_authority_derived_key_owner, + args.current_authority_derived_key_seed.as_str(), + ) + } + VoteInstruction::AuthorizeCheckedWithSeed(args) => { + instruction_context.check_number_of_instruction_accounts(4)?; + let new_authority = transaction_context.get_key_of_account_at_index( + instruction_context.get_index_of_instruction_account_in_transaction(3)?, + )?; + if !instruction_context.is_instruction_account_signer(3)? { + return Err(InstructionError::MissingRequiredSignature); + } + process_authorize_with_seed_instruction( + invoke_context, + instruction_context, + transaction_context, + &mut me, + new_authority, + args.authorization_type, + &args.current_authority_derived_key_owner, + args.current_authority_derived_key_seed.as_str(), + ) + } + VoteInstruction::UpdateValidatorIdentity => { + instruction_context.check_number_of_instruction_accounts(2)?; + let node_pubkey = transaction_context.get_key_of_account_at_index( + instruction_context.get_index_of_instruction_account_in_transaction(1)?, + )?; + vote_state::update_validator_identity( + &mut me, + node_pubkey, + &signers, + &invoke_context.feature_set, + ) + } + VoteInstruction::UpdateCommission(commission) => { + if invoke_context.feature_set.is_active( + &feature_set::commission_updates_only_allowed_in_first_half_of_epoch::id(), + ) { + let sysvar_cache = invoke_context.get_sysvar_cache(); + let epoch_schedule = sysvar_cache.get_epoch_schedule()?; + let clock = sysvar_cache.get_clock()?; + if !vote_state::is_commission_update_allowed(clock.slot, &epoch_schedule) { + return Err(VoteError::CommissionUpdateTooLate.into()); + } + } + vote_state::update_commission( + &mut me, + commission, + &signers, + &invoke_context.feature_set, + ) + } + VoteInstruction::Vote(vote) | VoteInstruction::VoteSwitch(vote, _) => { + let slot_hashes = + get_sysvar_with_account_check::slot_hashes(invoke_context, instruction_context, 1)?; + let clock = + get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?; + vote_state::process_vote_with_account( + &mut me, + &slot_hashes, + &clock, + &vote, + &signers, + &invoke_context.feature_set, + ) + } + VoteInstruction::UpdateVoteState(vote_state_update) + | VoteInstruction::UpdateVoteStateSwitch(vote_state_update, _) => { + let sysvar_cache = invoke_context.get_sysvar_cache(); + let slot_hashes = sysvar_cache.get_slot_hashes()?; + let clock = sysvar_cache.get_clock()?; + vote_state::process_vote_state_update( + &mut me, + slot_hashes.slot_hashes(), + &clock, + vote_state_update, + &signers, + &invoke_context.feature_set, + ) + } + VoteInstruction::CompactUpdateVoteState(vote_state_update) + | VoteInstruction::CompactUpdateVoteStateSwitch(vote_state_update, _) => { + let sysvar_cache = invoke_context.get_sysvar_cache(); + let slot_hashes = sysvar_cache.get_slot_hashes()?; + let clock = sysvar_cache.get_clock()?; + vote_state::process_vote_state_update( + &mut me, + slot_hashes.slot_hashes(), + &clock, + vote_state_update, + &signers, + &invoke_context.feature_set, + ) } - let signers = instruction_context.get_signers(transaction_context)?; - match limited_deserialize(data)? { - VoteInstruction::InitializeAccount(vote_init) => { - let rent = - get_sysvar_with_account_check::rent(invoke_context, instruction_context, 1)?; - if !rent.is_exempt(me.get_lamports(), me.get_data().len()) { - return Err(InstructionError::InsufficientFunds); - } - let clock = - get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?; - vote_state::initialize_account( - &mut me, - &vote_init, - &signers, - &clock, - &invoke_context.feature_set, - ) - } - VoteInstruction::Authorize(voter_pubkey, vote_authorize) => { - let clock = - get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?; - vote_state::authorize( - &mut me, - &voter_pubkey, - vote_authorize, - &signers, - &clock, - &invoke_context.feature_set, - ) - } - VoteInstruction::AuthorizeWithSeed(args) => { - instruction_context.check_number_of_instruction_accounts(3)?; - process_authorize_with_seed_instruction( - invoke_context, - instruction_context, - transaction_context, - &mut me, - &args.new_authority, - args.authorization_type, - &args.current_authority_derived_key_owner, - args.current_authority_derived_key_seed.as_str(), - ) - } - VoteInstruction::AuthorizeCheckedWithSeed(args) => { + VoteInstruction::Withdraw(lamports) => { + instruction_context.check_number_of_instruction_accounts(2)?; + let rent_sysvar = invoke_context.get_sysvar_cache().get_rent()?; + let clock_sysvar = invoke_context.get_sysvar_cache().get_clock()?; + + drop(me); + vote_state::withdraw( + transaction_context, + instruction_context, + 0, + lamports, + 1, + &signers, + &rent_sysvar, + &clock_sysvar, + &invoke_context.feature_set, + ) + } + VoteInstruction::AuthorizeChecked(vote_authorize) => { + if invoke_context + .feature_set + .is_active(&feature_set::vote_stake_checked_instructions::id()) + { instruction_context.check_number_of_instruction_accounts(4)?; - let new_authority = transaction_context.get_key_of_account_at_index( + let voter_pubkey = transaction_context.get_key_of_account_at_index( instruction_context.get_index_of_instruction_account_in_transaction(3)?, )?; if !instruction_context.is_instruction_account_signer(3)? { return Err(InstructionError::MissingRequiredSignature); } - process_authorize_with_seed_instruction( - invoke_context, - instruction_context, - transaction_context, - &mut me, - new_authority, - args.authorization_type, - &args.current_authority_derived_key_owner, - args.current_authority_derived_key_seed.as_str(), - ) - } - VoteInstruction::UpdateValidatorIdentity => { - instruction_context.check_number_of_instruction_accounts(2)?; - let node_pubkey = transaction_context.get_key_of_account_at_index( - instruction_context.get_index_of_instruction_account_in_transaction(1)?, - )?; - vote_state::update_validator_identity( - &mut me, - node_pubkey, - &signers, - &invoke_context.feature_set, - ) - } - VoteInstruction::UpdateCommission(commission) => { - if invoke_context.feature_set.is_active( - &feature_set::commission_updates_only_allowed_in_first_half_of_epoch::id(), - ) { - let sysvar_cache = invoke_context.get_sysvar_cache(); - let epoch_schedule = sysvar_cache.get_epoch_schedule()?; - let clock = sysvar_cache.get_clock()?; - if !vote_state::is_commission_update_allowed(clock.slot, &epoch_schedule) { - return Err(VoteError::CommissionUpdateTooLate.into()); - } - } - vote_state::update_commission( - &mut me, - commission, - &signers, - &invoke_context.feature_set, - ) - } - VoteInstruction::Vote(vote) | VoteInstruction::VoteSwitch(vote, _) => { - let slot_hashes = get_sysvar_with_account_check::slot_hashes( - invoke_context, - instruction_context, - 1, - )?; let clock = - get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?; - vote_state::process_vote_with_account( + get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?; + vote_state::authorize( &mut me, - &slot_hashes, + voter_pubkey, + vote_authorize, + &signers, &clock, - &vote, - &signers, &invoke_context.feature_set, ) - } - VoteInstruction::UpdateVoteState(vote_state_update) - | VoteInstruction::UpdateVoteStateSwitch(vote_state_update, _) => { - let sysvar_cache = invoke_context.get_sysvar_cache(); - let slot_hashes = sysvar_cache.get_slot_hashes()?; - let clock = sysvar_cache.get_clock()?; - vote_state::process_vote_state_update( - &mut me, - slot_hashes.slot_hashes(), - &clock, - vote_state_update, - &signers, - &invoke_context.feature_set, - ) - } - VoteInstruction::CompactUpdateVoteState(vote_state_update) - | VoteInstruction::CompactUpdateVoteStateSwitch(vote_state_update, _) => { - let sysvar_cache = invoke_context.get_sysvar_cache(); - let slot_hashes = sysvar_cache.get_slot_hashes()?; - let clock = sysvar_cache.get_clock()?; - vote_state::process_vote_state_update( - &mut me, - slot_hashes.slot_hashes(), - &clock, - vote_state_update, - &signers, - &invoke_context.feature_set, - ) - } - - VoteInstruction::Withdraw(lamports) => { - instruction_context.check_number_of_instruction_accounts(2)?; - let rent_sysvar = invoke_context.get_sysvar_cache().get_rent()?; - let clock_sysvar = invoke_context.get_sysvar_cache().get_clock()?; - - drop(me); - vote_state::withdraw( - transaction_context, - instruction_context, - 0, - lamports, - 1, - &signers, - &rent_sysvar, - &clock_sysvar, - &invoke_context.feature_set, - ) - } - VoteInstruction::AuthorizeChecked(vote_authorize) => { - if invoke_context - .feature_set - .is_active(&feature_set::vote_stake_checked_instructions::id()) - { - instruction_context.check_number_of_instruction_accounts(4)?; - let voter_pubkey = transaction_context.get_key_of_account_at_index( - instruction_context.get_index_of_instruction_account_in_transaction(3)?, - )?; - if !instruction_context.is_instruction_account_signer(3)? { - return Err(InstructionError::MissingRequiredSignature); - } - let clock = get_sysvar_with_account_check::clock( - invoke_context, - instruction_context, - 1, - )?; - vote_state::authorize( - &mut me, - voter_pubkey, - vote_authorize, - &signers, - &clock, - &invoke_context.feature_set, - ) - } else { - Err(InstructionError::InvalidInstructionData) - } + } else { + Err(InstructionError::InvalidInstructionData) } } } -); +}); #[cfg(test)] mod tests { @@ -320,7 +309,7 @@ mod tests { transaction_accounts, instruction_accounts, expected_result, - super::process_instruction, + Entrypoint::vm, |_invoke_context| {}, |_invoke_context| {}, ) @@ -339,7 +328,7 @@ mod tests { transaction_accounts, instruction_accounts, expected_result, - super::process_instruction, + Entrypoint::vm, |invoke_context| { invoke_context.feature_set = std::sync::Arc::new(FeatureSet::default()); }, diff --git a/programs/zk-token-proof/src/lib.rs b/programs/zk-token-proof/src/lib.rs index 6ed1fb1f33..3e43c564e7 100644 --- a/programs/zk-token-proof/src/lib.rs +++ b/programs/zk-token-proof/src/lib.rs @@ -130,7 +130,7 @@ fn process_close_proof_context(invoke_context: &mut InvokeContext) -> Result<(), Ok(()) } -declare_process_instruction!(process_instruction, 0, |invoke_context| { +declare_process_instruction!(Entrypoint, 0, |invoke_context| { // Consume compute units if feature `native_programs_consume_cu` is activated let native_programs_consume_cu = invoke_context .feature_set diff --git a/runtime/benches/bank.rs b/runtime/benches/bank.rs index b853789ddb..21f4976d69 100644 --- a/runtime/benches/bank.rs +++ b/runtime/benches/bank.rs @@ -125,13 +125,13 @@ fn do_bench_transactions( // freeze bank so that slot hashes is populated bank.freeze(); - declare_process_instruction!(process_instruction, 1, |_invoke_context| { + declare_process_instruction!(MockBuiltin, 1, |_invoke_context| { // Do nothing Ok(()) }); let mut bank = Bank::new_from_parent(Arc::new(bank), &Pubkey::default(), 1); - bank.add_mockup_builtin(Pubkey::from(BUILTIN_PROGRAM_ID), process_instruction); + bank.add_mockup_builtin(Pubkey::from(BUILTIN_PROGRAM_ID), MockBuiltin::vm); bank.add_builtin_account("solana_noop_program", &Pubkey::from(NOOP_PROGRAM_ID), false); let bank = Arc::new(bank); let bank_client = BankClient::new_shared(bank.clone()); diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 9758210182..8402c2f05d 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -107,7 +107,7 @@ use { solana_program_runtime::{ accounts_data_meter::MAX_ACCOUNTS_DATA_LEN, compute_budget::{self, ComputeBudget}, - invoke_context::ProcessInstructionWithContext, + invoke_context::BuiltinFunctionWithContext, loaded_programs::{ LoadProgramMetrics, LoadedProgram, LoadedProgramMatchCriteria, LoadedProgramType, LoadedPrograms, LoadedProgramsForTxBatch, WorkingSlot, DELAY_VISIBILITY_SLOT_OFFSET, @@ -7885,12 +7885,12 @@ impl Bank { pub fn add_mockup_builtin( &mut self, program_id: Pubkey, - entrypoint: ProcessInstructionWithContext, + builtin_function: BuiltinFunctionWithContext, ) { self.add_builtin( program_id, "mockup".to_string(), - LoadedProgram::new_builtin(self.slot, 0, entrypoint), + LoadedProgram::new_builtin(self.slot, 0, builtin_function), ); } diff --git a/runtime/src/bank/tests.rs b/runtime/src/bank/tests.rs index 82393ef716..a20c6e3740 100644 --- a/runtime/src/bank/tests.rs +++ b/runtime/src/bank/tests.rs @@ -653,7 +653,7 @@ fn assert_capitalization_diff( } } -declare_process_instruction!(process_instruction, 1, |_invoke_context| { +declare_process_instruction!(MockBuiltin, 1, |_invoke_context| { // Default for all tests which don't bring their own processor Ok(()) }); @@ -1246,7 +1246,7 @@ fn test_rent_complex() { Deduction, } - declare_process_instruction!(process_instruction, 1, |invoke_context| { + declare_process_instruction!(MockBuiltin, 1, |invoke_context| { let transaction_context = &invoke_context.transaction_context; let instruction_context = transaction_context.get_current_instruction_context()?; let instruction_data = instruction_context.get_instruction_data(); @@ -1281,7 +1281,7 @@ fn test_rent_complex() { root_bank.restore_old_behavior_for_fragile_tests(); let root_bank = Arc::new(root_bank); let mut bank = create_child_bank_for_rent_test(root_bank, &genesis_config); - bank.add_mockup_builtin(mock_program_id, process_instruction); + bank.add_mockup_builtin(mock_program_id, MockBuiltin::vm); assert_eq!(bank.last_blockhash(), genesis_config.hash()); @@ -4684,7 +4684,7 @@ fn test_add_builtin() { fn mock_vote_program_id() -> Pubkey { Pubkey::from([42u8; 32]) } - declare_process_instruction!(process_instruction, 1, |invoke_context| { + declare_process_instruction!(MockBuiltin, 1, |invoke_context| { let transaction_context = &invoke_context.transaction_context; let instruction_context = transaction_context.get_current_instruction_context()?; let program_id = instruction_context.get_last_program_key(transaction_context)?; @@ -4695,7 +4695,7 @@ fn test_add_builtin() { }); assert!(bank.get_account(&mock_vote_program_id()).is_none()); - bank.add_mockup_builtin(mock_vote_program_id(), process_instruction); + bank.add_mockup_builtin(mock_vote_program_id(), MockBuiltin::vm); assert!(bank.get_account(&mock_vote_program_id()).is_some()); let mock_account = Keypair::new(); @@ -4740,7 +4740,7 @@ fn test_add_duplicate_static_program() { } = create_genesis_config_with_leader(500, &solana_sdk::pubkey::new_rand(), 0); let bank = Bank::new_for_tests(&genesis_config); - declare_process_instruction!(process_instruction, 1, |_invoke_context| { + declare_process_instruction!(MockBuiltin, 1, |_invoke_context| { Err(InstructionError::Custom(42)) }); @@ -4771,7 +4771,7 @@ fn test_add_duplicate_static_program() { let mut bank = Bank::new_from_parent(Arc::new(bank), &Pubkey::default(), slot); let vote_loader_account = bank.get_account(&solana_vote_program::id()).unwrap(); - bank.add_mockup_builtin(solana_vote_program::id(), process_instruction); + bank.add_mockup_builtin(solana_vote_program::id(), MockBuiltin::vm); let new_vote_loader_account = bank.get_account(&solana_vote_program::id()).unwrap(); // Vote loader account should not be updated since it was included in the genesis config. assert_eq!(vote_loader_account.data(), new_vote_loader_account.data()); @@ -4789,7 +4789,7 @@ fn test_add_instruction_processor_for_existing_unrelated_accounts() { for pass in 0..5 { let mut bank = create_simple_test_bank(500); - declare_process_instruction!(process_instruction, 1, |_invoke_context| { + declare_process_instruction!(MockBuiltin, 1, |_invoke_context| { Err(InstructionError::Custom(42)) }); @@ -4825,12 +4825,12 @@ fn test_add_instruction_processor_for_existing_unrelated_accounts() { bank.add_builtin( vote_id, "mock_program1".to_string(), - LoadedProgram::new_builtin(0, 0, process_instruction), + LoadedProgram::new_builtin(0, 0, MockBuiltin::vm), ); bank.add_builtin( stake_id, "mock_program2".to_string(), - LoadedProgram::new_builtin(0, 0, process_instruction), + LoadedProgram::new_builtin(0, 0, MockBuiltin::vm), ); { let stakes = bank.stakes_cache.stakes(); @@ -4854,8 +4854,8 @@ fn test_add_instruction_processor_for_existing_unrelated_accounts() { // Re-adding builtin programs should be no-op bank.update_accounts_hash_for_tests(); let old_hash = bank.get_accounts_hash().unwrap(); - bank.add_mockup_builtin(vote_id, process_instruction); - bank.add_mockup_builtin(stake_id, process_instruction); + bank.add_mockup_builtin(vote_id, MockBuiltin::vm); + bank.add_mockup_builtin(stake_id, MockBuiltin::vm); add_root_and_flush_write_cache(&bank); bank.update_accounts_hash_for_tests(); let new_hash = bank.get_accounts_hash().unwrap(); @@ -6086,7 +6086,7 @@ fn test_transaction_with_duplicate_accounts_in_instruction() { let (genesis_config, mint_keypair) = create_genesis_config(500); let mut bank = Bank::new_for_tests(&genesis_config); - declare_process_instruction!(process_instruction, 1, |invoke_context| { + declare_process_instruction!(MockBuiltin, 1, |invoke_context| { let transaction_context = &invoke_context.transaction_context; let instruction_context = transaction_context.get_current_instruction_context()?; let instruction_data = instruction_context.get_instruction_data(); @@ -6107,7 +6107,7 @@ fn test_transaction_with_duplicate_accounts_in_instruction() { }); let mock_program_id = Pubkey::from([2u8; 32]); - bank.add_mockup_builtin(mock_program_id, process_instruction); + bank.add_mockup_builtin(mock_program_id, MockBuiltin::vm); let from_pubkey = solana_sdk::pubkey::new_rand(); let to_pubkey = solana_sdk::pubkey::new_rand(); @@ -6143,7 +6143,7 @@ fn test_transaction_with_program_ids_passed_to_programs() { let mut bank = Bank::new_for_tests(&genesis_config); let mock_program_id = Pubkey::from([2u8; 32]); - bank.add_mockup_builtin(mock_program_id, process_instruction); + bank.add_mockup_builtin(mock_program_id, MockBuiltin::vm); let from_pubkey = solana_sdk::pubkey::new_rand(); let to_pubkey = solana_sdk::pubkey::new_rand(); @@ -6198,7 +6198,7 @@ fn test_account_ids_after_program_ids() { let slot = bank.slot().saturating_add(1); let mut bank = Bank::new_from_parent(Arc::new(bank), &Pubkey::default(), slot); - bank.add_mockup_builtin(solana_vote_program::id(), process_instruction); + bank.add_mockup_builtin(solana_vote_program::id(), MockBuiltin::vm); let result = bank.process_transaction(&tx); assert_eq!(result, Ok(())); let account = bank.get_account(&solana_vote_program::id()).unwrap(); @@ -6248,7 +6248,7 @@ fn test_duplicate_account_key() { AccountMeta::new(to_pubkey, false), ]; - bank.add_mockup_builtin(solana_vote_program::id(), process_instruction); + bank.add_mockup_builtin(solana_vote_program::id(), MockBuiltin::vm); let instruction = Instruction::new_with_bincode(solana_vote_program::id(), &10, account_metas); let mut tx = Transaction::new_signed_with_payer( @@ -6277,7 +6277,7 @@ fn test_process_transaction_with_too_many_account_locks() { AccountMeta::new(to_pubkey, false), ]; - bank.add_mockup_builtin(solana_vote_program::id(), process_instruction); + bank.add_mockup_builtin(solana_vote_program::id(), MockBuiltin::vm); let instruction = Instruction::new_with_bincode(solana_vote_program::id(), &10, account_metas); let mut tx = Transaction::new_signed_with_payer( @@ -6310,7 +6310,7 @@ fn test_program_id_as_payer() { AccountMeta::new(to_pubkey, false), ]; - bank.add_mockup_builtin(solana_vote_program::id(), process_instruction); + bank.add_mockup_builtin(solana_vote_program::id(), MockBuiltin::vm); let instruction = Instruction::new_with_bincode(solana_vote_program::id(), &10, account_metas); let mut tx = Transaction::new_signed_with_payer( @@ -6356,7 +6356,7 @@ fn test_ref_account_key_after_program_id() { let slot = bank.slot().saturating_add(1); let mut bank = Bank::new_from_parent(Arc::new(bank), &Pubkey::default(), slot); - bank.add_mockup_builtin(solana_vote_program::id(), process_instruction); + bank.add_mockup_builtin(solana_vote_program::id(), MockBuiltin::vm); let instruction = Instruction::new_with_bincode(solana_vote_program::id(), &10, account_metas); let mut tx = Transaction::new_signed_with_payer( @@ -6390,7 +6390,7 @@ fn test_fuzz_instructions() { bank.add_builtin( key, name.clone(), - LoadedProgram::new_builtin(0, 0, process_instruction), + LoadedProgram::new_builtin(0, 0, MockBuiltin::vm), ); (key, name.as_bytes().to_vec()) }) @@ -6584,7 +6584,7 @@ fn test_bank_hash_consistency() { #[ignore] #[test] fn test_same_program_id_uses_unique_executable_accounts() { - declare_process_instruction!(process_instruction, 1, |invoke_context| { + declare_process_instruction!(MockBuiltin, 1, |invoke_context| { let transaction_context = &invoke_context.transaction_context; let instruction_context = transaction_context.get_current_instruction_context()?; instruction_context @@ -6597,7 +6597,7 @@ fn test_same_program_id_uses_unique_executable_accounts() { // Add a new program let program1_pubkey = solana_sdk::pubkey::new_rand(); - bank.add_mockup_builtin(program1_pubkey, process_instruction); + bank.add_mockup_builtin(program1_pubkey, MockBuiltin::vm); // Add a new program owned by the first let program2_pubkey = solana_sdk::pubkey::new_rand(); @@ -6814,13 +6814,13 @@ fn test_add_builtin_no_overwrite() { Arc::get_mut(&mut bank) .unwrap() - .add_mockup_builtin(program_id, process_instruction); + .add_mockup_builtin(program_id, MockBuiltin::vm); assert_eq!(bank.get_account_modified_slot(&program_id).unwrap().1, slot); let mut bank = Arc::new(new_from_parent(bank)); Arc::get_mut(&mut bank) .unwrap() - .add_mockup_builtin(program_id, process_instruction); + .add_mockup_builtin(program_id, MockBuiltin::vm); assert_eq!(bank.get_account_modified_slot(&program_id).unwrap().1, slot); } @@ -6838,13 +6838,13 @@ fn test_add_builtin_loader_no_overwrite() { Arc::get_mut(&mut bank) .unwrap() - .add_mockup_builtin(loader_id, process_instruction); + .add_mockup_builtin(loader_id, MockBuiltin::vm); assert_eq!(bank.get_account_modified_slot(&loader_id).unwrap().1, slot); let mut bank = Arc::new(new_from_parent(bank)); Arc::get_mut(&mut bank) .unwrap() - .add_mockup_builtin(loader_id, process_instruction); + .add_mockup_builtin(loader_id, MockBuiltin::vm); assert_eq!(bank.get_account_modified_slot(&loader_id).unwrap().1, slot); } @@ -7403,7 +7403,7 @@ fn test_bpf_loader_upgradeable_deploy_with_max_len() { ], Vec::new(), Ok(()), - solana_bpf_loader_program::process_instruction, + solana_bpf_loader_program::Entrypoint::vm, |invoke_context| { invoke_context .programs_modified_by_tx @@ -9708,7 +9708,7 @@ fn test_tx_return_data() { ); let mut bank = Bank::new_for_tests(&genesis_config); - declare_process_instruction!(process_instruction, 1, |invoke_context| { + declare_process_instruction!(MockBuiltin, 1, |invoke_context| { let mock_program_id = Pubkey::from([2u8; 32]); let transaction_context = &mut invoke_context.transaction_context; let instruction_context = transaction_context.get_current_instruction_context()?; @@ -9726,7 +9726,7 @@ fn test_tx_return_data() { let mock_program_id = Pubkey::from([2u8; 32]); let blockhash = bank.last_blockhash(); - bank.add_mockup_builtin(mock_program_id, process_instruction); + bank.add_mockup_builtin(mock_program_id, MockBuiltin::vm); for index in [ None, @@ -9906,7 +9906,7 @@ fn test_transfer_sysvar() { ); let mut bank = Bank::new_for_tests(&genesis_config); - declare_process_instruction!(process_instruction, 1, |invoke_context| { + declare_process_instruction!(MockBuiltin, 1, |invoke_context| { let transaction_context = &invoke_context.transaction_context; let instruction_context = transaction_context.get_current_instruction_context()?; instruction_context @@ -9916,7 +9916,7 @@ fn test_transfer_sysvar() { }); let program_id = solana_sdk::pubkey::new_rand(); - bank.add_mockup_builtin(program_id, process_instruction); + bank.add_mockup_builtin(program_id, MockBuiltin::vm); let blockhash = bank.last_blockhash(); #[allow(deprecated)] @@ -10115,7 +10115,7 @@ fn test_compute_budget_program_noop() { ); let mut bank = Bank::new_for_tests(&genesis_config); - declare_process_instruction!(process_instruction, 1, |invoke_context| { + declare_process_instruction!(MockBuiltin, 1, |invoke_context| { let compute_budget = invoke_context.get_compute_budget(); assert_eq!( *compute_budget, @@ -10128,7 +10128,7 @@ fn test_compute_budget_program_noop() { Ok(()) }); let program_id = solana_sdk::pubkey::new_rand(); - bank.add_mockup_builtin(program_id, process_instruction); + bank.add_mockup_builtin(program_id, MockBuiltin::vm); let message = Message::new( &[ @@ -10158,7 +10158,7 @@ fn test_compute_request_instruction() { ); let mut bank = Bank::new_for_tests(&genesis_config); - declare_process_instruction!(process_instruction, 1, |invoke_context| { + declare_process_instruction!(MockBuiltin, 1, |invoke_context| { let compute_budget = invoke_context.get_compute_budget(); assert_eq!( *compute_budget, @@ -10171,7 +10171,7 @@ fn test_compute_request_instruction() { Ok(()) }); let program_id = solana_sdk::pubkey::new_rand(); - bank.add_mockup_builtin(program_id, process_instruction); + bank.add_mockup_builtin(program_id, MockBuiltin::vm); let message = Message::new( &[ @@ -10208,7 +10208,7 @@ fn test_failed_compute_request_instruction() { bank.transfer(10, &mint_keypair, &payer1_keypair.pubkey()) .unwrap(); - declare_process_instruction!(process_instruction, 1, |invoke_context| { + declare_process_instruction!(MockBuiltin, 1, |invoke_context| { let compute_budget = invoke_context.get_compute_budget(); assert_eq!( *compute_budget, @@ -10221,7 +10221,7 @@ fn test_failed_compute_request_instruction() { Ok(()) }); let program_id = solana_sdk::pubkey::new_rand(); - bank.add_mockup_builtin(program_id, process_instruction); + bank.add_mockup_builtin(program_id, MockBuiltin::vm); // This message will not be executed because the compute budget request is invalid let message0 = Message::new( @@ -10825,7 +10825,7 @@ enum MockTransferInstruction { Transfer(u64), } -declare_process_instruction!(mock_transfer_process_instruction, 1, |invoke_context| { +declare_process_instruction!(MockTransferBuiltin, 1, |invoke_context| { let transaction_context = &invoke_context.transaction_context; let instruction_context = transaction_context.get_current_instruction_context()?; let instruction_data = instruction_context.get_instruction_data(); @@ -10908,7 +10908,7 @@ fn test_invalid_rent_state_changes_existing_accounts() { ); let mut bank = Bank::new_for_tests(&genesis_config); - bank.add_mockup_builtin(mock_program_id, mock_transfer_process_instruction); + bank.add_mockup_builtin(mock_program_id, MockTransferBuiltin::vm); let recent_blockhash = bank.last_blockhash(); let check_account_is_rent_exempt = |pubkey: &Pubkey| -> bool { @@ -10991,7 +10991,7 @@ fn test_invalid_rent_state_changes_new_accounts() { let rent_exempt_minimum = genesis_config.rent.minimum_balance(account_data_size); let mut bank = Bank::new_for_tests(&genesis_config); - bank.add_mockup_builtin(mock_program_id, mock_transfer_process_instruction); + bank.add_mockup_builtin(mock_program_id, MockTransferBuiltin::vm); let recent_blockhash = bank.last_blockhash(); let check_account_is_rent_exempt = |pubkey: &Pubkey| -> bool { @@ -11050,7 +11050,7 @@ fn test_drained_created_account() { let created_keypair = Keypair::new(); let mut bank = Bank::new_for_tests(&genesis_config); - bank.add_mockup_builtin(mock_program_id, mock_transfer_process_instruction); + bank.add_mockup_builtin(mock_program_id, MockTransferBuiltin::vm); let recent_blockhash = bank.last_blockhash(); // Create and drain a small data size account @@ -11578,7 +11578,7 @@ enum MockReallocInstruction { Realloc(usize, u64, Pubkey), } -declare_process_instruction!(mock_realloc_process_instruction, 1, |invoke_context| { +declare_process_instruction!(MockReallocBuiltin, 1, |invoke_context| { let transaction_context = &invoke_context.transaction_context; let instruction_context = transaction_context.get_current_instruction_context()?; let instruction_data = instruction_context.get_instruction_data(); @@ -11658,7 +11658,7 @@ fn test_resize_and_rent() { let mut bank = Bank::new_for_tests(&genesis_config); let mock_program_id = Pubkey::new_unique(); - bank.add_mockup_builtin(mock_program_id, mock_realloc_process_instruction); + bank.add_mockup_builtin(mock_program_id, MockReallocBuiltin::vm); let recent_blockhash = bank.last_blockhash(); let account_data_size_small = 1024; @@ -11929,7 +11929,7 @@ fn test_accounts_data_size_and_resize_transactions() { } = genesis_utils::create_genesis_config(100 * LAMPORTS_PER_SOL); let mut bank = Bank::new_for_tests(&genesis_config); let mock_program_id = Pubkey::new_unique(); - bank.add_mockup_builtin(mock_program_id, mock_realloc_process_instruction); + bank.add_mockup_builtin(mock_program_id, MockReallocBuiltin::vm); let recent_blockhash = bank.last_blockhash(); diff --git a/runtime/src/builtins.rs b/runtime/src/builtins.rs index 06a1709335..2c7c36fa0e 100644 --- a/runtime/src/builtins.rs +++ b/runtime/src/builtins.rs @@ -1,5 +1,5 @@ use { - solana_program_runtime::invoke_context::ProcessInstructionWithContext, + solana_program_runtime::invoke_context::BuiltinFunctionWithContext, solana_sdk::{ bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, feature_set, pubkey::Pubkey, }, @@ -10,7 +10,7 @@ pub struct BuiltinPrototype { pub feature_id: Option, pub program_id: Pubkey, pub name: &'static str, - pub entrypoint: ProcessInstructionWithContext, + pub entrypoint: BuiltinFunctionWithContext, } impl std::fmt::Debug for BuiltinPrototype { @@ -27,7 +27,7 @@ impl std::fmt::Debug for BuiltinPrototype { impl solana_frozen_abi::abi_example::AbiExample for BuiltinPrototype { fn example() -> Self { // BuiltinPrototype isn't serializable by definition. - solana_program_runtime::declare_process_instruction!(entrypoint, 0, |_invoke_context| { + solana_program_runtime::declare_process_instruction!(MockBuiltin, 0, |_invoke_context| { // Do nothing Ok(()) }); @@ -35,7 +35,7 @@ impl solana_frozen_abi::abi_example::AbiExample for BuiltinPrototype { feature_id: None, program_id: Pubkey::default(), name: "", - entrypoint, + entrypoint: MockBuiltin::vm, } } } @@ -45,66 +45,66 @@ pub static BUILTINS: &[BuiltinPrototype] = &[ feature_id: None, program_id: solana_system_program::id(), name: "system_program", - entrypoint: solana_system_program::system_processor::process_instruction, + entrypoint: solana_system_program::system_processor::Entrypoint::vm, }, BuiltinPrototype { feature_id: None, program_id: solana_vote_program::id(), name: "vote_program", - entrypoint: solana_vote_program::vote_processor::process_instruction, + entrypoint: solana_vote_program::vote_processor::Entrypoint::vm, }, BuiltinPrototype { feature_id: None, program_id: solana_stake_program::id(), name: "stake_program", - entrypoint: solana_stake_program::stake_instruction::process_instruction, + entrypoint: solana_stake_program::stake_instruction::Entrypoint::vm, }, BuiltinPrototype { feature_id: None, program_id: solana_config_program::id(), name: "config_program", - entrypoint: solana_config_program::config_processor::process_instruction, + entrypoint: solana_config_program::config_processor::Entrypoint::vm, }, BuiltinPrototype { feature_id: None, program_id: bpf_loader_deprecated::id(), name: "solana_bpf_loader_deprecated_program", - entrypoint: solana_bpf_loader_program::process_instruction, + entrypoint: solana_bpf_loader_program::Entrypoint::vm, }, BuiltinPrototype { feature_id: None, program_id: bpf_loader::id(), name: "solana_bpf_loader_program", - entrypoint: solana_bpf_loader_program::process_instruction, + entrypoint: solana_bpf_loader_program::Entrypoint::vm, }, BuiltinPrototype { feature_id: None, program_id: bpf_loader_upgradeable::id(), name: "solana_bpf_loader_upgradeable_program", - entrypoint: solana_bpf_loader_program::process_instruction, + entrypoint: solana_bpf_loader_program::Entrypoint::vm, }, BuiltinPrototype { feature_id: None, program_id: solana_sdk::compute_budget::id(), name: "compute_budget_program", - entrypoint: solana_compute_budget_program::process_instruction, + entrypoint: solana_compute_budget_program::Entrypoint::vm, }, BuiltinPrototype { feature_id: None, program_id: solana_sdk::address_lookup_table::program::id(), name: "address_lookup_table_program", - entrypoint: solana_address_lookup_table_program::processor::process_instruction, + entrypoint: solana_address_lookup_table_program::processor::Entrypoint::vm, }, BuiltinPrototype { feature_id: Some(feature_set::zk_token_sdk_enabled::id()), program_id: solana_zk_token_sdk::zk_token_proof_program::id(), name: "zk_token_proof_program", - entrypoint: solana_zk_token_proof_program::process_instruction, + entrypoint: solana_zk_token_proof_program::Entrypoint::vm, }, BuiltinPrototype { feature_id: Some(feature_set::enable_program_runtime_v2_and_loader_v4::id()), program_id: solana_sdk::loader_v4::id(), name: "loader_v4", - entrypoint: solana_loader_v4_program::process_instruction, + entrypoint: solana_loader_v4_program::Entrypoint::vm, }, ];