Skip to content

Commit

Permalink
Switch programs activation to whole-set based gating (#11750)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
jackcmay and ryoqun authored Aug 25, 2020
1 parent 2c5366f commit db4bbb3
Show file tree
Hide file tree
Showing 10 changed files with 760 additions and 175 deletions.
167 changes: 93 additions & 74 deletions genesis-programs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down Expand Up @@ -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
}
]
.into_iter()
.map(|program| (program, 0))
.collect::<Vec<_>>(),
);
}
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![
OperatingMode::Preview => {
// 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::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![
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!()),
])
} else {
None
}
]
.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);
Expand All @@ -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);
})
}

Expand All @@ -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))),
Expand All @@ -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]
Expand All @@ -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());
}
}
2 changes: 1 addition & 1 deletion genesis/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
);

let native_instruction_processors =
solana_genesis_programs::get_native_programs(operating_mode, 0).unwrap_or_else(Vec::new);
solana_genesis_programs::get_native_programs_for_genesis(operating_mode);
let inflation = solana_genesis_programs::get_inflation(operating_mode, 0).unwrap();

let mut genesis_config = GenesisConfig {
Expand Down
Loading

0 comments on commit db4bbb3

Please sign in to comment.