diff --git a/Cargo.lock b/Cargo.lock index 25be241e4bc51a..dbe3a20c540fe8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3368,7 +3368,6 @@ version = "1.4.0" dependencies = [ "bincode", "byteorder", - "jemalloc-sys", "num-derive 0.3.0", "num-traits", "rand 0.7.3", diff --git a/bench-exchange/tests/bench_exchange.rs b/bench-exchange/tests/bench_exchange.rs index ea24fffd14e4f3..bd239bd0aa278e 100644 --- a/bench-exchange/tests/bench_exchange.rs +++ b/bench-exchange/tests/bench_exchange.rs @@ -7,7 +7,7 @@ use solana_exchange_program::id; use solana_exchange_program::solana_exchange_program; use solana_faucet::faucet::run_local_faucet; use solana_local_cluster::local_cluster::{ClusterConfig, LocalCluster}; -use solana_runtime::bank::Bank; +use solana_runtime::bank::{Bank, BuiltinEntrypoint}; use solana_runtime::bank_client::BankClient; use solana_sdk::genesis_config::create_genesis_config; use solana_sdk::signature::{Keypair, Signer}; @@ -86,7 +86,11 @@ fn test_exchange_bank_client() { solana_logger::setup(); let (genesis_config, identity) = create_genesis_config(100_000_000_000_000); let mut bank = Bank::new(&genesis_config); - bank.add_builtin_program("exchange_program", id(), process_instruction); + bank.add_builtin( + "exchange_program", + id(), + BuiltinEntrypoint::Program(process_instruction), + ); let clients = vec![BankClient::new(bank)]; let mut config = Config::default(); diff --git a/core/src/validator.rs b/core/src/validator.rs index 32983d80c926a8..32248d9564672c 100644 --- a/core/src/validator.rs +++ b/core/src/validator.rs @@ -190,7 +190,7 @@ impl Validator { } report_target_features(); - info!("entrypoint: {:?}", entrypoint_info_option); + // info!("entrypoint: {:?}", entrypoint_info_option); if solana_perf::perf_libs::api().is_some() { info!("Initializing sigverify, this could take a while..."); @@ -868,10 +868,10 @@ impl TestValidator { 42, bootstrap_validator_lamports, ); - genesis_config - .native_instruction_processors - .push(solana_bpf_loader_program!()); - + // TODO + // 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; genesis_config.fee_rate_governor = FeeRateGovernor::new(fees, 0); diff --git a/genesis-programs/src/lib.rs b/genesis-programs/src/lib.rs index ca951cee032bb9..fec75d32f794c5 100644 --- a/genesis-programs/src/lib.rs +++ b/genesis-programs/src/lib.rs @@ -1,6 +1,3 @@ -use solana_sdk::{ - clock::Epoch, genesis_config::OperatingMode, inflation::Inflation, pubkey::Pubkey, -}; #[macro_use] extern crate solana_bpf_loader_program; @@ -12,7 +9,11 @@ extern crate solana_exchange_program; extern crate solana_vest_program; use log::*; -use solana_runtime::bank::{Bank, EnteredEpochCallback}; +use solana_runtime::bank::{Bank, BuiltinEntrypoint, EnteredEpochCallback}; +use solana_sdk::{ + bpf_loader, clock::Epoch, genesis_config::OperatingMode, inflation::Inflation, + pubkey::Pubkey, +}; pub fn get_inflation(operating_mode: OperatingMode, epoch: Epoch) -> Option { match operating_mode { @@ -45,17 +46,28 @@ pub fn get_inflation(operating_mode: OperatingMode, epoch: Epoch) -> Option Option> { +// TODO Need to be public? +pub enum Program { + Native((String, Pubkey)), + Builtin(String, Pubkey, BuiltinEntrypoint), +} + +pub fn get_programs(operating_mode: OperatingMode, epoch: Epoch) -> Option> { + println!("get_progarms {:?} {:?}", operating_mode, epoch); match operating_mode { OperatingMode::Development => { if epoch == 0 { Some(vec![ // Enable all Stable programs - solana_bpf_loader_program!(), - solana_vest_program!(), + Program::Builtin( + "bpf_loader_program".to_string(), + bpf_loader::id(), + BuiltinEntrypoint::Loader(solana_bpf_loader_program::process_instruction), + ), + Program::Native(solana_vest_program!()), // Programs that are only available in Development mode - solana_budget_program!(), - solana_exchange_program!(), + Program::Native(solana_budget_program!()), + Program::Native(solana_exchange_program!()), ]) } else { None @@ -65,22 +77,30 @@ pub fn get_programs(operating_mode: OperatingMode, epoch: Epoch) -> Option { if epoch == 0 { - Some(vec![solana_bpf_loader_program!()]) + Some(vec![Program::Builtin( + "bpf_loader_program".to_string(), + bpf_loader::id(), + BuiltinEntrypoint::Loader(solana_bpf_loader_program::process_instruction), + )]) } else if epoch == std::u64::MAX { // The epoch of std::u64::MAX is a placeholder and is expected to be reduced in a // future hard fork. - Some(vec![solana_vest_program!()]) + Some(vec![Program::Native(solana_vest_program!())]) } else { None } @@ -88,6 +108,25 @@ pub fn get_programs(operating_mode: OperatingMode, epoch: Epoch) -> Option Option> { + println!("get_native_progarms {:?} {:?}", operating_mode, epoch); + match get_programs(operating_mode, epoch) { + Some(programs) => { + let mut native_programs = vec![]; + for program in programs { + if let Program::Native((string, key)) = program { + native_programs.push((string, key)); + } + } + Some(native_programs) + } + None => None, + } +} + pub fn get_entered_epoch_callback(operating_mode: OperatingMode) -> EnteredEpochCallback { Box::new(move |bank: &mut Bank| { info!( @@ -99,10 +138,18 @@ pub fn get_entered_epoch_callback(operating_mode: OperatingMode) -> EnteredEpoch info!("Entering new epoch with inflation {:?}", inflation); bank.set_inflation(inflation); } - if let Some(new_programs) = get_programs(operating_mode, bank.epoch()) { - for (name, program_id) in new_programs.iter() { - info!("Registering {} at {}", name, program_id); - bank.add_native_program(name, program_id); + if let Some(programs) = get_programs(operating_mode, bank.epoch()) { + for program in programs { + match program { + Program::Native((name, program_id)) => { + info!("Registering {} at {}", name, program_id); + bank.add_native_program(&name, &program_id); + } + Program::Builtin(name, program_id, entrypoint) => { + info!("Registering builtin {} at {}", name, program_id); + bank.add_builtin(&name, program_id, entrypoint); + } + } } } if OperatingMode::Stable == operating_mode { @@ -121,8 +168,13 @@ mod tests { #[test] fn test_id_uniqueness() { let mut unique = HashSet::new(); - let ids = get_programs(OperatingMode::Development, 0).unwrap(); - assert!(ids.into_iter().all(move |id| unique.insert(id))); + let programs = get_programs(OperatingMode::Development, 0).unwrap(); + for program in programs { + match program { + Program::Native((name, id)) => assert!(unique.insert((name, id))), + Program::Builtin(name, id, _) => assert!(unique.insert((name, id))), + } + } } #[test] @@ -140,7 +192,18 @@ mod tests { get_programs(OperatingMode::Development, 0).unwrap().len(), 4 ); - assert_eq!(get_programs(OperatingMode::Development, 1), None); + assert!(get_programs(OperatingMode::Development, 1).is_none()); + } + + #[test] + fn test_native_development_programs() { + assert_eq!( + get_native_programs(OperatingMode::Development, 0) + .unwrap() + .len(), + 4 + ); + assert!(get_native_programs(OperatingMode::Development, 1).is_none()); } #[test] @@ -158,7 +221,7 @@ mod tests { #[test] fn test_softlaunch_programs() { - assert_eq!(get_programs(OperatingMode::Stable, 1), None); + assert!(get_programs(OperatingMode::Stable, 1).is_none()); assert!(get_programs(OperatingMode::Stable, std::u64::MAX - 1).is_some()); assert!(get_programs(OperatingMode::Stable, std::u64::MAX).is_some()); } diff --git a/genesis/src/main.rs b/genesis/src/main.rs index a4ca134a6ad7bd..9e125da3aef4c4 100644 --- a/genesis/src/main.rs +++ b/genesis/src/main.rs @@ -467,8 +467,9 @@ fn main() -> Result<(), Box> { matches.is_present("enable_warmup_epochs"), ); + // TODO does not include bpf loader in development operating mode let native_instruction_processors = - solana_genesis_programs::get_programs(operating_mode, 0).unwrap_or_else(Vec::new); + solana_genesis_programs::get_native_programs(operating_mode, 0).unwrap_or_else(Vec::new); let inflation = solana_genesis_programs::get_inflation(operating_mode, 0).unwrap(); let mut genesis_config = GenesisConfig { diff --git a/local-cluster/src/local_cluster.rs b/local-cluster/src/local_cluster.rs index e2797cb155fe52..437e109db326a0 100644 --- a/local-cluster/src/local_cluster.rs +++ b/local-cluster/src/local_cluster.rs @@ -171,7 +171,7 @@ impl LocalCluster { match genesis_config.operating_mode { OperatingMode::Stable | OperatingMode::Preview => { genesis_config.native_instruction_processors = - solana_genesis_programs::get_programs(genesis_config.operating_mode, 0) + solana_genesis_programs::get_native_programs(genesis_config.operating_mode, 0) .unwrap_or_default() } _ => (), diff --git a/metrics/src/metrics.rs b/metrics/src/metrics.rs index ee0a37bd290fab..b6ef5b8ae74ad8 100644 --- a/metrics/src/metrics.rs +++ b/metrics/src/metrics.rs @@ -242,7 +242,7 @@ impl MetricsAgent { points.push(point); } MetricsCommand::SubmitCounter(counter, level, bucket) => { - debug!("{:?}", counter); + // debug!("{:?}", counter); let (counters, _) = points_map .entry(level) .or_insert((HashMap::new(), Vec::new())); diff --git a/programs/bpf/Cargo.lock b/programs/bpf/Cargo.lock index 4c99002d93b23b..5b72d35983a246 100644 --- a/programs/bpf/Cargo.lock +++ b/programs/bpf/Cargo.lock @@ -1614,15 +1614,14 @@ checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4" name = "solana-bpf-loader-program" version = "1.4.0" dependencies = [ - "bincode", - "byteorder 1.3.4", - "jemalloc-sys", - "num-derive 0.3.0", - "num-traits", - "solana-runtime", - "solana-sdk", - "solana_rbpf", - "thiserror", + "bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-runtime 1.3.0", + "solana-sdk 1.3.0", + "solana_rbpf 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index e3242f1c467fa8..8693b62f34a5d8 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -1,8 +1,7 @@ #[cfg(any(feature = "bpf_c", feature = "bpf_rust"))] mod bpf { - use solana_bpf_loader_program::solana_bpf_loader_program; use solana_runtime::{ - bank::Bank, + bank::{Bank, BuiltinEntrypoint}, bank_client::BankClient, genesis_utils::{create_genesis_config, GenesisConfigInfo}, loader_utils::load_program, @@ -84,14 +83,18 @@ mod bpf { println!("Test program: {:?}", program.0); let GenesisConfigInfo { - mut genesis_config, + genesis_config, mint_keypair, .. } = create_genesis_config(50); - genesis_config - .native_instruction_processors - .push(solana_bpf_loader_program!()); - let bank = Arc::new(Bank::new(&genesis_config)); + let mut bank = Bank::new(&genesis_config); + bank.add_builtin( + "solana_bpf_loader_program", + bpf_loader::id(), + BuiltinEntrypoint::Loader(solana_bpf_loader_program::process_instruction), + ); + let bank = Arc::new(bank); + // Create bank with a specific slot, used by solana_bpf_rust_sysvar test let bank = Bank::new_from_parent(&bank, &Pubkey::default(), DEFAULT_SLOTS_PER_EPOCH + 1); @@ -137,14 +140,17 @@ mod bpf { println!("Test program: {:?}", program); let GenesisConfigInfo { - mut genesis_config, + genesis_config, mint_keypair, .. } = create_genesis_config(50); - genesis_config - .native_instruction_processors - .push(solana_bpf_loader_program!()); - let bank = Arc::new(Bank::new(&genesis_config)); + let mut bank = Bank::new(&genesis_config); + bank.add_builtin( + "solana_bpf_loader_program", + bpf_loader::id(), + BuiltinEntrypoint::Loader(solana_bpf_loader_program::process_instruction), + ); + let bank = Arc::new(bank); let bank_client = BankClient::new_shared(&bank); let program_id = load_bpf_program(&bank_client, &mint_keypair, program); let payee_account = Account::new(10, 1, &program_id); @@ -222,14 +228,16 @@ mod bpf { println!("Test program: {:?}", program); let GenesisConfigInfo { - mut genesis_config, + genesis_config, mint_keypair, .. } = create_genesis_config(50); - genesis_config - .native_instruction_processors - .push(solana_bpf_loader_program!()); - let bank = Bank::new(&genesis_config); + let mut bank = Bank::new(&genesis_config); + bank.add_builtin( + "solana_bpf_loader_program", + bpf_loader::id(), + BuiltinEntrypoint::Loader(solana_bpf_loader_program::process_instruction), + ); let bank_client = BankClient::new(bank); let program_id = load_bpf_program(&bank_client, &mint_keypair, program); let account_metas = vec![AccountMeta::new(mint_keypair.pubkey(), true)]; @@ -333,14 +341,17 @@ mod bpf { println!("Test program: {:?}", program); let GenesisConfigInfo { - mut genesis_config, + genesis_config, mint_keypair, .. } = create_genesis_config(50); - genesis_config - .native_instruction_processors - .push(solana_bpf_loader_program!()); - let bank = Arc::new(Bank::new(&genesis_config)); + let mut bank = Bank::new(&genesis_config); + bank.add_builtin( + "solana_bpf_loader_program", + bpf_loader::id(), + BuiltinEntrypoint::Loader(solana_bpf_loader_program::process_instruction), + ); + let bank = Arc::new(bank); let bank_client = BankClient::new_shared(&bank); let invoke_program_id = load_bpf_program(&bank_client, &mint_keypair, program.0); diff --git a/programs/bpf_loader/Cargo.toml b/programs/bpf_loader/Cargo.toml index c0da39310761d0..7f6585a8998f6a 100644 --- a/programs/bpf_loader/Cargo.toml +++ b/programs/bpf_loader/Cargo.toml @@ -11,7 +11,6 @@ edition = "2018" [dependencies] bincode = "1.3.1" byteorder = "1.3.4" -jemalloc-sys = { version = "0.3.2", features = ["disable_initial_exec_tls"] } num-derive = { version = "0.3" } num-traits = { version = "0.2" } solana-runtime = { path = "../../runtime", version = "1.4.0" } @@ -24,7 +23,7 @@ rand = "0.7.3" rustversion = "1.0.3" [lib] -crate-type = ["lib", "cdylib"] +crate-type = ["lib"] name = "solana_bpf_loader_program" [package.metadata.docs.rs] diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index c48874e11c6cef..a988edc9aade1f 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -25,12 +25,6 @@ use solana_sdk::{ use std::{io::prelude::*, mem}; use thiserror::Error; -solana_sdk::declare_loader!( - solana_sdk::bpf_loader::ID, - solana_bpf_loader_program, - process_instruction -); - #[derive(Error, Debug, Clone, PartialEq, FromPrimitive, ToPrimitive)] pub enum BPFLoaderError { #[error("failed to create virtual machine")] diff --git a/programs/budget/src/budget_processor.rs b/programs/budget/src/budget_processor.rs index 797bee321300bd..5bb60efbf5d6a1 100644 --- a/programs/budget/src/budget_processor.rs +++ b/programs/budget/src/budget_processor.rs @@ -224,7 +224,7 @@ mod tests { use super::*; use crate::budget_instruction; use crate::id; - use solana_runtime::bank::Bank; + use solana_runtime::bank::{Bank, BuiltinEntrypoint}; use solana_runtime::bank_client::BankClient; use solana_sdk::account::Account; use solana_sdk::client::SyncClient; @@ -238,7 +238,11 @@ mod tests { fn create_bank(lamports: u64) -> (Bank, Keypair) { let (genesis_config, mint_keypair) = create_genesis_config(lamports); let mut bank = Bank::new(&genesis_config); - bank.add_builtin_program("budget_program", id(), process_instruction); + bank.add_builtin( + "budget_program", + id(), + BuiltinEntrypoint::Program(process_instruction), + ); (bank, mint_keypair) } diff --git a/programs/exchange/src/exchange_processor.rs b/programs/exchange/src/exchange_processor.rs index a31df31c8ca494..9af6122315648a 100644 --- a/programs/exchange/src/exchange_processor.rs +++ b/programs/exchange/src/exchange_processor.rs @@ -488,7 +488,7 @@ pub fn process_instruction( mod test { use super::*; use crate::{exchange_instruction, id}; - use solana_runtime::bank::Bank; + use solana_runtime::bank::{Bank, BuiltinEntrypoint}; use solana_runtime::bank_client::BankClient; use solana_sdk::client::SyncClient; use solana_sdk::genesis_config::create_genesis_config; @@ -578,7 +578,11 @@ mod test { fn create_bank(lamports: u64) -> (Bank, Keypair) { let (genesis_config, mint_keypair) = create_genesis_config(lamports); let mut bank = Bank::new(&genesis_config); - bank.add_builtin_program("exchange_program", id(), process_instruction); + bank.add_builtin( + "exchange_program", + id(), + BuiltinEntrypoint::Program(process_instruction), + ); (bank, mint_keypair) } diff --git a/programs/ownable/src/ownable_processor.rs b/programs/ownable/src/ownable_processor.rs index 3e6a2724a4353e..1391ae3894cb22 100644 --- a/programs/ownable/src/ownable_processor.rs +++ b/programs/ownable/src/ownable_processor.rs @@ -57,7 +57,10 @@ pub fn process_instruction( mod tests { use super::*; use crate::ownable_instruction; - use solana_runtime::{bank::Bank, bank_client::BankClient}; + use solana_runtime::{ + bank::{Bank, BuiltinEntrypoint}, + bank_client::BankClient, + }; use solana_sdk::{ account::Account, client::SyncClient, @@ -71,7 +74,11 @@ mod tests { fn create_bank(lamports: u64) -> (Bank, Keypair) { let (genesis_config, mint_keypair) = create_genesis_config(lamports); let mut bank = Bank::new(&genesis_config); - bank.add_builtin_program("ownable_program", crate::id(), process_instruction); + bank.add_builtin( + "ownable_program", + crate::id(), + BuiltinEntrypoint::Program(process_instruction), + ); (bank, mint_keypair) } diff --git a/programs/vest/src/vest_processor.rs b/programs/vest/src/vest_processor.rs index 2dc574811f4b0d..3c935b1d620417 100644 --- a/programs/vest/src/vest_processor.rs +++ b/programs/vest/src/vest_processor.rs @@ -147,7 +147,7 @@ mod tests { use crate::id; use crate::vest_instruction; use solana_config_program::date_instruction; - use solana_runtime::bank::Bank; + use solana_runtime::bank::{Bank, BuiltinEntrypoint}; use solana_runtime::bank_client::BankClient; use solana_sdk::client::SyncClient; use solana_sdk::genesis_config::create_genesis_config; @@ -161,7 +161,11 @@ mod tests { fn create_bank(lamports: u64) -> (Bank, Keypair) { let (genesis_config, mint_keypair) = create_genesis_config(lamports); let mut bank = Bank::new(&genesis_config); - bank.add_builtin_program("vest_program", id(), process_instruction); + bank.add_builtin( + "vest_program", + id(), + BuiltinEntrypoint::Program(process_instruction), + ); (bank, mint_keypair) } diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index bec1b0d21f8f0d..ebdee404340387 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -35,7 +35,7 @@ use solana_sdk::{ Epoch, Slot, SlotCount, SlotIndex, UnixTimestamp, DEFAULT_TICKS_PER_SECOND, MAX_PROCESSING_AGE, MAX_RECENT_BLOCKHASHES, SECONDS_PER_DAY, }, - entrypoint_native::ProcessInstruction, + entrypoint_native::{ProcessInstruction, ProcessInstructionWithContext}, epoch_info::EpochInfo, epoch_schedule::EpochSchedule, fee_calculator::{FeeCalculator, FeeRateGovernor}, @@ -98,6 +98,11 @@ type RentCollectionCycleParams = ( type EpochCount = u64; +pub enum BuiltinEntrypoint { + Program(ProcessInstruction), + Loader(ProcessInstructionWithContext), +} + #[derive(Default)] pub struct BankRc { /// where all the Accounts are stored @@ -427,6 +432,7 @@ impl Bank { paths: Vec, frozen_account_pubkeys: &[Pubkey], ) -> Self { + println!("bank::new_with_paths"); let mut bank = Self::default(); bank.operating_mode = Some(genesis_config.operating_mode); bank.ancestors.insert(bank.slot(), 0); @@ -462,6 +468,7 @@ impl Bank { /// Create a new bank that points to an immutable checkpoint of another bank. pub fn new_from_parent(parent: &Arc, collector_id: &Pubkey, slot: Slot) -> Self { + println!("bank::new_from_parent"); parent.freeze(); assert_ne!(slot, parent.slot()); @@ -537,10 +544,14 @@ impl Bank { ); let leader_schedule_epoch = epoch_schedule.get_leader_schedule_epoch(slot); + println!("parent.epoch {:?} new.epoch {:?}", parent.epoch(), new.epoch()); if parent.epoch() < new.epoch() { + println!("uyup"); if let Some(entered_epoch_callback) = parent.entered_epoch_callback.read().unwrap().as_ref() { + println!("call entered callack"); + entered_epoch_callback(&mut new) } @@ -548,7 +559,11 @@ impl Bank { get_epoch_activated_builtin_programs(new.operating_mode(), new.epoch) { for program in builtin_programs.iter() { - new.add_builtin_program(&program.name, program.id, program.process_instruction); + new.add_builtin( + &program.name, + program.id, + BuiltinEntrypoint::Program(program.process_instruction), + ); } } } @@ -1189,6 +1204,7 @@ impl Bank { // Add additional native programs specified in the genesis config for (name, program_id) in &genesis_config.native_instruction_processors { + println!("add native program!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); self.add_native_program(name, program_id); } } @@ -1196,7 +1212,7 @@ impl Bank { pub fn add_native_program(&self, name: &str, program_id: &Pubkey) { let account = native_loader::create_loadable_account(name); self.store_account(program_id, &account); - debug!("Added native program {} under {:?}", name, program_id); + println!("Added native program {} under {:?}", name, program_id); } pub fn set_cross_program_support(&mut self, is_supported: bool) { @@ -2565,7 +2581,11 @@ impl Bank { pub fn finish_init(&mut self) { let builtin_programs = get_builtin_programs(self.operating_mode(), self.epoch); for program in builtin_programs.iter() { - self.add_builtin_program(&program.name, program.id, program.process_instruction); + self.add_builtin( + &program.name, + program.id, + BuiltinEntrypoint::Program(program.process_instruction), + ); } } @@ -3009,19 +3029,16 @@ impl Bank { !self.is_delta.load(Ordering::Relaxed) } + + // TODO adds these twice during local cluster creation /// Add an instruction processor to intercept instructions before the dynamic loader. - pub fn add_builtin_program( - &mut self, - name: &str, - program_id: Pubkey, - process_instruction: ProcessInstruction, - ) { + pub fn add_builtin(&mut self, name: &str, program_id: Pubkey, entrypoint: BuiltinEntrypoint) { match self.get_account(&program_id) { Some(account) => { assert_eq!( account.owner, native_loader::id(), - "Cannot overwrite non-native loader account" + "Cannot overwrite non-native account" ); } None => { @@ -3030,9 +3047,18 @@ impl Bank { self.store_account(&program_id, &account); } } - self.message_processor - .add_program(program_id, process_instruction); - debug!("Added static program {} under {:?}", name, program_id); + match entrypoint { + BuiltinEntrypoint::Program(process_instruction) => { + self.message_processor + .add_program(program_id, process_instruction); + println!("Added static program {} under {:?}", name, program_id); + } + BuiltinEntrypoint::Loader(process_instruction_with_context) => { + self.message_processor + .add_loader(program_id, process_instruction_with_context); + println!("Added static loader {} under {:?}", name, program_id); + } + } } pub fn compare_bank(&self, dbank: &Bank) { @@ -3597,7 +3623,11 @@ mod tests { ) as u64, ); bank.rent_collector.slots_per_year = 421_812.0; - bank.add_builtin_program("mock_program", mock_program_id, mock_process_instruction); + bank.add_builtin( + "mock_program", + mock_program_id, + BuiltinEntrypoint::Program(mock_process_instruction), + ); bank } @@ -6632,7 +6662,7 @@ mod tests { } #[test] - fn test_add_builtin_program() { + fn test_add_builtin() { let (genesis_config, mint_keypair) = create_genesis_config(500); let mut bank = Bank::new(&genesis_config); @@ -6651,10 +6681,10 @@ mod tests { } assert!(bank.get_account(&mock_vote_program_id()).is_none()); - bank.add_builtin_program( + bank.add_builtin( "mock_vote_program", mock_vote_program_id(), - mock_vote_processor, + BuiltinEntrypoint::Program(mock_vote_processor), ); assert!(bank.get_account(&mock_vote_program_id()).is_some()); @@ -6724,10 +6754,10 @@ mod tests { ); let vote_loader_account = bank.get_account(&solana_vote_program::id()).unwrap(); - bank.add_builtin_program( + bank.add_builtin( "solana_vote_program", solana_vote_program::id(), - mock_vote_processor, + BuiltinEntrypoint::Program(mock_vote_processor), ); 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. @@ -6756,7 +6786,11 @@ mod tests { } // Non-native loader accounts can not be used for instruction processing - bank.add_builtin_program("mock_program", mint_keypair.pubkey(), mock_ix_processor); + bank.add_builtin( + "mock_program", + mint_keypair.pubkey(), + BuiltinEntrypoint::Program(mock_ix_processor), + ); } #[test] fn test_recent_blockhashes_sysvar() { @@ -7393,7 +7427,11 @@ mod tests { } let mock_program_id = Pubkey::new(&[2u8; 32]); - bank.add_builtin_program("mock_program", mock_program_id, mock_process_instruction); + bank.add_builtin( + "mock_program", + mock_program_id, + BuiltinEntrypoint::Program(mock_process_instruction), + ); let from_pubkey = Pubkey::new_rand(); let to_pubkey = Pubkey::new_rand(); @@ -7436,7 +7474,11 @@ mod tests { } let mock_program_id = Pubkey::new(&[2u8; 32]); - bank.add_builtin_program("mock_program", mock_program_id, mock_process_instruction); + bank.add_builtin( + "mock_program", + mock_program_id, + BuiltinEntrypoint::Program(mock_process_instruction), + ); let from_pubkey = Pubkey::new_rand(); let to_pubkey = Pubkey::new_rand(); @@ -7488,10 +7530,10 @@ mod tests { tx.message.account_keys.push(Pubkey::new_rand()); - bank.add_builtin_program( + bank.add_builtin( "mock_vote", solana_vote_program::id(), - mock_ok_vote_processor, + BuiltinEntrypoint::Program(mock_ok_vote_processor), ); let result = bank.process_transaction(&tx); assert_eq!(result, Ok(())); @@ -7542,10 +7584,10 @@ mod tests { AccountMeta::new(to_pubkey, false), ]; - bank.add_builtin_program( + bank.add_builtin( "mock_vote", solana_vote_program::id(), - mock_ok_vote_processor, + BuiltinEntrypoint::Program(mock_ok_vote_processor), ); let instruction = Instruction::new(solana_vote_program::id(), &10, account_metas); @@ -7575,10 +7617,10 @@ mod tests { AccountMeta::new(to_pubkey, false), ]; - bank.add_builtin_program( + bank.add_builtin( "mock_vote", solana_vote_program::id(), - mock_ok_vote_processor, + BuiltinEntrypoint::Program(mock_ok_vote_processor), ); let instruction = Instruction::new(solana_vote_program::id(), &10, account_metas); @@ -7630,10 +7672,10 @@ mod tests { AccountMeta::new(to_pubkey, false), ]; - bank.add_builtin_program( + bank.add_builtin( "mock_vote", solana_vote_program::id(), - mock_ok_vote_processor, + BuiltinEntrypoint::Program(mock_ok_vote_processor), ); let instruction = Instruction::new(solana_vote_program::id(), &10, account_metas); @@ -7666,7 +7708,11 @@ mod tests { .map(|i| { let key = Pubkey::new_rand(); let name = format!("program{:?}", i); - bank.add_builtin_program(&name, key, mock_ok_vote_processor); + bank.add_builtin( + &name, + key, + BuiltinEntrypoint::Program(mock_ok_vote_processor), + ); (key, name.as_bytes().to_vec()) }) .collect(); @@ -7871,7 +7917,11 @@ mod tests { // Add a new program let program1_pubkey = Pubkey::new_rand(); - bank.add_builtin_program("program", program1_pubkey, nested_processor); + bank.add_builtin( + "program", + program1_pubkey, + BuiltinEntrypoint::Program(nested_processor), + ); // Add a new program owned by the first let program2_pubkey = Pubkey::new_rand(); diff --git a/runtime/src/message_processor.rs b/runtime/src/message_processor.rs index 311caf198a162a..d46bb3be28cf70 100644 --- a/runtime/src/message_processor.rs +++ b/runtime/src/message_processor.rs @@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize}; use solana_sdk::{ account::{create_keyed_readonly_accounts, Account, KeyedAccount}, clock::Epoch, - entrypoint_native::{InvokeContext, Logger, ProcessInstruction}, + entrypoint_native::{InvokeContext, Logger, ProcessInstruction, ProcessInstructionWithContext}, instruction::{CompiledInstruction, InstructionError}, message::Message, native_loader, @@ -247,9 +247,6 @@ impl Logger for ThisLogger { } } -pub type ProcessInstructionWithContext = - fn(&Pubkey, &[KeyedAccount], &[u8], &mut dyn InvokeContext) -> Result<(), InstructionError>; - #[derive(Deserialize, Serialize)] pub struct MessageProcessor { #[serde(skip)] @@ -353,6 +350,17 @@ impl MessageProcessor { ) -> Result<(), InstructionError> { if native_loader::check_id(&keyed_accounts[0].owner()?) { let root_id = keyed_accounts[0].unsigned_key(); + for (id, process_instruction) in &self.loaders { + if id == root_id { + // Call the builtin loader + return process_instruction( + &root_id, + &keyed_accounts[1..], + instruction_data, + invoke_context, + ); + } + } for (id, process_instruction) in &self.programs { if id == root_id { // Call the builtin program @@ -367,9 +375,9 @@ impl MessageProcessor { invoke_context, ); } else { - let owner_id = keyed_accounts[0].owner()?; + let owner_id = &keyed_accounts[0].owner()?; for (id, process_instruction) in &self.loaders { - if *id == owner_id { + if id == owner_id { // Call the program via a builtin loader return process_instruction( &owner_id, diff --git a/sdk/src/entrypoint_native.rs b/sdk/src/entrypoint_native.rs index 931c32dc810d2c..fc532c800cdbd0 100644 --- a/sdk/src/entrypoint_native.rs +++ b/sdk/src/entrypoint_native.rs @@ -194,6 +194,8 @@ macro_rules! declare_loader( ); pub type ProcessInstruction = fn(&Pubkey, &[KeyedAccount], &[u8]) -> Result<(), InstructionError>; +pub type ProcessInstructionWithContext = + fn(&Pubkey, &[KeyedAccount], &[u8], &mut dyn InvokeContext) -> Result<(), InstructionError>; /// Invocation context passed to loaders pub trait InvokeContext {