From 0f3d1fe30f9cfa938d79b27107136461a0ae5f30 Mon Sep 17 00:00:00 2001 From: Joe Caulfield Date: Thu, 7 Nov 2024 23:41:37 +0400 Subject: [PATCH 1/2] SVM: add `new` bootstrap method --- svm/examples/paytube/src/processor.rs | 23 ++++------- svm/src/transaction_processor.rs | 58 ++++++++++++++++++++++----- svm/tests/concurrent_tests.rs | 4 +- svm/tests/conformance.rs | 25 ++++-------- 4 files changed, 66 insertions(+), 44 deletions(-) diff --git a/svm/examples/paytube/src/processor.rs b/svm/examples/paytube/src/processor.rs index b22bc6fde8586f..d840a1a66b6017 100644 --- a/svm/examples/paytube/src/processor.rs +++ b/svm/examples/paytube/src/processor.rs @@ -47,23 +47,16 @@ pub(crate) fn create_transaction_batch_processor::new_uninitialized( - /* slot */ 1, /* epoch */ 1, - ); - - { - let mut cache = processor.program_cache.write().unwrap(); - - // Initialize the mocked fork graph. - cache.fork_graph = Some(Arc::downgrade(&fork_graph)); - - // Initialize a proper cache environment. - // (Use Loader v4 program to initialize runtime v2 if desired) - cache.environments.program_runtime_v1 = Arc::new( + let processor = TransactionBatchProcessor::::new( + /* slot */ 1, + /* epoch */ 1, + Arc::downgrade(&fork_graph), + Some(Arc::new( create_program_runtime_environment_v1(feature_set, compute_budget, false, false) .unwrap(), - ); - } + )), + None, + ); // Add the system program builtin. processor.add_builtin( diff --git a/svm/src/transaction_processor.rs b/svm/src/transaction_processor.rs index 2f92d376152363..c302ccebe700f4 100644 --- a/svm/src/transaction_processor.rs +++ b/svm/src/transaction_processor.rs @@ -34,7 +34,11 @@ use { invoke_context::{EnvironmentConfig, InvokeContext}, loaded_programs::{ ForkGraph, ProgramCache, ProgramCacheEntry, ProgramCacheForTxBatch, - ProgramCacheMatchCriteria, + ProgramCacheMatchCriteria, ProgramRuntimeEnvironment, + }, + solana_rbpf::{ + program::{BuiltinProgram, FunctionRegistry}, + vm::Config as VmConfig, }, sysvar_cache::SysvarCache, }, @@ -61,6 +65,7 @@ use { collections::{hash_map::Entry, HashMap, HashSet}, fmt::{Debug, Formatter}, rc::Rc, + sync::Weak, }, }; @@ -208,6 +213,42 @@ impl TransactionBatchProcessor { } } + /// Create a new `TransactionBatchProcessor`. + /// + /// The created processor's program cache is initialized with the provided + /// fork graph and loaders. If any loaders are omitted, a default "empty" + /// loader (no syscalls) will be used. + /// + /// The cache will still not contain any builtin programs. It's advisable to + /// call `add_builtin` to add the required builtins before using the processor. + pub fn new( + slot: Slot, + epoch: Epoch, + fork_graph: Weak>, + program_runtime_environment_v1: Option, + program_runtime_environment_v2: Option, + ) -> Self { + let processor = Self::new_uninitialized(slot, epoch); + { + let empty_loader = || { + Arc::new(BuiltinProgram::new_loader( + VmConfig::default(), + FunctionRegistry::default(), + )) + }; + + let mut program_cache = processor.program_cache.write().unwrap(); + program_cache.set_fork_graph(fork_graph); + program_cache.latest_root_slot = slot; + program_cache.latest_root_epoch = epoch; + program_cache.environments.program_runtime_v1 = + program_runtime_environment_v1.unwrap_or(empty_loader()); + program_cache.environments.program_runtime_v2 = + program_runtime_environment_v2.unwrap_or(empty_loader()); + } + processor + } + /// Create a new `TransactionBatchProcessor` from the current instance, but /// with the provided slot and epoch. /// @@ -1378,10 +1419,9 @@ mod tests { #[should_panic = "called load_program_with_pubkey() with nonexistent account"] fn test_replenish_program_cache_with_nonexistent_accounts() { let mock_bank = MockBankCallback::default(); - let batch_processor = TransactionBatchProcessor::::default(); let fork_graph = Arc::new(RwLock::new(TestForkGraph {})); - batch_processor.program_cache.write().unwrap().fork_graph = - Some(Arc::downgrade(&fork_graph)); + let batch_processor = + TransactionBatchProcessor::new(0, 0, Arc::downgrade(&fork_graph), None, None); let key = Pubkey::new_unique(); let mut account_maps: HashMap = HashMap::new(); @@ -1393,10 +1433,9 @@ mod tests { #[test] fn test_replenish_program_cache() { let mock_bank = MockBankCallback::default(); - let batch_processor = TransactionBatchProcessor::::default(); let fork_graph = Arc::new(RwLock::new(TestForkGraph {})); - batch_processor.program_cache.write().unwrap().fork_graph = - Some(Arc::downgrade(&fork_graph)); + let batch_processor = + TransactionBatchProcessor::new(0, 0, Arc::downgrade(&fork_graph), None, None); let key = Pubkey::new_unique(); let mut account_data = AccountSharedData::default(); @@ -1881,10 +1920,9 @@ mod tests { #[test] fn test_add_builtin() { let mock_bank = MockBankCallback::default(); - let batch_processor = TransactionBatchProcessor::::default(); let fork_graph = Arc::new(RwLock::new(TestForkGraph {})); - batch_processor.program_cache.write().unwrap().fork_graph = - Some(Arc::downgrade(&fork_graph)); + let batch_processor = + TransactionBatchProcessor::new(0, 0, Arc::downgrade(&fork_graph), None, None); let key = Pubkey::new_unique(); let name = "a_builtin_name"; diff --git a/svm/tests/concurrent_tests.rs b/svm/tests/concurrent_tests.rs index 4d0a500b845bc7..604cde243cbe44 100644 --- a/svm/tests/concurrent_tests.rs +++ b/svm/tests/concurrent_tests.rs @@ -40,9 +40,9 @@ mod transaction_builder; fn program_cache_execution(threads: usize) { let mut mock_bank = MockBankCallback::default(); - let batch_processor = TransactionBatchProcessor::::new_uninitialized(5, 5); let fork_graph = Arc::new(RwLock::new(MockForkGraph {})); - batch_processor.program_cache.write().unwrap().fork_graph = Some(Arc::downgrade(&fork_graph)); + let batch_processor = + TransactionBatchProcessor::new(5, 5, Arc::downgrade(&fork_graph), None, None); let programs = vec![ deploy_program("hello-solana".to_string(), 0, &mut mock_bank), diff --git a/svm/tests/conformance.rs b/svm/tests/conformance.rs index 3828c6cdfc71a9..4d7fe4bcf80642 100644 --- a/svm/tests/conformance.rs +++ b/svm/tests/conformance.rs @@ -11,11 +11,7 @@ use { solana_log_collector::LogCollector, solana_program_runtime::{ invoke_context::{EnvironmentConfig, InvokeContext}, - loaded_programs::{ProgramCacheEntry, ProgramCacheForTxBatch, ProgramRuntimeEnvironments}, - solana_rbpf::{ - program::{BuiltinProgram, FunctionRegistry}, - vm::Config, - }, + loaded_programs::{ProgramCacheEntry, ProgramCacheForTxBatch}, }, solana_sdk::{ account::{AccountSharedData, ReadableAccount, WritableAccount}, @@ -244,20 +240,15 @@ fn run_fixture(fixture: InstrFixture, filename: OsString, execute_as_instr: bool create_program_runtime_environment_v1(&feature_set, &compute_budget, false, false).unwrap(); mock_bank.override_feature_set(feature_set); - let batch_processor = TransactionBatchProcessor::::new_uninitialized(42, 2); let fork_graph = Arc::new(RwLock::new(MockForkGraph {})); - { - let mut program_cache = batch_processor.program_cache.write().unwrap(); - program_cache.environments = ProgramRuntimeEnvironments { - program_runtime_v1: Arc::new(v1_environment), - program_runtime_v2: Arc::new(BuiltinProgram::new_loader( - Config::default(), - FunctionRegistry::default(), - )), - }; - program_cache.fork_graph = Some(Arc::downgrade(&fork_graph.clone())); - } + let batch_processor = TransactionBatchProcessor::new( + 42, + 2, + Arc::downgrade(&fork_graph), + Some(Arc::new(v1_environment)), + None, + ); batch_processor.fill_missing_sysvar_cache_entries(&mock_bank); register_builtins(&batch_processor, &mock_bank); From 2baa79c77106339f8510e428762118bf58b2dd0d Mon Sep 17 00:00:00 2001 From: Joe Caulfield Date: Fri, 8 Nov 2024 10:50:23 +0400 Subject: [PATCH 2/2] SVM: add `configure_program_runtime_environments` method --- runtime/src/bank.rs | 33 ++++++++++---------- svm/src/transaction_processor.rs | 53 ++++++++++++++++++++++++-------- 2 files changed, 56 insertions(+), 30 deletions(-) diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index e1ec7c4a5f0c03..2556c8bd605831 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -5141,23 +5141,22 @@ impl Bank { } } - let mut program_cache = self.transaction_processor.program_cache.write().unwrap(); - program_cache.latest_root_slot = self.slot(); - program_cache.latest_root_epoch = self.epoch(); - program_cache.environments.program_runtime_v1 = Arc::new( - create_program_runtime_environment_v1( - &self.feature_set, - &self.compute_budget().unwrap_or_default(), - false, /* deployment */ - false, /* debugging_features */ - ) - .unwrap(), - ); - program_cache.environments.program_runtime_v2 = - Arc::new(create_program_runtime_environment_v2( - &self.compute_budget().unwrap_or_default(), - false, /* debugging_features */ - )); + self.transaction_processor + .configure_program_runtime_environments( + Some(Arc::new( + create_program_runtime_environment_v1( + &self.feature_set, + &self.compute_budget().unwrap_or_default(), + false, /* deployment */ + false, /* debugging_features */ + ) + .unwrap(), + )), + Some(Arc::new(create_program_runtime_environment_v2( + &self.compute_budget().unwrap_or_default(), + false, /* debugging_features */ + ))), + ); } pub fn set_inflation(&self, inflation: Inflation) { diff --git a/svm/src/transaction_processor.rs b/svm/src/transaction_processor.rs index c302ccebe700f4..da6edb824a2837 100644 --- a/svm/src/transaction_processor.rs +++ b/svm/src/transaction_processor.rs @@ -230,21 +230,13 @@ impl TransactionBatchProcessor { ) -> Self { let processor = Self::new_uninitialized(slot, epoch); { - let empty_loader = || { - Arc::new(BuiltinProgram::new_loader( - VmConfig::default(), - FunctionRegistry::default(), - )) - }; - let mut program_cache = processor.program_cache.write().unwrap(); program_cache.set_fork_graph(fork_graph); - program_cache.latest_root_slot = slot; - program_cache.latest_root_epoch = epoch; - program_cache.environments.program_runtime_v1 = - program_runtime_environment_v1.unwrap_or(empty_loader()); - program_cache.environments.program_runtime_v2 = - program_runtime_environment_v2.unwrap_or(empty_loader()); + processor.configure_program_runtime_environments_inner( + &mut program_cache, + program_runtime_environment_v1, + program_runtime_environment_v2, + ); } processor } @@ -265,6 +257,41 @@ impl TransactionBatchProcessor { } } + fn configure_program_runtime_environments_inner( + &self, + program_cache: &mut ProgramCache, + program_runtime_environment_v1: Option, + program_runtime_environment_v2: Option, + ) { + let empty_loader = || { + Arc::new(BuiltinProgram::new_loader( + VmConfig::default(), + FunctionRegistry::default(), + )) + }; + + program_cache.latest_root_slot = self.slot; + program_cache.latest_root_epoch = self.epoch; + program_cache.environments.program_runtime_v1 = + program_runtime_environment_v1.unwrap_or(empty_loader()); + program_cache.environments.program_runtime_v2 = + program_runtime_environment_v2.unwrap_or(empty_loader()); + } + + /// Configures the program runtime environments (loaders) in the + /// transaction processor's program cache. + pub fn configure_program_runtime_environments( + &self, + program_runtime_environment_v1: Option, + program_runtime_environment_v2: Option, + ) { + self.configure_program_runtime_environments_inner( + &mut self.program_cache.write().unwrap(), + program_runtime_environment_v1, + program_runtime_environment_v2, + ); + } + /// Returns the current environments depending on the given epoch /// Returns None if the call could result in a deadlock #[cfg(feature = "dev-context-only-utils")]