From fc35b1336591045a7c4736add7514ca2ba33cc6f Mon Sep 17 00:00:00 2001 From: Pankaj Garg Date: Fri, 21 Jul 2023 13:43:46 -0700 Subject: [PATCH] Cleanup load_program() in bank.rs (#32146) --- programs/bpf_loader/src/lib.rs | 69 +------------ runtime/src/bank.rs | 174 ++++++++++++++++++++------------- 2 files changed, 106 insertions(+), 137 deletions(-) diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 1c0cfea02d462a..625ae348425944 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -99,73 +99,6 @@ pub fn load_program_from_bytes( Ok(loaded_program) } -pub fn load_program_from_account( - feature_set: &FeatureSet, - log_collector: Option>>, - program: &BorrowedAccount, - programdata: &BorrowedAccount, - program_runtime_environment: Arc>>, -) -> Result<(Arc, LoadProgramMetrics), InstructionError> { - if !check_loader_id(program.get_owner()) { - ic_logger_msg!( - log_collector, - "Executable account not owned by the BPF loader" - ); - return Err(InstructionError::IncorrectProgramId); - } - - let (programdata_offset, deployment_slot) = - if bpf_loader_upgradeable::check_id(program.get_owner()) { - if let UpgradeableLoaderState::Program { - programdata_address: _, - } = program.get_state()? - { - if let UpgradeableLoaderState::ProgramData { - slot, - upgrade_authority_address: _, - } = programdata.get_state()? - { - (UpgradeableLoaderState::size_of_programdata_metadata(), slot) - } else { - ic_logger_msg!(log_collector, "Program has been closed"); - return Err(InstructionError::InvalidAccountData); - } - } else { - ic_logger_msg!(log_collector, "Invalid Program account"); - return Err(InstructionError::InvalidAccountData); - } - } else { - (0, 0) - }; - - let programdata_size = if programdata_offset != 0 { - programdata.get_data().len() - } else { - 0 - }; - - let mut load_program_metrics = LoadProgramMetrics { - program_id: program.get_key().to_string(), - ..LoadProgramMetrics::default() - }; - - let loaded_program = Arc::new(load_program_from_bytes( - feature_set, - log_collector, - &mut load_program_metrics, - programdata - .get_data() - .get(programdata_offset..) - .ok_or(InstructionError::AccountDataTooSmall)?, - program.get_owner(), - program.get_data().len().saturating_add(programdata_size), - deployment_slot, - program_runtime_environment, - )?); - - Ok((loaded_program, load_program_metrics)) -} - fn find_program_in_cache( invoke_context: &InvokeContext, pubkey: &Pubkey, @@ -246,7 +179,7 @@ fn write_program_data( Ok(()) } -fn check_loader_id(id: &Pubkey) -> bool { +pub fn check_loader_id(id: &Pubkey) -> bool { bpf_loader::check_id(id) || bpf_loader_deprecated::check_id(id) || bpf_loader_upgradeable::check_id(id) diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index e7d175adb96ad2..09dee0a2ee4c53 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -105,8 +105,8 @@ use { compute_budget::{self, ComputeBudget}, invoke_context::ProcessInstructionWithContext, loaded_programs::{ - LoadedProgram, LoadedProgramMatchCriteria, LoadedProgramType, LoadedPrograms, - LoadedProgramsForTxBatch, WorkingSlot, + LoadProgramMetrics, LoadedProgram, LoadedProgramMatchCriteria, LoadedProgramType, + LoadedPrograms, LoadedProgramsForTxBatch, WorkingSlot, }, log_collector::LogCollector, message_processor::MessageProcessor, @@ -144,6 +144,7 @@ use { hash::{extend_and_hash, hashv, Hash}, incinerator, inflation::Inflation, + instruction::InstructionError, lamports::LamportsError, loader_v4, message::{AccountKeys, SanitizedMessage}, @@ -295,6 +296,13 @@ impl BankRc { } } +enum ProgramAccountLoadResult { + AccountNotFound, + InvalidAccountData, + ProgramOfLoaderV1orV2(AccountSharedData), + ProgramOfLoaderV3(AccountSharedData, AccountSharedData, Slot), +} + pub struct LoadAndExecuteTransactionsOutput { pub loaded_transactions: Vec, // Vector of results indicating whether a transaction was executed or could not @@ -4594,86 +4602,114 @@ impl Bank { } } - pub fn load_program(&self, pubkey: &Pubkey) -> Arc { - let Some(program) = self.get_account_with_fixed_root(pubkey) else { - return Arc::new(LoadedProgram::new_tombstone( - self.slot, - LoadedProgramType::Closed, - )); + fn load_program_accounts(&self, pubkey: &Pubkey) -> ProgramAccountLoadResult { + let program_account = match self.get_account_with_fixed_root(pubkey) { + None => return ProgramAccountLoadResult::AccountNotFound, + Some(account) => account, }; - let mut transaction_accounts = vec![(*pubkey, program)]; - let is_upgradeable_loader = - bpf_loader_upgradeable::check_id(transaction_accounts[0].1.owner()); - if is_upgradeable_loader { - if let Ok(UpgradeableLoaderState::Program { - programdata_address, - }) = transaction_accounts[0].1.state() + + debug_assert!(solana_bpf_loader_program::check_loader_id( + program_account.owner() + )); + + if !bpf_loader_upgradeable::check_id(program_account.owner()) { + return ProgramAccountLoadResult::ProgramOfLoaderV1orV2(program_account); + } + + if let Ok(UpgradeableLoaderState::Program { + programdata_address, + }) = program_account.state() + { + let programdata_account = match self.get_account_with_fixed_root(&programdata_address) { + None => return ProgramAccountLoadResult::AccountNotFound, + Some(account) => account, + }; + + if let Ok(UpgradeableLoaderState::ProgramData { + slot, + upgrade_authority_address: _, + }) = programdata_account.state() { - if let Some(programdata_account) = - self.get_account_with_fixed_root(&programdata_address) - { - transaction_accounts.push((programdata_address, programdata_account)); - } else { - return Arc::new(LoadedProgram::new_tombstone( - self.slot, - LoadedProgramType::Closed, - )); - } - } else { - return Arc::new(LoadedProgram::new_tombstone( - self.slot, - LoadedProgramType::Closed, - )); + return ProgramAccountLoadResult::ProgramOfLoaderV3( + program_account, + programdata_account, + slot, + ); } } - let mut transaction_context = TransactionContext::new( - transaction_accounts, - Some(sysvar::rent::Rent::default()), - 1, - 1, - ); - let instruction_context = transaction_context.get_next_instruction_context().unwrap(); - instruction_context.configure(if is_upgradeable_loader { &[0, 1] } else { &[0] }, &[], &[]); - transaction_context.push().unwrap(); - let instruction_context = transaction_context - .get_current_instruction_context() - .unwrap(); - let program = instruction_context - .try_borrow_program_account(&transaction_context, 0) - .unwrap(); - let programdata = if is_upgradeable_loader { - Some( - instruction_context - .try_borrow_program_account(&transaction_context, 1) - .unwrap(), - ) - } else { - None - }; + ProgramAccountLoadResult::InvalidAccountData + } + + pub fn load_program(&self, pubkey: &Pubkey) -> Arc { let program_runtime_environment_v1 = self .loaded_programs_cache .read() .unwrap() .program_runtime_environment_v1 .clone(); - solana_bpf_loader_program::load_program_from_account( - &self.feature_set, - None, // log_collector - &program, - programdata.as_ref().unwrap_or(&program), - program_runtime_environment_v1.clone(), - ) - .map(|(loaded_program, metrics)| { - let mut timings = ExecuteDetailsTimings::default(); - metrics.submit_datapoint(&mut timings); - loaded_program - }) + + let mut load_program_metrics = LoadProgramMetrics { + program_id: pubkey.to_string(), + ..LoadProgramMetrics::default() + }; + + let loaded_program = match self.load_program_accounts(pubkey) { + ProgramAccountLoadResult::AccountNotFound => Ok(LoadedProgram::new_tombstone( + self.slot, + LoadedProgramType::Closed, + )), + + ProgramAccountLoadResult::InvalidAccountData => { + Err(InstructionError::InvalidAccountData) + } + + ProgramAccountLoadResult::ProgramOfLoaderV1orV2(program_account) => { + solana_bpf_loader_program::load_program_from_bytes( + &self.feature_set, + None, + &mut load_program_metrics, + program_account.data(), + program_account.owner(), + program_account.data().len(), + 0, + program_runtime_environment_v1.clone(), + ) + } + + ProgramAccountLoadResult::ProgramOfLoaderV3( + program_account, + programdata_account, + slot, + ) => programdata_account + .data() + .get(UpgradeableLoaderState::size_of_programdata_metadata()..) + .ok_or(InstructionError::InvalidAccountData) + .and_then(|programdata| { + solana_bpf_loader_program::load_program_from_bytes( + &self.feature_set, + None, + &mut load_program_metrics, + programdata, + program_account.owner(), + program_account + .data() + .len() + .saturating_add(programdata_account.data().len()), + slot, + program_runtime_environment_v1.clone(), + ) + }), + } .unwrap_or_else(|_| { - Arc::new(LoadedProgram::new_tombstone( + LoadedProgram::new_tombstone( self.slot, LoadedProgramType::FailedVerification(program_runtime_environment_v1), - )) - }) + ) + }); + + let mut timings = ExecuteDetailsTimings::default(); + load_program_metrics.submit_datapoint(&mut timings); + Arc::new(loaded_program) } pub fn clear_program_cache(&self) {