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