Switch programs activation to whole-set based gating (#11750)
* Implement Debug for MessageProcessor * Switch from delta-based gating to whole-set gating * Remove dbg! * Fix clippy * Clippy * Add test * add loader to stable operating mode at proper epoch * refresh_programs_and_inflation after ancestor setup * Callback via snapshot; avoid account re-add; Debug * Fix test * Fix test and fix the past history * Make callback management stricter and cleaner * Fix test * Test overwrite and frozen for native programs * Test epoch callback with genesis-programs * Add assertions for parent bank * Add tests and some minor cleaning * Remove unsteady assertion... * Fix test... * Fix DOS * Skip ensuring account by dual (whole/delta) gating * Fix frozen abi implementation... * Move compute budget constatnt init back into bank Co-authored-by: Ryo Onodera <ryoqun@gmail.com>
This commit is contained in:
@@ -8,13 +8,13 @@ extern crate solana_exchange_program;
|
||||
extern crate solana_vest_program;
|
||||
|
||||
use log::*;
|
||||
use solana_runtime::{
|
||||
bank::{Bank, EnteredEpochCallback},
|
||||
message_processor::{DEFAULT_COMPUTE_BUDGET, DEFAULT_MAX_INVOKE_DEPTH},
|
||||
};
|
||||
use solana_runtime::bank::{Bank, EnteredEpochCallback};
|
||||
use solana_sdk::{
|
||||
clock::Epoch, entrypoint_native::ProcessInstructionWithContext, genesis_config::OperatingMode,
|
||||
inflation::Inflation, pubkey::Pubkey,
|
||||
clock::{Epoch, GENESIS_EPOCH},
|
||||
entrypoint_native::{ErasedProcessInstructionWithContext, ProcessInstructionWithContext},
|
||||
genesis_config::OperatingMode,
|
||||
inflation::Inflation,
|
||||
pubkey::Pubkey,
|
||||
};
|
||||
|
||||
pub fn get_inflation(operating_mode: OperatingMode, epoch: Epoch) -> Option<Inflation> {
|
||||
@@ -52,79 +52,114 @@ enum Program {
|
||||
BuiltinLoader((String, Pubkey, ProcessInstructionWithContext)),
|
||||
}
|
||||
|
||||
fn get_programs(operating_mode: OperatingMode, epoch: Epoch) -> Option<Vec<Program>> {
|
||||
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 operating_mode and epoch, return the entire set of enabled programs
|
||||
fn get_programs(operating_mode: OperatingMode) -> Vec<(Program, Epoch)> {
|
||||
let mut programs = vec![];
|
||||
|
||||
match operating_mode {
|
||||
OperatingMode::Development => {
|
||||
if epoch == 0 {
|
||||
// Programs used for testing
|
||||
Some(vec![
|
||||
// Programs used for testing
|
||||
programs.extend(
|
||||
vec![
|
||||
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!()),
|
||||
])
|
||||
} else if epoch == std::u64::MAX {
|
||||
// The epoch of std::u64::MAX is a placeholder and is expected
|
||||
// to be reduced in a future network update.
|
||||
Some(vec![Program::BuiltinLoader(solana_bpf_loader_program!())])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
OperatingMode::Stable => {
|
||||
if epoch == std::u64::MAX {
|
||||
// The epoch of std::u64::MAX is a placeholder and is expected
|
||||
// to be reduced in a future network update.
|
||||
Some(vec![
|
||||
Program::BuiltinLoader(solana_bpf_loader_program!()),
|
||||
Program::Native(solana_vest_program!()),
|
||||
])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
]
|
||||
.into_iter()
|
||||
.map(|program| (program, 0))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
OperatingMode::Preview => {
|
||||
if epoch == std::u64::MAX {
|
||||
// The epoch of std::u64::MAX is a placeholder and is expected
|
||||
// to be reduced in a future network update.
|
||||
Some(vec![
|
||||
// tds enabled async cluster restart with smart contract being enabled
|
||||
// at slot 2196960 (midway epoch 17) with v1.0.1 on Mar 1, 2020
|
||||
programs.extend(vec![(
|
||||
Program::BuiltinLoader(solana_bpf_loader_deprecated_program!()),
|
||||
17,
|
||||
)]);
|
||||
// The epoch of Epoch::max_value() is a placeholder and is expected
|
||||
// to be reduced in a future network update.
|
||||
programs.extend(
|
||||
vec![
|
||||
Program::BuiltinLoader(solana_bpf_loader_program!()),
|
||||
Program::Native(solana_vest_program!()),
|
||||
])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
]
|
||||
.into_iter()
|
||||
.map(|program| (program, Epoch::MAX))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
}
|
||||
OperatingMode::Stable => {
|
||||
programs.extend(vec![(
|
||||
Program::BuiltinLoader(solana_bpf_loader_deprecated_program!()),
|
||||
34,
|
||||
)]);
|
||||
// The epoch of std::u64::MAX is a placeholder and is expected
|
||||
// to be reduced in a future network update.
|
||||
programs.extend(
|
||||
vec![
|
||||
Program::BuiltinLoader(solana_bpf_loader_program!()),
|
||||
Program::Native(solana_vest_program!()),
|
||||
]
|
||||
.into_iter()
|
||||
.map(|program| (program, Epoch::MAX))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
programs
|
||||
}
|
||||
|
||||
pub fn get_native_programs(
|
||||
operating_mode: OperatingMode,
|
||||
epoch: Epoch,
|
||||
) -> Option<Vec<(String, Pubkey)>> {
|
||||
match get_programs(operating_mode, epoch) {
|
||||
Some(programs) => {
|
||||
let mut native_programs = vec![];
|
||||
for program in programs {
|
||||
if let Program::Native((string, key)) = program {
|
||||
native_programs.push((string, key));
|
||||
}
|
||||
pub fn get_native_programs_for_genesis(operating_mode: OperatingMode) -> Vec<(String, Pubkey)> {
|
||||
let mut native_programs = vec![];
|
||||
for (program, start_epoch) in get_programs(operating_mode) {
|
||||
if let Program::Native((string, key)) = program {
|
||||
if start_epoch == GENESIS_EPOCH {
|
||||
native_programs.push((string, key));
|
||||
}
|
||||
Some(native_programs)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
native_programs
|
||||
}
|
||||
|
||||
pub fn get_entered_epoch_callback(operating_mode: OperatingMode) -> EnteredEpochCallback {
|
||||
Box::new(move |bank: &mut Bank| {
|
||||
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
|
||||
|
||||
if let Some(inflation) = get_inflation(operating_mode, bank.epoch()) {
|
||||
info!("Entering new epoch with inflation {:?}", inflation);
|
||||
bank.set_inflation(inflation);
|
||||
}
|
||||
if let Some(programs) = get_programs(operating_mode, bank.epoch()) {
|
||||
for program in programs {
|
||||
for (program, start_epoch) in get_programs(operating_mode) {
|
||||
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);
|
||||
@@ -143,14 +178,6 @@ pub fn get_entered_epoch_callback(operating_mode: OperatingMode) -> EnteredEpoch
|
||||
}
|
||||
}
|
||||
}
|
||||
if OperatingMode::Stable == operating_mode {
|
||||
bank.set_cross_program_support(bank.epoch() >= 63);
|
||||
} else {
|
||||
bank.set_cross_program_support(true);
|
||||
}
|
||||
|
||||
bank.set_max_invoke_depth(DEFAULT_MAX_INVOKE_DEPTH);
|
||||
bank.set_compute_budget(DEFAULT_COMPUTE_BUDGET);
|
||||
})
|
||||
}
|
||||
|
||||
@@ -162,8 +189,8 @@ mod tests {
|
||||
#[test]
|
||||
fn test_id_uniqueness() {
|
||||
let mut unique = HashSet::new();
|
||||
let programs = get_programs(OperatingMode::Development, 0).unwrap();
|
||||
for program in programs {
|
||||
let programs = get_programs(OperatingMode::Development);
|
||||
for (program, _start_epoch) in programs {
|
||||
match program {
|
||||
Program::Native((name, id)) => assert!(unique.insert((name, id))),
|
||||
Program::BuiltinLoader((name, id, _)) => assert!(unique.insert((name, id))),
|
||||
@@ -182,22 +209,15 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_development_programs() {
|
||||
assert_eq!(
|
||||
get_programs(OperatingMode::Development, 0).unwrap().len(),
|
||||
5
|
||||
);
|
||||
assert!(get_programs(OperatingMode::Development, 1).is_none());
|
||||
assert_eq!(get_programs(OperatingMode::Development).len(), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_native_development_programs() {
|
||||
assert_eq!(
|
||||
get_native_programs(OperatingMode::Development, 0)
|
||||
.unwrap()
|
||||
.len(),
|
||||
get_native_programs_for_genesis(OperatingMode::Development).len(),
|
||||
3
|
||||
);
|
||||
assert!(get_native_programs(OperatingMode::Development, 1).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -215,7 +235,6 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_softlaunch_programs() {
|
||||
assert!(get_programs(OperatingMode::Stable, 1).is_none());
|
||||
assert!(get_programs(OperatingMode::Stable, std::u64::MAX).is_some());
|
||||
assert!(!get_programs(OperatingMode::Stable).is_empty());
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user