diff --git a/program-runtime/src/invoke_context.rs b/program-runtime/src/invoke_context.rs index 0850c9202..1700dfeed 100644 --- a/program-runtime/src/invoke_context.rs +++ b/program-runtime/src/invoke_context.rs @@ -232,35 +232,30 @@ impl<'a> InvokeContext<'a> { } } - pub fn new_mock_with_sysvars_and_features( - transaction_context: &'a mut TransactionContext, - sysvar_cache: &'a SysvarCache, - feature_set: Arc, - ) -> Self { - Self::new( - transaction_context, - Rent::default(), - &[], - Cow::Borrowed(sysvar_cache), - Some(LogCollector::new_ref()), - ComputeBudget::default(), - Rc::new(RefCell::new(Executors::default())), - feature_set, - Hash::default(), - 0, - 0, - ) - } - pub fn new_mock( transaction_context: &'a mut TransactionContext, builtin_programs: &'a [BuiltinProgram], ) -> Self { + let mut sysvar_cache = SysvarCache::default(); + sysvar_cache.fill_missing_entries(|pubkey| { + (0..transaction_context.get_number_of_accounts()).find_map(|index| { + if transaction_context.get_key_of_account_at_index(index) == pubkey { + Some( + transaction_context + .get_account_at_index(index) + .borrow() + .clone(), + ) + } else { + None + } + }) + }); Self::new( transaction_context, Rent::default(), builtin_programs, - Cow::Owned(SysvarCache::default()), + Cow::Owned(sysvar_cache), Some(LogCollector::new_ref()), ComputeBudget::default(), Rc::new(RefCell::new(Executors::default())), @@ -1072,14 +1067,13 @@ pub fn with_mock_invoke_context R>( callback(&mut invoke_context) } -pub fn mock_process_instruction_with_sysvars( +pub fn mock_process_instruction( loader_id: &Pubkey, mut program_indices: Vec, instruction_data: &[u8], transaction_accounts: Vec, instruction_accounts: Vec, expected_result: Result<(), InstructionError>, - sysvar_cache: &SysvarCache, process_instruction: ProcessInstructionWithContext, ) -> Vec { program_indices.insert(0, transaction_accounts.len()); @@ -1095,7 +1089,6 @@ pub fn mock_process_instruction_with_sysvars( 1, ); let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); - invoke_context.sysvar_cache = Cow::Borrowed(sysvar_cache); let result = invoke_context .push( &preparation.instruction_accounts, @@ -1110,27 +1103,6 @@ pub fn mock_process_instruction_with_sysvars( transaction_accounts } -pub fn mock_process_instruction( - loader_id: &Pubkey, - program_indices: Vec, - instruction_data: &[u8], - transaction_accounts: Vec, - instruction_accounts: Vec, - expected_result: Result<(), InstructionError>, - process_instruction: ProcessInstructionWithContext, -) -> Vec { - mock_process_instruction_with_sysvars( - loader_id, - program_indices, - instruction_data, - transaction_accounts, - instruction_accounts, - expected_result, - &SysvarCache::default(), - process_instruction, - ) -} - /// Visit each unique instruction account index once fn visit_each_account_once( instruction_accounts: &[InstructionAccount], diff --git a/program-runtime/src/sysvar_cache.rs b/program-runtime/src/sysvar_cache.rs index 6bc744b63..d67498e75 100644 --- a/program-runtime/src/sysvar_cache.rs +++ b/program-runtime/src/sysvar_cache.rs @@ -1,10 +1,15 @@ +use crate::invoke_context::InvokeContext; #[allow(deprecated)] -use solana_sdk::sysvar::fees::Fees; +use solana_sdk::sysvar::{fees::Fees, recent_blockhashes::RecentBlockhashes}; use { solana_sdk::{ + account::{AccountSharedData, ReadableAccount}, instruction::InstructionError, + keyed_account::{check_sysvar_keyed_account, KeyedAccount}, + pubkey::Pubkey, sysvar::{ clock::Clock, epoch_schedule::EpochSchedule, rent::Rent, slot_hashes::SlotHashes, + stake_history::StakeHistory, SysvarId, }, }, std::sync::Arc, @@ -26,6 +31,9 @@ pub struct SysvarCache { fees: Option>, rent: Option>, slot_hashes: Option>, + #[allow(deprecated)] + recent_blockhashes: Option>, + stake_history: Option>, } impl SysvarCache { @@ -78,4 +86,139 @@ impl SysvarCache { pub fn set_slot_hashes(&mut self, slot_hashes: SlotHashes) { self.slot_hashes = Some(Arc::new(slot_hashes)); } + + #[deprecated] + #[allow(deprecated)] + pub fn get_recent_blockhashes(&self) -> Result, InstructionError> { + self.recent_blockhashes + .clone() + .ok_or(InstructionError::UnsupportedSysvar) + } + + #[deprecated] + #[allow(deprecated)] + pub fn set_recent_blockhashes(&mut self, recent_blockhashes: RecentBlockhashes) { + self.recent_blockhashes = Some(Arc::new(recent_blockhashes)); + } + + pub fn get_stake_history(&self) -> Result, InstructionError> { + self.stake_history + .clone() + .ok_or(InstructionError::UnsupportedSysvar) + } + + pub fn set_stake_history(&mut self, stake_history: StakeHistory) { + self.stake_history = Some(Arc::new(stake_history)); + } + + pub fn fill_missing_entries Option>( + &mut self, + mut load_sysvar_account: F, + ) { + if self.get_clock().is_err() { + if let Some(clock) = load_sysvar_account(&Clock::id()) + .and_then(|account| bincode::deserialize(account.data()).ok()) + { + self.set_clock(clock); + } + } + if self.get_epoch_schedule().is_err() { + if let Some(epoch_schedule) = load_sysvar_account(&EpochSchedule::id()) + .and_then(|account| bincode::deserialize(account.data()).ok()) + { + self.set_epoch_schedule(epoch_schedule); + } + } + #[allow(deprecated)] + if self.get_fees().is_err() { + if let Some(fees) = load_sysvar_account(&Fees::id()) + .and_then(|account| bincode::deserialize(account.data()).ok()) + { + self.set_fees(fees); + } + } + if self.get_rent().is_err() { + if let Some(rent) = load_sysvar_account(&Rent::id()) + .and_then(|account| bincode::deserialize(account.data()).ok()) + { + self.set_rent(rent); + } + } + if self.get_slot_hashes().is_err() { + if let Some(slot_hashes) = load_sysvar_account(&SlotHashes::id()) + .and_then(|account| bincode::deserialize(account.data()).ok()) + { + self.set_slot_hashes(slot_hashes); + } + } + #[allow(deprecated)] + if self.get_recent_blockhashes().is_err() { + if let Some(recent_blockhashes) = load_sysvar_account(&RecentBlockhashes::id()) + .and_then(|account| bincode::deserialize(account.data()).ok()) + { + self.set_recent_blockhashes(recent_blockhashes); + } + } + if self.get_stake_history().is_err() { + if let Some(stake_history) = load_sysvar_account(&StakeHistory::id()) + .and_then(|account| bincode::deserialize(account.data()).ok()) + { + self.set_stake_history(stake_history); + } + } + } + + pub fn reset(&mut self) { + *self = SysvarCache::default(); + } +} + +/// These methods facilitate a transition from fetching sysvars from keyed +/// accounts to fetching from the sysvar cache without breaking consensus. In +/// order to keep consistent behavior, they continue to enforce the same checks +/// as `solana_sdk::keyed_account::from_keyed_account` despite dynamically +/// loading them instead of deserializing from account data. +pub mod get_sysvar_with_account_check { + use super::*; + + pub fn clock( + keyed_account: &KeyedAccount, + invoke_context: &InvokeContext, + ) -> Result, InstructionError> { + check_sysvar_keyed_account::(keyed_account)?; + invoke_context.get_sysvar_cache().get_clock() + } + + pub fn rent( + keyed_account: &KeyedAccount, + invoke_context: &InvokeContext, + ) -> Result, InstructionError> { + check_sysvar_keyed_account::(keyed_account)?; + invoke_context.get_sysvar_cache().get_rent() + } + + pub fn slot_hashes( + keyed_account: &KeyedAccount, + invoke_context: &InvokeContext, + ) -> Result, InstructionError> { + check_sysvar_keyed_account::(keyed_account)?; + invoke_context.get_sysvar_cache().get_slot_hashes() + } + + #[allow(deprecated)] + pub fn recent_blockhashes( + keyed_account: &KeyedAccount, + invoke_context: &InvokeContext, + ) -> Result, InstructionError> { + check_sysvar_keyed_account::(keyed_account)?; + invoke_context.get_sysvar_cache().get_recent_blockhashes() + } + + pub fn stake_history( + keyed_account: &KeyedAccount, + invoke_context: &InvokeContext, + ) -> Result, InstructionError> { + check_sysvar_keyed_account::(keyed_account)?; + invoke_context.get_sysvar_cache().get_stake_history() + } } diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index d14ad4264..4497fb459 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -23,6 +23,7 @@ use { invoke_context::{ComputeMeter, Executor, InvokeContext}, log_collector::LogCollector, stable_log, + sysvar_cache::get_sysvar_with_account_check, }, solana_rbpf::{ aligned_memory::AlignedMemory, @@ -38,7 +39,6 @@ use { account_utils::State, bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable::{self, UpgradeableLoaderState}, - clock::Clock, entrypoint::{HEAP_LENGTH, SUCCESS}, feature_set::{ cap_accounts_data_len, do_support_realloc, reduce_required_deploy_balance, @@ -47,13 +47,12 @@ use { start_verify_shift32_imm, stop_verify_mul64_imm_nonzero, }, instruction::{AccountMeta, InstructionError}, - keyed_account::{from_keyed_account, keyed_account_at_index, KeyedAccount}, + keyed_account::{keyed_account_at_index, KeyedAccount}, loader_instruction::LoaderInstruction, loader_upgradeable_instruction::UpgradeableLoaderInstruction, program_error::ACCOUNTS_DATA_BUDGET_EXCEEDED, program_utils::limited_deserialize, pubkey::Pubkey, - rent::Rent, saturating_add_assign, system_instruction::{self, MAX_PERMITTED_DATA_LENGTH}, }, @@ -460,14 +459,14 @@ fn process_loader_upgradeable_instruction( keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?; let program = keyed_account_at_index(keyed_accounts, first_instruction_account + 2)?; let buffer = keyed_account_at_index(keyed_accounts, first_instruction_account + 3)?; - let rent = from_keyed_account::(keyed_account_at_index( - keyed_accounts, - first_instruction_account + 4, - )?)?; - let clock = from_keyed_account::(keyed_account_at_index( - keyed_accounts, - first_instruction_account + 5, - )?)?; + let rent = get_sysvar_with_account_check::rent( + keyed_account_at_index(keyed_accounts, first_instruction_account + 4)?, + invoke_context, + )?; + let clock = get_sysvar_with_account_check::clock( + keyed_account_at_index(keyed_accounts, first_instruction_account + 5)?, + invoke_context, + )?; let authority = keyed_account_at_index(keyed_accounts, first_instruction_account + 7)?; let upgrade_authority_address = Some(*authority.unsigned_key()); let upgrade_authority_signer = authority.signer_key().is_none(); @@ -614,14 +613,14 @@ fn process_loader_upgradeable_instruction( let programdata = keyed_account_at_index(keyed_accounts, first_instruction_account)?; let program = keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?; let buffer = keyed_account_at_index(keyed_accounts, first_instruction_account + 2)?; - let rent = from_keyed_account::(keyed_account_at_index( - keyed_accounts, - first_instruction_account + 4, - )?)?; - let clock = from_keyed_account::(keyed_account_at_index( - keyed_accounts, - first_instruction_account + 5, - )?)?; + let rent = get_sysvar_with_account_check::rent( + keyed_account_at_index(keyed_accounts, first_instruction_account + 4)?, + invoke_context, + )?; + let clock = get_sysvar_with_account_check::clock( + keyed_account_at_index(keyed_accounts, first_instruction_account + 5)?, + invoke_context, + )?; let authority = keyed_account_at_index(keyed_accounts, first_instruction_account + 6)?; // Verify Program account @@ -2588,7 +2587,7 @@ mod tests { let mut elf_new = Vec::new(); file.read_to_end(&mut elf_new).unwrap(); assert_ne!(elf_orig.len(), elf_new.len()); - let slot = 42; + const SLOT: u64 = 42; let buffer_address = Pubkey::new_unique(); let upgrade_authority_address = Pubkey::new_unique(); @@ -2596,7 +2595,6 @@ mod tests { buffer_address: &Pubkey, buffer_authority: &Pubkey, upgrade_authority_address: &Pubkey, - slot: u64, elf_orig: &[u8], elf_new: &[u8], ) -> (Vec<(Pubkey, AccountSharedData)>, Vec) { @@ -2631,7 +2629,7 @@ mod tests { ); programdata_account .set_state(&UpgradeableLoaderState::ProgramData { - slot, + slot: SLOT, upgrade_authority_address: Some(*upgrade_authority_address), }) .unwrap(); @@ -2649,7 +2647,7 @@ mod tests { let spill_account = AccountSharedData::new(0, 0, &Pubkey::new_unique()); let rent_account = create_account_for_test(&rent); let clock_account = create_account_for_test(&Clock { - slot, + slot: SLOT, ..Clock::default() }); let upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique()); @@ -2725,7 +2723,6 @@ mod tests { &buffer_address, &upgrade_authority_address, &upgrade_authority_address, - slot, &elf_orig, &elf_new, ); @@ -2740,7 +2737,7 @@ mod tests { assert_eq!( state, UpgradeableLoaderState::ProgramData { - slot, + slot: SLOT, upgrade_authority_address: Some(upgrade_authority_address) } ); @@ -2758,14 +2755,13 @@ mod tests { &buffer_address, &upgrade_authority_address, &upgrade_authority_address, - slot, &elf_orig, &elf_new, ); transaction_accounts[0] .1 .set_state(&UpgradeableLoaderState::ProgramData { - slot, + slot: SLOT, upgrade_authority_address: None, }) .unwrap(); @@ -2780,7 +2776,6 @@ mod tests { &buffer_address, &upgrade_authority_address, &upgrade_authority_address, - slot, &elf_orig, &elf_new, ); @@ -2798,7 +2793,6 @@ mod tests { &buffer_address, &upgrade_authority_address, &upgrade_authority_address, - slot, &elf_orig, &elf_new, ); @@ -2814,7 +2808,6 @@ mod tests { &buffer_address, &upgrade_authority_address, &upgrade_authority_address, - slot, &elf_orig, &elf_new, ); @@ -2830,7 +2823,6 @@ mod tests { &buffer_address, &upgrade_authority_address, &upgrade_authority_address, - slot, &elf_orig, &elf_new, ); @@ -2846,7 +2838,6 @@ mod tests { &buffer_address, &upgrade_authority_address, &upgrade_authority_address, - slot, &elf_orig, &elf_new, ); @@ -2862,7 +2853,6 @@ mod tests { &buffer_address, &upgrade_authority_address, &upgrade_authority_address, - slot, &elf_orig, &elf_new, ); @@ -2881,7 +2871,6 @@ mod tests { &buffer_address, &upgrade_authority_address, &upgrade_authority_address, - slot, &elf_orig, &elf_new, ); @@ -2899,7 +2888,6 @@ mod tests { &buffer_address, &upgrade_authority_address, &upgrade_authority_address, - slot, &elf_orig, &elf_new, ); @@ -2918,7 +2906,6 @@ mod tests { &buffer_address, &upgrade_authority_address, &upgrade_authority_address, - slot, &elf_orig, &elf_new, ); @@ -2944,7 +2931,6 @@ mod tests { &buffer_address, &upgrade_authority_address, &upgrade_authority_address, - slot, &elf_orig, &elf_new, ); @@ -2966,7 +2952,6 @@ mod tests { &buffer_address, &buffer_address, &upgrade_authority_address, - slot, &elf_orig, &elf_new, ); @@ -2981,7 +2966,6 @@ mod tests { &buffer_address, &buffer_address, &upgrade_authority_address, - slot, &elf_orig, &elf_new, ); @@ -3002,14 +2986,13 @@ mod tests { &buffer_address, &buffer_address, &upgrade_authority_address, - slot, &elf_orig, &elf_new, ); transaction_accounts[0] .1 .set_state(&UpgradeableLoaderState::ProgramData { - slot, + slot: SLOT, upgrade_authority_address: None, }) .unwrap(); diff --git a/programs/stake/src/stake_instruction.rs b/programs/stake/src/stake_instruction.rs index dcb209684..0c04c1175 100644 --- a/programs/stake/src/stake_instruction.rs +++ b/programs/stake/src/stake_instruction.rs @@ -323,10 +323,7 @@ mod tests { super::*, crate::stake_state::{Meta, StakeState}, bincode::serialize, - solana_program_runtime::{ - invoke_context::{mock_process_instruction, mock_process_instruction_with_sysvars}, - sysvar_cache::SysvarCache, - }, + solana_program_runtime::invoke_context::mock_process_instruction, solana_sdk::{ account::{self, AccountSharedData}, instruction::{AccountMeta, Instruction}, @@ -339,7 +336,7 @@ mod tests { }, sysvar::{self, stake_history::StakeHistory}, }, - std::str::FromStr, + std::{collections::HashSet, str::FromStr}, }; fn create_default_account() -> AccountSharedData { @@ -387,31 +384,36 @@ mod tests { instruction: &Instruction, expected_result: Result<(), InstructionError>, ) -> Vec { - let transaction_accounts = instruction + let mut pubkeys: HashSet = instruction .accounts .iter() - .map(|meta| { + .map(|meta| meta.pubkey) + .collect(); + pubkeys.insert(sysvar::clock::id()); + let transaction_accounts = pubkeys + .iter() + .map(|pubkey| { ( - meta.pubkey, - if sysvar::clock::check_id(&meta.pubkey) { + *pubkey, + if sysvar::clock::check_id(pubkey) { account::create_account_shared_data_for_test( &sysvar::clock::Clock::default(), ) - } else if sysvar::rewards::check_id(&meta.pubkey) { + } else if sysvar::rewards::check_id(pubkey) { account::create_account_shared_data_for_test( &sysvar::rewards::Rewards::new(0.0), ) - } else if sysvar::stake_history::check_id(&meta.pubkey) { + } else if sysvar::stake_history::check_id(pubkey) { account::create_account_shared_data_for_test(&StakeHistory::default()) - } else if stake_config::check_id(&meta.pubkey) { + } else if stake_config::check_id(pubkey) { config::create_account(0, &stake_config::Config::default()) - } else if sysvar::rent::check_id(&meta.pubkey) { + } else if sysvar::rent::check_id(pubkey) { account::create_account_shared_data_for_test(&Rent::default()) - } else if meta.pubkey == invalid_stake_state_pubkey() { + } else if *pubkey == invalid_stake_state_pubkey() { AccountSharedData::new(0, 0, &id()) - } else if meta.pubkey == invalid_vote_state_pubkey() { + } else if *pubkey == invalid_vote_state_pubkey() { AccountSharedData::new(0, 0, &solana_vote_program::id()) - } else if meta.pubkey == spoofed_stake_state_pubkey() { + } else if *pubkey == spoofed_stake_state_pubkey() { AccountSharedData::new(0, 0, &spoofed_stake_program_id()) } else { AccountSharedData::new(0, 0, &id()) @@ -419,17 +421,11 @@ mod tests { ) }) .collect(); - let mut sysvar_cache = SysvarCache::default(); - sysvar_cache.set_clock(Clock::default()); - mock_process_instruction_with_sysvars( - &id(), - Vec::new(), + process_instruction( &instruction.data, transaction_accounts, instruction.accounts.clone(), expected_result, - &sysvar_cache, - super::process_instruction, ) } @@ -1116,7 +1112,7 @@ mod tests { vec![ (address_with_seed, stake_account), (authorized_owner, authorized_account), - (clock_address, clock_account), + (clock_address, clock_account.clone()), (withdrawer, new_authorized_account), ], vec![ @@ -1169,13 +1165,10 @@ mod tests { ) .unwrap(); - let mut sysvar_cache = SysvarCache::default(); - sysvar_cache.set_clock(Clock::default()); - mock_process_instruction_with_sysvars( - &id(), - Vec::new(), + process_instruction( &instruction.data, vec![ + (clock_address, clock_account), (stake_address, stake_account), (withdrawer, withdrawer_account), (custodian, custodian_account), @@ -1198,8 +1191,6 @@ mod tests { }, ], Ok(()), - &sysvar_cache, - super::process_instruction, ); } } diff --git a/programs/vote/benches/process_vote.rs b/programs/vote/benches/process_vote.rs index 1e45845ae..4ab1e56f7 100644 --- a/programs/vote/benches/process_vote.rs +++ b/programs/vote/benches/process_vote.rs @@ -3,7 +3,7 @@ extern crate test; use { - solana_program_runtime::{invoke_context::InvokeContext, sysvar_cache::SysvarCache}, + solana_program_runtime::invoke_context::InvokeContext, solana_sdk::{ account::{create_account_for_test, Account, AccountSharedData}, clock::{Clock, Slot}, @@ -148,10 +148,6 @@ fn do_bench_process_vote_instruction(bencher: &mut Bencher, feature: Option>(); - let mut sysvar_cache = SysvarCache::default(); - sysvar_cache.set_clock(clock); - sysvar_cache.set_slot_hashes(slot_hashes); - bencher.iter(|| { let mut transaction_context = TransactionContext::new( vec![ @@ -174,12 +170,8 @@ fn do_bench_process_vote_instruction(bencher: &mut Bencher, feature: Option Result, InstructionError> { - check_sysvar_keyed_account::(keyed_account)?; - invoke_context.get_sysvar_cache().get_clock() - } - - pub fn rent( - keyed_account: &KeyedAccount, - invoke_context: &InvokeContext, - ) -> Result, InstructionError> { - check_sysvar_keyed_account::(keyed_account)?; - invoke_context.get_sysvar_cache().get_rent() - } - - pub fn slot_hashes( - keyed_account: &KeyedAccount, - invoke_context: &InvokeContext, - ) -> Result, InstructionError> { - check_sysvar_keyed_account::(keyed_account)?; - invoke_context.get_sysvar_cache().get_slot_hashes() - } -} - pub fn process_instruction( first_instruction_account: usize, data: &[u8], @@ -70,19 +36,19 @@ pub fn process_instruction( let signers: HashSet = get_signers(&keyed_accounts[first_instruction_account..]); match limited_deserialize(data)? { VoteInstruction::InitializeAccount(vote_init) => { - let rent = get_sysvar_with_keyed_account_check::rent( + let rent = get_sysvar_with_account_check::rent( keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?, invoke_context, )?; verify_rent_exemption(me, &rent)?; - let clock = get_sysvar_with_keyed_account_check::clock( + let clock = get_sysvar_with_account_check::clock( keyed_account_at_index(keyed_accounts, first_instruction_account + 2)?, invoke_context, )?; vote_state::initialize_account(me, &vote_init, &signers, &clock) } VoteInstruction::Authorize(voter_pubkey, vote_authorize) => { - let clock = get_sysvar_with_keyed_account_check::clock( + let clock = get_sysvar_with_account_check::clock( keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?, invoke_context, )?; @@ -105,11 +71,11 @@ pub fn process_instruction( } VoteInstruction::Vote(vote) | VoteInstruction::VoteSwitch(vote, _) => { inc_new_counter_info!("vote-native", 1); - let slot_hashes = get_sysvar_with_keyed_account_check::slot_hashes( + let slot_hashes = get_sysvar_with_account_check::slot_hashes( keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?, invoke_context, )?; - let clock = get_sysvar_with_keyed_account_check::clock( + let clock = get_sysvar_with_account_check::clock( keyed_account_at_index(keyed_accounts, first_instruction_account + 2)?, invoke_context, )?; @@ -164,15 +130,16 @@ pub fn process_instruction( &keyed_account_at_index(keyed_accounts, first_instruction_account + 3)? .signer_key() .ok_or(InstructionError::MissingRequiredSignature)?; + let clock = get_sysvar_with_account_check::clock( + keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?, + invoke_context, + )?; vote_state::authorize( me, voter_pubkey, vote_authorize, &signers, - &from_keyed_account::(keyed_account_at_index( - keyed_accounts, - first_instruction_account + 1, - )?)?, + &clock, &invoke_context.feature_set, ) } else { @@ -206,15 +173,12 @@ mod tests { vote_state::{Vote, VoteAuthorize, VoteInit, VoteState, VoteStateUpdate}, }, bincode::serialize, - solana_program_runtime::{ - invoke_context::{mock_process_instruction, mock_process_instruction_with_sysvars}, - sysvar_cache::SysvarCache, - }, + solana_program_runtime::invoke_context::mock_process_instruction, solana_sdk::{ account::{self, Account, AccountSharedData}, hash::Hash, instruction::{AccountMeta, Instruction}, - sysvar, + sysvar::{self, clock::Clock, slot_hashes::SlotHashes}, }, std::str::FromStr, }; @@ -244,19 +208,26 @@ mod tests { instruction: &Instruction, expected_result: Result<(), InstructionError>, ) -> Vec { - let transaction_accounts: Vec<_> = instruction + let mut pubkeys: HashSet = instruction .accounts .iter() - .map(|meta| { + .map(|meta| meta.pubkey) + .collect(); + pubkeys.insert(sysvar::clock::id()); + pubkeys.insert(sysvar::rent::id()); + pubkeys.insert(sysvar::slot_hashes::id()); + let transaction_accounts: Vec<_> = pubkeys + .iter() + .map(|pubkey| { ( - meta.pubkey, - if sysvar::clock::check_id(&meta.pubkey) { + *pubkey, + if sysvar::clock::check_id(pubkey) { account::create_account_shared_data_for_test(&Clock::default()) - } else if sysvar::slot_hashes::check_id(&meta.pubkey) { + } else if sysvar::slot_hashes::check_id(pubkey) { account::create_account_shared_data_for_test(&SlotHashes::default()) - } else if sysvar::rent::check_id(&meta.pubkey) { + } else if sysvar::rent::check_id(pubkey) { account::create_account_shared_data_for_test(&Rent::free()) - } else if meta.pubkey == invalid_vote_state_pubkey() { + } else if *pubkey == invalid_vote_state_pubkey() { AccountSharedData::from(Account { owner: invalid_vote_state_pubkey(), ..Account::default() @@ -270,19 +241,11 @@ mod tests { ) }) .collect(); - let mut sysvar_cache = SysvarCache::default(); - sysvar_cache.set_rent(Rent::free()); - sysvar_cache.set_clock(Clock::default()); - sysvar_cache.set_slot_hashes(SlotHashes::default()); - mock_process_instruction_with_sysvars( - &id(), - Vec::new(), + process_instruction( &instruction.data, transaction_accounts, instruction.accounts.clone(), expected_result, - &sysvar_cache, - super::process_instruction, ) } diff --git a/runtime/src/bank/sysvar_cache.rs b/runtime/src/bank/sysvar_cache.rs index f4262027c..66d28abeb 100644 --- a/runtime/src/bank/sysvar_cache.rs +++ b/runtime/src/bank/sysvar_cache.rs @@ -1,51 +1,14 @@ -use { - super::Bank, - solana_program_runtime::sysvar_cache::SysvarCache, - solana_sdk::{account::ReadableAccount, sysvar::Sysvar}, -}; +use super::Bank; impl Bank { pub(crate) fn fill_missing_sysvar_cache_entries(&self) { let mut sysvar_cache = self.sysvar_cache.write().unwrap(); - if sysvar_cache.get_clock().is_err() { - if let Some(clock) = self.load_sysvar_account() { - sysvar_cache.set_clock(clock); - } - } - if sysvar_cache.get_epoch_schedule().is_err() { - if let Some(epoch_schedule) = self.load_sysvar_account() { - sysvar_cache.set_epoch_schedule(epoch_schedule); - } - } - #[allow(deprecated)] - if sysvar_cache.get_fees().is_err() { - if let Some(fees) = self.load_sysvar_account() { - sysvar_cache.set_fees(fees); - } - } - if sysvar_cache.get_rent().is_err() { - if let Some(rent) = self.load_sysvar_account() { - sysvar_cache.set_rent(rent); - } - } - if sysvar_cache.get_slot_hashes().is_err() { - if let Some(slot_hashes) = self.load_sysvar_account() { - sysvar_cache.set_slot_hashes(slot_hashes); - } - } + sysvar_cache.fill_missing_entries(|pubkey| self.get_account_with_fixed_root(pubkey)); } pub(crate) fn reset_sysvar_cache(&self) { let mut sysvar_cache = self.sysvar_cache.write().unwrap(); - *sysvar_cache = SysvarCache::default(); - } - - fn load_sysvar_account(&self) -> Option { - if let Some(account) = self.get_account_with_fixed_root(&T::id()) { - bincode::deserialize(account.data()).ok() - } else { - None - } + sysvar_cache.reset(); } }