radix_engine/system/system_modules/costing/
costing_module.rs

1use super::*;
2use super::{FeeReserveError, FeeTable, SystemLoanFeeReserve};
3use crate::blueprints::package::PackageRoyaltyNativeBlueprint;
4use crate::internal_prelude::*;
5use crate::kernel::kernel_api::*;
6use crate::kernel::kernel_callback_api::*;
7use crate::object_modules::royalty::ComponentRoyaltyBlueprint;
8use crate::system::actor::{Actor, FunctionActor, MethodActor, MethodType};
9use crate::system::module::*;
10use crate::system::system_callback::*;
11use crate::{
12    errors::{CanBeAbortion, RuntimeError, SystemModuleError},
13    transaction::AbortReason,
14};
15use radix_engine_interface::api::AttachedModuleId;
16use radix_engine_interface::blueprints::package::BlueprintVersionKey;
17use radix_engine_interface::blueprints::resource::LiquidFungibleResource;
18use radix_engine_interface::types::NodeId;
19
20#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
21pub enum CostingError {
22    FeeReserveError(FeeReserveError),
23}
24
25impl CanBeAbortion for CostingError {
26    fn abortion(&self) -> Option<&AbortReason> {
27        match self {
28            Self::FeeReserveError(err) => err.abortion(),
29        }
30    }
31}
32
33#[derive(Debug, Clone, Default)]
34pub enum OnApplyCost {
35    #[default]
36    Normal,
37    ForceFailOnCount {
38        fail_after: Rc<RefCell<u64>>,
39    },
40}
41
42impl OnApplyCost {
43    pub fn on_call(&mut self) -> Result<(), CostingError> {
44        match self {
45            OnApplyCost::Normal => {}
46            OnApplyCost::ForceFailOnCount { fail_after } => {
47                if *fail_after.borrow() == 0 {
48                    return Ok(());
49                }
50
51                *fail_after.borrow_mut() -= 1;
52                if *fail_after.borrow() == 0 {
53                    return Err(CostingError::FeeReserveError(
54                        FeeReserveError::InsufficientBalance {
55                            required: Decimal::MAX,
56                            remaining: Decimal::ONE,
57                        },
58                    ));
59                }
60            }
61        }
62
63        Ok(())
64    }
65}
66
67#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
68pub struct CostingModuleConfig {
69    /// The maximum allowed method royalty in XRD allowed to be set by package and component owners
70    pub max_per_function_royalty_in_xrd: Decimal,
71    /// If true, execution costing for all system calls will occur
72    pub apply_execution_cost_2: bool,
73    /// If true, costing on reference checks on boot will occur
74    pub apply_boot_ref_check_costing: bool,
75}
76
77impl CostingModuleConfig {
78    pub fn babylon_genesis() -> Self {
79        Self {
80            max_per_function_royalty_in_xrd: Decimal::try_from(MAX_PER_FUNCTION_ROYALTY_IN_XRD)
81                .unwrap(),
82            apply_execution_cost_2: false,
83            apply_boot_ref_check_costing: false,
84        }
85    }
86
87    pub fn bottlenose() -> Self {
88        Self {
89            max_per_function_royalty_in_xrd: Decimal::try_from(MAX_PER_FUNCTION_ROYALTY_IN_XRD)
90                .unwrap(),
91            apply_execution_cost_2: true,
92            apply_boot_ref_check_costing: true,
93        }
94    }
95}
96
97#[derive(Debug, Clone, ScryptoSbor, PartialEq, Eq)]
98pub struct DetailedExecutionCostBreakdownEntry {
99    pub depth: usize,
100    pub item: ExecutionCostBreakdownItem,
101}
102
103#[derive(Debug, Clone, ScryptoSbor, PartialEq, Eq)]
104pub enum ExecutionCostBreakdownItem {
105    Invocation {
106        actor: Actor,
107        args: (ScryptoValue,),
108    },
109    InvocationComplete,
110    Execution {
111        simple_name: String,
112        item: owned::ExecutionCostingEntryOwned,
113        cost_units: u32,
114    },
115}
116
117#[derive(Debug, Clone, Default)]
118pub struct CostBreakdown {
119    pub execution_cost_breakdown: IndexMap<String, u32>,
120    pub finalization_cost_breakdown: IndexMap<String, u32>,
121    pub storage_cost_breakdown: IndexMap<StorageType, usize>,
122}
123
124#[derive(Debug, Clone, Default)]
125pub struct DetailedCostBreakdown {
126    /// A more detailed cost breakdown with information on the depth.
127    pub detailed_execution_cost_breakdown: Vec<DetailedExecutionCostBreakdownEntry>,
128}
129
130#[derive(Debug, Clone)]
131pub struct CostingModule {
132    pub config: CostingModuleConfig,
133    pub fee_reserve: SystemLoanFeeReserve,
134    pub fee_table: FeeTable,
135    pub on_apply_cost: OnApplyCost,
136
137    pub tx_payload_len: usize,
138    pub tx_num_of_signature_validations: usize,
139    pub cost_breakdown: Option<CostBreakdown>,
140    pub detailed_cost_breakdown: Option<DetailedCostBreakdown>,
141
142    /// This keeps track of the current kernel depth.
143    pub current_depth: usize,
144}
145
146impl CostingModule {
147    pub fn apply_execution_cost(
148        &mut self,
149        costing_entry: ExecutionCostingEntry,
150    ) -> Result<(), CostingError> {
151        self.on_apply_cost.on_call()?;
152
153        let cost_units = costing_entry.to_execution_cost_units(&self.fee_table);
154
155        self.fee_reserve
156            .consume_execution(cost_units)
157            .map_err(CostingError::FeeReserveError)?;
158
159        if let Some(cost_breakdown) = &mut self.cost_breakdown {
160            let key = costing_entry.to_trace_key();
161            cost_breakdown
162                .execution_cost_breakdown
163                .entry(key)
164                .or_default()
165                .add_assign(cost_units);
166        }
167        if let Some(detailed_cost_breakdown) = &mut self.detailed_cost_breakdown {
168            // Add an entry for the more detailed execution cost
169            detailed_cost_breakdown
170                .detailed_execution_cost_breakdown
171                .push(DetailedExecutionCostBreakdownEntry {
172                    depth: self.current_depth,
173                    item: ExecutionCostBreakdownItem::Execution {
174                        simple_name: costing_entry.to_trace_key(),
175                        item: owned::ExecutionCostingEntryOwned::from(costing_entry),
176                        cost_units,
177                    },
178                });
179        }
180
181        Ok(())
182    }
183
184    pub fn apply_execution_cost_2(
185        &mut self,
186        costing_entry: ExecutionCostingEntry,
187    ) -> Result<(), CostingError> {
188        if self.config.apply_execution_cost_2 {
189            self.apply_execution_cost(costing_entry)
190        } else {
191            Ok(())
192        }
193    }
194
195    pub fn apply_deferred_execution_cost(
196        &mut self,
197        costing_entry: ExecutionCostingEntry,
198    ) -> Result<(), CostingError> {
199        if let ExecutionCostingEntry::CheckReference { .. } = &costing_entry {
200            if !self.config.apply_boot_ref_check_costing {
201                return Ok(());
202            }
203        }
204
205        self.on_apply_cost.on_call()?;
206
207        let cost_units = costing_entry.to_execution_cost_units(&self.fee_table);
208
209        self.fee_reserve
210            .consume_deferred_execution(cost_units)
211            .map_err(CostingError::FeeReserveError)?;
212
213        if let Some(cost_breakdown) = &mut self.cost_breakdown {
214            let key = costing_entry.to_trace_key();
215            cost_breakdown
216                .execution_cost_breakdown
217                .entry(key)
218                .or_default()
219                .add_assign(cost_units);
220        }
221
222        if let Some(detailed_cost_breakdown) = &mut self.detailed_cost_breakdown {
223            // Add an entry for the more detailed execution cost
224            detailed_cost_breakdown
225                .detailed_execution_cost_breakdown
226                .push(DetailedExecutionCostBreakdownEntry {
227                    depth: 0,
228                    item: ExecutionCostBreakdownItem::Execution {
229                        simple_name: costing_entry.to_trace_key(),
230                        item: owned::ExecutionCostingEntryOwned::from(costing_entry),
231                        cost_units,
232                    },
233                });
234        }
235
236        Ok(())
237    }
238
239    pub fn apply_deferred_finalization_cost(
240        &mut self,
241        costing_entry: FinalizationCostingEntry,
242    ) -> Result<(), CostingError> {
243        self.on_apply_cost.on_call()?;
244
245        let cost_units = costing_entry.to_finalization_cost_units(&self.fee_table);
246
247        self.fee_reserve
248            .consume_deferred_finalization(cost_units)
249            .map_err(CostingError::FeeReserveError)?;
250
251        if let Some(cost_breakdown) = &mut self.cost_breakdown {
252            let key = costing_entry.to_trace_key();
253            cost_breakdown
254                .finalization_cost_breakdown
255                .entry(key)
256                .or_default()
257                .add_assign(cost_units);
258        }
259
260        Ok(())
261    }
262
263    pub fn apply_deferred_storage_cost(
264        &mut self,
265        storage_type: StorageType,
266        size_increase: usize,
267    ) -> Result<(), CostingError> {
268        self.on_apply_cost.on_call()?;
269
270        self.fee_reserve
271            .consume_deferred_storage(storage_type, size_increase)
272            .map_err(CostingError::FeeReserveError)?;
273
274        if let Some(cost_breakdown) = &mut self.cost_breakdown {
275            cost_breakdown
276                .storage_cost_breakdown
277                .entry(storage_type)
278                .or_default()
279                .add_assign(size_increase);
280        }
281
282        Ok(())
283    }
284
285    pub fn apply_finalization_cost(
286        &mut self,
287        costing_entry: FinalizationCostingEntry,
288    ) -> Result<(), CostingError> {
289        self.on_apply_cost.on_call()?;
290
291        let cost_units = costing_entry.to_finalization_cost_units(&self.fee_table);
292
293        self.fee_reserve
294            .consume_finalization(cost_units)
295            .map_err(CostingError::FeeReserveError)?;
296
297        if let Some(cost_breakdown) = &mut self.cost_breakdown {
298            let key = costing_entry.to_trace_key();
299            cost_breakdown
300                .finalization_cost_breakdown
301                .entry(key)
302                .or_default()
303                .add_assign(cost_units);
304        }
305
306        Ok(())
307    }
308
309    pub fn apply_storage_cost(
310        &mut self,
311        storage_type: StorageType,
312        size_increase: usize,
313    ) -> Result<(), CostingError> {
314        self.on_apply_cost.on_call()?;
315
316        self.fee_reserve
317            .consume_storage(storage_type, size_increase)
318            .map_err(CostingError::FeeReserveError)?;
319
320        if let Some(cost_breakdown) = &mut self.cost_breakdown {
321            cost_breakdown
322                .storage_cost_breakdown
323                .entry(storage_type)
324                .or_default()
325                .add_assign(size_increase);
326        }
327
328        Ok(())
329    }
330
331    pub fn lock_fee(
332        &mut self,
333        vault_id: NodeId,
334        locked_fee: LiquidFungibleResource,
335        contingent: bool,
336    ) {
337        self.fee_reserve.lock_fee(vault_id, locked_fee, contingent);
338    }
339
340    pub fn unpack_for_receipt(
341        self,
342    ) -> (
343        SystemLoanFeeReserve,
344        Option<CostBreakdown>,
345        Option<DetailedCostBreakdown>,
346    ) {
347        (
348            self.fee_reserve,
349            self.cost_breakdown,
350            self.detailed_cost_breakdown,
351        )
352    }
353}
354
355pub fn apply_royalty_cost(
356    api: &mut impl SystemModuleApiFor<CostingModule>,
357    royalty_amount: RoyaltyAmount,
358    recipient: RoyaltyRecipient,
359) -> Result<(), RuntimeError> {
360    api.module()
361        .on_apply_cost
362        .on_call()
363        .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
364
365    api.module()
366        .fee_reserve
367        .consume_royalty(royalty_amount, recipient)
368        .map_err(|e| {
369            RuntimeError::SystemModuleError(SystemModuleError::CostingError(
370                CostingError::FeeReserveError(e),
371            ))
372        })
373}
374
375impl InitSystemModule for CostingModule {
376    fn init(&mut self) -> Result<(), BootloadingError> {
377        self.apply_deferred_execution_cost(ExecutionCostingEntry::ValidateTxPayload {
378            size: self.tx_payload_len,
379        })
380        .map_err(BootloadingError::FailedToApplyDeferredCosts)?;
381
382        self.apply_deferred_execution_cost(ExecutionCostingEntry::VerifyTxSignatures {
383            num_signatures: self.tx_num_of_signature_validations,
384        })
385        .map_err(BootloadingError::FailedToApplyDeferredCosts)?;
386
387        self.apply_deferred_storage_cost(StorageType::Archive, self.tx_payload_len)
388            .map_err(BootloadingError::FailedToApplyDeferredCosts)?;
389
390        Ok(())
391    }
392}
393
394impl ResolvableSystemModule for CostingModule {
395    #[inline]
396    fn resolve_from_system(system: &mut impl HasModules) -> &mut Self {
397        &mut system.modules_mut().costing
398    }
399}
400
401impl PrivilegedSystemModule for CostingModule {
402    /// Runs after SystemModule::before_invoke
403    /// Called from the Module Mixer
404    fn privileged_before_invoke(
405        api: &mut impl SystemBasedKernelApi,
406        invocation: &KernelInvocation<Actor>,
407    ) -> Result<(), RuntimeError> {
408        // This check only applies in SystemV1.
409        // In this case, there was a call from Root => Transaction Processor, which this check avoids charging for.
410        // From SystemV2 onwards, there is no explicit call, and the Root actor is simply overwritten.
411        if api.kernel_get_system_state().current_call_frame.is_root() {
412            return Ok(());
413        }
414
415        // Identify the function, and optional component address
416        let (optional_blueprint_id, ident, maybe_object_royalties) = {
417            let (maybe_component, ident) = match &invocation.call_frame_data {
418                Actor::Method(MethodActor {
419                    method_type,
420                    node_id,
421                    ident,
422                    object_info,
423                    ..
424                }) => {
425                    // Only do royalty costing for Main
426                    match method_type {
427                        MethodType::Main | MethodType::Direct => {}
428                        MethodType::Module(..) => return Ok(()),
429                    }
430
431                    match &object_info.object_type {
432                        ObjectType::Global { modules }
433                            if modules.contains_key(&AttachedModuleId::Royalty) =>
434                        {
435                            (Some(*node_id), ident)
436                        }
437                        _ => (None, ident),
438                    }
439                }
440                Actor::Function(FunctionActor { ident, .. }) => (None, ident),
441                Actor::BlueprintHook(..) | Actor::Root => {
442                    return Ok(());
443                }
444            };
445
446            (
447                invocation.call_frame_data.blueprint_id(),
448                ident,
449                maybe_component,
450            )
451        };
452
453        //===========================
454        // Apply package royalty
455        //===========================
456        if let Some(blueprint_id) = optional_blueprint_id {
457            let bp_version_key =
458                BlueprintVersionKey::new_default(blueprint_id.blueprint_name.as_str());
459            PackageRoyaltyNativeBlueprint::charge_package_royalty(
460                blueprint_id.package_address.as_node_id(),
461                &bp_version_key,
462                ident,
463                api,
464            )?;
465        }
466
467        //===========================
468        // Apply component royalty
469        //===========================
470        if let Some(node_id) = maybe_object_royalties {
471            ComponentRoyaltyBlueprint::charge_component_royalty(&node_id, ident, api)?;
472        }
473
474        Ok(())
475    }
476}
477
478impl<ModuleApi: SystemModuleApiFor<Self>> SystemModule<ModuleApi> for CostingModule {
479    fn before_invoke(
480        api: &mut ModuleApi,
481        invocation: &KernelInvocation<Actor>,
482    ) -> Result<(), RuntimeError> {
483        let depth = api.current_stack_depth_uncosted();
484        let is_root = api.system_state().current_call_frame.is_root();
485        let costing_module = api.module();
486
487        // Add invocation information to the execution cost breakdown.
488        if let Some(ref mut detailed_cost_breakdown) = costing_module.detailed_cost_breakdown {
489            detailed_cost_breakdown
490                .detailed_execution_cost_breakdown
491                .push(DetailedExecutionCostBreakdownEntry {
492                    depth,
493                    item: ExecutionCostBreakdownItem::Invocation {
494                        actor: invocation.call_frame_data.clone(),
495                        args: (invocation.args.as_scrypto_value().to_owned(),),
496                    },
497                });
498        }
499
500        // This check only applies in SystemV1.
501        // In this case, there was a call from Root => Transaction Processor, which this check avoids charging for.
502        // From SystemV2 onwards, there is no explicit call, and the Root actor is simply overwritten.
503        if is_root {
504            return Ok(());
505        }
506
507        costing_module.current_depth = depth;
508        costing_module
509            .apply_execution_cost(ExecutionCostingEntry::BeforeInvoke {
510                actor: &invocation.call_frame_data,
511                input_size: invocation.len(),
512            })
513            .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
514
515        // NOTE: privileged_before_invoke is now called by the module mixer
516
517        Ok(())
518    }
519
520    #[inline(always)]
521    fn after_invoke(api: &mut ModuleApi, output: &IndexedScryptoValue) -> Result<(), RuntimeError> {
522        let depth = api.current_stack_depth_uncosted();
523
524        // Add invocation information to the execution cost breakdown.
525        if let Some(ref mut detailed_cost_breakdown) = api.module().detailed_cost_breakdown {
526            detailed_cost_breakdown
527                .detailed_execution_cost_breakdown
528                .push(DetailedExecutionCostBreakdownEntry {
529                    depth,
530                    item: ExecutionCostBreakdownItem::InvocationComplete,
531                });
532        }
533
534        // This check only applies in SystemV1.
535        // In this case, there was a call from Root => Transaction Processor, which this check avoids charging for.
536        // From SystemV2 onwards, there is no explicit call, and the Root actor is simply overwritten.
537        if api.system_state().current_call_frame.is_root() {
538            return Ok(());
539        }
540
541        api.module().current_depth = depth;
542        api.module()
543            .apply_execution_cost(ExecutionCostingEntry::AfterInvoke {
544                output_size: output.len(),
545            })
546            .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
547
548        Ok(())
549    }
550
551    fn on_create_node(api: &mut ModuleApi, event: &CreateNodeEvent) -> Result<(), RuntimeError> {
552        api.module().current_depth = api.current_stack_depth_uncosted();
553        api.module()
554            .apply_execution_cost(ExecutionCostingEntry::CreateNode { event })
555            .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
556
557        Ok(())
558    }
559
560    fn on_pin_node(api: &mut ModuleApi, node_id: &NodeId) -> Result<(), RuntimeError> {
561        api.module()
562            .apply_execution_cost(ExecutionCostingEntry::PinNode { node_id })
563            .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
564
565        Ok(())
566    }
567
568    fn on_drop_node(api: &mut ModuleApi, event: &DropNodeEvent) -> Result<(), RuntimeError> {
569        api.module().current_depth = api.current_stack_depth_uncosted();
570        api.module()
571            .apply_execution_cost(ExecutionCostingEntry::DropNode { event })
572            .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
573
574        Ok(())
575    }
576
577    fn on_move_module(api: &mut ModuleApi, event: &MoveModuleEvent) -> Result<(), RuntimeError> {
578        api.module().current_depth = api.current_stack_depth_uncosted();
579        api.module()
580            .apply_execution_cost(ExecutionCostingEntry::MoveModule { event })
581            .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
582
583        Ok(())
584    }
585
586    fn on_open_substate(
587        api: &mut ModuleApi,
588        event: &OpenSubstateEvent,
589    ) -> Result<(), RuntimeError> {
590        api.module().current_depth = api.current_stack_depth_uncosted();
591        api.module()
592            .apply_execution_cost(ExecutionCostingEntry::OpenSubstate { event })
593            .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
594
595        Ok(())
596    }
597
598    fn on_mark_substate_as_transient(
599        api: &mut ModuleApi,
600        node_id: &NodeId,
601        partition_number: &PartitionNumber,
602        substate_key: &SubstateKey,
603    ) -> Result<(), RuntimeError> {
604        api.module()
605            .apply_execution_cost(ExecutionCostingEntry::MarkSubstateAsTransient {
606                node_id,
607                partition_number,
608                substate_key,
609            })
610            .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
611
612        Ok(())
613    }
614
615    fn on_read_substate(
616        api: &mut ModuleApi,
617        event: &ReadSubstateEvent,
618    ) -> Result<(), RuntimeError> {
619        api.module().current_depth = api.current_stack_depth_uncosted();
620        api.module()
621            .apply_execution_cost(ExecutionCostingEntry::ReadSubstate { event })
622            .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
623
624        Ok(())
625    }
626
627    fn on_write_substate(
628        api: &mut ModuleApi,
629        event: &WriteSubstateEvent,
630    ) -> Result<(), RuntimeError> {
631        api.module().current_depth = api.current_stack_depth_uncosted();
632        api.module()
633            .apply_execution_cost(ExecutionCostingEntry::WriteSubstate { event })
634            .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
635
636        Ok(())
637    }
638
639    fn on_close_substate(
640        api: &mut ModuleApi,
641        event: &CloseSubstateEvent,
642    ) -> Result<(), RuntimeError> {
643        api.module().current_depth = api.current_stack_depth_uncosted();
644        api.module()
645            .apply_execution_cost(ExecutionCostingEntry::CloseSubstate { event })
646            .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
647
648        Ok(())
649    }
650
651    fn on_set_substate(api: &mut ModuleApi, event: &SetSubstateEvent) -> Result<(), RuntimeError> {
652        api.module()
653            .apply_execution_cost(ExecutionCostingEntry::SetSubstate { event })
654            .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
655
656        Ok(())
657    }
658
659    fn on_remove_substate(
660        api: &mut ModuleApi,
661        event: &RemoveSubstateEvent,
662    ) -> Result<(), RuntimeError> {
663        api.module()
664            .apply_execution_cost(ExecutionCostingEntry::RemoveSubstate { event })
665            .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
666
667        Ok(())
668    }
669
670    fn on_scan_keys(api: &mut ModuleApi, event: &ScanKeysEvent) -> Result<(), RuntimeError> {
671        api.module()
672            .apply_execution_cost(ExecutionCostingEntry::ScanKeys { event })
673            .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
674
675        Ok(())
676    }
677
678    fn on_drain_substates(
679        api: &mut ModuleApi,
680        event: &DrainSubstatesEvent,
681    ) -> Result<(), RuntimeError> {
682        api.module()
683            .apply_execution_cost(ExecutionCostingEntry::DrainSubstates { event })
684            .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
685
686        Ok(())
687    }
688
689    fn on_scan_sorted_substates(
690        api: &mut ModuleApi,
691        event: &ScanSortedSubstatesEvent,
692    ) -> Result<(), RuntimeError> {
693        api.module()
694            .apply_execution_cost(ExecutionCostingEntry::ScanSortedSubstates { event })
695            .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
696
697        Ok(())
698    }
699
700    fn on_allocate_node_id(
701        api: &mut ModuleApi,
702        _entity_type: EntityType,
703    ) -> Result<(), RuntimeError> {
704        api.module().current_depth = api.current_stack_depth_uncosted();
705        api.module()
706            .apply_execution_cost(ExecutionCostingEntry::AllocateNodeId)
707            .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
708
709        Ok(())
710    }
711
712    fn on_get_stack_id(api: &mut ModuleApi) -> Result<(), RuntimeError> {
713        api.module()
714            .apply_execution_cost(ExecutionCostingEntry::GetStackId)
715            .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
716
717        Ok(())
718    }
719
720    fn on_switch_stack(api: &mut ModuleApi) -> Result<(), RuntimeError> {
721        api.module()
722            .apply_execution_cost(ExecutionCostingEntry::SwitchStack)
723            .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
724
725        Ok(())
726    }
727
728    fn on_send_to_stack(api: &mut ModuleApi, data_len: usize) -> Result<(), RuntimeError> {
729        api.module()
730            .apply_execution_cost(ExecutionCostingEntry::SendToStack { data_len })
731            .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
732
733        Ok(())
734    }
735
736    fn on_set_call_frame_data(api: &mut ModuleApi, data_len: usize) -> Result<(), RuntimeError> {
737        api.module()
738            .apply_execution_cost(ExecutionCostingEntry::SetCallFrameData { data_len })
739            .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
740
741        Ok(())
742    }
743
744    fn on_get_owned_nodes(api: &mut ModuleApi) -> Result<(), RuntimeError> {
745        api.module()
746            .apply_execution_cost(ExecutionCostingEntry::GetOwnedNodes)
747            .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
748
749        Ok(())
750    }
751}