Refactoring - Remove redundant definition of `BuiltinProgram` (#31429)

* Replaces BuiltinProgram in the program-runtime with the one from solana_rbpf.

* Adjusts the runtimes built-ins to use Arc<LoadedProgram>.

* Adjusts the tests and benchmarks.
This commit is contained in:
Alexander Meißner 2023-05-02 23:01:28 +02:00 committed by GitHub
parent 9b547fe9f8
commit ae75c7cb3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 285 additions and 213 deletions

View File

@ -1809,7 +1809,7 @@ pub mod tests {
matches::assert_matches,
rand::{thread_rng, Rng},
solana_entry::entry::{create_ticks, next_entry, next_entry_mut},
solana_program_runtime::declare_process_instruction,
solana_program_runtime::{builtin_program::create_builtin, declare_process_instruction},
solana_runtime::{
genesis_utils::{
self, create_genesis_config_with_vote_accounts, ValidatorVoteKeypairs,
@ -2971,7 +2971,10 @@ pub mod tests {
let mock_program_id = solana_sdk::pubkey::new_rand();
let mut bank = Bank::new_for_tests(&genesis_config);
bank.add_builtin("mock_processor", &mock_program_id, mock_processor_ok);
bank.add_builtin(
mock_program_id,
create_builtin("mockup".to_string(), mock_processor_ok),
);
let tx = Transaction::new_signed_with_payer(
&[Instruction::new_with_bincode(
@ -3012,7 +3015,10 @@ pub mod tests {
(0..get_instruction_errors().len()).for_each(|err| {
let mut bank = Bank::new_for_tests(&genesis_config);
bank.add_builtin("mock_processor", &mock_program_id, mock_processor_err);
bank.add_builtin(
mock_program_id,
create_builtin("mockup".to_string(), mock_processor_err),
);
let tx = Transaction::new_signed_with_payer(
&[Instruction::new_with_bincode(

View File

@ -1,44 +1,28 @@
#[cfg(RUSTC_WITH_SPECIALIZATION)]
use {crate::declare_process_instruction, solana_frozen_abi::abi_example::AbiExample};
use solana_frozen_abi::abi_example::AbiExample;
use {
crate::invoke_context::InvokeContext, solana_rbpf::vm::BuiltInFunction,
crate::{invoke_context::InvokeContext, loaded_programs::LoadedProgram},
solana_rbpf::vm::{BuiltInFunction, BuiltInProgram},
solana_sdk::pubkey::Pubkey,
std::sync::Arc,
};
pub type ProcessInstructionWithContext = BuiltInFunction<InvokeContext<'static>>;
#[derive(Clone)]
pub struct BuiltinProgram {
pub name: String,
pub program_id: Pubkey,
pub process_instruction: ProcessInstructionWithContext,
}
impl std::fmt::Debug for BuiltinProgram {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Builtin [name={}, id={}]", self.name, self.program_id)
}
}
#[cfg(RUSTC_WITH_SPECIALIZATION)]
impl AbiExample for BuiltinProgram {
fn example() -> Self {
declare_process_instruction!(empty_mock_process_instruction, 1, |_invoke_context| {
// Do nothing
Ok(())
});
Self {
name: String::default(),
program_id: Pubkey::default(),
process_instruction: empty_mock_process_instruction,
}
}
pub fn create_builtin(
name: String,
process_instruction: ProcessInstructionWithContext,
) -> Arc<LoadedProgram> {
let mut program = BuiltInProgram::default();
program
.register_function_by_name("entrypoint", process_instruction)
.unwrap();
Arc::new(LoadedProgram::new_builtin(name, 0, program))
}
#[derive(Debug, Clone, Default)]
pub struct BuiltinPrograms {
pub vec: Vec<BuiltinProgram>,
pub vec: Vec<(Pubkey, Arc<LoadedProgram>)>,
}
#[cfg(RUSTC_WITH_SPECIALIZATION)]
@ -54,11 +38,10 @@ impl BuiltinPrograms {
process_instruction: ProcessInstructionWithContext,
) -> Self {
Self {
vec: vec![BuiltinProgram {
name: "mock instruction processor".to_string(),
vec: vec![(
program_id,
process_instruction,
}],
create_builtin("mockup".to_string(), process_instruction),
)],
}
}
}

View File

@ -5,6 +5,7 @@ use {
compute_budget::ComputeBudget,
executor_cache::TransactionExecutorCache,
ic_logger_msg, ic_msg,
loaded_programs::LoadedProgramType,
log_collector::LogCollector,
pre_account::PreAccount,
stable_log,
@ -40,7 +41,7 @@ use {
cell::RefCell,
fmt::{self, Debug},
rc::Rc,
sync::Arc,
sync::{atomic::Ordering, Arc},
},
};
@ -719,19 +720,29 @@ impl<'a> InvokeContext<'a> {
};
for entry in self.builtin_programs.vec.iter() {
if entry.program_id == builtin_id {
if entry.0 == builtin_id {
// The Murmur3 hash value (used by RBPF) of the string "entrypoint"
const ENTRYPOINT_KEY: u32 = 0x71E3CF81;
let process_instruction = match &entry.1.program {
LoadedProgramType::Builtin(_name, program) => program
.lookup_function(ENTRYPOINT_KEY)
.map(|(_name, process_instruction)| process_instruction),
_ => None,
}
.ok_or(InstructionError::GenericError)?;
entry.1.usage_counter.fetch_add(1, Ordering::Relaxed);
let program_id =
*instruction_context.get_last_program_key(self.transaction_context)?;
self.transaction_context
.set_return_data(program_id, Vec::new())?;
let logger = self.get_log_collector();
stable_log::program_invoke(&logger, &program_id, self.get_stack_height());
let pre_remaining_units = self.get_remaining();
let mock_config = Config::default();
let mut mock_memory_mapping = MemoryMapping::new(Vec::new(), &mock_config).unwrap();
let mut result = ProgramResult::Ok(0);
(entry.process_instruction)(
process_instruction(
// Removes lifetime tracking
unsafe { std::mem::transmute::<&mut InvokeContext, &mut InvokeContext>(self) },
0,

View File

@ -72,7 +72,7 @@ pub enum LoadedProgramType {
Typed(VerifiedExecutable<RequisiteVerifier, InvokeContext<'static>>),
#[cfg(test)]
TestLoaded,
BuiltIn(BuiltInProgram<InvokeContext<'static>>),
Builtin(String, BuiltInProgram<InvokeContext<'static>>),
}
impl Debug for LoadedProgramType {
@ -89,7 +89,9 @@ impl Debug for LoadedProgramType {
LoadedProgramType::Typed(_) => write!(f, "LoadedProgramType::Typed"),
#[cfg(test)]
LoadedProgramType::TestLoaded => write!(f, "LoadedProgramType::TestLoaded"),
LoadedProgramType::BuiltIn(_) => write!(f, "LoadedProgramType::BuiltIn"),
LoadedProgramType::Builtin(name, _) => {
write!(f, "LoadedProgramType::Builtin({name})")
}
}
}
}
@ -215,7 +217,8 @@ impl LoadedProgram {
}
/// Creates a new built-in program
pub fn new_built_in(
pub fn new_builtin(
name: String,
deployment_slot: Slot,
program: BuiltInProgram<InvokeContext<'static>>,
) -> Self {
@ -225,7 +228,7 @@ impl LoadedProgram {
effective_slot: deployment_slot.saturating_add(1),
maybe_expiration_slot: None,
usage_counter: AtomicU64::new(0),
program: LoadedProgramType::BuiltIn(program),
program: LoadedProgramType::Builtin(name, program),
}
}
@ -294,16 +297,6 @@ impl LoadedProgramsForTxBatch {
}
}
#[cfg(RUSTC_WITH_SPECIALIZATION)]
impl solana_frozen_abi::abi_example::AbiExample for LoadedPrograms {
fn example() -> Self {
// Delegate AbiExample impl to Default before going deep and stuck with
// not easily impl-able Arc<dyn Executor> due to rust's coherence issue
// This is safe because LoadedPrograms isn't serializable by definition.
Self::default()
}
}
pub enum LoadedProgramMatchCriteria {
DeployedOnOrAfterSlot(Slot),
Closed,
@ -474,7 +467,7 @@ impl LoadedPrograms {
LoadedProgramType::FailedVerification
| LoadedProgramType::Closed
| LoadedProgramType::DelayVisibility
| LoadedProgramType::BuiltIn(_) => None,
| LoadedProgramType::Builtin(_, _) => None,
})
})
.sorted_by_cached_key(|(order, (_id, program))| {
@ -561,6 +554,22 @@ impl LoadedPrograms {
}
}
#[cfg(RUSTC_WITH_SPECIALIZATION)]
impl solana_frozen_abi::abi_example::AbiExample for LoadedProgram {
fn example() -> Self {
// LoadedProgram isn't serializable by definition.
Self::default()
}
}
#[cfg(RUSTC_WITH_SPECIALIZATION)]
impl solana_frozen_abi::abi_example::AbiExample for LoadedPrograms {
fn example() -> Self {
// LoadedPrograms isn't serializable by definition.
Self::default()
}
}
#[cfg(test)]
mod tests {
use {
@ -582,7 +591,7 @@ mod tests {
fn new_test_builtin_program(deployment_slot: Slot, effective_slot: Slot) -> Arc<LoadedProgram> {
Arc::new(LoadedProgram {
program: LoadedProgramType::BuiltIn(BuiltInProgram::default()),
program: LoadedProgramType::Builtin("mockup".to_string(), BuiltInProgram::default()),
account_size: 0,
deployment_slot,
effective_slot,

View File

@ -11,7 +11,7 @@ use {
solana_banks_server::banks_server::start_local_server,
solana_bpf_loader_program::serialization::serialize_parameters,
solana_program_runtime::{
builtin_program::{BuiltinProgram, BuiltinPrograms, ProcessInstructionWithContext},
builtin_program::{create_builtin, BuiltinPrograms, ProcessInstructionWithContext},
compute_budget::ComputeBudget,
ic_msg, stable_log,
timings::ExecuteTimings,
@ -692,11 +692,10 @@ impl ProgramTest {
process_instruction: ProcessInstructionWithContext,
) {
info!("\"{}\" builtin program", program_name);
self.builtin_programs.vec.push(BuiltinProgram {
name: program_name.to_string(),
self.builtin_programs.vec.push((
program_id,
process_instruction,
});
create_builtin(program_name.to_string(), process_instruction),
));
}
/// Deactivate a runtime feature.
@ -791,12 +790,8 @@ impl ProgramTest {
}
// User-supplied additional builtins
for builtin in self.builtin_programs.vec.iter() {
bank.add_builtin(
&builtin.name,
&builtin.program_id,
builtin.process_instruction,
);
for (program_id, builtin) in self.builtin_programs.vec.iter() {
bank.add_builtin(*program_id, builtin.clone());
}
for (address, account) in self.accounts.iter() {

View File

@ -5,7 +5,7 @@ extern crate test;
use {
log::*,
solana_program_runtime::declare_process_instruction,
solana_program_runtime::{builtin_program::create_builtin, declare_process_instruction},
solana_runtime::{
bank::{test_utils::goto_end_of_slot, *},
bank_client::BankClient,
@ -132,9 +132,8 @@ fn do_bench_transactions(
let mut bank = Bank::new_from_parent(&Arc::new(bank), &Pubkey::default(), 1);
bank.add_builtin(
"builtin_program",
&Pubkey::from(BUILTIN_PROGRAM_ID),
process_instruction,
Pubkey::from(BUILTIN_PROGRAM_ID),
create_builtin("mockup".to_string(), process_instruction),
);
bank.add_builtin_account("solana_noop_program", &Pubkey::from(NOOP_PROGRAM_ID), false);
let bank = Arc::new(bank);

View File

@ -94,7 +94,7 @@ use {
solana_perf::perf_libs,
solana_program_runtime::{
accounts_data_meter::MAX_ACCOUNTS_DATA_LEN,
builtin_program::{BuiltinProgram, BuiltinPrograms, ProcessInstructionWithContext},
builtin_program::BuiltinPrograms,
compute_budget::{self, ComputeBudget},
executor_cache::{BankExecutorCache, TransactionExecutorCache, MAX_CACHED_EXECUTORS},
loaded_programs::{
@ -6350,12 +6350,8 @@ impl Bank {
.extend_from_slice(&additional_builtins.feature_transitions);
}
if !debug_do_not_add_builtins {
for builtin in builtins.genesis_builtins {
self.add_builtin(
&builtin.name,
&builtin.program_id,
builtin.process_instruction,
);
for (program_id, builtin) in builtins.genesis_builtins {
self.add_builtin(program_id, builtin);
}
for precompile in get_precompiles() {
if precompile.feature.is_none() {
@ -7379,27 +7375,24 @@ impl Bank {
}
/// Add an instruction processor to intercept instructions before the dynamic loader.
pub fn add_builtin(
&mut self,
name: &str,
program_id: &Pubkey,
process_instruction: ProcessInstructionWithContext,
) {
pub fn add_builtin(&mut self, program_id: Pubkey, builtin: Arc<LoadedProgram>) {
let name = match &builtin.program {
LoadedProgramType::Builtin(name, _) => name,
_ => unreachable!(),
};
debug!("Adding program {} under {:?}", name, program_id);
self.add_builtin_account(name, program_id, false);
self.add_builtin_account(name.as_str(), &program_id, false);
if let Some(entry) = self
.builtin_programs
.vec
.iter_mut()
.find(|entry| entry.program_id == *program_id)
.find(|entry| entry.0 == program_id)
{
entry.process_instruction = process_instruction;
entry.1 = builtin.clone();
} else {
self.builtin_programs.vec.push(BuiltinProgram {
name: name.to_string(),
program_id: *program_id,
process_instruction,
});
self.builtin_programs
.vec
.push((program_id, builtin.clone()));
}
debug!("Added program {} under {:?}", name, program_id);
}
@ -7413,7 +7406,7 @@ impl Bank {
.builtin_programs
.vec
.iter()
.position(|entry| entry.program_id == *program_id)
.position(|entry| entry.0 == *program_id)
{
self.builtin_programs.vec.remove(position);
}
@ -7665,11 +7658,9 @@ impl Bank {
transition.to_action(&should_apply_action_for_feature_transition)
{
match builtin_action {
BuiltinAction::Add(builtin) => self.add_builtin(
&builtin.name,
&builtin.program_id,
builtin.process_instruction,
),
BuiltinAction::Add(program_id, builtin) => {
self.add_builtin(program_id, builtin)
}
BuiltinAction::Remove(program_id) => self.remove_builtin(&program_id),
}
}

View File

@ -33,6 +33,7 @@ use {
serde::{Deserialize, Serialize},
solana_logger,
solana_program_runtime::{
builtin_program::create_builtin,
compute_budget::{self, ComputeBudget, MAX_COMPUTE_UNIT_LIMIT},
declare_process_instruction,
executor_cache::TransactionExecutorCache,
@ -1380,7 +1381,10 @@ fn test_rent_complex() {
root_bank.restore_old_behavior_for_fragile_tests();
let root_bank = Arc::new(root_bank);
let mut bank = create_child_bank_for_rent_test(&root_bank, &genesis_config);
bank.add_builtin("mock_program", &mock_program_id, process_instruction);
bank.add_builtin(
mock_program_id,
create_builtin("mockup".to_string(), process_instruction),
);
assert_eq!(bank.last_blockhash(), genesis_config.hash());
@ -4817,9 +4821,8 @@ fn test_add_builtin() {
assert!(bank.get_account(&mock_vote_program_id()).is_none());
bank.add_builtin(
"mock_vote_program",
&mock_vote_program_id(),
process_instruction,
mock_vote_program_id(),
create_builtin("mockup".to_string(), process_instruction),
);
assert!(bank.get_account(&mock_vote_program_id()).is_some());
@ -4894,9 +4897,8 @@ fn test_add_duplicate_static_program() {
let vote_loader_account = bank.get_account(&solana_vote_program::id()).unwrap();
bank.add_builtin(
"solana_vote_program",
&solana_vote_program::id(),
process_instruction,
solana_vote_program::id(),
create_builtin("mockup".to_string(), process_instruction),
);
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.
@ -4948,8 +4950,14 @@ fn test_add_instruction_processor_for_existing_unrelated_accounts() {
continue;
}
bank.add_builtin("mock_program1", &vote_id, process_instruction);
bank.add_builtin("mock_program2", &stake_id, process_instruction);
bank.add_builtin(
vote_id,
create_builtin("mock_program1".to_string(), process_instruction),
);
bank.add_builtin(
stake_id,
create_builtin("mock_program2".to_string(), process_instruction),
);
{
let stakes = bank.stakes_cache.stakes();
assert!(stakes.vote_accounts().as_ref().is_empty());
@ -4972,8 +4980,14 @@ fn test_add_instruction_processor_for_existing_unrelated_accounts() {
// Re-adding builtin programs should be no-op
bank.update_accounts_hash_for_tests();
let old_hash = bank.get_accounts_hash().unwrap();
bank.add_builtin("mock_program1", &vote_id, process_instruction);
bank.add_builtin("mock_program2", &stake_id, process_instruction);
bank.add_builtin(
vote_id,
create_builtin("mockup".to_string(), process_instruction),
);
bank.add_builtin(
stake_id,
create_builtin("mockup".to_string(), process_instruction),
);
add_root_and_flush_write_cache(&bank);
bank.update_accounts_hash_for_tests();
let new_hash = bank.get_accounts_hash().unwrap();
@ -6224,7 +6238,10 @@ fn test_transaction_with_duplicate_accounts_in_instruction() {
});
let mock_program_id = Pubkey::from([2u8; 32]);
bank.add_builtin("mock_program", &mock_program_id, process_instruction);
bank.add_builtin(
mock_program_id,
create_builtin("mockup".to_string(), process_instruction),
);
let from_pubkey = solana_sdk::pubkey::new_rand();
let to_pubkey = solana_sdk::pubkey::new_rand();
@ -6260,7 +6277,10 @@ fn test_transaction_with_program_ids_passed_to_programs() {
let mut bank = Bank::new_for_tests(&genesis_config);
let mock_program_id = Pubkey::from([2u8; 32]);
bank.add_builtin("mock_program", &mock_program_id, process_instruction);
bank.add_builtin(
mock_program_id,
create_builtin("mockup".to_string(), process_instruction),
);
let from_pubkey = solana_sdk::pubkey::new_rand();
let to_pubkey = solana_sdk::pubkey::new_rand();
@ -6312,7 +6332,10 @@ fn test_account_ids_after_program_ids() {
tx.message.account_keys.push(solana_sdk::pubkey::new_rand());
bank.add_builtin("mock_vote", &solana_vote_program::id(), process_instruction);
bank.add_builtin(
solana_vote_program::id(),
create_builtin("mockup".to_string(), process_instruction),
);
let result = bank.process_transaction(&tx);
assert_eq!(result, Ok(()));
let account = bank.get_account(&solana_vote_program::id()).unwrap();
@ -6362,7 +6385,10 @@ fn test_duplicate_account_key() {
AccountMeta::new(to_pubkey, false),
];
bank.add_builtin("mock_vote", &solana_vote_program::id(), process_instruction);
bank.add_builtin(
solana_vote_program::id(),
create_builtin("mockup".to_string(), process_instruction),
);
let instruction = Instruction::new_with_bincode(solana_vote_program::id(), &10, account_metas);
let mut tx = Transaction::new_signed_with_payer(
@ -6391,7 +6417,10 @@ fn test_process_transaction_with_too_many_account_locks() {
AccountMeta::new(to_pubkey, false),
];
bank.add_builtin("mock_vote", &solana_vote_program::id(), process_instruction);
bank.add_builtin(
solana_vote_program::id(),
create_builtin("mockup".to_string(), process_instruction),
);
let instruction = Instruction::new_with_bincode(solana_vote_program::id(), &10, account_metas);
let mut tx = Transaction::new_signed_with_payer(
@ -6424,7 +6453,10 @@ fn test_program_id_as_payer() {
AccountMeta::new(to_pubkey, false),
];
bank.add_builtin("mock_vote", &solana_vote_program::id(), process_instruction);
bank.add_builtin(
solana_vote_program::id(),
create_builtin("mockup".to_string(), process_instruction),
);
let instruction = Instruction::new_with_bincode(solana_vote_program::id(), &10, account_metas);
let mut tx = Transaction::new_signed_with_payer(
@ -6467,7 +6499,10 @@ fn test_ref_account_key_after_program_id() {
AccountMeta::new(to_pubkey, false),
];
bank.add_builtin("mock_vote", &solana_vote_program::id(), process_instruction);
bank.add_builtin(
solana_vote_program::id(),
create_builtin("mockup".to_string(), process_instruction),
);
let instruction = Instruction::new_with_bincode(solana_vote_program::id(), &10, account_metas);
let mut tx = Transaction::new_signed_with_payer(
@ -6498,7 +6533,7 @@ fn test_fuzz_instructions() {
.map(|i| {
let key = solana_sdk::pubkey::new_rand();
let name = format!("program{i:?}");
bank.add_builtin(&name, &key, process_instruction);
bank.add_builtin(key, create_builtin(name.clone(), process_instruction));
(key, name.as_bytes().to_vec())
})
.collect();
@ -6704,7 +6739,10 @@ fn test_same_program_id_uses_unqiue_executable_accounts() {
// Add a new program
let program1_pubkey = solana_sdk::pubkey::new_rand();
bank.add_builtin("program", &program1_pubkey, process_instruction);
bank.add_builtin(
program1_pubkey,
create_builtin("mockup".to_string(), process_instruction),
);
// Add a new program owned by the first
let program2_pubkey = solana_sdk::pubkey::new_rand();
@ -6919,15 +6957,17 @@ fn test_add_builtin_no_overwrite() {
));
assert_eq!(bank.get_account_modified_slot(&program_id), None);
Arc::get_mut(&mut bank)
.unwrap()
.add_builtin("mock_program", &program_id, process_instruction);
Arc::get_mut(&mut bank).unwrap().add_builtin(
program_id,
create_builtin("mockup".to_string(), process_instruction),
);
assert_eq!(bank.get_account_modified_slot(&program_id).unwrap().1, slot);
let mut bank = Arc::new(new_from_parent(&bank));
Arc::get_mut(&mut bank)
.unwrap()
.add_builtin("mock_program", &program_id, process_instruction);
Arc::get_mut(&mut bank).unwrap().add_builtin(
program_id,
create_builtin("mockup".to_string(), process_instruction),
);
assert_eq!(bank.get_account_modified_slot(&program_id).unwrap().1, slot);
}
@ -6943,15 +6983,17 @@ fn test_add_builtin_loader_no_overwrite() {
));
assert_eq!(bank.get_account_modified_slot(&loader_id), None);
Arc::get_mut(&mut bank)
.unwrap()
.add_builtin("mock_program", &loader_id, process_instruction);
Arc::get_mut(&mut bank).unwrap().add_builtin(
loader_id,
create_builtin("mockup".to_string(), process_instruction),
);
assert_eq!(bank.get_account_modified_slot(&loader_id).unwrap().1, slot);
let mut bank = Arc::new(new_from_parent(&bank));
Arc::get_mut(&mut bank)
.unwrap()
.add_builtin("mock_program", &loader_id, process_instruction);
Arc::get_mut(&mut bank).unwrap().add_builtin(
loader_id,
create_builtin("mockup".to_string(), process_instruction),
);
assert_eq!(bank.get_account_modified_slot(&loader_id).unwrap().1, slot);
}
@ -9694,7 +9736,10 @@ fn test_tx_return_data() {
let mock_program_id = Pubkey::from([2u8; 32]);
let blockhash = bank.last_blockhash();
bank.add_builtin("mock_program", &mock_program_id, process_instruction);
bank.add_builtin(
mock_program_id,
create_builtin("mockup".to_string(), process_instruction),
);
for index in [
None,
@ -9883,7 +9928,10 @@ fn test_transfer_sysvar() {
});
let program_id = solana_sdk::pubkey::new_rand();
bank.add_builtin("mock_program1", &program_id, process_instruction);
bank.add_builtin(
program_id,
create_builtin("mockup".to_string(), process_instruction),
);
let blockhash = bank.last_blockhash();
#[allow(deprecated)]
@ -10095,7 +10143,10 @@ fn test_compute_budget_program_noop() {
Ok(())
});
let program_id = solana_sdk::pubkey::new_rand();
bank.add_builtin("mock_program", &program_id, process_instruction);
bank.add_builtin(
program_id,
create_builtin("mockup".to_string(), process_instruction),
);
let message = Message::new(
&[
@ -10138,7 +10189,10 @@ fn test_compute_request_instruction() {
Ok(())
});
let program_id = solana_sdk::pubkey::new_rand();
bank.add_builtin("mock_program", &program_id, process_instruction);
bank.add_builtin(
program_id,
create_builtin("mockup".to_string(), process_instruction),
);
let message = Message::new(
&[
@ -10188,7 +10242,10 @@ fn test_failed_compute_request_instruction() {
Ok(())
});
let program_id = solana_sdk::pubkey::new_rand();
bank.add_builtin("mock_program", &program_id, process_instruction);
bank.add_builtin(
program_id,
create_builtin("mockup".to_string(), process_instruction),
);
// This message will not be executed because the compute budget request is invalid
let message0 = Message::new(
@ -10863,9 +10920,8 @@ fn test_invalid_rent_state_changes_existing_accounts() {
let mut bank = Bank::new_for_tests(&genesis_config);
bank.add_builtin(
"mock_program",
&mock_program_id,
mock_transfer_process_instruction,
mock_program_id,
create_builtin("mockup".to_string(), mock_transfer_process_instruction),
);
let recent_blockhash = bank.last_blockhash();
@ -10950,9 +11006,8 @@ fn test_invalid_rent_state_changes_new_accounts() {
let mut bank = Bank::new_for_tests(&genesis_config);
bank.add_builtin(
"mock_program",
&mock_program_id,
mock_transfer_process_instruction,
mock_program_id,
create_builtin("mockup".to_string(), mock_transfer_process_instruction),
);
let recent_blockhash = bank.last_blockhash();
@ -11013,9 +11068,8 @@ fn test_drained_created_account() {
let mut bank = Bank::new_for_tests(&genesis_config);
bank.add_builtin(
"mock_program",
&mock_program_id,
mock_transfer_process_instruction,
mock_program_id,
create_builtin("mockup".to_string(), mock_transfer_process_instruction),
);
let recent_blockhash = bank.last_blockhash();
@ -11668,9 +11722,8 @@ fn test_resize_and_rent() {
let mock_program_id = Pubkey::new_unique();
bank.add_builtin(
"mock_realloc_program",
&mock_program_id,
mock_realloc_process_instruction,
mock_program_id,
create_builtin("mockup".to_string(), mock_realloc_process_instruction),
);
let recent_blockhash = bank.last_blockhash();
@ -11943,9 +11996,8 @@ fn test_accounts_data_size_and_resize_transactions() {
let mut bank = Bank::new_for_tests(&genesis_config);
let mock_program_id = Pubkey::new_unique();
bank.add_builtin(
"mock_realloc_program",
&mock_program_id,
mock_realloc_process_instruction,
mock_program_id,
create_builtin("mockup".to_string(), mock_realloc_process_instruction),
);
let recent_blockhash = bank.last_blockhash();

View File

@ -1,14 +1,15 @@
use {
solana_program_runtime::builtin_program::BuiltinProgram,
solana_program_runtime::{builtin_program::create_builtin, loaded_programs::LoadedProgram},
solana_sdk::{
bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, feature_set, pubkey::Pubkey,
},
std::sync::Arc,
};
#[derive(Clone, Debug)]
pub struct Builtins {
/// Builtin programs that are always available
pub genesis_builtins: Vec<BuiltinProgram>,
pub genesis_builtins: Vec<(Pubkey, Arc<LoadedProgram>)>,
/// Dynamic feature transitions for builtin programs
pub feature_transitions: Vec<BuiltinFeatureTransition>,
@ -17,7 +18,7 @@ pub struct Builtins {
/// Actions taken by a bank when managing the list of active builtin programs.
#[derive(Debug, Clone)]
pub enum BuiltinAction {
Add(BuiltinProgram),
Add(Pubkey, Arc<LoadedProgram>),
Remove(Pubkey),
}
@ -27,13 +28,15 @@ pub enum BuiltinAction {
pub enum BuiltinFeatureTransition {
/// Add a builtin program if a feature is activated.
Add {
builtin: BuiltinProgram,
program_id: Pubkey,
builtin: Arc<LoadedProgram>,
feature_id: Pubkey,
},
/// Remove a builtin program if a feature is activated or
/// retain a previously added builtin.
RemoveOrRetain {
previously_added_builtin: BuiltinProgram,
program_id: Pubkey,
previously_added_builtin: Arc<LoadedProgram>,
addition_feature_id: Pubkey,
removal_feature_id: Pubkey,
},
@ -46,25 +49,30 @@ impl BuiltinFeatureTransition {
) -> Option<BuiltinAction> {
match self {
Self::Add {
program_id,
builtin,
feature_id,
} => {
if should_apply_action_for_feature(feature_id) {
Some(BuiltinAction::Add(builtin.clone()))
Some(BuiltinAction::Add(*program_id, builtin.clone()))
} else {
None
}
}
Self::RemoveOrRetain {
program_id,
previously_added_builtin,
addition_feature_id,
removal_feature_id,
} => {
if should_apply_action_for_feature(removal_feature_id) {
Some(BuiltinAction::Remove(previously_added_builtin.program_id))
Some(BuiltinAction::Remove(*program_id))
} else if should_apply_action_for_feature(addition_feature_id) {
// Retaining is no different from adding a new builtin.
Some(BuiltinAction::Add(previously_added_builtin.clone()))
Some(BuiltinAction::Add(
*program_id,
previously_added_builtin.clone(),
))
} else {
None
}
@ -74,43 +82,57 @@ impl BuiltinFeatureTransition {
}
/// Built-in programs that are always available
fn genesis_builtins() -> Vec<BuiltinProgram> {
fn genesis_builtins() -> Vec<(Pubkey, Arc<LoadedProgram>)> {
vec![
BuiltinProgram {
name: "system_program".to_string(),
program_id: solana_system_program::id(),
process_instruction: solana_system_program::system_processor::process_instruction,
},
BuiltinProgram {
name: "vote_program".to_string(),
program_id: solana_vote_program::id(),
process_instruction: solana_vote_program::vote_processor::process_instruction,
},
BuiltinProgram {
name: "stake_program".to_string(),
program_id: solana_stake_program::id(),
process_instruction: solana_stake_program::stake_instruction::process_instruction,
},
BuiltinProgram {
name: "config_program".to_string(),
program_id: solana_config_program::id(),
process_instruction: solana_config_program::config_processor::process_instruction,
},
BuiltinProgram {
name: "solana_bpf_loader_deprecated_program".to_string(),
program_id: bpf_loader_deprecated::id(),
process_instruction: solana_bpf_loader_program::process_instruction,
},
BuiltinProgram {
name: "solana_bpf_loader_program".to_string(),
program_id: bpf_loader::id(),
process_instruction: solana_bpf_loader_program::process_instruction,
},
BuiltinProgram {
name: "solana_bpf_loader_upgradeable_program".to_string(),
program_id: bpf_loader_upgradeable::id(),
process_instruction: solana_bpf_loader_program::process_instruction,
},
(
solana_system_program::id(),
create_builtin(
"system_program".to_string(),
solana_system_program::system_processor::process_instruction,
),
),
(
solana_vote_program::id(),
create_builtin(
"vote_program".to_string(),
solana_vote_program::vote_processor::process_instruction,
),
),
(
solana_stake_program::id(),
create_builtin(
"stake_program".to_string(),
solana_stake_program::stake_instruction::process_instruction,
),
),
(
solana_config_program::id(),
create_builtin(
"config_program".to_string(),
solana_config_program::config_processor::process_instruction,
),
),
(
bpf_loader_deprecated::id(),
create_builtin(
"solana_bpf_loader_deprecated_program".to_string(),
solana_bpf_loader_program::process_instruction,
),
),
(
bpf_loader::id(),
create_builtin(
"solana_bpf_loader_program".to_string(),
solana_bpf_loader_program::process_instruction,
),
),
(
bpf_loader_upgradeable::id(),
create_builtin(
"solana_bpf_loader_upgradeable_program".to_string(),
solana_bpf_loader_program::process_instruction,
),
),
]
}
@ -118,28 +140,27 @@ fn genesis_builtins() -> Vec<BuiltinProgram> {
fn builtin_feature_transitions() -> Vec<BuiltinFeatureTransition> {
vec![
BuiltinFeatureTransition::Add {
builtin: BuiltinProgram {
name: "compute_budget_program".to_string(),
program_id: solana_sdk::compute_budget::id(),
process_instruction: solana_compute_budget_program::process_instruction,
},
program_id: solana_sdk::compute_budget::id(),
builtin: create_builtin(
"compute_budget_program".to_string(),
solana_compute_budget_program::process_instruction,
),
feature_id: feature_set::add_compute_budget_program::id(),
},
BuiltinFeatureTransition::Add {
builtin: BuiltinProgram {
name: "address_lookup_table_program".to_string(),
program_id: solana_address_lookup_table_program::id(),
process_instruction:
solana_address_lookup_table_program::processor::process_instruction,
},
program_id: solana_address_lookup_table_program::id(),
builtin: create_builtin(
"address_lookup_table_program".to_string(),
solana_address_lookup_table_program::processor::process_instruction,
),
feature_id: feature_set::versioned_tx_message_enabled::id(),
},
BuiltinFeatureTransition::Add {
builtin: BuiltinProgram {
name: "zk_token_proof_program".to_string(),
program_id: solana_zk_token_sdk::zk_token_proof_program::id(),
process_instruction: solana_zk_token_proof_program::process_instruction,
},
program_id: solana_zk_token_sdk::zk_token_proof_program::id(),
builtin: create_builtin(
"zk_token_proof_program".to_string(),
solana_zk_token_proof_program::process_instruction,
),
feature_id: feature_set::zk_token_sdk_enabled::id(),
},
]
@ -157,9 +178,14 @@ pub fn get_pubkeys() -> Vec<Pubkey> {
let builtins = get();
let mut pubkeys = Vec::new();
pubkeys.extend(builtins.genesis_builtins.iter().map(|b| b.program_id));
pubkeys.extend(
builtins
.genesis_builtins
.iter()
.map(|(program_id, _builtin)| program_id),
);
pubkeys.extend(builtins.feature_transitions.iter().filter_map(|f| match f {
BuiltinFeatureTransition::Add { builtin, .. } => Some(builtin.program_id),
BuiltinFeatureTransition::Add { program_id, .. } => Some(program_id),
BuiltinFeatureTransition::RemoveOrRetain { .. } => None,
}));
pubkeys