From b8ca1bcb6871f8f5fa128b8738380a93dfb52c2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Wed, 13 Apr 2022 12:15:28 +0200 Subject: [PATCH] Remove `NativeLoader` from program runtime (#24296) * Deletes native_loader.rs * Deletes the feature: remove_native_loader --- program-runtime/src/invoke_context.rs | 28 +--- program-runtime/src/lib.rs | 1 - program-runtime/src/native_loader.rs | 226 -------------------------- sdk/src/feature_set.rs | 5 - 4 files changed, 2 insertions(+), 258 deletions(-) delete mode 100644 program-runtime/src/native_loader.rs diff --git a/program-runtime/src/invoke_context.rs b/program-runtime/src/invoke_context.rs index b11c46996..326cce9be 100644 --- a/program-runtime/src/invoke_context.rs +++ b/program-runtime/src/invoke_context.rs @@ -4,7 +4,6 @@ use { compute_budget::ComputeBudget, ic_logger_msg, ic_msg, log_collector::LogCollector, - native_loader::NativeLoader, pre_account::PreAccount, sysvar_cache::SysvarCache, timings::{ExecuteDetailsTimings, ExecuteTimings}, @@ -16,8 +15,8 @@ use { feature_set::{ cap_accounts_data_len, do_support_realloc, neon_evm_compute_budget, record_instruction_in_transaction_context_push, - reject_empty_instruction_without_program, remove_native_loader, requestable_heap_size, - tx_wide_compute_cap, FeatureSet, + reject_empty_instruction_without_program, requestable_heap_size, tx_wide_compute_cap, + FeatureSet, }, hash::Hash, instruction::{AccountMeta, Instruction, InstructionError}, @@ -982,12 +981,6 @@ impl<'a> InvokeContext<'a> { ); } } - if !self.feature_set.is_active(&remove_native_loader::id()) { - drop(borrowed_root_account); - let native_loader = NativeLoader::default(); - // Call the program via the native loader - return native_loader.process_instruction(0, self); - } } else { for entry in self.builtin_programs { if entry.program_id == *owner_id { @@ -1003,23 +996,6 @@ impl<'a> InvokeContext<'a> { Err(InstructionError::UnsupportedProgramId) } - /// Removes the first keyed account - #[deprecated( - since = "1.9.0", - note = "To be removed together with remove_native_loader" - )] - pub fn remove_first_keyed_account(&mut self) -> Result<(), InstructionError> { - if !self.feature_set.is_active(&remove_native_loader::id()) { - let stack_frame = &mut self - .invoke_stack - .last_mut() - .ok_or(InstructionError::CallDepth)?; - stack_frame.keyed_accounts_range.start = - stack_frame.keyed_accounts_range.start.saturating_add(1); - } - Ok(()) - } - /// Get the list of keyed accounts including the chain of program accounts pub fn get_keyed_accounts(&self) -> Result<&[KeyedAccount], InstructionError> { self.invoke_stack diff --git a/program-runtime/src/lib.rs b/program-runtime/src/lib.rs index 56eaf0da0..421fca20a 100644 --- a/program-runtime/src/lib.rs +++ b/program-runtime/src/lib.rs @@ -6,7 +6,6 @@ pub mod accounts_data_meter; pub mod compute_budget; pub mod invoke_context; pub mod log_collector; -pub mod native_loader; pub mod neon_evm_program; pub mod pre_account; pub mod stable_log; diff --git a/program-runtime/src/native_loader.rs b/program-runtime/src/native_loader.rs deleted file mode 100644 index 789d96b5f..000000000 --- a/program-runtime/src/native_loader.rs +++ /dev/null @@ -1,226 +0,0 @@ -//! Native loader -#[cfg(unix)] -use libloading::os::unix::*; -#[cfg(windows)] -use libloading::os::windows::*; -use { - crate::invoke_context::InvokeContext, - log::*, - num_derive::{FromPrimitive, ToPrimitive}, - serde::Serialize, - solana_sdk::{ - account::ReadableAccount, - decode_error::DecodeError, - instruction::InstructionError, - keyed_account::{keyed_account_at_index, KeyedAccount}, - native_loader, - pubkey::Pubkey, - }, - std::{ - collections::HashMap, - env, - path::{Path, PathBuf}, - str, - sync::RwLock, - }, - thiserror::Error, -}; - -/// Prototype of a native loader entry point -/// -/// program_id: Program ID of the currently executing program -/// keyed_accounts: Accounts passed as part of the instruction -/// instruction_data: Instruction data -/// invoke_context: Invocation context -pub type LoaderEntrypoint = unsafe extern "C" fn( - program_id: &Pubkey, - invoke_context: &InvokeContext, -) -> Result<(), InstructionError>; - -// Prototype of a native program entry point -/// -/// program_id: Program ID of the currently executing program -/// keyed_accounts: Accounts passed as part of the instruction -/// instruction_data: Instruction data -pub type ProgramEntrypoint = unsafe extern "C" fn( - program_id: &Pubkey, - keyed_accounts: &[KeyedAccount], - instruction_data: &[u8], -) -> Result<(), InstructionError>; - -#[derive(Error, Debug, Serialize, Clone, PartialEq, FromPrimitive, ToPrimitive)] -pub enum NativeLoaderError { - #[error("Entrypoint name in the account data is not a valid UTF-8 string")] - InvalidAccountData = 0x0aaa_0001, - #[error("Entrypoint was not found in the module")] - EntrypointNotFound = 0x0aaa_0002, - #[error("Failed to load the module")] - FailedToLoad = 0x0aaa_0003, -} -impl DecodeError for NativeLoaderError { - fn type_of() -> &'static str { - "NativeLoaderError" - } -} - -/// Dynamic link library prefixes -#[cfg(unix)] -const PLATFORM_FILE_PREFIX: &str = "lib"; -#[cfg(windows)] -const PLATFORM_FILE_PREFIX: &str = ""; - -/// Dynamic link library file extension specific to the platform -#[cfg(any(target_os = "macos", target_os = "ios"))] -const PLATFORM_FILE_EXTENSION: &str = "dylib"; -/// Dynamic link library file extension specific to the platform -#[cfg(all(unix, not(any(target_os = "macos", target_os = "ios"))))] -const PLATFORM_FILE_EXTENSION: &str = "so"; -/// Dynamic link library file extension specific to the platform -#[cfg(windows)] -const PLATFORM_FILE_EXTENSION: &str = "dll"; - -pub type ProgramSymbolCache = RwLock>>; -pub type LoaderSymbolCache = RwLock>>; - -#[derive(Debug, Default)] -pub struct NativeLoader { - program_symbol_cache: ProgramSymbolCache, - loader_symbol_cache: LoaderSymbolCache, -} -impl NativeLoader { - fn create_path(name: &str) -> Result { - let current_exe = env::current_exe().map_err(|e| { - error!("create_path(\"{}\"): current exe not found: {:?}", name, e); - InstructionError::from(NativeLoaderError::EntrypointNotFound) - })?; - let current_exe_directory = PathBuf::from(current_exe.parent().ok_or_else(|| { - error!( - "create_path(\"{}\"): no parent directory of {:?}", - name, current_exe - ); - InstructionError::from(NativeLoaderError::FailedToLoad) - })?); - - let library_file_name = PathBuf::from(PLATFORM_FILE_PREFIX.to_string() + name) - .with_extension(PLATFORM_FILE_EXTENSION); - - // Check the current_exe directory for the library as `cargo tests` are run - // from the deps/ subdirectory - let file_path = current_exe_directory.join(&library_file_name); - if file_path.exists() { - Ok(file_path) - } else { - // `cargo build` places dependent libraries in the deps/ subdirectory - Ok(current_exe_directory.join("deps").join(library_file_name)) - } - } - - #[cfg(windows)] - fn library_open(path: &Path) -> Result { - unsafe { Library::new(path) } - } - - #[cfg(not(windows))] - fn library_open(path: &Path) -> Result { - unsafe { - // Linux tls bug can cause crash on dlclose(), workaround by never unloading - #[cfg(target_os = "android")] - let flags = libc::RTLD_NOW; - #[cfg(not(target_os = "android"))] - let flags = libc::RTLD_NODELETE | libc::RTLD_NOW; - Library::open(Some(path), flags) - } - } - - fn get_entrypoint( - name: &str, - cache: &RwLock>>, - ) -> Result, InstructionError> { - let mut cache = cache.write().unwrap(); - if let Some(entrypoint) = cache.get(name) { - Ok(entrypoint.clone()) - } else { - match Self::library_open(&Self::create_path(name)?) { - Ok(library) => { - let result = unsafe { library.get::(name.as_bytes()) }; - match result { - Ok(entrypoint) => { - cache.insert(name.to_string(), entrypoint.clone()); - Ok(entrypoint) - } - Err(e) => { - error!("Unable to find program entrypoint in {:?}: {:?})", name, e); - Err(NativeLoaderError::EntrypointNotFound.into()) - } - } - } - Err(e) => { - error!("Failed to load: {:?}", e); - Err(NativeLoaderError::FailedToLoad.into()) - } - } - } - } - - pub fn process_instruction( - &self, - first_instruction_account: usize, - invoke_context: &mut InvokeContext, - ) -> Result<(), InstructionError> { - let (program_id, name_vec) = { - let transaction_context = &invoke_context.transaction_context; - let instruction_context = transaction_context.get_current_instruction_context()?; - let program_id = instruction_context.get_program_key(transaction_context)?; - let keyed_accounts = invoke_context.get_keyed_accounts()?; - let program = keyed_account_at_index(keyed_accounts, first_instruction_account)?; - if native_loader::id() != *program_id { - error!("Program id mismatch"); - return Err(InstructionError::IncorrectProgramId); - } - if program.owner()? != *program_id { - error!("Executable account now owned by loader"); - return Err(InstructionError::IncorrectProgramId); - } - // TODO: Remove these two copies (* deref is also a copy) - // Both could be avoided as we know that the first KeyedAccount - // still exists even after invoke_context.remove_first_keyed_account() is called - ( - *program.unsigned_key(), - &program.try_account_ref()?.data().to_vec(), - ) - }; - - let name = match str::from_utf8(name_vec) { - Ok(v) => v, - Err(e) => { - error!("Invalid UTF-8 sequence: {}", e); - return Err(NativeLoaderError::InvalidAccountData.into()); - } - }; - if name.is_empty() || name.starts_with('\0') { - error!("Empty name string"); - return Err(NativeLoaderError::InvalidAccountData.into()); - } - trace!("Call native {:?}", name); - #[allow(deprecated)] - invoke_context.remove_first_keyed_account()?; - let transaction_context = &invoke_context.transaction_context; - let instruction_context = transaction_context.get_current_instruction_context()?; - let instruction_data = instruction_context.get_instruction_data(); - if name.ends_with("loader_program") { - let entrypoint = - Self::get_entrypoint::(name, &self.loader_symbol_cache)?; - unsafe { entrypoint(&program_id, invoke_context) } - } else { - let entrypoint = - Self::get_entrypoint::(name, &self.program_symbol_cache)?; - unsafe { - entrypoint( - &program_id, - invoke_context.get_keyed_accounts()?, - instruction_data, - ) - } - } - } -} diff --git a/sdk/src/feature_set.rs b/sdk/src/feature_set.rs index 1aacc7972..c51a1d282 100644 --- a/sdk/src/feature_set.rs +++ b/sdk/src/feature_set.rs @@ -203,10 +203,6 @@ pub mod optimize_epoch_boundary_updates { solana_sdk::declare_id!("265hPS8k8xJ37ot82KEgjRunsUp5w4n4Q4VwwiN9i9ps"); } -pub mod remove_native_loader { - solana_sdk::declare_id!("HTTgmruMYRZEntyL3EdCDdnS6e4D5wRq1FA7kQsb66qq"); -} - pub mod send_to_tpu_vote_port { solana_sdk::declare_id!("C5fh68nJ7uyKAuYZg2x9sEQ5YrVf3dkW6oojNBSc3Jvo"); } @@ -384,7 +380,6 @@ lazy_static! { (do_support_realloc::id(), "support account data reallocation"), (prevent_calling_precompiles_as_programs::id(), "prevent calling precompiles as programs"), (optimize_epoch_boundary_updates::id(), "optimize epoch boundary updates"), - (remove_native_loader::id(), "remove support for the native loader"), (send_to_tpu_vote_port::id(), "send votes to the tpu vote port"), (requestable_heap_size::id(), "Requestable heap frame size"), (disable_fee_calculator::id(), "deprecate fee calculator"),