radix_engine/system/
system.rs

1use super::id_allocation::IDAllocation;
2use super::system_modules::costing::ExecutionCostingEntry;
3use crate::blueprints::package::PackageBlueprintVersionDefinitionEntrySubstate;
4use crate::blueprints::resource::fungible_vault::LockFeeEvent;
5use crate::errors::*;
6use crate::errors::{EventError, SystemUpstreamError};
7use crate::internal_prelude::*;
8use crate::kernel::call_frame::{NodeVisibility, ReferenceOrigin};
9use crate::kernel::kernel_api::*;
10use crate::system::actor::{Actor, FunctionActor, InstanceContext, MethodActor, MethodType};
11use crate::system::node_init::type_info_partition;
12use crate::system::system_callback::*;
13use crate::system::system_modules::transaction_runtime::Event;
14use crate::system::system_modules::{EnabledModules, SystemModuleMixer};
15use crate::system::system_substates::{KeyValueEntrySubstate, LockStatus};
16use crate::system::system_type_checker::{
17    BlueprintTypeTarget, KVStoreTypeTarget, SchemaValidationMeta, SystemMapper,
18};
19use crate::system::type_info::{TypeInfoBlueprint, TypeInfoSubstate};
20use crate::track::interface::NodeSubstates;
21use radix_blueprint_schema_init::{Condition, KeyValueStoreGenericSubstitutions};
22#[cfg(not(feature = "alloc"))]
23use radix_common_derive::*;
24use radix_engine_interface::api::actor_api::EventFlags;
25use radix_engine_interface::api::actor_index_api::SystemActorIndexApi;
26use radix_engine_interface::api::field_api::{FieldHandle, LockFlags};
27use radix_engine_interface::api::key_value_entry_api::{
28    KeyValueEntryHandle, SystemKeyValueEntryApi,
29};
30use radix_engine_interface::api::key_value_store_api::{
31    KeyValueStoreDataSchema, SystemKeyValueStoreApi,
32};
33use radix_engine_interface::api::object_api::ModuleId;
34use radix_engine_interface::api::*;
35use radix_engine_interface::blueprints::package::*;
36use radix_engine_interface::blueprints::resource::*;
37use radix_engine_profiling_derive::trace_resources;
38use radix_substate_store_interface::db_key_mapper::SubstateKeyContent;
39
40#[allow(clippy::upper_case_acronyms)]
41enum ActorStateRef {
42    SELF,
43    OuterObject,
44}
45
46impl TryFrom<ActorStateHandle> for ActorStateRef {
47    type Error = RuntimeError;
48    fn try_from(value: ActorStateHandle) -> Result<Self, Self::Error> {
49        match value {
50            ACTOR_STATE_SELF => Ok(ActorStateRef::SELF),
51            ACTOR_STATE_OUTER_OBJECT => Ok(ActorStateRef::OuterObject),
52            _ => Err(RuntimeError::SystemError(
53                SystemError::InvalidActorStateHandle,
54            )),
55        }
56    }
57}
58
59#[allow(clippy::upper_case_acronyms)]
60enum ActorObjectRef {
61    SELF,
62    Outer,
63    Global,
64    AuthZone,
65}
66
67impl TryFrom<ActorRefHandle> for ActorObjectRef {
68    type Error = RuntimeError;
69    fn try_from(value: ActorStateHandle) -> Result<Self, Self::Error> {
70        match value {
71            ACTOR_REF_SELF => Ok(ActorObjectRef::SELF),
72            ACTOR_REF_OUTER => Ok(ActorObjectRef::Outer),
73            ACTOR_REF_GLOBAL => Ok(ActorObjectRef::Global),
74            ACTOR_REF_AUTH_ZONE => Ok(ActorObjectRef::AuthZone),
75            _ => Err(RuntimeError::SystemError(
76                SystemError::InvalidActorRefHandle,
77            )),
78        }
79    }
80}
81
82enum EmitterActor {
83    CurrentActor,
84    AsObject(NodeId, Option<AttachedModuleId>),
85}
86
87/// A wrapper offering a comprehensive system api to callers. It is built on top
88/// of a [`SystemBasedKernelApi`], and you are free to access it.
89/// You can also construct a [`SystemService`] from the api with `api.system_service()`.
90///
91/// Like [`SystemModuleApiImpl`], we use a wrapper type rather than implementing this functionality
92/// directly on a `SystemBasedKernelApi` for a few reasons:
93/// * Trait coherence - the System traits aren't defined in this crate, so it prevents us
94///   from implementing them on any type implementing `SystemBasedKernelApi`.
95/// * Separation of APIs - we avoid exposing the methods of a [`SystemServiceApi`] directly
96///   if someone happens to have a [`SystemBasedKernelApi`], which prevents some
97///   possible confusion.
98pub struct SystemService<'a, Y: SystemBasedKernelApi + ?Sized> {
99    api: &'a mut Y,
100}
101
102impl<'a, Y: SystemBasedKernelApi + ?Sized> SystemService<'a, Y> {
103    pub fn new(api: &'a mut Y) -> Self {
104        Self { api }
105    }
106
107    pub fn api(&mut self) -> &mut Y {
108        self.api
109    }
110
111    pub fn system(&mut self) -> &mut System<Y::SystemCallback> {
112        self.api.kernel_get_system()
113    }
114}
115
116#[cfg_attr(
117    feature = "std",
118    catch_unwind(crate::utils::catch_unwind_system_panic_transformer)
119)]
120impl<'a, Y: SystemBasedKernelApi> SystemService<'a, Y> {
121    #[allow(clippy::too_many_arguments)]
122    fn validate_new_object(
123        &mut self,
124        blueprint_id: &BlueprintId,
125        blueprint_interface: &BlueprintInterface,
126        outer_obj_info: OuterObjectInfo,
127        features: IndexSet<String>,
128        outer_object_features: &IndexSet<String>,
129        generic_args: GenericArgs,
130        fields: IndexMap<u8, FieldValue>,
131        mut kv_entries: IndexMap<u8, IndexMap<Vec<u8>, KVEntry>>,
132    ) -> Result<(BlueprintInfo, NodeSubstates), RuntimeError> {
133        // Validate generic arguments
134        let (generic_substitutions, additional_schemas) = {
135            let mut additional_schemas = index_map_new();
136
137            if let Some(schema) = generic_args.additional_schema {
138                validate_schema(schema.v1())
139                    .map_err(|_| RuntimeError::SystemError(SystemError::InvalidGenericArgs))?;
140                let schema_hash = schema.generate_schema_hash();
141                additional_schemas.insert(schema_hash, schema);
142            }
143
144            self.validate_bp_generic_args(
145                blueprint_interface,
146                &additional_schemas,
147                &generic_args.generic_substitutions,
148            )
149            .map_err(|e| RuntimeError::SystemError(SystemError::TypeCheckError(e)))?;
150
151            (generic_args.generic_substitutions, additional_schemas)
152        };
153
154        let blueprint_info = BlueprintInfo {
155            blueprint_id: blueprint_id.clone(),
156            blueprint_version: BlueprintVersion::default(),
157            outer_obj_info,
158            features: features.clone(),
159            generic_substitutions: generic_substitutions.clone(),
160        };
161
162        let validation_target = BlueprintTypeTarget {
163            blueprint_info,
164            meta: SchemaValidationMeta::NewObject {
165                additional_schemas: additional_schemas.clone().into_iter().collect(),
166            },
167        };
168
169        // Fields
170        {
171            let expected_num_fields = blueprint_interface.state.num_fields();
172            for field_index in fields.keys() {
173                let field_index: usize = (*field_index) as usize;
174                if field_index >= expected_num_fields {
175                    return Err(RuntimeError::SystemError(SystemError::CreateObjectError(
176                        Box::new(CreateObjectError::InvalidFieldIndex(
177                            blueprint_id.clone(),
178                            field_index as u8,
179                        )),
180                    )));
181                }
182            }
183
184            if let Some((_partition, field_schemas)) = &blueprint_interface.state.fields {
185                for (i, field) in field_schemas.iter().enumerate() {
186                    let index = i as u8;
187
188                    let maybe_field = fields.get(&index);
189
190                    let field_value = match &field.condition {
191                        Condition::IfFeature(feature) => {
192                            match (features.contains(feature), maybe_field) {
193                                (false, Some(..)) => {
194                                    return Err(RuntimeError::SystemError(
195                                        SystemError::CreateObjectError(Box::new(
196                                            CreateObjectError::InvalidFieldDueToFeature(
197                                                blueprint_id.clone(),
198                                                index,
199                                            ),
200                                        )),
201                                    ));
202                                }
203                                (true, None) => {
204                                    return Err(RuntimeError::SystemError(
205                                        SystemError::CreateObjectError(Box::new(
206                                            CreateObjectError::MissingField(
207                                                blueprint_id.clone(),
208                                                index,
209                                            ),
210                                        )),
211                                    ));
212                                }
213                                (false, None) => continue,
214                                (true, Some(field_value)) => field_value,
215                            }
216                        }
217                        Condition::IfOuterFeature(feature) => {
218                            match (outer_object_features.contains(feature), maybe_field) {
219                                (false, Some(..)) => {
220                                    return Err(RuntimeError::SystemError(
221                                        SystemError::CreateObjectError(Box::new(
222                                            CreateObjectError::InvalidFieldDueToFeature(
223                                                blueprint_id.clone(),
224                                                index,
225                                            ),
226                                        )),
227                                    ));
228                                }
229                                (true, None) => {
230                                    return Err(RuntimeError::SystemError(
231                                        SystemError::CreateObjectError(Box::new(
232                                            CreateObjectError::MissingField(
233                                                blueprint_id.clone(),
234                                                index,
235                                            ),
236                                        )),
237                                    ));
238                                }
239                                (false, None) => continue,
240                                (true, Some(field_value)) => field_value,
241                            }
242                        }
243                        Condition::Always => match maybe_field {
244                            None => {
245                                return Err(RuntimeError::SystemError(
246                                    SystemError::CreateObjectError(Box::new(
247                                        CreateObjectError::MissingField(
248                                            blueprint_id.clone(),
249                                            index,
250                                        ),
251                                    )),
252                                ));
253                            }
254                            Some(field_value) => field_value,
255                        },
256                    };
257
258                    self.validate_blueprint_payload(
259                        &validation_target,
260                        BlueprintPayloadIdentifier::Field(i as u8),
261                        &field_value.value,
262                    )?;
263                }
264            }
265        };
266
267        // Collections
268        {
269            for (collection_index, entries) in &kv_entries {
270                let payloads: Vec<(&Vec<u8>, &Vec<u8>)> = entries
271                    .iter()
272                    .filter_map(|(key, entry)| entry.value.as_ref().map(|e| (key, e)))
273                    .collect();
274
275                self.validate_blueprint_kv_collection(
276                    &validation_target,
277                    *collection_index,
278                    &payloads,
279                )?;
280            }
281
282            for (collection_index, ..) in blueprint_interface.state.collections.iter().enumerate() {
283                let index = collection_index as u8;
284                if !kv_entries.contains_key(&index) {
285                    kv_entries.insert(index, index_map_new());
286                }
287            }
288        }
289
290        let mut node_substates = SystemMapper::system_struct_to_node_substates(
291            &blueprint_interface.state,
292            (fields, kv_entries),
293            MAIN_BASE_PARTITION,
294        );
295
296        let schema_partition = node_substates.entry(SCHEMAS_PARTITION).or_default();
297
298        for (schema_hash, schema) in additional_schemas {
299            let key = SubstateKey::Map(scrypto_encode(&schema_hash).unwrap());
300            let value =
301                IndexedScryptoValue::from_typed(&KeyValueEntrySubstate::locked_entry(schema));
302            schema_partition.insert(key, value);
303        }
304
305        Ok((validation_target.blueprint_info, node_substates))
306    }
307
308    pub fn get_blueprint_default_definition(
309        &mut self,
310        blueprint_id: BlueprintId,
311    ) -> Result<Rc<BlueprintDefinition>, RuntimeError> {
312        let bp_version_key = BlueprintVersionKey::new_default(blueprint_id.blueprint_name);
313        self.load_blueprint_definition(blueprint_id.package_address, &bp_version_key)
314    }
315
316    pub fn load_blueprint_definition(
317        &mut self,
318        package_address: PackageAddress,
319        bp_version_key: &BlueprintVersionKey,
320    ) -> Result<Rc<BlueprintDefinition>, RuntimeError> {
321        let canonical_bp_id = CanonicalBlueprintId {
322            address: package_address,
323            blueprint: bp_version_key.blueprint.to_string(),
324            version: bp_version_key.version,
325        };
326
327        // TODO: Use internment to cache blueprint interface rather than object cache?
328        let def = self
329            .api
330            .kernel_get_system_state()
331            .system
332            .blueprint_cache
333            .get(&canonical_bp_id);
334        if let Some(definition) = def {
335            return Ok(definition.clone());
336        }
337
338        let handle = self.api.kernel_open_substate_with_default(
339            package_address.as_node_id(),
340            MAIN_BASE_PARTITION
341                .at_offset(PACKAGE_BLUEPRINTS_PARTITION_OFFSET)
342                .unwrap(),
343            &SubstateKey::Map(scrypto_encode(bp_version_key).unwrap()),
344            LockFlags::read_only(),
345            Some(|| {
346                let kv_entry = KeyValueEntrySubstate::<()>::default();
347                IndexedScryptoValue::from_typed(&kv_entry)
348            }),
349            SystemLockData::default(),
350        )?;
351
352        let substate: PackageBlueprintVersionDefinitionEntrySubstate =
353            self.api.kernel_read_substate(handle)?.as_typed().unwrap();
354        self.api.kernel_close_substate(handle)?;
355
356        let definition = Rc::new(match substate.into_value() {
357            Some(definition) => definition.fully_update_and_into_latest_version(),
358            None => {
359                return Err(RuntimeError::SystemError(
360                    SystemError::BlueprintDoesNotExist(canonical_bp_id),
361                ))
362            }
363        });
364
365        self.api
366            .kernel_get_system_state()
367            .system
368            .blueprint_cache
369            .insert(canonical_bp_id, definition.clone());
370
371        Ok(definition)
372    }
373
374    pub fn prepare_global_address(
375        &mut self,
376        blueprint_id: BlueprintId,
377        global_address: GlobalAddress,
378    ) -> Result<GlobalAddressReservation, RuntimeError> {
379        // Create global address phantom
380
381        self.api.kernel_create_node(
382            *global_address.as_node_id(),
383            btreemap!(
384                TYPE_INFO_FIELD_PARTITION => type_info_partition(
385                    TypeInfoSubstate::GlobalAddressPhantom(GlobalAddressPhantom {
386                        blueprint_id,
387                    })
388                )
389            ),
390        )?;
391
392        // Create global address reservation
393        let global_address_reservation = self
394            .api
395            .kernel_allocate_node_id(EntityType::InternalGenericComponent)?;
396        self.api.kernel_create_node(
397            global_address_reservation,
398            btreemap!(
399                TYPE_INFO_FIELD_PARTITION => type_info_partition(
400                    TypeInfoSubstate::GlobalAddressReservation(global_address)
401                )
402            ),
403        )?;
404
405        self.api.kernel_pin_node(global_address_reservation)?;
406
407        Ok(GlobalAddressReservation(Own(global_address_reservation)))
408    }
409
410    pub fn get_node_type_info(
411        &mut self,
412        node_id: &NodeId,
413    ) -> Result<TypeInfoSubstate, RuntimeError> {
414        let handle = self.api.kernel_open_substate(
415            node_id,
416            TYPE_INFO_FIELD_PARTITION,
417            &TypeInfoField::TypeInfo.into(),
418            LockFlags::read_only(),
419            SystemLockData::default(),
420        )?;
421        let value = self.api.kernel_read_substate(handle)?;
422        let type_info = value.as_typed::<TypeInfoSubstate>().unwrap();
423        self.api.kernel_close_substate(handle)?;
424        Ok(type_info)
425    }
426
427    fn new_object_internal(
428        &mut self,
429        blueprint_id: &BlueprintId,
430        features: Vec<&str>,
431        instance_context: Option<InstanceContext>,
432        generic_args: GenericArgs,
433        fields: IndexMap<u8, FieldValue>,
434        kv_entries: IndexMap<u8, IndexMap<Vec<u8>, KVEntry>>,
435    ) -> Result<NodeId, RuntimeError> {
436        let blueprint_definition = self.get_blueprint_default_definition(blueprint_id.clone())?;
437        let blueprint_type = blueprint_definition.interface.blueprint_type.clone();
438
439        let object_features: IndexSet<String> =
440            features.into_iter().map(|s| s.to_string()).collect();
441        // Validate features
442        for feature in &object_features {
443            if !blueprint_definition.interface.feature_set.contains(feature) {
444                return Err(RuntimeError::SystemError(SystemError::InvalidFeature(
445                    feature.to_string(),
446                )));
447            }
448        }
449
450        let (outer_obj_info, outer_object_features) =
451            if let BlueprintType::Inner { outer_blueprint } = &blueprint_type {
452                match instance_context {
453                    Some(context) => {
454                        let info = self.get_object_info(context.outer_object.as_node_id())?;
455
456                        if !info
457                            .blueprint_info
458                            .blueprint_id
459                            .blueprint_name
460                            .eq(outer_blueprint)
461                        {
462                            return Err(RuntimeError::SystemError(
463                                SystemError::InvalidChildObjectCreation,
464                            ));
465                        }
466
467                        (
468                            OuterObjectInfo::Some {
469                                outer_object: context.outer_object,
470                            },
471                            info.blueprint_info.features,
472                        )
473                    }
474                    _ => {
475                        return Err(RuntimeError::SystemError(
476                            SystemError::InvalidChildObjectCreation,
477                        ));
478                    }
479                }
480            } else {
481                (OuterObjectInfo::None, index_set_new())
482            };
483
484        let (blueprint_info, mut node_substates) = self.validate_new_object(
485            blueprint_id,
486            &blueprint_definition.interface,
487            outer_obj_info,
488            object_features,
489            &outer_object_features,
490            generic_args,
491            fields,
492            kv_entries,
493        )?;
494
495        let node_id = self.api.kernel_allocate_node_id(
496            IDAllocation::Object {
497                blueprint_id: blueprint_id.clone(),
498                global: false,
499            }
500            .entity_type(),
501        )?;
502
503        node_substates.insert(
504            TYPE_INFO_FIELD_PARTITION,
505            type_info_partition(TypeInfoSubstate::Object(ObjectInfo {
506                blueprint_info,
507                object_type: ObjectType::Owned,
508            })),
509        );
510
511        self.api.kernel_create_node(node_id, node_substates)?;
512
513        if blueprint_definition.interface.is_transient {
514            self.api.kernel_pin_node(node_id)?;
515        }
516
517        if let Some((partition_offset, fields)) = &blueprint_definition.interface.state.fields {
518            for (index, field) in fields.iter().enumerate() {
519                if let FieldTransience::TransientStatic { .. } = field.transience {
520                    let partition_number = match partition_offset {
521                        PartitionDescription::Physical(partition_number) => *partition_number,
522                        PartitionDescription::Logical(offset) => {
523                            MAIN_BASE_PARTITION.at_offset(*offset).unwrap()
524                        }
525                    };
526                    self.api.kernel_mark_substate_as_transient(
527                        node_id,
528                        partition_number,
529                        SubstateKey::Field(index as u8),
530                    )?;
531                }
532            }
533        }
534
535        Ok(node_id)
536    }
537
538    fn emit_event_internal(
539        &mut self,
540        actor: EmitterActor,
541        event_name: String,
542        event_data: Vec<u8>,
543        event_flags: EventFlags,
544    ) -> Result<(), RuntimeError> {
545        self.api.kernel_get_system().modules.apply_execution_cost(
546            ExecutionCostingEntry::EmitEvent {
547                size: event_data.len(),
548            },
549        )?;
550
551        // Locking the package info substate associated with the emitter's package
552        // Getting the package address and blueprint name associated with the actor
553        let validation_target = match &actor {
554            EmitterActor::AsObject(node_id, module_id) => {
555                let bp_info = self.get_blueprint_info(node_id, *module_id)?;
556
557                BlueprintTypeTarget {
558                    blueprint_info: bp_info,
559                    meta: SchemaValidationMeta::ExistingObject {
560                        additional_schemas: *node_id,
561                    },
562                }
563            }
564            EmitterActor::CurrentActor => self.get_actor_type_target()?,
565        };
566
567        self.validate_blueprint_payload(
568            &validation_target,
569            BlueprintPayloadIdentifier::Event(event_name.clone()),
570            &event_data,
571        )?;
572
573        // Construct the event type identifier based on the current actor
574        let event_type_identifier = match actor {
575            EmitterActor::AsObject(node_id, module_id, ..) => Ok(EventTypeIdentifier(
576                Emitter::Method(node_id, module_id.into()),
577                event_name,
578            )),
579            EmitterActor::CurrentActor => match self.current_actor() {
580                Actor::Method(MethodActor {
581                    method_type,
582                    node_id,
583                    ..
584                }) => Ok(EventTypeIdentifier(
585                    Emitter::Method(node_id, method_type.module_id()),
586                    event_name,
587                )),
588                Actor::Function(FunctionActor { blueprint_id, .. }) => Ok(EventTypeIdentifier(
589                    Emitter::Function(blueprint_id.clone()),
590                    event_name,
591                )),
592                _ => Err(RuntimeError::SystemModuleError(
593                    SystemModuleError::EventError(Box::new(EventError::InvalidActor)),
594                )),
595            },
596        }?;
597
598        let event = Event {
599            type_identifier: event_type_identifier,
600            payload: event_data,
601            flags: event_flags,
602        };
603
604        // Adding the event to the event store
605        self.api
606            .kernel_get_system()
607            .modules
608            .checked_add_event(event)?;
609
610        Ok(())
611    }
612
613    /// Internal, handle must be checked or from trusted sources
614    fn key_value_entry_remove_and_close_substate(
615        &mut self,
616        handle: KeyValueEntryHandle,
617    ) -> Result<Vec<u8>, RuntimeError> {
618        // TODO: Replace with api::replace
619        let current_value = self
620            .api
621            .kernel_read_substate(handle)
622            .map(|v| v.as_slice().to_vec())?;
623
624        let mut kv_entry: KeyValueEntrySubstate<ScryptoValue> =
625            scrypto_decode(&current_value).unwrap();
626        let value = kv_entry.remove();
627        self.kernel_write_substate(handle, IndexedScryptoValue::from_typed(&kv_entry))?;
628
629        self.kernel_close_substate(handle)?;
630
631        let current_value = scrypto_encode(&value).unwrap();
632
633        Ok(current_value)
634    }
635
636    pub fn get_blueprint_info(
637        &mut self,
638        node_id: &NodeId,
639        module_id: Option<AttachedModuleId>,
640    ) -> Result<BlueprintInfo, RuntimeError> {
641        let info = match module_id {
642            None => self.get_object_info(node_id)?.blueprint_info,
643            Some(module_id) => BlueprintInfo {
644                blueprint_id: module_id.static_blueprint(),
645                blueprint_version: BlueprintVersion::default(),
646                outer_obj_info: OuterObjectInfo::None,
647                features: indexset!(),
648                generic_substitutions: vec![],
649            },
650        };
651
652        Ok(info)
653    }
654
655    pub fn get_actor_type_target(&mut self) -> Result<BlueprintTypeTarget, RuntimeError> {
656        let actor = self.current_actor();
657        match actor {
658            Actor::Root => Err(RuntimeError::SystemError(SystemError::RootHasNoType)),
659            Actor::BlueprintHook(actor) => Ok(BlueprintTypeTarget {
660                blueprint_info: BlueprintInfo {
661                    blueprint_id: actor.blueprint_id.clone(),
662                    blueprint_version: BlueprintVersion::default(),
663                    outer_obj_info: OuterObjectInfo::None,
664                    features: indexset!(),
665                    generic_substitutions: vec![],
666                },
667                meta: SchemaValidationMeta::Blueprint,
668            }),
669            Actor::Function(actor) => Ok(BlueprintTypeTarget {
670                blueprint_info: BlueprintInfo {
671                    blueprint_id: actor.blueprint_id.clone(),
672                    blueprint_version: BlueprintVersion::default(),
673                    outer_obj_info: OuterObjectInfo::None,
674                    features: indexset!(),
675                    generic_substitutions: vec![],
676                },
677                meta: SchemaValidationMeta::Blueprint,
678            }),
679            Actor::Method(actor) => {
680                let blueprint_info =
681                    self.get_blueprint_info(&actor.node_id, actor.method_type.module_id().into())?;
682                Ok(BlueprintTypeTarget {
683                    blueprint_info,
684                    meta: SchemaValidationMeta::ExistingObject {
685                        additional_schemas: actor.node_id,
686                    },
687                })
688            }
689        }
690    }
691
692    fn get_actor_object_id(
693        &mut self,
694        actor_object_type: ActorStateRef,
695    ) -> Result<(NodeId, Option<AttachedModuleId>), RuntimeError> {
696        let actor = self.current_actor();
697        let object_id = actor
698            .get_object_id()
699            .ok_or_else(|| RuntimeError::SystemError(SystemError::NotAnObject))?;
700
701        let object_id = match actor_object_type {
702            ActorStateRef::OuterObject => {
703                let module_id = object_id.1;
704
705                match module_id {
706                    None => {
707                        let node_id = object_id.0;
708                        let address = self.get_outer_object(&node_id)?;
709
710                        (address.into_node_id(), None)
711                    }
712                    _ => {
713                        return Err(RuntimeError::SystemError(
714                            SystemError::OuterObjectDoesNotExist,
715                        ));
716                    }
717                }
718            }
719            ActorStateRef::SELF => object_id,
720        };
721
722        Ok(object_id)
723    }
724
725    fn get_actor_collection_partition_info(
726        &mut self,
727        actor_object_type: ActorStateRef,
728        collection_index: u8,
729        expected_type: &BlueprintPartitionType,
730    ) -> Result<(NodeId, BlueprintInfo, PartitionNumber), RuntimeError> {
731        let (node_id, module_id) = self.get_actor_object_id(actor_object_type)?;
732        let blueprint_info = self.get_blueprint_info(&node_id, module_id)?;
733        let blueprint_definition =
734            self.get_blueprint_default_definition(blueprint_info.blueprint_id.clone())?;
735
736        let partition_num = {
737            let (partition_description, partition_type) = blueprint_definition
738                .interface
739                .state
740                .get_partition(collection_index)
741                .ok_or_else(|| {
742                    RuntimeError::SystemError(SystemError::CollectionIndexDoesNotExist(
743                        blueprint_info.blueprint_id.clone(),
744                        collection_index,
745                    ))
746                })?;
747
748            if !partition_type.eq(expected_type) {
749                return Err(RuntimeError::SystemError(
750                    SystemError::CollectionIndexIsOfWrongType(
751                        blueprint_info.blueprint_id.clone(),
752                        collection_index,
753                        expected_type.to_owned(),
754                        partition_type,
755                    ),
756                ));
757            }
758
759            match partition_description {
760                PartitionDescription::Physical(partition_num) => partition_num,
761                PartitionDescription::Logical(offset) => {
762                    let base = match module_id {
763                        None => MAIN_BASE_PARTITION,
764                        Some(module_id) => {
765                            let object_module: ModuleId = module_id.into();
766                            object_module.base_partition_num()
767                        }
768                    };
769                    base.at_offset(offset).expect("Module number overflow")
770                }
771            }
772        };
773
774        Ok((node_id, blueprint_info, partition_num))
775    }
776
777    fn get_actor_info(
778        &mut self,
779        actor_object_type: ActorStateRef,
780    ) -> Result<
781        (
782            NodeId,
783            Option<AttachedModuleId>,
784            Rc<BlueprintDefinition>,
785            BlueprintInfo,
786        ),
787        RuntimeError,
788    > {
789        let (node_id, module_id) = self.get_actor_object_id(actor_object_type)?;
790        let blueprint_info = self.get_blueprint_info(&node_id, module_id)?;
791        let blueprint_definition =
792            self.get_blueprint_default_definition(blueprint_info.blueprint_id.clone())?;
793
794        Ok((node_id, module_id, blueprint_definition, blueprint_info))
795    }
796
797    fn get_actor_field_info(
798        &mut self,
799        actor_object_type: ActorStateRef,
800        field_index: u8,
801    ) -> Result<(NodeId, BlueprintInfo, PartitionNumber, FieldTransience), RuntimeError> {
802        let (node_id, module_id, blueprint_definition, info) =
803            self.get_actor_info(actor_object_type)?;
804
805        let (partition_description, field_schema) = blueprint_definition
806            .interface
807            .state
808            .field(field_index)
809            .ok_or_else(|| {
810                RuntimeError::SystemError(SystemError::FieldDoesNotExist(
811                    info.blueprint_id.clone(),
812                    field_index,
813                ))
814            })?;
815
816        match field_schema.condition {
817            Condition::IfFeature(feature) => {
818                if !self.is_feature_enabled(&node_id, module_id, feature.as_str())? {
819                    return Err(RuntimeError::SystemError(SystemError::FieldDoesNotExist(
820                        info.blueprint_id.clone(),
821                        field_index,
822                    )));
823                }
824            }
825            Condition::IfOuterFeature(feature) => {
826                let parent_id = match info.outer_obj_info {
827                    OuterObjectInfo::Some { outer_object } => outer_object.into_node_id(),
828                    OuterObjectInfo::None => {
829                        panic!("Outer object should not have IfOuterFeature.")
830                    }
831                };
832
833                if !self.is_feature_enabled(&parent_id, None, feature.as_str())? {
834                    return Err(RuntimeError::SystemError(SystemError::FieldDoesNotExist(
835                        info.blueprint_id.clone(),
836                        field_index,
837                    )));
838                }
839            }
840            Condition::Always => {}
841        }
842
843        let partition_num = match partition_description {
844            PartitionDescription::Physical(partition_num) => partition_num,
845            PartitionDescription::Logical(offset) => {
846                let base = match module_id {
847                    None => MAIN_BASE_PARTITION,
848                    Some(module_id) => {
849                        let object_module: ModuleId = module_id.into();
850                        object_module.base_partition_num()
851                    }
852                };
853                base.at_offset(offset).expect("Module number overflow")
854            }
855        };
856
857        Ok((node_id, info, partition_num, field_schema.transience))
858    }
859
860    /// ASSUMPTIONS:
861    /// Assumes the caller has already checked that the entity type on the GlobalAddress is valid
862    /// against the given self module.
863    fn globalize_with_address_internal(
864        &mut self,
865        node_id: NodeId,
866        modules: IndexMap<AttachedModuleId, NodeId>,
867        global_address_reservation: GlobalAddressReservation,
868    ) -> Result<GlobalAddress, RuntimeError> {
869        // Check global address reservation
870        let global_address = {
871            let dropped_node = self.kernel_drop_node(global_address_reservation.0.as_node_id())?;
872
873            let type_info: Option<TypeInfoSubstate> = dropped_node
874                .substates
875                .get(&TYPE_INFO_FIELD_PARTITION)
876                .and_then(|x| x.get(&TypeInfoField::TypeInfo.into()))
877                .and_then(|x| x.as_typed().ok());
878
879            match type_info {
880                Some(TypeInfoSubstate::GlobalAddressReservation(x)) => x,
881                _ => {
882                    return Err(RuntimeError::SystemError(
883                        SystemError::InvalidGlobalAddressReservation,
884                    ));
885                }
886            }
887        };
888
889        // Check blueprint id
890        let reserved_blueprint_id = {
891            let lock_handle = self.kernel_open_substate(
892                global_address.as_node_id(),
893                TYPE_INFO_FIELD_PARTITION,
894                &TypeInfoField::TypeInfo.into(),
895                LockFlags::MUTABLE, // This is to ensure the substate is lock free!
896                SystemLockData::Default,
897            )?;
898            let type_info: TypeInfoSubstate =
899                self.kernel_read_substate(lock_handle)?.as_typed().unwrap();
900            self.kernel_close_substate(lock_handle)?;
901            match type_info {
902                TypeInfoSubstate::GlobalAddressPhantom(GlobalAddressPhantom { blueprint_id }) => {
903                    blueprint_id
904                }
905                _ => unreachable!(),
906            }
907        };
908
909        // For simplicity, a rule is enforced at system layer: only the package can globalize a node
910        // In the future, we may consider allowing customization at blueprint level.
911        let actor = self.current_actor();
912        if Some(reserved_blueprint_id.package_address) != actor.package_address() {
913            return Err(RuntimeError::SystemError(
914                SystemError::InvalidGlobalizeAccess(Box::new(InvalidGlobalizeAccess {
915                    package_address: reserved_blueprint_id.package_address,
916                    blueprint_name: reserved_blueprint_id.blueprint_name,
917                    actor_package: actor.package_address(),
918                })),
919            ));
920        }
921
922        // Check for required modules
923        if !modules.contains_key(&AttachedModuleId::RoleAssignment) {
924            return Err(RuntimeError::SystemError(SystemError::MissingModule(
925                ModuleId::RoleAssignment,
926            )));
927        }
928        if !modules.contains_key(&AttachedModuleId::Metadata) {
929            return Err(RuntimeError::SystemError(SystemError::MissingModule(
930                ModuleId::Metadata,
931            )));
932        }
933
934        self.api
935            .kernel_get_system_state()
936            .system
937            .modules
938            .add_replacement(
939                (node_id, ModuleId::Main),
940                (*global_address.as_node_id(), ModuleId::Main),
941            );
942
943        // Read the type info
944        let mut object_info = self.get_object_info(&node_id)?;
945
946        // Verify can globalize with address
947        let num_main_partitions = {
948            if object_info.is_global() {
949                return Err(RuntimeError::SystemError(SystemError::CannotGlobalize(
950                    CannotGlobalizeError::AlreadyGlobalized,
951                )));
952            }
953            if !object_info
954                .blueprint_info
955                .blueprint_id
956                .eq(&reserved_blueprint_id)
957            {
958                return Err(RuntimeError::SystemError(SystemError::CannotGlobalize(
959                    CannotGlobalizeError::InvalidBlueprintId,
960                )));
961            }
962            let blueprint_definition = self.get_blueprint_default_definition(
963                object_info.blueprint_info.blueprint_id.clone(),
964            )?;
965
966            if blueprint_definition.interface.is_transient {
967                return Err(RuntimeError::SystemError(
968                    SystemError::GlobalizingTransientBlueprint,
969                ));
970            }
971
972            blueprint_definition
973                .interface
974                .state
975                .num_logical_partitions()
976        };
977
978        let mut partitions = btreemap!(
979            SCHEMAS_PARTITION => (node_id, SCHEMAS_PARTITION),
980        );
981
982        // Move self modules to the newly created global node, and drop
983        for offset in 0u8..num_main_partitions {
984            let partition_number = MAIN_BASE_PARTITION
985                .at_offset(PartitionOffset(offset))
986                .unwrap();
987
988            partitions.insert(partition_number, (node_id, partition_number));
989        }
990
991        // Move other modules, and drop
992        for (module_id, node_id) in &modules {
993            match module_id {
994                AttachedModuleId::RoleAssignment
995                | AttachedModuleId::Metadata
996                | AttachedModuleId::Royalty => {
997                    let blueprint_id = self.get_object_info(node_id)?.blueprint_info.blueprint_id;
998                    let expected_blueprint = module_id.static_blueprint();
999                    if !blueprint_id.eq(&expected_blueprint) {
1000                        return Err(RuntimeError::SystemError(SystemError::InvalidModuleType(
1001                            Box::new(InvalidModuleType {
1002                                expected_blueprint,
1003                                actual_blueprint: blueprint_id,
1004                            }),
1005                        )));
1006                    }
1007
1008                    self.api
1009                        .kernel_get_system_state()
1010                        .system
1011                        .modules
1012                        .add_replacement(
1013                            (*node_id, ModuleId::Main),
1014                            (*global_address.as_node_id(), (*module_id).into()),
1015                        );
1016
1017                    // Move and drop
1018                    let blueprint_definition =
1019                        self.get_blueprint_default_definition(blueprint_id.clone())?;
1020                    let num_logical_partitions = blueprint_definition
1021                        .interface
1022                        .state
1023                        .num_logical_partitions();
1024
1025                    let module_id: ModuleId = (*module_id).into();
1026                    let module_base_partition = module_id.base_partition_num();
1027                    for offset in 0u8..num_logical_partitions {
1028                        let src = MAIN_BASE_PARTITION
1029                            .at_offset(PartitionOffset(offset))
1030                            .unwrap();
1031                        let dest = module_base_partition
1032                            .at_offset(PartitionOffset(offset))
1033                            .unwrap();
1034
1035                        partitions.insert(dest, (*node_id, src));
1036                    }
1037                }
1038            }
1039        }
1040
1041        self.kernel_create_node_from(global_address.into(), partitions)?;
1042
1043        // Update Object Info
1044        {
1045            let mut module_versions = index_map_new();
1046            for module_id in modules.keys() {
1047                module_versions.insert(*module_id, BlueprintVersion::default());
1048            }
1049            object_info.object_type = ObjectType::Global {
1050                modules: module_versions,
1051            };
1052
1053            self.kernel_set_substate(
1054                &global_address.into(),
1055                TYPE_INFO_FIELD_PARTITION,
1056                SubstateKey::Field(0u8),
1057                IndexedScryptoValue::from_typed(&TypeInfoSubstate::Object(object_info)),
1058            )?;
1059        }
1060
1061        // Drop nodes
1062        {
1063            self.kernel_drop_node(&node_id)?;
1064            for (_module_id, node_id) in &modules {
1065                self.kernel_drop_node(node_id)?;
1066            }
1067        }
1068
1069        Ok(global_address)
1070    }
1071
1072    #[cfg_attr(feature = "std", catch_unwind_ignore)]
1073    pub fn current_actor(&mut self) -> Actor {
1074        self.api
1075            .kernel_get_system_state()
1076            .current_call_frame
1077            .clone()
1078    }
1079
1080    pub fn get_object_info(&mut self, node_id: &NodeId) -> Result<ObjectInfo, RuntimeError> {
1081        let type_info = TypeInfoBlueprint::get_type(node_id, self.api)?;
1082        let object_info = match type_info {
1083            TypeInfoSubstate::Object(info) => info,
1084            _ => return Err(RuntimeError::SystemError(SystemError::NotAnObject)),
1085        };
1086
1087        Ok(object_info)
1088    }
1089
1090    pub fn is_feature_enabled(
1091        &mut self,
1092        node_id: &NodeId,
1093        module_id: Option<AttachedModuleId>,
1094        feature: &str,
1095    ) -> Result<bool, RuntimeError> {
1096        match module_id {
1097            None => {
1098                let object_info = self.get_object_info(node_id)?;
1099                let enabled = object_info.blueprint_info.features.contains(feature);
1100                Ok(enabled)
1101            }
1102            _ => Ok(false),
1103        }
1104    }
1105}
1106
1107#[cfg_attr(
1108    feature = "std",
1109    catch_unwind(crate::utils::catch_unwind_system_panic_transformer)
1110)]
1111impl<'a, Y: SystemBasedKernelApi> SystemFieldApi<RuntimeError> for SystemService<'a, Y> {
1112    // Costing through kernel
1113    #[trace_resources]
1114    fn field_read(&mut self, handle: FieldHandle) -> Result<Vec<u8>, RuntimeError> {
1115        let data = self.api.kernel_get_lock_data(handle)?;
1116        match data {
1117            SystemLockData::Field(..) => {}
1118            _ => {
1119                return Err(RuntimeError::SystemError(SystemError::NotAFieldHandle));
1120            }
1121        }
1122
1123        self.api.kernel_read_substate(handle).map(|v| {
1124            let wrapper: FieldSubstate<ScryptoValue> = v.as_typed().unwrap();
1125            scrypto_encode(&wrapper.into_payload()).unwrap()
1126        })
1127    }
1128
1129    // Costing through kernel
1130    #[trace_resources]
1131    fn field_write(&mut self, handle: FieldHandle, buffer: Vec<u8>) -> Result<(), RuntimeError> {
1132        let data = self.api.kernel_get_lock_data(handle)?;
1133
1134        match data {
1135            SystemLockData::Field(FieldLockData::Write {
1136                target,
1137                field_index,
1138            }) => {
1139                self.validate_blueprint_payload(
1140                    &target,
1141                    BlueprintPayloadIdentifier::Field(field_index),
1142                    &buffer,
1143                )?;
1144            }
1145            _ => {
1146                return Err(RuntimeError::SystemError(SystemError::NotAFieldWriteHandle));
1147            }
1148        };
1149
1150        let value: ScryptoValue =
1151            scrypto_decode(&buffer).expect("Should be valid due to payload check");
1152
1153        let substate = IndexedScryptoValue::from_typed(&FieldSubstate::new_unlocked_field(value));
1154
1155        self.api.kernel_write_substate(handle, substate)?;
1156
1157        Ok(())
1158    }
1159
1160    // Costing through kernel
1161    #[trace_resources]
1162    fn field_lock(&mut self, handle: FieldHandle) -> Result<(), RuntimeError> {
1163        let data = self.api.kernel_get_lock_data(handle)?;
1164
1165        match data {
1166            SystemLockData::Field(FieldLockData::Write { .. }) => {}
1167            _ => {
1168                return Err(RuntimeError::SystemError(SystemError::NotAFieldWriteHandle));
1169            }
1170        }
1171
1172        let v = self.api.kernel_read_substate(handle)?;
1173        let mut substate: FieldSubstate<ScryptoValue> = v.as_typed().unwrap();
1174        substate.lock();
1175        let indexed = IndexedScryptoValue::from_typed(&substate);
1176        self.api.kernel_write_substate(handle, indexed)?;
1177
1178        Ok(())
1179    }
1180
1181    // Costing through kernel
1182    #[trace_resources]
1183    fn field_close(&mut self, handle: FieldHandle) -> Result<(), RuntimeError> {
1184        let data = self.api.kernel_get_lock_data(handle)?;
1185        match data {
1186            SystemLockData::Field(..) => {}
1187            _ => {
1188                return Err(RuntimeError::SystemError(SystemError::NotAFieldHandle));
1189            }
1190        }
1191
1192        self.api.kernel_close_substate(handle)
1193    }
1194}
1195
1196#[cfg_attr(
1197    feature = "std",
1198    catch_unwind(crate::utils::catch_unwind_system_panic_transformer)
1199)]
1200impl<'a, Y: SystemBasedKernelApi> SystemObjectApi<RuntimeError> for SystemService<'a, Y> {
1201    // Costing through kernel
1202    #[trace_resources]
1203    fn new_object(
1204        &mut self,
1205        blueprint_ident: &str,
1206        features: Vec<&str>,
1207        generic_args: GenericArgs,
1208        fields: IndexMap<u8, FieldValue>,
1209        kv_entries: IndexMap<u8, IndexMap<Vec<u8>, KVEntry>>,
1210    ) -> Result<NodeId, RuntimeError> {
1211        let actor = self.current_actor();
1212        let package_address = actor
1213            .blueprint_id()
1214            .map(|b| b.package_address)
1215            .ok_or(RuntimeError::SystemError(SystemError::NoPackageAddress))?;
1216        let blueprint_id = BlueprintId::new(&package_address, blueprint_ident);
1217        let instance_context = actor.instance_context();
1218
1219        self.new_object_internal(
1220            &blueprint_id,
1221            features,
1222            instance_context,
1223            generic_args,
1224            fields,
1225            kv_entries,
1226        )
1227    }
1228
1229    // Costing through kernel
1230    #[trace_resources]
1231    fn allocate_global_address(
1232        &mut self,
1233        blueprint_id: BlueprintId,
1234    ) -> Result<(GlobalAddressReservation, GlobalAddress), RuntimeError> {
1235        let global_address_node_id = self.api.kernel_allocate_node_id(
1236            IDAllocation::Object {
1237                blueprint_id: blueprint_id.clone(),
1238                global: true,
1239            }
1240            .entity_type(),
1241        )?;
1242        let global_address = GlobalAddress::try_from(global_address_node_id.0).unwrap();
1243
1244        // Create global address reservation
1245        let global_address_reservation =
1246            self.prepare_global_address(blueprint_id, global_address)?;
1247
1248        // NOTE: Because allocated global address is represented as an owned object and nobody is allowed
1249        // to drop it except the system during globalization, we don't track the lifecycle of
1250        // allocated addresses.
1251
1252        Ok((global_address_reservation, global_address))
1253    }
1254
1255    // Costing through kernel
1256    #[trace_resources]
1257    fn allocate_virtual_global_address(
1258        &mut self,
1259        blueprint_id: BlueprintId,
1260        global_address: GlobalAddress,
1261    ) -> Result<GlobalAddressReservation, RuntimeError> {
1262        let global_address_reservation =
1263            self.prepare_global_address(blueprint_id, global_address)?;
1264
1265        Ok(global_address_reservation)
1266    }
1267
1268    // Costing through kernel
1269    #[trace_resources]
1270    fn globalize(
1271        &mut self,
1272        node_id: NodeId,
1273        modules: IndexMap<AttachedModuleId, NodeId>,
1274        address_reservation: Option<GlobalAddressReservation>,
1275    ) -> Result<GlobalAddress, RuntimeError> {
1276        // TODO: optimize by skipping address allocation
1277        let (global_address_reservation, global_address) =
1278            if let Some(reservation) = address_reservation {
1279                let address = self.get_reservation_address(reservation.0.as_node_id())?;
1280                (reservation, address)
1281            } else {
1282                let blueprint_id = self.get_object_info(&node_id)?.blueprint_info.blueprint_id;
1283                self.allocate_global_address(blueprint_id)?
1284            };
1285
1286        self.globalize_with_address_internal(node_id, modules, global_address_reservation)?;
1287
1288        Ok(global_address)
1289    }
1290
1291    // Costing through kernel
1292    #[trace_resources]
1293    fn globalize_with_address_and_create_inner_object_and_emit_event(
1294        &mut self,
1295        node_id: NodeId,
1296        modules: IndexMap<AttachedModuleId, NodeId>,
1297        address_reservation: GlobalAddressReservation,
1298        inner_object_blueprint: &str,
1299        inner_object_fields: IndexMap<u8, FieldValue>,
1300        event_name: &str,
1301        event_data: Vec<u8>,
1302    ) -> Result<(GlobalAddress, NodeId), RuntimeError> {
1303        let actor_blueprint = self.get_object_info(&node_id)?.blueprint_info.blueprint_id;
1304
1305        let global_address =
1306            self.globalize_with_address_internal(node_id, modules, address_reservation)?;
1307
1308        let blueprint_id =
1309            BlueprintId::new(&actor_blueprint.package_address, inner_object_blueprint);
1310
1311        let inner_object = self.new_object_internal(
1312            &blueprint_id,
1313            vec![],
1314            Some(InstanceContext {
1315                outer_object: global_address,
1316            }),
1317            GenericArgs::default(),
1318            inner_object_fields,
1319            indexmap!(),
1320        )?;
1321
1322        self.emit_event_internal(
1323            EmitterActor::AsObject(*global_address.as_node_id(), None),
1324            event_name.to_string(),
1325            event_data,
1326            EventFlags::empty(),
1327        )?;
1328
1329        Ok((global_address, inner_object))
1330    }
1331
1332    #[trace_resources]
1333    fn call_method(
1334        &mut self,
1335        receiver: &NodeId,
1336        method_name: &str,
1337        args: Vec<u8>,
1338    ) -> Result<Vec<u8>, RuntimeError> {
1339        let object_info = self.get_object_info(receiver)?;
1340
1341        let args = IndexedScryptoValue::from_vec(args).map_err(|e| {
1342            RuntimeError::SystemUpstreamError(SystemUpstreamError::InputDecodeError(e))
1343        })?;
1344
1345        let auth_actor_info = SystemModuleMixer::on_call_method(
1346            self,
1347            receiver,
1348            ModuleId::Main,
1349            false,
1350            method_name,
1351            &args,
1352        )?;
1353
1354        let rtn = self
1355            .api
1356            .kernel_invoke(Box::new(KernelInvocation {
1357                call_frame_data: Actor::Method(MethodActor {
1358                    method_type: MethodType::Main,
1359                    node_id: *receiver,
1360                    ident: method_name.to_string(),
1361                    auth_zone: auth_actor_info,
1362                    object_info,
1363                }),
1364                args,
1365            }))
1366            .map(|v| v.into())?;
1367
1368        SystemModuleMixer::on_call_method_finish(self, auth_actor_info)?;
1369
1370        Ok(rtn)
1371    }
1372
1373    #[trace_resources]
1374    fn call_direct_access_method(
1375        &mut self,
1376        receiver: &NodeId,
1377        method_name: &str,
1378        args: Vec<u8>,
1379    ) -> Result<Vec<u8>, RuntimeError> {
1380        let object_info = self.get_object_info(receiver)?;
1381
1382        let args = IndexedScryptoValue::from_vec(args).map_err(|e| {
1383            RuntimeError::SystemUpstreamError(SystemUpstreamError::InputDecodeError(e))
1384        })?;
1385
1386        let auth_actor_info = SystemModuleMixer::on_call_method(
1387            self,
1388            receiver,
1389            ModuleId::Main,
1390            true,
1391            method_name,
1392            &args,
1393        )?;
1394
1395        let rtn = self
1396            .api
1397            .kernel_invoke(Box::new(KernelInvocation {
1398                call_frame_data: Actor::Method(MethodActor {
1399                    method_type: MethodType::Direct,
1400                    node_id: *receiver,
1401                    ident: method_name.to_string(),
1402
1403                    auth_zone: auth_actor_info,
1404                    object_info,
1405                }),
1406                args,
1407            }))
1408            .map(|v| v.into())?;
1409
1410        SystemModuleMixer::on_call_method_finish(self, auth_actor_info)?;
1411
1412        Ok(rtn)
1413    }
1414
1415    // Costing through kernel
1416    #[trace_resources]
1417    fn call_module_method(
1418        &mut self,
1419        receiver: &NodeId,
1420        module_id: AttachedModuleId,
1421        method_name: &str,
1422        args: Vec<u8>,
1423    ) -> Result<Vec<u8>, RuntimeError> {
1424        // Key Value Stores do not have methods so we remove that possibility here
1425        let object_info = self.get_object_info(receiver)?;
1426        match &object_info.object_type {
1427            ObjectType::Owned => {
1428                return Err(RuntimeError::SystemError(
1429                    SystemError::ObjectModuleDoesNotExist(module_id),
1430                ));
1431            }
1432            ObjectType::Global { modules } => {
1433                if !modules.contains_key(&module_id) {
1434                    return Err(RuntimeError::SystemError(
1435                        SystemError::ObjectModuleDoesNotExist(module_id),
1436                    ));
1437                }
1438            }
1439        }
1440
1441        let args = IndexedScryptoValue::from_vec(args).map_err(|e| {
1442            RuntimeError::SystemUpstreamError(SystemUpstreamError::InputDecodeError(e))
1443        })?;
1444
1445        let auth_actor_info = SystemModuleMixer::on_call_method(
1446            self,
1447            receiver,
1448            module_id.into(),
1449            false,
1450            method_name,
1451            &args,
1452        )?;
1453
1454        let rtn = self
1455            .api
1456            .kernel_invoke(Box::new(KernelInvocation {
1457                call_frame_data: Actor::Method(MethodActor {
1458                    method_type: MethodType::Module(module_id),
1459                    node_id: *receiver,
1460                    ident: method_name.to_string(),
1461
1462                    auth_zone: auth_actor_info,
1463                    object_info,
1464                }),
1465                args,
1466            }))
1467            .map(|v| v.into())?;
1468
1469        SystemModuleMixer::on_call_method_finish(self, auth_actor_info)?;
1470
1471        Ok(rtn)
1472    }
1473
1474    // Costing through kernel
1475    #[trace_resources]
1476    fn get_blueprint_id(&mut self, node_id: &NodeId) -> Result<BlueprintId, RuntimeError> {
1477        let blueprint_id = self.get_object_info(node_id)?.blueprint_info.blueprint_id;
1478        Ok(blueprint_id)
1479    }
1480
1481    // Costing through kernel
1482    #[trace_resources]
1483    fn get_outer_object(&mut self, node_id: &NodeId) -> Result<GlobalAddress, RuntimeError> {
1484        match self.get_object_info(node_id)?.try_get_outer_object() {
1485            None => Err(RuntimeError::SystemError(
1486                SystemError::OuterObjectDoesNotExist,
1487            )),
1488            Some(address) => Ok(address),
1489        }
1490    }
1491
1492    // Costing through kernel
1493    #[trace_resources]
1494    fn get_reservation_address(&mut self, node_id: &NodeId) -> Result<GlobalAddress, RuntimeError> {
1495        let type_info = TypeInfoBlueprint::get_type(node_id, self.api)?;
1496        let address = match type_info {
1497            TypeInfoSubstate::GlobalAddressReservation(address) => address,
1498            _ => {
1499                return Err(RuntimeError::SystemError(
1500                    SystemError::NotAnAddressReservation,
1501                ))
1502            }
1503        };
1504
1505        Ok(address)
1506    }
1507
1508    // Costing through kernel
1509    #[trace_resources]
1510    fn drop_object(&mut self, node_id: &NodeId) -> Result<Vec<Vec<u8>>, RuntimeError> {
1511        // For simplicity, a rule is enforced at system layer: only the package can drop a node
1512        // In the future, we may consider allowing customization at blueprint level.
1513        let info = self.get_object_info(node_id)?;
1514        let actor = self.current_actor();
1515
1516        let instance_context_check = {
1517            // Allow proofs to be dropped on their own
1518            if info.blueprint_info.blueprint_id.eq(&BlueprintId::new(
1519                &RESOURCE_PACKAGE,
1520                FUNGIBLE_PROOF_BLUEPRINT,
1521            )) || info.blueprint_info.blueprint_id.eq(&BlueprintId::new(
1522                &RESOURCE_PACKAGE,
1523                NON_FUNGIBLE_PROOF_BLUEPRINT,
1524            )) {
1525                None
1526            } else {
1527                match info.blueprint_info.outer_obj_info {
1528                    OuterObjectInfo::Some { outer_object } => Some(outer_object),
1529                    OuterObjectInfo::None => None,
1530                }
1531            }
1532        };
1533
1534        // If outer object exists, only outer object may drop object
1535        if let Some(outer_object) = instance_context_check {
1536            match actor.instance_context() {
1537                Some(instance_context) if instance_context.outer_object.eq(&outer_object) => {}
1538                _ => {
1539                    return Err(RuntimeError::SystemError(SystemError::InvalidDropAccess(
1540                        Box::new(InvalidDropAccess {
1541                            node_id: (*node_id).into(),
1542                            package_address: info.blueprint_info.blueprint_id.package_address,
1543                            blueprint_name: info.blueprint_info.blueprint_id.blueprint_name,
1544                            actor_package: actor.package_address(),
1545                        }),
1546                    )));
1547                }
1548            }
1549        } else {
1550            // Otherwise, only blueprint may drop object
1551            if Some(info.blueprint_info.blueprint_id.clone()) != actor.blueprint_id() {
1552                return Err(RuntimeError::SystemError(SystemError::InvalidDropAccess(
1553                    Box::new(InvalidDropAccess {
1554                        node_id: (*node_id).into(),
1555                        package_address: info.blueprint_info.blueprint_id.package_address,
1556                        blueprint_name: info.blueprint_info.blueprint_id.blueprint_name,
1557                        actor_package: actor.package_address(),
1558                    }),
1559                )));
1560            }
1561        }
1562
1563        let mut dropped_node = self.api.kernel_drop_node(node_id)?;
1564        let fields =
1565            if let Some(user_substates) = dropped_node.substates.remove(&MAIN_BASE_PARTITION) {
1566                user_substates
1567                    .into_values()
1568                    .map(|v| {
1569                        let substate: FieldSubstate<ScryptoValue> = v.as_typed().unwrap();
1570                        scrypto_encode(&substate.into_payload()).unwrap()
1571                    })
1572                    .collect()
1573            } else {
1574                vec![]
1575            };
1576
1577        Ok(fields)
1578    }
1579}
1580
1581#[cfg_attr(
1582    feature = "std",
1583    catch_unwind(crate::utils::catch_unwind_system_panic_transformer)
1584)]
1585impl<'a, Y: SystemBasedKernelApi> SystemKeyValueEntryApi<RuntimeError> for SystemService<'a, Y> {
1586    // Costing through kernel
1587    #[trace_resources]
1588    fn key_value_entry_get(
1589        &mut self,
1590        handle: KeyValueEntryHandle,
1591    ) -> Result<Vec<u8>, RuntimeError> {
1592        let data = self.api.kernel_get_lock_data(handle)?;
1593        if !data.is_kv_entry() {
1594            return Err(RuntimeError::SystemError(
1595                SystemError::NotAKeyValueEntryHandle,
1596            ));
1597        }
1598
1599        self.api.kernel_read_substate(handle).map(|v| {
1600            let wrapper: KeyValueEntrySubstate<ScryptoValue> = v.as_typed().unwrap();
1601            scrypto_encode(&wrapper.into_value()).unwrap()
1602        })
1603    }
1604
1605    // Costing through kernel
1606    fn key_value_entry_lock(&mut self, handle: KeyValueEntryHandle) -> Result<(), RuntimeError> {
1607        let data = self.api.kernel_get_lock_data(handle)?;
1608        match data {
1609            SystemLockData::KeyValueEntry(
1610                KeyValueEntryLockData::KVStoreWrite { .. }
1611                | KeyValueEntryLockData::KVCollectionWrite { .. },
1612            ) => {}
1613            _ => {
1614                return Err(RuntimeError::SystemError(
1615                    SystemError::NotAKeyValueEntryWriteHandle,
1616                ));
1617            }
1618        };
1619
1620        let v = self.api.kernel_read_substate(handle)?;
1621        let mut kv_entry: KeyValueEntrySubstate<ScryptoValue> = v.as_typed().unwrap();
1622        kv_entry.lock();
1623        let indexed = IndexedScryptoValue::from_typed(&kv_entry);
1624        self.api.kernel_write_substate(handle, indexed)?;
1625        Ok(())
1626    }
1627
1628    // Costing through kernel
1629    fn key_value_entry_remove(
1630        &mut self,
1631        handle: KeyValueEntryHandle,
1632    ) -> Result<Vec<u8>, RuntimeError> {
1633        let data = self.api.kernel_get_lock_data(handle)?;
1634        if !data.is_kv_entry_with_write() {
1635            return Err(RuntimeError::SystemError(
1636                SystemError::NotAKeyValueEntryWriteHandle,
1637            ));
1638        }
1639
1640        let current_value = self
1641            .api
1642            .kernel_read_substate(handle)
1643            .map(|v| v.as_slice().to_vec())?;
1644
1645        let mut kv_entry: KeyValueEntrySubstate<ScryptoValue> =
1646            scrypto_decode(&current_value).unwrap();
1647        let value = kv_entry.remove();
1648        self.kernel_write_substate(handle, IndexedScryptoValue::from_typed(&kv_entry))?;
1649
1650        let current_value = scrypto_encode(&value).unwrap();
1651
1652        Ok(current_value)
1653    }
1654
1655    // Costing through kernel
1656    #[trace_resources]
1657    fn key_value_entry_set(
1658        &mut self,
1659        handle: KeyValueEntryHandle,
1660        buffer: Vec<u8>,
1661    ) -> Result<(), RuntimeError> {
1662        let data = self.api.kernel_get_lock_data(handle)?;
1663
1664        match data {
1665            SystemLockData::KeyValueEntry(KeyValueEntryLockData::KVCollectionWrite {
1666                collection_index,
1667                target,
1668            }) => {
1669                self.validate_blueprint_payload(
1670                    &target,
1671                    BlueprintPayloadIdentifier::KeyValueEntry(collection_index, KeyOrValue::Value),
1672                    &buffer,
1673                )?;
1674            }
1675            SystemLockData::KeyValueEntry(KeyValueEntryLockData::KVStoreWrite {
1676                kv_store_validation_target,
1677            }) => {
1678                self.validate_kv_store_payload(
1679                    &kv_store_validation_target,
1680                    KeyOrValue::Value,
1681                    &buffer,
1682                )?;
1683            }
1684            _ => {
1685                return Err(RuntimeError::SystemError(
1686                    SystemError::NotAKeyValueEntryWriteHandle,
1687                ));
1688            }
1689        }
1690
1691        let substate =
1692            IndexedScryptoValue::from_slice(&buffer).expect("Should be valid due to payload check");
1693
1694        let value = substate.as_scrypto_value().clone();
1695        let kv_entry = KeyValueEntrySubstate::unlocked_entry(value);
1696        let indexed = IndexedScryptoValue::from_typed(&kv_entry);
1697
1698        self.api.kernel_write_substate(handle, indexed)?;
1699
1700        Ok(())
1701    }
1702
1703    // Costing through kernel
1704    fn key_value_entry_close(&mut self, handle: KeyValueEntryHandle) -> Result<(), RuntimeError> {
1705        let data = self.api.kernel_get_lock_data(handle)?;
1706        if !data.is_kv_entry() {
1707            return Err(RuntimeError::SystemError(
1708                SystemError::NotAKeyValueEntryHandle,
1709            ));
1710        }
1711
1712        self.api.kernel_close_substate(handle)
1713    }
1714}
1715
1716#[cfg_attr(
1717    feature = "std",
1718    catch_unwind(crate::utils::catch_unwind_system_panic_transformer)
1719)]
1720impl<'a, Y: SystemBasedKernelApi> SystemKeyValueStoreApi<RuntimeError> for SystemService<'a, Y> {
1721    // Costing through kernel
1722    #[trace_resources]
1723    fn key_value_store_new(
1724        &mut self,
1725        data_schema: KeyValueStoreDataSchema,
1726    ) -> Result<NodeId, RuntimeError> {
1727        let mut additional_schemas = index_map_new();
1728        let (key_type, value_type, allow_ownership) = match data_schema {
1729            KeyValueStoreDataSchema::Local {
1730                additional_schema,
1731                key_type,
1732                value_type,
1733                allow_ownership,
1734            } => {
1735                validate_schema(additional_schema.v1())
1736                    .map_err(|_| RuntimeError::SystemError(SystemError::InvalidGenericArgs))?;
1737                let schema_hash = additional_schema.generate_schema_hash();
1738                additional_schemas.insert(schema_hash, additional_schema);
1739                (
1740                    GenericSubstitution::Local(ScopedTypeId(schema_hash, key_type)),
1741                    GenericSubstitution::Local(ScopedTypeId(schema_hash, value_type)),
1742                    allow_ownership,
1743                )
1744            }
1745            KeyValueStoreDataSchema::Remote {
1746                key_type,
1747                value_type,
1748                allow_ownership,
1749            } => (
1750                GenericSubstitution::Remote(key_type),
1751                GenericSubstitution::Remote(value_type),
1752                allow_ownership,
1753            ),
1754        };
1755
1756        self.validate_kv_store_generic_args(&additional_schemas, &key_type, &value_type)
1757            .map_err(|e| RuntimeError::SystemError(SystemError::TypeCheckError(e)))?;
1758
1759        let schema_partition = additional_schemas
1760            .into_iter()
1761            .map(|(schema_hash, schema)| {
1762                let key = SubstateKey::Map(scrypto_encode(&schema_hash).unwrap());
1763                let substate = KeyValueEntrySubstate::locked_entry(schema);
1764                let value = IndexedScryptoValue::from_typed(&substate);
1765                (key, value)
1766            })
1767            .collect();
1768
1769        let generic_substitutions = KeyValueStoreGenericSubstitutions {
1770            key_generic_substitution: key_type,
1771            value_generic_substitution: value_type,
1772            allow_ownership,
1773        };
1774
1775        let node_id = self
1776            .api
1777            .kernel_allocate_node_id(IDAllocation::KeyValueStore.entity_type())?;
1778
1779        self.api.kernel_create_node(
1780            node_id,
1781            btreemap!(
1782                MAIN_BASE_PARTITION => btreemap!(),
1783                TYPE_INFO_FIELD_PARTITION => type_info_partition(
1784                    TypeInfoSubstate::KeyValueStore(KeyValueStoreInfo {
1785                        generic_substitutions,
1786                    })
1787                ),
1788                SCHEMAS_PARTITION => schema_partition,
1789            ),
1790        )?;
1791
1792        Ok(node_id)
1793    }
1794
1795    // Costing through kernel
1796    #[trace_resources]
1797    fn key_value_store_open_entry(
1798        &mut self,
1799        node_id: &NodeId,
1800        key: &Vec<u8>,
1801        flags: LockFlags,
1802    ) -> Result<KeyValueEntryHandle, RuntimeError> {
1803        let type_info = TypeInfoBlueprint::get_type(node_id, self.api)?;
1804
1805        if flags.contains(LockFlags::UNMODIFIED_BASE) || flags.contains(LockFlags::FORCE_WRITE) {
1806            return Err(RuntimeError::SystemError(SystemError::InvalidLockFlags));
1807        }
1808
1809        let info = match type_info {
1810            TypeInfoSubstate::KeyValueStore(info) => info,
1811            _ => return Err(RuntimeError::SystemError(SystemError::NotAKeyValueStore)),
1812        };
1813
1814        let target = KVStoreTypeTarget {
1815            kv_store_type: info.generic_substitutions,
1816            meta: *node_id,
1817        };
1818
1819        self.validate_kv_store_payload(&target, KeyOrValue::Key, key)?;
1820
1821        let lock_data = if flags.contains(LockFlags::MUTABLE) {
1822            SystemLockData::KeyValueEntry(KeyValueEntryLockData::KVStoreWrite {
1823                kv_store_validation_target: target,
1824            })
1825        } else {
1826            SystemLockData::KeyValueEntry(KeyValueEntryLockData::Read)
1827        };
1828
1829        let handle = self.api.kernel_open_substate_with_default(
1830            node_id,
1831            MAIN_BASE_PARTITION,
1832            &SubstateKey::Map(key.clone()),
1833            flags,
1834            Some(|| {
1835                let kv_entry = KeyValueEntrySubstate::<()>::default();
1836                IndexedScryptoValue::from_typed(&kv_entry)
1837            }),
1838            lock_data,
1839        )?;
1840
1841        if flags.contains(LockFlags::MUTABLE) {
1842            let lock_status = self.api.kernel_read_substate(handle).map(|v| {
1843                let kv_entry: KeyValueEntrySubstate<ScryptoValue> = v.as_typed().unwrap();
1844                kv_entry.lock_status()
1845            })?;
1846
1847            if let LockStatus::Locked = lock_status {
1848                return Err(RuntimeError::SystemError(SystemError::KeyValueEntryLocked));
1849            }
1850        }
1851
1852        Ok(handle)
1853    }
1854
1855    // Costing through kernel
1856    fn key_value_store_remove_entry(
1857        &mut self,
1858        node_id: &NodeId,
1859        key: &Vec<u8>,
1860    ) -> Result<Vec<u8>, RuntimeError> {
1861        let handle = self.key_value_store_open_entry(node_id, key, LockFlags::MUTABLE)?;
1862        self.key_value_entry_remove_and_close_substate(handle)
1863    }
1864}
1865
1866#[cfg_attr(
1867    feature = "std",
1868    catch_unwind(crate::utils::catch_unwind_system_panic_transformer)
1869)]
1870impl<'a, Y: SystemBasedKernelApi> SystemActorIndexApi<RuntimeError> for SystemService<'a, Y> {
1871    // Costing through kernel
1872    fn actor_index_insert(
1873        &mut self,
1874        object_handle: ActorStateHandle,
1875        collection_index: CollectionIndex,
1876        key: Vec<u8>,
1877        buffer: Vec<u8>,
1878    ) -> Result<(), RuntimeError> {
1879        let actor_object_type: ActorStateRef = object_handle.try_into()?;
1880
1881        let (node_id, info, partition_num) = self.get_actor_collection_partition_info(
1882            actor_object_type,
1883            collection_index,
1884            &BlueprintPartitionType::IndexCollection,
1885        )?;
1886
1887        let target = BlueprintTypeTarget {
1888            blueprint_info: info,
1889            meta: SchemaValidationMeta::ExistingObject {
1890                additional_schemas: node_id,
1891            },
1892        };
1893
1894        self.validate_blueprint_payload(
1895            &target,
1896            BlueprintPayloadIdentifier::IndexEntry(collection_index, KeyOrValue::Key),
1897            &key,
1898        )?;
1899
1900        self.validate_blueprint_payload(
1901            &target,
1902            BlueprintPayloadIdentifier::IndexEntry(collection_index, KeyOrValue::Value),
1903            &buffer,
1904        )?;
1905
1906        let value: ScryptoValue = scrypto_decode(&buffer).unwrap();
1907        let index_entry = IndexEntrySubstate::entry(value);
1908        let value = IndexedScryptoValue::from_typed(&index_entry);
1909
1910        self.api
1911            .kernel_set_substate(&node_id, partition_num, SubstateKey::Map(key), value)
1912    }
1913
1914    // Costing through kernel
1915    fn actor_index_remove(
1916        &mut self,
1917        object_handle: ActorStateHandle,
1918        collection_index: CollectionIndex,
1919        key: Vec<u8>,
1920    ) -> Result<Option<Vec<u8>>, RuntimeError> {
1921        let actor_object_type: ActorStateRef = object_handle.try_into()?;
1922
1923        let (node_id, _info, partition_num) = self.get_actor_collection_partition_info(
1924            actor_object_type,
1925            collection_index,
1926            &BlueprintPartitionType::IndexCollection,
1927        )?;
1928
1929        let rtn = self
1930            .api
1931            .kernel_remove_substate(&node_id, partition_num, &SubstateKey::Map(key))?
1932            .map(|v| {
1933                let value: IndexEntrySubstate<ScryptoValue> = v.as_typed().unwrap();
1934                scrypto_encode(value.value()).unwrap()
1935            });
1936
1937        Ok(rtn)
1938    }
1939
1940    // Costing through kernel
1941    fn actor_index_scan_keys(
1942        &mut self,
1943        object_handle: ActorStateHandle,
1944        collection_index: CollectionIndex,
1945        limit: u32,
1946    ) -> Result<Vec<Vec<u8>>, RuntimeError> {
1947        let actor_object_type: ActorStateRef = object_handle.try_into()?;
1948
1949        let (node_id, _info, partition_num) = self.get_actor_collection_partition_info(
1950            actor_object_type,
1951            collection_index,
1952            &BlueprintPartitionType::IndexCollection,
1953        )?;
1954
1955        let substates = self
1956            .api
1957            .kernel_scan_keys::<MapKey>(&node_id, partition_num, limit)?
1958            .into_iter()
1959            .map(|key| key.into_map())
1960            .collect();
1961
1962        Ok(substates)
1963    }
1964
1965    // Costing through kernel
1966    fn actor_index_drain(
1967        &mut self,
1968        object_handle: ActorStateHandle,
1969        collection_index: CollectionIndex,
1970        limit: u32,
1971    ) -> Result<Vec<(Vec<u8>, Vec<u8>)>, RuntimeError> {
1972        let actor_object_type: ActorStateRef = object_handle.try_into()?;
1973
1974        let (node_id, _info, partition_num) = self.get_actor_collection_partition_info(
1975            actor_object_type,
1976            collection_index,
1977            &BlueprintPartitionType::IndexCollection,
1978        )?;
1979
1980        let substates = self
1981            .api
1982            .kernel_drain_substates::<MapKey>(&node_id, partition_num, limit)?
1983            .into_iter()
1984            .map(|(key, value)| {
1985                let value: IndexEntrySubstate<ScryptoValue> = value.as_typed().unwrap();
1986                let value = scrypto_encode(value.value()).unwrap();
1987
1988                (key.into_map(), value)
1989            })
1990            .collect();
1991
1992        Ok(substates)
1993    }
1994}
1995
1996#[cfg_attr(
1997    feature = "std",
1998    catch_unwind(crate::utils::catch_unwind_system_panic_transformer)
1999)]
2000impl<'a, Y: SystemBasedKernelApi> SystemActorSortedIndexApi<RuntimeError> for SystemService<'a, Y> {
2001    // Costing through kernel
2002    #[trace_resources]
2003    fn actor_sorted_index_insert(
2004        &mut self,
2005        object_handle: ActorStateHandle,
2006        collection_index: CollectionIndex,
2007        sorted_key: SortedKey,
2008        buffer: Vec<u8>,
2009    ) -> Result<(), RuntimeError> {
2010        let actor_object_type: ActorStateRef = object_handle.try_into()?;
2011
2012        let (node_id, info, partition_num) = self.get_actor_collection_partition_info(
2013            actor_object_type,
2014            collection_index,
2015            &BlueprintPartitionType::SortedIndexCollection,
2016        )?;
2017
2018        let target = BlueprintTypeTarget {
2019            blueprint_info: info,
2020            meta: SchemaValidationMeta::ExistingObject {
2021                additional_schemas: node_id,
2022            },
2023        };
2024
2025        self.validate_blueprint_payload(
2026            &target,
2027            BlueprintPayloadIdentifier::SortedIndexEntry(collection_index, KeyOrValue::Key),
2028            &sorted_key.1,
2029        )?;
2030
2031        self.validate_blueprint_payload(
2032            &target,
2033            BlueprintPayloadIdentifier::SortedIndexEntry(collection_index, KeyOrValue::Value),
2034            &buffer,
2035        )?;
2036
2037        let value: ScryptoValue = scrypto_decode(&buffer).unwrap();
2038        let sorted_entry = SortedIndexEntrySubstate::entry(value);
2039        let value = IndexedScryptoValue::from_typed(&sorted_entry);
2040
2041        self.api.kernel_set_substate(
2042            &node_id,
2043            partition_num,
2044            SubstateKey::Sorted((sorted_key.0, sorted_key.1)),
2045            value,
2046        )
2047    }
2048
2049    // Costing through kernel
2050    #[trace_resources]
2051    fn actor_sorted_index_remove(
2052        &mut self,
2053        object_handle: ActorStateHandle,
2054        collection_index: CollectionIndex,
2055        sorted_key: &SortedKey,
2056    ) -> Result<Option<Vec<u8>>, RuntimeError> {
2057        let actor_object_type: ActorStateRef = object_handle.try_into()?;
2058
2059        let (node_id, _info, partition_num) = self.get_actor_collection_partition_info(
2060            actor_object_type,
2061            collection_index,
2062            &BlueprintPartitionType::SortedIndexCollection,
2063        )?;
2064
2065        let rtn = self
2066            .api
2067            .kernel_remove_substate(
2068                &node_id,
2069                partition_num,
2070                &SubstateKey::Sorted((sorted_key.0, sorted_key.1.clone())),
2071            )?
2072            .map(|v| {
2073                let value: SortedIndexEntrySubstate<ScryptoValue> = v.as_typed().unwrap();
2074                scrypto_encode(value.value()).unwrap()
2075            });
2076
2077        Ok(rtn)
2078    }
2079
2080    // Costing through kernel
2081    #[trace_resources]
2082    fn actor_sorted_index_scan(
2083        &mut self,
2084        object_handle: ActorStateHandle,
2085        collection_index: CollectionIndex,
2086        limit: u32,
2087    ) -> Result<Vec<(SortedKey, Vec<u8>)>, RuntimeError> {
2088        let actor_object_type: ActorStateRef = object_handle.try_into()?;
2089
2090        let (node_id, _info, partition_num) = self.get_actor_collection_partition_info(
2091            actor_object_type,
2092            collection_index,
2093            &BlueprintPartitionType::SortedIndexCollection,
2094        )?;
2095
2096        let substates = self
2097            .api
2098            .kernel_scan_sorted_substates(&node_id, partition_num, limit)?
2099            .into_iter()
2100            .map(|(key, value)| {
2101                let value: SortedIndexEntrySubstate<ScryptoValue> = value.as_typed().unwrap();
2102                let value = scrypto_encode(value.value()).unwrap();
2103
2104                (key, value)
2105            })
2106            .collect();
2107
2108        Ok(substates)
2109    }
2110}
2111
2112#[cfg_attr(
2113    feature = "std",
2114    catch_unwind(crate::utils::catch_unwind_system_panic_transformer)
2115)]
2116impl<'a, Y: SystemBasedKernelApi> SystemBlueprintApi<RuntimeError> for SystemService<'a, Y> {
2117    // Costing through kernel
2118    fn call_function(
2119        &mut self,
2120        package_address: PackageAddress,
2121        blueprint_name: &str,
2122        function_name: &str,
2123        args: Vec<u8>,
2124    ) -> Result<Vec<u8>, RuntimeError> {
2125        let args = IndexedScryptoValue::from_vec(args).map_err(|e| {
2126            RuntimeError::SystemUpstreamError(SystemUpstreamError::InputDecodeError(e))
2127        })?;
2128        let blueprint_id = BlueprintId::new(&package_address, blueprint_name);
2129        let auth_zone = SystemModuleMixer::on_call_function(self, &blueprint_id, function_name)?;
2130
2131        let rtn = self
2132            .api
2133            .kernel_invoke(Box::new(KernelInvocation {
2134                call_frame_data: Actor::Function(FunctionActor {
2135                    blueprint_id,
2136                    ident: function_name.to_string(),
2137                    auth_zone,
2138                }),
2139                args,
2140            }))
2141            .map(|v| v.into())?;
2142
2143        SystemModuleMixer::on_call_function_finish(self, auth_zone)?;
2144
2145        Ok(rtn)
2146    }
2147
2148    fn resolve_blueprint_type(
2149        &mut self,
2150        blueprint_type_id: &BlueprintTypeIdentifier,
2151    ) -> Result<(Rc<VersionedScryptoSchema>, ScopedTypeId), RuntimeError> {
2152        self.get_blueprint_type_schema(blueprint_type_id)
2153    }
2154}
2155
2156#[cfg_attr(
2157    feature = "std",
2158    catch_unwind(crate::utils::catch_unwind_system_panic_transformer)
2159)]
2160impl<'a, Y: SystemBasedKernelApi> SystemCostingApi<RuntimeError> for SystemService<'a, Y> {
2161    fn consume_cost_units(
2162        &mut self,
2163        costing_entry: ClientCostingEntry,
2164    ) -> Result<(), RuntimeError> {
2165        let system_logic = self
2166            .api
2167            .kernel_get_system_state()
2168            .system
2169            .versioned_system_logic;
2170        if !system_logic.should_consume_cost_units(self.api) {
2171            return Ok(());
2172        }
2173
2174        self.api
2175            .kernel_get_system()
2176            .modules
2177            .apply_execution_cost(match costing_entry {
2178                ClientCostingEntry::RunNativeCode {
2179                    package_address,
2180                    export_name,
2181                    input_size,
2182                } => ExecutionCostingEntry::RunNativeCode {
2183                    package_address,
2184                    export_name,
2185                    input_size,
2186                },
2187                ClientCostingEntry::RunWasmCode {
2188                    package_address,
2189                    export_name,
2190                    wasm_execution_units,
2191                } => ExecutionCostingEntry::RunWasmCode {
2192                    package_address,
2193                    export_name,
2194                    wasm_execution_units,
2195                },
2196                ClientCostingEntry::PrepareWasmCode { size } => {
2197                    ExecutionCostingEntry::PrepareWasmCode { size }
2198                }
2199                ClientCostingEntry::Bls12381V1Verify { size } => {
2200                    ExecutionCostingEntry::Bls12381V1Verify { size }
2201                }
2202                ClientCostingEntry::Bls12381V1AggregateVerify { sizes } => {
2203                    ExecutionCostingEntry::Bls12381V1AggregateVerify { sizes }
2204                }
2205                ClientCostingEntry::Bls12381V1FastAggregateVerify { size, keys_cnt } => {
2206                    ExecutionCostingEntry::Bls12381V1FastAggregateVerify { size, keys_cnt }
2207                }
2208                ClientCostingEntry::Bls12381G2SignatureAggregate { signatures_cnt } => {
2209                    ExecutionCostingEntry::Bls12381G2SignatureAggregate { signatures_cnt }
2210                }
2211                ClientCostingEntry::Keccak256Hash { size } => {
2212                    ExecutionCostingEntry::Keccak256Hash { size }
2213                }
2214                ClientCostingEntry::Blake2b256Hash { size } => {
2215                    ExecutionCostingEntry::Blake2b256Hash { size }
2216                }
2217                ClientCostingEntry::Ed25519Verify { size } => {
2218                    ExecutionCostingEntry::Ed25519Verify { size }
2219                }
2220                ClientCostingEntry::Secp256k1EcdsaVerify => {
2221                    ExecutionCostingEntry::Secp256k1EcdsaVerify
2222                }
2223                ClientCostingEntry::Secp256k1EcdsaKeyRecover => {
2224                    ExecutionCostingEntry::Secp256k1EcdsaVerifyAndKeyRecover
2225                }
2226            })
2227    }
2228
2229    #[trace_resources]
2230    fn start_lock_fee(&mut self, amount: Decimal, contingent: bool) -> Result<bool, RuntimeError> {
2231        // Child subintents are only allowed to use contingent fees
2232        if !contingent {
2233            let stack_id = self.api.kernel_get_current_stack_id_uncosted();
2234            if stack_id != 0 {
2235                return Err(RuntimeError::SystemError(
2236                    SystemError::CannotLockFeeInChildSubintent(stack_id),
2237                ));
2238            }
2239        }
2240
2241        let costing_enabled = self
2242            .api
2243            .kernel_get_system()
2244            .modules
2245            .enabled_modules
2246            .contains(EnabledModules::COSTING);
2247
2248        // We do costing up front
2249        self.api
2250            .kernel_get_system()
2251            .modules
2252            .apply_execution_cost(ExecutionCostingEntry::LockFee)?;
2253
2254        let event_data = {
2255            let lock_fee_event = LockFeeEvent { amount };
2256            scrypto_encode(&lock_fee_event).unwrap()
2257        };
2258
2259        // If costing is enabled, reserve event and pay for the event up front for the call to lock_fee()
2260        // Otherwise, we just simulate the call
2261        if costing_enabled {
2262            self.api
2263                .kernel_get_system()
2264                .modules
2265                .assert_can_add_event()?;
2266            self.api.kernel_get_system().modules.apply_execution_cost(
2267                ExecutionCostingEntry::EmitEvent {
2268                    size: event_data.len(),
2269                },
2270            )?;
2271        } else {
2272            self.emit_event_internal(
2273                EmitterActor::CurrentActor,
2274                LockFeeEvent::EVENT_NAME.to_string(),
2275                event_data,
2276                EventFlags::FORCE_WRITE,
2277            )?;
2278        }
2279
2280        Ok(costing_enabled)
2281    }
2282
2283    #[trace_resources]
2284    #[cfg_attr(feature = "std", catch_unwind_ignore)]
2285    fn lock_fee(&mut self, locked_fee: LiquidFungibleResource, contingent: bool) {
2286        // Credit cost units
2287        let vault_id = self
2288            .current_actor()
2289            .node_id()
2290            .expect("Caller should only be fungible vault method");
2291        self.api
2292            .kernel_get_system()
2293            .modules
2294            .lock_fee(vault_id, locked_fee.clone(), contingent);
2295
2296        // Emit Locked Fee event
2297        {
2298            let type_identifier = EventTypeIdentifier(
2299                Emitter::Method(vault_id, ObjectModuleId::Main),
2300                LockFeeEvent::EVENT_NAME.to_string(),
2301            );
2302
2303            let lock_fee_event = LockFeeEvent {
2304                amount: locked_fee.amount(),
2305            };
2306            let payload = scrypto_encode(&lock_fee_event).unwrap();
2307
2308            let event = Event {
2309                type_identifier,
2310                payload,
2311                flags: EventFlags::FORCE_WRITE,
2312            };
2313
2314            self.api
2315                .kernel_get_system()
2316                .modules
2317                .add_event_unchecked(event)
2318                .expect("Event should never exceed size.");
2319        }
2320    }
2321
2322    fn execution_cost_unit_limit(&mut self) -> Result<u32, RuntimeError> {
2323        self.api
2324            .kernel_get_system()
2325            .modules
2326            .apply_execution_cost(ExecutionCostingEntry::QueryFeeReserve)?;
2327
2328        if let Some(fee_reserve) = self.api.kernel_get_system().modules.fee_reserve() {
2329            Ok(fee_reserve.execution_cost_unit_limit())
2330        } else {
2331            Err(RuntimeError::SystemError(
2332                SystemError::CostingModuleNotEnabled,
2333            ))
2334        }
2335    }
2336
2337    fn execution_cost_unit_price(&mut self) -> Result<Decimal, RuntimeError> {
2338        self.api
2339            .kernel_get_system()
2340            .modules
2341            .apply_execution_cost(ExecutionCostingEntry::QueryFeeReserve)?;
2342
2343        if let Some(fee_reserve) = self.api.kernel_get_system().modules.fee_reserve() {
2344            Ok(fee_reserve.execution_cost_unit_price())
2345        } else {
2346            Err(RuntimeError::SystemError(
2347                SystemError::CostingModuleNotEnabled,
2348            ))
2349        }
2350    }
2351
2352    fn finalization_cost_unit_limit(&mut self) -> Result<u32, RuntimeError> {
2353        self.api
2354            .kernel_get_system()
2355            .modules
2356            .apply_execution_cost(ExecutionCostingEntry::QueryFeeReserve)?;
2357
2358        if let Some(fee_reserve) = self.api.kernel_get_system().modules.fee_reserve() {
2359            Ok(fee_reserve.finalization_cost_unit_limit())
2360        } else {
2361            Err(RuntimeError::SystemError(
2362                SystemError::CostingModuleNotEnabled,
2363            ))
2364        }
2365    }
2366
2367    fn finalization_cost_unit_price(&mut self) -> Result<Decimal, RuntimeError> {
2368        self.api
2369            .kernel_get_system()
2370            .modules
2371            .apply_execution_cost(ExecutionCostingEntry::QueryFeeReserve)?;
2372
2373        if let Some(fee_reserve) = self.api.kernel_get_system().modules.fee_reserve() {
2374            Ok(fee_reserve.finalization_cost_unit_price())
2375        } else {
2376            Err(RuntimeError::SystemError(
2377                SystemError::CostingModuleNotEnabled,
2378            ))
2379        }
2380    }
2381
2382    fn usd_price(&mut self) -> Result<Decimal, RuntimeError> {
2383        if let Some(costing) = self.api.kernel_get_system().modules.costing_mut() {
2384            costing
2385                .apply_execution_cost_2(ExecutionCostingEntry::QueryFeeReserve)
2386                .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
2387        }
2388
2389        if let Some(fee_reserve) = self.api.kernel_get_system().modules.fee_reserve() {
2390            Ok(fee_reserve.usd_price())
2391        } else {
2392            Err(RuntimeError::SystemError(
2393                SystemError::CostingModuleNotEnabled,
2394            ))
2395        }
2396    }
2397
2398    fn max_per_function_royalty_in_xrd(&mut self) -> Result<Decimal, RuntimeError> {
2399        if let Some(costing) = self.api.kernel_get_system().modules.costing_mut() {
2400            costing
2401                .apply_execution_cost_2(ExecutionCostingEntry::QueryCostingModule)
2402                .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
2403            Ok(costing.config.max_per_function_royalty_in_xrd)
2404        } else {
2405            Err(RuntimeError::SystemError(
2406                SystemError::CostingModuleNotEnabled,
2407            ))
2408        }
2409    }
2410
2411    fn tip_percentage_truncated(&mut self) -> Result<u32, RuntimeError> {
2412        self.api
2413            .kernel_get_system()
2414            .modules
2415            .apply_execution_cost(ExecutionCostingEntry::QueryFeeReserve)?;
2416
2417        if let Some(fee_reserve) = self.api.kernel_get_system().modules.fee_reserve() {
2418            Ok(fee_reserve.tip().truncate_to_percentage_u32())
2419        } else {
2420            Err(RuntimeError::SystemError(
2421                SystemError::CostingModuleNotEnabled,
2422            ))
2423        }
2424    }
2425
2426    fn fee_balance(&mut self) -> Result<Decimal, RuntimeError> {
2427        self.api
2428            .kernel_get_system()
2429            .modules
2430            .apply_execution_cost(ExecutionCostingEntry::QueryFeeReserve)?;
2431
2432        if let Some(fee_reserve) = self.api.kernel_get_system().modules.fee_reserve() {
2433            Ok(fee_reserve.fee_balance())
2434        } else {
2435            Err(RuntimeError::SystemError(
2436                SystemError::CostingModuleNotEnabled,
2437            ))
2438        }
2439    }
2440}
2441
2442#[cfg_attr(
2443    feature = "std",
2444    catch_unwind(crate::utils::catch_unwind_system_panic_transformer)
2445)]
2446impl<'a, Y: SystemBasedKernelApi> SystemActorApi<RuntimeError> for SystemService<'a, Y> {
2447    #[trace_resources]
2448    fn actor_get_blueprint_id(&mut self) -> Result<BlueprintId, RuntimeError> {
2449        self.api
2450            .kernel_get_system()
2451            .modules
2452            .apply_execution_cost(ExecutionCostingEntry::QueryActor)?;
2453
2454        self.current_actor()
2455            .blueprint_id()
2456            .ok_or(RuntimeError::SystemError(SystemError::NoBlueprintId))
2457    }
2458
2459    #[trace_resources]
2460    fn actor_get_node_id(&mut self, ref_handle: ActorRefHandle) -> Result<NodeId, RuntimeError> {
2461        self.api
2462            .kernel_get_system()
2463            .modules
2464            .apply_execution_cost(ExecutionCostingEntry::QueryActor)?;
2465
2466        let actor_ref: ActorObjectRef = ref_handle.try_into()?;
2467
2468        let node_id = match actor_ref {
2469            ActorObjectRef::SELF => {
2470                self.current_actor()
2471                    .node_id()
2472                    .ok_or(RuntimeError::SystemError(
2473                        SystemError::ActorNodeIdDoesNotExist,
2474                    ))?
2475            }
2476            ActorObjectRef::Outer => {
2477                let (node_id, module_id) = self.get_actor_object_id(ActorStateRef::SELF)?;
2478                match module_id {
2479                    None => {
2480                        let info = self.get_object_info(&node_id)?;
2481                        match info.blueprint_info.outer_obj_info {
2482                            OuterObjectInfo::Some { outer_object } => {
2483                                Ok(outer_object.into_node_id())
2484                            }
2485                            OuterObjectInfo::None => Err(RuntimeError::SystemError(
2486                                SystemError::OuterObjectDoesNotExist,
2487                            )),
2488                        }
2489                    }
2490                    _ => Err(RuntimeError::SystemError(
2491                        SystemError::ModulesDontHaveOuterObjects,
2492                    )),
2493                }?
2494            }
2495            ActorObjectRef::Global => {
2496                let actor = self.current_actor();
2497                if actor.is_direct_access() {
2498                    return Err(RuntimeError::SystemError(
2499                        SystemError::GlobalAddressDoesNotExist,
2500                    ));
2501                }
2502
2503                if let Some(node_id) = actor.node_id() {
2504                    let visibility = self.kernel_get_node_visibility_uncosted(&node_id);
2505                    if let ReferenceOrigin::Global(address) =
2506                        visibility.reference_origin(node_id).unwrap()
2507                    {
2508                        address.into_node_id()
2509                    } else {
2510                        return Err(RuntimeError::SystemError(
2511                            SystemError::GlobalAddressDoesNotExist,
2512                        ));
2513                    }
2514                } else {
2515                    return Err(RuntimeError::SystemError(
2516                        SystemError::GlobalAddressDoesNotExist,
2517                    ));
2518                }
2519            }
2520            ActorObjectRef::AuthZone => self
2521                .current_actor()
2522                .self_auth_zone()
2523                .ok_or_else(|| RuntimeError::SystemError(SystemError::AuthModuleNotEnabled))?,
2524        };
2525
2526        Ok(node_id)
2527    }
2528
2529    #[trace_resources]
2530    fn actor_is_feature_enabled(
2531        &mut self,
2532        object_handle: ActorStateHandle,
2533        feature: &str,
2534    ) -> Result<bool, RuntimeError> {
2535        self.api
2536            .kernel_get_system()
2537            .modules
2538            .apply_execution_cost(ExecutionCostingEntry::QueryActor)?;
2539
2540        let actor_object_type: ActorStateRef = object_handle.try_into()?;
2541        let (node_id, module_id) = self.get_actor_object_id(actor_object_type)?;
2542        self.is_feature_enabled(&node_id, module_id, feature)
2543    }
2544
2545    // Costing through kernel
2546    #[trace_resources]
2547    fn actor_open_field(
2548        &mut self,
2549        object_handle: ActorStateHandle,
2550        field_index: u8,
2551        flags: LockFlags,
2552    ) -> Result<SubstateHandle, RuntimeError> {
2553        let actor_object_type: ActorStateRef = object_handle.try_into()?;
2554
2555        let (node_id, blueprint_info, partition_num, transient) =
2556            self.get_actor_field_info(actor_object_type, field_index)?;
2557
2558        // TODO: Remove
2559        if (flags.contains(LockFlags::UNMODIFIED_BASE) || flags.contains(LockFlags::FORCE_WRITE))
2560            && !(blueprint_info.blueprint_id.eq(&BlueprintId::new(
2561                &RESOURCE_PACKAGE,
2562                FUNGIBLE_VAULT_BLUEPRINT,
2563            )))
2564        {
2565            return Err(RuntimeError::SystemError(SystemError::InvalidLockFlags));
2566        }
2567
2568        let lock_data = if flags.contains(LockFlags::MUTABLE) {
2569            let target = BlueprintTypeTarget {
2570                blueprint_info,
2571                meta: SchemaValidationMeta::ExistingObject {
2572                    additional_schemas: node_id,
2573                },
2574            };
2575
2576            FieldLockData::Write {
2577                target,
2578                field_index,
2579            }
2580        } else {
2581            FieldLockData::Read
2582        };
2583
2584        let handle = match transient {
2585            FieldTransience::NotTransient => self.api.kernel_open_substate(
2586                &node_id,
2587                partition_num,
2588                &SubstateKey::Field(field_index),
2589                flags,
2590                SystemLockData::Field(lock_data),
2591            )?,
2592            FieldTransience::TransientStatic { default_value } => {
2593                let default_value: ScryptoValue = scrypto_decode(&default_value).unwrap();
2594                self.api.kernel_mark_substate_as_transient(
2595                    node_id,
2596                    partition_num,
2597                    SubstateKey::Field(field_index),
2598                )?;
2599                self.api.kernel_open_substate_with_default(
2600                    &node_id,
2601                    partition_num,
2602                    &SubstateKey::Field(field_index),
2603                    flags,
2604                    Some(|| {
2605                        IndexedScryptoValue::from_typed(&FieldSubstate::new_unlocked_field(
2606                            default_value,
2607                        ))
2608                    }),
2609                    SystemLockData::Field(lock_data),
2610                )?
2611            }
2612        };
2613
2614        if flags.contains(LockFlags::MUTABLE) {
2615            let lock_status = self.api.kernel_read_substate(handle).map(|v| {
2616                let field: FieldSubstate<ScryptoValue> = v.as_typed().unwrap();
2617                field.into_lock_status()
2618            })?;
2619
2620            if let LockStatus::Locked = lock_status {
2621                return Err(RuntimeError::SystemError(SystemError::FieldLocked(
2622                    object_handle,
2623                    field_index,
2624                )));
2625            }
2626        }
2627
2628        Ok(handle)
2629    }
2630
2631    #[trace_resources]
2632    fn actor_emit_event(
2633        &mut self,
2634        event_name: String,
2635        event_data: Vec<u8>,
2636        event_flags: EventFlags,
2637    ) -> Result<(), RuntimeError> {
2638        if event_flags.contains(EventFlags::FORCE_WRITE) {
2639            let blueprint_id = self.actor_get_blueprint_id()?;
2640
2641            if !blueprint_id.package_address.eq(&RESOURCE_PACKAGE)
2642                || !blueprint_id.blueprint_name.eq(FUNGIBLE_VAULT_BLUEPRINT)
2643            {
2644                return Err(RuntimeError::SystemError(
2645                    SystemError::ForceWriteEventFlagsNotAllowed,
2646                ));
2647            }
2648        }
2649
2650        self.emit_event_internal(
2651            EmitterActor::CurrentActor,
2652            event_name,
2653            event_data,
2654            event_flags,
2655        )
2656    }
2657}
2658
2659#[cfg_attr(
2660    feature = "std",
2661    catch_unwind(crate::utils::catch_unwind_system_panic_transformer)
2662)]
2663impl<'a, Y: SystemBasedKernelApi> SystemActorKeyValueEntryApi<RuntimeError>
2664    for SystemService<'a, Y>
2665{
2666    // Costing through kernel
2667    #[trace_resources]
2668    fn actor_open_key_value_entry(
2669        &mut self,
2670        object_handle: ActorStateHandle,
2671        collection_index: CollectionIndex,
2672        key: &Vec<u8>,
2673        flags: LockFlags,
2674    ) -> Result<KeyValueEntryHandle, RuntimeError> {
2675        if flags.contains(LockFlags::UNMODIFIED_BASE) || flags.contains(LockFlags::FORCE_WRITE) {
2676            return Err(RuntimeError::SystemError(SystemError::InvalidLockFlags));
2677        }
2678
2679        let actor_object_type: ActorStateRef = object_handle.try_into()?;
2680
2681        let (node_id, info, partition_num) = self.get_actor_collection_partition_info(
2682            actor_object_type,
2683            collection_index,
2684            &BlueprintPartitionType::KeyValueCollection,
2685        )?;
2686
2687        let target = BlueprintTypeTarget {
2688            blueprint_info: info,
2689            meta: SchemaValidationMeta::ExistingObject {
2690                additional_schemas: node_id,
2691            },
2692        };
2693
2694        self.validate_blueprint_payload(
2695            &target,
2696            BlueprintPayloadIdentifier::KeyValueEntry(collection_index, KeyOrValue::Key),
2697            key,
2698        )?;
2699
2700        let lock_data = if flags.contains(LockFlags::MUTABLE) {
2701            KeyValueEntryLockData::KVCollectionWrite {
2702                collection_index,
2703                target,
2704            }
2705        } else {
2706            KeyValueEntryLockData::Read
2707        };
2708
2709        let handle = self.api.kernel_open_substate_with_default(
2710            &node_id,
2711            partition_num,
2712            &SubstateKey::Map(key.to_vec()),
2713            flags,
2714            Some(|| {
2715                let kv_entry = KeyValueEntrySubstate::<()>::default();
2716                IndexedScryptoValue::from_typed(&kv_entry)
2717            }),
2718            SystemLockData::KeyValueEntry(lock_data),
2719        )?;
2720
2721        if flags.contains(LockFlags::MUTABLE) {
2722            let substate: KeyValueEntrySubstate<ScryptoValue> =
2723                self.api.kernel_read_substate(handle)?.as_typed().unwrap();
2724
2725            if substate.is_locked() {
2726                return Err(RuntimeError::SystemError(SystemError::KeyValueEntryLocked));
2727            }
2728        }
2729
2730        Ok(handle)
2731    }
2732
2733    // Costing through kernel
2734    fn actor_remove_key_value_entry(
2735        &mut self,
2736        object_handle: ActorStateHandle,
2737        collection_index: CollectionIndex,
2738        key: &Vec<u8>,
2739    ) -> Result<Vec<u8>, RuntimeError> {
2740        let handle = self.actor_open_key_value_entry(
2741            object_handle,
2742            collection_index,
2743            key,
2744            LockFlags::MUTABLE,
2745        )?;
2746        self.key_value_entry_remove_and_close_substate(handle)
2747    }
2748}
2749
2750#[cfg_attr(
2751    feature = "std",
2752    catch_unwind(crate::utils::catch_unwind_system_panic_transformer)
2753)]
2754impl<'a, Y: SystemBasedKernelApi> SystemExecutionTraceApi<RuntimeError> for SystemService<'a, Y> {
2755    // No costing should be applied
2756    #[trace_resources]
2757    fn update_instruction_index(&mut self, new_index: usize) -> Result<(), RuntimeError> {
2758        self.api
2759            .kernel_get_system()
2760            .modules
2761            .update_instruction_index(new_index);
2762        Ok(())
2763    }
2764}
2765
2766#[cfg_attr(
2767    feature = "std",
2768    catch_unwind(crate::utils::catch_unwind_system_panic_transformer)
2769)]
2770impl<'a, Y: SystemBasedKernelApi> SystemTransactionRuntimeApi<RuntimeError>
2771    for SystemService<'a, Y>
2772{
2773    #[trace_resources]
2774    fn get_transaction_hash(&mut self) -> Result<Hash, RuntimeError> {
2775        self.api
2776            .kernel_get_system()
2777            .modules
2778            .apply_execution_cost(ExecutionCostingEntry::QueryTransactionHash)?;
2779
2780        if let Some(hash) = self.api.kernel_get_system().modules.transaction_hash() {
2781            Ok(hash)
2782        } else {
2783            Err(RuntimeError::SystemError(
2784                SystemError::TransactionRuntimeModuleNotEnabled,
2785            ))
2786        }
2787    }
2788
2789    #[trace_resources]
2790    fn generate_ruid(&mut self) -> Result<[u8; 32], RuntimeError> {
2791        self.api
2792            .kernel_get_system()
2793            .modules
2794            .apply_execution_cost(ExecutionCostingEntry::GenerateRuid)?;
2795
2796        if let Some(ruid) = self.api.kernel_get_system().modules.generate_ruid() {
2797            Ok(ruid)
2798        } else {
2799            Err(RuntimeError::SystemError(
2800                SystemError::TransactionRuntimeModuleNotEnabled,
2801            ))
2802        }
2803    }
2804
2805    #[trace_resources]
2806    fn bech32_encode_address(&mut self, address: GlobalAddress) -> Result<String, RuntimeError> {
2807        if let Some(costing) = self.api.kernel_get_system().modules.costing_mut() {
2808            costing
2809                .apply_execution_cost_2(ExecutionCostingEntry::EncodeBech32Address)
2810                .map_err(|e| RuntimeError::SystemModuleError(SystemModuleError::CostingError(e)))?;
2811        }
2812
2813        let network_definition = &self
2814            .api
2815            .kernel_get_system()
2816            .modules
2817            .transaction_runtime
2818            .network_definition;
2819
2820        AddressBech32Encoder::new(network_definition)
2821            .encode(&address.into_node_id().0)
2822            .map_err(|_| RuntimeError::SystemError(SystemError::AddressBech32EncodeError))
2823    }
2824
2825    #[trace_resources]
2826    fn emit_log(&mut self, level: Level, message: String) -> Result<(), RuntimeError> {
2827        self.api.kernel_get_system().modules.apply_execution_cost(
2828            ExecutionCostingEntry::EmitLog {
2829                size: message.len(),
2830            },
2831        )?;
2832
2833        self.api
2834            .kernel_get_system()
2835            .modules
2836            .add_log(level, message)?;
2837
2838        Ok(())
2839    }
2840
2841    fn panic(&mut self, message: String) -> Result<(), RuntimeError> {
2842        self.api.kernel_get_system().modules.apply_execution_cost(
2843            ExecutionCostingEntry::Panic {
2844                size: message.len(),
2845            },
2846        )?;
2847
2848        self.api
2849            .kernel_get_system()
2850            .modules
2851            .set_panic_message(message.clone())?;
2852
2853        Err(RuntimeError::ApplicationError(
2854            ApplicationError::PanicMessage(message),
2855        ))
2856    }
2857}
2858
2859#[cfg_attr(
2860    feature = "std",
2861    catch_unwind(crate::utils::catch_unwind_system_panic_transformer)
2862)]
2863impl<'a, Y: SystemBasedKernelApi> SystemApi<RuntimeError> for SystemService<'a, Y> {}
2864
2865#[cfg_attr(
2866    feature = "std",
2867    catch_unwind(crate::utils::catch_unwind_system_panic_transformer)
2868)]
2869impl<'a, Y: SystemBasedKernelApi> KernelNodeApi for SystemService<'a, Y> {
2870    fn kernel_pin_node(&mut self, node_id: NodeId) -> Result<(), RuntimeError> {
2871        self.api.kernel_pin_node(node_id)
2872    }
2873
2874    fn kernel_drop_node(&mut self, node_id: &NodeId) -> Result<DroppedNode, RuntimeError> {
2875        self.api.kernel_drop_node(node_id)
2876    }
2877
2878    fn kernel_allocate_node_id(&mut self, entity_type: EntityType) -> Result<NodeId, RuntimeError> {
2879        self.api.kernel_allocate_node_id(entity_type)
2880    }
2881
2882    fn kernel_create_node(
2883        &mut self,
2884        node_id: NodeId,
2885        node_substates: NodeSubstates,
2886    ) -> Result<(), RuntimeError> {
2887        self.api.kernel_create_node(node_id, node_substates)
2888    }
2889
2890    fn kernel_create_node_from(
2891        &mut self,
2892        node_id: NodeId,
2893        partitions: BTreeMap<PartitionNumber, (NodeId, PartitionNumber)>,
2894    ) -> Result<(), RuntimeError> {
2895        self.api.kernel_create_node_from(node_id, partitions)
2896    }
2897}
2898
2899#[cfg_attr(
2900    feature = "std",
2901    catch_unwind(crate::utils::catch_unwind_system_panic_transformer)
2902)]
2903impl<'a, Y: SystemBasedKernelApi> KernelSubstateApi<SystemLockData> for SystemService<'a, Y> {
2904    fn kernel_mark_substate_as_transient(
2905        &mut self,
2906        node_id: NodeId,
2907        partition_num: PartitionNumber,
2908        key: SubstateKey,
2909    ) -> Result<(), RuntimeError> {
2910        self.api
2911            .kernel_mark_substate_as_transient(node_id, partition_num, key)
2912    }
2913
2914    fn kernel_open_substate_with_default<F: FnOnce() -> IndexedScryptoValue>(
2915        &mut self,
2916        node_id: &NodeId,
2917        partition_num: PartitionNumber,
2918        substate_key: &SubstateKey,
2919        flags: LockFlags,
2920        default: Option<F>,
2921        data: SystemLockData,
2922    ) -> Result<SubstateHandle, RuntimeError> {
2923        self.api.kernel_open_substate_with_default(
2924            node_id,
2925            partition_num,
2926            substate_key,
2927            flags,
2928            default,
2929            data,
2930        )
2931    }
2932
2933    fn kernel_get_lock_data(
2934        &mut self,
2935        lock_handle: SubstateHandle,
2936    ) -> Result<SystemLockData, RuntimeError> {
2937        self.api.kernel_get_lock_data(lock_handle)
2938    }
2939
2940    fn kernel_close_substate(&mut self, lock_handle: SubstateHandle) -> Result<(), RuntimeError> {
2941        self.api.kernel_close_substate(lock_handle)
2942    }
2943
2944    fn kernel_read_substate(
2945        &mut self,
2946        lock_handle: SubstateHandle,
2947    ) -> Result<&IndexedScryptoValue, RuntimeError> {
2948        self.api.kernel_read_substate(lock_handle)
2949    }
2950
2951    fn kernel_write_substate(
2952        &mut self,
2953        lock_handle: SubstateHandle,
2954        value: IndexedScryptoValue,
2955    ) -> Result<(), RuntimeError> {
2956        self.api.kernel_write_substate(lock_handle, value)
2957    }
2958
2959    fn kernel_set_substate(
2960        &mut self,
2961        node_id: &NodeId,
2962        partition_num: PartitionNumber,
2963        substate_key: SubstateKey,
2964        value: IndexedScryptoValue,
2965    ) -> Result<(), RuntimeError> {
2966        self.api
2967            .kernel_set_substate(node_id, partition_num, substate_key, value)
2968    }
2969
2970    fn kernel_remove_substate(
2971        &mut self,
2972        node_id: &NodeId,
2973        partition_num: PartitionNumber,
2974        substate_key: &SubstateKey,
2975    ) -> Result<Option<IndexedScryptoValue>, RuntimeError> {
2976        self.api
2977            .kernel_remove_substate(node_id, partition_num, substate_key)
2978    }
2979
2980    fn kernel_scan_sorted_substates(
2981        &mut self,
2982        node_id: &NodeId,
2983        partition_num: PartitionNumber,
2984        limit: u32,
2985    ) -> Result<Vec<(SortedKey, IndexedScryptoValue)>, RuntimeError> {
2986        self.api
2987            .kernel_scan_sorted_substates(node_id, partition_num, limit)
2988    }
2989
2990    fn kernel_scan_keys<K: SubstateKeyContent>(
2991        &mut self,
2992        node_id: &NodeId,
2993        partition_num: PartitionNumber,
2994        limit: u32,
2995    ) -> Result<Vec<SubstateKey>, RuntimeError> {
2996        self.api
2997            .kernel_scan_keys::<K>(node_id, partition_num, limit)
2998    }
2999
3000    fn kernel_drain_substates<K: SubstateKeyContent>(
3001        &mut self,
3002        node_id: &NodeId,
3003        partition_num: PartitionNumber,
3004        limit: u32,
3005    ) -> Result<Vec<(SubstateKey, IndexedScryptoValue)>, RuntimeError> {
3006        self.api
3007            .kernel_drain_substates::<K>(node_id, partition_num, limit)
3008    }
3009}
3010
3011impl<'a, Y: SystemBasedKernelApi> KernelInternalApi for SystemService<'a, Y> {
3012    type System = Y::CallbackObject;
3013
3014    fn kernel_get_system_state(&mut self) -> SystemState<'_, Y::CallbackObject> {
3015        self.api.kernel_get_system_state()
3016    }
3017
3018    fn kernel_get_current_stack_depth_uncosted(&self) -> usize {
3019        self.api.kernel_get_current_stack_depth_uncosted()
3020    }
3021
3022    fn kernel_get_current_stack_id_uncosted(&self) -> usize {
3023        self.api.kernel_get_current_stack_id_uncosted()
3024    }
3025
3026    fn kernel_get_node_visibility_uncosted(&self, node_id: &NodeId) -> NodeVisibility {
3027        self.api.kernel_get_node_visibility_uncosted(node_id)
3028    }
3029
3030    fn kernel_read_substate_uncosted(
3031        &self,
3032        node_id: &NodeId,
3033        partition_num: PartitionNumber,
3034        substate_key: &SubstateKey,
3035    ) -> Option<&IndexedScryptoValue> {
3036        self.api
3037            .kernel_read_substate_uncosted(node_id, partition_num, substate_key)
3038    }
3039}