Make default programs static (#9717)

This commit is contained in:
Jack May
2020-04-27 21:05:12 -07:00
committed by GitHub
parent 193dbb1794
commit efad193180
34 changed files with 134 additions and 173 deletions

View File

@ -27,6 +27,7 @@ rand = "0.6.5"
rayon = "1.3.0"
serde = { version = "1.0.106", features = ["rc"] }
serde_derive = "1.0.103"
solana-config-program = { path = "../programs/config", version = "1.2.0" }
solana-logger = { path = "../logger", version = "1.2.0" }
solana-measure = { path = "../measure", version = "1.2.0" }
solana-metrics = { path = "../metrics", version = "1.2.0" }
@ -38,7 +39,6 @@ solana-vote-program = { path = "../programs/vote", version = "1.2.0" }
tempfile = "3.1.0"
thiserror = "1.0"
[lib]
crate-type = ["lib"]
name = "solana_runtime"

View File

@ -122,11 +122,12 @@ fn do_bench_transactions(
let (mut genesis_config, mint_keypair) = create_genesis_config(100_000_000);
genesis_config.ticks_per_slot = 100;
let mut bank = Bank::new(&genesis_config);
bank.add_instruction_processor(Pubkey::new(&BUILTIN_PROGRAM_ID), process_instruction);
bank.register_native_instruction_processor(
"solana_noop_program",
&Pubkey::new(&NOOP_PROGRAM_ID),
bank.add_static_program(
"builtin_program",
Pubkey::new(&BUILTIN_PROGRAM_ID),
process_instruction,
);
bank.add_native_program("solana_noop_program", &Pubkey::new(&NOOP_PROGRAM_ID));
let bank = Arc::new(bank);
let bank_client = BankClient::new_shared(&bank);
let transactions = create_transactions(&bank_client, &mint_keypair);

View File

@ -18,7 +18,7 @@ use crate::{
status_cache::{SlotDelta, StatusCache},
storage_utils,
storage_utils::StorageAccounts,
system_instruction_processor::{get_system_account_kind, SystemAccountKind},
system_instruction_processor::{self, get_system_account_kind, SystemAccountKind},
transaction_batch::TransactionBatch,
transaction_utils::OrderedIterator,
};
@ -375,6 +375,7 @@ impl Bank {
bank.rc.accounts = Arc::new(Accounts::new(paths));
bank.process_genesis_config(genesis_config);
bank.finish_init();
// Freeze accounts after process_genesis_config creates the initial append vecs
Arc::get_mut(&mut bank.rc.accounts)
@ -457,7 +458,7 @@ impl Bank {
is_delta: AtomicBool::new(false),
tick_height: AtomicU64::new(parent.tick_height.load(Ordering::Relaxed)),
signature_count: AtomicU64::new(0),
message_processor: MessageProcessor::default(),
message_processor: parent.message_processor.clone(),
entered_epoch_callback: parent.entered_epoch_callback.clone(),
hard_forks: parent.hard_forks.clone(),
last_vote_sync: AtomicU64::new(parent.last_vote_sync.load(Ordering::Relaxed)),
@ -904,14 +905,14 @@ impl Bank {
// Add additional native programs specified in the genesis config
for (name, program_id) in &genesis_config.native_instruction_processors {
self.register_native_instruction_processor(name, program_id);
self.add_native_program(name, program_id);
}
}
pub fn register_native_instruction_processor(&self, name: &str, program_id: &Pubkey) {
debug!("Adding native program {} under {:?}", name, program_id);
pub fn add_native_program(&self, name: &str, program_id: &Pubkey) {
let account = native_loader::create_loadable_account(name);
self.store_account(program_id, &account);
debug!("Added native program {} under {:?}", name, program_id);
}
/// Return the last block hash registered.
@ -1765,6 +1766,29 @@ impl Bank {
self.src = status_cache_rc;
}
pub fn finish_init(&mut self) {
self.add_static_program(
"system_program",
solana_sdk::system_program::id(),
system_instruction_processor::process_instruction,
);
self.add_static_program(
"config_program",
solana_config_program::id(),
solana_config_program::config_processor::process_instruction,
);
self.add_static_program(
"stake_program",
solana_stake_program::id(),
solana_stake_program::stake_instruction::process_instruction,
);
self.add_static_program(
"vote_program",
solana_vote_program::id(),
solana_vote_program::vote_instruction::process_instruction,
);
}
pub fn set_parent(&mut self, parent: &Arc<Bank>) {
self.rc.parent = RwLock::new(Some(parent.clone()));
}
@ -2148,21 +2172,29 @@ impl Bank {
}
/// Add an instruction processor to intercept instructions before the dynamic loader.
pub fn add_instruction_processor(
pub fn add_static_program(
&mut self,
name: &str,
program_id: Pubkey,
process_instruction: ProcessInstruction,
) {
match self.get_account(&program_id) {
Some(account) => {
assert_eq!(
account.owner,
native_loader::id(),
"Cannot overwrite non-native loader account"
);
}
None => {
// Add a bogus executable native account, which will be loaded and ignored.
let account = native_loader::create_loadable_account(name);
self.store_account(&program_id, &account);
}
}
self.message_processor
.add_instruction_processor(program_id, process_instruction);
if let Some(program_account) = self.get_account(&program_id) {
// It is not valid to intercept instructions for a non-native loader account
assert_eq!(program_account.owner, solana_sdk::native_loader::id());
} else {
// Register a bogus executable account, which will be loaded and ignored.
self.register_native_instruction_processor("", &program_id);
}
debug!("Added static program {} under {:?}", name, program_id);
}
pub fn compare_bank(&self, dbank: &Bank) {
@ -2274,8 +2306,7 @@ mod tests {
poh_config::PohConfig,
rent::Rent,
signature::{Keypair, Signer},
system_instruction,
system_program::{self, solana_system_program},
system_instruction, system_program,
sysvar::{fees::Fees, rewards::Rewards},
timing::duration_as_s,
};
@ -2532,7 +2563,7 @@ mod tests {
bank_with_success_txs.store_account(&keypair6.pubkey(), &account6);
// Make native instruction loader rent exempt
let system_program_id = solana_system_program().1;
let system_program_id = system_program::id();
let mut system_program_account = bank.get_account(&system_program_id).unwrap();
system_program_account.lamports =
bank.get_minimum_balance_for_rent_exemption(system_program_account.data.len());
@ -2730,7 +2761,7 @@ mod tests {
) as u64,
);
bank.rent_collector.slots_per_year = 421_812.0;
bank.add_instruction_processor(mock_program_id, mock_process_instruction);
bank.add_static_program("mock_program", mock_program_id, mock_process_instruction);
bank
}
@ -5020,28 +5051,35 @@ mod tests {
}
#[test]
fn test_add_instruction_processor() {
fn test_add_static_program() {
let (genesis_config, mint_keypair) = create_genesis_config(500);
let mut bank = Bank::new(&genesis_config);
fn mock_vote_program_id() -> Pubkey {
Pubkey::new(&[42u8; 32])
}
fn mock_vote_processor(
program_id: &Pubkey,
_keyed_accounts: &[KeyedAccount],
_instruction_data: &[u8],
) -> std::result::Result<(), InstructionError> {
if !solana_vote_program::check_id(program_id) {
if mock_vote_program_id() != *program_id {
return Err(InstructionError::IncorrectProgramId);
}
Err(InstructionError::Custom(42))
}
assert!(bank.get_account(&solana_vote_program::id()).is_none());
bank.add_instruction_processor(solana_vote_program::id(), mock_vote_processor);
assert!(bank.get_account(&solana_vote_program::id()).is_some());
assert!(bank.get_account(&mock_vote_program_id()).is_none());
bank.add_static_program(
"mock_vote_program",
mock_vote_program_id(),
mock_vote_processor,
);
assert!(bank.get_account(&mock_vote_program_id()).is_some());
let mock_account = Keypair::new();
let mock_validator_identity = Keypair::new();
let instructions = vote_instruction::create_account(
let mut instructions = vote_instruction::create_account(
&mint_keypair.pubkey(),
&mock_account.pubkey(),
&VoteInit {
@ -5050,6 +5088,7 @@ mod tests {
},
1,
);
instructions[1].program_id = mock_vote_program_id();
let transaction = Transaction::new_signed_instructions(
&[&mint_keypair, &mock_account, &mock_validator_identity],
@ -5067,13 +5106,12 @@ mod tests {
}
#[test]
fn test_add_instruction_processor_for_existing_program() {
fn test_add_duplicate_static_program() {
let GenesisConfigInfo {
genesis_config,
mint_keypair,
..
} = create_genesis_config_with_leader(500, &Pubkey::new_rand(), 0);
let mut bank = Bank::new(&genesis_config);
fn mock_vote_processor(
@ -5103,7 +5141,11 @@ mod tests {
);
let vote_loader_account = bank.get_account(&solana_vote_program::id()).unwrap();
bank.add_instruction_processor(solana_vote_program::id(), mock_vote_processor);
bank.add_static_program(
"solana_vote_program",
solana_vote_program::id(),
mock_vote_processor,
);
let new_vote_loader_account = bank.get_account(&solana_vote_program::id()).unwrap();
// Vote loader account should not be updated since it was included in the genesis config.
assert_eq!(vote_loader_account.data, new_vote_loader_account.data);
@ -5131,7 +5173,7 @@ mod tests {
}
// Non-native loader accounts can not be used for instruction processing
bank.add_instruction_processor(mint_keypair.pubkey(), mock_ix_processor);
bank.add_static_program("mock_program", mint_keypair.pubkey(), mock_ix_processor);
}
#[test]
fn test_recent_blockhashes_sysvar() {
@ -5150,6 +5192,7 @@ mod tests {
bank = Arc::new(new_from_parent(&bank));
}
}
#[test]
fn test_bank_inherit_last_vote_sync() {
let (genesis_config, _) = create_genesis_config(500);
@ -5690,7 +5733,7 @@ mod tests {
}
let mock_program_id = Pubkey::new(&[2u8; 32]);
bank.add_instruction_processor(mock_program_id, mock_process_instruction);
bank.add_static_program("mock_program", mock_program_id, mock_process_instruction);
let from_pubkey = Pubkey::new_rand();
let to_pubkey = Pubkey::new_rand();
@ -5733,7 +5776,7 @@ mod tests {
}
let mock_program_id = Pubkey::new(&[2u8; 32]);
bank.add_instruction_processor(mock_program_id, mock_process_instruction);
bank.add_static_program("mock_program", mock_program_id, mock_process_instruction);
let from_pubkey = Pubkey::new_rand();
let to_pubkey = Pubkey::new_rand();

View File

@ -5,7 +5,7 @@ use solana_sdk::{
pubkey::Pubkey,
rent::Rent,
signature::{Keypair, Signer},
system_program::{self, solana_system_program},
system_program,
};
use solana_stake_program::stake_state;
use solana_vote_program::vote_state;
@ -133,17 +133,9 @@ pub fn create_genesis_config_with_leader_ex(
.cloned()
.collect();
// Bare minimum program set
let native_instruction_processors = vec![
solana_system_program(),
solana_vote_program!(),
solana_stake_program!(),
];
let fee_rate_governor = FeeRateGovernor::new(0, 0); // most tests can't handle transaction fees
let mut genesis_config = GenesisConfig {
accounts,
native_instruction_processors,
fee_rate_governor,
rent,
..GenesisConfig::default()

View File

@ -21,15 +21,12 @@ mod system_instruction_processor;
pub mod transaction_batch;
pub mod transaction_utils;
#[macro_use]
extern crate solana_metrics;
#[macro_use]
extern crate solana_config_program;
extern crate solana_stake_program;
extern crate solana_vote_program;
#[macro_use]
extern crate solana_stake_program;
extern crate solana_metrics;
#[macro_use]
extern crate serde_derive;

View File

@ -1,6 +1,4 @@
use crate::{
native_loader::NativeLoader, rent_collector::RentCollector, system_instruction_processor,
};
use crate::{native_loader::NativeLoader, rent_collector::RentCollector};
use serde::{Deserialize, Serialize};
use solana_sdk::{
account::{create_keyed_readonly_accounts, Account, KeyedAccount},
@ -161,20 +159,17 @@ impl PreAccount {
pub type ProcessInstruction = fn(&Pubkey, &[KeyedAccount], &[u8]) -> Result<(), InstructionError>;
#[derive(Serialize, Deserialize)]
#[derive(Default, Deserialize, Serialize)]
pub struct MessageProcessor {
#[serde(skip)]
instruction_processors: Vec<(Pubkey, ProcessInstruction)>,
#[serde(skip)]
native_loader: NativeLoader,
}
impl Default for MessageProcessor {
fn default() -> Self {
Self {
instruction_processors: vec![(
system_program::id(),
system_instruction_processor::process_instruction,
)],
impl Clone for MessageProcessor {
fn clone(&self) -> Self {
MessageProcessor {
instruction_processors: self.instruction_processors.clone(),
native_loader: NativeLoader::default(),
}
}
@ -186,8 +181,16 @@ impl MessageProcessor {
program_id: Pubkey,
process_instruction: ProcessInstruction,
) {
self.instruction_processors
.push((program_id, process_instruction));
match self
.instruction_processors
.iter_mut()
.find(|(key, _)| program_id == *key)
{
Some((_, processor)) => *processor = process_instruction,
None => self
.instruction_processors
.push((program_id, process_instruction)),
}
}
/// Process an instruction

View File

@ -103,7 +103,8 @@ pub(crate) mod tests {
let validator_keypair = Keypair::new();
let validator_pubkey = validator_keypair.pubkey();
let mut bank = Bank::new(&genesis_config);
bank.add_instruction_processor(
bank.add_static_program(
"storage_program",
solana_storage_program::id(),
storage_processor::process_instruction,
);

View File

@ -12,7 +12,7 @@ fn test_program_native_noop() {
let (genesis_config, alice_keypair) = create_genesis_config(50);
let program_id = Pubkey::new_rand();
let bank = Bank::new(&genesis_config);
bank.register_native_instruction_processor("solana_noop_program", &program_id);
bank.add_native_program("solana_noop_program", &program_id);
// Call user program
let instruction = create_invoke_instruction(alice_keypair.pubkey(), program_id, &1u8);

View File

@ -100,13 +100,10 @@ fn test_stake_create_and_split_single_signature() {
solana_logger::setup();
let GenesisConfigInfo {
mut genesis_config,
genesis_config,
mint_keypair: staker_keypair,
..
} = create_genesis_config_with_leader(100_000_000_000, &Pubkey::new_rand(), 1_000_000);
genesis_config
.native_instruction_processors
.push(solana_stake_program::solana_stake_program!());
let staker_pubkey = staker_keypair.pubkey();
@ -166,13 +163,10 @@ fn test_stake_account_lifetime() {
let identity_pubkey = identity_keypair.pubkey();
let GenesisConfigInfo {
mut genesis_config,
genesis_config,
mint_keypair,
..
} = create_genesis_config_with_leader(100_000_000_000, &Pubkey::new_rand(), 1_000_000);
genesis_config
.native_instruction_processors
.push(solana_stake_program::solana_stake_program!());
let bank = Bank::new(&genesis_config);
let mint_pubkey = mint_keypair.pubkey();
let mut bank = Arc::new(bank);
@ -403,13 +397,10 @@ fn test_create_stake_account_from_seed() {
let identity_pubkey = identity_keypair.pubkey();
let GenesisConfigInfo {
mut genesis_config,
genesis_config,
mint_keypair,
..
} = create_genesis_config_with_leader(100_000_000_000, &Pubkey::new_rand(), 1_000_000);
genesis_config
.native_instruction_processors
.push(solana_stake_program::solana_stake_program!());
let bank = Bank::new(&genesis_config);
let mint_pubkey = mint_keypair.pubkey();
let bank = Arc::new(bank);

View File

@ -45,7 +45,7 @@ fn test_account_owner() {
} = create_genesis_config(1000);
let mut bank = Bank::new(&genesis_config);
let mint_pubkey = mint_keypair.pubkey();
bank.add_instruction_processor(id(), process_instruction);
bank.add_static_program("storage_program", id(), process_instruction);
let bank = Arc::new(bank);
let bank_client = BankClient::new_shared(&bank);