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