Refactor - `LoadedProgramType::Loaded` and `LoadedProgramOwner` (#606)
* Adds LoadedProgram::account_owner() and LoadedProgramOwner. Merges LoadedProgramTypes LegacyV0, LegacyV1, Typed and TestLoaded into Loaded. * Review feedback.
This commit is contained in:
parent
2aeac5b468
commit
ac36dbbc87
|
@ -344,7 +344,7 @@ fn load_program<'a>(
|
|||
);
|
||||
match result {
|
||||
Ok(loaded_program) => match loaded_program.program {
|
||||
LoadedProgramType::LegacyV1(program) => Ok(program),
|
||||
LoadedProgramType::Loaded(program) => Ok(program),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Err(err) => Err(format!("Loading executable failed: {err:?}")),
|
||||
|
|
|
@ -16,7 +16,7 @@ use {
|
|||
solana_sdk::{
|
||||
bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable,
|
||||
clock::{Epoch, Slot},
|
||||
loader_v4,
|
||||
loader_v4, native_loader,
|
||||
pubkey::Pubkey,
|
||||
saturating_add_assign,
|
||||
},
|
||||
|
@ -60,6 +60,48 @@ pub trait ForkGraph {
|
|||
}
|
||||
}
|
||||
|
||||
/// The owner of a programs accounts, thus the loader of a program
|
||||
#[derive(Default, Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum LoadedProgramOwner {
|
||||
#[default]
|
||||
NativeLoader,
|
||||
LoaderV1,
|
||||
LoaderV2,
|
||||
LoaderV3,
|
||||
LoaderV4,
|
||||
}
|
||||
|
||||
impl TryFrom<&Pubkey> for LoadedProgramOwner {
|
||||
type Error = ();
|
||||
fn try_from(loader_key: &Pubkey) -> Result<Self, ()> {
|
||||
if native_loader::check_id(loader_key) {
|
||||
Ok(LoadedProgramOwner::NativeLoader)
|
||||
} else if bpf_loader_deprecated::check_id(loader_key) {
|
||||
Ok(LoadedProgramOwner::LoaderV1)
|
||||
} else if bpf_loader::check_id(loader_key) {
|
||||
Ok(LoadedProgramOwner::LoaderV2)
|
||||
} else if bpf_loader_upgradeable::check_id(loader_key) {
|
||||
Ok(LoadedProgramOwner::LoaderV3)
|
||||
} else if loader_v4::check_id(loader_key) {
|
||||
Ok(LoadedProgramOwner::LoaderV4)
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<LoadedProgramOwner> for Pubkey {
|
||||
fn from(loaded_program_owner: LoadedProgramOwner) -> Self {
|
||||
match loaded_program_owner {
|
||||
LoadedProgramOwner::NativeLoader => native_loader::id(),
|
||||
LoadedProgramOwner::LoaderV1 => bpf_loader_deprecated::id(),
|
||||
LoadedProgramOwner::LoaderV2 => bpf_loader::id(),
|
||||
LoadedProgramOwner::LoaderV3 => bpf_loader_upgradeable::id(),
|
||||
LoadedProgramOwner::LoaderV4 => loader_v4::id(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Actual payload of [LoadedProgram].
|
||||
#[derive(Default)]
|
||||
pub enum LoadedProgramType {
|
||||
|
@ -76,14 +118,8 @@ pub enum LoadedProgramType {
|
|||
///
|
||||
/// It continues to track usage statistics even when the compiled executable of the program is evicted from memory.
|
||||
Unloaded(ProgramRuntimeEnvironment),
|
||||
/// Verified and compiled program of loader-v1 or loader-v2
|
||||
LegacyV0(Executable<InvokeContext<'static>>),
|
||||
/// Verified and compiled program of loader-v3 (aka upgradable loader)
|
||||
LegacyV1(Executable<InvokeContext<'static>>),
|
||||
/// Verified and compiled program of loader-v4
|
||||
Typed(Executable<InvokeContext<'static>>),
|
||||
#[cfg(test)]
|
||||
TestLoaded(ProgramRuntimeEnvironment),
|
||||
/// Verified and compiled program
|
||||
Loaded(Executable<InvokeContext<'static>>),
|
||||
/// A built-in program which is not stored on-chain but backed into and distributed with the validator
|
||||
Builtin(BuiltinProgram<InvokeContext<'static>>),
|
||||
}
|
||||
|
@ -97,11 +133,7 @@ impl Debug for LoadedProgramType {
|
|||
LoadedProgramType::Closed => write!(f, "LoadedProgramType::Closed"),
|
||||
LoadedProgramType::DelayVisibility => write!(f, "LoadedProgramType::DelayVisibility"),
|
||||
LoadedProgramType::Unloaded(_) => write!(f, "LoadedProgramType::Unloaded"),
|
||||
LoadedProgramType::LegacyV0(_) => write!(f, "LoadedProgramType::LegacyV0"),
|
||||
LoadedProgramType::LegacyV1(_) => write!(f, "LoadedProgramType::LegacyV1"),
|
||||
LoadedProgramType::Typed(_) => write!(f, "LoadedProgramType::Typed"),
|
||||
#[cfg(test)]
|
||||
LoadedProgramType::TestLoaded(_) => write!(f, "LoadedProgramType::TestLoaded"),
|
||||
LoadedProgramType::Loaded(_) => write!(f, "LoadedProgramType::Loaded"),
|
||||
LoadedProgramType::Builtin(_) => write!(f, "LoadedProgramType::Builtin"),
|
||||
}
|
||||
}
|
||||
|
@ -111,14 +143,10 @@ impl LoadedProgramType {
|
|||
/// Returns a reference to its environment if it has one
|
||||
pub fn get_environment(&self) -> Option<&ProgramRuntimeEnvironment> {
|
||||
match self {
|
||||
LoadedProgramType::LegacyV0(program)
|
||||
| LoadedProgramType::LegacyV1(program)
|
||||
| LoadedProgramType::Typed(program) => Some(program.get_loader()),
|
||||
LoadedProgramType::Loaded(program) => Some(program.get_loader()),
|
||||
LoadedProgramType::FailedVerification(env) | LoadedProgramType::Unloaded(env) => {
|
||||
Some(env)
|
||||
}
|
||||
#[cfg(test)]
|
||||
LoadedProgramType::TestLoaded(environment) => Some(environment),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -131,6 +159,8 @@ impl LoadedProgramType {
|
|||
pub struct LoadedProgram {
|
||||
/// The program of this entry
|
||||
pub program: LoadedProgramType,
|
||||
/// The loader of this entry
|
||||
pub account_owner: LoadedProgramOwner,
|
||||
/// Size of account that stores the program and program data
|
||||
pub account_size: usize,
|
||||
/// Slot in which the program was (re)deployed
|
||||
|
@ -355,22 +385,13 @@ impl LoadedProgram {
|
|||
metrics.jit_compile_us = jit_compile_time.end_as_us();
|
||||
}
|
||||
|
||||
let program = if bpf_loader_deprecated::check_id(loader_key) {
|
||||
LoadedProgramType::LegacyV0(executable)
|
||||
} else if bpf_loader::check_id(loader_key) || bpf_loader_upgradeable::check_id(loader_key) {
|
||||
LoadedProgramType::LegacyV1(executable)
|
||||
} else if loader_v4::check_id(loader_key) {
|
||||
LoadedProgramType::Typed(executable)
|
||||
} else {
|
||||
panic!();
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
deployment_slot,
|
||||
account_owner: LoadedProgramOwner::try_from(loader_key).unwrap(),
|
||||
account_size,
|
||||
effective_slot,
|
||||
tx_usage_counter: AtomicU64::new(0),
|
||||
program,
|
||||
program: LoadedProgramType::Loaded(executable),
|
||||
ix_usage_counter: AtomicU64::new(0),
|
||||
latest_access_slot: AtomicU64::new(0),
|
||||
})
|
||||
|
@ -378,11 +399,7 @@ impl LoadedProgram {
|
|||
|
||||
pub fn to_unloaded(&self) -> Option<Self> {
|
||||
match &self.program {
|
||||
LoadedProgramType::LegacyV0(_)
|
||||
| LoadedProgramType::LegacyV1(_)
|
||||
| LoadedProgramType::Typed(_) => {}
|
||||
#[cfg(test)]
|
||||
LoadedProgramType::TestLoaded(_) => {}
|
||||
LoadedProgramType::Loaded(_) => {}
|
||||
LoadedProgramType::FailedVerification(_)
|
||||
| LoadedProgramType::Closed
|
||||
| LoadedProgramType::DelayVisibility
|
||||
|
@ -393,6 +410,7 @@ impl LoadedProgram {
|
|||
}
|
||||
Some(Self {
|
||||
program: LoadedProgramType::Unloaded(self.program.get_environment()?.clone()),
|
||||
account_owner: self.account_owner,
|
||||
account_size: self.account_size,
|
||||
deployment_slot: self.deployment_slot,
|
||||
effective_slot: self.effective_slot,
|
||||
|
@ -414,6 +432,7 @@ impl LoadedProgram {
|
|||
.unwrap();
|
||||
Self {
|
||||
deployment_slot,
|
||||
account_owner: LoadedProgramOwner::NativeLoader,
|
||||
account_size,
|
||||
effective_slot: deployment_slot,
|
||||
tx_usage_counter: AtomicU64::new(0),
|
||||
|
@ -423,9 +442,14 @@ impl LoadedProgram {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new_tombstone(slot: Slot, reason: LoadedProgramType) -> Self {
|
||||
pub fn new_tombstone(
|
||||
slot: Slot,
|
||||
account_owner: LoadedProgramOwner,
|
||||
reason: LoadedProgramType,
|
||||
) -> Self {
|
||||
let tombstone = Self {
|
||||
program: reason,
|
||||
account_owner,
|
||||
account_size: 0,
|
||||
deployment_slot: slot,
|
||||
effective_slot: slot,
|
||||
|
@ -464,6 +488,10 @@ impl LoadedProgram {
|
|||
let decaying_for = std::cmp::min(63, now.saturating_sub(last_access));
|
||||
self.tx_usage_counter.load(Ordering::Relaxed) >> decaying_for
|
||||
}
|
||||
|
||||
pub fn account_owner(&self) -> Pubkey {
|
||||
self.account_owner.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Globally shared RBPF config and syscall registry
|
||||
|
@ -691,6 +719,7 @@ impl LoadedProgramsForTxBatch {
|
|||
// the tombstone to reflect that.
|
||||
Arc::new(LoadedProgram::new_tombstone(
|
||||
entry.deployment_slot,
|
||||
entry.account_owner,
|
||||
LoadedProgramType::DelayVisibility,
|
||||
))
|
||||
} else {
|
||||
|
@ -777,11 +806,7 @@ impl<FG: ForkGraph> ProgramCache<FG> {
|
|||
let existing = slot_versions.get_mut(index).unwrap();
|
||||
match (&existing.program, &entry.program) {
|
||||
(LoadedProgramType::Builtin(_), LoadedProgramType::Builtin(_))
|
||||
| (LoadedProgramType::Unloaded(_), LoadedProgramType::LegacyV0(_))
|
||||
| (LoadedProgramType::Unloaded(_), LoadedProgramType::LegacyV1(_))
|
||||
| (LoadedProgramType::Unloaded(_), LoadedProgramType::Typed(_)) => {}
|
||||
#[cfg(test)]
|
||||
(LoadedProgramType::Unloaded(_), LoadedProgramType::TestLoaded(_)) => {}
|
||||
| (LoadedProgramType::Unloaded(_), LoadedProgramType::Loaded(_)) => {}
|
||||
_ => {
|
||||
// Something is wrong, I can feel it ...
|
||||
error!("ProgramCache::assign_program() failed key={:?} existing={:?} entry={:?}", key, slot_versions, entry);
|
||||
|
@ -967,6 +992,7 @@ impl<FG: ForkGraph> ProgramCache<FG> {
|
|||
// the tombstone to reflect that.
|
||||
Arc::new(LoadedProgram::new_tombstone(
|
||||
entry.deployment_slot,
|
||||
entry.account_owner,
|
||||
LoadedProgramType::DelayVisibility,
|
||||
))
|
||||
} else {
|
||||
|
@ -1061,16 +1087,17 @@ impl<FG: ForkGraph> ProgramCache<FG> {
|
|||
.slot_versions
|
||||
.iter()
|
||||
.filter_map(move |program| match program.program {
|
||||
LoadedProgramType::LegacyV0(_) | LoadedProgramType::LegacyV1(_)
|
||||
if include_program_runtime_v1 =>
|
||||
{
|
||||
Some((*id, program.clone()))
|
||||
LoadedProgramType::Loaded(_) => {
|
||||
if (program.account_owner != LoadedProgramOwner::LoaderV4
|
||||
&& include_program_runtime_v1)
|
||||
|| (program.account_owner == LoadedProgramOwner::LoaderV4
|
||||
&& include_program_runtime_v2)
|
||||
{
|
||||
Some((*id, program.clone()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
LoadedProgramType::Typed(_) if include_program_runtime_v2 => {
|
||||
Some((*id, program.clone()))
|
||||
}
|
||||
#[cfg(test)]
|
||||
LoadedProgramType::TestLoaded(_) => Some((*id, program.clone())),
|
||||
_ => None,
|
||||
})
|
||||
})
|
||||
|
@ -1207,15 +1234,17 @@ impl<FG: ForkGraph> solana_frozen_abi::abi_example::AbiExample for ProgramCache<
|
|||
mod tests {
|
||||
use {
|
||||
crate::loaded_programs::{
|
||||
BlockRelation, ForkGraph, LoadedProgram, LoadedProgramMatchCriteria, LoadedProgramType,
|
||||
LoadedProgramsForTxBatch, ProgramCache, ProgramRuntimeEnvironment,
|
||||
ProgramRuntimeEnvironments, DELAY_VISIBILITY_SLOT_OFFSET,
|
||||
BlockRelation, ForkGraph, LoadedProgram, LoadedProgramMatchCriteria,
|
||||
LoadedProgramOwner, LoadedProgramType, LoadedProgramsForTxBatch, ProgramCache,
|
||||
ProgramRuntimeEnvironment, ProgramRuntimeEnvironments, DELAY_VISIBILITY_SLOT_OFFSET,
|
||||
},
|
||||
assert_matches::assert_matches,
|
||||
percentage::Percentage,
|
||||
solana_rbpf::program::BuiltinProgram,
|
||||
solana_rbpf::{elf::Executable, program::BuiltinProgram},
|
||||
solana_sdk::{clock::Slot, pubkey::Pubkey},
|
||||
std::{
|
||||
fs::File,
|
||||
io::Read,
|
||||
ops::ControlFlow,
|
||||
sync::{
|
||||
atomic::{AtomicU64, Ordering},
|
||||
|
@ -1228,12 +1257,15 @@ mod tests {
|
|||
static MOCK_ENVIRONMENT: std::sync::OnceLock<ProgramRuntimeEnvironment> =
|
||||
std::sync::OnceLock::<ProgramRuntimeEnvironment>::new();
|
||||
|
||||
fn get_mock_env() -> ProgramRuntimeEnvironment {
|
||||
MOCK_ENVIRONMENT
|
||||
.get_or_init(|| Arc::new(BuiltinProgram::new_mock()))
|
||||
.clone()
|
||||
}
|
||||
|
||||
fn new_mock_cache<FG: ForkGraph>() -> ProgramCache<FG> {
|
||||
let mut cache = ProgramCache::new(0, 0);
|
||||
|
||||
cache.environments.program_runtime_v1 = MOCK_ENVIRONMENT
|
||||
.get_or_init(|| Arc::new(BuiltinProgram::new_mock()))
|
||||
.clone();
|
||||
cache.environments.program_runtime_v1 = get_mock_env();
|
||||
cache
|
||||
}
|
||||
|
||||
|
@ -1241,13 +1273,24 @@ mod tests {
|
|||
new_test_loaded_program_with_usage(deployment_slot, effective_slot, AtomicU64::default())
|
||||
}
|
||||
|
||||
fn new_loaded_program(env: ProgramRuntimeEnvironment) -> LoadedProgramType {
|
||||
let mut elf = Vec::new();
|
||||
File::open("../programs/bpf_loader/test_elfs/out/noop_aligned.so")
|
||||
.unwrap()
|
||||
.read_to_end(&mut elf)
|
||||
.unwrap();
|
||||
let executable = Executable::load(&elf, env).unwrap();
|
||||
LoadedProgramType::Loaded(executable)
|
||||
}
|
||||
|
||||
fn new_test_loaded_program_with_usage(
|
||||
deployment_slot: Slot,
|
||||
effective_slot: Slot,
|
||||
usage_counter: AtomicU64,
|
||||
) -> Arc<LoadedProgram> {
|
||||
Arc::new(LoadedProgram {
|
||||
program: LoadedProgramType::TestLoaded(MOCK_ENVIRONMENT.get().unwrap().clone()),
|
||||
program: new_loaded_program(get_mock_env()),
|
||||
account_owner: LoadedProgramOwner::LoaderV2,
|
||||
account_size: 0,
|
||||
deployment_slot,
|
||||
effective_slot,
|
||||
|
@ -1260,6 +1303,7 @@ mod tests {
|
|||
fn new_test_builtin_program(deployment_slot: Slot, effective_slot: Slot) -> Arc<LoadedProgram> {
|
||||
Arc::new(LoadedProgram {
|
||||
program: LoadedProgramType::Builtin(BuiltinProgram::new_mock()),
|
||||
account_owner: LoadedProgramOwner::NativeLoader,
|
||||
account_size: 0,
|
||||
deployment_slot,
|
||||
effective_slot,
|
||||
|
@ -1275,7 +1319,11 @@ mod tests {
|
|||
slot: Slot,
|
||||
reason: LoadedProgramType,
|
||||
) -> Arc<LoadedProgram> {
|
||||
let program = Arc::new(LoadedProgram::new_tombstone(slot, reason));
|
||||
let program = Arc::new(LoadedProgram::new_tombstone(
|
||||
slot,
|
||||
LoadedProgramOwner::LoaderV2,
|
||||
reason,
|
||||
));
|
||||
cache.assign_program(key, program.clone());
|
||||
program
|
||||
}
|
||||
|
@ -1285,21 +1333,9 @@ mod tests {
|
|||
key: Pubkey,
|
||||
slot: Slot,
|
||||
) -> Arc<LoadedProgram> {
|
||||
let unloaded = Arc::new(
|
||||
LoadedProgram {
|
||||
program: LoadedProgramType::TestLoaded(
|
||||
cache.environments.program_runtime_v1.clone(),
|
||||
),
|
||||
account_size: 0,
|
||||
deployment_slot: slot,
|
||||
effective_slot: slot.saturating_add(1),
|
||||
tx_usage_counter: AtomicU64::default(),
|
||||
ix_usage_counter: AtomicU64::default(),
|
||||
latest_access_slot: AtomicU64::default(),
|
||||
}
|
||||
.to_unloaded()
|
||||
.expect("Failed to unload the program"),
|
||||
);
|
||||
let loaded =
|
||||
new_test_loaded_program_with_usage(slot, slot.saturating_add(1), AtomicU64::default());
|
||||
let unloaded = Arc::new(loaded.to_unloaded().expect("Failed to unload the program"));
|
||||
cache.assign_program(key, unloaded.clone());
|
||||
unloaded
|
||||
}
|
||||
|
@ -1439,7 +1475,7 @@ mod tests {
|
|||
// Count the number of loaded, unloaded and tombstone entries.
|
||||
programs.sort_by_key(|(_id, _slot, usage_count)| *usage_count);
|
||||
let num_loaded = num_matching_entries(&cache, |program_type| {
|
||||
matches!(program_type, LoadedProgramType::TestLoaded(_))
|
||||
matches!(program_type, LoadedProgramType::Loaded(_))
|
||||
});
|
||||
let num_unloaded = num_matching_entries(&cache, |program_type| {
|
||||
matches!(program_type, LoadedProgramType::Unloaded(_))
|
||||
|
@ -1468,7 +1504,7 @@ mod tests {
|
|||
|
||||
// Count the number of loaded, unloaded and tombstone entries.
|
||||
let num_loaded = num_matching_entries(&cache, |program_type| {
|
||||
matches!(program_type, LoadedProgramType::TestLoaded(_))
|
||||
matches!(program_type, LoadedProgramType::Loaded(_))
|
||||
});
|
||||
let num_unloaded = num_matching_entries(&cache, |program_type| {
|
||||
matches!(program_type, LoadedProgramType::Unloaded(_))
|
||||
|
@ -1527,7 +1563,7 @@ mod tests {
|
|||
// Count the number of loaded, unloaded and tombstone entries.
|
||||
programs.sort_by_key(|(_id, _slot, usage_count)| *usage_count);
|
||||
let num_loaded = num_matching_entries(&cache, |program_type| {
|
||||
matches!(program_type, LoadedProgramType::TestLoaded(_))
|
||||
matches!(program_type, LoadedProgramType::Loaded(_))
|
||||
});
|
||||
let num_unloaded = num_matching_entries(&cache, |program_type| {
|
||||
matches!(program_type, LoadedProgramType::Unloaded(_))
|
||||
|
@ -1573,7 +1609,7 @@ mod tests {
|
|||
|
||||
// Count the number of loaded, unloaded and tombstone entries.
|
||||
let num_loaded = num_matching_entries(&cache, |program_type| {
|
||||
matches!(program_type, LoadedProgramType::TestLoaded(_))
|
||||
matches!(program_type, LoadedProgramType::Loaded(_))
|
||||
});
|
||||
let num_unloaded = num_matching_entries(&cache, |program_type| {
|
||||
matches!(program_type, LoadedProgramType::Unloaded(_))
|
||||
|
@ -1681,13 +1717,13 @@ mod tests {
|
|||
(
|
||||
LoadedProgramType::Closed,
|
||||
LoadedProgramType::FailedVerification(Arc::new(BuiltinProgram::new_mock())),
|
||||
LoadedProgramType::TestLoaded(Arc::new(BuiltinProgram::new_mock())),
|
||||
new_loaded_program(get_mock_env()),
|
||||
),
|
||||
(
|
||||
LoadedProgramType::FailedVerification(Arc::new(BuiltinProgram::new_mock())),
|
||||
LoadedProgramType::Closed,
|
||||
LoadedProgramType::Unloaded(Arc::new(BuiltinProgram::new_mock())),
|
||||
LoadedProgramType::TestLoaded(Arc::new(BuiltinProgram::new_mock())),
|
||||
new_loaded_program(get_mock_env()),
|
||||
LoadedProgramType::Builtin(BuiltinProgram::new_mock()),
|
||||
)
|
||||
)]
|
||||
|
@ -1708,7 +1744,7 @@ mod tests {
|
|||
LoadedProgramType::FailedVerification(Arc::new(BuiltinProgram::new_mock())),
|
||||
LoadedProgramType::Closed,
|
||||
LoadedProgramType::Unloaded(Arc::new(BuiltinProgram::new_mock())),
|
||||
LoadedProgramType::TestLoaded(Arc::new(BuiltinProgram::new_mock())),
|
||||
new_loaded_program(get_mock_env()),
|
||||
)
|
||||
)]
|
||||
#[should_panic(expected = "Unexpected replacement of an entry")]
|
||||
|
@ -1719,6 +1755,7 @@ mod tests {
|
|||
program_id,
|
||||
Arc::new(LoadedProgram {
|
||||
program: old,
|
||||
account_owner: LoadedProgramOwner::LoaderV2,
|
||||
account_size: 0,
|
||||
deployment_slot: 10,
|
||||
effective_slot: 11,
|
||||
|
@ -1731,6 +1768,7 @@ mod tests {
|
|||
program_id,
|
||||
Arc::new(LoadedProgram {
|
||||
program: new,
|
||||
account_owner: LoadedProgramOwner::LoaderV2,
|
||||
account_size: 0,
|
||||
deployment_slot: 10,
|
||||
effective_slot: 11,
|
||||
|
@ -1743,7 +1781,7 @@ mod tests {
|
|||
|
||||
#[test_case(
|
||||
LoadedProgramType::Unloaded(Arc::new(BuiltinProgram::new_mock())),
|
||||
LoadedProgramType::TestLoaded(Arc::new(BuiltinProgram::new_mock()))
|
||||
new_loaded_program(get_mock_env())
|
||||
)]
|
||||
#[test_case(
|
||||
LoadedProgramType::Builtin(BuiltinProgram::new_mock()),
|
||||
|
@ -1756,6 +1794,7 @@ mod tests {
|
|||
program_id,
|
||||
Arc::new(LoadedProgram {
|
||||
program: old,
|
||||
account_owner: LoadedProgramOwner::LoaderV2,
|
||||
account_size: 0,
|
||||
deployment_slot: 10,
|
||||
effective_slot: 11,
|
||||
|
@ -1768,6 +1807,7 @@ mod tests {
|
|||
program_id,
|
||||
Arc::new(LoadedProgram {
|
||||
program: new,
|
||||
account_owner: LoadedProgramOwner::LoaderV2,
|
||||
account_size: 0,
|
||||
deployment_slot: 10,
|
||||
effective_slot: 11,
|
||||
|
@ -1781,14 +1821,21 @@ mod tests {
|
|||
#[test]
|
||||
fn test_tombstone() {
|
||||
let env = Arc::new(BuiltinProgram::new_mock());
|
||||
let tombstone =
|
||||
LoadedProgram::new_tombstone(0, LoadedProgramType::FailedVerification(env.clone()));
|
||||
let tombstone = LoadedProgram::new_tombstone(
|
||||
0,
|
||||
LoadedProgramOwner::LoaderV2,
|
||||
LoadedProgramType::FailedVerification(env.clone()),
|
||||
);
|
||||
assert_matches!(tombstone.program, LoadedProgramType::FailedVerification(_));
|
||||
assert!(tombstone.is_tombstone());
|
||||
assert_eq!(tombstone.deployment_slot, 0);
|
||||
assert_eq!(tombstone.effective_slot, 0);
|
||||
|
||||
let tombstone = LoadedProgram::new_tombstone(100, LoadedProgramType::Closed);
|
||||
let tombstone = LoadedProgram::new_tombstone(
|
||||
100,
|
||||
LoadedProgramOwner::LoaderV2,
|
||||
LoadedProgramType::Closed,
|
||||
);
|
||||
assert_matches!(tombstone.program, LoadedProgramType::Closed);
|
||||
assert!(tombstone.is_tombstone());
|
||||
assert_eq!(tombstone.deployment_slot, 100);
|
||||
|
@ -1921,7 +1968,8 @@ mod tests {
|
|||
program_runtime_v2: new_env.clone(),
|
||||
});
|
||||
let updated_program = Arc::new(LoadedProgram {
|
||||
program: LoadedProgramType::TestLoaded(new_env.clone()),
|
||||
program: new_loaded_program(new_env.clone()),
|
||||
account_owner: LoadedProgramOwner::LoaderV2,
|
||||
account_size: 0,
|
||||
deployment_slot: 20,
|
||||
effective_slot: 20,
|
||||
|
@ -2460,6 +2508,7 @@ mod tests {
|
|||
] {
|
||||
let entry = Arc::new(LoadedProgram {
|
||||
program: loaded_program_type,
|
||||
account_owner: LoadedProgramOwner::LoaderV2,
|
||||
account_size: 0,
|
||||
deployment_slot: 0,
|
||||
effective_slot: 0,
|
||||
|
@ -2623,7 +2672,11 @@ mod tests {
|
|||
#[test]
|
||||
fn test_usable_entries_for_slot() {
|
||||
new_mock_cache::<TestForkGraph>();
|
||||
let tombstone = Arc::new(LoadedProgram::new_tombstone(0, LoadedProgramType::Closed));
|
||||
let tombstone = Arc::new(LoadedProgram::new_tombstone(
|
||||
0,
|
||||
LoadedProgramOwner::LoaderV2,
|
||||
LoadedProgramType::Closed,
|
||||
));
|
||||
|
||||
assert!(
|
||||
ProgramCache::<TestForkGraph>::matches_loaded_program_criteria(
|
||||
|
|
|
@ -10,7 +10,8 @@ use {
|
|||
ic_logger_msg, ic_msg,
|
||||
invoke_context::{BpfAllocator, InvokeContext, SerializedAccountMetadata, SyscallContext},
|
||||
loaded_programs::{
|
||||
LoadProgramMetrics, LoadedProgram, LoadedProgramType, DELAY_VISIBILITY_SLOT_OFFSET,
|
||||
LoadProgramMetrics, LoadedProgram, LoadedProgramOwner, LoadedProgramType,
|
||||
DELAY_VISIBILITY_SLOT_OFFSET,
|
||||
},
|
||||
log_collector::LogCollector,
|
||||
stable_log,
|
||||
|
@ -456,8 +457,7 @@ pub fn process_instruction_inner(
|
|||
ic_logger_msg!(log_collector, "Program is not deployed");
|
||||
Err(Box::new(InstructionError::InvalidAccountData) as Box<dyn std::error::Error>)
|
||||
}
|
||||
LoadedProgramType::LegacyV0(executable) => execute(executable, invoke_context),
|
||||
LoadedProgramType::LegacyV1(executable) => execute(executable, invoke_context),
|
||||
LoadedProgramType::Loaded(executable) => execute(executable, invoke_context),
|
||||
_ => Err(Box::new(InstructionError::IncorrectProgramId) as Box<dyn std::error::Error>),
|
||||
}
|
||||
.map(|_| 0)
|
||||
|
@ -1113,6 +1113,7 @@ fn process_loader_upgradeable_instruction(
|
|||
program_key,
|
||||
Arc::new(LoadedProgram::new_tombstone(
|
||||
clock.slot,
|
||||
LoadedProgramOwner::LoaderV3,
|
||||
LoadedProgramType::Closed,
|
||||
)),
|
||||
);
|
||||
|
@ -3761,6 +3762,7 @@ mod tests {
|
|||
let env = Arc::new(BuiltinProgram::new_mock());
|
||||
let program = LoadedProgram {
|
||||
program: LoadedProgramType::Unloaded(env),
|
||||
account_owner: LoadedProgramOwner::LoaderV2,
|
||||
account_size: 0,
|
||||
deployment_slot: 0,
|
||||
effective_slot: 0,
|
||||
|
@ -3804,6 +3806,7 @@ mod tests {
|
|||
let env = Arc::new(BuiltinProgram::new_mock());
|
||||
let program = LoadedProgram {
|
||||
program: LoadedProgramType::Unloaded(env),
|
||||
account_owner: LoadedProgramOwner::LoaderV2,
|
||||
account_size: 0,
|
||||
deployment_slot: 0,
|
||||
effective_slot: 0,
|
||||
|
|
|
@ -608,7 +608,7 @@ pub fn process_instruction_inner(
|
|||
ic_logger_msg!(log_collector, "Program is not deployed");
|
||||
Err(Box::new(InstructionError::InvalidAccountData) as Box<dyn std::error::Error>)
|
||||
}
|
||||
LoadedProgramType::Typed(executable) => execute(invoke_context, executable),
|
||||
LoadedProgramType::Loaded(executable) => execute(invoke_context, executable),
|
||||
_ => Err(Box::new(InstructionError::IncorrectProgramId) as Box<dyn std::error::Error>),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,7 +99,8 @@ use {
|
|||
compute_budget_processor::process_compute_budget_instructions,
|
||||
invoke_context::BuiltinFunctionWithContext,
|
||||
loaded_programs::{
|
||||
LoadedProgram, LoadedProgramMatchCriteria, LoadedProgramType, ProgramCache,
|
||||
LoadedProgram, LoadedProgramMatchCriteria, LoadedProgramOwner, LoadedProgramType,
|
||||
ProgramCache,
|
||||
},
|
||||
timings::{ExecuteTimingType, ExecuteTimings},
|
||||
},
|
||||
|
@ -6312,7 +6313,11 @@ impl Bank {
|
|||
self,
|
||||
program_id,
|
||||
name,
|
||||
LoadedProgram::new_tombstone(self.slot, LoadedProgramType::Closed),
|
||||
LoadedProgram::new_tombstone(
|
||||
self.slot,
|
||||
LoadedProgramOwner::NativeLoader,
|
||||
LoadedProgramType::Closed,
|
||||
),
|
||||
);
|
||||
debug!("Removed program {}", program_id);
|
||||
}
|
||||
|
|
|
@ -454,7 +454,7 @@ mod tests {
|
|||
assert_eq!(target_entry.latest_access_slot.load(Relaxed), bank.slot());
|
||||
|
||||
// The target program entry should now be a BPF program.
|
||||
assert_matches!(target_entry.program, LoadedProgramType::LegacyV1(..));
|
||||
assert_matches!(target_entry.program, LoadedProgramType::Loaded(..));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7106,7 +7106,7 @@ fn test_bank_load_program() {
|
|||
bank.store_account_and_update_capitalization(&key1, &program_account);
|
||||
bank.store_account_and_update_capitalization(&programdata_key, &programdata_account);
|
||||
let program = bank.load_program(&key1, false, bank.epoch()).unwrap();
|
||||
assert_matches!(program.program, LoadedProgramType::LegacyV1(_));
|
||||
assert_matches!(program.program, LoadedProgramType::Loaded(_));
|
||||
assert_eq!(
|
||||
program.account_size,
|
||||
program_account.data().len() + programdata_account.data().len()
|
||||
|
@ -7352,7 +7352,7 @@ fn test_bpf_loader_upgradeable_deploy_with_max_len() {
|
|||
assert_eq!(slot_versions[1].effective_slot, 1);
|
||||
assert!(matches!(
|
||||
slot_versions[1].program,
|
||||
LoadedProgramType::LegacyV1(_),
|
||||
LoadedProgramType::Loaded(_),
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@ use {
|
|||
invoke_context::InvokeContext,
|
||||
loaded_programs::{
|
||||
ForkGraph, LoadProgramMetrics, LoadedProgram, LoadedProgramMatchCriteria,
|
||||
LoadedProgramType, LoadedProgramsForTxBatch, ProgramCache, ProgramRuntimeEnvironment,
|
||||
DELAY_VISIBILITY_SLOT_OFFSET,
|
||||
LoadedProgramOwner, LoadedProgramType, LoadedProgramsForTxBatch, ProgramCache,
|
||||
ProgramRuntimeEnvironment, DELAY_VISIBILITY_SLOT_OFFSET,
|
||||
},
|
||||
log_collector::LogCollector,
|
||||
sysvar_cache::SysvarCache,
|
||||
|
@ -30,6 +30,7 @@ use {
|
|||
solana_sdk::{
|
||||
account::{AccountSharedData, ReadableAccount, PROGRAM_OWNERS},
|
||||
account_utils::StateMut,
|
||||
bpf_loader, bpf_loader_deprecated,
|
||||
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
|
||||
clock::{Epoch, Slot},
|
||||
epoch_schedule::EpochSchedule,
|
||||
|
@ -114,8 +115,9 @@ pub trait TransactionProcessingCallback {
|
|||
|
||||
#[derive(Debug)]
|
||||
enum ProgramAccountLoadResult {
|
||||
InvalidAccountData,
|
||||
ProgramOfLoaderV1orV2(AccountSharedData),
|
||||
InvalidAccountData(LoadedProgramOwner),
|
||||
ProgramOfLoaderV1(AccountSharedData),
|
||||
ProgramOfLoaderV2(AccountSharedData),
|
||||
ProgramOfLoaderV3(AccountSharedData, AccountSharedData, Slot),
|
||||
ProgramOfLoaderV4(AccountSharedData, Slot),
|
||||
}
|
||||
|
@ -411,12 +413,11 @@ impl<FG: ForkGraph> TransactionBatchProcessor<FG> {
|
|||
};
|
||||
|
||||
let mut loaded_program = match self.load_program_accounts(callbacks, pubkey)? {
|
||||
ProgramAccountLoadResult::InvalidAccountData => Ok(LoadedProgram::new_tombstone(
|
||||
self.slot,
|
||||
LoadedProgramType::Closed,
|
||||
)),
|
||||
ProgramAccountLoadResult::InvalidAccountData(owner) => Ok(
|
||||
LoadedProgram::new_tombstone(self.slot, owner, LoadedProgramType::Closed),
|
||||
),
|
||||
|
||||
ProgramAccountLoadResult::ProgramOfLoaderV1orV2(program_account) => {
|
||||
ProgramAccountLoadResult::ProgramOfLoaderV1(program_account) => {
|
||||
Self::load_program_from_bytes(
|
||||
&mut load_program_metrics,
|
||||
program_account.data(),
|
||||
|
@ -426,7 +427,20 @@ impl<FG: ForkGraph> TransactionBatchProcessor<FG> {
|
|||
environments.program_runtime_v1.clone(),
|
||||
reload,
|
||||
)
|
||||
.map_err(|_| (0, environments.program_runtime_v1.clone()))
|
||||
.map_err(|_| (0, LoadedProgramOwner::LoaderV1))
|
||||
}
|
||||
|
||||
ProgramAccountLoadResult::ProgramOfLoaderV2(program_account) => {
|
||||
Self::load_program_from_bytes(
|
||||
&mut load_program_metrics,
|
||||
program_account.data(),
|
||||
program_account.owner(),
|
||||
program_account.data().len(),
|
||||
0,
|
||||
environments.program_runtime_v1.clone(),
|
||||
reload,
|
||||
)
|
||||
.map_err(|_| (0, LoadedProgramOwner::LoaderV2))
|
||||
}
|
||||
|
||||
ProgramAccountLoadResult::ProgramOfLoaderV3(
|
||||
|
@ -451,7 +465,7 @@ impl<FG: ForkGraph> TransactionBatchProcessor<FG> {
|
|||
reload,
|
||||
)
|
||||
})
|
||||
.map_err(|_| (slot, environments.program_runtime_v1.clone())),
|
||||
.map_err(|_| (slot, LoadedProgramOwner::LoaderV3)),
|
||||
|
||||
ProgramAccountLoadResult::ProgramOfLoaderV4(program_account, slot) => program_account
|
||||
.data()
|
||||
|
@ -468,10 +482,15 @@ impl<FG: ForkGraph> TransactionBatchProcessor<FG> {
|
|||
reload,
|
||||
)
|
||||
})
|
||||
.map_err(|_| (slot, environments.program_runtime_v2.clone())),
|
||||
.map_err(|_| (slot, LoadedProgramOwner::LoaderV4)),
|
||||
}
|
||||
.unwrap_or_else(|(slot, env)| {
|
||||
LoadedProgram::new_tombstone(slot, LoadedProgramType::FailedVerification(env))
|
||||
.unwrap_or_else(|(slot, owner)| {
|
||||
let env = if let LoadedProgramOwner::LoaderV4 = &owner {
|
||||
environments.program_runtime_v2.clone()
|
||||
} else {
|
||||
environments.program_runtime_v1.clone()
|
||||
};
|
||||
LoadedProgram::new_tombstone(slot, owner, LoadedProgramType::FailedVerification(env))
|
||||
});
|
||||
|
||||
let mut timings = ExecuteDetailsTimings::default();
|
||||
|
@ -856,14 +875,18 @@ impl<FG: ForkGraph> TransactionBatchProcessor<FG> {
|
|||
(!matches!(state.status, LoaderV4Status::Retracted)).then_some(state.slot)
|
||||
})
|
||||
.map(|slot| ProgramAccountLoadResult::ProgramOfLoaderV4(program_account, slot))
|
||||
.unwrap_or(ProgramAccountLoadResult::InvalidAccountData),
|
||||
.unwrap_or(ProgramAccountLoadResult::InvalidAccountData(
|
||||
LoadedProgramOwner::LoaderV4,
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
if !bpf_loader_upgradeable::check_id(program_account.owner()) {
|
||||
return Some(ProgramAccountLoadResult::ProgramOfLoaderV1orV2(
|
||||
program_account,
|
||||
));
|
||||
if bpf_loader_deprecated::check_id(program_account.owner()) {
|
||||
return Some(ProgramAccountLoadResult::ProgramOfLoaderV1(program_account));
|
||||
}
|
||||
|
||||
if bpf_loader::check_id(program_account.owner()) {
|
||||
return Some(ProgramAccountLoadResult::ProgramOfLoaderV2(program_account));
|
||||
}
|
||||
|
||||
if let Ok(UpgradeableLoaderState::Program {
|
||||
|
@ -886,7 +909,9 @@ impl<FG: ForkGraph> TransactionBatchProcessor<FG> {
|
|||
}
|
||||
}
|
||||
}
|
||||
Some(ProgramAccountLoadResult::InvalidAccountData)
|
||||
Some(ProgramAccountLoadResult::InvalidAccountData(
|
||||
LoadedProgramOwner::LoaderV3,
|
||||
))
|
||||
}
|
||||
|
||||
/// Extract the InnerInstructionsList from a TransactionContext
|
||||
|
@ -1139,7 +1164,7 @@ mod tests {
|
|||
let result = batch_processor.load_program_accounts(&mock_bank, &key);
|
||||
assert!(matches!(
|
||||
result,
|
||||
Some(ProgramAccountLoadResult::InvalidAccountData)
|
||||
Some(ProgramAccountLoadResult::InvalidAccountData(_))
|
||||
));
|
||||
|
||||
account_data.set_data(Vec::new());
|
||||
|
@ -1152,7 +1177,7 @@ mod tests {
|
|||
|
||||
assert!(matches!(
|
||||
result,
|
||||
Some(ProgramAccountLoadResult::InvalidAccountData)
|
||||
Some(ProgramAccountLoadResult::InvalidAccountData(_))
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -1171,7 +1196,7 @@ mod tests {
|
|||
let result = batch_processor.load_program_accounts(&mock_bank, &key);
|
||||
assert!(matches!(
|
||||
result,
|
||||
Some(ProgramAccountLoadResult::InvalidAccountData)
|
||||
Some(ProgramAccountLoadResult::InvalidAccountData(_))
|
||||
));
|
||||
|
||||
account_data.set_data(vec![0; 64]);
|
||||
|
@ -1182,7 +1207,7 @@ mod tests {
|
|||
let result = batch_processor.load_program_accounts(&mock_bank, &key);
|
||||
assert!(matches!(
|
||||
result,
|
||||
Some(ProgramAccountLoadResult::InvalidAccountData)
|
||||
Some(ProgramAccountLoadResult::InvalidAccountData(_))
|
||||
));
|
||||
|
||||
let loader_data = LoaderV4State {
|
||||
|
@ -1227,7 +1252,8 @@ mod tests {
|
|||
|
||||
let result = batch_processor.load_program_accounts(&mock_bank, &key);
|
||||
match result {
|
||||
Some(ProgramAccountLoadResult::ProgramOfLoaderV1orV2(data)) => {
|
||||
Some(ProgramAccountLoadResult::ProgramOfLoaderV1(data))
|
||||
| Some(ProgramAccountLoadResult::ProgramOfLoaderV2(data)) => {
|
||||
assert_eq!(data, account_data);
|
||||
}
|
||||
_ => panic!("Invalid result"),
|
||||
|
@ -1351,6 +1377,7 @@ mod tests {
|
|||
|
||||
let loaded_program = LoadedProgram::new_tombstone(
|
||||
0,
|
||||
LoadedProgramOwner::LoaderV4,
|
||||
LoadedProgramType::FailedVerification(
|
||||
batch_processor
|
||||
.program_cache
|
||||
|
@ -1380,6 +1407,7 @@ mod tests {
|
|||
let result = batch_processor.load_program_with_pubkey(&mock_bank, &key, false, 20);
|
||||
let loaded_program = LoadedProgram::new_tombstone(
|
||||
0,
|
||||
LoadedProgramOwner::LoaderV2,
|
||||
LoadedProgramType::FailedVerification(
|
||||
batch_processor
|
||||
.program_cache
|
||||
|
@ -1450,6 +1478,7 @@ mod tests {
|
|||
let result = batch_processor.load_program_with_pubkey(&mock_bank, &key1, false, 0);
|
||||
let loaded_program = LoadedProgram::new_tombstone(
|
||||
0,
|
||||
LoadedProgramOwner::LoaderV3,
|
||||
LoadedProgramType::FailedVerification(
|
||||
batch_processor
|
||||
.program_cache
|
||||
|
@ -1526,6 +1555,7 @@ mod tests {
|
|||
let result = batch_processor.load_program_with_pubkey(&mock_bank, &key, false, 0);
|
||||
let loaded_program = LoadedProgram::new_tombstone(
|
||||
0,
|
||||
LoadedProgramOwner::LoaderV4,
|
||||
LoadedProgramType::FailedVerification(
|
||||
batch_processor
|
||||
.program_cache
|
||||
|
|
Loading…
Reference in New Issue