Port BPFLoader2 activation to FeatureSet and rework built-in program activation
This commit is contained in:
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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,
|
||||
|
@ -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)]
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -212,6 +212,7 @@ fn test_bank_serialize_style(serde_style: SerdeStyle) {
|
||||
&genesis_config,
|
||||
&[],
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
dbank.src = ref_sc;
|
||||
|
@ -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,
|
||||
),
|
||||
}?)
|
||||
})?;
|
||||
|
Reference in New Issue
Block a user