1use super::module::*;
2use super::system_modules::costing::{CostingModuleConfig, ExecutionCostingEntry};
3use super::type_info::{TypeInfoBlueprint, TypeInfoSubstate};
4use crate::blueprints::account::ACCOUNT_CREATE_PREALLOCATED_ED25519_ID;
5use crate::blueprints::account::ACCOUNT_CREATE_PREALLOCATED_SECP256K1_ID;
6use crate::blueprints::consensus_manager::*;
7use crate::blueprints::identity::IDENTITY_CREATE_PREALLOCATED_ED25519_ID;
8use crate::blueprints::identity::IDENTITY_CREATE_PREALLOCATED_SECP256K1_ID;
9use crate::blueprints::resource::fungible_vault::{DepositEvent, PayFeeEvent};
10use crate::blueprints::resource::*;
11use crate::blueprints::transaction_tracker::*;
12use crate::errors::*;
13use crate::internal_prelude::*;
14use crate::kernel::call_frame::{CallFrameInit, CallFrameMessage, StableReferenceType};
15use crate::kernel::kernel_api::*;
16use crate::kernel::kernel_callback_api::*;
17use crate::system::actor::BlueprintHookActor;
18use crate::system::actor::FunctionActor;
19use crate::system::actor::MethodActor;
20use crate::system::actor::{Actor, MethodType};
21use crate::system::module::InitSystemModule;
22use crate::system::system::SystemService;
23use crate::system::system_callback_api::SystemCallbackObject;
24use crate::system::system_db_reader::SystemDatabaseReader;
25use crate::system::system_modules::auth::AuthModule;
26use crate::system::system_modules::costing::*;
27use crate::system::system_modules::execution_trace::ExecutionTraceModule;
28use crate::system::system_modules::kernel_trace::KernelTraceModule;
29use crate::system::system_modules::limits::LimitsModule;
30use crate::system::system_modules::transaction_runtime::TransactionRuntimeModule;
31use crate::system::system_modules::{EnabledModules, SystemModuleMixer};
32use crate::system::system_substates::KeyValueEntrySubstate;
33use crate::system::system_type_checker::{BlueprintTypeTarget, KVStoreTypeTarget};
34use crate::system::transaction::multithread_intent_processor::MultiThreadIntentProcessor;
35use crate::track::*;
36use crate::transaction::*;
37use radix_blueprint_schema_init::RefTypes;
38use radix_engine_interface::api::field_api::LockFlags;
39use radix_engine_interface::api::SystemObjectApi;
40use radix_engine_interface::api::{CollectionIndex, SystemBlueprintApi};
41use radix_engine_interface::blueprints::account::ACCOUNT_BLUEPRINT;
42use radix_engine_interface::blueprints::hooks::*;
43use radix_engine_interface::blueprints::identity::IDENTITY_BLUEPRINT;
44use radix_engine_interface::blueprints::package::*;
45use radix_engine_interface::blueprints::transaction_processor::*;
46use radix_substate_store_interface::interface::*;
47use radix_transactions::model::*;
48
49#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
50pub struct SystemParameters {
51 pub network_definition: NetworkDefinition,
52 pub costing_module_config: CostingModuleConfig,
53 pub costing_parameters: CostingParameters,
54 pub limit_parameters: LimitParameters,
55}
56
57impl SystemParameters {
58 pub fn latest(network_definition: NetworkDefinition) -> Self {
59 Self::bottlenose(network_definition)
60 }
61
62 pub fn bottlenose(network_definition: NetworkDefinition) -> Self {
63 Self {
64 network_definition,
65 costing_module_config: CostingModuleConfig::bottlenose(),
66 costing_parameters: CostingParameters::babylon_genesis(),
67 limit_parameters: LimitParameters::babylon_genesis(),
68 }
69 }
70
71 pub fn babylon_genesis(network_definition: NetworkDefinition) -> Self {
72 Self {
73 network_definition,
74 costing_module_config: CostingModuleConfig::babylon_genesis(),
75 costing_parameters: CostingParameters::babylon_genesis(),
76 limit_parameters: LimitParameters::babylon_genesis(),
77 }
78 }
79}
80
81pub type SystemBootSubstate = SystemBoot;
82
83#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor, ScryptoSborAssertion)]
84#[sbor_assert(backwards_compatible(
85 cuttlefish = "FILE:system_boot_substate_cuttlefish_schema.bin",
86 dugong = "FILE:system_boot_substate_dugong_schema.bin",
87 eagle_ray = "FILE:system_boot_substate_eagle_ray_schema.bin",
88))]
89pub enum SystemBoot {
90 V1(SystemParameters),
91 V2(SystemVersion, SystemParameters),
92}
93
94impl SystemBoot {
95 pub fn load(substate_db: &impl SubstateDatabase, execution_config: &ExecutionConfig) -> Self {
101 substate_db
102 .get_substate(
103 TRANSACTION_TRACKER,
104 BOOT_LOADER_PARTITION,
105 BootLoaderField::SystemBoot,
106 )
107 .unwrap_or_else(|| {
108 let overrides = execution_config.system_overrides.as_ref();
109 let network_definition = overrides.and_then(|o| o.network_definition.as_ref())
110 .expect("Before bottlenose, no SystemBoot substate exists, so a network_definition must be provided in the SystemOverrides of the ExecutionConfig.");
111 SystemBoot::babylon_genesis(network_definition.clone())
112 })
113 }
114
115 pub fn latest(network_definition: NetworkDefinition) -> Self {
116 Self::eagle_ray_for_previous_parameters(SystemParameters::latest(network_definition))
117 }
118
119 pub fn eagle_ray_for_previous_parameters(parameters: SystemParameters) -> Self {
120 SystemBoot::V2(SystemVersion::V5, parameters)
121 }
122
123 pub fn cuttlefish(network_definition: NetworkDefinition) -> Self {
124 SystemBoot::V2(
125 SystemVersion::V3,
126 SystemParameters::bottlenose(network_definition),
127 )
128 }
129
130 pub fn cuttlefish_part1_for_previous_parameters(parameters: SystemParameters) -> Self {
131 SystemBoot::V2(SystemVersion::V2, parameters)
132 }
133
134 pub fn cuttlefish_part2_for_previous_parameters(parameters: SystemParameters) -> Self {
135 SystemBoot::V2(SystemVersion::V3, parameters)
136 }
137
138 pub fn dugong_for_previous_parameters(parameters: SystemParameters) -> Self {
139 SystemBoot::V2(SystemVersion::V4, parameters)
140 }
141
142 pub fn bottlenose(network_definition: NetworkDefinition) -> Self {
143 SystemBoot::V1(SystemParameters::bottlenose(network_definition))
144 }
145
146 pub fn babylon_genesis(network_definition: NetworkDefinition) -> Self {
147 SystemBoot::V1(SystemParameters::babylon_genesis(network_definition))
148 }
149
150 pub fn system_version(&self) -> SystemVersion {
151 match self {
152 Self::V1(..) => SystemVersion::V1,
153 Self::V2(version, _) => *version,
154 }
155 }
156
157 pub fn into_parameters(self) -> SystemParameters {
158 match self {
159 Self::V1(parameters) => parameters,
160 Self::V2(_, parameters) => parameters,
161 }
162 }
163}
164
165#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ScryptoSbor)]
167pub enum SystemVersion {
168 V1,
169 V2,
170 V3,
171 V4,
172 V5,
173}
174
175impl SystemVersion {
176 pub const fn latest() -> Self {
177 Self::V5
178 }
179
180 fn create_auth_module(
181 self,
182 executable: &ExecutableTransaction,
183 ) -> Result<AuthModule, RejectionReason> {
184 let auth_module = if self <= SystemVersion::V1 {
185 if !executable.subintents().is_empty() {
188 return Err(RejectionReason::SubintentsNotYetSupported);
189 }
190 let intent = executable.transaction_intent();
191 AuthModule::new_with_transaction_processor_auth_zone(intent.auth_zone_init.clone())
192 } else {
193 AuthModule::new()
194 };
195
196 Ok(auth_module)
197 }
198
199 fn execute_transaction<Y: SystemBasedKernelApi>(
200 self,
201 api: &mut Y,
202 executable: &ExecutableTransaction,
203 global_address_reservations: Vec<GlobalAddressReservation>,
204 ) -> Result<Vec<InstructionOutput>, RuntimeError> {
205 let output = if self <= SystemVersion::V1 {
206 let mut system_service = SystemService::new(api);
207 let intent = executable.transaction_intent();
208 let rtn = system_service.call_function(
209 TRANSACTION_PROCESSOR_PACKAGE,
210 TRANSACTION_PROCESSOR_BLUEPRINT,
211 TRANSACTION_PROCESSOR_RUN_IDENT,
212 scrypto_encode(&TransactionProcessorRunInputEfficientEncodable {
213 manifest_encoded_instructions: intent.encoded_instructions.as_ref(),
214 global_address_reservations: global_address_reservations.as_slice(),
215 references: &intent.references,
216 blobs: &intent.blobs,
217 })
218 .unwrap(),
219 )?;
220 let output: Vec<InstructionOutput> = scrypto_decode(&rtn).unwrap();
221 output
222 } else {
223 let mut txn_threads = MultiThreadIntentProcessor::init(
224 executable,
225 global_address_reservations.as_slice(),
226 api,
227 )?;
228 txn_threads.execute(api)?;
229 let output = txn_threads
230 .threads
231 .get_mut(0)
232 .unwrap()
233 .0
234 .outputs
235 .drain(..)
236 .collect();
237 output
238 };
239
240 Ok(output)
241 }
242
243 pub fn should_consume_cost_units<Y: SystemBasedKernelApi>(self, api: &mut Y) -> bool {
244 if self <= SystemVersion::V1 {
245 api.kernel_get_current_stack_depth_uncosted() != 1
247 } else {
248 true
249 }
250 }
251
252 pub fn should_inject_transaction_processor_proofs_in_call_function(self) -> bool {
253 self <= SystemVersion::V1
254 }
255
256 pub fn should_charge_for_transaction_intent(self) -> bool {
257 self >= SystemVersion::V2
258 }
259
260 pub fn use_root_for_verify_parent_instruction(self) -> bool {
261 self <= SystemVersion::V2
262 }
263
264 pub fn assert_access_rule_is_noop_when_auth_module_disabled(self) -> bool {
265 matches!(self, SystemVersion::V4)
267 }
268
269 pub fn should_check_method_receiver_access(self) -> bool {
270 self >= SystemVersion::V5
271 }
272}
273
274#[derive(Clone, Default)]
275pub enum SystemLockData {
276 KeyValueEntry(KeyValueEntryLockData),
277 Field(FieldLockData),
278 #[default]
279 Default,
280}
281
282#[derive(Clone)]
283pub enum KeyValueEntryLockData {
284 Read,
285 KVStoreWrite {
286 kv_store_validation_target: KVStoreTypeTarget,
287 },
288 KVCollectionWrite {
289 target: BlueprintTypeTarget,
290 collection_index: CollectionIndex,
291 },
292}
293
294#[derive(Clone)]
295#[allow(clippy::large_enum_variant)]
296pub enum FieldLockData {
297 Read,
298 Write {
299 target: BlueprintTypeTarget,
300 field_index: u8,
301 },
302}
303
304impl SystemLockData {
305 pub fn is_kv_entry(&self) -> bool {
306 matches!(self, SystemLockData::KeyValueEntry(..))
307 }
308
309 pub fn is_kv_entry_with_write(&self) -> bool {
310 matches!(
311 self,
312 SystemLockData::KeyValueEntry(KeyValueEntryLockData::KVCollectionWrite { .. })
313 | SystemLockData::KeyValueEntry(KeyValueEntryLockData::KVStoreWrite { .. })
314 )
315 }
316}
317
318pub trait SystemBasedKernelApi: KernelApi<CallbackObject = System<Self::SystemCallback>> {
320 type SystemCallback: SystemCallbackObject;
321
322 fn system_service(&mut self) -> SystemService<'_, Self> {
323 SystemService::new(self)
324 }
325}
326
327impl<V: SystemCallbackObject, K: KernelApi<CallbackObject = System<V>>> SystemBasedKernelApi for K {
328 type SystemCallback = V;
329}
330
331pub trait SystemBasedKernelInternalApi:
333 KernelInternalApi<System = System<Self::SystemCallback>>
334{
335 type SystemCallback: SystemCallbackObject;
336
337 fn system_module_api(&mut self) -> SystemModuleApiImpl<'_, Self> {
338 SystemModuleApiImpl::new(self)
339 }
340}
341
342impl<V: SystemCallbackObject, K: KernelInternalApi<System = System<V>>> SystemBasedKernelInternalApi
343 for K
344{
345 type SystemCallback = V;
346}
347
348pub struct SystemInit<I: InitializationParameters<For: SystemCallbackObject<Init = I>>> {
349 pub self_init: SystemSelfInit,
350 pub callback_init: I,
351}
352
353impl<I: InitializationParameters<For: SystemCallbackObject<Init = I>>> SystemInit<I> {
354 pub fn load(
357 substate_db: &impl SubstateDatabase,
358 execution_config: ExecutionConfig,
359 callback_init: I,
360 ) -> Self {
361 let system_boot = SystemBoot::load(substate_db, &execution_config);
362 let self_init = SystemSelfInit::new(
363 execution_config,
364 system_boot.system_version(),
365 system_boot.into_parameters(),
366 );
367 Self {
368 self_init,
369 callback_init,
370 }
371 }
372}
373
374impl<I: InitializationParameters<For: SystemCallbackObject<Init = I>>> InitializationParameters
375 for SystemInit<I>
376{
377 type For = System<I::For>;
378}
379
380pub struct SystemSelfInit {
381 pub enable_kernel_trace: bool,
383 pub enable_cost_breakdown: bool,
384 pub execution_trace: Option<usize>,
385 pub enable_debug_information: bool,
386
387 pub system_parameters: SystemParameters,
389 pub system_logic_version: SystemVersion,
390 pub system_overrides: Option<SystemOverrides>,
391}
392
393impl SystemSelfInit {
394 pub fn new(
395 execution_config: ExecutionConfig,
396 system_logic_version: SystemVersion,
397 system_parameters: SystemParameters,
398 ) -> Self {
399 Self {
400 enable_kernel_trace: execution_config.enable_kernel_trace,
401 enable_cost_breakdown: execution_config.enable_cost_breakdown,
402 enable_debug_information: execution_config.enable_debug_information,
403 execution_trace: execution_config.execution_trace,
404 system_overrides: execution_config.system_overrides,
405 system_logic_version,
406 system_parameters,
407 }
408 }
409}
410
411pub struct System<V: SystemCallbackObject> {
412 pub versioned_system_logic: SystemVersion,
413 pub callback: V,
414 pub blueprint_cache: NonIterMap<CanonicalBlueprintId, Rc<BlueprintDefinition>>,
415 pub schema_cache: NonIterMap<SchemaHash, Rc<VersionedScryptoSchema>>,
416 pub auth_cache: NonIterMap<CanonicalBlueprintId, AuthConfig>,
417 pub modules: SystemModuleMixer,
418 pub finalization: SystemFinalization,
419}
420
421pub trait HasModules {
422 fn modules_mut(&mut self) -> &mut SystemModuleMixer;
423}
424
425impl<V: SystemCallbackObject> HasModules for System<V> {
426 #[inline]
427 fn modules_mut(&mut self) -> &mut SystemModuleMixer {
428 &mut self.modules
429 }
430}
431
432pub struct SystemFinalization {
433 pub intent_nullifications: Vec<IntentHashNullification>,
434}
435
436impl SystemFinalization {
437 pub fn no_nullifications() -> Self {
438 Self {
439 intent_nullifications: vec![],
440 }
441 }
442}
443
444impl<V: SystemCallbackObject> System<V> {
445 pub fn new(
446 versioned_system_logic: SystemVersion,
447 callback: V,
448 modules: SystemModuleMixer,
449 finalization: SystemFinalization,
450 ) -> Self {
451 Self {
452 callback,
453 blueprint_cache: NonIterMap::new(),
454 auth_cache: NonIterMap::new(),
455 schema_cache: NonIterMap::new(),
456 modules,
457 finalization,
458 versioned_system_logic,
459 }
460 }
461
462 fn on_move_node<Y: SystemBasedKernelApi>(
463 node_id: &NodeId,
464 is_moving_down: bool,
465 is_to_barrier: bool,
466 destination_blueprint_id: Option<BlueprintId>,
467 api: &mut Y,
468 ) -> Result<(), RuntimeError> {
469 let type_info = TypeInfoBlueprint::get_type(node_id, api)?;
470
471 match type_info {
472 TypeInfoSubstate::Object(object_info) => {
473 let mut service = SystemService::new(api);
474 let definition = service.load_blueprint_definition(
475 object_info.blueprint_info.blueprint_id.package_address,
476 &BlueprintVersionKey {
477 blueprint: object_info
478 .blueprint_info
479 .blueprint_id
480 .blueprint_name
481 .clone(),
482 version: BlueprintVersion::default(),
483 },
484 )?;
485 if definition.hook_exports.contains_key(&BlueprintHook::OnMove) {
486 api.kernel_invoke(Box::new(KernelInvocation {
487 call_frame_data: Actor::BlueprintHook(BlueprintHookActor {
488 receiver: Some(*node_id),
489 blueprint_id: object_info.blueprint_info.blueprint_id.clone(),
490 hook: BlueprintHook::OnMove,
491 }),
492 args: IndexedScryptoValue::from_typed(&OnMoveInput {
493 is_moving_down,
494 is_to_barrier,
495 destination_blueprint_id,
496 }),
497 }))
498 .map(|_| ())
499 } else {
500 Ok(())
501 }
502 }
503 TypeInfoSubstate::KeyValueStore(_)
504 | TypeInfoSubstate::GlobalAddressReservation(_)
505 | TypeInfoSubstate::GlobalAddressPhantom(_) => Ok(()),
506 }
507 }
508}
509
510impl<V: SystemCallbackObject> System<V> {
511 #[cfg(not(feature = "alloc"))]
512 fn print_executable(executable: &ExecutableTransaction) {
513 println!("{:-^120}", "Executable");
514 println!("Intent hash: {}", executable.unique_hash());
515 println!("Payload size: {}", executable.payload_size());
516 println!(
517 "Transaction costing parameters: {:?}",
518 executable.costing_parameters()
519 );
520 println!(
521 "Pre-allocated addresses: {:?}",
522 executable.pre_allocated_addresses()
523 );
524 println!("Blobs: {:?}", executable.all_blob_hashes());
525 println!("References: {:?}", executable.all_references());
526 }
527
528 fn read_epoch_uncosted<S: CommitableSubstateStore>(store: &mut S) -> Option<Epoch> {
529 match store.read_substate(
532 CONSENSUS_MANAGER.as_node_id(),
533 MAIN_BASE_PARTITION,
534 &ConsensusManagerField::State.into(),
535 ) {
536 Some(x) => {
537 let substate: FieldSubstate<ConsensusManagerStateFieldPayload> =
538 x.as_typed().unwrap();
539 Some(substate.into_payload().into_unique_version().epoch)
540 }
541 None => None,
542 }
543 }
544
545 fn validate_epoch_range(
546 current_epoch: Epoch,
547 start_epoch_inclusive: Epoch,
548 end_epoch_exclusive: Epoch,
549 ) -> Result<(), RejectionReason> {
550 if current_epoch < start_epoch_inclusive {
551 return Err(RejectionReason::TransactionEpochNotYetValid {
552 valid_from: start_epoch_inclusive,
553 current_epoch,
554 });
555 }
556 if current_epoch >= end_epoch_exclusive {
557 return Err(RejectionReason::TransactionEpochNoLongerValid {
558 valid_until: end_epoch_exclusive.previous().unwrap_or(Epoch::zero()),
559 current_epoch,
560 });
561 }
562
563 Ok(())
564 }
565
566 fn validate_intent_hash_uncosted<S: CommitableSubstateStore>(
567 store: &mut S,
568 intent_hash: IntentHash,
569 expiry_epoch: Epoch,
570 ) -> Result<(), RejectionReason> {
571 let substate: FieldSubstate<TransactionTrackerSubstate> = store
572 .read_substate(
573 TRANSACTION_TRACKER.as_node_id(),
574 MAIN_BASE_PARTITION,
575 &TransactionTrackerField::TransactionTracker.into(),
576 )
577 .unwrap()
578 .as_typed()
579 .unwrap();
580
581 let partition_number = substate
582 .into_payload()
583 .v1()
584 .partition_for_expiry_epoch(expiry_epoch)
585 .expect("Transaction tracker should cover all valid epoch ranges");
586
587 let substate = store.read_substate(
588 TRANSACTION_TRACKER.as_node_id(),
589 PartitionNumber(partition_number),
590 &SubstateKey::Map(scrypto_encode(intent_hash.as_hash()).unwrap()),
591 );
592
593 if let Some(value) = substate {
594 let substate: KeyValueEntrySubstate<TransactionStatus> = value.as_typed().unwrap();
595 if let Some(status) = substate.into_value() {
596 match status.into_v1() {
597 TransactionStatusV1::CommittedSuccess
598 | TransactionStatusV1::CommittedFailure => {
599 return Err(RejectionReason::IntentHashPreviouslyCommitted(intent_hash));
600 }
601 TransactionStatusV1::Cancelled => {
602 return Err(RejectionReason::IntentHashPreviouslyCancelled(intent_hash));
603 }
604 }
605 }
606 }
607
608 Ok(())
609 }
610
611 fn determine_result_type(
612 interpretation_result: Result<Vec<InstructionOutput>, TransactionExecutionError>,
613 fee_reserve: &mut SystemLoanFeeReserve,
614 ) -> TransactionResultType {
615 let final_repay_result = fee_reserve.repay_all();
621
622 match interpretation_result {
623 Ok(output) => match final_repay_result {
624 Ok(_) => TransactionResultType::Commit(Ok(output)), Err(e) => {
626 if let Some(abort_reason) = e.abortion() {
627 TransactionResultType::Abort(abort_reason.clone())
628 } else {
629 TransactionResultType::Reject(RejectionReason::SuccessButFeeLoanNotRepaid)
630 }
631 }
632 },
633 Err(e) => match e {
634 TransactionExecutionError::BootloadingError(e) => {
635 TransactionResultType::Reject(RejectionReason::BootloadingError(e))
636 }
637 TransactionExecutionError::RuntimeError(e) => {
638 if let Some(abort_reason) = e.abortion() {
639 TransactionResultType::Abort(abort_reason.clone())
640 } else if fee_reserve.fully_repaid() {
641 TransactionResultType::Commit(Err(e))
642 } else {
643 TransactionResultType::Reject(
644 RejectionReason::ErrorBeforeLoanAndDeferredCostsRepaid(e),
645 )
646 }
647 }
648 },
649 }
650 }
651
652 #[allow(clippy::type_complexity)]
653 fn finalize_fees_for_commit<S: SubstateDatabase>(
654 track: &mut Track<S>,
655 fee_reserve: SystemLoanFeeReserve,
656 is_success: bool,
657 ) -> (
658 FeeReserveFinalizationSummary,
659 IndexMap<NodeId, Decimal>,
660 Vec<(EventTypeIdentifier, Vec<u8>)>,
661 CostingParameters,
662 TransactionCostingParameters,
663 ) {
664 let mut events = Vec::<(EventTypeIdentifier, Vec<u8>)>::new();
665
666 for (recipient, amount) in fee_reserve.royalty_cost_breakdown().clone() {
668 let node_id = recipient.vault_id();
669 let substate_key = FungibleVaultField::Balance.into();
670 let mut vault_balance = track
671 .read_substate(&node_id, MAIN_BASE_PARTITION, &substate_key)
672 .unwrap()
673 .as_typed::<FungibleVaultBalanceFieldSubstate>()
674 .unwrap()
675 .into_payload()
676 .into_unique_version();
677 vault_balance.put(LiquidFungibleResource::new(amount));
678 let updated_substate_content =
679 FungibleVaultBalanceFieldPayload::from_content_source(vault_balance)
680 .into_unlocked_substate();
681 track
682 .set_substate(
683 node_id,
684 MAIN_BASE_PARTITION,
685 substate_key,
686 IndexedScryptoValue::from_typed(&updated_substate_content),
687 &mut |_| -> Result<(), ()> { Ok(()) },
688 )
689 .unwrap();
690 events.push((
691 EventTypeIdentifier(
692 Emitter::Method(node_id, ModuleId::Main),
693 DepositEvent::EVENT_NAME.to_string(),
694 ),
695 scrypto_encode(&DepositEvent { amount }).unwrap(),
696 ));
697 }
698
699 let (fee_reserve_finalization, costing_parameters, transaction_costing_parameters) =
701 fee_reserve.finalize();
702 let mut fee_payments: IndexMap<NodeId, Decimal> = index_map_new();
703 let mut required = fee_reserve_finalization.total_cost();
704 let mut collected_fees = LiquidFungibleResource::new(Decimal::ZERO);
705 for (vault_id, mut locked, contingent) in
706 fee_reserve_finalization.locked_fees.iter().cloned().rev()
707 {
708 let amount = if contingent {
709 if is_success {
710 Decimal::min(locked.amount(), required)
711 } else {
712 Decimal::zero()
713 }
714 } else {
715 Decimal::min(locked.amount(), required)
716 };
717
718 collected_fees.put(locked.take_by_amount(amount).unwrap());
723 required = required.checked_sub(amount).unwrap();
724
725 let mut vault_balance = track
727 .read_substate(
728 &vault_id,
729 MAIN_BASE_PARTITION,
730 &FungibleVaultField::Balance.into(),
731 )
732 .unwrap()
733 .as_typed::<FungibleVaultBalanceFieldSubstate>()
734 .unwrap()
735 .into_payload()
736 .into_unique_version();
737 vault_balance.put(locked);
738 let updated_substate_content =
739 FungibleVaultBalanceFieldPayload::from_content_source(vault_balance)
740 .into_unlocked_substate();
741 track
742 .set_substate(
743 vault_id,
744 MAIN_BASE_PARTITION,
745 FungibleVaultField::Balance.into(),
746 IndexedScryptoValue::from_typed(&updated_substate_content),
747 &mut |_| -> Result<(), ()> { Ok(()) },
748 )
749 .unwrap();
750
751 let entry = fee_payments.entry(vault_id).or_default();
753 *entry = entry.checked_add(amount).unwrap();
754
755 events.push((
756 EventTypeIdentifier(
757 Emitter::Method(vault_id, ModuleId::Main),
758 PayFeeEvent::EVENT_NAME.to_string(),
759 ),
760 scrypto_encode(&PayFeeEvent { amount }).unwrap(),
761 ));
762 }
763 let free_credit = transaction_costing_parameters.free_credit_in_xrd;
765 if free_credit.is_positive() {
766 let amount = Decimal::min(free_credit, required);
767 collected_fees.put(LiquidFungibleResource::new(amount));
768 required = required.checked_sub(amount).unwrap();
769 }
770
771 let to_proposer = fee_reserve_finalization.to_proposer_amount();
772 let to_validator_set = fee_reserve_finalization.to_validator_set_amount();
773 let to_burn = fee_reserve_finalization.to_burn_amount();
774
775 assert!(
777 fee_reserve_finalization.total_bad_debt_in_xrd == Decimal::ZERO,
778 "Bad debt is non-zero: {}",
779 fee_reserve_finalization.total_bad_debt_in_xrd
780 );
781 assert!(
782 required == Decimal::ZERO,
783 "Locked fee does not cover transaction cost: {} required",
784 required
785 );
786 let remaining_collected_fees = collected_fees.amount().checked_sub(fee_reserve_finalization.total_royalty_cost_in_xrd ).unwrap();
787 let to_distribute = to_proposer
788 .checked_add(to_validator_set)
789 .unwrap()
790 .checked_add(to_burn)
791 .unwrap();
792 assert!(
793 remaining_collected_fees == to_distribute,
794 "Remaining collected fee isn't equal to amount to distribute (proposer/validator set/burn): {} != {}",
795 remaining_collected_fees,
796 to_distribute,
797 );
798
799 if !to_proposer.is_zero() || !to_validator_set.is_zero() {
800 let substate: FieldSubstate<ConsensusManagerStateFieldPayload> = track
803 .read_substate(
804 CONSENSUS_MANAGER.as_node_id(),
805 MAIN_BASE_PARTITION,
806 &ConsensusManagerField::State.into(),
807 )
808 .unwrap()
809 .as_typed()
810 .unwrap();
811 let current_leader = substate.into_payload().into_unique_version().current_leader;
812
813 let substate: FieldSubstate<ConsensusManagerValidatorRewardsFieldPayload> = track
815 .read_substate(
816 CONSENSUS_MANAGER.as_node_id(),
817 MAIN_BASE_PARTITION,
818 &ConsensusManagerField::ValidatorRewards.into(),
819 )
820 .unwrap()
821 .as_typed()
822 .unwrap();
823
824 let mut rewards = substate.into_payload().into_unique_version();
825
826 if let Some(current_leader) = current_leader {
827 let entry = rewards.proposer_rewards.entry(current_leader).or_default();
828 *entry = entry.checked_add(to_proposer).unwrap()
829 } else {
830 };
832 let vault_node_id = rewards.rewards_vault.0 .0;
833
834 track
835 .set_substate(
836 CONSENSUS_MANAGER.into_node_id(),
837 MAIN_BASE_PARTITION,
838 ConsensusManagerField::ValidatorRewards.into(),
839 IndexedScryptoValue::from_typed(&FieldSubstate::new_unlocked_field(
840 ConsensusManagerValidatorRewardsFieldPayload::from_content_source(rewards),
841 )),
842 &mut |_| -> Result<(), ()> { Ok(()) },
843 )
844 .unwrap();
845
846 let total_amount = to_proposer.checked_add(to_validator_set).unwrap();
848 let mut vault_balance = track
849 .read_substate(
850 &vault_node_id,
851 MAIN_BASE_PARTITION,
852 &FungibleVaultField::Balance.into(),
853 )
854 .unwrap()
855 .as_typed::<FungibleVaultBalanceFieldSubstate>()
856 .unwrap()
857 .into_payload()
858 .into_unique_version();
859 vault_balance.put(collected_fees.take_by_amount(total_amount).unwrap());
860 let updated_substate_content =
861 FungibleVaultBalanceFieldPayload::from_content_source(vault_balance)
862 .into_unlocked_substate();
863 track
864 .set_substate(
865 vault_node_id,
866 MAIN_BASE_PARTITION,
867 FungibleVaultField::Balance.into(),
868 IndexedScryptoValue::from_typed(&updated_substate_content),
869 &mut |_| -> Result<(), ()> { Ok(()) },
870 )
871 .unwrap();
872
873 events.push((
874 EventTypeIdentifier(
875 Emitter::Method(vault_node_id, ModuleId::Main),
876 DepositEvent::EVENT_NAME.to_string(),
877 ),
878 scrypto_encode(&DepositEvent {
879 amount: total_amount,
880 })
881 .unwrap(),
882 ));
883 }
884
885 if to_burn.is_positive() {
886 events.push((
887 EventTypeIdentifier(
888 Emitter::Method(XRD.into_node_id(), ModuleId::Main),
889 "BurnFungibleResourceEvent".to_string(),
890 ),
891 scrypto_encode(&BurnFungibleResourceEvent { amount: to_burn }).unwrap(),
892 ));
893 }
894
895 (
896 fee_reserve_finalization,
897 fee_payments,
898 events,
899 costing_parameters,
900 transaction_costing_parameters,
901 )
902 }
903
904 fn update_transaction_tracker<S: SubstateDatabase>(
905 track: &mut Track<S>,
906 next_epoch: Epoch,
907 intent_hash_nullifications: Vec<IntentHashNullification>,
908 is_success: bool,
909 ) -> Vec<Nullification> {
910 let mut transaction_tracker = track
915 .read_substate(
916 TRANSACTION_TRACKER.as_node_id(),
917 MAIN_BASE_PARTITION,
918 &TransactionTrackerField::TransactionTracker.into(),
919 )
920 .unwrap()
921 .as_typed::<FieldSubstate<TransactionTrackerSubstate>>()
922 .unwrap()
923 .into_payload()
924 .into_v1();
925
926 let mut performed_nullifications = vec![];
927
928 for intent_hash_nullification in intent_hash_nullifications {
929 let Some(nullification) = Nullification::of_intent(
930 intent_hash_nullification,
931 Epoch::of(transaction_tracker.start_epoch),
932 is_success,
933 ) else {
934 continue;
935 };
936 let (expiry_epoch, hash) = nullification.transaction_tracker_keys();
937 performed_nullifications.push(nullification);
938
939 let partition_number = transaction_tracker.partition_for_expiry_epoch(expiry_epoch)
940 .expect("Validation of the max expiry epoch window combined with the current epoch check on launch should ensure that the expiry epoch is in range for the transaction tracker");
941
942 track
944 .set_substate(
945 TRANSACTION_TRACKER.into_node_id(),
946 PartitionNumber(partition_number),
947 SubstateKey::Map(scrypto_encode(&hash).unwrap()),
948 IndexedScryptoValue::from_typed(&KeyValueEntrySubstate::V1(
949 KeyValueEntrySubstateV1 {
950 value: Some(if is_success {
951 TransactionStatus::V1(TransactionStatusV1::CommittedSuccess)
952 } else {
953 TransactionStatus::V1(TransactionStatusV1::CommittedFailure)
954 }),
955 lock_status: LockStatus::Unlocked,
957 },
958 )),
959 &mut |_| -> Result<(), ()> { Ok(()) },
960 )
961 .unwrap();
962 }
963
964 if next_epoch.number()
972 >= transaction_tracker.start_epoch + transaction_tracker.epochs_per_partition
973 {
974 let discarded_partition = transaction_tracker.advance();
975 track.delete_partition(
976 TRANSACTION_TRACKER.as_node_id(),
977 PartitionNumber(discarded_partition),
978 );
979 }
980 track
981 .set_substate(
982 TRANSACTION_TRACKER.into_node_id(),
983 MAIN_BASE_PARTITION,
984 TransactionTrackerField::TransactionTracker.into(),
985 IndexedScryptoValue::from_typed(&FieldSubstate::new_unlocked_field(
986 TransactionTrackerSubstate::V1(transaction_tracker),
987 )),
988 &mut |_| -> Result<(), ()> { Ok(()) },
989 )
990 .unwrap();
991
992 performed_nullifications
993 }
994
995 #[cfg(not(feature = "alloc"))]
996 fn print_execution_summary(receipt: &TransactionReceipt) {
997 if let Some(fee_details) = &receipt.fee_details {
1000 println!("{:-^120}", "Execution Cost Breakdown");
1001 for (k, v) in &fee_details.execution_cost_breakdown {
1002 println!("{:<75}: {:>25}", k, v.to_string());
1003 }
1004
1005 println!("{:-^120}", "Finalization Cost Breakdown");
1006 for (k, v) in &fee_details.finalization_cost_breakdown {
1007 println!("{:<75}: {:>25}", k, v.to_string());
1008 }
1009 }
1010
1011 println!("{:-^120}", "Fee Summary");
1012 println!(
1013 "{:<40}: {:>25}",
1014 "Execution Cost Units Consumed",
1015 receipt
1016 .fee_summary
1017 .total_execution_cost_units_consumed
1018 .to_string()
1019 );
1020 println!(
1021 "{:<40}: {:>25}",
1022 "Finalization Cost Units Consumed",
1023 receipt
1024 .fee_summary
1025 .total_finalization_cost_units_consumed
1026 .to_string()
1027 );
1028 println!(
1029 "{:<40}: {:>25}",
1030 "Execution Cost in XRD",
1031 receipt.fee_summary.total_execution_cost_in_xrd.to_string()
1032 );
1033 println!(
1034 "{:<40}: {:>25}",
1035 "Finalization Cost in XRD",
1036 receipt
1037 .fee_summary
1038 .total_finalization_cost_in_xrd
1039 .to_string()
1040 );
1041 println!(
1042 "{:<40}: {:>25}",
1043 "Tipping Cost in XRD",
1044 receipt.fee_summary.total_tipping_cost_in_xrd.to_string()
1045 );
1046 println!(
1047 "{:<40}: {:>25}",
1048 "Storage Cost in XRD",
1049 receipt.fee_summary.total_storage_cost_in_xrd.to_string()
1050 );
1051 println!(
1052 "{:<40}: {:>25}",
1053 "Royalty Costs in XRD",
1054 receipt.fee_summary.total_royalty_cost_in_xrd.to_string()
1055 );
1056
1057 match &receipt.result {
1058 TransactionResult::Commit(commit) => {
1059 println!("{:-^120}", "Application Logs");
1060 for (level, message) in &commit.application_logs {
1061 println!("[{}] {}", level, message);
1062 }
1063
1064 println!("{:-^120}", "Outcome");
1065 println!(
1066 "{}",
1067 match &commit.outcome {
1068 TransactionOutcome::Success(_) => "Success".to_string(),
1069 TransactionOutcome::Failure(error) => format!("Failure: {:?}", error),
1070 }
1071 );
1072 }
1073 TransactionResult::Reject(e) => {
1074 println!("{:-^120}", "Transaction Rejected");
1075 println!("{:?}", e.reason);
1076 }
1077 TransactionResult::Abort(e) => {
1078 println!("{:-^120}", "Transaction Aborted");
1079 println!("{:?}", e);
1080 }
1081 }
1082 println!("{:-^120}", "Finish");
1083 }
1084
1085 fn reference_check(
1086 references: &IndexSet<Reference>,
1087 modules: &mut SystemModuleMixer,
1088 store: &mut impl CommitableSubstateStore,
1089 always_visible_global_nodes: &IndexSet<NodeId>,
1090 ) -> Result<(IndexSet<GlobalAddress>, IndexSet<InternalAddress>), BootloadingError> {
1091 let mut global_addresses = indexset!();
1092 let mut direct_accesses = indexset!();
1093
1094 for reference in references.iter() {
1096 let node_id = &reference.0;
1097
1098 if always_visible_global_nodes.contains(node_id) {
1099 continue;
1101 }
1102
1103 if node_id.is_global_preallocated() {
1104 global_addresses.insert(GlobalAddress::new_or_panic((*node_id).into()));
1106 continue;
1107 }
1108
1109 let ref_value = store
1110 .read_substate(
1111 node_id,
1112 TYPE_INFO_FIELD_PARTITION,
1113 &TypeInfoField::TypeInfo.into(),
1114 )
1115 .ok_or_else(|| BootloadingError::ReferencedNodeDoesNotExist((*node_id).into()))?;
1116
1117 match Self::verify_boot_ref_value(modules, node_id, ref_value)? {
1118 StableReferenceType::Global => {
1119 global_addresses.insert(GlobalAddress::new_or_panic((*node_id).into()));
1120 }
1121 StableReferenceType::DirectAccess => {
1122 direct_accesses.insert(InternalAddress::new_or_panic((*node_id).into()));
1123 }
1124 }
1125 }
1126
1127 Ok((global_addresses, direct_accesses))
1128 }
1129
1130 fn build_call_frame_inits_with_reference_check<'a>(
1132 intents: impl Iterator<Item = &'a ExecutableIntent>,
1133 modules: &mut SystemModuleMixer,
1134 store: &mut impl CommitableSubstateStore,
1135 always_visible_global_nodes: &'static IndexSet<NodeId>,
1136 ) -> Result<Vec<CallFrameInit<Actor>>, BootloadingError> {
1137 let mut init_call_frames = vec![];
1138 for (index, intent) in intents.enumerate() {
1139 let (global_addresses, direct_accesses) = Self::reference_check(
1140 &intent.references,
1141 modules,
1142 store,
1143 always_visible_global_nodes,
1144 )?;
1145
1146 init_call_frames.push(CallFrameInit {
1147 data: Actor::Root,
1148 global_addresses,
1149 direct_accesses,
1150 always_visible_global_nodes,
1151 stack_id: index,
1152 });
1153 }
1154
1155 Ok(init_call_frames)
1156 }
1157
1158 fn verify_boot_ref_value(
1159 modules: &mut SystemModuleMixer,
1160 node_id: &NodeId,
1161 ref_value: &IndexedScryptoValue,
1162 ) -> Result<StableReferenceType, BootloadingError> {
1163 if let Some(costing) = modules.costing_mut() {
1164 let io_access = IOAccess::ReadFromDb(
1165 CanonicalSubstateKey {
1166 node_id: *node_id,
1167 partition_number: TYPE_INFO_FIELD_PARTITION,
1168 substate_key: SubstateKey::Field(TypeInfoField::TypeInfo.field_index()),
1169 },
1170 ref_value.len(),
1171 );
1172 let event = CheckReferenceEvent::IOAccess(&io_access);
1173
1174 costing
1175 .apply_deferred_execution_cost(ExecutionCostingEntry::CheckReference {
1176 event: &event,
1177 })
1178 .map_err(BootloadingError::FailedToApplyDeferredCosts)?;
1179 }
1180
1181 let type_substate: TypeInfoSubstate = ref_value.as_typed().unwrap();
1182 match &type_substate {
1183 TypeInfoSubstate::Object(
1184 info @ ObjectInfo {
1185 blueprint_info: BlueprintInfo { blueprint_id, .. },
1186 ..
1187 },
1188 ) => {
1189 if info.is_global() {
1190 Ok(StableReferenceType::Global)
1191 } else if blueprint_id.package_address.eq(&RESOURCE_PACKAGE)
1192 && (blueprint_id.blueprint_name.eq(FUNGIBLE_VAULT_BLUEPRINT)
1193 || blueprint_id.blueprint_name.eq(NON_FUNGIBLE_VAULT_BLUEPRINT))
1194 {
1195 Ok(StableReferenceType::DirectAccess)
1196 } else {
1197 Err(BootloadingError::ReferencedNodeDoesNotAllowDirectAccess(
1198 (*node_id).into(),
1199 ))
1200 }
1201 }
1202 _ => Err(BootloadingError::ReferencedNodeIsNotAnObject(
1203 (*node_id).into(),
1204 )),
1205 }
1206 }
1207
1208 fn create_non_commit_receipt(
1209 result: TransactionResult,
1210 print_execution_summary: bool,
1211 costing_module: CostingModule,
1212 ) -> TransactionReceipt {
1213 let (fee_reserve, cost_breakdown, detailed_cost_breakdown) =
1214 costing_module.unpack_for_receipt();
1215 let (finalization_summary, costing_parameters, transaction_costing_parameters) =
1216 fee_reserve.finalize();
1217 let fee_summary = finalization_summary.into();
1218
1219 Self::create_receipt_internal(
1220 print_execution_summary,
1221 costing_parameters,
1222 cost_breakdown,
1223 detailed_cost_breakdown,
1224 transaction_costing_parameters,
1225 fee_summary,
1226 result,
1227 )
1228 }
1229
1230 fn create_rejection_receipt(
1231 reason: impl Into<RejectionReason>,
1232 modules: SystemModuleMixer,
1233 ) -> TransactionReceipt {
1234 Self::create_non_commit_receipt(
1235 TransactionResult::Reject(RejectResult {
1236 reason: reason.into(),
1237 }),
1238 modules.is_kernel_trace_enabled(),
1239 modules.unpack_costing(),
1240 )
1241 }
1242
1243 fn create_abort_receipt(
1244 reason: impl Into<AbortReason>,
1245 modules: SystemModuleMixer,
1246 ) -> TransactionReceipt {
1247 Self::create_non_commit_receipt(
1248 TransactionResult::Abort(AbortResult {
1249 reason: reason.into(),
1250 }),
1251 modules.is_kernel_trace_enabled(),
1252 modules.unpack_costing(),
1253 )
1254 }
1255
1256 fn create_commit_receipt<S: SubstateDatabase>(
1257 outcome: Result<Vec<InstructionOutput>, RuntimeError>,
1258 mut track: Track<S>,
1259 modules: SystemModuleMixer,
1260 system_finalization: SystemFinalization,
1261 ) -> TransactionReceipt {
1262 let print_execution_summary = modules.is_kernel_trace_enabled();
1263 let execution_trace_enabled = modules.is_execution_trace_enabled();
1264 let (costing_module, runtime_module, execution_trace_module) = modules.unpack();
1265 let (mut fee_reserve, cost_breakdown, detailed_cost_breakdown) =
1266 costing_module.unpack_for_receipt();
1267 let is_success = outcome.is_ok();
1268
1269 if !is_success {
1271 fee_reserve.revert_royalty();
1272 track.revert_non_force_write_changes();
1273 }
1274
1275 let (
1277 fee_reserve_finalization,
1278 paying_vaults,
1279 finalization_events,
1280 costing_parameters,
1281 transaction_costing_parameters,
1282 ) = Self::finalize_fees_for_commit(&mut track, fee_reserve, is_success);
1283
1284 let fee_destination = FeeDestination {
1285 to_proposer: fee_reserve_finalization.to_proposer_amount(),
1286 to_validator_set: fee_reserve_finalization.to_validator_set_amount(),
1287 to_burn: fee_reserve_finalization.to_burn_amount(),
1288 to_royalty_recipients: fee_reserve_finalization.royalty_cost_breakdown.clone(),
1289 };
1290
1291 let performed_nullifications =
1293 if let Some(next_epoch) = Self::read_epoch_uncosted(&mut track) {
1294 Self::update_transaction_tracker(
1295 &mut track,
1296 next_epoch,
1297 system_finalization.intent_nullifications,
1298 is_success,
1299 )
1300 } else {
1301 vec![]
1302 };
1303
1304 let (mut application_events, application_logs) = runtime_module.finalize(is_success);
1306 application_events.extend(finalization_events);
1307
1308 let (tracked_substates, substate_db) = {
1310 match track.finalize() {
1311 Ok(result) => result,
1312 Err(TrackFinalizeError::TransientSubstateOwnsNode) => {
1313 panic!("System invariants should prevent transient substate from owning nodes");
1314 }
1315 }
1316 };
1317
1318 let (new_node_ids, state_updates) = tracked_substates.to_state_updates();
1321
1322 let system_structure =
1324 SystemStructure::resolve(substate_db, &state_updates, &application_events);
1325 let state_update_summary =
1326 StateUpdateSummary::new(substate_db, new_node_ids, &state_updates);
1327
1328 if transaction_costing_parameters.free_credit_in_xrd.is_zero() {
1330 reconcile_resource_state_and_events(
1331 &state_update_summary,
1332 &application_events,
1333 SystemDatabaseReader::new_with_overlay(substate_db, &state_updates),
1334 );
1335 }
1336
1337 let execution_trace = if execution_trace_enabled {
1338 Some(execution_trace_module.finalize(&paying_vaults, is_success))
1339 } else {
1340 None
1341 };
1342
1343 let fee_summary = fee_reserve_finalization.into();
1344 let result = TransactionResult::Commit(CommitResult {
1345 state_updates,
1346 state_update_summary,
1347 fee_source: FeeSource { paying_vaults },
1348 fee_destination,
1349 outcome: match outcome {
1350 Ok(o) => TransactionOutcome::Success(o),
1351 Err(e) => TransactionOutcome::Failure(e),
1352 },
1353 application_events,
1354 application_logs,
1355 system_structure,
1356 execution_trace,
1357 performed_nullifications,
1358 });
1359
1360 Self::create_receipt_internal(
1361 print_execution_summary,
1362 costing_parameters,
1363 cost_breakdown,
1364 detailed_cost_breakdown,
1365 transaction_costing_parameters,
1366 fee_summary,
1367 result,
1368 )
1369 }
1370
1371 #[cfg_attr(feature = "alloc", allow(unused_variables))]
1372 fn create_receipt_internal(
1373 print_execution_summary: bool,
1374 costing_parameters: CostingParameters,
1375 cost_breakdown: Option<CostBreakdown>,
1376 detailed_cost_breakdown: Option<DetailedCostBreakdown>,
1377 transaction_costing_parameters: TransactionCostingParameters,
1378 fee_summary: TransactionFeeSummary,
1379 result: TransactionResult,
1380 ) -> TransactionReceipt {
1381 let transaction_costing_parameters = TransactionCostingParametersReceiptV2 {
1382 tip_proportion: transaction_costing_parameters.tip.proportion(),
1383 free_credit_in_xrd: transaction_costing_parameters.free_credit_in_xrd,
1384 };
1385
1386 let fee_details = cost_breakdown.map(|b| TransactionFeeDetails {
1387 execution_cost_breakdown: b.execution_cost_breakdown.into_iter().collect(),
1388 finalization_cost_breakdown: b.finalization_cost_breakdown.into_iter().collect(),
1389 });
1390
1391 let debug_information = detailed_cost_breakdown.map(|b| TransactionDebugInformation {
1392 detailed_execution_cost_breakdown: b.detailed_execution_cost_breakdown,
1393 });
1394
1395 let receipt = TransactionReceipt {
1396 costing_parameters,
1397 transaction_costing_parameters,
1398 fee_summary,
1399 fee_details,
1400 result,
1401 resources_usage: None,
1402 debug_information,
1403 };
1404
1405 #[cfg(not(feature = "alloc"))]
1407 if print_execution_summary {
1408 Self::print_execution_summary(&receipt);
1409 }
1410
1411 receipt
1412 }
1413
1414 fn resolve_modules(
1415 executable: &ExecutableTransaction,
1416 init_input: SystemSelfInit,
1417 ) -> Result<SystemModuleMixer, TransactionReceiptV1> {
1418 let mut system_parameters = init_input.system_parameters;
1419 let system_logic_version = init_input.system_logic_version;
1420
1421 let mut enabled_modules = {
1422 let mut enabled_modules = EnabledModules::AUTH | EnabledModules::TRANSACTION_RUNTIME;
1423 if !executable.disable_limits_and_costing_modules() {
1424 enabled_modules |= EnabledModules::LIMITS;
1425 enabled_modules |= EnabledModules::COSTING;
1426 };
1427
1428 if init_input.enable_kernel_trace {
1429 enabled_modules |= EnabledModules::KERNEL_TRACE;
1430 }
1431 if init_input.execution_trace.is_some() {
1432 enabled_modules |= EnabledModules::EXECUTION_TRACE;
1433 }
1434
1435 enabled_modules
1436 };
1437
1438 let mut abort_when_loan_repaid = false;
1439
1440 if let Some(system_overrides) = &init_input.system_overrides {
1442 if let Some(costing_override) = &system_overrides.costing_parameters {
1443 system_parameters.costing_parameters = *costing_override;
1444 }
1445
1446 if let Some(limits_override) = &system_overrides.limit_parameters {
1447 system_parameters.limit_parameters = *limits_override;
1448 }
1449
1450 if let Some(network_definition) = &system_overrides.network_definition {
1451 system_parameters.network_definition = network_definition.clone();
1452 }
1453
1454 if system_overrides.disable_auth {
1455 enabled_modules.remove(EnabledModules::AUTH);
1456 }
1457
1458 if system_overrides.disable_costing {
1459 enabled_modules.remove(EnabledModules::COSTING);
1460 }
1461
1462 if system_overrides.disable_limits {
1463 enabled_modules.remove(EnabledModules::LIMITS);
1464 }
1465
1466 if system_overrides.abort_when_loan_repaid {
1467 abort_when_loan_repaid = true;
1468 }
1469 }
1470
1471 let costing_module = CostingModule {
1472 current_depth: 0,
1473 fee_reserve: SystemLoanFeeReserve::new(
1474 system_parameters.costing_parameters,
1475 executable.costing_parameters().clone(),
1476 abort_when_loan_repaid,
1477 ),
1478 fee_table: FeeTable::new(system_logic_version),
1479 tx_payload_len: executable.payload_size(),
1480 tx_num_of_signature_validations: executable.num_of_signature_validations(),
1481 config: system_parameters.costing_module_config,
1482 cost_breakdown: if init_input.enable_cost_breakdown {
1483 Some(Default::default())
1484 } else {
1485 None
1486 },
1487 detailed_cost_breakdown: if init_input.enable_debug_information {
1488 Some(Default::default())
1489 } else {
1490 None
1491 },
1492 on_apply_cost: Default::default(),
1493 };
1494
1495 let auth_module = system_logic_version
1496 .create_auth_module(executable)
1497 .map_err(|reason| {
1498 let print_execution_summary =
1499 enabled_modules.contains(EnabledModules::KERNEL_TRACE);
1500 Self::create_non_commit_receipt(
1501 TransactionResult::Reject(RejectResult { reason }),
1502 print_execution_summary,
1503 costing_module.clone(),
1504 )
1505 })?;
1506
1507 let module_mixer = SystemModuleMixer::new(
1508 enabled_modules,
1509 KernelTraceModule,
1510 TransactionRuntimeModule::new(
1511 system_parameters.network_definition,
1512 *executable.unique_hash(),
1513 ),
1514 auth_module,
1515 LimitsModule::from_params(system_parameters.limit_parameters),
1516 costing_module,
1517 ExecutionTraceModule::new(init_input.execution_trace.unwrap_or(0)),
1518 );
1519
1520 Ok(module_mixer)
1521 }
1522}
1523
1524impl<V: SystemCallbackObject> KernelTransactionExecutor for System<V> {
1525 type Init = SystemInit<V::Init>;
1526 type Executable = ExecutableTransaction;
1527 type ExecutionOutput = Vec<InstructionOutput>;
1528 type Receipt = TransactionReceipt;
1529
1530 fn init(
1531 store: &mut impl CommitableSubstateStore,
1532 executable: &ExecutableTransaction,
1533 init_input: Self::Init,
1534 always_visible_global_nodes: &'static IndexSet<NodeId>,
1535 ) -> Result<(Self, Vec<CallFrameInit<Actor>>), Self::Receipt> {
1536 #[cfg(not(feature = "alloc"))]
1538 if init_input.self_init.enable_kernel_trace {
1539 Self::print_executable(executable);
1540 }
1541
1542 let logic_version = init_input.self_init.system_logic_version;
1543 let mut modules = Self::resolve_modules(executable, init_input.self_init)?;
1544
1545 let callback = match V::init(init_input.callback_init) {
1547 Ok(callback) => callback,
1548 Err(error) => return Err(Self::create_rejection_receipt(error, modules)),
1549 };
1550
1551 match modules.init() {
1552 Ok(()) => {}
1553 Err(error) => return Err(Self::create_rejection_receipt(error, modules)),
1554 }
1555
1556 if let Some(current_epoch) = Self::read_epoch_uncosted(store) {
1559 if let Some(range) = executable.overall_epoch_range() {
1561 let epoch_validation_result = Self::validate_epoch_range(
1562 current_epoch,
1563 range.start_epoch_inclusive,
1564 range.end_epoch_exclusive,
1565 );
1566 match epoch_validation_result {
1567 Ok(()) => {}
1568 Err(error) => return Err(Self::create_rejection_receipt(error, modules)),
1569 }
1570 }
1571 }
1572
1573 for hash_nullification in executable.intent_hash_nullifications() {
1574 let intent_hash_validation_result = match hash_nullification {
1575 IntentHashNullification::TransactionIntent {
1576 intent_hash,
1577 expiry_epoch,
1578 } => Self::validate_intent_hash_uncosted(
1579 store,
1580 IntentHash::Transaction(*intent_hash),
1581 *expiry_epoch,
1582 ),
1583 IntentHashNullification::SimulatedTransactionIntent { .. } => {
1584 Ok(())
1586 }
1587 IntentHashNullification::Subintent {
1588 intent_hash,
1589 expiry_epoch,
1590 } => Self::validate_intent_hash_uncosted(
1591 store,
1592 IntentHash::Subintent(*intent_hash),
1593 *expiry_epoch,
1594 ),
1595 IntentHashNullification::SimulatedSubintent { .. } => {
1596 Ok(())
1598 }
1599 }
1600 .and_then(|_| {
1601 let charge_for_nullification_check = match hash_nullification {
1602 IntentHashNullification::TransactionIntent { .. }
1603 | IntentHashNullification::SimulatedTransactionIntent { .. } => {
1604 logic_version.should_charge_for_transaction_intent()
1605 }
1606 IntentHashNullification::Subintent { .. }
1607 | IntentHashNullification::SimulatedSubintent { .. } => true,
1608 };
1609
1610 if charge_for_nullification_check {
1611 if let Some(costing) = modules.costing_mut() {
1612 return costing
1613 .apply_deferred_execution_cost(
1614 ExecutionCostingEntry::CheckIntentValidity,
1615 )
1616 .map_err(|e| {
1617 RejectionReason::BootloadingError(
1618 BootloadingError::FailedToApplyDeferredCosts(e),
1619 )
1620 });
1621 }
1622 }
1623
1624 Ok(())
1625 });
1626
1627 match intent_hash_validation_result {
1628 Ok(()) => {}
1629 Err(error) => return Err(Self::create_rejection_receipt(error, modules)),
1630 }
1631 }
1632
1633 if let Some(range) = executable.overall_proposer_timestamp_range() {
1634 if range.start_timestamp_inclusive.is_some() || range.end_timestamp_exclusive.is_some()
1635 {
1636 let substate: ConsensusManagerProposerMilliTimestampFieldSubstate = store
1637 .read_substate(
1638 CONSENSUS_MANAGER.as_node_id(),
1639 MAIN_BASE_PARTITION,
1640 &ConsensusManagerField::ProposerMilliTimestamp.into(),
1641 )
1642 .unwrap()
1643 .as_typed()
1644 .unwrap();
1645 let current_time = Instant::new(
1646 substate
1647 .into_payload()
1648 .fully_update_and_into_latest_version()
1649 .epoch_milli
1650 / 1000,
1651 );
1652 if let Some(start_timestamp_inclusive) = range.start_timestamp_inclusive {
1653 if current_time < start_timestamp_inclusive {
1654 return Err(Self::create_rejection_receipt(
1655 RejectionReason::TransactionProposerTimestampNotYetValid {
1656 valid_from_inclusive: start_timestamp_inclusive,
1657 current_time,
1658 },
1659 modules,
1660 ));
1661 }
1662 }
1663
1664 if let Some(end_timestamp_exclusive) = range.end_timestamp_exclusive {
1665 if current_time >= end_timestamp_exclusive {
1666 return Err(Self::create_rejection_receipt(
1667 RejectionReason::TransactionProposerTimestampNoLongerValid {
1668 valid_to_exclusive: end_timestamp_exclusive,
1669 current_time,
1670 },
1671 modules,
1672 ));
1673 }
1674 }
1675
1676 if let Some(costing) = modules.costing_mut() {
1677 if let Err(error) =
1678 costing.apply_deferred_execution_cost(ExecutionCostingEntry::CheckTimestamp)
1679 {
1680 return Err(Self::create_rejection_receipt(
1681 RejectionReason::BootloadingError(
1682 BootloadingError::FailedToApplyDeferredCosts(error),
1683 ),
1684 modules,
1685 ));
1686 }
1687 }
1688 }
1689 }
1690
1691 let call_frame_inits = match Self::build_call_frame_inits_with_reference_check(
1692 executable.all_intents(),
1693 &mut modules,
1694 store,
1695 always_visible_global_nodes,
1696 ) {
1697 Ok(call_frame_inits) => call_frame_inits,
1698 Err(error) => return Err(Self::create_rejection_receipt(error, modules)),
1699 };
1700
1701 let system = System::new(
1702 logic_version,
1703 callback,
1704 modules,
1705 SystemFinalization {
1706 intent_nullifications: executable.intent_hash_nullifications().to_vec(),
1707 },
1708 );
1709
1710 Ok((system, call_frame_inits))
1711 }
1712
1713 fn execute<Y: SystemBasedKernelApi>(
1714 api: &mut Y,
1715 executable: &ExecutableTransaction,
1716 ) -> Result<Vec<InstructionOutput>, RuntimeError> {
1717 let mut system_service = SystemService::new(api);
1718
1719 let mut global_address_reservations = Vec::new();
1721 for PreAllocatedAddress {
1722 blueprint_id,
1723 address,
1724 } in executable.pre_allocated_addresses()
1725 {
1726 let global_address_reservation =
1727 system_service.prepare_global_address(blueprint_id.clone(), *address)?;
1728 global_address_reservations.push(global_address_reservation);
1729 }
1730
1731 let system_logic_version = system_service.system().versioned_system_logic;
1732
1733 let output = system_logic_version.execute_transaction(
1734 api,
1735 executable,
1736 global_address_reservations,
1737 )?;
1738
1739 Ok(output)
1740 }
1741
1742 fn finalize(
1743 &mut self,
1744 executable: &ExecutableTransaction,
1745 info: StoreCommitInfo,
1746 ) -> Result<(), RuntimeError> {
1747 self.modules.on_teardown()?;
1748
1749 for store_commit in &info {
1752 self.modules
1753 .apply_finalization_cost(FinalizationCostingEntry::CommitStateUpdates {
1754 store_commit,
1755 })
1756 .map_err(RuntimeError::FinalizationCostingError)?;
1757 }
1758 self.modules
1759 .apply_finalization_cost(FinalizationCostingEntry::CommitEvents {
1760 events: &self.modules.events().clone(),
1761 })
1762 .map_err(RuntimeError::FinalizationCostingError)?;
1763 self.modules
1764 .apply_finalization_cost(FinalizationCostingEntry::CommitLogs {
1765 logs: &self.modules.logs().clone(),
1766 })
1767 .map_err(RuntimeError::FinalizationCostingError)?;
1768 let num_of_intent_statuses = executable
1769 .intent_hash_nullifications()
1770 .iter()
1771 .map(|n| match n {
1772 IntentHashNullification::TransactionIntent { .. }
1773 | IntentHashNullification::SimulatedTransactionIntent { .. } => {
1774 if self
1775 .versioned_system_logic
1776 .should_charge_for_transaction_intent()
1777 {
1778 1
1779 } else {
1780 0
1781 }
1782 }
1783 IntentHashNullification::Subintent { .. }
1784 | IntentHashNullification::SimulatedSubintent { .. } => 1,
1785 })
1786 .sum();
1787 self.modules
1788 .apply_finalization_cost(FinalizationCostingEntry::CommitIntentStatus {
1789 num_of_intent_statuses,
1790 })
1791 .map_err(RuntimeError::FinalizationCostingError)?;
1792
1793 for store_commit in &info {
1795 self.modules
1796 .apply_storage_cost(StorageType::State, store_commit.len_increase())
1797 .map_err(RuntimeError::FinalizationCostingError)?;
1798 }
1799
1800 let total_event_size = self.modules.events().iter().map(|x| x.len()).sum();
1802 self.modules
1803 .apply_storage_cost(StorageType::Archive, total_event_size)
1804 .map_err(RuntimeError::FinalizationCostingError)?;
1805
1806 let total_log_size = self.modules.logs().iter().map(|x| x.1.len()).sum();
1807 self.modules
1808 .apply_storage_cost(StorageType::Archive, total_log_size)
1809 .map_err(RuntimeError::FinalizationCostingError)?;
1810
1811 Ok(())
1812 }
1813
1814 fn create_receipt<S: SubstateDatabase>(
1815 mut self,
1816 track: Track<S>,
1817 interpretation_result: Result<Vec<InstructionOutput>, TransactionExecutionError>,
1818 ) -> TransactionReceipt {
1819 #[cfg(feature = "std")]
1823 if let Err(TransactionExecutionError::RuntimeError(RuntimeError::SystemError(
1824 SystemError::SystemPanic(..),
1825 ))) = interpretation_result
1826 {
1827 panic!("An error has occurred in the system layer or below and thus the transaction executor has panicked. Error: \"{interpretation_result:?}\"")
1828 }
1829
1830 #[cfg(not(feature = "alloc"))]
1831 if self.modules.is_kernel_trace_enabled() {
1832 println!("{:-^120}", "Interpretation Results");
1833 println!("{:?}", interpretation_result);
1834 }
1835
1836 let result_type = Self::determine_result_type(
1837 interpretation_result,
1838 &mut self.modules.costing_mut_even_if_disabled().fee_reserve,
1839 );
1840
1841 match result_type {
1842 TransactionResultType::Reject(reason) => {
1843 Self::create_rejection_receipt(reason, self.modules)
1844 }
1845 TransactionResultType::Abort(reason) => {
1846 Self::create_abort_receipt(reason, self.modules)
1847 }
1848 TransactionResultType::Commit(outcome) => {
1849 Self::create_commit_receipt(outcome, track, self.modules, self.finalization)
1850 }
1851 }
1852 }
1853}
1854
1855impl<V: SystemCallbackObject> KernelCallbackObject for System<V> {
1856 type LockData = SystemLockData;
1857 type CallFrameData = Actor;
1858
1859 fn on_pin_node<Y: KernelInternalApi<System = Self>>(
1860 node_id: &NodeId,
1861 api: &mut Y,
1862 ) -> Result<(), RuntimeError> {
1863 SystemModuleMixer::on_pin_node(api, node_id)
1864 }
1865
1866 fn on_create_node<Y: KernelInternalApi<System = Self>>(
1867 event: CreateNodeEvent,
1868 api: &mut Y,
1869 ) -> Result<(), RuntimeError> {
1870 SystemModuleMixer::on_create_node(api, &event)
1871 }
1872
1873 fn on_drop_node<Y: KernelInternalApi<System = Self>>(
1874 event: DropNodeEvent,
1875 api: &mut Y,
1876 ) -> Result<(), RuntimeError> {
1877 SystemModuleMixer::on_drop_node(api, &event)
1878 }
1879
1880 fn on_move_module<Y: KernelInternalApi<System = Self>>(
1881 event: MoveModuleEvent,
1882 api: &mut Y,
1883 ) -> Result<(), RuntimeError> {
1884 SystemModuleMixer::on_move_module(api, &event)
1885 }
1886
1887 fn on_open_substate<Y: KernelInternalApi<System = Self>>(
1888 event: OpenSubstateEvent,
1889 api: &mut Y,
1890 ) -> Result<(), RuntimeError> {
1891 SystemModuleMixer::on_open_substate(api, &event)
1892 }
1893
1894 fn on_close_substate<Y: KernelInternalApi<System = Self>>(
1895 event: CloseSubstateEvent,
1896 api: &mut Y,
1897 ) -> Result<(), RuntimeError> {
1898 SystemModuleMixer::on_close_substate(api, &event)
1899 }
1900
1901 fn on_read_substate<Y: KernelInternalApi<System = Self>>(
1902 event: ReadSubstateEvent,
1903 api: &mut Y,
1904 ) -> Result<(), RuntimeError> {
1905 SystemModuleMixer::on_read_substate(api, &event)
1906 }
1907
1908 fn on_write_substate<Y: KernelInternalApi<System = Self>>(
1909 event: WriteSubstateEvent,
1910 api: &mut Y,
1911 ) -> Result<(), RuntimeError> {
1912 SystemModuleMixer::on_write_substate(api, &event)
1913 }
1914
1915 fn on_set_substate<Y: KernelInternalApi<System = Self>>(
1916 event: SetSubstateEvent,
1917 api: &mut Y,
1918 ) -> Result<(), RuntimeError> {
1919 SystemModuleMixer::on_set_substate(api, &event)
1920 }
1921
1922 fn on_remove_substate<Y: KernelInternalApi<System = Self>>(
1923 event: RemoveSubstateEvent,
1924 api: &mut Y,
1925 ) -> Result<(), RuntimeError> {
1926 SystemModuleMixer::on_remove_substate(api, &event)
1927 }
1928
1929 fn on_scan_keys<Y: KernelInternalApi<System = Self>>(
1930 event: ScanKeysEvent,
1931 api: &mut Y,
1932 ) -> Result<(), RuntimeError> {
1933 SystemModuleMixer::on_scan_keys(api, &event)
1934 }
1935
1936 fn on_drain_substates<Y: KernelInternalApi<System = Self>>(
1937 event: DrainSubstatesEvent,
1938 api: &mut Y,
1939 ) -> Result<(), RuntimeError> {
1940 SystemModuleMixer::on_drain_substates(api, &event)
1941 }
1942
1943 fn on_scan_sorted_substates<Y: KernelInternalApi<System = Self>>(
1944 event: ScanSortedSubstatesEvent,
1945 api: &mut Y,
1946 ) -> Result<(), RuntimeError> {
1947 SystemModuleMixer::on_scan_sorted_substates(api, &event)
1948 }
1949
1950 fn before_invoke<Y: KernelApi<CallbackObject = Self>>(
1951 invocation: &KernelInvocation<Actor>,
1952 api: &mut Y,
1953 ) -> Result<(), RuntimeError> {
1954 if api
1955 .kernel_get_system()
1956 .versioned_system_logic
1957 .should_check_method_receiver_access()
1958 {
1959 let can_be_invoked = match invocation.call_frame_data {
1960 Actor::Method(MethodActor {
1961 method_type: MethodType::Direct,
1962 node_id,
1963 ..
1964 }) => api
1965 .kernel_get_node_visibility_uncosted(&node_id)
1966 .can_be_invoked(true),
1967 Actor::Method(MethodActor {
1968 method_type: MethodType::Main | MethodType::Module(..),
1969 node_id,
1970 ..
1971 }) => api
1972 .kernel_get_node_visibility_uncosted(&node_id)
1973 .can_be_invoked(false),
1974 Actor::Root | Actor::Function(..) | Actor::BlueprintHook(..) => true,
1975 };
1976
1977 if !can_be_invoked {
1978 return Err(RuntimeError::SystemError(SystemError::InvalidInvokeAccess));
1979 }
1980 }
1981
1982 let is_to_barrier = invocation.call_frame_data.is_barrier();
1983 let destination_blueprint_id = invocation.call_frame_data.blueprint_id();
1984
1985 for node_id in invocation.args.owned_nodes() {
1986 Self::on_move_node(
1987 node_id,
1988 true,
1989 is_to_barrier,
1990 destination_blueprint_id.clone(),
1991 api,
1992 )?;
1993 }
1994
1995 SystemModuleMixer::before_invoke(api, invocation)
1996 }
1997
1998 fn on_execution_start<Y: KernelInternalApi<System = Self>>(
1999 api: &mut Y,
2000 ) -> Result<(), RuntimeError> {
2001 SystemModuleMixer::on_execution_start(api)
2002 }
2003
2004 fn invoke_upstream<Y: KernelApi<CallbackObject = Self>>(
2005 input: &IndexedScryptoValue,
2006 api: &mut Y,
2007 ) -> Result<IndexedScryptoValue, RuntimeError> {
2008 let mut system = SystemService::new(api);
2009 let actor = system.current_actor();
2010 let node_id = actor.node_id();
2011 let is_direct_access = actor.is_direct_access();
2012
2013 if let Some(blueprint_id) = actor.blueprint_id() {
2015 let key = BlueprintVersionKey {
2016 blueprint: blueprint_id.blueprint_name.clone(),
2017 version: BlueprintVersion::default(),
2018 };
2019
2020 let handle = system.kernel_open_substate_with_default(
2021 blueprint_id.package_address.as_node_id(),
2022 MAIN_BASE_PARTITION
2023 .at_offset(PACKAGE_BLUEPRINT_DEPENDENCIES_PARTITION_OFFSET)
2024 .unwrap(),
2025 &SubstateKey::Map(scrypto_encode(&key).unwrap()),
2026 LockFlags::read_only(),
2027 Some(|| {
2028 let kv_entry = KeyValueEntrySubstate::<()>::default();
2029 IndexedScryptoValue::from_typed(&kv_entry)
2030 }),
2031 SystemLockData::default(),
2032 )?;
2033 system.kernel_read_substate(handle)?;
2034 system.kernel_close_substate(handle)?;
2035 }
2036
2037 match &actor {
2038 Actor::Root => panic!("Root is invoked"),
2039 actor @ Actor::Method(MethodActor { ident, .. })
2040 | actor @ Actor::Function(FunctionActor { ident, .. }) => {
2041 let blueprint_id = actor.blueprint_id().unwrap();
2042
2043 let definition = system.load_blueprint_definition(
2045 blueprint_id.package_address,
2046 &BlueprintVersionKey::new_default(blueprint_id.blueprint_name.as_str()),
2047 )?;
2048
2049 let target = system.get_actor_type_target()?;
2050
2051 system.validate_blueprint_payload(
2053 &target,
2054 BlueprintPayloadIdentifier::Function(ident.clone(), InputOrOutput::Input),
2055 input.as_vec_ref(),
2056 )?;
2057
2058 let function_schema = definition
2060 .interface
2061 .functions
2062 .get(ident)
2063 .expect("Should exist due to schema check");
2064 match (&function_schema.receiver, node_id) {
2065 (Some(receiver_info), Some(_)) => {
2066 if is_direct_access
2067 != receiver_info.ref_types.contains(RefTypes::DIRECT_ACCESS)
2068 {
2069 return Err(RuntimeError::SystemUpstreamError(
2070 SystemUpstreamError::ReceiverNotMatch(ident.to_string()),
2071 ));
2072 }
2073 }
2074 (None, None) => {}
2075 _ => {
2076 return Err(RuntimeError::SystemUpstreamError(
2077 SystemUpstreamError::ReceiverNotMatch(ident.to_string()),
2078 ));
2079 }
2080 }
2081
2082 let export = definition
2084 .function_exports
2085 .get(ident)
2086 .expect("Schema should have validated this exists")
2087 .clone();
2088 let output =
2089 { V::invoke(&blueprint_id.package_address, export, input, &mut system)? };
2090
2091 system.validate_blueprint_payload(
2093 &target,
2094 BlueprintPayloadIdentifier::Function(ident.clone(), InputOrOutput::Output),
2095 output.as_vec_ref(),
2096 )?;
2097
2098 Ok(output)
2099 }
2100 Actor::BlueprintHook(BlueprintHookActor {
2101 blueprint_id, hook, ..
2102 }) => {
2103 let definition = system.load_blueprint_definition(
2105 blueprint_id.package_address,
2106 &BlueprintVersionKey::new_default(blueprint_id.blueprint_name.as_str()),
2107 )?;
2108 let export =
2109 definition
2110 .hook_exports
2111 .get(hook)
2112 .ok_or(RuntimeError::SystemUpstreamError(
2113 SystemUpstreamError::HookNotFound(*hook),
2114 ))?;
2115
2116 let output = V::invoke(
2120 &blueprint_id.package_address,
2121 export.clone(),
2122 input,
2123 &mut system,
2124 )?;
2125
2126 match hook {
2128 BlueprintHook::OnVirtualize => {
2129 scrypto_decode::<OnVirtualizeOutput>(output.as_slice()).map(|_| ())
2130 }
2131 BlueprintHook::OnDrop => {
2132 scrypto_decode::<OnDropOutput>(output.as_slice()).map(|_| ())
2133 }
2134 BlueprintHook::OnMove => {
2135 scrypto_decode::<OnMoveOutput>(output.as_slice()).map(|_| ())
2136 }
2137 }
2138 .map_err(|e| {
2139 RuntimeError::SystemUpstreamError(SystemUpstreamError::OutputDecodeError(e))
2140 })?;
2141
2142 Ok(output)
2143 }
2144 }
2145 }
2146
2147 fn auto_drop<Y: KernelApi<CallbackObject = Self>>(
2149 nodes: Vec<NodeId>,
2150 api: &mut Y,
2151 ) -> Result<(), RuntimeError> {
2152 for node_id in nodes {
2154 let type_info = TypeInfoBlueprint::get_type(&node_id, api)?;
2155
2156 if let TypeInfoSubstate::Object(ObjectInfo {
2157 blueprint_info: BlueprintInfo { blueprint_id, .. },
2158 ..
2159 }) = type_info
2160 {
2161 match (
2162 blueprint_id.package_address,
2163 blueprint_id.blueprint_name.as_str(),
2164 ) {
2165 (RESOURCE_PACKAGE, FUNGIBLE_PROOF_BLUEPRINT) => {
2166 let mut system = SystemService::new(api);
2167 system.call_function(
2168 RESOURCE_PACKAGE,
2169 FUNGIBLE_PROOF_BLUEPRINT,
2170 PROOF_DROP_IDENT,
2171 scrypto_encode(&ProofDropInput {
2172 proof: Proof(Own(node_id)),
2173 })
2174 .unwrap(),
2175 )?;
2176 }
2177 (RESOURCE_PACKAGE, NON_FUNGIBLE_PROOF_BLUEPRINT) => {
2178 let mut system = SystemService::new(api);
2179 system.call_function(
2180 RESOURCE_PACKAGE,
2181 NON_FUNGIBLE_PROOF_BLUEPRINT,
2182 PROOF_DROP_IDENT,
2183 scrypto_encode(&ProofDropInput {
2184 proof: Proof(Own(node_id)),
2185 })
2186 .unwrap(),
2187 )?;
2188 }
2189 _ => {
2190 }
2192 }
2193 }
2194 }
2195
2196 Ok(())
2197 }
2198
2199 fn on_execution_finish<Y: KernelInternalApi<System = Self>>(
2200 message: &CallFrameMessage,
2201 api: &mut Y,
2202 ) -> Result<(), RuntimeError> {
2203 SystemModuleMixer::on_execution_finish(api, message)?;
2204
2205 Ok(())
2206 }
2207
2208 fn on_get_stack_id<Y: KernelInternalApi<System = Self>>(
2209 api: &mut Y,
2210 ) -> Result<(), RuntimeError> {
2211 SystemModuleMixer::on_get_stack_id(api)
2212 }
2213
2214 fn on_switch_stack<Y: KernelInternalApi<System = Self>>(
2215 api: &mut Y,
2216 ) -> Result<(), RuntimeError> {
2217 SystemModuleMixer::on_switch_stack(api)
2218 }
2219
2220 fn on_send_to_stack<Y: KernelInternalApi<System = Self>>(
2221 value: &IndexedScryptoValue,
2222 api: &mut Y,
2223 ) -> Result<(), RuntimeError> {
2224 SystemModuleMixer::on_send_to_stack(api, value.len())
2225 }
2226
2227 fn on_set_call_frame_data<Y: KernelInternalApi<System = Self>>(
2228 data: &Self::CallFrameData,
2229 api: &mut Y,
2230 ) -> Result<(), RuntimeError> {
2231 SystemModuleMixer::on_set_call_frame_data(api, data.len())
2232 }
2233
2234 fn on_get_owned_nodes<Y: KernelInternalApi<System = Self>>(
2235 api: &mut Y,
2236 ) -> Result<(), RuntimeError> {
2237 SystemModuleMixer::on_get_owned_nodes(api)
2238 }
2239
2240 fn after_invoke<Y: KernelApi<CallbackObject = Self>>(
2245 output: &IndexedScryptoValue,
2246 api: &mut Y,
2247 ) -> Result<(), RuntimeError> {
2248 let current_actor = api.kernel_get_system_state().current_call_frame;
2249 let is_to_barrier = current_actor.is_barrier();
2250 let destination_blueprint_id = current_actor.blueprint_id();
2251 for node_id in output.owned_nodes() {
2252 Self::on_move_node(
2253 node_id,
2254 false,
2255 is_to_barrier,
2256 destination_blueprint_id.clone(),
2257 api,
2258 )?;
2259 }
2260
2261 SystemModuleMixer::after_invoke(api, output)
2262 }
2263
2264 fn on_allocate_node_id<Y: KernelInternalApi<System = Self>>(
2265 entity_type: EntityType,
2266 api: &mut Y,
2267 ) -> Result<(), RuntimeError> {
2268 SystemModuleMixer::on_allocate_node_id(api, entity_type)
2269 }
2270
2271 fn on_mark_substate_as_transient<Y: KernelInternalApi<System = Self>>(
2272 node_id: &NodeId,
2273 partition_number: &PartitionNumber,
2274 substate_key: &SubstateKey,
2275 api: &mut Y,
2276 ) -> Result<(), RuntimeError> {
2277 SystemModuleMixer::on_mark_substate_as_transient(
2278 api,
2279 node_id,
2280 partition_number,
2281 substate_key,
2282 )
2283 }
2284
2285 fn on_substate_lock_fault<Y: KernelApi<CallbackObject = Self>>(
2286 node_id: NodeId,
2287 partition_num: PartitionNumber,
2288 offset: &SubstateKey,
2289 api: &mut Y,
2290 ) -> Result<bool, RuntimeError> {
2291 if !partition_num.eq(&TYPE_INFO_FIELD_PARTITION)
2295 || !offset.eq(&TypeInfoField::TypeInfo.into())
2296 {
2297 return Ok(false);
2298 }
2299
2300 let (blueprint_id, variant_id) = match node_id.entity_type() {
2301 Some(EntityType::GlobalPreallocatedSecp256k1Account) => (
2302 BlueprintId::new(&ACCOUNT_PACKAGE, ACCOUNT_BLUEPRINT),
2303 ACCOUNT_CREATE_PREALLOCATED_SECP256K1_ID,
2304 ),
2305 Some(EntityType::GlobalPreallocatedEd25519Account) => (
2306 BlueprintId::new(&ACCOUNT_PACKAGE, ACCOUNT_BLUEPRINT),
2307 ACCOUNT_CREATE_PREALLOCATED_ED25519_ID,
2308 ),
2309 Some(EntityType::GlobalPreallocatedSecp256k1Identity) => (
2310 BlueprintId::new(&IDENTITY_PACKAGE, IDENTITY_BLUEPRINT),
2311 IDENTITY_CREATE_PREALLOCATED_SECP256K1_ID,
2312 ),
2313 Some(EntityType::GlobalPreallocatedEd25519Identity) => (
2314 BlueprintId::new(&IDENTITY_PACKAGE, IDENTITY_BLUEPRINT),
2315 IDENTITY_CREATE_PREALLOCATED_ED25519_ID,
2316 ),
2317 _ => return Ok(false),
2318 };
2319
2320 let mut service = SystemService::new(api);
2321 let definition = service.load_blueprint_definition(
2322 blueprint_id.package_address,
2323 &BlueprintVersionKey {
2324 blueprint: blueprint_id.blueprint_name.clone(),
2325 version: BlueprintVersion::default(),
2326 },
2327 )?;
2328 if definition
2329 .hook_exports
2330 .contains_key(&BlueprintHook::OnVirtualize)
2331 {
2332 let mut system = SystemService::new(api);
2333 let address = GlobalAddress::new_or_panic(node_id.into());
2334 let address_reservation =
2335 system.allocate_virtual_global_address(blueprint_id.clone(), address)?;
2336
2337 api.kernel_invoke(Box::new(KernelInvocation {
2338 call_frame_data: Actor::BlueprintHook(BlueprintHookActor {
2339 blueprint_id: blueprint_id.clone(),
2340 hook: BlueprintHook::OnVirtualize,
2341 receiver: None,
2342 }),
2343 args: IndexedScryptoValue::from_typed(&OnVirtualizeInput {
2344 variant_id,
2345 rid: copy_u8_array(&node_id.as_bytes()[1..]),
2346 address_reservation,
2347 }),
2348 }))?;
2349 Ok(true)
2350 } else {
2351 Ok(false)
2352 }
2353 }
2354
2355 fn on_drop_node_mut<Y: KernelApi<CallbackObject = Self>>(
2356 node_id: &NodeId,
2357 api: &mut Y,
2358 ) -> Result<(), RuntimeError> {
2359 let type_info = TypeInfoBlueprint::get_type(node_id, api)?;
2360
2361 match type_info {
2362 TypeInfoSubstate::Object(node_object_info) => {
2363 let mut service = SystemService::new(api);
2364 let definition = service.load_blueprint_definition(
2365 node_object_info.blueprint_info.blueprint_id.package_address,
2366 &BlueprintVersionKey {
2367 blueprint: node_object_info
2368 .blueprint_info
2369 .blueprint_id
2370 .blueprint_name
2371 .clone(),
2372 version: BlueprintVersion::default(),
2373 },
2374 )?;
2375 if definition.hook_exports.contains_key(&BlueprintHook::OnDrop) {
2376 api.kernel_invoke(Box::new(KernelInvocation {
2377 call_frame_data: Actor::BlueprintHook(BlueprintHookActor {
2378 blueprint_id: node_object_info.blueprint_info.blueprint_id.clone(),
2379 hook: BlueprintHook::OnDrop,
2380 receiver: Some(*node_id),
2381 }),
2382 args: IndexedScryptoValue::from_typed(&OnDropInput {}),
2383 }))
2384 .map(|_| ())
2385 } else {
2386 Ok(())
2387 }
2388 }
2389 TypeInfoSubstate::KeyValueStore(_)
2390 | TypeInfoSubstate::GlobalAddressReservation(_)
2391 | TypeInfoSubstate::GlobalAddressPhantom(_) => {
2392 Ok(())
2394 }
2395 }
2396 }
2397}