diff --git a/Cargo.toml b/Cargo.toml index dedbd16717..3cb505a336 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,6 @@ members = [ "perf", "validator", "genesis", - "genesis-programs", "gossip", "install", "keygen", diff --git a/core/Cargo.toml b/core/Cargo.toml index 507a065427..b839b4c670 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -45,10 +45,10 @@ serde_derive = "1.0.103" serde_json = "1.0.56" solana-account-decoder = { path = "../account-decoder", version = "1.4.0" } solana-banks-server = { path = "../banks-server", version = "1.4.0" } +solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.4.0" } solana-clap-utils = { path = "../clap-utils", version = "1.4.0" } solana-client = { path = "../client", version = "1.4.0" } solana-faucet = { path = "../faucet", version = "1.4.0" } -solana-genesis-programs = { path = "../genesis-programs", version = "1.4.0" } solana-ledger = { path = "../ledger", version = "1.4.0" } solana-logger = { path = "../logger", version = "1.4.0" } solana-merkle-tree = { path = "../merkle-tree", version = "1.4.0" } diff --git a/core/src/builtins.rs b/core/src/builtins.rs new file mode 100644 index 0000000000..d4926d69fe --- /dev/null +++ b/core/src/builtins.rs @@ -0,0 +1,44 @@ +use solana_runtime::{ + bank::{Builtin, Builtins, Entrypoint}, + feature_set, +}; +use solana_sdk::{genesis_config::ClusterType, pubkey::Pubkey}; + +/// Builtin programs that are always available +fn genesis_builtins(cluster_type: ClusterType) -> Vec { + let builtins = if cluster_type != ClusterType::MainnetBeta { + vec![ + solana_bpf_loader_deprecated_program!(), + solana_bpf_loader_program!(), + ] + } else { + // Remove this `else` block and the `cluster_type` argument to this function once + // `feature_set::bpf_loader2_program::id()` is active on Mainnet Beta + vec![solana_bpf_loader_deprecated_program!()] + }; + + builtins + .into_iter() + .map(|b| Builtin::new(&b.0, b.1, Entrypoint::Loader(b.2))) + .collect() +} + +/// Builtin programs activated dynamically by feature +fn feature_builtins() -> Vec<(Builtin, Pubkey)> { + let builtins = vec![( + solana_bpf_loader_program!(), + feature_set::bpf_loader2_program::id(), + )]; + + builtins + .into_iter() + .map(|(b, p)| (Builtin::new(&b.0, b.1, Entrypoint::Loader(b.2)), p)) + .collect() +} + +pub(crate) fn get(cluster_type: ClusterType) -> Builtins { + Builtins { + genesis_builtins: genesis_builtins(cluster_type), + feature_builtins: feature_builtins(), + } +} diff --git a/core/src/lib.rs b/core/src/lib.rs index 97c39a03fa..ed08e7da94 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -6,11 +6,15 @@ //! command-line tools to spin up validators and a Rust library //! +#[macro_use] +extern crate solana_bpf_loader_program; + pub mod accounts_background_service; pub mod accounts_hash_verifier; pub mod banking_stage; pub mod bigtable_upload_service; pub mod broadcast_stage; +mod builtins; pub mod cache_block_time_service; pub mod cluster_info_vote_listener; pub mod commitment_service; diff --git a/core/src/test_validator.rs b/core/src/test_validator.rs index 0873b3ea8d..37d7f7ac69 100644 --- a/core/src/test_validator.rs +++ b/core/src/test_validator.rs @@ -69,6 +69,7 @@ impl TestValidator { &Pubkey::new_rand(), 42, bootstrap_validator_lamports, + solana_sdk::genesis_config::ClusterType::Development, ); genesis_config.rent.lamports_per_byte_year = 1; genesis_config.rent.exemption_threshold = 1.0; diff --git a/core/src/validator.rs b/core/src/validator.rs index 26d0984c16..44cdfa4a35 100644 --- a/core/src/validator.rs +++ b/core/src/validator.rs @@ -2,6 +2,7 @@ use crate::{ broadcast_stage::BroadcastStageType, + builtins, cache_block_time_service::{CacheBlockTimeSender, CacheBlockTimeService}, cluster_info::{ClusterInfo, Node}, cluster_info_vote_listener::VoteTracker, @@ -791,6 +792,7 @@ fn new_banks_from_ledger( new_hard_forks: config.new_hard_forks.clone(), frozen_accounts: config.frozen_accounts.clone(), debug_keys: config.debug_keys.clone(), + additional_builtins: Some(builtins::get(genesis_config.cluster_type)), ..blockstore_processor::ProcessOptions::default() }; diff --git a/core/tests/bank_forks.rs b/core/tests/bank_forks.rs index ec386c84e4..b31ed8f154 100644 --- a/core/tests/bank_forks.rs +++ b/core/tests/bank_forks.rs @@ -89,6 +89,7 @@ mod tests { vec![accounts_dir.path().to_path_buf()], &[], None, + None, ); bank0.freeze(); let mut bank_forks = BankForks::new(bank0); @@ -143,6 +144,7 @@ mod tests { CompressionType::Bzip2, old_genesis_config, None, + None, ) .unwrap(); diff --git a/genesis-programs/Cargo.toml b/genesis-programs/Cargo.toml deleted file mode 100644 index 8ff726ddcb..0000000000 --- a/genesis-programs/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "solana-genesis-programs" -version = "1.4.0" -description = "Solana genesis programs" -authors = ["Solana Maintainers "] -repository = "https://github.com/solana-labs/solana" -license = "Apache-2.0" -homepage = "https://solana.com/" -edition = "2018" - -[dependencies] -log = { version = "0.4.8" } -solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "1.4.0" } -solana-budget-program = { path = "../programs/budget", version = "1.4.0" } -solana-exchange-program = { path = "../programs/exchange", version = "1.4.0" } -solana-runtime = { path = "../runtime", version = "1.4.0" } -solana-sdk = { path = "../sdk", version = "1.4.0" } -solana-vest-program = { path = "../programs/vest", version = "1.4.0" } - -[lib] -crate-type = ["lib"] -name = "solana_genesis_programs" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] diff --git a/genesis-programs/src/lib.rs b/genesis-programs/src/lib.rs deleted file mode 100644 index c8e3cf7e7b..0000000000 --- a/genesis-programs/src/lib.rs +++ /dev/null @@ -1,190 +0,0 @@ -#[macro_use] -extern crate solana_bpf_loader_program; -#[macro_use] -extern crate solana_budget_program; -#[macro_use] -extern crate solana_exchange_program; -#[macro_use] -extern crate solana_vest_program; - -use solana_runtime::bank::{Bank, EnteredEpochCallback}; -use solana_sdk::{ - clock::{Epoch, GENESIS_EPOCH}, - entrypoint_native::{ErasedProcessInstructionWithContext, ProcessInstructionWithContext}, - genesis_config::ClusterType, - pubkey::Pubkey, -}; - -enum Program { - Native((String, Pubkey)), - BuiltinLoader((String, Pubkey, ProcessInstructionWithContext)), -} - -impl std::fmt::Debug for Program { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - #[derive(Debug)] - enum Program { - Native((String, Pubkey)), - BuiltinLoader((String, Pubkey, String)), - } - let program = match self { - crate::Program::Native((string, pubkey)) => Program::Native((string.clone(), *pubkey)), - crate::Program::BuiltinLoader((string, pubkey, instruction)) => { - let erased: ErasedProcessInstructionWithContext = *instruction; - Program::BuiltinLoader((string.clone(), *pubkey, format!("{:p}", erased))) - } - }; - write!(f, "{:?}", program) - } -} - -// given cluster type, return the entire set of enabled programs -fn get_programs(cluster_type: ClusterType) -> Vec<(Program, Epoch)> { - match cluster_type { - ClusterType::Development => vec![ - // Programs used for testing - Program::BuiltinLoader(solana_bpf_loader_program!()), - Program::BuiltinLoader(solana_bpf_loader_deprecated_program!()), - Program::Native(solana_vest_program!()), - Program::Native(solana_budget_program!()), - Program::Native(solana_exchange_program!()), - ] - .into_iter() - .map(|program| (program, GENESIS_EPOCH)) - .collect::>(), - - ClusterType::Devnet => vec![ - ( - Program::BuiltinLoader(solana_bpf_loader_deprecated_program!()), - GENESIS_EPOCH, - ), - (Program::Native(solana_vest_program!()), GENESIS_EPOCH), - (Program::Native(solana_budget_program!()), GENESIS_EPOCH), - (Program::Native(solana_exchange_program!()), GENESIS_EPOCH), - (Program::BuiltinLoader(solana_bpf_loader_program!()), 400), - ], - - ClusterType::Testnet => vec![ - ( - Program::BuiltinLoader(solana_bpf_loader_deprecated_program!()), - GENESIS_EPOCH, - ), - (Program::BuiltinLoader(solana_bpf_loader_program!()), 89), - ], - - ClusterType::MainnetBeta => vec![ - ( - Program::BuiltinLoader(solana_bpf_loader_deprecated_program!()), - 34, - ), - ( - Program::BuiltinLoader(solana_bpf_loader_program!()), - // The epoch of std::u64::MAX is a placeholder and is expected - // to be reduced in a future cluster update. - Epoch::MAX, - ), - ], - } -} - -pub fn get_native_programs_for_genesis(cluster_type: ClusterType) -> Vec<(String, Pubkey)> { - let mut native_programs = vec![]; - for (program, start_epoch) in get_programs(cluster_type) { - if let Program::Native((string, key)) = program { - if start_epoch == GENESIS_EPOCH { - native_programs.push((string, key)); - } - } - } - native_programs -} - -pub fn get_entered_epoch_callback(cluster_type: ClusterType) -> EnteredEpochCallback { - Box::new(move |bank: &mut Bank, initial: bool| { - // Be careful to add arbitrary logic here; this should be idempotent and can be called - // at arbitrary point in an epoch not only epoch boundaries. - // This is because this closure need to be executed immediately after snapshot restoration, - // in addition to usual epoch boundaries - // In other words, this callback initializes some skip(serde) fields, regardless - // frozen or not - - for (program, start_epoch) in get_programs(cluster_type) { - let should_populate = - initial && bank.epoch() >= start_epoch || !initial && bank.epoch() == start_epoch; - if should_populate { - match program { - Program::Native((name, program_id)) => { - bank.add_native_program(&name, &program_id); - } - Program::BuiltinLoader(( - name, - program_id, - process_instruction_with_context, - )) => { - bank.add_builtin_loader( - &name, - program_id, - process_instruction_with_context, - ); - } - } - } - } - }) -} - -#[cfg(test)] -mod tests { - use super::*; - use std::collections::HashSet; - - fn do_test_uniqueness(programs: Vec<(Program, Epoch)>) { - let mut unique_ids = HashSet::new(); - let mut unique_names = HashSet::new(); - let mut prev_start_epoch = GENESIS_EPOCH; - for (program, next_start_epoch) in programs { - assert!(next_start_epoch >= prev_start_epoch); - match program { - Program::Native((name, id)) => { - assert!(unique_ids.insert(id)); - assert!(unique_names.insert(name)); - } - Program::BuiltinLoader((name, id, _)) => { - assert!(unique_ids.insert(id)); - assert!(unique_names.insert(name)); - } - } - prev_start_epoch = next_start_epoch; - } - } - - #[test] - fn test_uniqueness() { - do_test_uniqueness(get_programs(ClusterType::Development)); - do_test_uniqueness(get_programs(ClusterType::Devnet)); - do_test_uniqueness(get_programs(ClusterType::Testnet)); - do_test_uniqueness(get_programs(ClusterType::MainnetBeta)); - } - - #[test] - fn test_development_programs() { - assert_eq!(get_programs(ClusterType::Development).len(), 5); - } - - #[test] - fn test_native_development_programs() { - assert_eq!( - get_native_programs_for_genesis(ClusterType::Development).len(), - 3 - ); - } - #[test] - fn test_softlaunch_programs() { - assert!(!get_programs(ClusterType::MainnetBeta).is_empty()); - } - - #[test] - fn test_debug() { - assert!(!format!("{:?}", get_programs(ClusterType::Development)).is_empty()); - } -} diff --git a/genesis/Cargo.toml b/genesis/Cargo.toml index 399195c4b8..dbfda8977d 100644 --- a/genesis/Cargo.toml +++ b/genesis/Cargo.toml @@ -15,15 +15,17 @@ chrono = "0.4" serde = "1.0.112" serde_json = "1.0.56" serde_yaml = "0.8.13" +solana-budget-program = { path = "../programs/budget", version = "1.4.0" } solana-clap-utils = { path = "../clap-utils", version = "1.4.0" } -solana-genesis-programs = { path = "../genesis-programs", version = "1.4.0" } +solana-exchange-program = { path = "../programs/exchange", version = "1.4.0" } solana-ledger = { path = "../ledger", version = "1.4.0" } solana-logger = { path = "../logger", version = "1.4.0" } solana-runtime = { path = "../runtime", version = "1.4.0" } solana-sdk = { path = "../sdk", version = "1.4.0" } solana-stake-program = { path = "../programs/stake", version = "1.4.0" } -solana-vote-program = { path = "../programs/vote", version = "1.4.0" } solana-version = { path = "../version", version = "1.4.0" } +solana-vest-program = { path = "../programs/vest", version = "1.4.0" } +solana-vote-program = { path = "../programs/vote", version = "1.4.0" } tempfile = "3.1.0" [[bin]] diff --git a/genesis/src/main.rs b/genesis/src/main.rs index 5f27f42135..6f45809266 100644 --- a/genesis/src/main.rs +++ b/genesis/src/main.rs @@ -1,5 +1,12 @@ //! A command-line executable for generating the chain's genesis config. +#[macro_use] +extern crate solana_budget_program; +#[macro_use] +extern crate solana_exchange_program; +#[macro_use] +extern crate solana_vest_program; + use clap::{crate_description, crate_name, value_t, value_t_or_exit, App, Arg, ArgMatches}; use solana_clap_utils::{ input_parsers::{cluster_type_of, pubkey_of, pubkeys_of, unix_timestamp_from_rfc3339_datetime}, @@ -462,8 +469,15 @@ fn main() -> Result<(), Box> { matches.is_present("enable_warmup_epochs"), ); - let native_instruction_processors = - solana_genesis_programs::get_native_programs_for_genesis(cluster_type); + let native_instruction_processors = if cluster_type == ClusterType::Development { + vec![ + solana_vest_program!(), + solana_budget_program!(), + solana_exchange_program!(), + ] + } else { + vec![] + }; let mut genesis_config = GenesisConfig { native_instruction_processors, @@ -526,7 +540,9 @@ fn main() -> Result<(), Box> { } solana_stake_program::add_genesis_accounts(&mut genesis_config); - solana_runtime::genesis_utils::add_feature_accounts(&mut genesis_config); + if genesis_config.cluster_type == ClusterType::Development { + solana_runtime::genesis_utils::activate_all_features(&mut genesis_config); + } if let Some(files) = matches.values_of("primordial_accounts_file") { for file in files { diff --git a/ledger/Cargo.toml b/ledger/Cargo.toml index 2e6c7da52a..0fbc9d967f 100644 --- a/ledger/Cargo.toml +++ b/ledger/Cargo.toml @@ -32,7 +32,6 @@ serde = "1.0.112" serde_bytes = "0.11.4" sha2 = "0.8.2" solana-transaction-status = { path = "../transaction-status", version = "1.4.0" } -solana-genesis-programs = { path = "../genesis-programs", version = "1.4.0" } solana-logger = { path = "../logger", version = "1.4.0" } solana-measure = { path = "../measure", version = "1.4.0" } solana-merkle-tree = { path = "../merkle-tree", version = "1.4.0" } diff --git a/ledger/src/bank_forks_utils.rs b/ledger/src/bank_forks_utils.rs index 3447475e3c..d9b58d6b19 100644 --- a/ledger/src/bank_forks_utils.rs +++ b/ledger/src/bank_forks_utils.rs @@ -13,7 +13,7 @@ use solana_runtime::{ snapshot_utils, }; use solana_sdk::{clock::Slot, genesis_config::GenesisConfig, hash::Hash}; -use std::{fs, path::PathBuf, process, result, sync::Arc}; +use std::{fs, path::PathBuf, process, result}; pub type LoadResult = result::Result< (BankForks, LeaderScheduleCache, Option<(Slot, Hash)>), @@ -66,6 +66,7 @@ pub fn load( compression, genesis_config, process_options.debug_keys.clone(), + process_options.additional_builtins.as_ref(), ) .expect("Load from snapshot failed"); @@ -84,9 +85,8 @@ pub fn load( return to_loadresult( blockstore_processor::process_blockstore_from_root( - genesis_config, blockstore, - Arc::new(deserialized_bank), + deserialized_bank, &process_options, &VerifyRecyclers::default(), transaction_status_sender, diff --git a/ledger/src/blockstore_processor.rs b/ledger/src/blockstore_processor.rs index c46fd97386..fc8739e96d 100644 --- a/ledger/src/blockstore_processor.rs +++ b/ledger/src/blockstore_processor.rs @@ -16,7 +16,7 @@ use solana_metrics::{datapoint_error, inc_new_counter_debug}; use solana_rayon_threadlimit::get_thread_count; use solana_runtime::{ bank::{ - Bank, InnerInstructionsList, TransactionBalancesSet, TransactionProcessResult, + Bank, Builtins, InnerInstructionsList, TransactionBalancesSet, TransactionProcessResult, TransactionResults, }, bank_forks::BankForks, @@ -318,14 +318,7 @@ pub struct ProcessOptions { pub new_hard_forks: Option>, pub frozen_accounts: Vec, pub debug_keys: Option>>, -} - -fn initiate_callback(mut bank: &mut Arc, genesis_config: &GenesisConfig) { - Arc::get_mut(&mut bank) - .unwrap() - .initiate_entered_epoch_callback(solana_genesis_programs::get_entered_epoch_callback( - genesis_config.cluster_type, - )); + pub additional_builtins: Option, } pub fn process_blockstore( @@ -344,55 +337,43 @@ pub fn process_blockstore( } // Setup bank for slot 0 - let mut bank0 = Arc::new(Bank::new_with_paths( + let bank0 = Bank::new_with_paths( &genesis_config, account_paths, &opts.frozen_accounts, opts.debug_keys.clone(), - )); - initiate_callback(&mut bank0, genesis_config); + opts.additional_builtins.as_ref(), + ); + let bank0 = Arc::new(bank0); info!("processing ledger for slot 0..."); let recyclers = VerifyRecyclers::default(); process_bank_0(&bank0, blockstore, &opts, &recyclers)?; - do_process_blockstore_from_root( - genesis_config, - blockstore, - bank0, - &opts, - &recyclers, - None, - false, - ) + do_process_blockstore_from_root(blockstore, bank0, &opts, &recyclers, None) } // Process blockstore from a known root bank -pub fn process_blockstore_from_root( - genesis_config: &GenesisConfig, +pub(crate) fn process_blockstore_from_root( blockstore: &Blockstore, - bank: Arc, + bank: Bank, opts: &ProcessOptions, recyclers: &VerifyRecyclers, transaction_status_sender: Option, ) -> BlockstoreProcessorResult { do_process_blockstore_from_root( - genesis_config, blockstore, - bank, + Arc::new(bank), opts, recyclers, transaction_status_sender, - true, ) } fn do_process_blockstore_from_root( - genesis_config: &GenesisConfig, blockstore: &Blockstore, - mut bank: Arc, + bank: Arc, opts: &ProcessOptions, recyclers: &VerifyRecyclers, transaction_status_sender: Option, - enable_callback: bool, ) -> BlockstoreProcessorResult { info!("processing ledger from slot {}...", bank.slot()); let allocated = thread_mem_usage::Allocatedp::default(); @@ -404,10 +385,6 @@ fn do_process_blockstore_from_root( let now = Instant::now(); let mut root = start_slot; - if enable_callback { - initiate_callback(&mut bank, genesis_config); - } - if let Some(ref new_hard_forks) = opts.new_hard_forks { let hard_forks = bank.hard_forks(); @@ -2662,8 +2639,7 @@ pub mod tests { blockstore.set_roots(&[3, 5]).unwrap(); // Set up bank1 - let mut bank0 = Arc::new(Bank::new(&genesis_config)); - initiate_callback(&mut bank0, &genesis_config); + let bank0 = Arc::new(Bank::new(&genesis_config)); let opts = ProcessOptions { poh_verify: true, ..ProcessOptions::default() @@ -2684,16 +2660,8 @@ pub mod tests { bank1.squash(); // Test process_blockstore_from_root() from slot 1 onwards - let (bank_forks, _leader_schedule) = do_process_blockstore_from_root( - &genesis_config, - &blockstore, - bank1, - &opts, - &recyclers, - None, - false, - ) - .unwrap(); + let (bank_forks, _leader_schedule) = + do_process_blockstore_from_root(&blockstore, bank1, &opts, &recyclers, None).unwrap(); assert_eq!(frozen_bank_slots(&bank_forks), vec![5, 6]); assert_eq!(bank_forks.working_bank().slot(), 6); @@ -2857,7 +2825,7 @@ pub mod tests { genesis_config: &GenesisConfig, account_paths: Vec, ) -> EpochSchedule { - let bank = Bank::new_with_paths(&genesis_config, account_paths, &[], None); + let bank = Bank::new_with_paths(&genesis_config, account_paths, &[], None, None); *bank.epoch_schedule() } @@ -3211,95 +3179,4 @@ pub mod tests { 8 ); } - - #[test] - fn test_process_blockstore_feature_activations_since_genesis() { - let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(123); - - let (ledger_path, _blockhash) = create_new_tmp_ledger!(&genesis_config); - let blockstore = Blockstore::open(&ledger_path).unwrap(); - - let opts = ProcessOptions::default(); - let (bank_forks, _leader_schedule) = - process_blockstore(&genesis_config, &blockstore, vec![], opts).unwrap(); - - assert_eq!(bank_forks.working_bank().slot(), 0); - assert_eq!( - bank_forks.working_bank().builtin_loader_ids(), - vec![ - solana_sdk::bpf_loader::id(), - solana_sdk::bpf_loader_deprecated::id() - ] - ); - } - - #[test] - fn test_process_blockstore_feature_activations_from_snapshot() { - let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(123); - - let (ledger_path, _blockhash) = create_new_tmp_ledger!(&genesis_config); - let blockstore = Blockstore::open(&ledger_path).unwrap(); - - // Set up bank1 - let mut bank0 = Arc::new(Bank::new(&genesis_config)); - initiate_callback(&mut bank0, &genesis_config); - let recyclers = VerifyRecyclers::default(); - let opts = ProcessOptions::default(); - process_bank_0(&bank0, &blockstore, &opts, &recyclers).unwrap(); - let restored_slot = genesis_config.epoch_schedule.get_first_slot_in_epoch(1); - let mut bank1 = Bank::new_from_parent(&bank0, &Pubkey::default(), restored_slot); - bank1.squash(); - - // this is similar to snapshot deserialization - bank1.reset_callback_and_message_processor(); - assert_eq!(bank1.builtin_loader_ids(), vec![]); - - let bank1 = Arc::new(bank1); - let (bank_forks, _leader_schedule) = process_blockstore_from_root( - &genesis_config, - &blockstore, - bank1, - &opts, - &recyclers, - None, - ) - .unwrap(); - assert_eq!(bank_forks.working_bank().slot(), restored_slot); - assert_eq!( - bank_forks.working_bank().builtin_loader_ids(), - vec![ - solana_sdk::bpf_loader::id(), - solana_sdk::bpf_loader_deprecated::id() - ] - ); - } - - #[test] - fn test_process_blockstore_feature_activations_into_epoch_with_activation() { - let GenesisConfigInfo { - mut genesis_config, .. - } = create_genesis_config(123); - - genesis_config.cluster_type = solana_sdk::genesis_config::ClusterType::MainnetBeta; - let (ledger_path, _blockhash) = create_new_tmp_ledger!(&genesis_config); - let blockstore = Blockstore::open(&ledger_path).unwrap(); - - let opts = ProcessOptions::default(); - let (bank_forks, _leader_schedule) = - process_blockstore(&genesis_config, &blockstore, vec![], opts).unwrap(); - let bank0 = bank_forks.working_bank(); - assert_eq!(bank0.builtin_loader_ids(), vec![]); - - let restored_slot = genesis_config.epoch_schedule.get_first_slot_in_epoch(34); - let bank1 = Bank::new_from_parent(&bank0, &Pubkey::default(), restored_slot); - - assert_eq!(bank0.slot(), 0); - assert_eq!(bank0.builtin_loader_ids(), vec![]); - - assert_eq!(bank1.slot(), restored_slot); - assert_eq!( - bank1.builtin_loader_ids(), - vec![solana_sdk::bpf_loader_deprecated::id()] - ); - } } diff --git a/local-cluster/Cargo.toml b/local-cluster/Cargo.toml index 48b75864da..a5c3a388bf 100644 --- a/local-cluster/Cargo.toml +++ b/local-cluster/Cargo.toml @@ -19,7 +19,6 @@ solana-client = { path = "../client", version = "1.4.0" } solana-download-utils = { path = "../download-utils", version = "1.4.0" } solana-faucet = { path = "../faucet", version = "1.4.0" } solana-exchange-program = { path = "../programs/exchange", version = "1.4.0" } -solana-genesis-programs = { path = "../genesis-programs", version = "1.4.0" } solana-ledger = { path = "../ledger", version = "1.4.0" } solana-logger = { path = "../logger", version = "1.4.0" } solana-runtime = { path = "../runtime", version = "1.4.0" } diff --git a/local-cluster/src/local_cluster.rs b/local-cluster/src/local_cluster.rs index 101f8f89e7..53dd74b921 100644 --- a/local-cluster/src/local_cluster.rs +++ b/local-cluster/src/local_cluster.rs @@ -13,7 +13,8 @@ use solana_core::{ }; use solana_ledger::create_new_tmp_ledger; use solana_runtime::genesis_utils::{ - create_genesis_config_with_vote_accounts, GenesisConfigInfo, ValidatorVoteKeypairs, + create_genesis_config_with_vote_accounts_and_cluster_type, GenesisConfigInfo, + ValidatorVoteKeypairs, }; use solana_sdk::{ client::SyncClient, @@ -155,10 +156,11 @@ impl LocalCluster { mut genesis_config, mint_keypair, .. - } = create_genesis_config_with_vote_accounts( + } = create_genesis_config_with_vote_accounts_and_cluster_type( config.cluster_lamports, &keys_in_genesis, stakes_in_genesis, + config.cluster_type, ); genesis_config.ticks_per_slot = config.ticks_per_slot; genesis_config.epoch_schedule = EpochSchedule::custom( @@ -166,19 +168,7 @@ impl LocalCluster { config.stakers_slot_offset, !config.skip_warmup_slots, ); - genesis_config.cluster_type = config.cluster_type; genesis_config.poh_config = config.poh_config.clone(); - - match genesis_config.cluster_type { - ClusterType::MainnetBeta | ClusterType::Testnet => { - genesis_config.native_instruction_processors = - solana_genesis_programs::get_native_programs_for_genesis( - genesis_config.cluster_type, - ) - } - _ => (), - } - genesis_config .native_instruction_processors .extend_from_slice(&config.native_instruction_processors); diff --git a/local-cluster/tests/local_cluster.rs b/local-cluster/tests/local_cluster.rs index b7a944aa8c..2579014b48 100644 --- a/local-cluster/tests/local_cluster.rs +++ b/local-cluster/tests/local_cluster.rs @@ -759,6 +759,7 @@ fn test_mainnet_beta_cluster_type() { &solana_sdk::system_program::id(), &solana_stake_program::id(), &solana_vote_program::id(), + &solana_sdk::bpf_loader_deprecated::id(), ] .iter() { @@ -774,13 +775,7 @@ fn test_mainnet_beta_cluster_type() { } // Programs that are not available at epoch 0 - for program_id in [ - &solana_sdk::bpf_loader::id(), - &solana_sdk::bpf_loader_deprecated::id(), - &solana_vest_program::id(), - ] - .iter() - { + for program_id in [&solana_sdk::bpf_loader::id(), &solana_vest_program::id()].iter() { assert_eq!( ( program_id, diff --git a/runtime/benches/accounts.rs b/runtime/benches/accounts.rs index 766467a806..b14c4ea093 100644 --- a/runtime/benches/accounts.rs +++ b/runtime/benches/accounts.rs @@ -36,7 +36,13 @@ fn bench_has_duplicates(bencher: &mut Bencher) { #[bench] fn test_accounts_create(bencher: &mut Bencher) { let (genesis_config, _) = create_genesis_config(10_000); - let bank0 = Bank::new_with_paths(&genesis_config, vec![PathBuf::from("bench_a0")], &[], None); + let bank0 = Bank::new_with_paths( + &genesis_config, + vec![PathBuf::from("bench_a0")], + &[], + None, + None, + ); bencher.iter(|| { let mut pubkeys: Vec = vec![]; deposit_many(&bank0, &mut pubkeys, 1000); @@ -51,6 +57,7 @@ fn test_accounts_squash(bencher: &mut Bencher) { vec![PathBuf::from("bench_a1")], &[], None, + None, )); let mut pubkeys: Vec = vec![]; deposit_many(&bank1, &mut pubkeys, 250_000); diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index c237ce723e..bf27258b3b 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -10,7 +10,7 @@ use crate::{ accounts_db::{ErrorCounters, SnapshotStorages}, accounts_index::Ancestors, blockhash_queue::BlockhashQueue, - builtins::*, + builtins, epoch_stakes::{EpochStakes, NodeVoteAccounts}, feature::Feature, feature_set::{self, FeatureSet}, @@ -137,6 +137,7 @@ pub enum Entrypoint { Program(ProcessInstruction), Loader(ProcessInstructionWithContext), } +#[derive(Clone)] pub struct Builtin { pub name: String, pub id: Pubkey, @@ -186,6 +187,15 @@ impl CowCachedExecutors { } } +#[derive(Clone)] +pub struct Builtins { + /// Builtin programs that are always available + pub genesis_builtins: Vec, + + /// Builtin programs activated dynamically by feature + pub feature_builtins: Vec<(Builtin, Pubkey)>, +} + const MAX_CACHED_EXECUTORS: usize = 100; // 10 MB assuming programs are around 100k /// LFU Cache of executors @@ -327,9 +337,6 @@ impl StatusCacheRc { } } -pub type EnteredEpochCallback = Box; -type WrappedEnteredEpochCallback = Arc>>; - pub type TransactionProcessResult = (Result<()>, Option); pub struct TransactionResults { pub fee_collection_results: Vec>, @@ -559,9 +566,8 @@ pub struct Bank { /// The Message processor message_processor: MessageProcessor, - /// Callback to be notified when a bank enters a new Epoch - /// (used to adjust cluster features over time) - entered_epoch_callback: WrappedEnteredEpochCallback, + /// Builtin programs activated dynamically by feature + feature_builtins: Arc>, /// Last time when the cluster info vote listener has synced with this bank pub last_vote_sync: AtomicU64, @@ -594,7 +600,7 @@ impl Default for BlockhashQueue { impl Bank { pub fn new(genesis_config: &GenesisConfig) -> Self { - Self::new_with_paths(&genesis_config, Vec::new(), &[], None) + Self::new_with_paths(&genesis_config, Vec::new(), &[], None, None) } pub fn new_with_paths( @@ -602,6 +608,7 @@ impl Bank { paths: Vec, frozen_account_pubkeys: &[Pubkey], debug_keys: Option>>, + additional_builtins: Option<&Builtins>, ) -> Self { let mut bank = Self::default(); bank.transaction_debug_keys = debug_keys; @@ -610,7 +617,7 @@ impl Bank { bank.rc.accounts = Arc::new(Accounts::new(paths, &genesis_config.cluster_type)); bank.process_genesis_config(genesis_config); - bank.finish_init(genesis_config); + bank.finish_init(genesis_config, additional_builtins); // Freeze accounts after process_genesis_config creates the initial append vecs Arc::get_mut(&mut Arc::get_mut(&mut bank.rc.accounts).unwrap().accounts_db) @@ -697,7 +704,7 @@ impl Bank { tick_height: AtomicU64::new(parent.tick_height.load(Relaxed)), signature_count: AtomicU64::new(0), message_processor: parent.message_processor.clone(), - entered_epoch_callback: parent.entered_epoch_callback.clone(), + feature_builtins: parent.feature_builtins.clone(), hard_forks: parent.hard_forks.clone(), last_vote_sync: AtomicU64::new(parent.last_vote_sync.load(Relaxed)), rewards: None, @@ -725,7 +732,7 @@ impl Bank { // Following code may touch AccountsDB, requiring proper ancestors if parent.epoch() < new.epoch() { - new.apply_feature_activations(false, false); + new.apply_feature_activations(false); } new.update_slot_hashes(); @@ -747,7 +754,7 @@ impl Bank { /// * Freezes the new bank, assuming that the user will `Bank::new_from_parent` from this bank pub fn warp_from_parent(parent: &Arc, collector_id: &Pubkey, slot: Slot) -> Self { let mut new = Bank::new_from_parent(parent, collector_id, slot); - new.apply_feature_activations(true, true); + new.apply_feature_activations(true); new.update_epoch_stakes(new.epoch_schedule().get_epoch(slot)); new.tick_height.store(new.max_tick_height(), Relaxed); new.freeze(); @@ -761,6 +768,7 @@ impl Bank { genesis_config: &GenesisConfig, fields: BankFieldsToDeserialize, debug_keys: Option>>, + additional_builtins: Option<&Builtins>, ) -> Self { fn new() -> T { T::default() @@ -803,7 +811,7 @@ impl Bank { epoch_stakes: fields.epoch_stakes, is_delta: AtomicBool::new(fields.is_delta), message_processor: new(), - entered_epoch_callback: new(), + feature_builtins: new(), last_vote_sync: new(), rewards: new(), skip_drop: new(), @@ -816,7 +824,7 @@ impl Bank { transaction_debug_keys: debug_keys, feature_set: new(), }; - bank.finish_init(genesis_config); + bank.finish_init(genesis_config, additional_builtins); // Sanity assertions between bank snapshot and genesis config // Consider removing from serializable bank state @@ -2967,19 +2975,29 @@ impl Bank { self.rc.accounts.clone() } - pub fn set_bank_rc(&mut self, bank_rc: BankRc, status_cache_rc: StatusCacheRc) { - self.rc = bank_rc; - self.src = status_cache_rc; - } - - pub fn finish_init(&mut self, genesis_config: &GenesisConfig) { + fn finish_init( + &mut self, + genesis_config: &GenesisConfig, + additional_builtins: Option<&Builtins>, + ) { self.rewards_pool_pubkeys = Arc::new(genesis_config.rewards_pools.keys().cloned().collect()); - self.apply_feature_activations(true, false); - } - pub fn set_parent(&mut self, parent: &Arc) { - self.rc.parent = RwLock::new(Some(parent.clone())); + let mut builtins = builtins::get(); + if let Some(additional_builtins) = additional_builtins { + builtins + .genesis_builtins + .extend_from_slice(&additional_builtins.genesis_builtins); + builtins + .feature_builtins + .extend_from_slice(&additional_builtins.feature_builtins); + } + for builtin in builtins.genesis_builtins { + self.add_builtin(&builtin.name, builtin.id, builtin.entrypoint); + } + self.feature_builtins = Arc::new(builtins.feature_builtins); + + self.apply_feature_activations(true); } pub fn set_inflation(&self, inflation: Inflation) { @@ -2990,19 +3008,6 @@ impl Bank { self.hard_forks.clone() } - pub fn initiate_entered_epoch_callback( - &mut self, - entered_epoch_callback: EnteredEpochCallback, - ) { - { - let mut callback_w = self.entered_epoch_callback.write().unwrap(); - assert!(callback_w.is_none(), "Already callback has been initiated"); - *callback_w = Some(entered_epoch_callback); - } - // immediately fire the callback as initial invocation - self.reinvoke_entered_epoch_callback(true); - } - pub fn get_account(&self, pubkey: &Pubkey) -> Option { self.get_account_modified_slot(pubkey) .map(|(acc, _slot)| acc) @@ -3558,7 +3563,7 @@ impl Bank { // This is called from snapshot restore AND for each epoch boundary // The entire code path herein must be idempotent - fn apply_feature_activations(&mut self, init_finish_or_warp: bool, initiate_callback: bool) { + fn apply_feature_activations(&mut self, init_finish_or_warp: bool) { let new_feature_activations = self.compute_active_feature_set(!init_finish_or_warp); if new_feature_activations.contains(&feature_set::pico_inflation::id()) { @@ -3571,8 +3576,7 @@ impl Bank { self.apply_spl_token_v2_multisig_fix(); } - self.ensure_builtins(init_finish_or_warp, &new_feature_activations); - self.reinvoke_entered_epoch_callback(initiate_callback); + self.ensure_feature_builtins(init_finish_or_warp, &new_feature_activations); self.recheck_cross_program_support(); self.recheck_compute_budget(); self.reconfigure_token2_native_mint(); @@ -3623,32 +3627,21 @@ impl Bank { newly_activated } - fn ensure_builtins(&mut self, init_or_warp: bool, new_feature_activations: &HashSet) { - for (program, start_epoch) in get_cluster_builtins(self.cluster_type()) { - let should_populate = init_or_warp && self.epoch() >= start_epoch - || !init_or_warp && self.epoch() == start_epoch; - if should_populate { - self.add_builtin(&program.name, program.id, program.entrypoint); - } - } - - for (program, feature) in get_feature_builtins() { + fn ensure_feature_builtins( + &mut self, + init_or_warp: bool, + new_feature_activations: &HashSet, + ) { + let feature_builtins = self.feature_builtins.clone(); + for (builtin, feature) in feature_builtins.iter() { let should_populate = init_or_warp && self.feature_set.is_active(&feature) || !init_or_warp && new_feature_activations.contains(&feature); if should_populate { - self.add_builtin(&program.name, program.id, program.entrypoint); + self.add_builtin(&builtin.name, builtin.id, builtin.entrypoint); } } } - fn reinvoke_entered_epoch_callback(&mut self, initiate: bool) { - if let Some(entered_epoch_callback) = - self.entered_epoch_callback.clone().read().unwrap().as_ref() - { - entered_epoch_callback(self, initiate) - } - } - fn recheck_cross_program_support(&mut self) { if ClusterType::MainnetBeta == self.cluster_type() { self.set_cross_program_support(self.epoch() >= 63); @@ -3769,22 +3762,6 @@ impl Bank { .is_active(&feature_set::consistent_recent_blockhashes_sysvar::id()), } } - - // only used for testing - pub fn builtin_loader_ids(&self) -> Vec { - self.message_processor.builtin_loader_ids() - } - - // only used for testing - pub fn builtin_program_ids(&self) -> Vec { - self.message_processor.builtin_program_ids() - } - - // only used for testing - pub fn reset_callback_and_message_processor(&mut self) { - self.entered_epoch_callback = WrappedEnteredEpochCallback::default(); - self.message_processor = MessageProcessor::default(); - } } impl Drop for Bank { @@ -3845,7 +3822,7 @@ mod tests { vote_instruction, vote_state::{self, Vote, VoteInit, VoteState, MAX_LOCKOUT_HISTORY}, }; - use std::{result, sync::atomic::Ordering::SeqCst, time::Duration}; + use std::{result, time::Duration}; #[test] fn test_hash_age_kind_is_durable_nonce() { @@ -6943,45 +6920,6 @@ mod tests { ); } - #[test] - fn test_bank_entered_epoch_callback() { - let (genesis_config, _) = create_genesis_config(500); - let mut bank0 = Arc::new(Bank::new(&genesis_config)); - let callback_count = Arc::new(AtomicU64::new(0)); - - Arc::get_mut(&mut bank0) - .unwrap() - .initiate_entered_epoch_callback({ - let callback_count = callback_count.clone(); - Box::new(move |_, _| { - callback_count.fetch_add(1, SeqCst); - }) - }); - - // set_entered_eepoc_callbak fires the initial call - assert_eq!(callback_count.load(SeqCst), 1); - - let _bank1 = - Bank::new_from_parent(&bank0, &Pubkey::default(), bank0.get_slots_in_epoch(0) - 1); - // No callback called while within epoch 0 - assert_eq!(callback_count.load(SeqCst), 1); - - let _bank1 = Bank::new_from_parent(&bank0, &Pubkey::default(), bank0.get_slots_in_epoch(0)); - // Callback called as bank1 is in epoch 1 - assert_eq!(callback_count.load(SeqCst), 2); - - callback_count.store(0, SeqCst); - let _bank1 = Bank::new_from_parent( - &bank0, - &Pubkey::default(), - std::u64::MAX / bank0.ticks_per_slot - 1, - ); - // If the new bank jumps ahead multiple epochs the callback is still only called once. - // This was done to keep the callback implementation simpler as new bank will never jump - // cross multiple epochs in a real deployment. - assert_eq!(callback_count.load(SeqCst), 1); - } - #[test] fn test_is_delta_true() { let (genesis_config, mint_keypair) = create_genesis_config(500); @@ -8406,7 +8344,6 @@ mod tests { }) .collect() } else { - use std::collections::HashSet; let mut inserted = HashSet::new(); (0..num_keys) .map(|_| { @@ -8740,7 +8677,7 @@ mod tests { bank.message_processor.set_cross_program_support(false); // simulate bank is just after deserialized from snapshot - bank.finish_init(&genesis_config); + bank.finish_init(&genesis_config, None); assert_eq!(bank.message_processor.get_cross_program_support(), true); } diff --git a/runtime/src/builtins.rs b/runtime/src/builtins.rs index b7ac385d46..beb8294480 100644 --- a/runtime/src/builtins.rs +++ b/runtime/src/builtins.rs @@ -1,76 +1,37 @@ use crate::{ - bank::{Builtin, Entrypoint}, + bank::{Builtin, Builtins, Entrypoint}, feature_set, system_instruction_processor, }; -use solana_sdk::{ - clock::{Epoch, GENESIS_EPOCH}, - genesis_config::ClusterType, - pubkey::Pubkey, - system_program, -}; +use solana_sdk::{pubkey::Pubkey, system_program}; -use log::*; - -/// Builtin programs that should be active for the given cluster_type -/// -/// Old style. Use `get_feature_builtins()` instead -pub fn get_cluster_builtins(cluster_type: ClusterType) -> Vec<(Builtin, Epoch)> { - trace!("get_cluster_builtins: {:?}", cluster_type); - let mut builtins = vec![]; - - builtins.extend( - vec![ - Builtin::new( - "system_program", - system_program::id(), - Entrypoint::Program(system_instruction_processor::process_instruction), - ), - Builtin::new( - "config_program", - solana_config_program::id(), - Entrypoint::Program(solana_config_program::config_processor::process_instruction), - ), - Builtin::new( - "stake_program", - solana_stake_program::id(), - Entrypoint::Program(solana_stake_program::stake_instruction::process_instruction), - ), - Builtin::new( - "vote_program", - solana_vote_program::id(), - Entrypoint::Program(solana_vote_program::vote_instruction::process_instruction), - ), - ] - .into_iter() - .map(|program| (program, GENESIS_EPOCH)) - .collect::>(), - ); - - // repurpose Testnet for test_get_builtins because the Development is overloaded... - #[cfg(test)] - if cluster_type == ClusterType::Testnet { - use solana_sdk::account::KeyedAccount; - use solana_sdk::instruction::InstructionError; - use std::str::FromStr; - fn mock_ix_processor( - _pubkey: &Pubkey, - _ka: &[KeyedAccount], - _data: &[u8], - ) -> std::result::Result<(), InstructionError> { - Err(InstructionError::Custom(42)) - } - let program_id = Pubkey::from_str("7saCc6X5a2syoYANA5oUUnPZLcLMfKoSjiDhFU5fbpoK").unwrap(); - builtins.push(( - Builtin::new("mock", program_id, Entrypoint::Program(mock_ix_processor)), - 2, - )); - } - - builtins +/// Builtin programs that are always available +fn genesis_builtins() -> Vec { + vec![ + Builtin::new( + "system_program", + system_program::id(), + Entrypoint::Program(system_instruction_processor::process_instruction), + ), + Builtin::new( + "vote_program", + solana_vote_program::id(), + Entrypoint::Program(solana_vote_program::vote_instruction::process_instruction), + ), + Builtin::new( + "stake_program", + solana_stake_program::id(), + Entrypoint::Program(solana_stake_program::stake_instruction::process_instruction), + ), + Builtin::new( + "config_program", + solana_config_program::id(), + Entrypoint::Program(solana_config_program::config_processor::process_instruction), + ), + ] } -/// Builtin programs that are activated dynamically by feature -pub fn get_feature_builtins() -> Vec<(Builtin, Pubkey)> { +/// Builtin programs activated dynamically by feature +fn feature_builtins() -> Vec<(Builtin, Pubkey)> { vec![( Builtin::new( "secp256k1_program", @@ -81,108 +42,9 @@ pub fn get_feature_builtins() -> Vec<(Builtin, Pubkey)> { )] } -#[cfg(test)] -mod tests { - use super::*; - use crate::bank::Bank; - use solana_sdk::genesis_config::create_genesis_config; - use std::{collections::HashSet, str::FromStr, sync::Arc}; - - fn do_test_uniqueness(builtins: Vec<(Builtin, Epoch)>) { - let mut unique_ids = HashSet::new(); - let mut unique_names = HashSet::new(); - let mut prev_start_epoch = 0; - for (builtin, next_start_epoch) in builtins { - assert!(next_start_epoch >= prev_start_epoch); - assert!(unique_ids.insert(builtin.name)); - assert!(unique_names.insert(builtin.id)); - prev_start_epoch = next_start_epoch; - } - } - - #[test] - fn test_uniqueness() { - do_test_uniqueness(get_cluster_builtins(ClusterType::Development)); - do_test_uniqueness(get_cluster_builtins(ClusterType::Devnet)); - do_test_uniqueness(get_cluster_builtins(ClusterType::Testnet)); - do_test_uniqueness(get_cluster_builtins(ClusterType::MainnetBeta)); - } - - #[test] - fn test_get_builtins() { - let mock_program_id = - Pubkey::from_str("7saCc6X5a2syoYANA5oUUnPZLcLMfKoSjiDhFU5fbpoK").unwrap(); - - let (mut genesis_config, _mint_keypair) = create_genesis_config(100_000); - genesis_config.cluster_type = ClusterType::Testnet; - let bank0 = Arc::new(Bank::new(&genesis_config)); - - let restored_slot1 = genesis_config.epoch_schedule.get_first_slot_in_epoch(2); - let bank1 = Arc::new(Bank::new_from_parent( - &bank0, - &Pubkey::default(), - restored_slot1, - )); - - let restored_slot2 = genesis_config.epoch_schedule.get_first_slot_in_epoch(3); - let bank2 = Arc::new(Bank::new_from_parent( - &bank1, - &Pubkey::default(), - restored_slot2, - )); - - let warped_slot = genesis_config.epoch_schedule.get_first_slot_in_epoch(999); - let warped_bank = Arc::new(Bank::warp_from_parent( - &bank0, - &Pubkey::default(), - warped_slot, - )); - - assert_eq!(bank0.slot(), 0); - assert_eq!( - bank0.builtin_program_ids(), - vec![ - system_program::id(), - solana_config_program::id(), - solana_stake_program::id(), - solana_vote_program::id(), - ] - ); - - assert_eq!(bank1.slot(), restored_slot1); - assert_eq!( - bank1.builtin_program_ids(), - vec![ - system_program::id(), - solana_config_program::id(), - solana_stake_program::id(), - solana_vote_program::id(), - mock_program_id, - ] - ); - - assert_eq!(bank2.slot(), restored_slot2); - assert_eq!( - bank2.builtin_program_ids(), - vec![ - system_program::id(), - solana_config_program::id(), - solana_stake_program::id(), - solana_vote_program::id(), - mock_program_id, - ] - ); - - assert_eq!(warped_bank.slot(), warped_slot); - assert_eq!( - warped_bank.builtin_program_ids(), - vec![ - system_program::id(), - solana_config_program::id(), - solana_stake_program::id(), - solana_vote_program::id(), - mock_program_id, - ] - ); +pub(crate) fn get() -> Builtins { + Builtins { + genesis_builtins: genesis_builtins(), + feature_builtins: feature_builtins(), } } diff --git a/runtime/src/feature_set.rs b/runtime/src/feature_set.rs index c7e7d9be8e..c4e6d840c3 100644 --- a/runtime/src/feature_set.rs +++ b/runtime/src/feature_set.rs @@ -25,6 +25,10 @@ pub mod spl_token_v2_multisig_fix { solana_sdk::declare_id!("E5JiFDQCwyC6QfT9REFyMpfK2mHcmv1GUDySU1Ue7TYv"); } +pub mod bpf_loader2_program { + solana_sdk::declare_id!("DFBnrgThdzH4W6wZ12uGPoWcMnvfZj11EHnxHcVxLPhD"); +} + lazy_static! { /// Map of feature identifiers to user-visible description pub static ref FEATURE_NAMES: HashMap = [ @@ -33,6 +37,7 @@ lazy_static! { (consistent_recent_blockhashes_sysvar::id(), "consistent recentblockhashes sysvar"), (pico_inflation::id(), "pico-inflation"), (spl_token_v2_multisig_fix::id(), "spl-token multisig fix"), + (bpf_loader2_program::id(), "bpf_loader2 program"), /*************** ADD NEW FEATURES HERE ***************/ ] .iter() diff --git a/runtime/src/genesis_utils.rs b/runtime/src/genesis_utils.rs index 4b52a08b8e..2e26413ccd 100644 --- a/runtime/src/genesis_utils.rs +++ b/runtime/src/genesis_utils.rs @@ -53,6 +53,20 @@ pub fn create_genesis_config_with_vote_accounts( mint_lamports: u64, voting_keypairs: &[impl Borrow], stakes: Vec, +) -> GenesisConfigInfo { + create_genesis_config_with_vote_accounts_and_cluster_type( + mint_lamports, + voting_keypairs, + stakes, + ClusterType::Development, + ) +} + +pub fn create_genesis_config_with_vote_accounts_and_cluster_type( + mint_lamports: u64, + voting_keypairs: &[impl Borrow], + stakes: Vec, + cluster_type: ClusterType, ) -> GenesisConfigInfo { assert!(!voting_keypairs.is_empty()); assert_eq!(voting_keypairs.len(), stakes.len()); @@ -64,6 +78,7 @@ pub fn create_genesis_config_with_vote_accounts( &voting_keypairs[0].borrow().stake_keypair.pubkey(), stakes[0], BOOTSTRAP_VALIDATOR_LAMPORTS, + cluster_type, ); for (validator_voting_keypairs, stake) in voting_keypairs[1..].iter().zip(&stakes[1..]) { @@ -105,24 +120,23 @@ pub fn create_genesis_config_with_leader( &Pubkey::new_rand(), bootstrap_validator_stake_lamports, BOOTSTRAP_VALIDATOR_LAMPORTS, + ClusterType::Development, ) } -pub fn add_feature_accounts(genesis_config: &mut GenesisConfig) { - if genesis_config.cluster_type == ClusterType::Development { - // Activate all features at genesis in development mode - for feature_id in FeatureSet::default().inactive { - let feature = Feature { - activated_at: Some(0), - }; - genesis_config.accounts.insert( - feature_id, - feature.create_account(std::cmp::max( - genesis_config.rent.minimum_balance(Feature::size_of()), - 1, - )), - ); - } +pub fn activate_all_features(genesis_config: &mut GenesisConfig) { + // Activate all features at genesis in development mode + for feature_id in FeatureSet::default().inactive { + let feature = Feature { + activated_at: Some(0), + }; + genesis_config.accounts.insert( + feature_id, + feature.create_account(std::cmp::max( + genesis_config.rent.minimum_balance(Feature::size_of()), + 1, + )), + ); } } @@ -133,6 +147,7 @@ pub fn create_genesis_config_with_leader_ex( bootstrap_validator_staking_pubkey: &Pubkey, bootstrap_validator_stake_lamports: u64, bootstrap_validator_lamports: u64, + cluster_type: ClusterType, ) -> GenesisConfigInfo { let mint_keypair = Keypair::new(); let bootstrap_validator_vote_account = vote_state::create_account( @@ -179,11 +194,14 @@ pub fn create_genesis_config_with_leader_ex( accounts, fee_rate_governor, rent, + cluster_type, ..GenesisConfig::default() }; solana_stake_program::add_genesis_accounts(&mut genesis_config); - add_feature_accounts(&mut genesis_config); + if genesis_config.cluster_type == ClusterType::Development { + activate_all_features(&mut genesis_config); + } GenesisConfigInfo { genesis_config, diff --git a/runtime/src/message_processor.rs b/runtime/src/message_processor.rs index 43a48d8fba..654526d433 100644 --- a/runtime/src/message_processor.rs +++ b/runtime/src/message_processor.rs @@ -759,16 +759,6 @@ impl MessageProcessor { } Ok(()) } - - // only used for testing - pub fn builtin_loader_ids(&self) -> Vec { - self.loaders.iter().map(|a| a.0).collect::>() - } - - // only used for testing - pub fn builtin_program_ids(&self) -> Vec { - self.programs.iter().map(|a| a.0).collect::>() - } } #[cfg(test)] diff --git a/runtime/src/serde_snapshot.rs b/runtime/src/serde_snapshot.rs index a3c3857669..ad1c691be9 100644 --- a/runtime/src/serde_snapshot.rs +++ b/runtime/src/serde_snapshot.rs @@ -4,7 +4,7 @@ use { accounts_db::{AccountStorageEntry, AccountsDB, AppendVecId, BankHashInfo}, accounts_index::Ancestors, append_vec::AppendVec, - bank::{Bank, BankFieldsToDeserialize, BankRc}, + bank::{Bank, BankFieldsToDeserialize, BankRc, Builtins}, blockhash_queue::BlockhashQueue, epoch_stakes::EpochStakes, message_processor::MessageProcessor, @@ -125,6 +125,7 @@ pub(crate) fn bank_from_stream( genesis_config: &GenesisConfig, frozen_account_pubkeys: &[Pubkey], debug_keys: Option>>, + additional_builtins: Option<&Builtins>, ) -> std::result::Result where R: Read, @@ -142,6 +143,7 @@ where account_paths, append_vecs_path, debug_keys, + additional_builtins, )?; Ok(bank) }}; @@ -227,6 +229,7 @@ fn reconstruct_bank_from_fields( account_paths: &[PathBuf], append_vecs_path: P, debug_keys: Option>>, + additional_builtins: Option<&Builtins>, ) -> Result where E: Into, @@ -241,7 +244,13 @@ where accounts_db.freeze_accounts(&bank_fields.ancestors, frozen_account_pubkeys); let bank_rc = BankRc::new(Accounts::new_empty(accounts_db), bank_fields.slot); - let bank = Bank::new_from_fields(bank_rc, genesis_config, bank_fields, debug_keys); + let bank = Bank::new_from_fields( + bank_rc, + genesis_config, + bank_fields, + debug_keys, + additional_builtins, + ); Ok(bank) } diff --git a/runtime/src/serde_snapshot/tests.rs b/runtime/src/serde_snapshot/tests.rs index 31bc57ab0e..f16a023c0a 100644 --- a/runtime/src/serde_snapshot/tests.rs +++ b/runtime/src/serde_snapshot/tests.rs @@ -212,6 +212,7 @@ fn test_bank_serialize_style(serde_style: SerdeStyle) { &genesis_config, &[], None, + None, ) .unwrap(); dbank.src = ref_sc; diff --git a/runtime/src/snapshot_utils.rs b/runtime/src/snapshot_utils.rs index f2f0e1194b..85c7456e7c 100644 --- a/runtime/src/snapshot_utils.rs +++ b/runtime/src/snapshot_utils.rs @@ -1,5 +1,5 @@ use crate::{ - bank::{Bank, BankSlotDelta}, + bank::{Bank, BankSlotDelta, Builtins}, bank_forks::CompressionType, hardened_unpack::{unpack_snapshot, UnpackError}, serde_snapshot::{ @@ -574,6 +574,7 @@ pub fn bank_from_archive>( compression: CompressionType, genesis_config: &GenesisConfig, debug_keys: Option>>, + additional_builtins: Option<&Builtins>, ) -> Result { // Untar the snapshot into a temp directory under `snapshot_config.snapshot_path()` let unpack_dir = tempfile::tempdir_in(snapshot_path)?; @@ -595,6 +596,7 @@ pub fn bank_from_archive>( unpacked_accounts_dir, genesis_config, debug_keys, + additional_builtins, )?; if !bank.verify_snapshot_bank() { @@ -753,6 +755,7 @@ fn rebuild_bank_from_snapshots

( append_vecs_path: P, genesis_config: &GenesisConfig, debug_keys: Option>>, + additional_builtins: Option<&Builtins>, ) -> Result where P: AsRef, @@ -785,6 +788,7 @@ where genesis_config, frozen_account_pubkeys, debug_keys, + additional_builtins, ), }?) })?;