Refactor - Merges `BuiltinPrograms` into `LoadedPrograms` (#31654)

* Merges BuiltinPrograms into LoadedPrograms.

* Prevents built-ins from being pruned.
This commit is contained in:
Alexander Meißner 2023-05-18 22:18:28 +02:00 committed by GitHub
parent a57fe0c23d
commit 520c647918
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 369 additions and 551 deletions

View File

@ -531,12 +531,7 @@ pub fn program(ledger_path: &Path, matches: &ArgMatches<'_>) {
AccountSharedData::new(0, 0, &loader_id),
));
let interpreted = matches.value_of("mode").unwrap() != "jit";
with_mock_invoke_context!(
invoke_context,
transaction_context,
transaction_accounts,
bank.get_builtin_programs()
);
with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
// Adding `DELAY_VISIBILITY_SLOT_OFFSET` to slots to accommodate for delay visibility of the program
let mut loaded_programs =

View File

@ -1840,7 +1840,7 @@ pub mod tests {
matches::assert_matches,
rand::{thread_rng, Rng},
solana_entry::entry::{create_ticks, next_entry, next_entry_mut},
solana_program_runtime::{builtin_program::create_builtin, declare_process_instruction},
solana_program_runtime::declare_process_instruction,
solana_runtime::{
genesis_utils::{
self, create_genesis_config_with_vote_accounts, ValidatorVoteKeypairs,
@ -3002,10 +3002,7 @@ 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_program_id,
create_builtin("mockup".to_string(), mock_processor_ok),
);
bank.add_mockup_builtin(mock_program_id, mock_processor_ok);
let tx = Transaction::new_signed_with_payer(
&[Instruction::new_with_bincode(
@ -3046,10 +3043,7 @@ pub mod tests {
(0..get_instruction_errors().len()).for_each(|err| {
let mut bank = Bank::new_for_tests(&genesis_config);
bank.add_builtin(
mock_program_id,
create_builtin("mockup".to_string(), mock_processor_err),
);
bank.add_mockup_builtin(mock_program_id, mock_processor_err);
let tx = Transaction::new_signed_with_payer(
&[Instruction::new_with_bincode(

View File

@ -1,47 +0,0 @@
#[cfg(RUSTC_WITH_SPECIALIZATION)]
use solana_frozen_abi::abi_example::AbiExample;
use {
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>>;
pub fn create_builtin(
name: String,
process_instruction: ProcessInstructionWithContext,
) -> Arc<LoadedProgram> {
let mut program = BuiltInProgram::default();
program
.register_function(b"entrypoint", process_instruction)
.unwrap();
Arc::new(LoadedProgram::new_builtin(name, 0, program))
}
#[derive(Debug, Clone, Default)]
pub struct BuiltinPrograms {
pub vec: Vec<(Pubkey, Arc<LoadedProgram>)>,
}
#[cfg(RUSTC_WITH_SPECIALIZATION)]
impl AbiExample for BuiltinPrograms {
fn example() -> Self {
Self::default()
}
}
impl BuiltinPrograms {
pub fn new_mock(
program_id: Pubkey,
process_instruction: ProcessInstructionWithContext,
) -> Self {
Self {
vec: vec![(
program_id,
create_builtin("mockup".to_string(), process_instruction),
)],
}
}
}

View File

@ -1,10 +1,9 @@
use {
crate::{
accounts_data_meter::AccountsDataMeter,
builtin_program::{BuiltinPrograms, ProcessInstructionWithContext},
compute_budget::ComputeBudget,
ic_logger_msg, ic_msg,
loaded_programs::{LoadedProgramType, LoadedProgramsForTxBatch},
loaded_programs::{LoadedProgram, LoadedProgramType, LoadedProgramsForTxBatch},
log_collector::LogCollector,
pre_account::PreAccount,
stable_log,
@ -15,7 +14,7 @@ use {
solana_rbpf::{
ebpf::MM_HEAP_START,
memory_region::MemoryMapping,
vm::{Config, ContextObject, ProgramResult},
vm::{BuiltInFunction, Config, ContextObject, ProgramResult},
},
solana_sdk::{
account::{AccountSharedData, ReadableAccount},
@ -44,6 +43,8 @@ use {
},
};
pub type ProcessInstructionWithContext = BuiltInFunction<InvokeContext<'static>>;
/// Adapter so we can unify the interfaces of built-in programs and syscalls
#[macro_export]
macro_rules! declare_process_instruction {
@ -152,7 +153,6 @@ pub struct InvokeContext<'a> {
pub transaction_context: &'a mut TransactionContext,
rent: Rent,
pre_accounts: Vec<PreAccount>,
builtin_programs: &'a BuiltinPrograms,
sysvar_cache: &'a SysvarCache,
log_collector: Option<Rc<RefCell<LogCollector>>>,
compute_budget: ComputeBudget,
@ -175,7 +175,6 @@ impl<'a> InvokeContext<'a> {
pub fn new(
transaction_context: &'a mut TransactionContext,
rent: Rent,
builtin_programs: &'a BuiltinPrograms,
sysvar_cache: &'a SysvarCache,
log_collector: Option<Rc<RefCell<LogCollector>>>,
compute_budget: ComputeBudget,
@ -191,7 +190,6 @@ impl<'a> InvokeContext<'a> {
transaction_context,
rent,
pre_accounts: Vec::new(),
builtin_programs,
sysvar_cache,
log_collector,
current_compute_budget: compute_budget,
@ -724,80 +722,77 @@ impl<'a> InvokeContext<'a> {
}
};
for entry in self.builtin_programs.vec.iter() {
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);
// The Murmur3 hash value (used by RBPF) of the string "entrypoint"
const ENTRYPOINT_KEY: u32 = 0x71E3CF81;
let entry = self
.programs_loaded_for_tx_batch
.find(&builtin_id)
.ok_or(InstructionError::UnsupportedProgramId)?;
let process_instruction = match &entry.program {
LoadedProgramType::Builtin(program) => program
.lookup_function(ENTRYPOINT_KEY)
.map(|(_name, process_instruction)| process_instruction),
_ => None,
}
.ok_or(InstructionError::UnsupportedProgramId)?;
entry.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);
process_instruction(
// Removes lifetime tracking
unsafe { std::mem::transmute::<&mut InvokeContext, &mut InvokeContext>(self) },
0,
0,
0,
0,
0,
&mut mock_memory_mapping,
&mut result,
);
let result = match result {
ProgramResult::Ok(_) => {
stable_log::program_success(&logger, &program_id);
Ok(())
}
ProgramResult::Err(err) => {
stable_log::program_failure(&logger, &program_id, err.as_ref());
if let Some(err) = err.downcast_ref::<InstructionError>() {
Err(err.clone())
} else {
Err(InstructionError::ProgramFailedToComplete)
}
}
};
let post_remaining_units = self.get_remaining();
*compute_units_consumed = pre_remaining_units.saturating_sub(post_remaining_units);
if builtin_id == program_id
&& result.is_ok()
&& *compute_units_consumed == 0
&& self
.feature_set
.is_active(&native_programs_consume_cu::id())
{
return Err(InstructionError::BuiltinProgramsMustConsumeComputeUnits);
}
process_executable_chain_time.stop();
saturating_add_assign!(
timings
.execute_accessories
.process_instructions
.process_executable_chain_us,
process_executable_chain_time.as_us()
);
return result;
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);
process_instruction(
// Removes lifetime tracking
unsafe { std::mem::transmute::<&mut InvokeContext, &mut InvokeContext>(self) },
0,
0,
0,
0,
0,
&mut mock_memory_mapping,
&mut result,
);
let result = match result {
ProgramResult::Ok(_) => {
stable_log::program_success(&logger, &program_id);
Ok(())
}
ProgramResult::Err(err) => {
stable_log::program_failure(&logger, &program_id, err.as_ref());
if let Some(err) = err.downcast_ref::<InstructionError>() {
Err(err.clone())
} else {
Err(InstructionError::ProgramFailedToComplete)
}
}
};
let post_remaining_units = self.get_remaining();
*compute_units_consumed = pre_remaining_units.saturating_sub(post_remaining_units);
if builtin_id == program_id
&& result.is_ok()
&& *compute_units_consumed == 0
&& self
.feature_set
.is_active(&native_programs_consume_cu::id())
{
return Err(InstructionError::BuiltinProgramsMustConsumeComputeUnits);
}
Err(InstructionError::UnsupportedProgramId)
process_executable_chain_time.stop();
saturating_add_assign!(
timings
.execute_accessories
.process_instructions
.process_executable_chain_us,
process_executable_chain_time.as_us()
);
result
}
/// Get this invocation's LogCollector
@ -893,12 +888,11 @@ impl<'a> InvokeContext<'a> {
}
#[macro_export]
macro_rules! with_mock_invoke_context_and_builtin_programs {
macro_rules! with_mock_invoke_context {
(
$invoke_context:ident,
$transaction_context:ident,
$transaction_accounts:expr,
$builtin_programs:expr
$transaction_accounts:expr $(,)?
) => {
use {
solana_sdk::{
@ -944,7 +938,6 @@ macro_rules! with_mock_invoke_context_and_builtin_programs {
let mut $invoke_context = InvokeContext::new(
&mut $transaction_context,
Rent::default(),
$builtin_programs,
&sysvar_cache,
Some(LogCollector::new_ref()),
compute_budget,
@ -959,37 +952,6 @@ macro_rules! with_mock_invoke_context_and_builtin_programs {
};
}
#[macro_export]
macro_rules! with_mock_invoke_context {
(
$invoke_context:ident,
$transaction_context:ident,
$transaction_accounts:expr,
$builtin_programs:expr
) => {
use $crate::with_mock_invoke_context_and_builtin_programs;
with_mock_invoke_context_and_builtin_programs!(
$invoke_context,
$transaction_context,
$transaction_accounts,
$builtin_programs
);
};
($invoke_context:ident, $transaction_context:ident, $transaction_accounts:expr) => {
use $crate::{
builtin_program::BuiltinPrograms, with_mock_invoke_context_and_builtin_programs,
};
let builtin_programs = BuiltinPrograms::default();
with_mock_invoke_context_and_builtin_programs!(
$invoke_context,
$transaction_context,
$transaction_accounts,
&builtin_programs
);
};
}
pub fn mock_process_instruction<F: FnMut(&mut InvokeContext), G: FnMut(&mut InvokeContext)>(
loader_id: &Pubkey,
mut program_indices: Vec<IndexOfAccount>,
@ -1028,13 +990,13 @@ pub fn mock_process_instruction<F: FnMut(&mut InvokeContext), G: FnMut(&mut Invo
program_indices.insert(0, transaction_accounts.len() as IndexOfAccount);
let processor_account = AccountSharedData::new(0, 0, &native_loader::id());
transaction_accounts.push((*loader_id, processor_account));
let builtin_programs = BuiltinPrograms::new_mock(*loader_id, process_instruction);
with_mock_invoke_context!(
invoke_context,
transaction_context,
transaction_accounts,
&builtin_programs
with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
programs_loaded_for_tx_batch.replenish(
*loader_id,
Arc::new(LoadedProgram::new_builtin(0, 0, process_instruction)),
);
invoke_context.programs_loaded_for_tx_batch = &programs_loaded_for_tx_batch;
pre_adjustments(&mut invoke_context);
let result = invoke_context.process_instruction(
instruction_data,
@ -1282,13 +1244,13 @@ mod tests {
is_writable: instruction_account_index < 2,
})
.collect::<Vec<_>>();
let builtin_programs = BuiltinPrograms::new_mock(callee_program_id, process_instruction);
with_mock_invoke_context!(
invoke_context,
transaction_context,
transaction_accounts,
&builtin_programs
with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
programs_loaded_for_tx_batch.replenish(
callee_program_id,
Arc::new(LoadedProgram::new_builtin(0, 0, process_instruction)),
);
invoke_context.programs_loaded_for_tx_batch = &programs_loaded_for_tx_batch;
// Account modification tests
let cases = vec![
@ -1428,13 +1390,13 @@ mod tests {
is_writable: false,
},
];
let builtin_programs = BuiltinPrograms::new_mock(program_key, process_instruction);
with_mock_invoke_context!(
invoke_context,
transaction_context,
transaction_accounts,
&builtin_programs
with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
programs_loaded_for_tx_batch.replenish(
program_key,
Arc::new(LoadedProgram::new_builtin(0, 0, process_instruction)),
);
invoke_context.programs_loaded_for_tx_batch = &programs_loaded_for_tx_batch;
// Test: Resize the account to *the same size*, so not consuming any additional size; this must succeed
{

View File

@ -11,7 +11,6 @@ extern crate solana_metrics;
pub use solana_rbpf;
pub mod accounts_data_meter;
pub mod builtin_program;
pub mod compute_budget;
pub mod invoke_context;
pub mod loaded_programs;

View File

@ -1,7 +1,10 @@
#[cfg(all(not(target_os = "windows"), target_arch = "x86_64"))]
use solana_rbpf::error::EbpfError;
use {
crate::{invoke_context::InvokeContext, timings::ExecuteDetailsTimings},
crate::{
invoke_context::{InvokeContext, ProcessInstructionWithContext},
timings::ExecuteDetailsTimings,
},
itertools::Itertools,
log::{debug, log_enabled, trace},
percentage::PercentageInteger,
@ -68,7 +71,7 @@ pub enum LoadedProgramType {
Typed(Executable<RequisiteVerifier, InvokeContext<'static>>),
#[cfg(test)]
TestLoaded,
Builtin(String, BuiltInProgram<InvokeContext<'static>>),
Builtin(BuiltInProgram<InvokeContext<'static>>),
}
impl Debug for LoadedProgramType {
@ -85,9 +88,7 @@ impl Debug for LoadedProgramType {
LoadedProgramType::Typed(_) => write!(f, "LoadedProgramType::Typed"),
#[cfg(test)]
LoadedProgramType::TestLoaded => write!(f, "LoadedProgramType::TestLoaded"),
LoadedProgramType::Builtin(name, _) => {
write!(f, "LoadedProgramType::Builtin({name})")
}
LoadedProgramType::Builtin(_) => write!(f, "LoadedProgramType::Builtin"),
}
}
}
@ -268,17 +269,21 @@ impl LoadedProgram {
/// Creates a new built-in program
pub fn new_builtin(
name: String,
deployment_slot: Slot,
program: BuiltInProgram<InvokeContext<'static>>,
account_size: usize,
entrypoint: ProcessInstructionWithContext,
) -> Self {
let mut program = BuiltInProgram::default();
program
.register_function(b"entrypoint", entrypoint)
.unwrap();
Self {
deployment_slot,
account_size: 0,
effective_slot: deployment_slot.saturating_add(1),
account_size,
effective_slot: deployment_slot,
maybe_expiration_slot: None,
usage_counter: AtomicU64::new(0),
program: LoadedProgramType::Builtin(name, program),
program: LoadedProgramType::Builtin(program),
}
}
@ -318,7 +323,9 @@ impl LoadedProgram {
}
fn is_implicit_delay_visibility_tombstone(&self, slot: Slot) -> bool {
self.effective_slot.saturating_sub(self.deployment_slot) == DELAY_VISIBILITY_SLOT_OFFSET
!matches!(self.program, LoadedProgramType::Builtin(_))
&& self.effective_slot.saturating_sub(self.deployment_slot)
== DELAY_VISIBILITY_SLOT_OFFSET
&& slot >= self.deployment_slot
&& slot < self.effective_slot
}
@ -420,7 +427,10 @@ impl LoadedPrograms {
if existing.deployment_slot == entry.deployment_slot
&& existing.effective_slot == entry.effective_slot
{
if matches!(existing.program, LoadedProgramType::Unloaded) {
if matches!(existing.program, LoadedProgramType::Builtin(_)) {
// Allow built-ins to be overwritten
second_level.swap_remove(entry_index);
} else if matches!(existing.program, LoadedProgramType::Unloaded) {
// The unloaded program is getting reloaded
// Copy over the usage counter to the new entry
entry.usage_counter.store(
@ -463,7 +473,9 @@ impl LoadedPrograms {
.rev()
.filter(|entry| {
let relation = fork_graph.relationship(entry.deployment_slot, new_root);
if entry.deployment_slot >= new_root {
if matches!(entry.program, LoadedProgramType::Builtin(_)) {
true
} else if entry.deployment_slot >= new_root {
matches!(relation, BlockRelation::Equal | BlockRelation::Descendant)
} else if !first_ancestor_found
&& (matches!(relation, BlockRelation::Ancestor)
@ -603,7 +615,7 @@ impl LoadedPrograms {
| LoadedProgramType::FailedVerification
| LoadedProgramType::Closed
| LoadedProgramType::DelayVisibility
| LoadedProgramType::Builtin(_, _) => None,
| LoadedProgramType::Builtin(_) => None,
})
})
.sorted_by_cached_key(|(_id, program)| program.usage_counter.load(Ordering::Relaxed))
@ -712,7 +724,7 @@ mod tests {
fn new_test_builtin_program(deployment_slot: Slot, effective_slot: Slot) -> Arc<LoadedProgram> {
Arc::new(LoadedProgram {
program: LoadedProgramType::Builtin("mockup".to_string(), BuiltInProgram::default()),
program: LoadedProgramType::Builtin(BuiltInProgram::default()),
account_size: 0,
deployment_slot,
effective_slot,

View File

@ -12,10 +12,8 @@ use {
solana_banks_server::banks_server::start_local_server,
solana_bpf_loader_program::serialization::serialize_parameters,
solana_program_runtime::{
builtin_program::{create_builtin, BuiltinPrograms, ProcessInstructionWithContext},
compute_budget::ComputeBudget,
ic_msg, stable_log,
timings::ExecuteTimings,
compute_budget::ComputeBudget, ic_msg, invoke_context::ProcessInstructionWithContext,
loaded_programs::LoadedProgram, stable_log, timings::ExecuteTimings,
},
solana_runtime::{
accounts_background_service::{AbsRequestSender, SnapshotRequestType},
@ -436,7 +434,7 @@ pub fn read_file<P: AsRef<Path>>(path: P) -> Vec<u8> {
pub struct ProgramTest {
accounts: Vec<(Pubkey, AccountSharedData)>,
builtin_programs: BuiltinPrograms,
builtin_programs: Vec<(Pubkey, String, LoadedProgram)>,
compute_max_units: Option<u64>,
prefer_bpf: bool,
deactivate_feature_set: HashSet<Pubkey>,
@ -473,7 +471,7 @@ impl Default for ProgramTest {
Self {
accounts: vec![],
builtin_programs: BuiltinPrograms::default(),
builtin_programs: vec![],
compute_max_units: None,
prefer_bpf,
deactivate_feature_set,
@ -694,9 +692,10 @@ impl ProgramTest {
process_instruction: ProcessInstructionWithContext,
) {
info!("\"{}\" builtin program", program_name);
self.builtin_programs.vec.push((
self.builtin_programs.push((
program_id,
create_builtin(program_name.to_string(), process_instruction),
program_name.to_string(),
LoadedProgram::new_builtin(0, program_name.len(), process_instruction),
));
}
@ -708,7 +707,7 @@ impl ProgramTest {
}
fn setup_bank(
&self,
&mut self,
) -> (
Arc<RwLock<BankForks>>,
Arc<RwLock<BlockCommitmentCache>>,
@ -792,8 +791,10 @@ impl ProgramTest {
}
// User-supplied additional builtins
for (program_id, builtin) in self.builtin_programs.vec.iter() {
bank.add_builtin(*program_id, builtin.clone());
let mut builtin_programs = Vec::new();
std::mem::swap(&mut self.builtin_programs, &mut builtin_programs);
for (program_id, name, builtin) in builtin_programs.into_iter() {
bank.add_builtin(program_id, name, builtin);
}
for (address, account) in self.accounts.iter() {
@ -831,7 +832,7 @@ impl ProgramTest {
)
}
pub async fn start(self) -> (BanksClient, Keypair, Hash) {
pub async fn start(mut self) -> (BanksClient, Keypair, Hash) {
let (bank_forks, block_commitment_cache, last_blockhash, gci) = self.setup_bank();
let target_tick_duration = gci.genesis_config.poh_config.target_tick_duration;
let target_slot_duration = target_tick_duration * gci.genesis_config.ticks_per_slot as u32;
@ -866,7 +867,7 @@ impl ProgramTest {
///
/// Returns a `BanksClient` interface into the test environment as well as a payer `Keypair`
/// with SOL for sending transactions
pub async fn start_with_context(self) -> ProgramTestContext {
pub async fn start_with_context(mut self) -> ProgramTestContext {
let (bank_forks, block_commitment_cache, last_blockhash, gci) = self.setup_bank();
let target_tick_duration = gci.genesis_config.poh_config.target_tick_duration;
let transport = start_local_server(

View File

@ -3884,7 +3884,7 @@ mod tests {
programdata_account = accounts.first().unwrap().clone();
program_account = accounts.get(3).unwrap().clone();
process_instruction(
&program_address,
&loader_id,
&[0, 1],
&[],
vec![

View File

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

View File

@ -56,7 +56,7 @@ use {
ancestors::{Ancestors, AncestorsForSerialization},
bank::metrics::*,
blockhash_queue::BlockhashQueue,
builtins::{self, BuiltinFeatureTransition, Builtins},
builtins::{BuiltinPrototype, BUILTINS},
cost_tracker::CostTracker,
epoch_accounts_hash::{self, EpochAccountsHash},
epoch_stakes::{EpochStakes, NodeVoteAccounts},
@ -93,8 +93,8 @@ use {
solana_perf::perf_libs,
solana_program_runtime::{
accounts_data_meter::MAX_ACCOUNTS_DATA_LEN,
builtin_program::BuiltinPrograms,
compute_budget::{self, ComputeBudget},
invoke_context::ProcessInstructionWithContext,
loaded_programs::{
LoadedProgram, LoadedProgramMatchCriteria, LoadedProgramType, LoadedPrograms,
LoadedProgramsForTxBatch, WorkingSlot,
@ -777,7 +777,6 @@ impl PartialEq for Bank {
// TODO: Confirm if all these fields are intentionally ignored!
builtin_programs: _,
runtime_config: _,
builtin_feature_transitions: _,
rewards: _,
cluster_type: _,
lazy_rent_collection: _,
@ -1016,16 +1015,11 @@ pub struct Bank {
/// stream for the slot == self.slot
is_delta: AtomicBool,
/// The builtin programs
builtin_programs: BuiltinPrograms,
builtin_programs: HashSet<Pubkey>,
/// Optional config parameters that can override runtime behavior
runtime_config: Arc<RuntimeConfig>,
/// Dynamic feature transitions for builtin programs
#[allow(clippy::rc_buffer)]
builtin_feature_transitions: Arc<Vec<BuiltinFeatureTransition>>,
/// Protocol-level rewards that were distributed by this bank
pub rewards: RwLock<Vec<(Pubkey, RewardInfo)>>,
@ -1281,9 +1275,8 @@ impl Bank {
stakes_cache: StakesCache::default(),
epoch_stakes: HashMap::<Epoch, EpochStakes>::default(),
is_delta: AtomicBool::default(),
builtin_programs: BuiltinPrograms::default(),
builtin_programs: HashSet::<Pubkey>::default(),
runtime_config: Arc::<RuntimeConfig>::default(),
builtin_feature_transitions: Arc::<Vec<BuiltinFeatureTransition>>::default(),
rewards: RwLock::<Vec<(Pubkey, RewardInfo)>>::default(),
cluster_type: Option::<ClusterType>::default(),
lazy_rent_collection: AtomicBool::default(),
@ -1358,7 +1351,7 @@ impl Bank {
runtime_config: Arc<RuntimeConfig>,
paths: Vec<PathBuf>,
debug_keys: Option<Arc<HashSet<Pubkey>>>,
additional_builtins: Option<&Builtins>,
additional_builtins: Option<&[BuiltinPrototype]>,
account_indexes: AccountSecondaryIndexes,
shrink_ratio: AccountShrinkThreshold,
debug_do_not_add_builtins: bool,
@ -1555,11 +1548,10 @@ impl Bank {
ancestors: Ancestors::default(),
hash: RwLock::new(Hash::default()),
is_delta: AtomicBool::new(false),
builtin_programs,
tick_height: AtomicU64::new(parent.tick_height.load(Relaxed)),
signature_count: AtomicU64::new(0),
builtin_programs,
runtime_config: parent.runtime_config.clone(),
builtin_feature_transitions: parent.builtin_feature_transitions.clone(),
hard_forks: parent.hard_forks.clone(),
rewards: RwLock::new(vec![]),
cluster_type: parent.cluster_type,
@ -1834,7 +1826,7 @@ impl Bank {
runtime_config: Arc<RuntimeConfig>,
fields: BankFieldsToDeserialize,
debug_keys: Option<Arc<HashSet<Pubkey>>>,
additional_builtins: Option<&Builtins>,
additional_builtins: Option<&[BuiltinPrototype]>,
debug_do_not_add_builtins: bool,
accounts_data_size_initial: u64,
) -> Self {
@ -1902,7 +1894,6 @@ impl Bank {
is_delta: AtomicBool::new(fields.is_delta),
builtin_programs: new(),
runtime_config,
builtin_feature_transitions: new(),
rewards: new(),
cluster_type: Some(genesis_config.cluster_type),
lazy_rent_collection: new(),
@ -4275,7 +4266,6 @@ impl Bank {
let mut programs_updated_only_for_global_cache = LoadedProgramsForTxBatch::new(self.slot);
let mut process_message_time = Measure::start("process_message_time");
let process_result = MessageProcessor::process_message(
&self.builtin_programs,
tx.message(),
&loaded_transaction.program_indices,
&mut transaction_context,
@ -4528,13 +4518,20 @@ impl Bank {
bpf_loader_deprecated::id(),
];
let program_owners_refs: Vec<&Pubkey> = program_owners.iter().collect();
let program_accounts_map = self.rc.accounts.filter_executable_program_accounts(
let mut program_accounts_map = self.rc.accounts.filter_executable_program_accounts(
&self.ancestors,
sanitized_txs,
&mut check_results,
&program_owners_refs,
&self.blockhash_queue.read().unwrap(),
);
for precompile in get_precompiles() {
program_accounts_map.remove(&precompile.program_id);
}
let native_loader = native_loader::id();
for builtin_program in self.builtin_programs.iter() {
program_accounts_map.insert(*builtin_program, &native_loader);
}
let programs_loaded_for_tx_batch = Rc::new(RefCell::new(
self.replenish_program_cache(&program_accounts_map),
@ -6262,24 +6259,24 @@ impl Bank {
fn finish_init(
&mut self,
genesis_config: &GenesisConfig,
additional_builtins: Option<&Builtins>,
additional_builtins: Option<&[BuiltinPrototype]>,
debug_do_not_add_builtins: bool,
) {
self.rewards_pool_pubkeys =
Arc::new(genesis_config.rewards_pools.keys().cloned().collect());
let mut builtins = builtins::get();
if let Some(additional_builtins) = additional_builtins {
builtins
.genesis_builtins
.extend_from_slice(&additional_builtins.genesis_builtins);
builtins
.feature_transitions
.extend_from_slice(&additional_builtins.feature_transitions);
}
if !debug_do_not_add_builtins {
for (program_id, builtin) in builtins.genesis_builtins {
self.add_builtin(program_id, builtin);
for builtin in BUILTINS
.iter()
.chain(additional_builtins.unwrap_or(&[]).iter())
{
if builtin.feature_id.is_none() {
self.add_builtin(
builtin.program_id,
builtin.name.to_string(),
LoadedProgram::new_builtin(0, builtin.name.len(), builtin.entrypoint),
);
}
}
for precompile in get_precompiles() {
if precompile.feature.is_none() {
@ -6287,7 +6284,6 @@ impl Bank {
}
}
}
self.builtin_feature_transitions = Arc::new(builtins.feature_transitions);
self.apply_feature_activations(
ApplyFeatureActivationsCaller::FinishInit,
@ -7311,40 +7307,39 @@ impl Bank {
!self.is_delta.load(Relaxed)
}
pub fn add_mockup_builtin(
&mut self,
program_id: Pubkey,
entrypoint: ProcessInstructionWithContext,
) {
self.add_builtin(
program_id,
"mockup".to_string(),
LoadedProgram::new_builtin(0, 0, entrypoint),
);
}
/// Add a built-in program
pub fn add_builtin(&mut self, program_id: Pubkey, builtin: Arc<LoadedProgram>) {
let name = match &builtin.program {
LoadedProgramType::Builtin(name, _) => name,
_ => unreachable!(),
};
pub fn add_builtin(&mut self, program_id: Pubkey, name: String, builtin: LoadedProgram) {
debug!("Adding program {} under {:?}", name, program_id);
self.add_builtin_account(name.as_str(), &program_id, false);
if let Some(entry) = self
.builtin_programs
.vec
.iter_mut()
.find(|entry| entry.0 == program_id)
{
entry.1 = builtin.clone();
} else {
self.builtin_programs
.vec
.push((program_id, builtin.clone()));
}
self.builtin_programs.insert(program_id);
self.loaded_programs_cache
.write()
.unwrap()
.replenish(program_id, Arc::new(builtin));
debug!("Added program {} under {:?}", name, program_id);
}
/// Remove a built-in instruction processor
pub fn remove_builtin(&mut self, program_id: Pubkey) {
pub fn remove_builtin(&mut self, program_id: Pubkey, name: String) {
debug!("Removing program {}", program_id);
// Don't remove the account since the bank expects the account state to
// be idempotent
self.add_builtin(
program_id,
Arc::new(LoadedProgram::new_tombstone(
self.slot,
LoadedProgramType::Closed,
)),
name,
LoadedProgram::new_tombstone(self.slot, LoadedProgramType::Closed),
);
debug!("Removed program {}", program_id);
}
@ -7573,18 +7568,25 @@ impl Bank {
only_apply_transitions_for_new_features: bool,
new_feature_activations: &HashSet<Pubkey>,
) {
let feature_set = self.feature_set.clone();
let builtin_feature_transitions = self.builtin_feature_transitions.clone();
for transition in builtin_feature_transitions.iter() {
let should_apply_action_for_feature_transition =
if only_apply_transitions_for_new_features {
new_feature_activations.contains(&transition.feature_id)
} else {
feature_set.is_active(&transition.feature_id)
};
if should_apply_action_for_feature_transition {
self.add_builtin(transition.program_id, transition.builtin.clone());
for builtin in BUILTINS.iter() {
if let Some(feature_id) = builtin.feature_id {
let should_apply_action_for_feature_transition =
if only_apply_transitions_for_new_features {
new_feature_activations.contains(&feature_id)
} else {
self.feature_set.is_active(&feature_id)
};
if should_apply_action_for_feature_transition {
self.add_builtin(
builtin.program_id,
builtin.name.to_string(),
LoadedProgram::new_builtin(
self.feature_set.activated_slot(&feature_id).unwrap_or(0),
builtin.name.len(),
builtin.entrypoint,
),
);
}
}
}
@ -7775,11 +7777,6 @@ impl Bank {
&mut error_counters,
)
}
/// Return reference to builtin_progams
pub fn get_builtin_programs(&self) -> &BuiltinPrograms {
&self.builtin_programs
}
}
/// Compute how much an account has changed size. This function is useful when the data size delta

View File

@ -33,11 +33,10 @@ use {
serde::{Deserialize, Serialize},
solana_logger,
solana_program_runtime::{
builtin_program::create_builtin,
compute_budget::{self, ComputeBudget, MAX_COMPUTE_UNIT_LIMIT},
declare_process_instruction,
invoke_context::mock_process_instruction,
loaded_programs::{LoadedProgramType, DELAY_VISIBILITY_SLOT_OFFSET},
loaded_programs::{LoadedProgram, LoadedProgramType, DELAY_VISIBILITY_SLOT_OFFSET},
prioritization_fee::{PrioritizationFeeDetails, PrioritizationFeeType},
timings::ExecuteTimings,
},
@ -1379,10 +1378,7 @@ 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_id,
create_builtin("mockup".to_string(), process_instruction),
);
bank.add_mockup_builtin(mock_program_id, process_instruction);
assert_eq!(bank.last_blockhash(), genesis_config.hash());
@ -4818,10 +4814,7 @@ fn test_add_builtin() {
});
assert!(bank.get_account(&mock_vote_program_id()).is_none());
bank.add_builtin(
mock_vote_program_id(),
create_builtin("mockup".to_string(), process_instruction),
);
bank.add_mockup_builtin(mock_vote_program_id(), process_instruction);
assert!(bank.get_account(&mock_vote_program_id()).is_some());
let mock_account = Keypair::new();
@ -4894,10 +4887,7 @@ fn test_add_duplicate_static_program() {
);
let vote_loader_account = bank.get_account(&solana_vote_program::id()).unwrap();
bank.add_builtin(
solana_vote_program::id(),
create_builtin("mockup".to_string(), process_instruction),
);
bank.add_mockup_builtin(solana_vote_program::id(), 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.
assert_eq!(vote_loader_account.data(), new_vote_loader_account.data());
@ -4950,11 +4940,13 @@ fn test_add_instruction_processor_for_existing_unrelated_accounts() {
bank.add_builtin(
vote_id,
create_builtin("mock_program1".to_string(), process_instruction),
"mock_program1".to_string(),
LoadedProgram::new_builtin(0, 0, process_instruction),
);
bank.add_builtin(
stake_id,
create_builtin("mock_program2".to_string(), process_instruction),
"mock_program2".to_string(),
LoadedProgram::new_builtin(0, 0, process_instruction),
);
{
let stakes = bank.stakes_cache.stakes();
@ -4978,14 +4970,8 @@ 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(
vote_id,
create_builtin("mockup".to_string(), process_instruction),
);
bank.add_builtin(
stake_id,
create_builtin("mockup".to_string(), process_instruction),
);
bank.add_mockup_builtin(vote_id, process_instruction);
bank.add_mockup_builtin(stake_id, process_instruction);
add_root_and_flush_write_cache(&bank);
bank.update_accounts_hash_for_tests();
let new_hash = bank.get_accounts_hash().unwrap();
@ -6236,10 +6222,7 @@ fn test_transaction_with_duplicate_accounts_in_instruction() {
});
let mock_program_id = Pubkey::from([2u8; 32]);
bank.add_builtin(
mock_program_id,
create_builtin("mockup".to_string(), process_instruction),
);
bank.add_mockup_builtin(mock_program_id, process_instruction);
let from_pubkey = solana_sdk::pubkey::new_rand();
let to_pubkey = solana_sdk::pubkey::new_rand();
@ -6275,10 +6258,7 @@ 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_id,
create_builtin("mockup".to_string(), process_instruction),
);
bank.add_mockup_builtin(mock_program_id, process_instruction);
let from_pubkey = solana_sdk::pubkey::new_rand();
let to_pubkey = solana_sdk::pubkey::new_rand();
@ -6330,10 +6310,7 @@ fn test_account_ids_after_program_ids() {
tx.message.account_keys.push(solana_sdk::pubkey::new_rand());
bank.add_builtin(
solana_vote_program::id(),
create_builtin("mockup".to_string(), process_instruction),
);
bank.add_mockup_builtin(solana_vote_program::id(), process_instruction);
let result = bank.process_transaction(&tx);
assert_eq!(result, Ok(()));
let account = bank.get_account(&solana_vote_program::id()).unwrap();
@ -6383,10 +6360,7 @@ fn test_duplicate_account_key() {
AccountMeta::new(to_pubkey, false),
];
bank.add_builtin(
solana_vote_program::id(),
create_builtin("mockup".to_string(), process_instruction),
);
bank.add_mockup_builtin(solana_vote_program::id(), process_instruction);
let instruction = Instruction::new_with_bincode(solana_vote_program::id(), &10, account_metas);
let mut tx = Transaction::new_signed_with_payer(
@ -6415,10 +6389,7 @@ fn test_process_transaction_with_too_many_account_locks() {
AccountMeta::new(to_pubkey, false),
];
bank.add_builtin(
solana_vote_program::id(),
create_builtin("mockup".to_string(), process_instruction),
);
bank.add_mockup_builtin(solana_vote_program::id(), process_instruction);
let instruction = Instruction::new_with_bincode(solana_vote_program::id(), &10, account_metas);
let mut tx = Transaction::new_signed_with_payer(
@ -6451,10 +6422,7 @@ fn test_program_id_as_payer() {
AccountMeta::new(to_pubkey, false),
];
bank.add_builtin(
solana_vote_program::id(),
create_builtin("mockup".to_string(), process_instruction),
);
bank.add_mockup_builtin(solana_vote_program::id(), process_instruction);
let instruction = Instruction::new_with_bincode(solana_vote_program::id(), &10, account_metas);
let mut tx = Transaction::new_signed_with_payer(
@ -6497,10 +6465,7 @@ fn test_ref_account_key_after_program_id() {
AccountMeta::new(to_pubkey, false),
];
bank.add_builtin(
solana_vote_program::id(),
create_builtin("mockup".to_string(), process_instruction),
);
bank.add_mockup_builtin(solana_vote_program::id(), process_instruction);
let instruction = Instruction::new_with_bincode(solana_vote_program::id(), &10, account_metas);
let mut tx = Transaction::new_signed_with_payer(
@ -6531,7 +6496,11 @@ fn test_fuzz_instructions() {
.map(|i| {
let key = solana_sdk::pubkey::new_rand();
let name = format!("program{i:?}");
bank.add_builtin(key, create_builtin(name.clone(), process_instruction));
bank.add_builtin(
key,
name.clone(),
LoadedProgram::new_builtin(0, 0, process_instruction),
);
(key, name.as_bytes().to_vec())
})
.collect();
@ -6737,10 +6706,7 @@ fn test_same_program_id_uses_unqiue_executable_accounts() {
// Add a new program
let program1_pubkey = solana_sdk::pubkey::new_rand();
bank.add_builtin(
program1_pubkey,
create_builtin("mockup".to_string(), process_instruction),
);
bank.add_mockup_builtin(program1_pubkey, process_instruction);
// Add a new program owned by the first
let program2_pubkey = solana_sdk::pubkey::new_rand();
@ -6955,17 +6921,15 @@ fn test_add_builtin_no_overwrite() {
));
assert_eq!(bank.get_account_modified_slot(&program_id), None);
Arc::get_mut(&mut bank).unwrap().add_builtin(
program_id,
create_builtin("mockup".to_string(), process_instruction),
);
Arc::get_mut(&mut bank)
.unwrap()
.add_mockup_builtin(program_id, 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(
program_id,
create_builtin("mockup".to_string(), process_instruction),
);
Arc::get_mut(&mut bank)
.unwrap()
.add_mockup_builtin(program_id, process_instruction);
assert_eq!(bank.get_account_modified_slot(&program_id).unwrap().1, slot);
}
@ -6981,17 +6945,15 @@ 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(
loader_id,
create_builtin("mockup".to_string(), process_instruction),
);
Arc::get_mut(&mut bank)
.unwrap()
.add_mockup_builtin(loader_id, 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(
loader_id,
create_builtin("mockup".to_string(), process_instruction),
);
Arc::get_mut(&mut bank)
.unwrap()
.add_mockup_builtin(loader_id, process_instruction);
assert_eq!(bank.get_account_modified_slot(&loader_id).unwrap().1, slot);
}
@ -9576,10 +9538,7 @@ fn test_tx_return_data() {
let mock_program_id = Pubkey::from([2u8; 32]);
let blockhash = bank.last_blockhash();
bank.add_builtin(
mock_program_id,
create_builtin("mockup".to_string(), process_instruction),
);
bank.add_mockup_builtin(mock_program_id, process_instruction);
for index in [
None,
@ -9768,10 +9727,7 @@ fn test_transfer_sysvar() {
});
let program_id = solana_sdk::pubkey::new_rand();
bank.add_builtin(
program_id,
create_builtin("mockup".to_string(), process_instruction),
);
bank.add_mockup_builtin(program_id, process_instruction);
let blockhash = bank.last_blockhash();
#[allow(deprecated)]
@ -9983,10 +9939,7 @@ fn test_compute_budget_program_noop() {
Ok(())
});
let program_id = solana_sdk::pubkey::new_rand();
bank.add_builtin(
program_id,
create_builtin("mockup".to_string(), process_instruction),
);
bank.add_mockup_builtin(program_id, process_instruction);
let message = Message::new(
&[
@ -10029,10 +9982,7 @@ fn test_compute_request_instruction() {
Ok(())
});
let program_id = solana_sdk::pubkey::new_rand();
bank.add_builtin(
program_id,
create_builtin("mockup".to_string(), process_instruction),
);
bank.add_mockup_builtin(program_id, process_instruction);
let message = Message::new(
&[
@ -10082,10 +10032,7 @@ fn test_failed_compute_request_instruction() {
Ok(())
});
let program_id = solana_sdk::pubkey::new_rand();
bank.add_builtin(
program_id,
create_builtin("mockup".to_string(), process_instruction),
);
bank.add_mockup_builtin(program_id, process_instruction);
// This message will not be executed because the compute budget request is invalid
let message0 = Message::new(
@ -10759,10 +10706,7 @@ fn test_invalid_rent_state_changes_existing_accounts() {
);
let mut bank = Bank::new_for_tests(&genesis_config);
bank.add_builtin(
mock_program_id,
create_builtin("mockup".to_string(), mock_transfer_process_instruction),
);
bank.add_mockup_builtin(mock_program_id, mock_transfer_process_instruction);
let recent_blockhash = bank.last_blockhash();
let check_account_is_rent_exempt = |pubkey: &Pubkey| -> bool {
@ -10845,10 +10789,7 @@ fn test_invalid_rent_state_changes_new_accounts() {
let rent_exempt_minimum = genesis_config.rent.minimum_balance(account_data_size);
let mut bank = Bank::new_for_tests(&genesis_config);
bank.add_builtin(
mock_program_id,
create_builtin("mockup".to_string(), mock_transfer_process_instruction),
);
bank.add_mockup_builtin(mock_program_id, mock_transfer_process_instruction);
let recent_blockhash = bank.last_blockhash();
let check_account_is_rent_exempt = |pubkey: &Pubkey| -> bool {
@ -10907,10 +10848,7 @@ fn test_drained_created_account() {
let created_keypair = Keypair::new();
let mut bank = Bank::new_for_tests(&genesis_config);
bank.add_builtin(
mock_program_id,
create_builtin("mockup".to_string(), mock_transfer_process_instruction),
);
bank.add_mockup_builtin(mock_program_id, mock_transfer_process_instruction);
let recent_blockhash = bank.last_blockhash();
// Create and drain a small data size account
@ -11562,10 +11500,7 @@ fn test_resize_and_rent() {
let mut bank = Bank::new_for_tests(&genesis_config);
let mock_program_id = Pubkey::new_unique();
bank.add_builtin(
mock_program_id,
create_builtin("mockup".to_string(), mock_realloc_process_instruction),
);
bank.add_mockup_builtin(mock_program_id, mock_realloc_process_instruction);
let recent_blockhash = bank.last_blockhash();
let account_data_size_small = 1024;
@ -11836,10 +11771,7 @@ fn test_accounts_data_size_and_resize_transactions() {
} = genesis_utils::create_genesis_config(100 * LAMPORTS_PER_SOL);
let mut bank = Bank::new_for_tests(&genesis_config);
let mock_program_id = Pubkey::new_unique();
bank.add_builtin(
mock_program_id,
create_builtin("mockup".to_string(), mock_realloc_process_instruction),
);
bank.add_mockup_builtin(mock_program_id, mock_realloc_process_instruction);
let recent_blockhash = bank.last_blockhash();

View File

@ -1,120 +1,104 @@
use {
solana_program_runtime::{builtin_program::create_builtin, loaded_programs::LoadedProgram},
solana_program_runtime::invoke_context::ProcessInstructionWithContext,
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<(Pubkey, Arc<LoadedProgram>)>,
/// Dynamic feature transitions for builtin programs
pub feature_transitions: Vec<BuiltinFeatureTransition>,
/// Transitions of built-in programs at epoch bondaries when features are activated.
pub struct BuiltinPrototype {
pub feature_id: Option<Pubkey>,
pub program_id: Pubkey,
pub name: &'static str,
pub entrypoint: ProcessInstructionWithContext,
}
/// Transitions of built-in programs at epoch bondaries when features are activated.
#[derive(Debug, Default, Clone)]
pub struct BuiltinFeatureTransition {
pub feature_id: Pubkey,
pub program_id: Pubkey,
pub builtin: Arc<LoadedProgram>,
impl std::fmt::Debug for BuiltinPrototype {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let mut builder = f.debug_struct("BuiltinPrototype");
builder.field("program_id", &self.program_id);
builder.field("name", &self.name);
builder.field("feature_id", &self.feature_id);
builder.finish()
}
}
#[cfg(RUSTC_WITH_SPECIALIZATION)]
impl solana_frozen_abi::abi_example::AbiExample for BuiltinFeatureTransition {
impl solana_frozen_abi::abi_example::AbiExample for BuiltinPrototype {
fn example() -> Self {
// BuiltinFeatureTransition isn't serializable by definition.
Self::default()
// BuiltinPrototype isn't serializable by definition.
solana_program_runtime::declare_process_instruction!(entrypoint, 0, |_invoke_context| {
// Do nothing
Ok(())
});
Self {
feature_id: None,
program_id: Pubkey::default(),
name: "",
entrypoint,
}
}
}
/// Built-in programs that are always available
fn genesis_builtins() -> Vec<(Pubkey, Arc<LoadedProgram>)> {
vec![
(
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,
),
),
(
solana_sdk::compute_budget::id(),
create_builtin(
"compute_budget_program".to_string(),
solana_compute_budget_program::process_instruction,
),
),
(
solana_address_lookup_table_program::id(),
create_builtin(
"address_lookup_table_program".to_string(),
solana_address_lookup_table_program::processor::process_instruction,
),
),
]
}
/// Dynamic feature transitions for builtin programs
fn builtin_feature_transitions() -> Vec<BuiltinFeatureTransition> {
vec![BuiltinFeatureTransition {
feature_id: feature_set::zk_token_sdk_enabled::id(),
pub static BUILTINS: &[BuiltinPrototype] = &[
BuiltinPrototype {
feature_id: None,
program_id: solana_system_program::id(),
name: "system_program",
entrypoint: solana_system_program::system_processor::process_instruction,
},
BuiltinPrototype {
feature_id: None,
program_id: solana_vote_program::id(),
name: "vote_program",
entrypoint: solana_vote_program::vote_processor::process_instruction,
},
BuiltinPrototype {
feature_id: None,
program_id: solana_stake_program::id(),
name: "stake_program",
entrypoint: solana_stake_program::stake_instruction::process_instruction,
},
BuiltinPrototype {
feature_id: None,
program_id: solana_config_program::id(),
name: "config_program",
entrypoint: solana_config_program::config_processor::process_instruction,
},
BuiltinPrototype {
feature_id: None,
program_id: bpf_loader_deprecated::id(),
name: "solana_bpf_loader_deprecated_program",
entrypoint: solana_bpf_loader_program::process_instruction,
},
BuiltinPrototype {
feature_id: None,
program_id: bpf_loader::id(),
name: "solana_bpf_loader_program",
entrypoint: solana_bpf_loader_program::process_instruction,
},
BuiltinPrototype {
feature_id: None,
program_id: bpf_loader_upgradeable::id(),
name: "solana_bpf_loader_upgradeable_program",
entrypoint: solana_bpf_loader_program::process_instruction,
},
BuiltinPrototype {
feature_id: None,
program_id: solana_sdk::compute_budget::id(),
name: "compute_budget_program",
entrypoint: solana_compute_budget_program::process_instruction,
},
BuiltinPrototype {
feature_id: None,
program_id: solana_address_lookup_table_program::id(),
name: "address_lookup_table_program",
entrypoint: solana_address_lookup_table_program::processor::process_instruction,
},
BuiltinPrototype {
feature_id: Some(feature_set::zk_token_sdk_enabled::id()),
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,
),
}]
}
pub(crate) fn get() -> Builtins {
Builtins {
genesis_builtins: genesis_builtins(),
feature_transitions: builtin_feature_transitions(),
}
}
name: "zk_token_proof_program",
entrypoint: solana_zk_token_proof_program::process_instruction,
},
];

View File

@ -2,7 +2,6 @@ use {
serde::{Deserialize, Serialize},
solana_measure::measure::Measure,
solana_program_runtime::{
builtin_program::BuiltinPrograms,
compute_budget::ComputeBudget,
invoke_context::InvokeContext,
loaded_programs::LoadedProgramsForTxBatch,
@ -52,7 +51,6 @@ impl MessageProcessor {
/// The accounts are committed back to the bank only if every instruction succeeds.
#[allow(clippy::too_many_arguments)]
pub fn process_message(
builtin_programs: &BuiltinPrograms,
message: &SanitizedMessage,
program_indices: &[Vec<IndexOfAccount>],
transaction_context: &mut TransactionContext,
@ -73,7 +71,6 @@ impl MessageProcessor {
let mut invoke_context = InvokeContext::new(
transaction_context,
rent,
builtin_programs,
sysvar_cache,
log_collector,
compute_budget,
@ -193,7 +190,7 @@ mod tests {
use {
super::*,
crate::rent_collector::RentCollector,
solana_program_runtime::declare_process_instruction,
solana_program_runtime::{declare_process_instruction, loaded_programs::LoadedProgram},
solana_sdk::{
account::{AccountSharedData, ReadableAccount},
instruction::{AccountMeta, Instruction, InstructionError},
@ -254,10 +251,7 @@ mod tests {
let writable_pubkey = Pubkey::new_unique();
let readonly_pubkey = Pubkey::new_unique();
let mock_system_program_id = Pubkey::new_unique();
let rent_collector = RentCollector::default();
let builtin_programs =
BuiltinPrograms::new_mock(mock_system_program_id, process_instruction);
let accounts = vec![
(
@ -276,7 +270,11 @@ mod tests {
let mut transaction_context =
TransactionContext::new(accounts, Some(Rent::default()), 1, 3);
let program_indices = vec![vec![2]];
let programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
programs_loaded_for_tx_batch.replenish(
mock_system_program_id,
Arc::new(LoadedProgram::new_builtin(0, 0, process_instruction)),
);
let account_keys = (0..transaction_context.get_number_of_accounts())
.map(|index| {
*transaction_context
@ -308,7 +306,6 @@ mod tests {
let mut programs_modified_by_tx = LoadedProgramsForTxBatch::default();
let mut programs_updated_only_for_global_cache = LoadedProgramsForTxBatch::default();
let result = MessageProcessor::process_message(
&builtin_programs,
&message,
&program_indices,
&mut transaction_context,
@ -362,7 +359,6 @@ mod tests {
let mut programs_modified_by_tx = LoadedProgramsForTxBatch::default();
let mut programs_updated_only_for_global_cache = LoadedProgramsForTxBatch::default();
let result = MessageProcessor::process_message(
&builtin_programs,
&message,
&program_indices,
&mut transaction_context,
@ -406,7 +402,6 @@ mod tests {
let mut programs_modified_by_tx = LoadedProgramsForTxBatch::default();
let mut programs_updated_only_for_global_cache = LoadedProgramsForTxBatch::default();
let result = MessageProcessor::process_message(
&builtin_programs,
&message,
&program_indices,
&mut transaction_context,
@ -490,11 +485,8 @@ mod tests {
Err(InstructionError::InvalidInstructionData)
}
});
let mock_program_id = Pubkey::from([2u8; 32]);
let rent_collector = RentCollector::default();
let builtin_programs = BuiltinPrograms::new_mock(mock_program_id, process_instruction);
let accounts = vec![
(
solana_sdk::pubkey::new_rand(),
@ -512,7 +504,11 @@ mod tests {
let mut transaction_context =
TransactionContext::new(accounts, Some(Rent::default()), 1, 3);
let program_indices = vec![vec![2]];
let programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
programs_loaded_for_tx_batch.replenish(
mock_program_id,
Arc::new(LoadedProgram::new_builtin(0, 0, process_instruction)),
);
let account_metas = vec![
AccountMeta::new(
*transaction_context.get_key_of_account_at_index(0).unwrap(),
@ -541,7 +537,6 @@ mod tests {
let mut programs_modified_by_tx = LoadedProgramsForTxBatch::default();
let mut programs_updated_only_for_global_cache = LoadedProgramsForTxBatch::default();
let result = MessageProcessor::process_message(
&builtin_programs,
&message,
&program_indices,
&mut transaction_context,
@ -579,7 +574,6 @@ mod tests {
let mut programs_modified_by_tx = LoadedProgramsForTxBatch::default();
let mut programs_updated_only_for_global_cache = LoadedProgramsForTxBatch::default();
let result = MessageProcessor::process_message(
&builtin_programs,
&message,
&program_indices,
&mut transaction_context,
@ -614,7 +608,6 @@ mod tests {
let mut programs_modified_by_tx = LoadedProgramsForTxBatch::default();
let mut programs_updated_only_for_global_cache = LoadedProgramsForTxBatch::default();
let result = MessageProcessor::process_message(
&builtin_programs,
&message,
&program_indices,
&mut transaction_context,
@ -665,7 +658,6 @@ mod tests {
declare_process_instruction!(process_instruction, 1, |_invoke_context| {
Err(InstructionError::Custom(0xbabb1e))
});
let builtin_programs = BuiltinPrograms::new_mock(mock_program_id, process_instruction);
let mut secp256k1_account = AccountSharedData::new(1, 0, &native_loader::id());
secp256k1_account.set_executable(true);
@ -689,11 +681,14 @@ mod tests {
None,
)));
let sysvar_cache = SysvarCache::default();
let programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
let mut programs_loaded_for_tx_batch = LoadedProgramsForTxBatch::default();
programs_loaded_for_tx_batch.replenish(
mock_program_id,
Arc::new(LoadedProgram::new_builtin(0, 0, process_instruction)),
);
let mut programs_modified_by_tx = LoadedProgramsForTxBatch::default();
let mut programs_updated_only_for_global_cache = LoadedProgramsForTxBatch::default();
let result = MessageProcessor::process_message(
&builtin_programs,
&message,
&[vec![0], vec![1]],
&mut transaction_context,

View File

@ -12,7 +12,7 @@ use {
accounts_update_notifier_interface::AccountsUpdateNotifier,
bank::{Bank, BankFieldsToDeserialize, BankRc},
blockhash_queue::BlockhashQueue,
builtins::Builtins,
builtins::BuiltinPrototype,
epoch_accounts_hash::EpochAccountsHash,
epoch_stakes::EpochStakes,
rent_collector::RentCollector,
@ -353,7 +353,7 @@ pub(crate) fn bank_from_streams<R>(
genesis_config: &GenesisConfig,
runtime_config: &RuntimeConfig,
debug_keys: Option<Arc<HashSet<Pubkey>>>,
additional_builtins: Option<&Builtins>,
additional_builtins: Option<&[BuiltinPrototype]>,
account_secondary_indexes: AccountSecondaryIndexes,
limit_load_slot_count_from_snapshot: Option<usize>,
shrink_ratio: AccountShrinkThreshold,
@ -563,7 +563,7 @@ fn reconstruct_bank_from_fields<E>(
account_paths: &[PathBuf],
storage_and_next_append_vec_id: StorageAndNextAppendVecId,
debug_keys: Option<Arc<HashSet<Pubkey>>>,
additional_builtins: Option<&Builtins>,
additional_builtins: Option<&[BuiltinPrototype]>,
account_secondary_indexes: AccountSecondaryIndexes,
limit_load_slot_count_from_snapshot: Option<usize>,
shrink_ratio: AccountShrinkThreshold,

View File

@ -7,6 +7,7 @@ use {
},
accounts_partition,
bank::Bank,
builtins::BUILTINS,
static_ids,
},
dashmap::DashSet,
@ -114,13 +115,9 @@ impl<'a> SnapshotMinimizer<'a> {
/// Used to get builtin accounts in `minimize`
fn get_builtins(&self) {
self.bank
.get_builtin_programs()
.vec
.iter()
.for_each(|(pubkey, _builtin)| {
self.minimized_account_set.insert(*pubkey);
});
BUILTINS.iter().for_each(|e| {
self.minimized_account_set.insert(e.program_id);
});
}
/// Used to get static runtime accounts in `minimize`

View File

@ -10,7 +10,7 @@ use {
accounts_update_notifier_interface::AccountsUpdateNotifier,
append_vec::AppendVec,
bank::{Bank, BankFieldsToDeserialize, BankSlotDelta},
builtins::Builtins,
builtins::BuiltinPrototype,
hardened_unpack::{
streaming_unpack_snapshot, unpack_snapshot, ParallelSelector, UnpackError,
UnpackedAppendVecMap,
@ -1475,7 +1475,7 @@ pub fn bank_from_snapshot_archives(
genesis_config: &GenesisConfig,
runtime_config: &RuntimeConfig,
debug_keys: Option<Arc<HashSet<Pubkey>>>,
additional_builtins: Option<&Builtins>,
additional_builtins: Option<&[BuiltinPrototype]>,
account_secondary_indexes: AccountSecondaryIndexes,
limit_load_slot_count_from_snapshot: Option<usize>,
shrink_ratio: AccountShrinkThreshold,
@ -1594,7 +1594,7 @@ pub fn bank_from_latest_snapshot_archives(
genesis_config: &GenesisConfig,
runtime_config: &RuntimeConfig,
debug_keys: Option<Arc<HashSet<Pubkey>>>,
additional_builtins: Option<&Builtins>,
additional_builtins: Option<&[BuiltinPrototype]>,
account_secondary_indexes: AccountSecondaryIndexes,
limit_load_slot_count_from_snapshot: Option<usize>,
shrink_ratio: AccountShrinkThreshold,
@ -1689,7 +1689,7 @@ pub fn bank_from_snapshot_dir(
genesis_config: &GenesisConfig,
runtime_config: &RuntimeConfig,
debug_keys: Option<Arc<HashSet<Pubkey>>>,
additional_builtins: Option<&Builtins>,
additional_builtins: Option<&[BuiltinPrototype]>,
account_secondary_indexes: AccountSecondaryIndexes,
limit_load_slot_count_from_snapshot: Option<usize>,
shrink_ratio: AccountShrinkThreshold,
@ -1757,7 +1757,7 @@ pub fn bank_from_latest_snapshot_dir(
runtime_config: &RuntimeConfig,
account_paths: &[PathBuf],
debug_keys: Option<Arc<HashSet<Pubkey>>>,
additional_builtins: Option<&Builtins>,
additional_builtins: Option<&[BuiltinPrototype]>,
account_secondary_indexes: AccountSecondaryIndexes,
limit_load_slot_count_from_snapshot: Option<usize>,
shrink_ratio: AccountShrinkThreshold,
@ -2599,7 +2599,7 @@ fn rebuild_bank_from_unarchived_snapshots(
genesis_config: &GenesisConfig,
runtime_config: &RuntimeConfig,
debug_keys: Option<Arc<HashSet<Pubkey>>>,
additional_builtins: Option<&Builtins>,
additional_builtins: Option<&[BuiltinPrototype]>,
account_secondary_indexes: AccountSecondaryIndexes,
limit_load_slot_count_from_snapshot: Option<usize>,
shrink_ratio: AccountShrinkThreshold,
@ -2695,7 +2695,7 @@ fn rebuild_bank_from_snapshot(
genesis_config: &GenesisConfig,
runtime_config: &RuntimeConfig,
debug_keys: Option<Arc<HashSet<Pubkey>>>,
additional_builtins: Option<&Builtins>,
additional_builtins: Option<&[BuiltinPrototype]>,
account_secondary_indexes: AccountSecondaryIndexes,
limit_load_slot_count_from_snapshot: Option<usize>,
shrink_ratio: AccountShrinkThreshold,