diff --git a/ledger-tool/src/program.rs b/ledger-tool/src/program.rs index f8c8a0fe66be84..7a5f5cc6492e6b 100644 --- a/ledger-tool/src/program.rs +++ b/ledger-tool/src/program.rs @@ -522,7 +522,11 @@ pub fn program(ledger_path: &Path, matches: &ArgMatches<'_>) { let mut loaded_programs = bank.new_program_cache_for_tx_batch_for_slot(bank.slot() + DELAY_VISIBILITY_SLOT_OFFSET); for key in cached_account_keys { - loaded_programs.replenish(key, bank.load_program(&key, false, bank.epoch()).unwrap()); + loaded_programs.replenish( + key, + bank.load_program(&key, false, bank.epoch()) + .expect("Couldn't find program account"), + ); debug!("Loaded program {}", key); } invoke_context.programs_loaded_for_tx_batch = &loaded_programs; diff --git a/program-runtime/src/loaded_programs.rs b/program-runtime/src/loaded_programs.rs index ef269e58bcda96..419ae7330b410e 100644 --- a/program-runtime/src/loaded_programs.rs +++ b/program-runtime/src/loaded_programs.rs @@ -65,7 +65,9 @@ pub trait ForkGraph { pub enum LoadedProgramType { /// Tombstone for programs which currently do not pass the verifier but could if the feature set changed. FailedVerification(ProgramRuntimeEnvironment), - /// Tombstone for accounts which are not programs but might still be owned by a loader. + /// Tombstone for programs that were either explicitly closed or never deployed. + /// + /// It's also used for accounts belonging to program loaders, that don't actually contain program code (e.g. buffer accounts for LoaderV3 programs). #[default] Closed, /// Tombstone for programs which have recently been modified but the new version is not visible yet. @@ -774,6 +776,7 @@ impl ProgramCache { Ok(index) => { let existing = slot_versions.get_mut(index).unwrap(); match (&existing.program, &entry.program) { + // Add test for Closed => Loaded transition in same slot (LoadedProgramType::Builtin(_), LoadedProgramType::Builtin(_)) | (LoadedProgramType::Closed, LoadedProgramType::LegacyV0(_)) | (LoadedProgramType::Closed, LoadedProgramType::LegacyV1(_)) diff --git a/svm/src/transaction_processor.rs b/svm/src/transaction_processor.rs index bd3746cb553d30..d827695e159f4b 100644 --- a/svm/src/transaction_processor.rs +++ b/svm/src/transaction_processor.rs @@ -384,8 +384,11 @@ impl TransactionBatchProcessor { result } - /// Load program with a specific pubkey from program cache, and - /// update the program's access slot as a side-effect. + /// Loads the program with the given pubkey. + /// + /// If the account doesn't exist it returns `None`. If the account does exist, it must be a program + /// account (belong to one of the program loaders). Returns `Some(InvalidAccountData)` if the program + /// account is `Closed`, contains invalid data or any of the programdata accounts are invalid. pub fn load_program_with_pubkey( &self, callbacks: &CB, @@ -838,10 +841,6 @@ impl TransactionBatchProcessor { ) -> Option { let program_account = callbacks.get_account_shared_data(pubkey)?; - debug_assert!(solana_bpf_loader_program::check_loader_id( - program_account.owner() - )); - if loader_v4::check_id(program_account.owner()) { return Some( solana_loader_v4_program::get_state(program_account.data())