From edc5781f1407a0eee67004b4ecb1fa79ea22258e Mon Sep 17 00:00:00 2001 From: David Edey Date: Mon, 23 Sep 2024 11:46:50 +0100 Subject: [PATCH] refactor: Streamline engine init --- radix-common/src/state/state_updates.rs | 23 ++ radix-common/src/types/node_and_substate.rs | 10 + .../tests/kernel/kernel_open_substate.rs | 41 +- radix-engine-tests/tests/kernel/panics.rs | 33 +- radix-engine-tests/tests/vm/native_vm.rs | 30 +- radix-engine/src/init.rs | 3 + radix-engine/src/kernel/kernel.rs | 106 +++-- .../src/kernel/kernel_callback_api.rs | 25 +- radix-engine/src/lib.rs | 3 + radix-engine/src/system/bootstrap.rs | 2 +- radix-engine/src/system/system_callback.rs | 369 ++++++++++++------ .../src/system/system_callback_api.rs | 5 +- radix-engine/src/track/interface.rs | 14 - radix-engine/src/track/track.rs | 17 - .../src/transaction/transaction_executor.rs | 91 +---- radix-engine/src/updates/bottlenose.rs | 9 +- radix-engine/src/updates/cuttlefish.rs | 40 +- radix-engine/src/vm/versions.rs | 16 +- radix-engine/src/vm/vm.rs | 60 +-- .../src/interface.rs | 33 +- ...ttlefish-protocol-system-logic-updates.txt | 2 +- .../src/model/execution/executable_common.rs | 5 - .../src/model/v1/system_transaction.rs | 2 +- scrypto-test/src/environment/builder.rs | 17 +- .../ledger_simulator/inject_costing_err.rs | 217 +++++----- .../src/ledger_simulator/ledger_simulator.rs | 26 +- 26 files changed, 630 insertions(+), 569 deletions(-) create mode 100644 radix-engine/src/init.rs diff --git a/radix-common/src/state/state_updates.rs b/radix-common/src/state/state_updates.rs index 95ee6bfe560..ef26a9a84ac 100644 --- a/radix-common/src/state/state_updates.rs +++ b/radix-common/src/state/state_updates.rs @@ -16,6 +16,12 @@ pub struct StateUpdates { } impl StateUpdates { + pub fn empty() -> Self { + Self { + by_node: Default::default(), + } + } + /// Starts a Node-level update. pub fn of_node(&mut self, node_id: NodeId) -> &mut NodeStateUpdates { self.by_node @@ -25,6 +31,23 @@ impl StateUpdates { }) } + pub fn set_substate<'a>( + mut self, + node_id: impl Into, + partition_num: PartitionNumber, + substate_key: impl ResolvableSubstateKey<'a>, + new_value: impl ScryptoEncode, + ) -> Self { + let new_value = scrypto_encode(&new_value).expect("New substate value should be encodable"); + self.of_node(node_id.into()) + .of_partition(partition_num) + .update_substates([( + substate_key.into_substate_key(), + DatabaseUpdate::Set(new_value), + )]); + self + } + pub fn rebuild_without_empty_entries(&self) -> Self { Self { by_node: self diff --git a/radix-common/src/types/node_and_substate.rs b/radix-common/src/types/node_and_substate.rs index ca883099d3e..7e76a035cfe 100644 --- a/radix-common/src/types/node_and_substate.rs +++ b/radix-common/src/types/node_and_substate.rs @@ -307,6 +307,16 @@ impl<'a> SubstateKeyOrRef<'a> { pub trait ResolvableSubstateKey<'a>: Sized { fn into_substate_key_or_ref(self) -> SubstateKeyOrRef<'a>; + fn into_substate_key(self) -> SubstateKey { + match self.into_substate_key_or_ref() { + SubstateKeyOrRef::Owned(key) => key, + SubstateKeyOrRef::Borrowed(SubstateKeyRef::Field(key)) => SubstateKey::Field(*key), + SubstateKeyOrRef::Borrowed(SubstateKeyRef::Map(key)) => SubstateKey::Map(key.clone()), + SubstateKeyOrRef::Borrowed(SubstateKeyRef::Sorted(key)) => { + SubstateKey::Sorted(key.clone()) + } + } + } } impl<'a> ResolvableSubstateKey<'a> for &'a SubstateKey { diff --git a/radix-engine-tests/tests/kernel/kernel_open_substate.rs b/radix-engine-tests/tests/kernel/kernel_open_substate.rs index cb1ed8f0c33..d2b6b7d83e9 100644 --- a/radix-engine-tests/tests/kernel/kernel_open_substate.rs +++ b/radix-engine-tests/tests/kernel/kernel_open_substate.rs @@ -1,31 +1,7 @@ -use radix_common::prelude::*; -use radix_engine::errors::{CallFrameError, KernelError, RuntimeError}; -use radix_engine::kernel::call_frame::OpenSubstateError; -use radix_engine::kernel::id_allocator::IdAllocator; -use radix_engine::kernel::kernel::Kernel; -use radix_engine::kernel::kernel_api::KernelSubstateApi; -use radix_engine::system::system_callback::{System, SystemLockData, VersionedSystemLogic}; -use radix_engine::system::system_modules::auth::AuthModule; -use radix_engine::system::system_modules::costing::{ - CostingModule, CostingModuleConfig, FeeTable, SystemLoanFeeReserve, -}; -use radix_engine::system::system_modules::execution_trace::ExecutionTraceModule; use radix_engine::system::system_modules::kernel_trace::KernelTraceModule; use radix_engine::system::system_modules::limits::LimitsModule; use radix_engine::system::system_modules::transaction_runtime::TransactionRuntimeModule; -use radix_engine::system::system_modules::{EnabledModules, SystemModuleMixer}; -use radix_engine::track::Track; -use radix_engine::updates::ProtocolBuilder; -use radix_engine::vm::wasm::DefaultWasmEngine; -use radix_engine::vm::*; -use radix_engine_interface::api::LockFlags; -use radix_engine_interface::prelude::*; -use radix_substate_store_impls::memory_db::InMemorySubstateDatabase; -use radix_substate_store_queries::typed_substate_layout::{ - BlueprintVersionKey, PACKAGE_AUTH_TEMPLATE_PARTITION_OFFSET, -}; -use radix_transactions::prelude::*; -use scrypto_test::prelude::UniqueTransaction; +use scrypto_test::prelude::*; #[test] pub fn test_open_substate_of_invisible_package_address() { @@ -46,17 +22,14 @@ pub fn test_open_substate_of_invisible_package_address() { .commit_each_protocol_update(&mut database); // Create kernel - let mut system = System { - versioned_system_logic: VersionedSystemLogic::V1, - blueprint_cache: NonIterMap::new(), - auth_cache: NonIterMap::new(), - schema_cache: NonIterMap::new(), - callback: Vm { + let mut system = System::new( + SystemVersion::latest(), + Vm { scrypto_vm: &scrypto_vm, native_vm, vm_boot: VmBoot::latest(), }, - modules: SystemModuleMixer::new( + SystemModuleMixer::new( EnabledModules::for_test_transaction(), KernelTraceModule, TransactionRuntimeModule::new( @@ -78,8 +51,8 @@ pub fn test_open_substate_of_invisible_package_address() { }, ExecutionTraceModule::new(MAX_EXECUTION_TRACE_DEPTH), ), - finalization: Default::default(), - }; + SystemFinalization::no_nullifications(), + ); let mut track = Track::new(&database); let mut id_allocator = IdAllocator::new(executable.unique_seed_for_id_allocator()); let mut kernel = Kernel::new_no_refs(&mut track, &mut id_allocator, &mut system); diff --git a/radix-engine-tests/tests/kernel/panics.rs b/radix-engine-tests/tests/kernel/panics.rs index 2e69c96a8a6..ae04403ae48 100644 --- a/radix-engine-tests/tests/kernel/panics.rs +++ b/radix-engine-tests/tests/kernel/panics.rs @@ -2,7 +2,6 @@ use radix_common::prelude::*; use radix_engine::errors::*; use radix_engine::kernel::call_frame::*; use radix_engine::kernel::kernel_api::*; -use radix_engine::system::actor::*; #[cfg(not(feature = "alloc"))] use radix_engine::system::system::SystemService; use radix_engine::system::system_callback::*; @@ -11,13 +10,13 @@ use radix_engine::vm::wasm::*; use radix_engine::vm::*; use radix_engine_interface::prelude::*; use radix_substate_store_interface::db_key_mapper::*; -use scrypto_test::prelude::SystemCallbackObject; +use scrypto_test::prelude::*; #[cfg(feature = "std")] #[test] fn panics_at_the_system_layer_or_below_can_be_caught() { // Arrange - let mut kernel = MockKernel(PhantomData::>); + let mut kernel = MockKernel(PhantomData::>>); let mut system_service = SystemService::new(&mut kernel); // Act @@ -36,14 +35,14 @@ macro_rules! panic1 { }; } -pub struct MockKernel(PhantomData); +pub struct MockKernel(PhantomData); -impl KernelApi for MockKernel { - type CallbackObject = System; +impl KernelApi for MockKernel { + type CallbackObject = E; } -impl KernelStackApi for MockKernel { - type CallFrameData = Actor; +impl KernelStackApi for MockKernel { + type CallFrameData = E::CallFrameData; fn kernel_get_stack_id(&self) -> usize { panic1!() @@ -53,7 +52,7 @@ impl KernelStackApi for MockKernel { panic1!() } - fn kernel_set_call_frame_data(&mut self, _data: Actor) -> Result<(), RuntimeError> { + fn kernel_set_call_frame_data(&mut self, _data: E::CallFrameData) -> Result<(), RuntimeError> { panic1!() } @@ -62,7 +61,7 @@ impl KernelStackApi for MockKernel { } } -impl KernelNodeApi for MockKernel { +impl KernelNodeApi for MockKernel { fn kernel_pin_node(&mut self, _: NodeId) -> Result<(), RuntimeError> { panic1!() } @@ -88,7 +87,7 @@ impl KernelNodeApi for MockKernel { } } -impl KernelSubstateApi for MockKernel { +impl KernelSubstateApi for MockKernel { fn kernel_mark_substate_as_transient( &mut self, _: NodeId, @@ -105,12 +104,12 @@ impl KernelSubstateApi for MockKernel, - _: SystemLockData, + _: E::LockData, ) -> Result { panic1!() } - fn kernel_get_lock_data(&mut self, _: SubstateHandle) -> Result { + fn kernel_get_lock_data(&mut self, _: SubstateHandle) -> Result { panic1!() } @@ -180,17 +179,17 @@ impl KernelSubstateApi for MockKernel KernelInvokeApi for MockKernel { +impl KernelInvokeApi for MockKernel { fn kernel_invoke( &mut self, - _: Box>, + _: Box>, ) -> Result { panic1!() } } -impl KernelInternalApi for MockKernel { - type System = System; +impl KernelInternalApi for MockKernel { + type System = E; fn kernel_get_system_state(&mut self) -> SystemState<'_, Self::System> { panic1!() diff --git a/radix-engine-tests/tests/vm/native_vm.rs b/radix-engine-tests/tests/vm/native_vm.rs index 030b5ab52db..aa283350ba3 100644 --- a/radix-engine-tests/tests/vm/native_vm.rs +++ b/radix-engine-tests/tests/vm/native_vm.rs @@ -65,17 +65,14 @@ fn panics_can_be_caught_in_the_native_vm_and_converted_into_results() { let native_vm = NativeVm::new_with_extension(Extension); let intent_hash = Hash([0; 32]); - let mut system = System { - versioned_system_logic: VersionedSystemLogic::V1, - blueprint_cache: NonIterMap::new(), - auth_cache: NonIterMap::new(), - schema_cache: NonIterMap::new(), - callback: Vm { + let mut system = System::new( + SystemVersion::latest(), + Vm { scrypto_vm: &scrypto_vm, native_vm, vm_boot: VmBoot::latest(), }, - modules: SystemModuleMixer::new( + SystemModuleMixer::new( EnabledModules::for_notarized_transaction(), KernelTraceModule, TransactionRuntimeModule::new(NetworkDefinition::simulator(), intent_hash), @@ -94,8 +91,8 @@ fn panics_can_be_caught_in_the_native_vm_and_converted_into_results() { }, ExecutionTraceModule::new(MAX_EXECUTION_TRACE_DEPTH), ), - finalization: Default::default(), - }; + SystemFinalization::no_nullifications(), + ); let mut id_allocator = IdAllocator::new(intent_hash); let mut kernel = Kernel::new_no_refs(&mut track, &mut id_allocator, &mut system); @@ -136,17 +133,14 @@ fn any_panics_can_be_caught_in_the_native_vm_and_converted_into_results() { let native_vm = NativeVm::new_with_extension(NonStringPanicExtension); let intent_hash = Hash([0; 32]); - let mut system = System { - versioned_system_logic: VersionedSystemLogic::V1, - blueprint_cache: NonIterMap::new(), - auth_cache: NonIterMap::new(), - schema_cache: NonIterMap::new(), - callback: Vm { + let mut system = System::new( + SystemVersion::latest(), + Vm { scrypto_vm: &scrypto_vm, native_vm, vm_boot: VmBoot::latest(), }, - modules: SystemModuleMixer::new( + SystemModuleMixer::new( EnabledModules::for_notarized_transaction(), KernelTraceModule, TransactionRuntimeModule::new(NetworkDefinition::simulator(), intent_hash), @@ -165,8 +159,8 @@ fn any_panics_can_be_caught_in_the_native_vm_and_converted_into_results() { }, ExecutionTraceModule::new(MAX_EXECUTION_TRACE_DEPTH), ), - finalization: Default::default(), - }; + SystemFinalization::no_nullifications(), + ); let mut id_allocator = IdAllocator::new(intent_hash); let mut kernel = Kernel::new_no_refs(&mut track, &mut id_allocator, &mut system); diff --git a/radix-engine/src/init.rs b/radix-engine/src/init.rs new file mode 100644 index 00000000000..32b3f61ea02 --- /dev/null +++ b/radix-engine/src/init.rs @@ -0,0 +1,3 @@ +pub trait InitializationParameters { + type For; +} diff --git a/radix-engine/src/kernel/kernel.rs b/radix-engine/src/kernel/kernel.rs index e58ebbc2718..cfde5968bae 100644 --- a/radix-engine/src/kernel/kernel.rs +++ b/radix-engine/src/kernel/kernel.rs @@ -37,63 +37,98 @@ pub enum KernelBoot { } impl KernelBoot { + /// Loads kernel boot from the database, or resolves a fallback. + pub fn load(substate_db: &impl SubstateDatabase) -> Self { + substate_db + .get_substate( + TRANSACTION_TRACKER, + BOOT_LOADER_PARTITION, + BOOT_LOADER_KERNEL_BOOT_FIELD_KEY, + ) + .unwrap_or_else(|| KernelBoot::babylon()) + } + pub fn babylon() -> Self { Self::V1 } } -/// Organizes the radix engine stack to make a function entrypoint available for execution -pub struct BootLoader<'h, M: KernelTransactionCallbackObject, S: SubstateDatabase> { - pub id_allocator: IdAllocator, - pub track: Track<'h, S>, - pub init: M::Init, - pub phantom: PhantomData, +pub struct KernelInit< + 's, + S: SubstateDatabase, + I: InitializationParameters>, +> { + substate_db: &'s S, + kernel_boot: KernelBoot, + callback_init: I, } -impl<'h, M: KernelTransactionCallbackObject, S: SubstateDatabase> BootLoader<'h, M, S> { +impl< + 's, + S: SubstateDatabase, + I: InitializationParameters>, + > KernelInit<'s, S, I> +{ + pub fn load(substate_db: &'s S, callback_init: I) -> Self { + let kernel_boot = KernelBoot::load(substate_db); + Self { + substate_db, + kernel_boot, + callback_init, + } + } + /// Executes a transaction - pub fn execute(self, executable: M::Executable) -> M::Receipt { - // Start hardware resource usage tracker - #[cfg(all(target_os = "linux", feature = "std", feature = "cpu_ram_metrics"))] - let mut resources_tracker = - crate::kernel::resources_tracker::ResourcesTracker::start_measurement(); + pub fn execute( + self, + executable: ::Executable, + ) -> ::Receipt { + let boot_loader = BootLoader { + id_allocator: IdAllocator::new(executable.unique_seed_for_id_allocator()), + track: Track::new(self.substate_db), + }; #[cfg(not(all(target_os = "linux", feature = "std", feature = "cpu_ram_metrics")))] { - self.execute_internal(executable) + boot_loader.execute::(self.kernel_boot, self.callback_init, executable) } #[cfg(all(target_os = "linux", feature = "std", feature = "cpu_ram_metrics"))] { - let mut receipt = self.execute_internal(executable); + use crate::kernel::resources_tracker::ResourcesTracker; - // Stop hardware resource usage tracker + let mut resources_tracker = ResourcesTracker::start_measurement(); + let mut receipt = + boot_loader.execute::(self.kernel_boot, self.callback_init, executable); receipt.set_resource_usage(resources_tracker.end_measurement()); - receipt } } +} - fn execute_internal(mut self, executable: M::Executable) -> M::Receipt { +/// Organizes the radix engine stack to make a function entrypoint available for execution +pub struct BootLoader<'h, S: SubstateDatabase> { + id_allocator: IdAllocator, + track: Track<'h, S>, +} + +impl<'h, S: SubstateDatabase> BootLoader<'h, S> { + fn execute( + mut self, + kernel_boot: KernelBoot, + callback_init: E::Init, + executable: E::Executable, + ) -> E::Receipt { #[cfg(feature = "resource_tracker")] radix_engine_profiling::QEMU_PLUGIN_CALIBRATOR.with(|v| { v.borrow_mut(); }); - // Read kernel boot configuration // Unused for now - let _kernel_boot: KernelBoot = self - .track - .read_boot_substate( - TRANSACTION_TRACKER.as_node_id(), - BOOT_LOADER_PARTITION, - &SubstateKey::Field(BOOT_LOADER_KERNEL_BOOT_FIELD_KEY), - ) - .map(|v| scrypto_decode(v.as_slice()).unwrap()) - .unwrap_or(KernelBoot::babylon()); + let _ = kernel_boot; // Upper Layer Initialization - let system_init_result = M::init(&mut self.track, &executable, self.init); + let system_init_result = E::init(&mut self.track, &executable, callback_init); let (mut system, call_frame_inits) = match system_init_result { Ok(success) => success, @@ -109,9 +144,9 @@ impl<'h, M: KernelTransactionCallbackObject, S: SubstateDatabase> BootLoader<'h, ); // Execution - let result = || -> Result { + let result = || -> Result { // Invoke transaction processor - let output = M::start(&mut kernel, executable)?; + let output = E::execute(&mut kernel, executable)?; // Sanity check call frame for stack in &kernel.stacks.stacks { @@ -123,7 +158,7 @@ impl<'h, M: KernelTransactionCallbackObject, S: SubstateDatabase> BootLoader<'h, // Finalize state updates based on what has occurred let commit_info = kernel.substate_io.store.get_commit_info(); - kernel.callback.finish(commit_info)?; + kernel.callback.finalize(commit_info)?; Ok(output) }() @@ -272,11 +307,8 @@ pub struct Kernel< callback: &'g mut M, } -impl< - 'g, - M: KernelCallbackObject, - S: CommitableSubstateStore + BootStore, - > Kernel<'g, M, S> +impl<'g, M: KernelCallbackObject, S: CommitableSubstateStore> + Kernel<'g, M, S> { pub fn new_no_refs( store: &'g mut S, @@ -296,7 +328,7 @@ impl< } } -impl<'g, M: KernelCallbackObject, S: CommitableSubstateStore + BootStore> Kernel<'g, M, S> { +impl<'g, M: KernelCallbackObject, S: CommitableSubstateStore> Kernel<'g, M, S> { pub fn new( store: &'g mut S, id_allocator: &'g mut IdAllocator, diff --git a/radix-engine/src/kernel/kernel_callback_api.rs b/radix-engine/src/kernel/kernel_callback_api.rs index 3b59a586b66..8bbfa0055b8 100644 --- a/radix-engine/src/kernel/kernel_callback_api.rs +++ b/radix-engine/src/kernel/kernel_callback_api.rs @@ -9,6 +9,7 @@ use crate::track::*; use crate::transaction::ResourcesUsage; use radix_engine_interface::api::field_api::LockFlags; use radix_substate_store_interface::interface::SubstateDatabase; +use radix_transactions::model::ExecutableTransaction; pub trait CallFrameReferences { fn global_references(&self) -> Vec; @@ -137,31 +138,43 @@ pub trait ExecutionReceipt { fn set_resource_usage(&mut self, resources_usage: ResourcesUsage); } -pub trait KernelTransactionCallbackObject: KernelCallbackObject { +/// A transaction which has a unique id, useful for creating an IdAllocator which +/// requires a unique input +pub trait UniqueSeed { + fn unique_seed_for_id_allocator(&self) -> Hash; +} + +impl UniqueSeed for ExecutableTransaction { + fn unique_seed_for_id_allocator(&self) -> Hash { + *self.unique_hash() + } +} + +pub trait KernelTransactionExecutor: KernelCallbackObject { /// Initialization object type Init; /// The transaction object - type Executable; + type Executable: UniqueSeed; /// Output to be returned at the end of execution type ExecutionOutput; /// Final receipt to be created after transaction execution type Receipt: ExecutionReceipt; /// Create the callback object (system layer) and the initial call frame configuration for each intent - fn init( - store: &mut S, + fn init( + store: &mut impl CommitableSubstateStore, executable: &Self::Executable, init: Self::Init, ) -> Result<(Self, Vec>), Self::Receipt>; /// Start execution - fn start>( + fn execute>( api: &mut Y, executable: Self::Executable, ) -> Result; /// Finish execution - fn finish(&mut self, store_commit_info: StoreCommitInfo) -> Result<(), RuntimeError>; + fn finalize(&mut self, store_commit_info: StoreCommitInfo) -> Result<(), RuntimeError>; /// Create final receipt fn create_receipt( diff --git a/radix-engine/src/lib.rs b/radix-engine/src/lib.rs index 2aa98746f11..c8ac4128438 100644 --- a/radix-engine/src/lib.rs +++ b/radix-engine/src/lib.rs @@ -35,9 +35,12 @@ pub mod vm; /// Protocol updates pub mod updates; +pub mod init; + pub(crate) mod internal_prelude { pub use crate::blueprints::internal_prelude::*; pub use crate::errors::*; + pub use crate::init::*; pub use crate::system::system_substates::*; pub use crate::{ dispatch, event_schema, function_schema, method_auth_template, roles_template, diff --git a/radix-engine/src/system/bootstrap.rs b/radix-engine/src/system/bootstrap.rs index 166cdd34870..827d6f154b9 100644 --- a/radix-engine/src/system/bootstrap.rs +++ b/radix-engine/src/system/bootstrap.rs @@ -338,7 +338,7 @@ pub fn create_system_bootstrap_flash( native_code_id.to_be_bytes().to_vec(), system_instructions, false, - &VmBoot::babylon(), + &VmBoot::babylon_genesis(), ) .unwrap_or_else(|err| { panic!( diff --git a/radix-engine/src/system/system_callback.rs b/radix-engine/src/system/system_callback.rs index 49aaf187eae..3db678a02a8 100644 --- a/radix-engine/src/system/system_callback.rs +++ b/radix-engine/src/system/system_callback.rs @@ -57,46 +57,115 @@ pub struct SystemParameters { pub limit_parameters: LimitParameters, } +impl SystemParameters { + pub fn latest(network_definition: NetworkDefinition) -> Self { + Self::bottlenose(network_definition) + } + + pub fn bottlenose(network_definition: NetworkDefinition) -> Self { + Self { + network_definition, + costing_module_config: CostingModuleConfig::bottlenose(), + costing_parameters: CostingParameters::babylon_genesis(), + limit_parameters: LimitParameters::babylon_genesis(), + } + } + + pub fn babylon_genesis(network_definition: NetworkDefinition) -> Self { + Self { + network_definition, + costing_module_config: CostingModuleConfig::babylon_genesis(), + costing_parameters: CostingParameters::babylon_genesis(), + limit_parameters: LimitParameters::babylon_genesis(), + } + } +} + pub type SystemBootSubstate = SystemBoot; #[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)] pub enum SystemBoot { V1(SystemParameters), - V2(VersionedSystemLogic, SystemParameters), + V2(SystemVersion, SystemParameters), } impl SystemBoot { + /// Loads system boot from the database, or resolves a fallback.. + /// + /// # Panics + /// This method panics if the database is pre-bottlenose and the execution config + /// does not specify a network definition. + pub fn load(substate_db: &impl SubstateDatabase, execution_config: &ExecutionConfig) -> Self { + substate_db + .get_substate( + TRANSACTION_TRACKER, + BOOT_LOADER_PARTITION, + BOOT_LOADER_SYSTEM_SUBSTATE_FIELD_KEY, + ) + .unwrap_or_else(|| { + let overrides = execution_config.system_overrides.as_ref(); + let network_definition = overrides.and_then(|o| o.network_definition.as_ref()) + .expect("Before bottlenose, no SystemBoot substate exists, so a network_definition must be provided in the SystemOverrides of the ExecutionConfig."); + SystemBoot::babylon_genesis(network_definition.clone()) + }) + } + + pub fn latest(network_definition: NetworkDefinition) -> Self { + Self::cuttlefish(network_definition) + } + + pub fn cuttlefish(network_definition: NetworkDefinition) -> Self { + SystemBoot::V2( + SystemVersion::V2, + SystemParameters::bottlenose(network_definition), + ) + } + + pub fn cuttlefish_for_previous_parameters(parameters: SystemParameters) -> Self { + SystemBoot::V2(SystemVersion::V2, parameters) + } + + pub fn bottlenose(network_definition: NetworkDefinition) -> Self { + SystemBoot::V1(SystemParameters::bottlenose(network_definition)) + } + pub fn babylon_genesis(network_definition: NetworkDefinition) -> Self { - SystemBoot::V1(SystemParameters { - network_definition, - costing_parameters: CostingParameters::babylon_genesis(), - costing_module_config: CostingModuleConfig::babylon_genesis(), - limit_parameters: LimitParameters::babylon_genesis(), - }) + SystemBoot::V1(SystemParameters::babylon_genesis(network_definition)) } - fn system_logic_version(&self) -> VersionedSystemLogic { + pub fn system_version(&self) -> SystemVersion { match self { - Self::V1(..) => VersionedSystemLogic::V1, - Self::V2(logic, _) => *logic, + Self::V1(..) => SystemVersion::V1, + Self::V2(version, _) => *version, + } + } + + pub fn into_parameters(self) -> SystemParameters { + match self { + Self::V1(parameters) => parameters, + Self::V2(_, parameters) => parameters, } } } /// System logic which may change given a protocol version #[derive(Debug, Copy, Clone, PartialEq, Eq, ScryptoSbor)] -pub enum VersionedSystemLogic { +pub enum SystemVersion { V1, V2, } -impl VersionedSystemLogic { +impl SystemVersion { + pub const fn latest() -> Self { + Self::V2 + } + fn create_auth_module( &self, executable: &ExecutableTransaction, ) -> Result { let auth_module = match self { - VersionedSystemLogic::V1 => { + SystemVersion::V1 => { // This isn't exactly a necessary check as node logic should protect against this // but keep it here for sanity let intent = if executable.intents().len() != 1 { @@ -106,7 +175,7 @@ impl VersionedSystemLogic { }; AuthModule::new_with_transaction_processor_auth_zone(intent.auth_zone_init.clone()) } - VersionedSystemLogic::V2 => AuthModule::new(), + SystemVersion::V2 => AuthModule::new(), }; Ok(auth_module) @@ -119,7 +188,7 @@ impl VersionedSystemLogic { global_address_reservations: Vec, ) -> Result, RuntimeError> { let output = match self { - VersionedSystemLogic::V1 => { + SystemVersion::V1 => { let mut system_service = SystemService::new(api); let intent = executable .intents() @@ -140,7 +209,7 @@ impl VersionedSystemLogic { let output: Vec = scrypto_decode(&rtn).unwrap(); output } - VersionedSystemLogic::V2 => { + SystemVersion::V2 => { let mut txn_threads = MultiThreadedTxnProcessor::init(executable, global_address_reservations, api)?; txn_threads.execute(api)?; @@ -162,13 +231,13 @@ impl VersionedSystemLogic { pub fn should_consume_cost_units(&self, api: &mut Y) -> bool { match self { - VersionedSystemLogic::V1 => { + SystemVersion::V1 => { // Skip client-side costing requested by TransactionProcessor if api.kernel_get_current_depth() == 1 { return false; } } - VersionedSystemLogic::V2 => {} + SystemVersion::V2 => {} } true @@ -253,9 +322,36 @@ impl>> SystemBa type SystemCallback = V; } -pub struct SystemInit { +pub struct SystemInit>> { pub self_init: SystemSelfInit, - pub callback_init: V, + pub callback_init: I, +} + +impl>> SystemInit { + /// This is expected to follow up with a match statement and a call to `v1` / `v2` + /// etc, to select the correct concrete generic. + pub fn load( + substate_db: &impl SubstateDatabase, + execution_config: ExecutionConfig, + callback_init: I, + ) -> Self { + let system_boot = SystemBoot::load(substate_db, &execution_config); + let self_init = SystemSelfInit::new( + execution_config, + system_boot.system_version(), + system_boot.into_parameters(), + ); + Self { + self_init, + callback_init, + } + } +} + +impl>> InitializationParameters + for SystemInit +{ + type For = System; } pub struct SystemSelfInit { @@ -265,12 +361,32 @@ pub struct SystemSelfInit { pub execution_trace: Option, pub enable_debug_information: bool, - // An override of system configuration + // Configuration + pub system_parameters: SystemParameters, + pub system_logic_version: SystemVersion, pub system_overrides: Option, } +impl SystemSelfInit { + pub fn new( + execution_config: ExecutionConfig, + system_logic_version: SystemVersion, + system_parameters: SystemParameters, + ) -> Self { + Self { + enable_kernel_trace: execution_config.enable_kernel_trace, + enable_cost_breakdown: execution_config.enable_cost_breakdown, + enable_debug_information: execution_config.enable_debug_information, + execution_trace: execution_config.execution_trace, + system_overrides: execution_config.system_overrides, + system_logic_version, + system_parameters, + } + } +} + pub struct System { - pub versioned_system_logic: VersionedSystemLogic, + pub versioned_system_logic: SystemVersion, pub callback: V, pub blueprint_cache: NonIterMap>, pub schema_cache: NonIterMap>, @@ -290,12 +406,36 @@ impl HasModules for System { } } -#[derive(Default)] pub struct SystemFinalization { - intent_nullifications: Vec, + pub intent_nullifications: Vec, +} + +impl SystemFinalization { + pub fn no_nullifications() -> Self { + Self { + intent_nullifications: vec![], + } + } } impl System { + pub fn new( + versioned_system_logic: SystemVersion, + callback: V, + modules: SystemModuleMixer, + finalization: SystemFinalization, + ) -> Self { + Self { + callback, + blueprint_cache: NonIterMap::new(), + auth_cache: NonIterMap::new(), + schema_cache: NonIterMap::new(), + modules, + finalization, + versioned_system_logic, + } + } + fn on_move_node( node_id: &NodeId, is_moving_down: bool, @@ -746,14 +886,14 @@ impl System { fn update_transaction_tracker( track: &mut Track, next_epoch: Epoch, - intent_hash_nullification: IntentHashNullification, + intent_hash_nullifications: Vec, is_success: bool, ) { // NOTE: In the case of system transactions, we could skip most of this... // except for backwards compatibility, we can't! // Read the intent hash store - let transaction_tracker = track + let mut transaction_tracker = track .read_substate( TRANSACTION_TRACKER.as_node_id(), MAIN_BASE_PARTITION, @@ -762,59 +902,53 @@ impl System { .unwrap() .as_typed::>() .unwrap() - .into_payload(); - - let mut transaction_tracker = transaction_tracker.into_v1(); - - let mark_intent_result = match intent_hash_nullification { - IntentHashNullification::TransactionIntent { - intent_hash, - expiry_epoch, - .. - } => Some((intent_hash.into_hash(), expiry_epoch)), - IntentHashNullification::Subintent { - intent_hash, - expiry_epoch, - .. - } => { - // Only write subintent nullification on success. - // Subintents can't pay fees, so this isn't a problem. - if is_success { - Some((intent_hash.into_hash(), expiry_epoch)) - } else { - None + .into_payload() + .into_v1(); + + for intent_hash_nullification in intent_hash_nullifications { + let (intent_hash, expiry_epoch) = match intent_hash_nullification { + IntentHashNullification::TransactionIntent { + intent_hash, + expiry_epoch, + .. + } => (intent_hash.into_hash(), expiry_epoch), + IntentHashNullification::Subintent { + intent_hash, + expiry_epoch, + .. + } => { + // Don't write subintent nullification on failure. + // Subintents can't pay fees, so this isn't abusable. + if !is_success { + continue; + } + (intent_hash.into_hash(), expiry_epoch) } - } - IntentHashNullification::System => None, - }; + }; + + let partition_number = transaction_tracker.partition_for_expiry_epoch(expiry_epoch) + .expect("Validation of the max expiry epoch window should ensure that the expiry epoch is in range for the transaction tracker"); - if let Some((intent_hash, expiry_epoch)) = mark_intent_result { // Update the status of the intent hash - if let Some(partition_number) = - transaction_tracker.partition_for_expiry_epoch(expiry_epoch) - { - track - .set_substate( - TRANSACTION_TRACKER.into_node_id(), - PartitionNumber(partition_number), - SubstateKey::Map(scrypto_encode(&intent_hash).unwrap()), - IndexedScryptoValue::from_typed(&KeyValueEntrySubstate::V1( - KeyValueEntrySubstateV1 { - value: Some(if is_success { - TransactionStatus::V1(TransactionStatusV1::CommittedSuccess) - } else { - TransactionStatus::V1(TransactionStatusV1::CommittedFailure) - }), - // TODO: maybe make it immutable, but how does this affect partition deletion? - lock_status: LockStatus::Unlocked, - }, - )), - &mut |_| -> Result<(), ()> { Ok(()) }, - ) - .unwrap(); - } else { - panic!("No partition for an expiry epoch") - } + track + .set_substate( + TRANSACTION_TRACKER.into_node_id(), + PartitionNumber(partition_number), + SubstateKey::Map(scrypto_encode(&intent_hash).unwrap()), + IndexedScryptoValue::from_typed(&KeyValueEntrySubstate::V1( + KeyValueEntrySubstateV1 { + value: Some(if is_success { + TransactionStatus::V1(TransactionStatusV1::CommittedSuccess) + } else { + TransactionStatus::V1(TransactionStatusV1::CommittedFailure) + }), + // TODO: maybe make it immutable, but how does this affect partition deletion? + lock_status: LockStatus::Unlocked, + }, + )), + &mut |_| -> Result<(), ()> { Ok(()) }, + ) + .unwrap(); } // Check if all intent hashes in the first epoch have expired, based on the `next_epoch`. @@ -939,7 +1073,7 @@ impl System { fn reference_check( references: &IndexSet, modules: &mut SystemModuleMixer, - store: &mut (impl BootStore + CommitableSubstateStore), + store: &mut impl CommitableSubstateStore, ) -> Result<(IndexSet, IndexSet), BootloadingError> { let mut global_addresses = indexset!(); let mut direct_accesses = indexset!(); @@ -984,7 +1118,7 @@ impl System { fn build_call_frame_inits_with_reference_check( intents: &Vec, modules: &mut SystemModuleMixer, - store: &mut (impl BootStore + CommitableSubstateStore), + store: &mut impl CommitableSubstateStore, ) -> Result>, BootloadingError> { let mut init_call_frames = vec![]; for intent in intents { @@ -1134,14 +1268,12 @@ impl System { // Update intent hash status if let Some(next_epoch) = Self::read_epoch_uncosted(&mut track) { - for intent_nullification in system_finalization.intent_nullifications { - Self::update_transaction_tracker( - &mut track, - next_epoch, - intent_nullification, - is_success, - ); - } + Self::update_transaction_tracker( + &mut track, + next_epoch, + system_finalization.intent_nullifications, + is_success, + ); } // Finalize events and logs @@ -1253,30 +1385,11 @@ impl System { } fn resolve_modules( - store: &mut impl BootStore, executable: &ExecutableTransaction, init_input: SystemSelfInit, - ) -> Result<(VersionedSystemLogic, SystemModuleMixer), TransactionReceipt> { - let system_boot = store - .read_boot_substate( - TRANSACTION_TRACKER.as_node_id(), - BOOT_LOADER_PARTITION, - &SubstateKey::Field(BOOT_LOADER_SYSTEM_SUBSTATE_FIELD_KEY), - ) - .map(|v| scrypto_decode(v.as_slice()).unwrap()) - .unwrap_or_else(|| { - let overrides = init_input.system_overrides.as_ref(); - let network_definition = overrides.and_then(|o| o.network_definition.as_ref()) - .expect("Before bottlenose, no SystemBoot substate exists, so a network_definition must be provided in the SystemOverrides of the ExecutionConfig."); - SystemBoot::babylon_genesis(network_definition.clone()) - }); - - let system_logic_version = system_boot.system_logic_version(); - let mut system_parameters = match system_boot { - SystemBoot::V1(system_parameters) | SystemBoot::V2(_, system_parameters) => { - system_parameters - } - }; + ) -> Result { + let mut system_parameters = init_input.system_parameters; + let system_logic_version = init_input.system_logic_version; let mut enabled_modules = { let mut enabled_modules = EnabledModules::AUTH | EnabledModules::TRANSACTION_RUNTIME; @@ -1369,20 +1482,21 @@ impl System { costing_module, ExecutionTraceModule::new(init_input.execution_trace.unwrap_or(0)), ); - Ok((system_logic_version, module_mixer)) + + Ok(module_mixer) } } -impl KernelTransactionCallbackObject for System { +impl KernelTransactionExecutor for System { type Init = SystemInit; type Executable = ExecutableTransaction; type ExecutionOutput = Vec; type Receipt = TransactionReceipt; - fn init( - store: &mut S, + fn init( + store: &mut impl CommitableSubstateStore, executable: &ExecutableTransaction, - init_input: SystemInit, + init_input: Self::Init, ) -> Result<(Self, Vec>), Self::Receipt> { // Dump executable #[cfg(not(feature = "alloc"))] @@ -1390,11 +1504,11 @@ impl KernelTransactionCallbackObject for System { Self::print_executable(executable); } - let (logic_version, mut modules) = - Self::resolve_modules(store, executable, init_input.self_init)?; + let logic_version = init_input.self_init.system_logic_version; + let mut modules = Self::resolve_modules(executable, init_input.self_init)?; // NOTE: Have to use match pattern rather than map_err to appease the borrow checker - let callback = match V::init(store, init_input.callback_init) { + let callback = match V::init(init_input.callback_init) { Ok(callback) => callback, Err(error) => return Err(Self::create_rejection_receipt(error, modules)), }; @@ -1405,10 +1519,9 @@ impl KernelTransactionCallbackObject for System { } // Perform runtime validation. - // TODO: the following assumptions can be removed with better interface. - // We are assuming that intent hash store is ready when epoch manager is ready. - let current_epoch = Self::read_epoch_uncosted(store); - if let Some(current_epoch) = current_epoch { + // NOTE: The epoch doesn't exist yet on the very first transaction, so we skip this + if let Some(current_epoch) = Self::read_epoch_uncosted(store) { + // We are assuming that intent hash store is ready when epoch manager is ready. if let Some(range) = executable.overall_epoch_range() { let epoch_validation_result = Self::validate_epoch_range( current_epoch, @@ -1454,7 +1567,6 @@ impl KernelTransactionCallbackObject for System { ) } } - IntentHashNullification::System => Ok(()), }; match intent_hash_validation_result { Ok(()) => {} @@ -1471,26 +1583,23 @@ impl KernelTransactionCallbackObject for System { Err(error) => return Err(Self::create_rejection_receipt(error, modules)), }; - let system = System { - versioned_system_logic: logic_version, - blueprint_cache: NonIterMap::new(), - auth_cache: NonIterMap::new(), - schema_cache: NonIterMap::new(), + let system = System::new( + logic_version, callback, modules, - finalization: SystemFinalization { + SystemFinalization { intent_nullifications: executable .intent_hash_nullifications() .iter() .cloned() .collect(), }, - }; + ); Ok((system, call_frame_inits)) } - fn start( + fn execute( api: &mut Y, executable: ExecutableTransaction, ) -> Result, RuntimeError> { @@ -1519,7 +1628,7 @@ impl KernelTransactionCallbackObject for System { Ok(output) } - fn finish(&mut self, info: StoreCommitInfo) -> Result<(), RuntimeError> { + fn finalize(&mut self, info: StoreCommitInfo) -> Result<(), RuntimeError> { self.modules.on_teardown()?; // Note that if a transactions fails during this phase, the costing is diff --git a/radix-engine/src/system/system_callback_api.rs b/radix-engine/src/system/system_callback_api.rs index a029482dbb6..7a3eb810291 100644 --- a/radix-engine/src/system/system_callback_api.rs +++ b/radix-engine/src/system/system_callback_api.rs @@ -2,17 +2,16 @@ use crate::errors::RuntimeError; use crate::internal_prelude::*; use crate::kernel::kernel_api::{KernelNodeApi, KernelSubstateApi}; use crate::system::system_callback::*; -use crate::track::BootStore; use radix_engine_interface::api::SystemApi; use radix_engine_interface::blueprints::package::PackageExport; /// Callback object invoked by the system layer pub trait SystemCallbackObject: Sized { /// Initialization Object - type Init: Clone; + type Init: InitializationParameters; /// Initialize and create the callback object above the system - fn init(store: &S, init_input: Self::Init) -> Result; + fn init(init_input: Self::Init) -> Result; /// Invoke a function fn invoke< diff --git a/radix-engine/src/track/interface.rs b/radix-engine/src/track/interface.rs index b58f7eec5ed..a0b2889f6b6 100644 --- a/radix-engine/src/track/interface.rs +++ b/radix-engine/src/track/interface.rs @@ -35,20 +35,6 @@ pub enum TrackedSubstateInfo { Unmodified, } -/// The interface to be used during boot loading -/// This interface is different from the CommitableSubstateStore in -/// that these reads should not be tracked / costed since it will -/// cause a protocol break. -pub trait BootStore { - /// Read a substate from the store - fn read_boot_substate( - &self, - node_id: &NodeId, - partition_num: PartitionNumber, - substate_key: &SubstateKey, - ) -> Option; -} - /// Represents the interface between Radix Engine and Track. /// /// In practice, we will likely end up with only one implementation. diff --git a/radix-engine/src/track/track.rs b/radix-engine/src/track/track.rs index 4e3e19dae6f..51ae397c610 100644 --- a/radix-engine/src/track/track.rs +++ b/radix-engine/src/track/track.rs @@ -4,7 +4,6 @@ use crate::track::interface::{ CommitableSubstateStore, IOAccess, NodeSubstates, TrackedSubstateInfo, }; use crate::track::state_updates::*; -use crate::track::BootStore; use radix_engine_interface::types::*; use radix_substate_store_interface::db_key_mapper::{SpreadPrefixKeyMapper, SubstateKeyContent}; use radix_substate_store_interface::interface::DbPartitionKey; @@ -40,22 +39,6 @@ pub struct MappedTrack<'s, S: SubstateDatabase, M: DatabaseKeyMapper + 'static> phantom_data: PhantomData, } -impl<'s, S: SubstateDatabase, M: DatabaseKeyMapper + 'static> BootStore for MappedTrack<'s, S, M> { - fn read_boot_substate( - &self, - node_id: &NodeId, - partition_num: PartitionNumber, - substate_key: &SubstateKey, - ) -> Option { - let db_partition_key = M::to_db_partition_key(node_id, partition_num); - let db_sort_key = M::to_db_sort_key(&substate_key); - - self.substate_db - .get_raw_substate_by_db_key(&db_partition_key, &db_sort_key) - .map(|e| IndexedScryptoValue::from_vec(e).expect("Failed to decode substate")) - } -} - /// Records all the substates that have been read or written into, and all the partitions to delete. /// /// `NodeId` in this struct isn't always valid. diff --git a/radix-engine/src/transaction/transaction_executor.rs b/radix-engine/src/transaction/transaction_executor.rs index 4378674a390..96366926f25 100644 --- a/radix-engine/src/transaction/transaction_executor.rs +++ b/radix-engine/src/transaction/transaction_executor.rs @@ -1,11 +1,7 @@ use crate::errors::*; use crate::internal_prelude::*; -use crate::kernel::id_allocator::IdAllocator; -use crate::kernel::kernel::BootLoader; -use crate::kernel::kernel_callback_api::*; +use crate::kernel::kernel::KernelInit; use crate::system::system_callback::*; -use crate::system::system_callback_api::SystemCallbackObject; -use crate::track::Track; use crate::transaction::*; use crate::vm::*; use radix_common::constants::*; @@ -262,82 +258,15 @@ impl ExecutionConfig { } } -/// A transaction which has a unique id, useful for creating an IdAllocator which -/// requires a unique input -pub trait UniqueTransaction { - fn unique_seed_for_id_allocator(&self) -> Hash; -} - -impl UniqueTransaction for ExecutableTransaction { - fn unique_seed_for_id_allocator(&self) -> Hash { - *self.unique_hash() - } -} - -pub struct TransactionExecutor<'s, S, V: KernelTransactionCallbackObject> -where - S: SubstateDatabase, -{ - substate_db: &'s S, - system_init: V::Init, - phantom: PhantomData, -} - -impl<'s, S, V> TransactionExecutor<'s, S, V> -where - S: SubstateDatabase, - V: KernelTransactionCallbackObject, -{ - pub fn new(substate_db: &'s S, system_init: V::Init) -> Self { - Self { - substate_db, - system_init, - phantom: PhantomData::default(), - } - } - - pub fn execute(self, executable: V::Executable) -> V::Receipt { - BootLoader { - id_allocator: IdAllocator::new(executable.unique_seed_for_id_allocator()), - track: Track::new(self.substate_db), - init: self.system_init, - phantom: PhantomData::::default(), - } - .execute(executable) - } -} - -pub fn execute_transaction_with_configuration( - substate_db: &S, - vm_init: V::Init, - execution_config: &ExecutionConfig, - executable: ExecutableTransaction, -) -> TransactionReceipt { - let system_init = SystemInit { - self_init: SystemSelfInit { - enable_kernel_trace: execution_config.enable_kernel_trace, - enable_cost_breakdown: execution_config.enable_cost_breakdown, - enable_debug_information: execution_config.enable_debug_information, - execution_trace: execution_config.execution_trace, - system_overrides: execution_config.system_overrides.clone(), - }, - callback_init: vm_init, - }; - TransactionExecutor::<_, System>::new(substate_db, system_init).execute(executable) -} - -pub fn execute_transaction<'s, V: VmInitialize>( +pub fn execute_transaction<'v, V: VmInitialize>( substate_db: &impl SubstateDatabase, - vm_modules: &'s V, + vm_modules: &'v V, execution_config: &ExecutionConfig, executable: ExecutableTransaction, ) -> TransactionReceipt { - execute_transaction_with_configuration::<_, Vm<'s, V::WasmEngine, V::NativeVmExtension>>( - substate_db, - vm_modules.create_vm_init(), - execution_config, - executable, - ) + let vm_init = VmInit::load(substate_db, vm_modules); + let system_init = SystemInit::load(substate_db, execution_config.clone(), vm_init); + KernelInit::load(substate_db, system_init).execute(executable) } pub fn execute_and_commit_transaction<'s, V: VmInitialize>( @@ -346,13 +275,7 @@ pub fn execute_and_commit_transaction<'s, V: VmInitialize>( execution_config: &ExecutionConfig, executable: ExecutableTransaction, ) -> TransactionReceipt { - let receipt = - execute_transaction_with_configuration::<_, Vm<'s, V::WasmEngine, V::NativeVmExtension>>( - substate_db, - vm_modules.create_vm_init(), - execution_config, - executable, - ); + let receipt = execute_transaction(substate_db, vm_modules, execution_config, executable); if let TransactionResult::Commit(commit) = &receipt.result { substate_db.commit(&commit.state_updates.create_database_updates()); } diff --git a/radix-engine/src/updates/bottlenose.rs b/radix-engine/src/updates/bottlenose.rs index 6050b681d06..baebb5db4c4 100644 --- a/radix-engine/src/updates/bottlenose.rs +++ b/radix-engine/src/updates/bottlenose.rs @@ -8,8 +8,6 @@ use crate::kernel::kernel::*; use crate::object_modules::role_assignment::*; use crate::system::system_callback::*; use crate::system::system_db_reader::*; -use crate::system::system_modules::costing::CostingModuleConfig; -use crate::transaction::*; use crate::vm::*; use radix_engine_interface::blueprints::access_controller::*; use radix_engine_interface::blueprints::account::*; @@ -511,12 +509,7 @@ fn generate_protocol_params_to_state_updates( BOOT_LOADER_PARTITION => PartitionStateUpdates::Delta { by_substate: indexmap! { SubstateKey::Field(BOOT_LOADER_SYSTEM_SUBSTATE_FIELD_KEY) => DatabaseUpdate::Set( - scrypto_encode(&SystemBoot::V1(SystemParameters { - network_definition, - costing_module_config: CostingModuleConfig::bottlenose(), - costing_parameters: CostingParameters::babylon_genesis(), - limit_parameters: LimitParameters::babylon_genesis(), - })).unwrap() + scrypto_encode(&SystemBoot::bottlenose(network_definition)).unwrap() ), } }, diff --git a/radix-engine/src/updates/cuttlefish.rs b/radix-engine/src/updates/cuttlefish.rs index 44daf40ccb3..2b451d7b472 100644 --- a/radix-engine/src/updates/cuttlefish.rs +++ b/radix-engine/src/updates/cuttlefish.rs @@ -1,7 +1,5 @@ use super::*; -use crate::system::system_callback::{ - SystemBoot, VersionedSystemLogic, BOOT_LOADER_SYSTEM_SUBSTATE_FIELD_KEY, -}; +use crate::system::system_callback::*; #[derive(Clone)] pub struct CuttlefishSettings { @@ -88,35 +86,21 @@ fn generate_principal_batch( } fn generate_system_logic_v2_updates(db: &S) -> StateUpdates { - let system_boot: SystemBoot = db - .get_substate( - TRANSACTION_TRACKER, - BOOT_LOADER_PARTITION, - SubstateKey::Field(BOOT_LOADER_SYSTEM_SUBSTATE_FIELD_KEY), - ) - .unwrap(); + let system_boot: SystemBoot = db.get_existing_substate( + TRANSACTION_TRACKER, + BOOT_LOADER_PARTITION, + BOOT_LOADER_SYSTEM_SUBSTATE_FIELD_KEY, + ); let cur_system_parameters = match system_boot { SystemBoot::V1(parameters) => parameters, _ => panic!("Unexpected SystemBoot version"), }; - StateUpdates { - by_node: indexmap!( - TRANSACTION_TRACKER.into_node_id() => NodeStateUpdates::Delta { - by_partition: indexmap! { - BOOT_LOADER_PARTITION => PartitionStateUpdates::Delta { - by_substate: indexmap! { - SubstateKey::Field(BOOT_LOADER_SYSTEM_SUBSTATE_FIELD_KEY) => DatabaseUpdate::Set( - scrypto_encode(&SystemBoot::V2( - VersionedSystemLogic::V2, - cur_system_parameters, - )).unwrap() - ), - } - }, - } - } - ), - } + StateUpdates::empty().set_substate( + TRANSACTION_TRACKER, + BOOT_LOADER_PARTITION, + BOOT_LOADER_SYSTEM_SUBSTATE_FIELD_KEY, + SystemBoot::cuttlefish_for_previous_parameters(cur_system_parameters), + ) } diff --git a/radix-engine/src/vm/versions.rs b/radix-engine/src/vm/versions.rs index 8f454aa4ce5..59bb524f744 100644 --- a/radix-engine/src/vm/versions.rs +++ b/radix-engine/src/vm/versions.rs @@ -8,12 +8,20 @@ pub enum ScryptoVmVersion { } impl ScryptoVmVersion { - pub fn latest() -> ScryptoVmVersion { - ScryptoVmVersion::V1_1 + pub const fn latest() -> ScryptoVmVersion { + Self::anemone() } - pub fn crypto_utils_added() -> ScryptoVmVersion { - ScryptoVmVersion::V1_1 + pub const fn babylon_genesis() -> ScryptoVmVersion { + Self::V1_0 + } + + pub const fn anemone() -> ScryptoVmVersion { + Self::V1_1 + } + + pub const fn crypto_utils_added() -> ScryptoVmVersion { + Self::V1_1 } } diff --git a/radix-engine/src/vm/vm.rs b/radix-engine/src/vm/vm.rs index 57940435ba8..7a7c5382ce3 100644 --- a/radix-engine/src/vm/vm.rs +++ b/radix-engine/src/vm/vm.rs @@ -5,7 +5,6 @@ use crate::kernel::kernel_api::{KernelNodeApi, KernelSubstateApi}; use crate::system::system_callback::*; use crate::system::system_callback_api::SystemCallbackObject; use crate::system::system_substates::KeyValueEntrySubstate; -use crate::track::BootStore; use crate::vm::wasm::{ScryptoV1WasmValidator, WasmEngine}; use crate::vm::{NativeVm, NativeVmExtension, ScryptoVm}; use radix_engine_interface::api::field_api::LockFlags; @@ -26,13 +25,28 @@ pub enum VmBoot { } impl VmBoot { + /// Loads vm boot from the database, or resolves a fallback. + pub fn load(substate_db: &impl SubstateDatabase) -> Self { + substate_db + .get_substate( + TRANSACTION_TRACKER, + BOOT_LOADER_PARTITION, + BOOT_LOADER_VM_BOOT_FIELD_KEY, + ) + .unwrap_or_else(|| Self::babylon_genesis()) + } + pub fn latest() -> Self { + Self::bottlenose() + } + + pub fn bottlenose() -> Self { Self::V1 { - scrypto_version: ScryptoVmVersion::latest().into(), + scrypto_version: ScryptoVmVersion::V1_1.into(), } } - pub fn babylon() -> Self { + pub fn babylon_genesis() -> Self { Self::V1 { scrypto_version: ScryptoVmVersion::V1_0.into(), } @@ -66,11 +80,6 @@ pub trait VmInitialize { fn get_vm_extension(&self) -> Self::NativeVmExtension; fn get_scrypto_vm(&self) -> &ScryptoVm; - - fn create_vm_init(&self) -> VmInit { - let vm_extension = self.get_vm_extension(); - VmInit::new(self.get_scrypto_vm(), vm_extension) - } } pub struct VmModules { @@ -123,22 +132,22 @@ impl VmInitialize for VmModules { pub struct VmInit<'g, W: WasmEngine, E: NativeVmExtension> { pub scrypto_vm: &'g ScryptoVm, pub native_vm_extension: E, + pub vm_boot: VmBoot, } -impl<'g, W: WasmEngine, E: NativeVmExtension> VmInit<'g, W, E> { - pub fn new(scrypto_vm: &'g ScryptoVm, native_vm_extension: E) -> Self { - Self { - scrypto_vm, - native_vm_extension, - } - } +impl<'g, W: WasmEngine, E: NativeVmExtension> InitializationParameters for VmInit<'g, W, E> { + type For = Vm<'g, W, E>; } -impl<'g, W: WasmEngine, E: NativeVmExtension> Clone for VmInit<'g, W, E> { - fn clone(&self) -> Self { +impl<'g, W: WasmEngine, E: NativeVmExtension> VmInit<'g, W, E> { + pub fn load( + substate_db: &impl SubstateDatabase, + vm_modules: &'g impl VmInitialize, + ) -> Self { Self { - scrypto_vm: self.scrypto_vm, - native_vm_extension: self.native_vm_extension.clone(), + scrypto_vm: vm_modules.get_scrypto_vm(), + native_vm_extension: vm_modules.get_vm_extension(), + vm_boot: VmBoot::load(substate_db), } } } @@ -152,20 +161,11 @@ pub struct Vm<'g, W: WasmEngine, E: NativeVmExtension> { impl<'g, W: WasmEngine + 'g, E: NativeVmExtension> SystemCallbackObject for Vm<'g, W, E> { type Init = VmInit<'g, W, E>; - fn init(store: &S, vm_init: VmInit<'g, W, E>) -> Result { - let vm_boot = store - .read_boot_substate( - TRANSACTION_TRACKER.as_node_id(), - BOOT_LOADER_PARTITION, - &SubstateKey::Field(BOOT_LOADER_VM_BOOT_FIELD_KEY), - ) - .map(|v| scrypto_decode(v.as_slice()).unwrap()) - .unwrap_or(VmBoot::babylon()); - + fn init(vm_init: VmInit<'g, W, E>) -> Result { Ok(Self { scrypto_vm: vm_init.scrypto_vm, native_vm: NativeVm::new_with_extension(vm_init.native_vm_extension), - vm_boot, + vm_boot: vm_init.vm_boot, }) } diff --git a/radix-substate-store-interface/src/interface.rs b/radix-substate-store-interface/src/interface.rs index fff4931e7a5..51106e78953 100644 --- a/radix-substate-store-interface/src/interface.rs +++ b/radix-substate-store-interface/src/interface.rs @@ -281,7 +281,8 @@ pub trait SubstateDatabaseExtensions: SubstateDatabase { ) } - /// Gets the substate's value, if it exists, and returns it decoded as `V`. + /// Gets the substate's value, if it exists, and returns it decoded as `Some(V)`. + /// If it doesn't exist, `None` is returned. /// /// # Panics /// This method panics if: @@ -305,6 +306,36 @@ pub trait SubstateDatabaseExtensions: SubstateDatabase { Some(decode_value(&raw)) } + /// Gets the value of a subsate which is expected to exist, returns it decoded as `V`. + /// + /// # Panics + /// This method panics if: + /// * The substate doesn't exist in the database. + /// * There is an error decoding the value into the `V`. + /// + /// # Example use: + /// ```ignore + /// let existing_type_info_substate: TypeInfoSubstate = db.get_existing_substate( + /// PACKAGE_PACKAGE, + /// TYPE_INFO_FIELD_PARTITION, + /// TypeInfoField::TypeInfo, + /// )?; + /// ``` + fn get_existing_substate<'a, V: ScryptoDecode>( + &self, + node_id: impl AsRef, + partition_number: PartitionNumber, + substate_key: impl ResolvableSubstateKey<'a>, + ) -> V { + let substate_value = self.get_substate(node_id, partition_number, substate_key); + substate_value.unwrap_or_else(|| { + panic!( + "Expected substate of type {} to already exist.", + core::any::type_name::(), + ) + }) + } + // ------------------------------------------------------------------------------------ // LIST RAW // ------------------------------------------------------------------------------------ diff --git a/radix-transaction-scenarios/generated-protocol-updates/cuttlefish/receipts/00-00-00--cuttlefish-protocol-system-logic-updates.txt b/radix-transaction-scenarios/generated-protocol-updates/cuttlefish/receipts/00-00-00--cuttlefish-protocol-system-logic-updates.txt index f35b3e5e2f1..832d4adb61a 100644 --- a/radix-transaction-scenarios/generated-protocol-updates/cuttlefish/receipts/00-00-00--cuttlefish-protocol-system-logic-updates.txt +++ b/radix-transaction-scenarios/generated-protocol-updates/cuttlefish/receipts/00-00-00--cuttlefish-protocol-system-logic-updates.txt @@ -16,7 +16,7 @@ STATE UPDATES: 1 entity └─ Partition(32): 1 change └─ Set: SystemBoot Value: SystemBoot::V2( - VersionedSystemLogic::V2, + SystemVersion::V2, SystemParameters { network_definition: NetworkDefinition { id: 242u8, diff --git a/radix-transactions/src/model/execution/executable_common.rs b/radix-transactions/src/model/execution/executable_common.rs index b8e78040c86..f00187b81d3 100644 --- a/radix-transactions/src/model/execution/executable_common.rs +++ b/radix-transactions/src/model/execution/executable_common.rs @@ -81,10 +81,6 @@ pub enum IntentHashNullification { expiry_epoch: Epoch, ignore_duplicate: bool, }, - /// For system transactions which currently need to go through - /// nullification process. - /// TODO: Cleanup hash nullification and remove this - System, } impl IntentHashNullification { @@ -96,7 +92,6 @@ impl IntentHashNullification { IntentHashNullification::Subintent { intent_hash, .. } => { Some(IntentHash::Sub(*intent_hash)) } - IntentHashNullification::System => None, } } } diff --git a/radix-transactions/src/model/v1/system_transaction.rs b/radix-transactions/src/model/v1/system_transaction.rs index 10caaf0b6e5..ce29914a9a9 100644 --- a/radix-transactions/src/model/v1/system_transaction.rs +++ b/radix-transactions/src/model/v1/system_transaction.rs @@ -146,7 +146,7 @@ impl PreparedSystemTransactionV1 { self.blobs.blobs_by_hash.clone(), ExecutionContext { unique_hash: self.hash_for_execution.hash, - intent_hash_nullifications: vec![IntentHashNullification::System], + intent_hash_nullifications: vec![], epoch_range: None, payload_size: 0, num_of_signature_validations: 0, diff --git a/scrypto-test/src/environment/builder.rs b/scrypto-test/src/environment/builder.rs index 3b900d09cbb..1ecfc0b8573 100644 --- a/scrypto-test/src/environment/builder.rs +++ b/scrypto-test/src/environment/builder.rs @@ -213,7 +213,7 @@ where BOOT_LOADER_PARTITION, BOOT_LOADER_VM_BOOT_FIELD_KEY, ) - .unwrap_or(VmBoot::babylon()); + .unwrap_or(VmBoot::babylon_genesis()); let transaction_runtime_module = TransactionRuntimeModule::new( NetworkDefinition::simulator(), @@ -236,17 +236,14 @@ where on_apply_cost: Default::default(), }; - System { - versioned_system_logic: VersionedSystemLogic::V1, - blueprint_cache: NonIterMap::new(), - auth_cache: NonIterMap::new(), - schema_cache: NonIterMap::new(), - callback: Vm { + System::new( + SystemVersion::latest(), + Vm { scrypto_vm, native_vm: native_vm.clone(), vm_boot, }, - modules: SystemModuleMixer::new( + SystemModuleMixer::new( EnabledModules::LIMITS | EnabledModules::AUTH | EnabledModules::TRANSACTION_RUNTIME, @@ -257,8 +254,8 @@ where costing_module, ExecutionTraceModule::new(MAX_EXECUTION_TRACE_DEPTH), ), - finalization: Default::default(), - } + SystemFinalization::no_nullifications(), + ) }, |system_config, track, id_allocator| { Kernel::kernel_create_kernel_for_testing( diff --git a/scrypto-test/src/ledger_simulator/inject_costing_err.rs b/scrypto-test/src/ledger_simulator/inject_costing_err.rs index 0fa1c45b4ec..be015d324c1 100644 --- a/scrypto-test/src/ledger_simulator/inject_costing_err.rs +++ b/scrypto-test/src/ledger_simulator/inject_costing_err.rs @@ -1,36 +1,25 @@ -use radix_common::prelude::*; -use radix_engine::errors::*; -use radix_engine::kernel::call_frame::{CallFrameInit, CallFrameMessage, NodeVisibility}; -use radix_engine::kernel::kernel_api::*; -use radix_engine::kernel::kernel_callback_api::*; -use radix_engine::system::actor::Actor; -use radix_engine::system::system_callback::{System, SystemInit, SystemLockData}; -use radix_engine::system::system_callback_api::SystemCallbackObject; -use radix_engine::system::system_modules::costing::{CostingError, FeeReserveError, OnApplyCost}; -use radix_engine::track::*; -use radix_engine::transaction::TransactionReceipt; -use radix_engine::vm::wasm::DefaultWasmEngine; -use radix_engine::vm::Vm; -use radix_engine_interface::blueprints::transaction_processor::InstructionOutput; -use radix_engine_interface::prelude::*; -use radix_substate_store_interface::db_key_mapper::SubstateKeyContent; -use radix_substate_store_interface::interface::SubstateDatabase; -use radix_transactions::model::ExecutableTransaction; - -pub type InjectSystemCostingError<'a, E> = InjectCostingError>; +use radix_engine::init::InitializationParameters; + +use crate::prelude::*; #[derive(Clone)] -pub struct InjectCostingErrorInput { +pub struct InjectCostingErrorInit { pub system_input: I, pub error_after_count: u64, } -pub struct InjectCostingError { +impl> InitializationParameters + for InjectCostingErrorInit +{ + type For = InjectCostingError; +} + +pub struct InjectCostingError { fail_after: Rc>, - system: System, + wrapped: Y, } -impl InjectCostingError { +impl InjectCostingError { fn maybe_err(&mut self) -> Result<(), RuntimeError> { if *self.fail_after.borrow() == 0 { return Ok(()); @@ -65,39 +54,51 @@ macro_rules! wrapped_internal_api { }; } -impl KernelTransactionCallbackObject for InjectCostingError { - type Init = InjectCostingErrorInput>; +impl< + E: KernelTransactionExecutor< + Executable = ExecutableTransaction, + ExecutionOutput = Vec, + Receipt = TransactionReceipt, + > + HasModules, + > KernelTransactionExecutor for InjectCostingError +{ + type Init = InjectCostingErrorInit; type Executable = ExecutableTransaction; type ExecutionOutput = Vec; type Receipt = TransactionReceipt; - fn init( - store: &mut S, + fn init( + store: &mut impl CommitableSubstateStore, executable: &ExecutableTransaction, init_input: Self::Init, - ) -> Result<(Self, Vec>), Self::Receipt> { - let (mut system, call_frame_inits) = - System::::init(store, executable, init_input.system_input)?; + ) -> Result<(Self, Vec>), Self::Receipt> { + let (mut system, call_frame_inits) = E::init(store, executable, init_input.system_input)?; let fail_after = Rc::new(RefCell::new(init_input.error_after_count)); - system.modules.costing_mut().unwrap().on_apply_cost = OnApplyCost::ForceFailOnCount { + system.modules_mut().costing_mut().unwrap().on_apply_cost = OnApplyCost::ForceFailOnCount { fail_after: fail_after.clone(), }; - Ok((Self { fail_after, system }, call_frame_inits)) + Ok(( + Self { + fail_after, + wrapped: system, + }, + call_frame_inits, + )) } - fn start>( + fn execute>( api: &mut Y, executable: ExecutableTransaction, ) -> Result, RuntimeError> { let mut api = wrapped_api!(api); - System::start(&mut api, executable) + E::execute(&mut api, executable) } - fn finish(&mut self, store_commit_info: StoreCommitInfo) -> Result<(), RuntimeError> { + fn finalize(&mut self, store_commit_info: StoreCommitInfo) -> Result<(), RuntimeError> { self.maybe_err()?; - self.system.finish(store_commit_info) + self.wrapped.finalize(store_commit_info) } fn create_receipt( @@ -105,15 +106,13 @@ impl KernelTransactionCallbackObject for InjectCostingE track: Track, result: Result, TransactionExecutionError>, ) -> TransactionReceipt { - self.system.create_receipt(track, result) + self.wrapped.create_receipt(track, result) } } -type InternalSystem = System; - -impl KernelCallbackObject for InjectCostingError { - type LockData = SystemLockData; - type CallFrameData = Actor; +impl KernelCallbackObject for InjectCostingError { + type LockData = E::LockData; + type CallFrameData = E::CallFrameData; fn on_pin_node>( node_id: &NodeId, @@ -121,7 +120,7 @@ impl KernelCallbackObject for InjectCostingError { ) -> Result<(), RuntimeError> { api.kernel_get_system_state().system.maybe_err()?; let mut api = wrapped_internal_api!(api); - InternalSystem::::on_pin_node(node_id, &mut api) + E::on_pin_node(node_id, &mut api) } fn on_create_node>( @@ -130,7 +129,7 @@ impl KernelCallbackObject for InjectCostingError { ) -> Result<(), RuntimeError> { api.kernel_get_system_state().system.maybe_err()?; let mut api = wrapped_internal_api!(api); - InternalSystem::::on_create_node(event, &mut api) + E::on_create_node(event, &mut api) } fn on_drop_node>( @@ -139,7 +138,7 @@ impl KernelCallbackObject for InjectCostingError { ) -> Result<(), RuntimeError> { api.kernel_get_system_state().system.maybe_err()?; let mut api = wrapped_internal_api!(api); - InternalSystem::::on_drop_node(event, &mut api) + E::on_drop_node(event, &mut api) } fn on_move_module>( @@ -148,7 +147,7 @@ impl KernelCallbackObject for InjectCostingError { ) -> Result<(), RuntimeError> { api.kernel_get_system_state().system.maybe_err()?; let mut api = wrapped_internal_api!(api); - InternalSystem::::on_move_module(event, &mut api) + E::on_move_module(event, &mut api) } fn on_open_substate>( @@ -157,7 +156,7 @@ impl KernelCallbackObject for InjectCostingError { ) -> Result<(), RuntimeError> { api.kernel_get_system_state().system.maybe_err()?; let mut api = wrapped_internal_api!(api); - InternalSystem::::on_open_substate(event, &mut api) + E::on_open_substate(event, &mut api) } fn on_close_substate>( @@ -166,7 +165,7 @@ impl KernelCallbackObject for InjectCostingError { ) -> Result<(), RuntimeError> { api.kernel_get_system_state().system.maybe_err()?; let mut api = wrapped_internal_api!(api); - InternalSystem::::on_close_substate(event, &mut api) + E::on_close_substate(event, &mut api) } fn on_read_substate>( @@ -175,7 +174,7 @@ impl KernelCallbackObject for InjectCostingError { ) -> Result<(), RuntimeError> { api.kernel_get_system_state().system.maybe_err()?; let mut api = wrapped_internal_api!(api); - InternalSystem::::on_read_substate(event, &mut api) + E::on_read_substate(event, &mut api) } fn on_write_substate>( @@ -184,7 +183,7 @@ impl KernelCallbackObject for InjectCostingError { ) -> Result<(), RuntimeError> { api.kernel_get_system_state().system.maybe_err()?; let mut api = wrapped_internal_api!(api); - InternalSystem::::on_write_substate(event, &mut api) + E::on_write_substate(event, &mut api) } fn on_set_substate>( @@ -193,7 +192,7 @@ impl KernelCallbackObject for InjectCostingError { ) -> Result<(), RuntimeError> { api.kernel_get_system_state().system.maybe_err()?; let mut api = wrapped_internal_api!(api); - InternalSystem::::on_set_substate(event, &mut api) + E::on_set_substate(event, &mut api) } fn on_remove_substate>( @@ -202,7 +201,7 @@ impl KernelCallbackObject for InjectCostingError { ) -> Result<(), RuntimeError> { api.kernel_get_system_state().system.maybe_err()?; let mut api = wrapped_internal_api!(api); - InternalSystem::::on_remove_substate(event, &mut api) + E::on_remove_substate(event, &mut api) } fn on_scan_keys>( @@ -211,7 +210,7 @@ impl KernelCallbackObject for InjectCostingError { ) -> Result<(), RuntimeError> { api.kernel_get_system_state().system.maybe_err()?; let mut api = wrapped_internal_api!(api); - InternalSystem::::on_scan_keys(event, &mut api) + E::on_scan_keys(event, &mut api) } fn on_drain_substates>( @@ -220,7 +219,7 @@ impl KernelCallbackObject for InjectCostingError { ) -> Result<(), RuntimeError> { api.kernel_get_system_state().system.maybe_err()?; let mut api = wrapped_internal_api!(api); - InternalSystem::::on_drain_substates(event, &mut api) + E::on_drain_substates(event, &mut api) } fn on_scan_sorted_substates>( @@ -229,7 +228,7 @@ impl KernelCallbackObject for InjectCostingError { ) -> Result<(), RuntimeError> { api.kernel_get_system_state().system.maybe_err()?; let mut api = wrapped_internal_api!(api); - InternalSystem::::on_scan_sorted_substates(event, &mut api) + E::on_scan_sorted_substates(event, &mut api) } fn before_invoke>( @@ -238,7 +237,7 @@ impl KernelCallbackObject for InjectCostingError { ) -> Result<(), RuntimeError> { api.kernel_get_system_state().system.maybe_err()?; let mut api = wrapped_api!(api); - InternalSystem::::before_invoke(invocation, &mut api) + E::before_invoke(invocation, &mut api) } fn on_execution_start>( @@ -246,7 +245,7 @@ impl KernelCallbackObject for InjectCostingError { ) -> Result<(), RuntimeError> { api.kernel_get_system_state().system.maybe_err()?; let mut api = wrapped_internal_api!(api); - InternalSystem::::on_execution_start(&mut api) + E::on_execution_start(&mut api) } fn invoke_upstream>( @@ -255,7 +254,7 @@ impl KernelCallbackObject for InjectCostingError { ) -> Result { api.kernel_get_system_state().system.maybe_err()?; let mut api = wrapped_api!(api); - InternalSystem::::invoke_upstream(args, &mut api) + E::invoke_upstream(args, &mut api) } fn auto_drop>( @@ -264,7 +263,7 @@ impl KernelCallbackObject for InjectCostingError { ) -> Result<(), RuntimeError> { api.kernel_get_system_state().system.maybe_err()?; let mut api = wrapped_api!(api); - InternalSystem::::auto_drop(nodes, &mut api) + E::auto_drop(nodes, &mut api) } fn on_execution_finish>( @@ -273,7 +272,7 @@ impl KernelCallbackObject for InjectCostingError { ) -> Result<(), RuntimeError> { api.kernel_get_system_state().system.maybe_err()?; let mut api = wrapped_internal_api!(api); - InternalSystem::::on_execution_finish(message, &mut api) + E::on_execution_finish(message, &mut api) } fn after_invoke>( @@ -282,7 +281,7 @@ impl KernelCallbackObject for InjectCostingError { ) -> Result<(), RuntimeError> { api.kernel_get_system_state().system.maybe_err()?; let mut api = wrapped_api!(api); - InternalSystem::::after_invoke(output, &mut api) + E::after_invoke(output, &mut api) } fn on_allocate_node_id>( @@ -291,7 +290,7 @@ impl KernelCallbackObject for InjectCostingError { ) -> Result<(), RuntimeError> { api.kernel_get_system_state().system.maybe_err()?; let mut api = wrapped_internal_api!(api); - InternalSystem::::on_allocate_node_id(entity_type, &mut api) + E::on_allocate_node_id(entity_type, &mut api) } fn on_mark_substate_as_transient>( @@ -302,12 +301,7 @@ impl KernelCallbackObject for InjectCostingError { ) -> Result<(), RuntimeError> { api.kernel_get_system_state().system.maybe_err()?; let mut api = wrapped_internal_api!(api); - InternalSystem::::on_mark_substate_as_transient( - node_id, - partition_number, - substate_key, - &mut api, - ) + E::on_mark_substate_as_transient(node_id, partition_number, substate_key, &mut api) } fn on_substate_lock_fault>( @@ -318,7 +312,7 @@ impl KernelCallbackObject for InjectCostingError { ) -> Result { api.kernel_get_system_state().system.maybe_err()?; let mut api = wrapped_api!(api); - InternalSystem::::on_substate_lock_fault(node_id, partition_num, offset, &mut api) + E::on_substate_lock_fault(node_id, partition_num, offset, &mut api) } fn on_drop_node_mut>( @@ -327,20 +321,23 @@ impl KernelCallbackObject for InjectCostingError { ) -> Result<(), RuntimeError> { api.kernel_get_system_state().system.maybe_err()?; let mut api = wrapped_api!(api); - InternalSystem::::on_drop_node_mut(node_id, &mut api) + E::on_drop_node_mut(node_id, &mut api) } } pub struct WrappedKernelApi< 'a, - M: SystemCallbackObject + 'a, - K: KernelApi>, + E: KernelTransactionExecutor + 'a, + K: KernelApi>, > { api: &'a mut K, } -impl<'a, M: SystemCallbackObject, K: KernelApi>> - KernelNodeApi for WrappedKernelApi<'a, M, K> +impl< + 'a, + E: KernelTransactionExecutor + 'a, + K: KernelApi>, + > KernelNodeApi for WrappedKernelApi<'a, E, K> { fn kernel_pin_node(&mut self, node_id: NodeId) -> Result<(), RuntimeError> { self.api.kernel_pin_node(node_id) @@ -371,8 +368,11 @@ impl<'a, M: SystemCallbackObject, K: KernelApi>> - KernelSubstateApi for WrappedKernelApi<'a, M, Y> +impl< + 'a, + E: KernelTransactionExecutor + 'a, + Y: KernelApi>, + > KernelSubstateApi for WrappedKernelApi<'a, E, Y> { fn kernel_mark_substate_as_transient( &mut self, @@ -391,7 +391,7 @@ impl<'a, M: SystemCallbackObject, Y: KernelApi, - lock_data: SystemLockData, + lock_data: E::LockData, ) -> Result { self.api.kernel_open_substate_with_default( node_id, @@ -406,7 +406,7 @@ impl<'a, M: SystemCallbackObject, Y: KernelApi Result { + ) -> Result { self.api.kernel_get_lock_data(lock_handle) } @@ -481,21 +481,27 @@ impl<'a, M: SystemCallbackObject, Y: KernelApi>> - KernelInvokeApi for WrappedKernelApi<'a, M, K> +impl< + 'a, + E: KernelTransactionExecutor + 'a, + K: KernelApi>, + > KernelInvokeApi for WrappedKernelApi<'a, E, K> { fn kernel_invoke( &mut self, - invocation: Box>, + invocation: Box>, ) -> Result { self.api.kernel_invoke(invocation) } } -impl<'a, M: SystemCallbackObject, K: KernelApi>> - KernelStackApi for WrappedKernelApi<'a, M, K> +impl< + 'a, + E: KernelTransactionExecutor + 'a, + K: KernelApi>, + > KernelStackApi for WrappedKernelApi<'a, E, K> { - type CallFrameData = Actor; + type CallFrameData = E::CallFrameData; fn kernel_get_stack_id(&self) -> usize { self.api.kernel_get_stack_id() @@ -505,7 +511,7 @@ impl<'a, M: SystemCallbackObject, K: KernelApi Result<(), RuntimeError> { + fn kernel_set_call_frame_data(&mut self, data: E::CallFrameData) -> Result<(), RuntimeError> { self.api.kernel_set_call_frame_data(data) } @@ -514,15 +520,18 @@ impl<'a, M: SystemCallbackObject, K: KernelApi>> - KernelInternalApi for WrappedKernelApi<'a, M, K> +impl< + 'a, + E: KernelTransactionExecutor + 'a, + K: KernelApi>, + > KernelInternalApi for WrappedKernelApi<'a, E, K> { - type System = System; + type System = E; - fn kernel_get_system_state(&mut self) -> SystemState<'_, System> { + fn kernel_get_system_state(&mut self) -> SystemState<'_, E> { let state = self.api.kernel_get_system_state(); SystemState { - system: &mut state.system.system, + system: &mut state.system.wrapped, caller_call_frame: state.caller_call_frame, current_call_frame: state.current_call_frame, } @@ -547,29 +556,35 @@ impl<'a, M: SystemCallbackObject, K: KernelApi>> KernelApi - for WrappedKernelApi<'a, M, K> +impl< + 'a, + E: KernelTransactionExecutor + 'a, + K: KernelApi>, + > KernelApi for WrappedKernelApi<'a, E, K> { - type CallbackObject = System; + type CallbackObject = E; } pub struct WrappedKernelInternalApi< 'a, - M: SystemCallbackObject + 'a, - K: KernelInternalApi>, + E: KernelTransactionExecutor + 'a, + K: KernelInternalApi>, > { api: &'a mut K, } -impl<'a, M: SystemCallbackObject, K: KernelInternalApi>> - KernelInternalApi for WrappedKernelInternalApi<'a, M, K> +impl< + 'a, + E: KernelTransactionExecutor + 'a, + K: KernelInternalApi>, + > KernelInternalApi for WrappedKernelInternalApi<'a, E, K> { - type System = System; + type System = E; - fn kernel_get_system_state(&mut self) -> SystemState<'_, System> { + fn kernel_get_system_state(&mut self) -> SystemState<'_, E> { let state = self.api.kernel_get_system_state(); SystemState { - system: &mut state.system.system, + system: &mut state.system.wrapped, caller_call_frame: state.caller_call_frame, current_call_frame: state.current_call_frame, } diff --git a/scrypto-test/src/ledger_simulator/ledger_simulator.rs b/scrypto-test/src/ledger_simulator/ledger_simulator.rs index c7f2d32909d..37f294cb78f 100644 --- a/scrypto-test/src/ledger_simulator/ledger_simulator.rs +++ b/scrypto-test/src/ledger_simulator/ledger_simulator.rs @@ -1203,29 +1203,17 @@ impl LedgerSimulator { ) }); - let vm_init = self.vm_modules.create_vm_init(); - // Override the kernel trace config execution_config = execution_config.with_kernel_trace(self.with_kernel_trace); - let executor = TransactionExecutor::<_, InjectSystemCostingError<'_, E>>::new( - &self.database, - InjectCostingErrorInput { - system_input: SystemInit { - self_init: SystemSelfInit { - enable_kernel_trace: execution_config.enable_kernel_trace, - enable_cost_breakdown: execution_config.enable_cost_breakdown, - enable_debug_information: execution_config.enable_debug_information, - execution_trace: execution_config.execution_trace, - system_overrides: execution_config.system_overrides.clone(), - }, - callback_init: vm_init, - }, - error_after_count, - }, - ); + let vm_init = VmInit::load(&self.database, &self.vm_modules); + let system_init = InjectCostingErrorInit { + system_input: SystemInit::load(&self.database, execution_config, vm_init), + error_after_count, + }; + let kernel_init = KernelInit::load(&self.database, system_init); - let transaction_receipt = executor.execute(executable); + let transaction_receipt = kernel_init.execute(executable); if let TransactionResult::Commit(commit) = &transaction_receipt.result { let database_updates = commit.state_updates.create_database_updates();