From d49ed4ec57ae72fa7a340594902877b1de3ad4b5 Mon Sep 17 00:00:00 2001 From: Justin Starry Date: Wed, 12 Jan 2022 11:19:11 +0800 Subject: [PATCH] Refactor: move sysvar cache to new module (cherry picked from commit 7171c95bdd5738b835150098cd3af3bcc3d0ada7) # Conflicts: # Cargo.lock # program-runtime/Cargo.toml # program-runtime/src/invoke_context.rs # program-runtime/src/lib.rs # programs/bpf/Cargo.lock # programs/bpf_loader/src/syscalls.rs # programs/stake/src/stake_instruction.rs # programs/vote/src/vote_instruction.rs # runtime/src/bank.rs # runtime/src/message_processor.rs --- Cargo.lock | 26 ++ program-runtime/Cargo.toml | 39 +++ program-runtime/src/invoke_context.rs | 29 ++- program-runtime/src/lib.rs | 12 + program-runtime/src/sysvar_cache.rs | 39 +++ programs/bpf/Cargo.lock | 30 +++ programs/bpf_loader/src/syscalls.rs | 52 +++- programs/stake/src/stake_instruction.rs | 58 +++++ programs/vote/src/vote_instruction.rs | 30 +++ runtime/src/bank.rs | 316 ++++++++++++++++++++++++ runtime/src/bank/sysvar_cache.rs | 33 +++ runtime/src/message_processor.rs | 177 +++++++++++++ 12 files changed, 831 insertions(+), 10 deletions(-) create mode 100644 program-runtime/Cargo.toml create mode 100644 program-runtime/src/lib.rs create mode 100644 program-runtime/src/sysvar_cache.rs create mode 100644 runtime/src/bank/sysvar_cache.rs diff --git a/Cargo.lock b/Cargo.lock index 1be1e90c9c1..bae3270aca7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5355,6 +5355,32 @@ dependencies = [ "solana-sdk-macro 1.8.13", "static_assertions", "thiserror", +<<<<<<< HEAD +======= + "wasm-bindgen", +] + +[[package]] +name = "solana-program-runtime" +version = "1.10.0" +dependencies = [ + "base64 0.13.0", + "bincode", + "itertools 0.10.3", + "libc", + "libloading", + "log 0.4.14", + "num-derive", + "num-traits", + "rustc_version 0.4.0", + "serde", + "solana-frozen-abi 1.10.0", + "solana-frozen-abi-macro 1.10.0", + "solana-logger 1.10.0", + "solana-measure", + "solana-sdk", + "thiserror", +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) ] [[package]] diff --git a/program-runtime/Cargo.toml b/program-runtime/Cargo.toml new file mode 100644 index 00000000000..cb5a4cf3342 --- /dev/null +++ b/program-runtime/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "solana-program-runtime" +version = "1.10.0" +description = "Solana program runtime" +authors = ["Solana Maintainers "] +repository = "https://github.com/solana-labs/solana" +license = "Apache-2.0" +homepage = "https://solana.com/" +documentation = "https://docs.rs/solana-program-runtime" +edition = "2021" + +[dependencies] +base64 = "0.13" +bincode = "1.3.3" +itertools = "0.10.1" +libc = "0.2.101" +libloading = "0.7.0" +log = "0.4.14" +num-derive = { version = "0.3" } +num-traits = { version = "0.2" } +serde = { version = "1.0.129", features = ["derive", "rc"] } +solana-frozen-abi = { path = "../frozen-abi", version = "=1.10.0" } +solana-frozen-abi-macro = { path = "../frozen-abi/macro", version = "=1.10.0" } +solana-measure = { path = "../measure", version = "=1.10.0" } +solana-sdk = { path = "../sdk", version = "=1.10.0" } +thiserror = "1.0" + +[dev-dependencies] +solana-logger = { path = "../logger", version = "=1.10.0" } + +[lib] +crate-type = ["lib"] +name = "solana_program_runtime" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[build-dependencies] +rustc_version = "0.4" diff --git a/program-runtime/src/invoke_context.rs b/program-runtime/src/invoke_context.rs index 526cc3ba14b..3eeac1ef074 100644 --- a/program-runtime/src/invoke_context.rs +++ b/program-runtime/src/invoke_context.rs @@ -1,8 +1,19 @@ use { crate::{ +<<<<<<< HEAD accounts_data_meter::AccountsDataMeter, ic_logger_msg, ic_msg, instruction_recorder::InstructionRecorder, log_collector::LogCollector, native_loader::NativeLoader, pre_account::PreAccount, timings::ExecuteDetailsTimings, +======= + accounts_data_meter::AccountsDataMeter, + ic_logger_msg, ic_msg, + instruction_recorder::InstructionRecorder, + log_collector::LogCollector, + native_loader::NativeLoader, + pre_account::PreAccount, + sysvar_cache::SysvarCache, + timings::{ExecuteDetailsTimings, ExecuteTimings}, +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) }, solana_sdk::{ account::{AccountSharedData, ReadableAccount}, @@ -22,7 +33,7 @@ use { sysvar::Sysvar, transaction_context::{InstructionAccount, TransactionAccount, TransactionContext}, }, - std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc, sync::Arc}, + std::{borrow::Cow, cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc, sync::Arc}, }; pub type ProcessInstructionWithContext = @@ -180,7 +191,7 @@ pub struct InvokeContext<'a> { rent: Rent, pre_accounts: Vec, builtin_programs: &'a [BuiltinProgram], - pub sysvars: &'a [(Pubkey, Vec)], + pub sysvar_cache: Cow<'a, SysvarCache>, log_collector: Option>>, compute_budget: ComputeBudget, current_compute_budget: ComputeBudget, @@ -200,7 +211,7 @@ impl<'a> InvokeContext<'a> { transaction_context: &'a mut TransactionContext, rent: Rent, builtin_programs: &'a [BuiltinProgram], - sysvars: &'a [(Pubkey, Vec)], + sysvar_cache: Cow<'a, SysvarCache>, log_collector: Option>>, compute_budget: ComputeBudget, executors: Rc>, @@ -217,7 +228,7 @@ impl<'a> InvokeContext<'a> { rent, pre_accounts: Vec::new(), builtin_programs, - sysvars, + sysvar_cache, log_collector, current_compute_budget: compute_budget, compute_budget, @@ -240,7 +251,7 @@ impl<'a> InvokeContext<'a> { transaction_context, Rent::default(), builtin_programs, - &[], + Cow::Owned(SysvarCache::default()), Some(LogCollector::new_ref()), ComputeBudget::default(), Rc::new(RefCell::new(Executors::default())), @@ -948,7 +959,7 @@ impl<'a> InvokeContext<'a> { /// Get the value of a sysvar by its id pub fn get_sysvar(&self, id: &Pubkey) -> Result { - self.sysvars + self.sysvar_cache .iter() .find_map(|(key, data)| { if id == key { @@ -1040,7 +1051,7 @@ pub fn mock_process_instruction_with_sysvars( transaction_accounts: Vec, instruction_accounts: Vec, expected_result: Result<(), InstructionError>, - sysvars: &[(Pubkey, Vec)], + sysvar_cache: &SysvarCache, process_instruction: ProcessInstructionWithContext, ) -> Vec { program_indices.insert(0, transaction_accounts.len()); @@ -1055,7 +1066,7 @@ pub fn mock_process_instruction_with_sysvars( ComputeBudget::default().max_invoke_depth.saturating_add(1), ); let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); - invoke_context.sysvars = sysvars; + invoke_context.sysvar_cache = Cow::Borrowed(sysvar_cache); let result = invoke_context .push( &preparation.instruction_accounts, @@ -1086,7 +1097,7 @@ pub fn mock_process_instruction( transaction_accounts, instruction_accounts, expected_result, - &[], + &SysvarCache::default(), process_instruction, ) } diff --git a/program-runtime/src/lib.rs b/program-runtime/src/lib.rs new file mode 100644 index 00000000000..e313be69c71 --- /dev/null +++ b/program-runtime/src/lib.rs @@ -0,0 +1,12 @@ +#![cfg_attr(RUSTC_WITH_SPECIALIZATION, feature(min_specialization))] + +pub mod accounts_data_meter; +pub mod instruction_recorder; +pub mod invoke_context; +pub mod log_collector; +pub mod native_loader; +pub mod neon_evm_program; +pub mod pre_account; +pub mod stable_log; +pub mod sysvar_cache; +pub mod timings; diff --git a/program-runtime/src/sysvar_cache.rs b/program-runtime/src/sysvar_cache.rs new file mode 100644 index 00000000000..ba9629c9924 --- /dev/null +++ b/program-runtime/src/sysvar_cache.rs @@ -0,0 +1,39 @@ +use { + solana_sdk::{ + account::{AccountSharedData, ReadableAccount}, + pubkey::Pubkey, + }, + std::ops::Deref, +}; + +#[cfg(RUSTC_WITH_SPECIALIZATION)] +impl ::solana_frozen_abi::abi_example::AbiExample for SysvarCache { + fn example() -> Self { + // SysvarCache is not Serialize so just rely on Default. + SysvarCache::default() + } +} + +#[derive(Default, Clone, Debug)] +pub struct SysvarCache(Vec<(Pubkey, Vec)>); + +impl Deref for SysvarCache { + type Target = Vec<(Pubkey, Vec)>; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl SysvarCache { + pub fn push_entry(&mut self, pubkey: Pubkey, data: Vec) { + self.0.push((pubkey, data)); + } + + pub fn update_entry(&mut self, pubkey: &Pubkey, new_account: &AccountSharedData) { + if let Some(position) = self.iter().position(|(id, _data)| id == pubkey) { + self.0[position].1 = new_account.data().to_vec(); + } else { + self.0.push((*pubkey, new_account.data().to_vec())); + } + } +} diff --git a/programs/bpf/Cargo.lock b/programs/bpf/Cargo.lock index ab78d1adca7..cc5607e0a29 100644 --- a/programs/bpf/Cargo.lock +++ b/programs/bpf/Cargo.lock @@ -3426,12 +3426,42 @@ dependencies = [ "serde", "serde_bytes", "serde_derive", +<<<<<<< HEAD "sha2", "sha3", "solana-frozen-abi 1.8.13", "solana-frozen-abi-macro 1.8.13", "solana-logger 1.8.13", "solana-sdk-macro 1.8.13", +======= + "sha2 0.10.1", + "sha3 0.10.0", + "solana-frozen-abi 1.10.0", + "solana-frozen-abi-macro 1.10.0", + "solana-sdk-macro 1.10.0", + "thiserror", + "wasm-bindgen", +] + +[[package]] +name = "solana-program-runtime" +version = "1.10.0" +dependencies = [ + "base64 0.13.0", + "bincode", + "itertools 0.10.3", + "libc", + "libloading", + "log", + "num-derive", + "num-traits", + "rustc_version 0.4.0", + "serde", + "solana-frozen-abi 1.10.0", + "solana-frozen-abi-macro 1.10.0", + "solana-measure", + "solana-sdk", +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) "thiserror", ] diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index d8803dfc6e7..aa80c22de32 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -2766,6 +2766,10 @@ impl<'a> SyscallObject for SyscallLogData<'a> { mod tests { use { super::*, +<<<<<<< HEAD +======= + solana_program_runtime::{invoke_context::InvokeContext, sysvar_cache::SysvarCache}, +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) solana_rbpf::{ ebpf::HOST_ALIGN, memory_region::MemoryRegion, user_error::UserError, vm::Config, }, @@ -2775,7 +2779,7 @@ mod tests { hash::hashv, process_instruction::{MockComputeMeter, MockInvokeContext, MockLogger}, }, - std::str::FromStr, + std::{borrow::Cow, str::FromStr}, }; macro_rules! assert_access_violation { @@ -3620,6 +3624,52 @@ mod tests { #[test] fn test_syscall_get_sysvar() { let config = Config::default(); +<<<<<<< HEAD +======= + let src_clock = Clock { + slot: 1, + epoch_start_timestamp: 2, + epoch: 3, + leader_schedule_epoch: 4, + unix_timestamp: 5, + }; + let src_epochschedule = EpochSchedule { + slots_per_epoch: 1, + leader_schedule_slot_offset: 2, + warmup: false, + first_normal_epoch: 3, + first_normal_slot: 4, + }; + let src_fees = Fees { + fee_calculator: FeeCalculator { + lamports_per_signature: 1, + }, + }; + let src_rent = Rent { + lamports_per_byte_year: 1, + exemption_threshold: 2.0, + burn_percent: 3, + }; + + let mut sysvar_cache = SysvarCache::default(); + sysvar_cache.push_entry(sysvar::clock::id(), bincode::serialize(&src_clock).unwrap()); + sysvar_cache.push_entry( + sysvar::epoch_schedule::id(), + bincode::serialize(&src_epochschedule).unwrap(), + ); + sysvar_cache.push_entry(sysvar::fees::id(), bincode::serialize(&src_fees).unwrap()); + sysvar_cache.push_entry(sysvar::rent::id(), bincode::serialize(&src_rent).unwrap()); + + let program_id = Pubkey::new_unique(); + let mut transaction_context = TransactionContext::new( + vec![(program_id, AccountSharedData::new(0, 0, &bpf_loader::id()))], + 1, + ); + let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); + invoke_context.sysvar_cache = Cow::Owned(sysvar_cache); + invoke_context.push(&[], &[0], &[]).unwrap(); + +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) // Test clock sysvar { let got_clock = Clock::default(); diff --git a/programs/stake/src/stake_instruction.rs b/programs/stake/src/stake_instruction.rs index ae37c580596..7d15c10214d 100644 --- a/programs/stake/src/stake_instruction.rs +++ b/programs/stake/src/stake_instruction.rs @@ -277,6 +277,13 @@ mod tests { super::*, crate::stake_state::{Meta, StakeState}, bincode::serialize, +<<<<<<< HEAD +======= + solana_program_runtime::{ + invoke_context::{mock_process_instruction, mock_process_instruction_with_sysvars}, + sysvar_cache::SysvarCache, + }, +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) solana_sdk::{ account::{self, Account, AccountSharedData, WritableAccount}, instruction::{AccountMeta, Instruction}, @@ -360,6 +367,7 @@ mod tests { }) }) .collect(); +<<<<<<< HEAD { let keyed_accounts: Vec<_> = instruction @@ -378,6 +386,21 @@ mod tests { .unwrap(); super::process_instruction(&Pubkey::default(), &instruction.data, &mut invoke_context) } +======= + let mut sysvar_cache = SysvarCache::default(); + let clock = Clock::default(); + sysvar_cache.push_entry(sysvar::clock::id(), bincode::serialize(&clock).unwrap()); + mock_process_instruction_with_sysvars( + &id(), + Vec::new(), + &instruction.data, + transaction_accounts, + instruction.accounts.clone(), + expected_result, + &sysvar_cache, + super::process_instruction, + ) +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) } #[test] @@ -1031,6 +1054,7 @@ mod tests { .unwrap(); let custodian_account = create_default_account(); +<<<<<<< HEAD let keyed_accounts = vec![ KeyedAccount::new(&stake_address, false, &stake_account), KeyedAccount::new(&withdrawer, true, &withdrawer_account), @@ -1056,6 +1080,40 @@ mod tests { &mut invoke_context ), Ok(()), +======= + let mut sysvar_cache = SysvarCache::default(); + let clock = Clock::default(); + sysvar_cache.push_entry(sysvar::clock::id(), bincode::serialize(&clock).unwrap()); + mock_process_instruction_with_sysvars( + &id(), + Vec::new(), + &instruction.data, + vec![ + (stake_address, stake_account), + (withdrawer, withdrawer_account), + (custodian, custodian_account), + ], + vec![ + AccountMeta { + pubkey: stake_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: withdrawer, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: custodian, + is_signer: true, + is_writable: false, + }, + ], + Ok(()), + &sysvar_cache, + super::process_instruction, +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) ); } } diff --git a/programs/vote/src/vote_instruction.rs b/programs/vote/src/vote_instruction.rs index 22b13bac6f1..77a177f314a 100644 --- a/programs/vote/src/vote_instruction.rs +++ b/programs/vote/src/vote_instruction.rs @@ -400,6 +400,13 @@ mod tests { use { super::*, bincode::serialize, +<<<<<<< HEAD +======= + solana_program_runtime::{ + invoke_context::{mock_process_instruction, mock_process_instruction_with_sysvars}, + sysvar_cache::SysvarCache, + }, +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) solana_sdk::{ account::{self, Account, AccountSharedData}, process_instruction::{mock_set_sysvar, MockInvokeContext}, @@ -450,6 +457,7 @@ mod tests { }) }) .collect(); +<<<<<<< HEAD for _ in 0..instruction.accounts.len() { accounts.push(RefCell::new(AccountSharedData::default())); @@ -470,6 +478,28 @@ mod tests { .unwrap(); super::process_instruction(&Pubkey::default(), &instruction.data, &mut invoke_context) } +======= + let mut sysvar_cache = SysvarCache::default(); + let rent = Rent::default(); + sysvar_cache.push_entry(sysvar::rent::id(), bincode::serialize(&rent).unwrap()); + let clock = Clock::default(); + sysvar_cache.push_entry(sysvar::clock::id(), bincode::serialize(&clock).unwrap()); + let slot_hashes = SlotHashes::default(); + sysvar_cache.push_entry( + sysvar::slot_hashes::id(), + bincode::serialize(&slot_hashes).unwrap(), + ); + mock_process_instruction_with_sysvars( + &id(), + Vec::new(), + &instruction.data, + transaction_accounts, + instruction.accounts.clone(), + expected_result, + &sysvar_cache, + super::process_instruction, + ) +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) } fn invalid_vote_state_pubkey() -> Pubkey { diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index f951d29403c..352966e8fb8 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -76,6 +76,18 @@ use { }, solana_measure::measure::Measure, solana_metrics::{inc_new_counter_debug, inc_new_counter_info}, +<<<<<<< HEAD +======= + solana_program_runtime::{ + instruction_recorder::InstructionRecorder, + invoke_context::{ + BuiltinProgram, Executor, Executors, ProcessInstructionWithContext, TransactionExecutor, + }, + log_collector::LogCollector, + sysvar_cache::SysvarCache, + timings::ExecuteTimings, + }, +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) solana_sdk::{ account::{ create_account_shared_data_with_fields as create_account, from_account, Account, @@ -145,6 +157,12 @@ use { }, }; +<<<<<<< HEAD +======= +mod sysvar_cache; +mod transaction_account_state_info; + +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) pub const SECONDS_PER_YEAR: f64 = 365.25 * 24.0 * 60.0 * 60.0; pub const MAX_LEADER_SCHEDULE_STAKES: Epoch = 5; @@ -1184,6 +1202,15 @@ pub struct Bank { vote_only_bank: bool, pub cost_tracker: RwLock, +<<<<<<< HEAD +======= + + sysvar_cache: RwLock, + + /// Current size of the accounts data. Used when processing messages to enforce a limit on its + /// maximum size. + accounts_data_len: AtomicU64, +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) } impl Default for BlockhashQueue { @@ -1260,6 +1287,122 @@ impl Bank { accounts_db_caching_enabled, shrink_ratio, false, +<<<<<<< HEAD +======= + ) + } + + fn default_with_accounts(accounts: Accounts) -> Self { + let bank = Self { + rc: BankRc::new(accounts, Slot::default()), + src: StatusCacheRc::default(), + blockhash_queue: RwLock::::default(), + ancestors: Ancestors::default(), + hash: RwLock::::default(), + parent_hash: Hash::default(), + parent_slot: Slot::default(), + hard_forks: Arc::>::default(), + transaction_count: AtomicU64::default(), + transaction_error_count: AtomicU64::default(), + transaction_entries_count: AtomicU64::default(), + transactions_per_entry_max: AtomicU64::default(), + tick_height: AtomicU64::default(), + signature_count: AtomicU64::default(), + capitalization: AtomicU64::default(), + max_tick_height: u64::default(), + hashes_per_tick: Option::::default(), + ticks_per_slot: u64::default(), + ns_per_slot: u128::default(), + genesis_creation_time: UnixTimestamp::default(), + slots_per_year: f64::default(), + unused: u64::default(), + slot: Slot::default(), + bank_id: BankId::default(), + epoch: Epoch::default(), + block_height: u64::default(), + collector_id: Pubkey::default(), + collector_fees: AtomicU64::default(), + fee_calculator: FeeCalculator::default(), + fee_rate_governor: FeeRateGovernor::default(), + collected_rent: AtomicU64::default(), + rent_collector: RentCollector::default(), + epoch_schedule: EpochSchedule::default(), + inflation: Arc::>::default(), + stakes_cache: StakesCache::default(), + epoch_stakes: HashMap::::default(), + is_delta: AtomicBool::default(), + builtin_programs: BuiltinPrograms::default(), + compute_budget: Option::::default(), + feature_builtins: Arc::>::default(), + rewards: RwLock::>::default(), + cluster_type: Option::::default(), + lazy_rent_collection: AtomicBool::default(), + rewards_pool_pubkeys: Arc::>::default(), + cached_executors: RwLock::>::default(), + transaction_debug_keys: Option::>>::default(), + transaction_log_collector_config: Arc::>::default( + ), + transaction_log_collector: Arc::>::default(), + feature_set: Arc::::default(), + drop_callback: RwLock::::default(), + freeze_started: AtomicBool::default(), + vote_only_bank: false, + cost_tracker: RwLock::::default(), + sysvar_cache: RwLock::::default(), + accounts_data_len: AtomicU64::default(), + }; + + let total_accounts_stats = bank.get_total_accounts_stats().unwrap(); + bank.store_accounts_data_len(total_accounts_stats.data_len as u64); + + bank + } + + pub fn new_with_paths_for_tests( + genesis_config: &GenesisConfig, + paths: Vec, + debug_keys: Option>>, + additional_builtins: Option<&Builtins>, + account_indexes: AccountSecondaryIndexes, + accounts_db_caching_enabled: bool, + shrink_ratio: AccountShrinkThreshold, + debug_do_not_add_builtins: bool, + ) -> Self { + Self::new_with_paths( + genesis_config, + paths, + debug_keys, + additional_builtins, + account_indexes, + accounts_db_caching_enabled, + shrink_ratio, + debug_do_not_add_builtins, + Some(ACCOUNTS_DB_CONFIG_FOR_TESTING), + None, + ) + } + + pub fn new_with_paths_for_benches( + genesis_config: &GenesisConfig, + paths: Vec, + debug_keys: Option>>, + additional_builtins: Option<&Builtins>, + account_indexes: AccountSecondaryIndexes, + accounts_db_caching_enabled: bool, + shrink_ratio: AccountShrinkThreshold, + debug_do_not_add_builtins: bool, + ) -> Self { + Self::new_with_paths( + genesis_config, + paths, + debug_keys, + additional_builtins, + account_indexes, + accounts_db_caching_enabled, + shrink_ratio, + debug_do_not_add_builtins, + Some(ACCOUNTS_DB_CONFIG_FOR_BENCHMARKS), +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) None, ) } @@ -1456,6 +1599,11 @@ impl Bank { )), freeze_started: AtomicBool::new(false), cost_tracker: RwLock::new(CostTracker::default()), +<<<<<<< HEAD +======= + sysvar_cache: RwLock::new(SysvarCache::default()), + accounts_data_len: AtomicU64::new(parent.load_accounts_data_len()), +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) }; let mut ancestors = Vec::with_capacity(1 + new.parents().len()); @@ -1631,6 +1779,11 @@ impl Bank { freeze_started: AtomicBool::new(fields.hash != Hash::default()), vote_only_bank: false, cost_tracker: RwLock::new(CostTracker::default()), +<<<<<<< HEAD +======= + sysvar_cache: RwLock::new(SysvarCache::default()), + accounts_data_len: AtomicU64::new(accounts_data_len), +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) }; bank.finish_init( genesis_config, @@ -1806,6 +1959,13 @@ impl Bank { } self.store_account_and_update_capitalization(pubkey, &new_account); +<<<<<<< HEAD +======= + + // Update the entry in the cache + let mut sysvar_cache = self.sysvar_cache.write().unwrap(); + sysvar_cache.update_entry(pubkey, &new_account); +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) } fn inherit_specially_retained_account_fields( @@ -3467,6 +3627,162 @@ impl Bank { Arc::make_mut(&mut cache).remove(pubkey); } +<<<<<<< HEAD +======= + pub fn load_lookup_table_addresses( + &self, + address_table_lookups: &[MessageAddressTableLookup], + ) -> Result { + if !self.versioned_tx_message_enabled() { + return Err(TransactionError::UnsupportedVersion); + } + + let slot_hashes: SlotHashes = self + .get_cached_sysvar(&sysvar::slot_hashes::id()) + .ok_or(TransactionError::AccountNotFound)?; + Ok(address_table_lookups + .iter() + .map(|address_table_lookup| { + self.rc.accounts.load_lookup_table_addresses( + &self.ancestors, + address_table_lookup, + &slot_hashes, + ) + }) + .collect::>()?) + } + + /// Execute a transaction using the provided loaded accounts and update + /// the executors cache if the transaction was successful. + fn execute_loaded_transaction( + &self, + tx: &SanitizedTransaction, + loaded_transaction: &mut LoadedTransaction, + compute_budget: ComputeBudget, + durable_nonce_fee: Option, + enable_cpi_recording: bool, + enable_log_recording: bool, + timings: &mut ExecuteTimings, + error_counters: &mut ErrorCounters, + ) -> TransactionExecutionResult { + let mut get_executors_time = Measure::start("get_executors_time"); + let executors = self.get_executors( + tx.message(), + &loaded_transaction.accounts, + &loaded_transaction.program_indices, + ); + get_executors_time.stop(); + saturating_add_assign!( + timings.execute_accessories.get_executors_us, + get_executors_time.as_us() + ); + + let mut transaction_accounts = Vec::new(); + std::mem::swap(&mut loaded_transaction.accounts, &mut transaction_accounts); + let mut transaction_context = TransactionContext::new( + transaction_accounts, + compute_budget.max_invoke_depth.saturating_add(1), + ); + + let pre_account_state_info = + self.get_transaction_account_state_info(&transaction_context, tx.message()); + + let instruction_recorder = if enable_cpi_recording { + Some(InstructionRecorder::new_ref( + tx.message().instructions().len(), + )) + } else { + None + }; + + let log_collector = if enable_log_recording { + Some(LogCollector::new_ref()) + } else { + None + }; + + let (blockhash, lamports_per_signature) = self.last_blockhash_and_lamports_per_signature(); + + let mut process_message_time = Measure::start("process_message_time"); + let process_result = MessageProcessor::process_message( + &self.builtin_programs.vec, + tx.message(), + &loaded_transaction.program_indices, + &mut transaction_context, + self.rent_collector.rent, + log_collector.clone(), + executors.clone(), + instruction_recorder.clone(), + self.feature_set.clone(), + compute_budget, + timings, + &*self.sysvar_cache.read().unwrap(), + blockhash, + lamports_per_signature, + self.load_accounts_data_len(), + ); + process_message_time.stop(); + saturating_add_assign!( + timings.execute_accessories.process_message_us, + process_message_time.as_us() + ); + + let mut update_executors_time = Measure::start("update_executors_time"); + self.update_executors(process_result.is_ok(), executors); + update_executors_time.stop(); + saturating_add_assign!( + timings.execute_accessories.update_executors_us, + update_executors_time.as_us() + ); + + let status = process_result + .and_then(|info| { + let post_account_state_info = + self.get_transaction_account_state_info(&transaction_context, tx.message()); + self.verify_transaction_account_state_changes( + &pre_account_state_info, + &post_account_state_info, + &transaction_context, + ) + .map(|_| info) + }) + .map(|info| { + self.store_accounts_data_len(info.accounts_data_len); + }) + .map_err(|err| { + match err { + TransactionError::InvalidRentPayingAccount => { + error_counters.invalid_rent_paying_account += 1; + } + _ => { + error_counters.instruction_error += 1; + } + } + err + }); + + let log_messages: Option = + log_collector.and_then(|log_collector| { + Rc::try_unwrap(log_collector) + .map(|log_collector| log_collector.into_inner().into()) + .ok() + }); + + let inner_instructions = instruction_recorder + .and_then(|instruction_recorder| Rc::try_unwrap(instruction_recorder).ok()) + .map(|instruction_recorder| instruction_recorder.into_inner().deconstruct()); + + loaded_transaction.accounts = transaction_context.deconstruct(); + + TransactionExecutionResult::Executed(TransactionExecutionDetails { + status, + log_messages, + inner_instructions, + durable_nonce_fee, + }) + } + +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) #[allow(clippy::type_complexity)] pub fn load_and_execute_transactions( &self, diff --git a/runtime/src/bank/sysvar_cache.rs b/runtime/src/bank/sysvar_cache.rs new file mode 100644 index 00000000000..c050276144f --- /dev/null +++ b/runtime/src/bank/sysvar_cache.rs @@ -0,0 +1,33 @@ +use { + super::Bank, + solana_sdk::{ + account::ReadableAccount, + pubkey::Pubkey, + sysvar::{self, Sysvar}, + }, +}; + +impl Bank { + pub(crate) fn fill_sysvar_cache(&mut self) { + let mut sysvar_cache = self.sysvar_cache.write().unwrap(); + for id in sysvar::ALL_IDS.iter() { + if !sysvar_cache.iter().any(|(key, _data)| key == id) { + if let Some(account) = self.get_account_with_fixed_root(id) { + sysvar_cache.push_entry(*id, account.data().to_vec()); + } + } + } + } + + /// Get the value of a cached sysvar by its id + pub fn get_cached_sysvar(&self, id: &Pubkey) -> Option { + let sysvar_cache = self.sysvar_cache.read().unwrap(); + sysvar_cache.iter().find_map(|(key, data)| { + if id == key { + bincode::deserialize(data).ok() + } else { + None + } + }) + } +} diff --git a/runtime/src/message_processor.rs b/runtime/src/message_processor.rs index aabc1ac3f8d..c0286801886 100644 --- a/runtime/src/message_processor.rs +++ b/runtime/src/message_processor.rs @@ -7,6 +7,7 @@ use { log::*, serde::{Deserialize, Serialize}, solana_measure::measure::Measure, +<<<<<<< HEAD solana_sdk::{ account::{AccountSharedData, ReadableAccount, WritableAccount}, account_utils::StateMut, @@ -26,17 +27,37 @@ use { Logger, ProcessInstructionWithContext, }, pubkey::Pubkey, +======= + solana_program_runtime::{ + instruction_recorder::InstructionRecorder, + invoke_context::{BuiltinProgram, Executors, InvokeContext}, + log_collector::LogCollector, + sysvar_cache::SysvarCache, + timings::ExecuteTimings, + }, + solana_sdk::{ + account::WritableAccount, + compute_budget::ComputeBudget, + feature_set::{prevent_calling_precompiles_as_programs, FeatureSet}, + hash::Hash, + message::SanitizedMessage, + precompiles::is_precompile, +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) rent::Rent, system_program, sysvar::instructions, transaction::TransactionError, }, +<<<<<<< HEAD std::{ cell::{Ref, RefCell}, collections::HashMap, rc::Rc, sync::Arc, }, +======= + std::{borrow::Cow, cell::RefCell, rc::Rc, sync::Arc}, +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) }; pub type Executors = HashMap; @@ -1303,6 +1324,7 @@ impl MessageProcessor { instruction_recorder: Option, instruction_index: usize, feature_set: Arc, +<<<<<<< HEAD bpf_compute_budget: BpfComputeBudget, compute_meter: Rc>, timings: &mut ExecuteDetailsTimings, @@ -1349,6 +1371,20 @@ impl MessageProcessor { executable_accounts, accounts, &self.programs, +======= + compute_budget: ComputeBudget, + timings: &mut ExecuteTimings, + sysvar_cache: &SysvarCache, + blockhash: Hash, + lamports_per_signature: u64, + current_accounts_data_len: u64, + ) -> Result { + let mut invoke_context = InvokeContext::new( + transaction_context, + rent, + builtin_programs, + Cow::Borrowed(sysvar_cache), +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) log_collector, bpf_compute_budget, compute_meter, @@ -1453,8 +1489,15 @@ mod tests { account::{AccountSharedData, ReadableAccount}, instruction::{AccountMeta, Instruction, InstructionError}, message::Message, +<<<<<<< HEAD native_loader::create_loadable_account_for_test, process_instruction::MockComputeMeter, +======= + native_loader::{self, create_loadable_account_for_test}, + pubkey::Pubkey, + secp256k1_instruction::new_secp256k1_instruction, + secp256k1_program, +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) }, }; @@ -2104,7 +2147,44 @@ mod tests { &MockSystemInstruction::Correct, account_metas.clone(), )], +<<<<<<< HEAD Some(&accounts[0].0), +======= + Some(transaction_context.get_key_of_account_at_index(0)), + )); + let sysvar_cache = SysvarCache::default(); + let result = MessageProcessor::process_message( + builtin_programs, + &message, + &program_indices, + &mut transaction_context, + rent_collector.rent, + None, + executors.clone(), + None, + Arc::new(FeatureSet::all_enabled()), + ComputeBudget::new(), + &mut ExecuteTimings::default(), + &sysvar_cache, + Hash::default(), + 0, + 0, + ); + assert!(result.is_ok()); + assert_eq!( + transaction_context + .get_account_at_index(0) + .borrow() + .lamports(), + 100 + ); + assert_eq!( + transaction_context + .get_account_at_index(1) + .borrow() + .lamports(), + 0 +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) ); let result = message_processor.process_message( @@ -2116,6 +2196,7 @@ mod tests { executors.clone(), None, Arc::new(FeatureSet::all_enabled()), +<<<<<<< HEAD BpfComputeBudget::new(), Rc::new(RefCell::new(MockComputeMeter::default())), &mut ExecuteDetailsTimings::default(), @@ -2149,6 +2230,14 @@ mod tests { &mut ExecuteDetailsTimings::default(), Arc::new(Accounts::default()), &ancestors, +======= + ComputeBudget::new(), + &mut ExecuteTimings::default(), + &sysvar_cache, + Hash::default(), + 0, + 0, +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) ); assert_eq!( result, @@ -2176,11 +2265,20 @@ mod tests { executors, None, Arc::new(FeatureSet::all_enabled()), +<<<<<<< HEAD BpfComputeBudget::new(), Rc::new(RefCell::new(MockComputeMeter::default())), &mut ExecuteDetailsTimings::default(), Arc::new(Accounts::default()), &ancestors, +======= + ComputeBudget::new(), + &mut ExecuteTimings::default(), + &sysvar_cache, + Hash::default(), + 0, + 0, +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) ); assert_eq!( result, @@ -2289,9 +2387,17 @@ mod tests { &MockSystemInstruction::BorrowFail, account_metas.clone(), )], +<<<<<<< HEAD Some(&accounts[0].0), ); let result = message_processor.process_message( +======= + Some(transaction_context.get_key_of_account_at_index(0)), + )); + let sysvar_cache = SysvarCache::default(); + let result = MessageProcessor::process_message( + builtin_programs, +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) &message, &loaders, &accounts, @@ -2300,11 +2406,20 @@ mod tests { executors.clone(), None, Arc::new(FeatureSet::all_enabled()), +<<<<<<< HEAD BpfComputeBudget::new(), Rc::new(RefCell::new(MockComputeMeter::default())), &mut ExecuteDetailsTimings::default(), Arc::new(Accounts::default()), &ancestors, +======= + ComputeBudget::new(), + &mut ExecuteTimings::default(), + &sysvar_cache, + Hash::default(), + 0, + 0, +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) ); assert_eq!( result, @@ -2332,11 +2447,20 @@ mod tests { executors.clone(), None, Arc::new(FeatureSet::all_enabled()), +<<<<<<< HEAD BpfComputeBudget::new(), Rc::new(RefCell::new(MockComputeMeter::default())), &mut ExecuteDetailsTimings::default(), Arc::new(Accounts::default()), &ancestors, +======= + ComputeBudget::new(), + &mut ExecuteTimings::default(), + &sysvar_cache, + Hash::default(), + 0, + 0, +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) ); assert_eq!(result, Ok(())); @@ -2362,11 +2486,39 @@ mod tests { executors, None, Arc::new(FeatureSet::all_enabled()), +<<<<<<< HEAD BpfComputeBudget::new(), Rc::new(RefCell::new(MockComputeMeter::default())), &mut ExecuteDetailsTimings::default(), Arc::new(Accounts::default()), &ancestors, +======= + ComputeBudget::new(), + &mut ExecuteTimings::default(), + &sysvar_cache, + Hash::default(), + 0, + 0, + ); + assert!(result.is_ok()); + assert_eq!( + transaction_context + .get_account_at_index(0) + .borrow() + .lamports(), + 80 + ); + assert_eq!( + transaction_context + .get_account_at_index(1) + .borrow() + .lamports(), + 20 + ); + assert_eq!( + transaction_context.get_account_at_index(0).borrow().data(), + &vec![42] +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) ); assert_eq!(result, Ok(())); assert_eq!(accounts[0].1.borrow().lamports(), 80); @@ -2448,6 +2600,7 @@ mod tests { (callee_program_id, Rc::new(RefCell::new(program_account))), ]; +<<<<<<< HEAD let programs: Vec<(_, ProcessInstructionWithContext)> = vec![(callee_program_id, mock_process_instruction)]; let metas = vec![ @@ -2471,6 +2624,21 @@ mod tests { let mut invoke_context = ThisInvokeContext::new( &caller_program_id, Rent::default(), +======= + let message = SanitizedMessage::Legacy(Message::new( + &[ + new_secp256k1_instruction( + &libsecp256k1::SecretKey::random(&mut rand::thread_rng()), + b"hello", + ), + Instruction::new_with_bytes(mock_program_id, &[], vec![]), + ], + None, + )); + let sysvar_cache = SysvarCache::default(); + let result = MessageProcessor::process_message( + builtin_programs, +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) &message, &caller_instruction, &executable_accounts, @@ -2706,8 +2874,17 @@ mod tests { Rc::new(RefCell::new(Executors::default())), None, Arc::new(FeatureSet::all_enabled()), +<<<<<<< HEAD Arc::new(Accounts::default()), &ancestors, +======= + ComputeBudget::new(), + &mut ExecuteTimings::default(), + &sysvar_cache, + Hash::default(), + 0, + 0, +>>>>>>> 7171c95bd (Refactor: move sysvar cache to new module) ); // not owned account modified by the invoker