Port BPFLoader2 activation to FeatureSet and rework built-in program activation

This commit is contained in:
Michael Vines 2020-09-24 12:23:09 -07:00
parent 6071d0d206
commit 31696a1d72
26 changed files with 251 additions and 703 deletions

View File

@ -19,7 +19,6 @@ members = [
"perf",
"validator",
"genesis",
"genesis-programs",
"gossip",
"install",
"keygen",

View File

@ -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" }

44
core/src/builtins.rs Normal file
View File

@ -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<Builtin> {
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(),
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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()
};

View File

@ -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();

View File

@ -1,25 +0,0 @@
[package]
name = "solana-genesis-programs"
version = "1.4.0"
description = "Solana genesis programs"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
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"]

View File

@ -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::<Vec<_>>(),
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());
}
}

View File

@ -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]]

View File

@ -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<dyn error::Error>> {
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<dyn error::Error>> {
}
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 {

View File

@ -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" }

View File

@ -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,

View File

@ -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<Vec<Slot>>,
pub frozen_accounts: Vec<Pubkey>,
pub debug_keys: Option<Arc<HashSet<Pubkey>>>,
}
fn initiate_callback(mut bank: &mut Arc<Bank>, 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<Builtins>,
}
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: Bank,
opts: &ProcessOptions,
recyclers: &VerifyRecyclers,
transaction_status_sender: Option<TransactionStatusSender>,
) -> 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>,
bank: Arc<Bank>,
opts: &ProcessOptions,
recyclers: &VerifyRecyclers,
transaction_status_sender: Option<TransactionStatusSender>,
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<PathBuf>,
) -> 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()]
);
}
}

View File

@ -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" }

View File

@ -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);

View File

@ -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,

View File

@ -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<Pubkey> = 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<Pubkey> = vec![];
deposit_many(&bank1, &mut pubkeys, 250_000);

View File

@ -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>,
/// 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<dyn Fn(&mut Bank, bool) + Sync + Send>;
type WrappedEnteredEpochCallback = Arc<RwLock<Option<EnteredEpochCallback>>>;
pub type TransactionProcessResult = (Result<()>, Option<HashAgeKind>);
pub struct TransactionResults {
pub fee_collection_results: Vec<Result<()>>,
@ -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<Vec<(Builtin, Pubkey)>>,
/// 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<PathBuf>,
frozen_account_pubkeys: &[Pubkey],
debug_keys: Option<Arc<HashSet<Pubkey>>>,
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<Bank>, 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<Arc<HashSet<Pubkey>>>,
additional_builtins: Option<&Builtins>,
) -> Self {
fn new<T: Default>() -> 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<Bank>) {
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<Account> {
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<Pubkey>) {
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<Pubkey>,
) {
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<Pubkey> {
self.message_processor.builtin_loader_ids()
}
// only used for testing
pub fn builtin_program_ids(&self) -> Vec<Pubkey> {
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);
}

View File

@ -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::<Vec<_>>(),
);
// 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<Builtin> {
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(),
}
}

View File

@ -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<Pubkey, &'static str> = [
@ -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()

View File

@ -53,6 +53,20 @@ pub fn create_genesis_config_with_vote_accounts(
mint_lamports: u64,
voting_keypairs: &[impl Borrow<ValidatorVoteKeypairs>],
stakes: Vec<u64>,
) -> 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<ValidatorVoteKeypairs>],
stakes: Vec<u64>,
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,

View File

@ -759,16 +759,6 @@ impl MessageProcessor {
}
Ok(())
}
// only used for testing
pub fn builtin_loader_ids(&self) -> Vec<Pubkey> {
self.loaders.iter().map(|a| a.0).collect::<Vec<_>>()
}
// only used for testing
pub fn builtin_program_ids(&self) -> Vec<Pubkey> {
self.programs.iter().map(|a| a.0).collect::<Vec<_>>()
}
}
#[cfg(test)]

View File

@ -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<R, P>(
genesis_config: &GenesisConfig,
frozen_account_pubkeys: &[Pubkey],
debug_keys: Option<Arc<HashSet<Pubkey>>>,
additional_builtins: Option<&Builtins>,
) -> std::result::Result<Bank, Error>
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<E, P>(
account_paths: &[PathBuf],
append_vecs_path: P,
debug_keys: Option<Arc<HashSet<Pubkey>>>,
additional_builtins: Option<&Builtins>,
) -> Result<Bank, Error>
where
E: Into<AccountStorageEntry>,
@ -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)
}

View File

@ -212,6 +212,7 @@ fn test_bank_serialize_style(serde_style: SerdeStyle) {
&genesis_config,
&[],
None,
None,
)
.unwrap();
dbank.src = ref_sc;

View File

@ -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<P: AsRef<Path>>(
compression: CompressionType,
genesis_config: &GenesisConfig,
debug_keys: Option<Arc<HashSet<Pubkey>>>,
additional_builtins: Option<&Builtins>,
) -> Result<Bank> {
// 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<P: AsRef<Path>>(
unpacked_accounts_dir,
genesis_config,
debug_keys,
additional_builtins,
)?;
if !bank.verify_snapshot_bank() {
@ -753,6 +755,7 @@ fn rebuild_bank_from_snapshots<P>(
append_vecs_path: P,
genesis_config: &GenesisConfig,
debug_keys: Option<Arc<HashSet<Pubkey>>>,
additional_builtins: Option<&Builtins>,
) -> Result<Bank>
where
P: AsRef<Path>,
@ -785,6 +788,7 @@ where
genesis_config,
frozen_account_pubkeys,
debug_keys,
additional_builtins,
),
}?)
})?;