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

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