Port BPFLoader2 activation to FeatureSet and rework built-in program activation
This commit is contained in:
@ -19,7 +19,6 @@ members = [
|
|||||||
"perf",
|
"perf",
|
||||||
"validator",
|
"validator",
|
||||||
"genesis",
|
"genesis",
|
||||||
"genesis-programs",
|
|
||||||
"gossip",
|
"gossip",
|
||||||
"install",
|
"install",
|
||||||
"keygen",
|
"keygen",
|
||||||
|
@ -45,10 +45,10 @@ serde_derive = "1.0.103"
|
|||||||
serde_json = "1.0.56"
|
serde_json = "1.0.56"
|
||||||
solana-account-decoder = { path = "../account-decoder", version = "1.4.0" }
|
solana-account-decoder = { path = "../account-decoder", version = "1.4.0" }
|
||||||
solana-banks-server = { path = "../banks-server", 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-clap-utils = { path = "../clap-utils", version = "1.4.0" }
|
||||||
solana-client = { path = "../client", version = "1.4.0" }
|
solana-client = { path = "../client", version = "1.4.0" }
|
||||||
solana-faucet = { path = "../faucet", 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-ledger = { path = "../ledger", version = "1.4.0" }
|
||||||
solana-logger = { path = "../logger", version = "1.4.0" }
|
solana-logger = { path = "../logger", version = "1.4.0" }
|
||||||
solana-merkle-tree = { path = "../merkle-tree", version = "1.4.0" }
|
solana-merkle-tree = { path = "../merkle-tree", version = "1.4.0" }
|
||||||
|
44
core/src/builtins.rs
Normal file
44
core/src/builtins.rs
Normal 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(),
|
||||||
|
}
|
||||||
|
}
|
@ -6,11 +6,15 @@
|
|||||||
//! command-line tools to spin up validators and a Rust library
|
//! 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_background_service;
|
||||||
pub mod accounts_hash_verifier;
|
pub mod accounts_hash_verifier;
|
||||||
pub mod banking_stage;
|
pub mod banking_stage;
|
||||||
pub mod bigtable_upload_service;
|
pub mod bigtable_upload_service;
|
||||||
pub mod broadcast_stage;
|
pub mod broadcast_stage;
|
||||||
|
mod builtins;
|
||||||
pub mod cache_block_time_service;
|
pub mod cache_block_time_service;
|
||||||
pub mod cluster_info_vote_listener;
|
pub mod cluster_info_vote_listener;
|
||||||
pub mod commitment_service;
|
pub mod commitment_service;
|
||||||
|
@ -69,6 +69,7 @@ impl TestValidator {
|
|||||||
&Pubkey::new_rand(),
|
&Pubkey::new_rand(),
|
||||||
42,
|
42,
|
||||||
bootstrap_validator_lamports,
|
bootstrap_validator_lamports,
|
||||||
|
solana_sdk::genesis_config::ClusterType::Development,
|
||||||
);
|
);
|
||||||
genesis_config.rent.lamports_per_byte_year = 1;
|
genesis_config.rent.lamports_per_byte_year = 1;
|
||||||
genesis_config.rent.exemption_threshold = 1.0;
|
genesis_config.rent.exemption_threshold = 1.0;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
broadcast_stage::BroadcastStageType,
|
broadcast_stage::BroadcastStageType,
|
||||||
|
builtins,
|
||||||
cache_block_time_service::{CacheBlockTimeSender, CacheBlockTimeService},
|
cache_block_time_service::{CacheBlockTimeSender, CacheBlockTimeService},
|
||||||
cluster_info::{ClusterInfo, Node},
|
cluster_info::{ClusterInfo, Node},
|
||||||
cluster_info_vote_listener::VoteTracker,
|
cluster_info_vote_listener::VoteTracker,
|
||||||
@ -791,6 +792,7 @@ fn new_banks_from_ledger(
|
|||||||
new_hard_forks: config.new_hard_forks.clone(),
|
new_hard_forks: config.new_hard_forks.clone(),
|
||||||
frozen_accounts: config.frozen_accounts.clone(),
|
frozen_accounts: config.frozen_accounts.clone(),
|
||||||
debug_keys: config.debug_keys.clone(),
|
debug_keys: config.debug_keys.clone(),
|
||||||
|
additional_builtins: Some(builtins::get(genesis_config.cluster_type)),
|
||||||
..blockstore_processor::ProcessOptions::default()
|
..blockstore_processor::ProcessOptions::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -89,6 +89,7 @@ mod tests {
|
|||||||
vec![accounts_dir.path().to_path_buf()],
|
vec![accounts_dir.path().to_path_buf()],
|
||||||
&[],
|
&[],
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
bank0.freeze();
|
bank0.freeze();
|
||||||
let mut bank_forks = BankForks::new(bank0);
|
let mut bank_forks = BankForks::new(bank0);
|
||||||
@ -143,6 +144,7 @@ mod tests {
|
|||||||
CompressionType::Bzip2,
|
CompressionType::Bzip2,
|
||||||
old_genesis_config,
|
old_genesis_config,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -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"]
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
@ -15,15 +15,17 @@ chrono = "0.4"
|
|||||||
serde = "1.0.112"
|
serde = "1.0.112"
|
||||||
serde_json = "1.0.56"
|
serde_json = "1.0.56"
|
||||||
serde_yaml = "0.8.13"
|
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-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-ledger = { path = "../ledger", version = "1.4.0" }
|
||||||
solana-logger = { path = "../logger", version = "1.4.0" }
|
solana-logger = { path = "../logger", version = "1.4.0" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.4.0" }
|
solana-runtime = { path = "../runtime", version = "1.4.0" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.4.0" }
|
solana-sdk = { path = "../sdk", version = "1.4.0" }
|
||||||
solana-stake-program = { path = "../programs/stake", 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-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"
|
tempfile = "3.1.0"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
//! A command-line executable for generating the chain's genesis config.
|
//! 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 clap::{crate_description, crate_name, value_t, value_t_or_exit, App, Arg, ArgMatches};
|
||||||
use solana_clap_utils::{
|
use solana_clap_utils::{
|
||||||
input_parsers::{cluster_type_of, pubkey_of, pubkeys_of, unix_timestamp_from_rfc3339_datetime},
|
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"),
|
matches.is_present("enable_warmup_epochs"),
|
||||||
);
|
);
|
||||||
|
|
||||||
let native_instruction_processors =
|
let native_instruction_processors = if cluster_type == ClusterType::Development {
|
||||||
solana_genesis_programs::get_native_programs_for_genesis(cluster_type);
|
vec![
|
||||||
|
solana_vest_program!(),
|
||||||
|
solana_budget_program!(),
|
||||||
|
solana_exchange_program!(),
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
|
||||||
let mut genesis_config = GenesisConfig {
|
let mut genesis_config = GenesisConfig {
|
||||||
native_instruction_processors,
|
native_instruction_processors,
|
||||||
@ -526,7 +540,9 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
solana_stake_program::add_genesis_accounts(&mut genesis_config);
|
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") {
|
if let Some(files) = matches.values_of("primordial_accounts_file") {
|
||||||
for file in files {
|
for file in files {
|
||||||
|
@ -32,7 +32,6 @@ serde = "1.0.112"
|
|||||||
serde_bytes = "0.11.4"
|
serde_bytes = "0.11.4"
|
||||||
sha2 = "0.8.2"
|
sha2 = "0.8.2"
|
||||||
solana-transaction-status = { path = "../transaction-status", version = "1.4.0" }
|
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-logger = { path = "../logger", version = "1.4.0" }
|
||||||
solana-measure = { path = "../measure", version = "1.4.0" }
|
solana-measure = { path = "../measure", version = "1.4.0" }
|
||||||
solana-merkle-tree = { path = "../merkle-tree", version = "1.4.0" }
|
solana-merkle-tree = { path = "../merkle-tree", version = "1.4.0" }
|
||||||
|
@ -13,7 +13,7 @@ use solana_runtime::{
|
|||||||
snapshot_utils,
|
snapshot_utils,
|
||||||
};
|
};
|
||||||
use solana_sdk::{clock::Slot, genesis_config::GenesisConfig, hash::Hash};
|
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<
|
pub type LoadResult = result::Result<
|
||||||
(BankForks, LeaderScheduleCache, Option<(Slot, Hash)>),
|
(BankForks, LeaderScheduleCache, Option<(Slot, Hash)>),
|
||||||
@ -66,6 +66,7 @@ pub fn load(
|
|||||||
compression,
|
compression,
|
||||||
genesis_config,
|
genesis_config,
|
||||||
process_options.debug_keys.clone(),
|
process_options.debug_keys.clone(),
|
||||||
|
process_options.additional_builtins.as_ref(),
|
||||||
)
|
)
|
||||||
.expect("Load from snapshot failed");
|
.expect("Load from snapshot failed");
|
||||||
|
|
||||||
@ -84,9 +85,8 @@ pub fn load(
|
|||||||
|
|
||||||
return to_loadresult(
|
return to_loadresult(
|
||||||
blockstore_processor::process_blockstore_from_root(
|
blockstore_processor::process_blockstore_from_root(
|
||||||
genesis_config,
|
|
||||||
blockstore,
|
blockstore,
|
||||||
Arc::new(deserialized_bank),
|
deserialized_bank,
|
||||||
&process_options,
|
&process_options,
|
||||||
&VerifyRecyclers::default(),
|
&VerifyRecyclers::default(),
|
||||||
transaction_status_sender,
|
transaction_status_sender,
|
||||||
|
@ -16,7 +16,7 @@ use solana_metrics::{datapoint_error, inc_new_counter_debug};
|
|||||||
use solana_rayon_threadlimit::get_thread_count;
|
use solana_rayon_threadlimit::get_thread_count;
|
||||||
use solana_runtime::{
|
use solana_runtime::{
|
||||||
bank::{
|
bank::{
|
||||||
Bank, InnerInstructionsList, TransactionBalancesSet, TransactionProcessResult,
|
Bank, Builtins, InnerInstructionsList, TransactionBalancesSet, TransactionProcessResult,
|
||||||
TransactionResults,
|
TransactionResults,
|
||||||
},
|
},
|
||||||
bank_forks::BankForks,
|
bank_forks::BankForks,
|
||||||
@ -318,14 +318,7 @@ pub struct ProcessOptions {
|
|||||||
pub new_hard_forks: Option<Vec<Slot>>,
|
pub new_hard_forks: Option<Vec<Slot>>,
|
||||||
pub frozen_accounts: Vec<Pubkey>,
|
pub frozen_accounts: Vec<Pubkey>,
|
||||||
pub debug_keys: Option<Arc<HashSet<Pubkey>>>,
|
pub debug_keys: Option<Arc<HashSet<Pubkey>>>,
|
||||||
}
|
pub additional_builtins: Option<Builtins>,
|
||||||
|
|
||||||
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 fn process_blockstore(
|
pub fn process_blockstore(
|
||||||
@ -344,55 +337,43 @@ pub fn process_blockstore(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup bank for slot 0
|
// Setup bank for slot 0
|
||||||
let mut bank0 = Arc::new(Bank::new_with_paths(
|
let bank0 = Bank::new_with_paths(
|
||||||
&genesis_config,
|
&genesis_config,
|
||||||
account_paths,
|
account_paths,
|
||||||
&opts.frozen_accounts,
|
&opts.frozen_accounts,
|
||||||
opts.debug_keys.clone(),
|
opts.debug_keys.clone(),
|
||||||
));
|
opts.additional_builtins.as_ref(),
|
||||||
initiate_callback(&mut bank0, genesis_config);
|
);
|
||||||
|
let bank0 = Arc::new(bank0);
|
||||||
info!("processing ledger for slot 0...");
|
info!("processing ledger for slot 0...");
|
||||||
let recyclers = VerifyRecyclers::default();
|
let recyclers = VerifyRecyclers::default();
|
||||||
process_bank_0(&bank0, blockstore, &opts, &recyclers)?;
|
process_bank_0(&bank0, blockstore, &opts, &recyclers)?;
|
||||||
do_process_blockstore_from_root(
|
do_process_blockstore_from_root(blockstore, bank0, &opts, &recyclers, None)
|
||||||
genesis_config,
|
|
||||||
blockstore,
|
|
||||||
bank0,
|
|
||||||
&opts,
|
|
||||||
&recyclers,
|
|
||||||
None,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process blockstore from a known root bank
|
// Process blockstore from a known root bank
|
||||||
pub fn process_blockstore_from_root(
|
pub(crate) fn process_blockstore_from_root(
|
||||||
genesis_config: &GenesisConfig,
|
|
||||||
blockstore: &Blockstore,
|
blockstore: &Blockstore,
|
||||||
bank: Arc<Bank>,
|
bank: Bank,
|
||||||
opts: &ProcessOptions,
|
opts: &ProcessOptions,
|
||||||
recyclers: &VerifyRecyclers,
|
recyclers: &VerifyRecyclers,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
) -> BlockstoreProcessorResult {
|
) -> BlockstoreProcessorResult {
|
||||||
do_process_blockstore_from_root(
|
do_process_blockstore_from_root(
|
||||||
genesis_config,
|
|
||||||
blockstore,
|
blockstore,
|
||||||
bank,
|
Arc::new(bank),
|
||||||
opts,
|
opts,
|
||||||
recyclers,
|
recyclers,
|
||||||
transaction_status_sender,
|
transaction_status_sender,
|
||||||
true,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_process_blockstore_from_root(
|
fn do_process_blockstore_from_root(
|
||||||
genesis_config: &GenesisConfig,
|
|
||||||
blockstore: &Blockstore,
|
blockstore: &Blockstore,
|
||||||
mut bank: Arc<Bank>,
|
bank: Arc<Bank>,
|
||||||
opts: &ProcessOptions,
|
opts: &ProcessOptions,
|
||||||
recyclers: &VerifyRecyclers,
|
recyclers: &VerifyRecyclers,
|
||||||
transaction_status_sender: Option<TransactionStatusSender>,
|
transaction_status_sender: Option<TransactionStatusSender>,
|
||||||
enable_callback: bool,
|
|
||||||
) -> BlockstoreProcessorResult {
|
) -> BlockstoreProcessorResult {
|
||||||
info!("processing ledger from slot {}...", bank.slot());
|
info!("processing ledger from slot {}...", bank.slot());
|
||||||
let allocated = thread_mem_usage::Allocatedp::default();
|
let allocated = thread_mem_usage::Allocatedp::default();
|
||||||
@ -404,10 +385,6 @@ fn do_process_blockstore_from_root(
|
|||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
let mut root = start_slot;
|
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 {
|
if let Some(ref new_hard_forks) = opts.new_hard_forks {
|
||||||
let hard_forks = bank.hard_forks();
|
let hard_forks = bank.hard_forks();
|
||||||
|
|
||||||
@ -2662,8 +2639,7 @@ pub mod tests {
|
|||||||
blockstore.set_roots(&[3, 5]).unwrap();
|
blockstore.set_roots(&[3, 5]).unwrap();
|
||||||
|
|
||||||
// Set up bank1
|
// Set up bank1
|
||||||
let mut bank0 = Arc::new(Bank::new(&genesis_config));
|
let bank0 = Arc::new(Bank::new(&genesis_config));
|
||||||
initiate_callback(&mut bank0, &genesis_config);
|
|
||||||
let opts = ProcessOptions {
|
let opts = ProcessOptions {
|
||||||
poh_verify: true,
|
poh_verify: true,
|
||||||
..ProcessOptions::default()
|
..ProcessOptions::default()
|
||||||
@ -2684,16 +2660,8 @@ pub mod tests {
|
|||||||
bank1.squash();
|
bank1.squash();
|
||||||
|
|
||||||
// Test process_blockstore_from_root() from slot 1 onwards
|
// Test process_blockstore_from_root() from slot 1 onwards
|
||||||
let (bank_forks, _leader_schedule) = do_process_blockstore_from_root(
|
let (bank_forks, _leader_schedule) =
|
||||||
&genesis_config,
|
do_process_blockstore_from_root(&blockstore, bank1, &opts, &recyclers, None).unwrap();
|
||||||
&blockstore,
|
|
||||||
bank1,
|
|
||||||
&opts,
|
|
||||||
&recyclers,
|
|
||||||
None,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(frozen_bank_slots(&bank_forks), vec![5, 6]);
|
assert_eq!(frozen_bank_slots(&bank_forks), vec![5, 6]);
|
||||||
assert_eq!(bank_forks.working_bank().slot(), 6);
|
assert_eq!(bank_forks.working_bank().slot(), 6);
|
||||||
@ -2857,7 +2825,7 @@ pub mod tests {
|
|||||||
genesis_config: &GenesisConfig,
|
genesis_config: &GenesisConfig,
|
||||||
account_paths: Vec<PathBuf>,
|
account_paths: Vec<PathBuf>,
|
||||||
) -> EpochSchedule {
|
) -> 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()
|
*bank.epoch_schedule()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3211,95 +3179,4 @@ pub mod tests {
|
|||||||
8
|
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()]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@ solana-client = { path = "../client", version = "1.4.0" }
|
|||||||
solana-download-utils = { path = "../download-utils", version = "1.4.0" }
|
solana-download-utils = { path = "../download-utils", version = "1.4.0" }
|
||||||
solana-faucet = { path = "../faucet", version = "1.4.0" }
|
solana-faucet = { path = "../faucet", version = "1.4.0" }
|
||||||
solana-exchange-program = { path = "../programs/exchange", 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-ledger = { path = "../ledger", version = "1.4.0" }
|
||||||
solana-logger = { path = "../logger", version = "1.4.0" }
|
solana-logger = { path = "../logger", version = "1.4.0" }
|
||||||
solana-runtime = { path = "../runtime", version = "1.4.0" }
|
solana-runtime = { path = "../runtime", version = "1.4.0" }
|
||||||
|
@ -13,7 +13,8 @@ use solana_core::{
|
|||||||
};
|
};
|
||||||
use solana_ledger::create_new_tmp_ledger;
|
use solana_ledger::create_new_tmp_ledger;
|
||||||
use solana_runtime::genesis_utils::{
|
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::{
|
use solana_sdk::{
|
||||||
client::SyncClient,
|
client::SyncClient,
|
||||||
@ -155,10 +156,11 @@ impl LocalCluster {
|
|||||||
mut genesis_config,
|
mut genesis_config,
|
||||||
mint_keypair,
|
mint_keypair,
|
||||||
..
|
..
|
||||||
} = create_genesis_config_with_vote_accounts(
|
} = create_genesis_config_with_vote_accounts_and_cluster_type(
|
||||||
config.cluster_lamports,
|
config.cluster_lamports,
|
||||||
&keys_in_genesis,
|
&keys_in_genesis,
|
||||||
stakes_in_genesis,
|
stakes_in_genesis,
|
||||||
|
config.cluster_type,
|
||||||
);
|
);
|
||||||
genesis_config.ticks_per_slot = config.ticks_per_slot;
|
genesis_config.ticks_per_slot = config.ticks_per_slot;
|
||||||
genesis_config.epoch_schedule = EpochSchedule::custom(
|
genesis_config.epoch_schedule = EpochSchedule::custom(
|
||||||
@ -166,19 +168,7 @@ impl LocalCluster {
|
|||||||
config.stakers_slot_offset,
|
config.stakers_slot_offset,
|
||||||
!config.skip_warmup_slots,
|
!config.skip_warmup_slots,
|
||||||
);
|
);
|
||||||
genesis_config.cluster_type = config.cluster_type;
|
|
||||||
genesis_config.poh_config = config.poh_config.clone();
|
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
|
genesis_config
|
||||||
.native_instruction_processors
|
.native_instruction_processors
|
||||||
.extend_from_slice(&config.native_instruction_processors);
|
.extend_from_slice(&config.native_instruction_processors);
|
||||||
|
@ -759,6 +759,7 @@ fn test_mainnet_beta_cluster_type() {
|
|||||||
&solana_sdk::system_program::id(),
|
&solana_sdk::system_program::id(),
|
||||||
&solana_stake_program::id(),
|
&solana_stake_program::id(),
|
||||||
&solana_vote_program::id(),
|
&solana_vote_program::id(),
|
||||||
|
&solana_sdk::bpf_loader_deprecated::id(),
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
{
|
{
|
||||||
@ -774,13 +775,7 @@ fn test_mainnet_beta_cluster_type() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Programs that are not available at epoch 0
|
// Programs that are not available at epoch 0
|
||||||
for program_id in [
|
for program_id in [&solana_sdk::bpf_loader::id(), &solana_vest_program::id()].iter() {
|
||||||
&solana_sdk::bpf_loader::id(),
|
|
||||||
&solana_sdk::bpf_loader_deprecated::id(),
|
|
||||||
&solana_vest_program::id(),
|
|
||||||
]
|
|
||||||
.iter()
|
|
||||||
{
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
(
|
(
|
||||||
program_id,
|
program_id,
|
||||||
|
@ -36,7 +36,13 @@ fn bench_has_duplicates(bencher: &mut Bencher) {
|
|||||||
#[bench]
|
#[bench]
|
||||||
fn test_accounts_create(bencher: &mut Bencher) {
|
fn test_accounts_create(bencher: &mut Bencher) {
|
||||||
let (genesis_config, _) = create_genesis_config(10_000);
|
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(|| {
|
bencher.iter(|| {
|
||||||
let mut pubkeys: Vec<Pubkey> = vec![];
|
let mut pubkeys: Vec<Pubkey> = vec![];
|
||||||
deposit_many(&bank0, &mut pubkeys, 1000);
|
deposit_many(&bank0, &mut pubkeys, 1000);
|
||||||
@ -51,6 +57,7 @@ fn test_accounts_squash(bencher: &mut Bencher) {
|
|||||||
vec![PathBuf::from("bench_a1")],
|
vec![PathBuf::from("bench_a1")],
|
||||||
&[],
|
&[],
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
));
|
));
|
||||||
let mut pubkeys: Vec<Pubkey> = vec![];
|
let mut pubkeys: Vec<Pubkey> = vec![];
|
||||||
deposit_many(&bank1, &mut pubkeys, 250_000);
|
deposit_many(&bank1, &mut pubkeys, 250_000);
|
||||||
|
@ -10,7 +10,7 @@ use crate::{
|
|||||||
accounts_db::{ErrorCounters, SnapshotStorages},
|
accounts_db::{ErrorCounters, SnapshotStorages},
|
||||||
accounts_index::Ancestors,
|
accounts_index::Ancestors,
|
||||||
blockhash_queue::BlockhashQueue,
|
blockhash_queue::BlockhashQueue,
|
||||||
builtins::*,
|
builtins,
|
||||||
epoch_stakes::{EpochStakes, NodeVoteAccounts},
|
epoch_stakes::{EpochStakes, NodeVoteAccounts},
|
||||||
feature::Feature,
|
feature::Feature,
|
||||||
feature_set::{self, FeatureSet},
|
feature_set::{self, FeatureSet},
|
||||||
@ -137,6 +137,7 @@ pub enum Entrypoint {
|
|||||||
Program(ProcessInstruction),
|
Program(ProcessInstruction),
|
||||||
Loader(ProcessInstructionWithContext),
|
Loader(ProcessInstructionWithContext),
|
||||||
}
|
}
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Builtin {
|
pub struct Builtin {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub id: Pubkey,
|
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
|
const MAX_CACHED_EXECUTORS: usize = 100; // 10 MB assuming programs are around 100k
|
||||||
|
|
||||||
/// LFU Cache of executors
|
/// 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 type TransactionProcessResult = (Result<()>, Option<HashAgeKind>);
|
||||||
pub struct TransactionResults {
|
pub struct TransactionResults {
|
||||||
pub fee_collection_results: Vec<Result<()>>,
|
pub fee_collection_results: Vec<Result<()>>,
|
||||||
@ -559,9 +566,8 @@ pub struct Bank {
|
|||||||
/// The Message processor
|
/// The Message processor
|
||||||
message_processor: MessageProcessor,
|
message_processor: MessageProcessor,
|
||||||
|
|
||||||
/// Callback to be notified when a bank enters a new Epoch
|
/// Builtin programs activated dynamically by feature
|
||||||
/// (used to adjust cluster features over time)
|
feature_builtins: Arc<Vec<(Builtin, Pubkey)>>,
|
||||||
entered_epoch_callback: WrappedEnteredEpochCallback,
|
|
||||||
|
|
||||||
/// Last time when the cluster info vote listener has synced with this bank
|
/// Last time when the cluster info vote listener has synced with this bank
|
||||||
pub last_vote_sync: AtomicU64,
|
pub last_vote_sync: AtomicU64,
|
||||||
@ -594,7 +600,7 @@ impl Default for BlockhashQueue {
|
|||||||
|
|
||||||
impl Bank {
|
impl Bank {
|
||||||
pub fn new(genesis_config: &GenesisConfig) -> Self {
|
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(
|
pub fn new_with_paths(
|
||||||
@ -602,6 +608,7 @@ impl Bank {
|
|||||||
paths: Vec<PathBuf>,
|
paths: Vec<PathBuf>,
|
||||||
frozen_account_pubkeys: &[Pubkey],
|
frozen_account_pubkeys: &[Pubkey],
|
||||||
debug_keys: Option<Arc<HashSet<Pubkey>>>,
|
debug_keys: Option<Arc<HashSet<Pubkey>>>,
|
||||||
|
additional_builtins: Option<&Builtins>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut bank = Self::default();
|
let mut bank = Self::default();
|
||||||
bank.transaction_debug_keys = debug_keys;
|
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.rc.accounts = Arc::new(Accounts::new(paths, &genesis_config.cluster_type));
|
||||||
bank.process_genesis_config(genesis_config);
|
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
|
// 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)
|
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)),
|
tick_height: AtomicU64::new(parent.tick_height.load(Relaxed)),
|
||||||
signature_count: AtomicU64::new(0),
|
signature_count: AtomicU64::new(0),
|
||||||
message_processor: parent.message_processor.clone(),
|
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(),
|
hard_forks: parent.hard_forks.clone(),
|
||||||
last_vote_sync: AtomicU64::new(parent.last_vote_sync.load(Relaxed)),
|
last_vote_sync: AtomicU64::new(parent.last_vote_sync.load(Relaxed)),
|
||||||
rewards: None,
|
rewards: None,
|
||||||
@ -725,7 +732,7 @@ impl Bank {
|
|||||||
|
|
||||||
// Following code may touch AccountsDB, requiring proper ancestors
|
// Following code may touch AccountsDB, requiring proper ancestors
|
||||||
if parent.epoch() < new.epoch() {
|
if parent.epoch() < new.epoch() {
|
||||||
new.apply_feature_activations(false, false);
|
new.apply_feature_activations(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
new.update_slot_hashes();
|
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
|
/// * 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 {
|
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);
|
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.update_epoch_stakes(new.epoch_schedule().get_epoch(slot));
|
||||||
new.tick_height.store(new.max_tick_height(), Relaxed);
|
new.tick_height.store(new.max_tick_height(), Relaxed);
|
||||||
new.freeze();
|
new.freeze();
|
||||||
@ -761,6 +768,7 @@ impl Bank {
|
|||||||
genesis_config: &GenesisConfig,
|
genesis_config: &GenesisConfig,
|
||||||
fields: BankFieldsToDeserialize,
|
fields: BankFieldsToDeserialize,
|
||||||
debug_keys: Option<Arc<HashSet<Pubkey>>>,
|
debug_keys: Option<Arc<HashSet<Pubkey>>>,
|
||||||
|
additional_builtins: Option<&Builtins>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
fn new<T: Default>() -> T {
|
fn new<T: Default>() -> T {
|
||||||
T::default()
|
T::default()
|
||||||
@ -803,7 +811,7 @@ impl Bank {
|
|||||||
epoch_stakes: fields.epoch_stakes,
|
epoch_stakes: fields.epoch_stakes,
|
||||||
is_delta: AtomicBool::new(fields.is_delta),
|
is_delta: AtomicBool::new(fields.is_delta),
|
||||||
message_processor: new(),
|
message_processor: new(),
|
||||||
entered_epoch_callback: new(),
|
feature_builtins: new(),
|
||||||
last_vote_sync: new(),
|
last_vote_sync: new(),
|
||||||
rewards: new(),
|
rewards: new(),
|
||||||
skip_drop: new(),
|
skip_drop: new(),
|
||||||
@ -816,7 +824,7 @@ impl Bank {
|
|||||||
transaction_debug_keys: debug_keys,
|
transaction_debug_keys: debug_keys,
|
||||||
feature_set: new(),
|
feature_set: new(),
|
||||||
};
|
};
|
||||||
bank.finish_init(genesis_config);
|
bank.finish_init(genesis_config, additional_builtins);
|
||||||
|
|
||||||
// Sanity assertions between bank snapshot and genesis config
|
// Sanity assertions between bank snapshot and genesis config
|
||||||
// Consider removing from serializable bank state
|
// Consider removing from serializable bank state
|
||||||
@ -2967,19 +2975,29 @@ impl Bank {
|
|||||||
self.rc.accounts.clone()
|
self.rc.accounts.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_bank_rc(&mut self, bank_rc: BankRc, status_cache_rc: StatusCacheRc) {
|
fn finish_init(
|
||||||
self.rc = bank_rc;
|
&mut self,
|
||||||
self.src = status_cache_rc;
|
genesis_config: &GenesisConfig,
|
||||||
}
|
additional_builtins: Option<&Builtins>,
|
||||||
|
) {
|
||||||
pub fn finish_init(&mut self, genesis_config: &GenesisConfig) {
|
|
||||||
self.rewards_pool_pubkeys =
|
self.rewards_pool_pubkeys =
|
||||||
Arc::new(genesis_config.rewards_pools.keys().cloned().collect());
|
Arc::new(genesis_config.rewards_pools.keys().cloned().collect());
|
||||||
self.apply_feature_activations(true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_parent(&mut self, parent: &Arc<Bank>) {
|
let mut builtins = builtins::get();
|
||||||
self.rc.parent = RwLock::new(Some(parent.clone()));
|
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) {
|
pub fn set_inflation(&self, inflation: Inflation) {
|
||||||
@ -2990,19 +3008,6 @@ impl Bank {
|
|||||||
self.hard_forks.clone()
|
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> {
|
pub fn get_account(&self, pubkey: &Pubkey) -> Option<Account> {
|
||||||
self.get_account_modified_slot(pubkey)
|
self.get_account_modified_slot(pubkey)
|
||||||
.map(|(acc, _slot)| acc)
|
.map(|(acc, _slot)| acc)
|
||||||
@ -3558,7 +3563,7 @@ impl Bank {
|
|||||||
|
|
||||||
// This is called from snapshot restore AND for each epoch boundary
|
// This is called from snapshot restore AND for each epoch boundary
|
||||||
// The entire code path herein must be idempotent
|
// 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);
|
let new_feature_activations = self.compute_active_feature_set(!init_finish_or_warp);
|
||||||
|
|
||||||
if new_feature_activations.contains(&feature_set::pico_inflation::id()) {
|
if new_feature_activations.contains(&feature_set::pico_inflation::id()) {
|
||||||
@ -3571,8 +3576,7 @@ impl Bank {
|
|||||||
self.apply_spl_token_v2_multisig_fix();
|
self.apply_spl_token_v2_multisig_fix();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.ensure_builtins(init_finish_or_warp, &new_feature_activations);
|
self.ensure_feature_builtins(init_finish_or_warp, &new_feature_activations);
|
||||||
self.reinvoke_entered_epoch_callback(initiate_callback);
|
|
||||||
self.recheck_cross_program_support();
|
self.recheck_cross_program_support();
|
||||||
self.recheck_compute_budget();
|
self.recheck_compute_budget();
|
||||||
self.reconfigure_token2_native_mint();
|
self.reconfigure_token2_native_mint();
|
||||||
@ -3623,32 +3627,21 @@ impl Bank {
|
|||||||
newly_activated
|
newly_activated
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ensure_builtins(&mut self, init_or_warp: bool, new_feature_activations: &HashSet<Pubkey>) {
|
fn ensure_feature_builtins(
|
||||||
for (program, start_epoch) in get_cluster_builtins(self.cluster_type()) {
|
&mut self,
|
||||||
let should_populate = init_or_warp && self.epoch() >= start_epoch
|
init_or_warp: bool,
|
||||||
|| !init_or_warp && self.epoch() == start_epoch;
|
new_feature_activations: &HashSet<Pubkey>,
|
||||||
if should_populate {
|
) {
|
||||||
self.add_builtin(&program.name, program.id, program.entrypoint);
|
let feature_builtins = self.feature_builtins.clone();
|
||||||
}
|
for (builtin, feature) in feature_builtins.iter() {
|
||||||
}
|
|
||||||
|
|
||||||
for (program, feature) in get_feature_builtins() {
|
|
||||||
let should_populate = init_or_warp && self.feature_set.is_active(&feature)
|
let should_populate = init_or_warp && self.feature_set.is_active(&feature)
|
||||||
|| !init_or_warp && new_feature_activations.contains(&feature);
|
|| !init_or_warp && new_feature_activations.contains(&feature);
|
||||||
if should_populate {
|
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) {
|
fn recheck_cross_program_support(&mut self) {
|
||||||
if ClusterType::MainnetBeta == self.cluster_type() {
|
if ClusterType::MainnetBeta == self.cluster_type() {
|
||||||
self.set_cross_program_support(self.epoch() >= 63);
|
self.set_cross_program_support(self.epoch() >= 63);
|
||||||
@ -3769,22 +3762,6 @@ impl Bank {
|
|||||||
.is_active(&feature_set::consistent_recent_blockhashes_sysvar::id()),
|
.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 {
|
impl Drop for Bank {
|
||||||
@ -3845,7 +3822,7 @@ mod tests {
|
|||||||
vote_instruction,
|
vote_instruction,
|
||||||
vote_state::{self, Vote, VoteInit, VoteState, MAX_LOCKOUT_HISTORY},
|
vote_state::{self, Vote, VoteInit, VoteState, MAX_LOCKOUT_HISTORY},
|
||||||
};
|
};
|
||||||
use std::{result, sync::atomic::Ordering::SeqCst, time::Duration};
|
use std::{result, time::Duration};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_hash_age_kind_is_durable_nonce() {
|
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]
|
#[test]
|
||||||
fn test_is_delta_true() {
|
fn test_is_delta_true() {
|
||||||
let (genesis_config, mint_keypair) = create_genesis_config(500);
|
let (genesis_config, mint_keypair) = create_genesis_config(500);
|
||||||
@ -8406,7 +8344,6 @@ mod tests {
|
|||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
use std::collections::HashSet;
|
|
||||||
let mut inserted = HashSet::new();
|
let mut inserted = HashSet::new();
|
||||||
(0..num_keys)
|
(0..num_keys)
|
||||||
.map(|_| {
|
.map(|_| {
|
||||||
@ -8740,7 +8677,7 @@ mod tests {
|
|||||||
bank.message_processor.set_cross_program_support(false);
|
bank.message_processor.set_cross_program_support(false);
|
||||||
|
|
||||||
// simulate bank is just after deserialized from snapshot
|
// 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);
|
assert_eq!(bank.message_processor.get_cross_program_support(), true);
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,11 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
bank::{Builtin, Entrypoint},
|
bank::{Builtin, Builtins, Entrypoint},
|
||||||
feature_set, system_instruction_processor,
|
feature_set, system_instruction_processor,
|
||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{pubkey::Pubkey, system_program};
|
||||||
clock::{Epoch, GENESIS_EPOCH},
|
|
||||||
genesis_config::ClusterType,
|
|
||||||
pubkey::Pubkey,
|
|
||||||
system_program,
|
|
||||||
};
|
|
||||||
|
|
||||||
use log::*;
|
/// Builtin programs that are always available
|
||||||
|
fn genesis_builtins() -> Vec<Builtin> {
|
||||||
/// 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![
|
vec![
|
||||||
Builtin::new(
|
Builtin::new(
|
||||||
"system_program",
|
"system_program",
|
||||||
@ -26,9 +13,9 @@ pub fn get_cluster_builtins(cluster_type: ClusterType) -> Vec<(Builtin, Epoch)>
|
|||||||
Entrypoint::Program(system_instruction_processor::process_instruction),
|
Entrypoint::Program(system_instruction_processor::process_instruction),
|
||||||
),
|
),
|
||||||
Builtin::new(
|
Builtin::new(
|
||||||
"config_program",
|
"vote_program",
|
||||||
solana_config_program::id(),
|
solana_vote_program::id(),
|
||||||
Entrypoint::Program(solana_config_program::config_processor::process_instruction),
|
Entrypoint::Program(solana_vote_program::vote_instruction::process_instruction),
|
||||||
),
|
),
|
||||||
Builtin::new(
|
Builtin::new(
|
||||||
"stake_program",
|
"stake_program",
|
||||||
@ -36,41 +23,15 @@ pub fn get_cluster_builtins(cluster_type: ClusterType) -> Vec<(Builtin, Epoch)>
|
|||||||
Entrypoint::Program(solana_stake_program::stake_instruction::process_instruction),
|
Entrypoint::Program(solana_stake_program::stake_instruction::process_instruction),
|
||||||
),
|
),
|
||||||
Builtin::new(
|
Builtin::new(
|
||||||
"vote_program",
|
"config_program",
|
||||||
solana_vote_program::id(),
|
solana_config_program::id(),
|
||||||
Entrypoint::Program(solana_vote_program::vote_instruction::process_instruction),
|
Entrypoint::Program(solana_config_program::config_processor::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 activated dynamically by feature
|
/// Builtin programs activated dynamically by feature
|
||||||
pub fn get_feature_builtins() -> Vec<(Builtin, Pubkey)> {
|
fn feature_builtins() -> Vec<(Builtin, Pubkey)> {
|
||||||
vec![(
|
vec![(
|
||||||
Builtin::new(
|
Builtin::new(
|
||||||
"secp256k1_program",
|
"secp256k1_program",
|
||||||
@ -81,108 +42,9 @@ pub fn get_feature_builtins() -> Vec<(Builtin, Pubkey)> {
|
|||||||
)]
|
)]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
pub(crate) fn get() -> Builtins {
|
||||||
mod tests {
|
Builtins {
|
||||||
use super::*;
|
genesis_builtins: genesis_builtins(),
|
||||||
use crate::bank::Bank;
|
feature_builtins: feature_builtins(),
|
||||||
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,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,10 @@ pub mod spl_token_v2_multisig_fix {
|
|||||||
solana_sdk::declare_id!("E5JiFDQCwyC6QfT9REFyMpfK2mHcmv1GUDySU1Ue7TYv");
|
solana_sdk::declare_id!("E5JiFDQCwyC6QfT9REFyMpfK2mHcmv1GUDySU1Ue7TYv");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod bpf_loader2_program {
|
||||||
|
solana_sdk::declare_id!("DFBnrgThdzH4W6wZ12uGPoWcMnvfZj11EHnxHcVxLPhD");
|
||||||
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// Map of feature identifiers to user-visible description
|
/// Map of feature identifiers to user-visible description
|
||||||
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
||||||
@ -33,6 +37,7 @@ lazy_static! {
|
|||||||
(consistent_recent_blockhashes_sysvar::id(), "consistent recentblockhashes sysvar"),
|
(consistent_recent_blockhashes_sysvar::id(), "consistent recentblockhashes sysvar"),
|
||||||
(pico_inflation::id(), "pico-inflation"),
|
(pico_inflation::id(), "pico-inflation"),
|
||||||
(spl_token_v2_multisig_fix::id(), "spl-token multisig fix"),
|
(spl_token_v2_multisig_fix::id(), "spl-token multisig fix"),
|
||||||
|
(bpf_loader2_program::id(), "bpf_loader2 program"),
|
||||||
/*************** ADD NEW FEATURES HERE ***************/
|
/*************** ADD NEW FEATURES HERE ***************/
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -53,6 +53,20 @@ pub fn create_genesis_config_with_vote_accounts(
|
|||||||
mint_lamports: u64,
|
mint_lamports: u64,
|
||||||
voting_keypairs: &[impl Borrow<ValidatorVoteKeypairs>],
|
voting_keypairs: &[impl Borrow<ValidatorVoteKeypairs>],
|
||||||
stakes: Vec<u64>,
|
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 {
|
) -> GenesisConfigInfo {
|
||||||
assert!(!voting_keypairs.is_empty());
|
assert!(!voting_keypairs.is_empty());
|
||||||
assert_eq!(voting_keypairs.len(), stakes.len());
|
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(),
|
&voting_keypairs[0].borrow().stake_keypair.pubkey(),
|
||||||
stakes[0],
|
stakes[0],
|
||||||
BOOTSTRAP_VALIDATOR_LAMPORTS,
|
BOOTSTRAP_VALIDATOR_LAMPORTS,
|
||||||
|
cluster_type,
|
||||||
);
|
);
|
||||||
|
|
||||||
for (validator_voting_keypairs, stake) in voting_keypairs[1..].iter().zip(&stakes[1..]) {
|
for (validator_voting_keypairs, stake) in voting_keypairs[1..].iter().zip(&stakes[1..]) {
|
||||||
@ -105,11 +120,11 @@ pub fn create_genesis_config_with_leader(
|
|||||||
&Pubkey::new_rand(),
|
&Pubkey::new_rand(),
|
||||||
bootstrap_validator_stake_lamports,
|
bootstrap_validator_stake_lamports,
|
||||||
BOOTSTRAP_VALIDATOR_LAMPORTS,
|
BOOTSTRAP_VALIDATOR_LAMPORTS,
|
||||||
|
ClusterType::Development,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_feature_accounts(genesis_config: &mut GenesisConfig) {
|
pub fn activate_all_features(genesis_config: &mut GenesisConfig) {
|
||||||
if genesis_config.cluster_type == ClusterType::Development {
|
|
||||||
// Activate all features at genesis in development mode
|
// Activate all features at genesis in development mode
|
||||||
for feature_id in FeatureSet::default().inactive {
|
for feature_id in FeatureSet::default().inactive {
|
||||||
let feature = Feature {
|
let feature = Feature {
|
||||||
@ -123,7 +138,6 @@ pub fn add_feature_accounts(genesis_config: &mut GenesisConfig) {
|
|||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_genesis_config_with_leader_ex(
|
pub fn create_genesis_config_with_leader_ex(
|
||||||
@ -133,6 +147,7 @@ pub fn create_genesis_config_with_leader_ex(
|
|||||||
bootstrap_validator_staking_pubkey: &Pubkey,
|
bootstrap_validator_staking_pubkey: &Pubkey,
|
||||||
bootstrap_validator_stake_lamports: u64,
|
bootstrap_validator_stake_lamports: u64,
|
||||||
bootstrap_validator_lamports: u64,
|
bootstrap_validator_lamports: u64,
|
||||||
|
cluster_type: ClusterType,
|
||||||
) -> GenesisConfigInfo {
|
) -> GenesisConfigInfo {
|
||||||
let mint_keypair = Keypair::new();
|
let mint_keypair = Keypair::new();
|
||||||
let bootstrap_validator_vote_account = vote_state::create_account(
|
let bootstrap_validator_vote_account = vote_state::create_account(
|
||||||
@ -179,11 +194,14 @@ pub fn create_genesis_config_with_leader_ex(
|
|||||||
accounts,
|
accounts,
|
||||||
fee_rate_governor,
|
fee_rate_governor,
|
||||||
rent,
|
rent,
|
||||||
|
cluster_type,
|
||||||
..GenesisConfig::default()
|
..GenesisConfig::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
solana_stake_program::add_genesis_accounts(&mut genesis_config);
|
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 {
|
GenesisConfigInfo {
|
||||||
genesis_config,
|
genesis_config,
|
||||||
|
@ -759,16 +759,6 @@ impl MessageProcessor {
|
|||||||
}
|
}
|
||||||
Ok(())
|
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)]
|
#[cfg(test)]
|
||||||
|
@ -4,7 +4,7 @@ use {
|
|||||||
accounts_db::{AccountStorageEntry, AccountsDB, AppendVecId, BankHashInfo},
|
accounts_db::{AccountStorageEntry, AccountsDB, AppendVecId, BankHashInfo},
|
||||||
accounts_index::Ancestors,
|
accounts_index::Ancestors,
|
||||||
append_vec::AppendVec,
|
append_vec::AppendVec,
|
||||||
bank::{Bank, BankFieldsToDeserialize, BankRc},
|
bank::{Bank, BankFieldsToDeserialize, BankRc, Builtins},
|
||||||
blockhash_queue::BlockhashQueue,
|
blockhash_queue::BlockhashQueue,
|
||||||
epoch_stakes::EpochStakes,
|
epoch_stakes::EpochStakes,
|
||||||
message_processor::MessageProcessor,
|
message_processor::MessageProcessor,
|
||||||
@ -125,6 +125,7 @@ pub(crate) fn bank_from_stream<R, P>(
|
|||||||
genesis_config: &GenesisConfig,
|
genesis_config: &GenesisConfig,
|
||||||
frozen_account_pubkeys: &[Pubkey],
|
frozen_account_pubkeys: &[Pubkey],
|
||||||
debug_keys: Option<Arc<HashSet<Pubkey>>>,
|
debug_keys: Option<Arc<HashSet<Pubkey>>>,
|
||||||
|
additional_builtins: Option<&Builtins>,
|
||||||
) -> std::result::Result<Bank, Error>
|
) -> std::result::Result<Bank, Error>
|
||||||
where
|
where
|
||||||
R: Read,
|
R: Read,
|
||||||
@ -142,6 +143,7 @@ where
|
|||||||
account_paths,
|
account_paths,
|
||||||
append_vecs_path,
|
append_vecs_path,
|
||||||
debug_keys,
|
debug_keys,
|
||||||
|
additional_builtins,
|
||||||
)?;
|
)?;
|
||||||
Ok(bank)
|
Ok(bank)
|
||||||
}};
|
}};
|
||||||
@ -227,6 +229,7 @@ fn reconstruct_bank_from_fields<E, P>(
|
|||||||
account_paths: &[PathBuf],
|
account_paths: &[PathBuf],
|
||||||
append_vecs_path: P,
|
append_vecs_path: P,
|
||||||
debug_keys: Option<Arc<HashSet<Pubkey>>>,
|
debug_keys: Option<Arc<HashSet<Pubkey>>>,
|
||||||
|
additional_builtins: Option<&Builtins>,
|
||||||
) -> Result<Bank, Error>
|
) -> Result<Bank, Error>
|
||||||
where
|
where
|
||||||
E: Into<AccountStorageEntry>,
|
E: Into<AccountStorageEntry>,
|
||||||
@ -241,7 +244,13 @@ where
|
|||||||
accounts_db.freeze_accounts(&bank_fields.ancestors, frozen_account_pubkeys);
|
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_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)
|
Ok(bank)
|
||||||
}
|
}
|
||||||
|
@ -212,6 +212,7 @@ fn test_bank_serialize_style(serde_style: SerdeStyle) {
|
|||||||
&genesis_config,
|
&genesis_config,
|
||||||
&[],
|
&[],
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
dbank.src = ref_sc;
|
dbank.src = ref_sc;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
bank::{Bank, BankSlotDelta},
|
bank::{Bank, BankSlotDelta, Builtins},
|
||||||
bank_forks::CompressionType,
|
bank_forks::CompressionType,
|
||||||
hardened_unpack::{unpack_snapshot, UnpackError},
|
hardened_unpack::{unpack_snapshot, UnpackError},
|
||||||
serde_snapshot::{
|
serde_snapshot::{
|
||||||
@ -574,6 +574,7 @@ pub fn bank_from_archive<P: AsRef<Path>>(
|
|||||||
compression: CompressionType,
|
compression: CompressionType,
|
||||||
genesis_config: &GenesisConfig,
|
genesis_config: &GenesisConfig,
|
||||||
debug_keys: Option<Arc<HashSet<Pubkey>>>,
|
debug_keys: Option<Arc<HashSet<Pubkey>>>,
|
||||||
|
additional_builtins: Option<&Builtins>,
|
||||||
) -> Result<Bank> {
|
) -> Result<Bank> {
|
||||||
// Untar the snapshot into a temp directory under `snapshot_config.snapshot_path()`
|
// Untar the snapshot into a temp directory under `snapshot_config.snapshot_path()`
|
||||||
let unpack_dir = tempfile::tempdir_in(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,
|
unpacked_accounts_dir,
|
||||||
genesis_config,
|
genesis_config,
|
||||||
debug_keys,
|
debug_keys,
|
||||||
|
additional_builtins,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if !bank.verify_snapshot_bank() {
|
if !bank.verify_snapshot_bank() {
|
||||||
@ -753,6 +755,7 @@ fn rebuild_bank_from_snapshots<P>(
|
|||||||
append_vecs_path: P,
|
append_vecs_path: P,
|
||||||
genesis_config: &GenesisConfig,
|
genesis_config: &GenesisConfig,
|
||||||
debug_keys: Option<Arc<HashSet<Pubkey>>>,
|
debug_keys: Option<Arc<HashSet<Pubkey>>>,
|
||||||
|
additional_builtins: Option<&Builtins>,
|
||||||
) -> Result<Bank>
|
) -> Result<Bank>
|
||||||
where
|
where
|
||||||
P: AsRef<Path>,
|
P: AsRef<Path>,
|
||||||
@ -785,6 +788,7 @@ where
|
|||||||
genesis_config,
|
genesis_config,
|
||||||
frozen_account_pubkeys,
|
frozen_account_pubkeys,
|
||||||
debug_keys,
|
debug_keys,
|
||||||
|
additional_builtins,
|
||||||
),
|
),
|
||||||
}?)
|
}?)
|
||||||
})?;
|
})?;
|
||||||
|
Reference in New Issue
Block a user