diff --git a/Cargo.lock b/Cargo.lock index 1c82e102e9..3b3474f630 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3943,7 +3943,6 @@ dependencies = [ "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", "serial_test 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "serial_test_derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "solana-bpf-loader-program 1.2.0", "solana-budget-program 1.2.0", "solana-chacha-cuda 1.2.0", "solana-clap-utils 1.2.0", @@ -4494,8 +4493,9 @@ dependencies = [ "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-bpf-loader-program 1.2.0", "solana-logger 1.2.0", "solana-measure 1.2.0", "solana-metrics 1.2.0", diff --git a/core/Cargo.toml b/core/Cargo.toml index cc1c19a662..5354ef7d77 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -40,8 +40,7 @@ rayon = "1.3.0" regex = "1.3.6" serde = "1.0.106" serde_derive = "1.0.103" -serde_json = "1.0.51" -solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.2.0" } +serde_json = "1.0.49" solana-budget-program = { path = "../programs/budget", version = "1.2.0" } solana-clap-utils = { path = "../clap-utils", version = "1.2.0" } solana-client = { path = "../client", version = "1.2.0" } diff --git a/core/src/lib.rs b/core/src/lib.rs index a0b7a6c6d3..52c5f9af54 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -58,9 +58,6 @@ pub mod verified_vote_packets; pub mod weighted_shuffle; pub mod window_service; -#[macro_use] -extern crate solana_bpf_loader_program; - #[macro_use] extern crate solana_budget_program; diff --git a/core/src/validator.rs b/core/src/validator.rs index 48503aac8b..c12de5fc34 100644 --- a/core/src/validator.rs +++ b/core/src/validator.rs @@ -717,9 +717,6 @@ impl TestValidator { genesis_config .native_instruction_processors .push(solana_budget_program!()); - genesis_config - .native_instruction_processors - .push(solana_bpf_loader_program!()); genesis_config.rent.lamports_per_byte_year = 1; genesis_config.rent.exemption_threshold = 1.0; diff --git a/genesis-programs/src/lib.rs b/genesis-programs/src/lib.rs index 24654ec9a8..543e870bd7 100644 --- a/genesis-programs/src/lib.rs +++ b/genesis-programs/src/lib.rs @@ -1,7 +1,6 @@ use solana_sdk::{ clock::Epoch, genesis_config::OperatingMode, inflation::Inflation, - move_loader::solana_move_loader_program, native_loader, pubkey::Pubkey, - system_program::solana_system_program, + move_loader::solana_move_loader_program, pubkey::Pubkey, system_program::solana_system_program, }; #[macro_use] @@ -50,10 +49,7 @@ pub fn get_inflation(operating_mode: OperatingMode, epoch: Epoch) -> Option Option> { +pub fn get_programs(operating_mode: OperatingMode, epoch: Epoch) -> Option> { match operating_mode { OperatingMode::Development => { if epoch == 0 { @@ -126,9 +122,9 @@ pub fn get_entered_epoch_callback(operating_mode: OperatingMode) -> EnteredEpoch bank.set_inflation(inflation); } if let Some(new_programs) = get_programs(operating_mode, bank.epoch()) { - for (info, program_id) in new_programs.iter() { - info!("Registering {:?} at {}", info, program_id); - bank.register_native_instruction_processor(info, program_id); + for (name, program_id) in new_programs.iter() { + info!("Registering {} at {}", name, program_id); + bank.register_native_instruction_processor(name, program_id); } } }) diff --git a/local-cluster/src/local_cluster.rs b/local-cluster/src/local_cluster.rs index 7f8f3c8dcb..5935142495 100644 --- a/local-cluster/src/local_cluster.rs +++ b/local-cluster/src/local_cluster.rs @@ -20,7 +20,6 @@ use solana_sdk::{ epoch_schedule::EpochSchedule, genesis_config::{GenesisConfig, OperatingMode}, message::Message, - native_loader, poh_config::PohConfig, pubkey::Pubkey, signature::{Keypair, Signer}, @@ -82,7 +81,7 @@ pub struct ClusterConfig { pub slots_per_epoch: u64, pub slots_per_segment: u64, pub stakers_slot_offset: u64, - pub native_instruction_processors: Vec<(native_loader::Info, Pubkey)>, + pub native_instruction_processors: Vec<(String, Pubkey)>, pub operating_mode: OperatingMode, pub poh_config: PohConfig, } @@ -180,13 +179,14 @@ impl LocalCluster { .push(solana_storage_program!()); } } - genesis_config - .native_instruction_processors - .extend_from_slice(&config.native_instruction_processors); genesis_config.inflation = solana_genesis_programs::get_inflation(genesis_config.operating_mode, 0).unwrap(); + genesis_config + .native_instruction_processors + .extend_from_slice(&config.native_instruction_processors); + let storage_keypair = Keypair::new(); genesis_config.add_account( storage_keypair.pubkey(), diff --git a/programs/bpf/Cargo.lock b/programs/bpf/Cargo.lock index ec230846c9..fda5c0faf5 100644 --- a/programs/bpf/Cargo.lock +++ b/programs/bpf/Cargo.lock @@ -1980,6 +1980,7 @@ dependencies = [ "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-bpf-loader-program 1.2.0", "solana-logger 1.2.0", "solana-measure 1.2.0", "solana-metrics 1.2.0", diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 6216e2bbb2..3be6f7976a 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -18,7 +18,6 @@ mod bpf { sysvar::{clock, fees, rent, rewards, slot_hashes, stake_history}, transaction::TransactionError, }; - use solana_bpf_loader_program::solana_bpf_loader_program; use std::{env, fs::File, io::Read, path::PathBuf, sync::Arc}; /// BPF program file extension @@ -84,11 +83,10 @@ mod bpf { println!("Test program: {:?}", program.0); let GenesisConfigInfo { - mut genesis_config, + genesis_config, mint_keypair, .. } = create_genesis_config(50); - genesis_config.add_native_instruction_processor(solana_bpf_loader_program!()); let bank = Arc::new(Bank::new(&genesis_config)); // Create bank with specific slot, used by solana_bpf_rust_sysvar test let bank = @@ -135,11 +133,10 @@ mod bpf { println!("Test program: {:?}", program); let GenesisConfigInfo { - mut genesis_config, + genesis_config, mint_keypair, .. } = create_genesis_config(50); - genesis_config.add_native_instruction_processor(solana_bpf_loader_program!()); let bank = Arc::new(Bank::new(&genesis_config)); let bank_client = BankClient::new_shared(&bank); let program_id = load_bpf_program(&bank_client, &mint_keypair, program); @@ -218,11 +215,10 @@ mod bpf { println!("Test program: {:?}", program); let GenesisConfigInfo { - mut genesis_config, + genesis_config, mint_keypair, .. } = create_genesis_config(50); - genesis_config.add_native_instruction_processor(solana_bpf_loader_program!()); let bank = Bank::new(&genesis_config); let bank_client = BankClient::new(bank); let program_id = load_bpf_program(&bank_client, &mint_keypair, program); diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 77486e2c2b..226e727520 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -25,7 +25,7 @@ use solana_sdk::{ use std::{io::prelude::*, mem}; use thiserror::Error; -solana_sdk::declare_loader!( +solana_sdk::declare_program!( solana_sdk::bpf_loader::ID, solana_bpf_loader_program, process_instruction diff --git a/programs/failure/tests/failure.rs b/programs/failure/tests/failure.rs index b001aff425..0741f26708 100644 --- a/programs/failure/tests/failure.rs +++ b/programs/failure/tests/failure.rs @@ -4,7 +4,6 @@ use solana_runtime::loader_utils::create_invoke_instruction; use solana_sdk::client::SyncClient; use solana_sdk::genesis_config::create_genesis_config; use solana_sdk::instruction::InstructionError; -use solana_sdk::native_program_info; use solana_sdk::pubkey::Pubkey; use solana_sdk::signature::Signer; use solana_sdk::transaction::TransactionError; @@ -14,10 +13,7 @@ fn test_program_native_failure() { let (genesis_config, alice_keypair) = create_genesis_config(50); let program_id = Pubkey::new_rand(); let bank = Bank::new(&genesis_config); - bank.register_native_instruction_processor( - &native_program_info!("solana_failure_program"), - &program_id, - ); + bank.register_native_instruction_processor("solana_failure_program", &program_id); // Call user program let instruction = create_invoke_instruction(alice_keypair.pubkey(), program_id, &1u8); diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 01ebf3af6c..766254fbfc 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -27,6 +27,7 @@ rand = "0.6.5" rayon = "1.3.0" serde = { version = "1.0.106", features = ["rc"] } serde_derive = "1.0.103" +solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.2.0" } solana-logger = { path = "../logger", version = "1.2.0" } solana-measure = { path = "../measure", version = "1.2.0" } solana-metrics = { path = "../metrics", version = "1.2.0" } diff --git a/runtime/benches/bank.rs b/runtime/benches/bank.rs index 56a6234267..1c5f82879b 100644 --- a/runtime/benches/bank.rs +++ b/runtime/benches/bank.rs @@ -11,7 +11,6 @@ use solana_sdk::{ clock::MAX_RECENT_BLOCKHASHES, genesis_config::create_genesis_config, instruction::InstructionError, - native_program_info, pubkey::Pubkey, signature::{Keypair, Signer}, transaction::Transaction, @@ -125,7 +124,7 @@ fn do_bench_transactions( let mut bank = Bank::new(&genesis_config); bank.add_instruction_processor(Pubkey::new(&BUILTIN_PROGRAM_ID), process_instruction); bank.register_native_instruction_processor( - &native_program_info!("solana_noop_program"), + "solana_noop_program", &Pubkey::new(&NOOP_PROGRAM_ID), ); let bank = Arc::new(bank); diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 9faea2b264..475d3b3309 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -39,8 +39,7 @@ use solana_sdk::{ hard_forks::HardForks, hash::{extend_and_hash, hashv, Hash}, inflation::Inflation, - native_loader::{self, create_loadable_account}, - native_program_info, nonce, + native_loader, nonce, pubkey::Pubkey, signature::{Keypair, Signature}, slot_hashes::SlotHashes, @@ -899,18 +898,14 @@ impl Bank { ); // Add additional native programs specified in the genesis config - for (info, program_id) in &genesis_config.native_instruction_processors { - self.register_native_instruction_processor(&info, program_id); + for (name, program_id) in &genesis_config.native_instruction_processors { + self.register_native_instruction_processor(name, program_id); } } - pub fn register_native_instruction_processor( - &self, - info: &native_loader::Info, - program_id: &Pubkey, - ) { - debug!("Adding {:?} under {:?}", info, program_id); - let account = create_loadable_account(info); + pub fn register_native_instruction_processor(&self, name: &str, program_id: &Pubkey) { + debug!("Adding native program {} under {:?}", name, program_id); + let account = native_loader::create_loadable_account(name); self.store_account(program_id, &account); } @@ -2161,7 +2156,7 @@ impl Bank { assert_eq!(program_account.owner, solana_sdk::native_loader::id()); } else { // Register a bogus executable account, which will be loaded and ignored. - self.register_native_instruction_processor(&native_program_info!(""), &program_id); + self.register_native_instruction_processor("", &program_id); } } diff --git a/runtime/src/genesis_utils.rs b/runtime/src/genesis_utils.rs index 51ce8c1a41..2accac24b6 100644 --- a/runtime/src/genesis_utils.rs +++ b/runtime/src/genesis_utils.rs @@ -136,6 +136,7 @@ pub fn create_genesis_config_with_leader_ex( // Bare minimum program set let native_instruction_processors = vec![ solana_system_program(), + solana_bpf_loader_program!(), solana_vote_program!(), solana_stake_program!(), ]; diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index c32ce2e923..bec77dc00f 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -30,6 +30,9 @@ extern crate solana_vote_program; #[macro_use] extern crate solana_stake_program; +#[macro_use] +extern crate solana_bpf_loader_program; + #[macro_use] extern crate serde_derive; diff --git a/runtime/src/message_processor.rs b/runtime/src/message_processor.rs index 8b72a5dcae..8b739f1046 100644 --- a/runtime/src/message_processor.rs +++ b/runtime/src/message_processor.rs @@ -1,18 +1,22 @@ -use crate::{ - native_loader::NativeLoader, rent_collector::RentCollector, system_instruction_processor, -}; +use crate::{native_loader, rent_collector::RentCollector, system_instruction_processor}; use serde::{Deserialize, Serialize}; use solana_sdk::{ account::{create_keyed_readonly_accounts, Account, KeyedAccount}, clock::Epoch, + entrypoint_native, instruction::{CompiledInstruction, InstructionError}, message::Message, - native_loader, + native_loader::id as native_loader_id, pubkey::Pubkey, system_program, transaction::TransactionError, }; -use std::{cell::RefCell, rc::Rc}; +use std::{cell::RefCell, collections::HashMap, rc::Rc, sync::RwLock}; + +#[cfg(unix)] +use libloading::os::unix::*; +#[cfg(windows)] +use libloading::os::windows::*; // The relevant state of an account before an Instruction executes, used // to verify account integrity after the Instruction completes @@ -155,13 +159,14 @@ impl PreAccount { } pub type ProcessInstruction = fn(&Pubkey, &[KeyedAccount], &[u8]) -> Result<(), InstructionError>; +pub type SymbolCache = RwLock, Symbol>>; #[derive(Serialize, Deserialize)] pub struct MessageProcessor { #[serde(skip)] instruction_processors: Vec<(Pubkey, ProcessInstruction)>, #[serde(skip)] - native_loader: NativeLoader, + symbol_cache: SymbolCache, } impl Default for MessageProcessor { fn default() -> Self { @@ -172,7 +177,7 @@ impl Default for MessageProcessor { Self { instruction_processors, - native_loader: NativeLoader::default(), + symbol_cache: RwLock::new(HashMap::new()), } } } @@ -213,10 +218,10 @@ impl MessageProcessor { }) .collect(); keyed_accounts.append(&mut keyed_accounts2); - assert!(keyed_accounts[0].executable()?, "account not executable"); + assert!(keyed_accounts[0].executable()?, "account not executable"); + let root_program_id = keyed_accounts[0].unsigned_key(); for (id, process_instruction) in &self.instruction_processors { - let root_program_id = keyed_accounts[0].unsigned_key(); if id == root_program_id { return process_instruction( &root_program_id, @@ -226,15 +231,12 @@ impl MessageProcessor { } } - if native_loader::check_id(&keyed_accounts[0].owner()?) { - self.native_loader.process_instruction( - &native_loader::id(), - &keyed_accounts, - &instruction.data, - ) - } else { - Err(InstructionError::UnsupportedProgramId) - } + native_loader::invoke_entrypoint( + &native_loader_id(), + &keyed_accounts, + &instruction.data, + &self.symbol_cache, + ) } /// Record the initial state of the accounts so that they can be compared @@ -370,7 +372,6 @@ mod tests { instruction::{AccountMeta, Instruction, InstructionError}, message::Message, native_loader::create_loadable_account, - native_program_info, }; #[test] @@ -916,9 +917,7 @@ mod tests { accounts.push(account); let mut loaders: Vec)>> = Vec::new(); - let account = RefCell::new(create_loadable_account(&native_program_info!( - "mock_system_program" - ))); + let account = RefCell::new(create_loadable_account("mock_system_program")); loaders.push(vec![(mock_system_program_id, account)]); let from_pubkey = Pubkey::new_rand(); @@ -1041,9 +1040,7 @@ mod tests { accounts.push(account); let mut loaders: Vec)>> = Vec::new(); - let account = RefCell::new(create_loadable_account(&native_program_info!( - "mock_system_program" - ))); + let account = RefCell::new(create_loadable_account("mock_system_program")); loaders.push(vec![(mock_program_id, account)]); let from_pubkey = Pubkey::new_rand(); diff --git a/runtime/src/native_loader.rs b/runtime/src/native_loader.rs index 8074b857c1..443902abf4 100644 --- a/runtime/src/native_loader.rs +++ b/runtime/src/native_loader.rs @@ -1,30 +1,29 @@ //! Native loader +use crate::message_processor::SymbolCache; #[cfg(unix)] use libloading::os::unix::*; #[cfg(windows)] use libloading::os::windows::*; use log::*; use num_derive::{FromPrimitive, ToPrimitive}; -use num_traits::FromPrimitive; use solana_sdk::{ account::KeyedAccount, - entrypoint_native::{LoaderEntrypoint, ProgramEntrypoint}, + entrypoint_native, instruction::InstructionError, - native_loader::Kind, program_utils::{next_keyed_account, DecodeError}, pubkey::Pubkey, }; -use std::{collections::HashMap, env, path::PathBuf, str, sync::RwLock}; +use std::{env, path::PathBuf, str}; use thiserror::Error; #[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")] - InvalidEntrypointName = 0x0aaa_0001, + InvalidEntrypointName, #[error("Entrypoint was not found in the module")] - EntrypointNotFound = 0x0aaa_0002, + EntrypointNotFound, #[error("Failed to load the module")] - FailedToLoad = 0x0aaa_0003, + FailedToLoad, } impl DecodeError for NativeLoaderError { fn type_of() -> &'static str { @@ -34,130 +33,103 @@ impl DecodeError for NativeLoaderError { /// Dynamic link library prefixes #[cfg(unix)] -const PLATFORM_FILE_PREFIX: &str = "lib"; +const PLATFORM_FILE_PREFIX_NATIVE: &str = "lib"; #[cfg(windows)] -const PLATFORM_FILE_PREFIX: &str = ""; +const PLATFORM_FILE_PREFIX_NATIVE: &str = ""; /// Dynamic link library file extension specific to the platform #[cfg(any(target_os = "macos", target_os = "ios"))] -const PLATFORM_FILE_EXTENSION: &str = "dylib"; +const PLATFORM_FILE_EXTENSION_NATIVE: &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"; +const PLATFORM_FILE_EXTENSION_NATIVE: &str = "so"; /// Dynamic link library file extension specific to the platform #[cfg(windows)] -const PLATFORM_FILE_EXTENSION: &str = "dll"; +const PLATFORM_FILE_EXTENSION_NATIVE: &str = "dll"; -pub type ProgramSymbolCache = RwLock>>; -pub type LoaderSymbolCache = RwLock>>; +fn create_path(name: &str) -> PathBuf { + let current_exe = env::current_exe() + .unwrap_or_else(|e| panic!("create_path(\"{}\"): current exe not found: {:?}", name, e)); + let current_exe_directory = PathBuf::from(current_exe.parent().unwrap_or_else(|| { + panic!( + "create_path(\"{}\"): no parent directory of {:?}", + name, current_exe, + ) + })); -#[derive(Debug, Default)] -pub struct NativeLoader { - program_symbol_cache: ProgramSymbolCache, - loader_symbol_cache: LoaderSymbolCache, + let library_file_name = PathBuf::from(PLATFORM_FILE_PREFIX_NATIVE.to_string() + name) + .with_extension(PLATFORM_FILE_EXTENSION_NATIVE); + + // 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() { + file_path + } else { + // `cargo build` places dependent libraries in the deps/ subdirectory + current_exe_directory.join("deps").join(library_file_name) + } } -impl NativeLoader { - fn create_path(name: &str) -> PathBuf { - let current_exe = env::current_exe().unwrap_or_else(|e| { - panic!("create_path(\"{}\"): current exe not found: {:?}", name, e) - }); - let current_exe_directory = PathBuf::from(current_exe.parent().unwrap_or_else(|| { - panic!( - "create_path(\"{}\"): no parent directory of {:?}", - name, current_exe, - ) - })); - let library_file_name = PathBuf::from(PLATFORM_FILE_PREFIX.to_string() + name) - .with_extension(PLATFORM_FILE_EXTENSION); +#[cfg(windows)] +fn library_open(path: &PathBuf) -> std::io::Result { + Library::new(path) +} - // 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() { - file_path - } else { - // `cargo build` places dependent libraries in the deps/ subdirectory - current_exe_directory.join("deps").join(library_file_name) +#[cfg(not(windows))] +fn library_open(path: &PathBuf) -> std::io::Result { + // Linux tls bug can cause crash on dlclose(), workaround by never unloading + Library::open(Some(path), libc::RTLD_NODELETE | libc::RTLD_NOW) +} + +pub fn invoke_entrypoint( + _program_id: &Pubkey, + keyed_accounts: &[KeyedAccount], + instruction_data: &[u8], + symbol_cache: &SymbolCache, +) -> Result<(), InstructionError> { + let mut keyed_accounts_iter = keyed_accounts.iter(); + let program = next_keyed_account(&mut keyed_accounts_iter)?; + let params = keyed_accounts_iter.as_slice(); + let name_vec = &program.try_account_ref()?.data; + if let Some(entrypoint) = symbol_cache.read().unwrap().get(name_vec) { + unsafe { + return entrypoint(program.unsigned_key(), params, instruction_data); } } - - #[cfg(windows)] - fn library_open(path: &PathBuf) -> std::io::Result { - Library::new(path) - } - - #[cfg(not(windows))] - fn library_open(path: &PathBuf) -> std::io::Result { - // Linux tls bug can cause crash on dlclose(), workaround by never unloading - Library::open(Some(path), libc::RTLD_NODELETE | libc::RTLD_NOW) - } - - fn invoke_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) => { - warn!("Unable to find program entrypoint in {:?}: {:?})", name, e); - Err(NativeLoaderError::EntrypointNotFound.into()) - } + let name = match str::from_utf8(name_vec) { + Ok(v) => v, + Err(e) => { + warn!("Invalid UTF-8 sequence: {}", e); + return Err(NativeLoaderError::InvalidEntrypointName.into()); + } + }; + trace!("Call native {:?}", name); + let path = create_path(&name); + match library_open(&path) { + Ok(library) => unsafe { + let entrypoint: Symbol = + match library.get(name.as_bytes()) { + Ok(s) => s, + Err(e) => { + warn!( + "Unable to find entrypoint {:?} (error: {:?})", + name.as_bytes(), + e + ); + return Err(NativeLoaderError::EntrypointNotFound.into()); } - } - Err(e) => { - warn!("Failed to load: {:?}", e); - Err(NativeLoaderError::FailedToLoad.into()) - } - } - } - } - - pub fn process_instruction( - &self, - _program_id: &Pubkey, - keyed_accounts: &[KeyedAccount], - instruction_data: &[u8], - ) -> Result<(), InstructionError> { - let mut keyed_accounts_iter = keyed_accounts.iter(); - let program = next_keyed_account(&mut keyed_accounts_iter)?; - let params = keyed_accounts_iter.as_slice(); - let data = &program.try_account_ref()?.data; - let program_kind = FromPrimitive::from_u8(data[0]); - let name = match str::from_utf8(&data[1..]) { - Ok(v) => v, - Err(e) => { - warn!("Invalid UTF-8 sequence: {}", e); - return Err(NativeLoaderError::InvalidEntrypointName.into()); - } - }; - - trace!("Call native {:?}: {:?}", program_kind, name); - match program_kind { - Some(Kind::Program) => { - let entrypoint = - Self::invoke_entrypoint::(name, &self.program_symbol_cache)?; - unsafe { entrypoint(program.unsigned_key(), params, instruction_data) } - } - Some(Kind::Loader) => { - let entrypoint = - Self::invoke_entrypoint::(name, &self.loader_symbol_cache)?; - unsafe { entrypoint(program.unsigned_key(), params, instruction_data) } - } - None => { - warn!("Invalid native type: {:?}", data[0]); - Err(NativeLoaderError::FailedToLoad.into()) - } + }; + let ret = entrypoint(program.unsigned_key(), params, instruction_data); + symbol_cache + .write() + .unwrap() + .insert(name_vec.to_vec(), entrypoint); + ret + }, + Err(e) => { + warn!("Failed to load: {:?}", e); + Err(NativeLoaderError::FailedToLoad.into()) } } } diff --git a/runtime/tests/noop.rs b/runtime/tests/noop.rs index ca80d5789f..eae9c0704d 100644 --- a/runtime/tests/noop.rs +++ b/runtime/tests/noop.rs @@ -2,8 +2,7 @@ use solana_runtime::{ bank::Bank, bank_client::BankClient, loader_utils::create_invoke_instruction, }; use solana_sdk::{ - client::SyncClient, genesis_config::create_genesis_config, native_program_info, pubkey::Pubkey, - signature::Signer, + client::SyncClient, genesis_config::create_genesis_config, pubkey::Pubkey, signature::Signer, }; #[test] @@ -13,10 +12,7 @@ fn test_program_native_noop() { let (genesis_config, alice_keypair) = create_genesis_config(50); let program_id = Pubkey::new_rand(); let bank = Bank::new(&genesis_config); - bank.register_native_instruction_processor( - &native_program_info!("solana_noop_program"), - &program_id, - ); + bank.register_native_instruction_processor("solana_noop_program", &program_id); // Call user program let instruction = create_invoke_instruction(alice_keypair.pubkey(), program_id, &1u8); diff --git a/sdk/src/entrypoint_native.rs b/sdk/src/entrypoint_native.rs index 585d7c0231..4ad5bb3342 100644 --- a/sdk/src/entrypoint_native.rs +++ b/sdk/src/entrypoint_native.rs @@ -7,19 +7,7 @@ use crate::{account::KeyedAccount, instruction::InstructionError, pubkey::Pubkey /// 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>; - -// 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( +pub type Entrypoint = unsafe extern "C" fn( program_id: &Pubkey, keyed_accounts: &[KeyedAccount], instruction_data: &[u8], @@ -101,32 +89,7 @@ macro_rules! declare_program( #[macro_export] macro_rules! $name { () => { - (solana_sdk::native_program_info!(stringify!($name).to_string()), $crate::id()) - }; - } - - #[no_mangle] - pub extern "C" fn $name( - program_id: &$crate::pubkey::Pubkey, - keyed_accounts: &[$crate::account::KeyedAccount], - instruction_data: &[u8], - ) -> Result<(), $crate::instruction::InstructionError> { - $entrypoint(program_id, keyed_accounts, instruction_data) - } - ) -); - -/// Same as declare_program but for native loaders -#[macro_export] -macro_rules! declare_loader( - ($bs58_string:expr, $name:ident, $entrypoint:expr) => ( - $crate::declare_id!($bs58_string); - - #[macro_export] - macro_rules! $name { - () => { - (solana_sdk::native_loader_info!(stringify!($name).to_string()), $crate::id()) - + (stringify!($name).to_string(), $crate::id()) }; } diff --git a/sdk/src/genesis_config.rs b/sdk/src/genesis_config.rs index bebd77ae3f..09e3737679 100644 --- a/sdk/src/genesis_config.rs +++ b/sdk/src/genesis_config.rs @@ -7,7 +7,6 @@ use crate::{ fee_calculator::FeeRateGovernor, hash::{hash, Hash}, inflation::Inflation, - native_loader, native_token::lamports_to_sol, poh_config::PohConfig, pubkey::Pubkey, @@ -42,7 +41,7 @@ pub struct GenesisConfig { /// initial accounts pub accounts: BTreeMap, /// built-in programs - pub native_instruction_processors: Vec<(native_loader::Info, Pubkey)>, + pub native_instruction_processors: Vec<(String, Pubkey)>, /// accounts for network rewards, these do not count towards capitalization pub rewards_pools: BTreeMap, pub ticks_per_slot: u64, @@ -105,7 +104,7 @@ impl Default for GenesisConfig { impl GenesisConfig { pub fn new( accounts: &[(Pubkey, Account)], - native_instruction_processors: &[(native_loader::Info, Pubkey)], + native_instruction_processors: &[(String, Pubkey)], ) -> Self { Self { accounts: accounts @@ -173,8 +172,8 @@ impl GenesisConfig { self.accounts.insert(pubkey, account); } - pub fn add_native_instruction_processor(&mut self, processor: (native_loader::Info, Pubkey)) { - self.native_instruction_processors.push(processor); + pub fn add_native_instruction_processor(&mut self, name: String, program_id: Pubkey) { + self.native_instruction_processors.push((name, program_id)); } pub fn add_rewards_pool(&mut self, pubkey: Pubkey, account: Account) { @@ -231,7 +230,6 @@ impl fmt::Display for GenesisConfig { mod tests { use super::*; use crate::signature::{Keypair, Signer}; - use solana_sdk::native_program_info; use std::path::PathBuf; fn make_tmp_path(name: &str) -> PathBuf { @@ -263,10 +261,7 @@ mod tests { Account::new(10_000, 0, &Pubkey::default()), ); config.add_account(Pubkey::new_rand(), Account::new(1, 0, &Pubkey::default())); - config.add_native_instruction_processor(( - native_program_info!("hi".to_string()), - Pubkey::new_rand(), - )); + config.add_native_instruction_processor("hi".to_string(), Pubkey::new_rand()); assert_eq!(config.accounts.len(), 2); assert!(config diff --git a/sdk/src/instruction.rs b/sdk/src/instruction.rs index ea3862f133..6d1cd3b3a4 100644 --- a/sdk/src/instruction.rs +++ b/sdk/src/instruction.rs @@ -134,10 +134,6 @@ pub enum InstructionError { /// Executable accounts must be rent exempt #[error("executable accounts must be rent exempt")] ExecutableAccountNotRentExempt, - - /// Unsupported program id - #[error("Unsupported program id")] - UnsupportedProgramId, } impl InstructionError { diff --git a/sdk/src/move_loader.rs b/sdk/src/move_loader.rs index 7d871177c1..d89c077d62 100644 --- a/sdk/src/move_loader.rs +++ b/sdk/src/move_loader.rs @@ -1,10 +1,5 @@ -use crate::{native_loader, native_program_info, pubkey::Pubkey}; - crate::declare_id!("MoveLdr111111111111111111111111111111111111"); -pub fn solana_move_loader_program() -> (native_loader::Info, Pubkey) { - ( - native_program_info!("solana_move_loader_program".to_string()), - id(), - ) +pub fn solana_move_loader_program() -> (String, crate::pubkey::Pubkey) { + ("solana_move_loader_program".to_string(), id()) } diff --git a/sdk/src/native_loader.rs b/sdk/src/native_loader.rs index f2386c7e76..e7bdff6d4b 100644 --- a/sdk/src/native_loader.rs +++ b/sdk/src/native_loader.rs @@ -1,46 +1,13 @@ use crate::{account::Account, hash::Hash}; -use num_derive::FromPrimitive; crate::declare_id!("NativeLoader1111111111111111111111111111111"); -#[derive(Debug, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)] -pub struct Info { - pub kind: Kind, - pub name: String, -} -#[derive(Debug, Clone, Copy, Deserialize, Eq, FromPrimitive, Hash, PartialEq, Serialize)] -pub enum Kind { - Program = 1, - Loader = 2, -} - -#[macro_export] -macro_rules! native_program_info( - ($name:expr) => ( - $crate::native_loader::Info { - kind: $crate::native_loader::Kind::Program, - name: $name.to_string(), - } - ) -); -#[macro_export] -macro_rules! native_loader_info( - ($name:expr) => ( - $crate::native_loader::Info { - kind: $crate::native_loader::Kind::Loader, - name: $name.to_string(), - } - ) -); - /// Create an executable account with the given shared object name. -pub fn create_loadable_account(info: &Info) -> Account { - let mut data = vec![info.kind as u8]; - data.extend_from_slice(info.name.as_bytes()); +pub fn create_loadable_account(name: &str) -> Account { Account { lamports: 1, owner: id(), - data, + data: name.as_bytes().to_vec(), executable: true, rent_epoch: 0, hash: Hash::default(), diff --git a/sdk/src/system_program.rs b/sdk/src/system_program.rs index 81624779fc..8b1ce46811 100644 --- a/sdk/src/system_program.rs +++ b/sdk/src/system_program.rs @@ -1,10 +1,5 @@ -use crate::{native_loader, native_program_info, pubkey::Pubkey}; - crate::declare_id!("11111111111111111111111111111111"); -pub fn solana_system_program() -> (native_loader::Info, Pubkey) { - ( - native_program_info!("solana_system_program".to_string()), - id(), - ) +pub fn solana_system_program() -> (String, crate::pubkey::Pubkey) { + ("solana_system_program".to_string(), id()) }