radix_engine/system/
system_db_reader.rs

1use crate::internal_prelude::*;
2use radix_engine_interface::api::{AttachedModuleId, CollectionIndex, ModuleId};
3use radix_engine_interface::blueprints::package::*;
4use radix_engine_interface::types::*;
5use radix_substate_store_interface::interface::*;
6use sbor::{validate_payload_against_schema, LocalTypeId, LocatedValidationError};
7
8use crate::blueprints::package::PackageBlueprintVersionDefinitionEntrySubstate;
9use crate::system::payload_validation::{SchemaOrigin, TypeInfoForValidation, ValidationContext};
10use crate::system::system_substates::FieldSubstate;
11use crate::system::system_substates::KeyValueEntrySubstate;
12use crate::system::system_substates::LockStatus;
13use crate::system::system_type_checker::{
14    BlueprintTypeTarget, KVStoreTypeTarget, SchemaValidationMeta,
15};
16use crate::system::type_info::TypeInfoSubstate;
17use crate::transaction::{
18    ObjectInstanceTypeReference, ObjectSubstateTypeReference, PackageTypeReference,
19};
20use radix_blueprint_schema_init::BlueprintCollectionSchema;
21
22#[derive(Clone, Debug)]
23pub enum SystemPartitionDescription {
24    TypeInfo,
25    Schema,
26    Module(ModuleId, PartitionOffset),
27}
28
29#[derive(Clone, Debug)]
30pub enum ObjectPartitionDescriptor {
31    Fields,
32    KeyValueCollection(u8),
33    IndexCollection(u8),
34    SortedIndexCollection(u8),
35}
36
37#[derive(Clone, Debug)]
38pub enum SystemPartitionDescriptor {
39    BootLoader,
40    ProtocolUpdateStatus,
41    TypeInfo,
42    Schema,
43    KeyValueStore,
44    Object(ModuleId, ObjectPartitionDescriptor),
45}
46
47pub struct ResolvedPayloadSchema {
48    pub schema: Rc<VersionedScryptoSchema>,
49    pub type_id: LocalTypeId,
50    pub allow_ownership: bool,
51    pub allow_non_global_refs: bool,
52    pub schema_origin: SchemaOrigin,
53}
54
55#[derive(Debug, Clone, PartialEq, Eq)]
56pub enum ObjectCollectionKey<'a, K: ScryptoEncode> {
57    KeyValue(u8, &'a K),
58    Index(u8, &'a K),
59    SortedIndex(u8, u16, &'a K),
60}
61
62impl<'a, K: ScryptoEncode> ObjectCollectionKey<'a, K> {
63    fn collection_index(&self) -> u8 {
64        match self {
65            ObjectCollectionKey::KeyValue(index, ..)
66            | ObjectCollectionKey::Index(index, ..)
67            | ObjectCollectionKey::SortedIndex(index, ..) => *index,
68        }
69    }
70}
71
72#[derive(Debug, Clone, PartialEq, Eq)]
73pub enum SystemReaderError {
74    FieldDoesNotExist,
75    CollectionDoesNotExist,
76    NodeIdDoesNotExist,
77    PayloadDoesNotExist,
78    BlueprintDoesNotExist,
79    ModuleDoesNotExist,
80    NotAKeyValueStore,
81    NotAnObject,
82    SchemaDoesNotExist,
83    TargetNotSupported,
84    BlueprintTypeNotFound(String),
85}
86
87/// A System Layer (Layer 2) abstraction over an underlying substate database
88pub struct SystemDatabaseReader<'a, S: SubstateDatabase + ?Sized> {
89    substate_db: &'a S,
90    state_updates: Option<&'a StateUpdates>,
91
92    blueprint_cache: RefCell<NonIterMap<CanonicalBlueprintId, Rc<BlueprintDefinition>>>,
93    schema_cache: RefCell<NonIterMap<SchemaHash, Rc<VersionedScryptoSchema>>>,
94}
95
96impl<'a, S: SubstateDatabase + ?Sized> SystemDatabaseReader<'a, S> {
97    pub fn new_with_overlay(substate_db: &'a S, state_updates: &'a StateUpdates) -> Self {
98        Self {
99            substate_db,
100            state_updates: Some(state_updates),
101            blueprint_cache: RefCell::new(NonIterMap::new()),
102            schema_cache: RefCell::new(NonIterMap::new()),
103        }
104    }
105
106    pub fn new(substate_db: &'a S) -> Self {
107        Self {
108            substate_db,
109            state_updates: None,
110            blueprint_cache: RefCell::new(NonIterMap::new()),
111            schema_cache: RefCell::new(NonIterMap::new()),
112        }
113    }
114
115    pub fn get_type_info(&self, node_id: &NodeId) -> Result<TypeInfoSubstate, SystemReaderError> {
116        self.fetch_substate::<TypeInfoSubstate>(
117            node_id,
118            TYPE_INFO_FIELD_PARTITION,
119            &TypeInfoField::TypeInfo.into(),
120        )
121        .ok_or_else(|| SystemReaderError::NodeIdDoesNotExist)
122    }
123
124    pub fn get_package_definition(
125        &self,
126        package_address: PackageAddress,
127    ) -> BTreeMap<BlueprintVersionKey, BlueprintDefinition> {
128        let entries = self
129            .substate_db
130            .list_map_values::<PackageBlueprintVersionDefinitionEntrySubstate>(
131                package_address.as_node_id(),
132                MAIN_BASE_PARTITION
133                    .at_offset(PACKAGE_BLUEPRINTS_PARTITION_OFFSET)
134                    .unwrap(),
135                None::<SubstateKey>,
136            );
137
138        let mut blueprints = BTreeMap::new();
139        for (key, blueprint_definition) in entries {
140            let bp_version_key: BlueprintVersionKey = scrypto_decode(&key).unwrap();
141
142            blueprints.insert(
143                bp_version_key,
144                blueprint_definition
145                    .into_value()
146                    .unwrap()
147                    .fully_update_and_into_latest_version(),
148            );
149        }
150
151        blueprints
152    }
153
154    pub fn read_object_field(
155        &self,
156        node_id: &NodeId,
157        module_id: ModuleId,
158        field_index: u8,
159    ) -> Result<IndexedScryptoValue, SystemReaderError> {
160        self.read_object_field_advanced(node_id, module_id, field_index)
161            .map(|x| x.0)
162    }
163
164    pub fn read_object_field_advanced(
165        &self,
166        node_id: &NodeId,
167        module_id: ModuleId,
168        field_index: u8,
169    ) -> Result<(IndexedScryptoValue, PartitionNumber), SystemReaderError> {
170        let blueprint_id = self.get_blueprint_id(node_id, module_id)?;
171        let definition = self.get_blueprint_definition(&blueprint_id)?;
172        let partition_description = &definition
173            .interface
174            .state
175            .fields
176            .as_ref()
177            .ok_or_else(|| SystemReaderError::FieldDoesNotExist)?
178            .0;
179        let partition_number = match partition_description {
180            PartitionDescription::Logical(offset) => {
181                let base_partition = match module_id {
182                    ModuleId::Main => MAIN_BASE_PARTITION,
183                    ModuleId::Metadata => METADATA_BASE_PARTITION,
184                    ModuleId::Royalty => ROYALTY_BASE_PARTITION,
185                    ModuleId::RoleAssignment => ROLE_ASSIGNMENT_BASE_PARTITION,
186                };
187                base_partition.at_offset(*offset).unwrap()
188            }
189            PartitionDescription::Physical(partition_number) => *partition_number,
190        };
191
192        let substate: FieldSubstate<ScryptoValue> = self
193            .substate_db
194            .get_substate(node_id, partition_number, SubstateKey::Field(field_index))
195            .ok_or_else(|| SystemReaderError::FieldDoesNotExist)?;
196
197        Ok((
198            IndexedScryptoValue::from_scrypto_value(substate.into_payload()),
199            partition_number,
200        ))
201    }
202
203    pub fn read_typed_kv_entry<K: ScryptoEncode, V: ScryptoDecode>(
204        &self,
205        node_id: &NodeId,
206        key: &K,
207    ) -> Option<V> {
208        self.substate_db
209            .get_substate::<KeyValueEntrySubstate<V>>(
210                node_id,
211                MAIN_BASE_PARTITION,
212                SubstateKey::Map(scrypto_encode(key).unwrap()),
213            )
214            .and_then(|v| v.into_value())
215    }
216
217    pub fn read_typed_object_field<V: ScryptoDecode>(
218        &self,
219        node_id: &NodeId,
220        module_id: ModuleId,
221        field_index: u8,
222    ) -> Result<V, SystemReaderError> {
223        let blueprint_id = self.get_blueprint_id(node_id, module_id)?;
224        let definition = self.get_blueprint_definition(&blueprint_id)?;
225        let partition_description = &definition
226            .interface
227            .state
228            .fields
229            .as_ref()
230            .ok_or_else(|| SystemReaderError::FieldDoesNotExist)?
231            .0;
232        let partition_number = match partition_description {
233            PartitionDescription::Logical(offset) => {
234                let base_partition = match module_id {
235                    ModuleId::Main => MAIN_BASE_PARTITION,
236                    ModuleId::Metadata => METADATA_BASE_PARTITION,
237                    ModuleId::Royalty => ROYALTY_BASE_PARTITION,
238                    ModuleId::RoleAssignment => ROLE_ASSIGNMENT_BASE_PARTITION,
239                };
240                base_partition.at_offset(*offset).unwrap()
241            }
242            PartitionDescription::Physical(partition_number) => *partition_number,
243        };
244
245        let substate: FieldSubstate<V> = self
246            .substate_db
247            .get_substate(node_id, partition_number, SubstateKey::Field(field_index))
248            .ok_or_else(|| SystemReaderError::FieldDoesNotExist)?;
249
250        Ok(substate.into_payload())
251    }
252
253    pub fn get_partition_of_collection(
254        &self,
255        node_id: &NodeId,
256        module_id: ModuleId,
257        collection_index: CollectionIndex,
258    ) -> Result<PartitionNumber, SystemReaderError> {
259        let blueprint_id = self.get_blueprint_id(node_id, module_id)?;
260        let definition = self.get_blueprint_definition(&blueprint_id)?;
261
262        let (partition_description, ..) = definition
263            .interface
264            .state
265            .collections
266            .get(collection_index as usize)
267            .ok_or_else(|| SystemReaderError::CollectionDoesNotExist)?;
268
269        let partition_number = match partition_description {
270            PartitionDescription::Logical(offset) => {
271                module_id.base_partition_num().at_offset(*offset).unwrap()
272            }
273            PartitionDescription::Physical(partition_number) => *partition_number,
274        };
275
276        Ok(partition_number)
277    }
278
279    pub fn read_object_collection_entry<K: ScryptoEncode, V: ScryptoDecode>(
280        &self,
281        node_id: &NodeId,
282        module_id: ModuleId,
283        collection_key: ObjectCollectionKey<K>,
284    ) -> Result<Option<V>, SystemReaderError> {
285        let partition_number = self.get_partition_of_collection(
286            node_id,
287            module_id,
288            collection_key.collection_index(),
289        )?;
290
291        let entry = match collection_key {
292            ObjectCollectionKey::KeyValue(_, key) => self
293                .substate_db
294                .get_substate::<KeyValueEntrySubstate<V>>(
295                    node_id,
296                    partition_number,
297                    SubstateKey::Map(scrypto_encode(key).unwrap()),
298                )
299                .and_then(|value| value.into_value()),
300            ObjectCollectionKey::Index(_, key) => self
301                .substate_db
302                .get_substate::<IndexEntrySubstate<V>>(
303                    node_id,
304                    partition_number,
305                    SubstateKey::Map(scrypto_encode(key).unwrap()),
306                )
307                .map(|value| value.into_value()),
308            ObjectCollectionKey::SortedIndex(_, sort, key) => self
309                .substate_db
310                .get_substate::<SortedIndexEntrySubstate<V>>(
311                    node_id,
312                    partition_number,
313                    SubstateKey::Sorted((sort.to_be_bytes(), scrypto_encode(key).unwrap())),
314                )
315                .map(|value| value.into_value()),
316        };
317
318        Ok(entry)
319    }
320
321    pub fn key_value_store_iter(
322        &self,
323        node_id: &NodeId,
324        from_key: Option<&MapKey>,
325    ) -> Result<Box<dyn Iterator<Item = (MapKey, Vec<u8>)> + '_>, SystemReaderError> {
326        if self.state_updates.is_some() {
327            panic!("key_value_store_iter with overlay not supported.");
328        }
329
330        match self.get_type_info(node_id)? {
331            TypeInfoSubstate::KeyValueStore(..) => {}
332            _ => return Err(SystemReaderError::NotAKeyValueStore),
333        }
334
335        let iterable = self
336            .substate_db
337            .list_map_values::<KeyValueEntrySubstate<ScryptoRawValue>>(
338                node_id,
339                MAIN_BASE_PARTITION,
340                from_key,
341            )
342            .filter_map(move |(map_key, substate)| {
343                let value = substate.into_value()?;
344                let value = scrypto_encode(&value).unwrap();
345
346                Some((map_key, value))
347            });
348
349        Ok(Box::new(iterable))
350    }
351
352    pub fn collection_iter(
353        &self,
354        node_id: &NodeId,
355        module_id: ModuleId,
356        collection_index: CollectionIndex,
357    ) -> Result<Box<dyn Iterator<Item = (SubstateKey, Vec<u8>)> + '_>, SystemReaderError> {
358        self.collection_iter_advanced(node_id, module_id, collection_index, None)
359            .map(|x| x.0)
360    }
361
362    pub fn collection_iter_advanced<'s, 'x>(
363        &'s self,
364        node_id: &'x NodeId,
365        module_id: ModuleId,
366        collection_index: CollectionIndex,
367        from_substate_key: Option<&'x SubstateKey>,
368    ) -> Result<
369        (
370            Box<dyn Iterator<Item = (SubstateKey, Vec<u8>)> + 's>,
371            PartitionNumber,
372        ),
373        SystemReaderError,
374    > {
375        if self.state_updates.is_some() {
376            panic!("collection_iter_advanced with overlay not supported.");
377        }
378
379        let blueprint_id = self.get_blueprint_id(node_id, module_id)?;
380        let definition = self.get_blueprint_definition(&blueprint_id)?;
381
382        let (partition_description, schema) = definition
383            .interface
384            .state
385            .collections
386            .get(collection_index as usize)
387            .ok_or_else(|| SystemReaderError::CollectionDoesNotExist)?
388            .clone();
389
390        let partition_number = match partition_description {
391            PartitionDescription::Physical(partition_num) => partition_num,
392            PartitionDescription::Logical(offset) => {
393                module_id.base_partition_num().at_offset(offset).unwrap()
394            }
395        };
396
397        let iterable: Box<dyn Iterator<Item = (SubstateKey, Vec<u8>)> + 's> = match schema {
398            BlueprintCollectionSchema::KeyValueStore(..) => {
399                let iterable = self
400                    .substate_db
401                    .list_map_values::<KeyValueEntrySubstate<ScryptoRawValue>>(
402                        node_id,
403                        partition_number,
404                        from_substate_key,
405                    )
406                    .filter_map(|(map_key, substate)| {
407                        Some((
408                            SubstateKey::Map(map_key),
409                            scrypto_encode(&substate.into_value()?).unwrap(),
410                        ))
411                    });
412                Box::new(iterable)
413            }
414            BlueprintCollectionSchema::Index(..) => {
415                let iterable = self
416                    .substate_db
417                    .list_map_values::<IndexEntrySubstate<ScryptoRawValue>>(
418                        node_id,
419                        partition_number,
420                        from_substate_key,
421                    )
422                    .map(|(map_key, substate)| {
423                        (
424                            SubstateKey::Map(map_key),
425                            scrypto_encode(&substate.into_value()).unwrap(),
426                        )
427                    });
428                Box::new(iterable)
429            }
430            BlueprintCollectionSchema::SortedIndex(..) => {
431                let iterable = self
432                    .substate_db
433                    .list_sorted_values::<SortedIndexEntrySubstate<ScryptoRawValue>>(
434                        node_id,
435                        partition_number,
436                        from_substate_key,
437                    )
438                    .map(|(key, substate)| {
439                        (
440                            SubstateKey::Sorted(key),
441                            scrypto_encode(&substate.into_value()).unwrap(),
442                        )
443                    });
444                Box::new(iterable)
445            }
446        };
447
448        Ok((iterable, partition_number))
449    }
450
451    pub fn get_object_info<A: Into<NodeId>>(
452        &self,
453        node_id: A,
454    ) -> Result<ObjectInfo, SystemReaderError> {
455        let type_info = self
456            .fetch_substate::<TypeInfoSubstate>(
457                &node_id.into(),
458                TYPE_INFO_FIELD_PARTITION,
459                &TypeInfoField::TypeInfo.into(),
460            )
461            .ok_or_else(|| SystemReaderError::NodeIdDoesNotExist)?;
462
463        match type_info {
464            TypeInfoSubstate::Object(object_info) => Ok(object_info),
465            _ => Err(SystemReaderError::NotAnObject),
466        }
467    }
468
469    pub fn get_blueprint_id(
470        &self,
471        node_id: &NodeId,
472        module_id: ModuleId,
473    ) -> Result<BlueprintId, SystemReaderError> {
474        let type_info = self
475            .fetch_substate::<TypeInfoSubstate>(
476                node_id,
477                TYPE_INFO_FIELD_PARTITION,
478                &TypeInfoField::TypeInfo.into(),
479            )
480            .ok_or_else(|| SystemReaderError::NodeIdDoesNotExist)?;
481
482        let object_info = match type_info {
483            TypeInfoSubstate::Object(object_info) => object_info,
484            _ => {
485                return Err(SystemReaderError::NotAnObject);
486            }
487        };
488
489        let module_id: Option<AttachedModuleId> = module_id.into();
490        if let Some(module_id) = module_id {
491            match object_info.object_type {
492                ObjectType::Global { modules } => {
493                    if !modules.contains_key(&module_id) {
494                        return Err(SystemReaderError::ModuleDoesNotExist);
495                    }
496                }
497                ObjectType::Owned => return Err(SystemReaderError::ModuleDoesNotExist),
498            }
499
500            Ok(module_id.static_blueprint())
501        } else {
502            Ok(object_info.blueprint_info.blueprint_id)
503        }
504    }
505
506    pub fn get_blueprint_definition(
507        &self,
508        blueprint_id: &BlueprintId,
509    ) -> Result<Rc<BlueprintDefinition>, SystemReaderError> {
510        let canonical_key = CanonicalBlueprintId {
511            address: blueprint_id.package_address,
512            blueprint: blueprint_id.blueprint_name.clone(),
513            version: BlueprintVersion::default(),
514        };
515        {
516            if let Some(cache) = self.blueprint_cache.borrow().get(&canonical_key) {
517                return Ok(cache.clone());
518            }
519        }
520
521        let bp_version_key = BlueprintVersionKey::new_default(blueprint_id.blueprint_name.clone());
522        let definition = Rc::new(
523            self.fetch_substate::<PackageBlueprintVersionDefinitionEntrySubstate>(
524                blueprint_id.package_address.as_node_id(),
525                MAIN_BASE_PARTITION
526                    .at_offset(PACKAGE_BLUEPRINTS_PARTITION_OFFSET)
527                    .unwrap(),
528                &SubstateKey::Map(scrypto_encode(&bp_version_key).unwrap()),
529            )
530            .ok_or_else(|| SystemReaderError::BlueprintDoesNotExist)?
531            .into_value()
532            .unwrap()
533            .fully_update_and_into_latest_version(),
534        );
535
536        self.blueprint_cache
537            .borrow_mut()
538            .insert(canonical_key, definition.clone());
539
540        Ok(definition)
541    }
542
543    pub fn get_kv_store_type_target(
544        &self,
545        node_id: &NodeId,
546    ) -> Result<KVStoreTypeTarget, SystemReaderError> {
547        let type_info = self
548            .fetch_substate::<TypeInfoSubstate>(
549                node_id,
550                TYPE_INFO_FIELD_PARTITION,
551                &TypeInfoField::TypeInfo.into(),
552            )
553            .ok_or_else(|| SystemReaderError::NodeIdDoesNotExist)?;
554
555        let kv_store_info = match type_info {
556            TypeInfoSubstate::KeyValueStore(kv_store_info) => kv_store_info,
557            _ => return Err(SystemReaderError::NotAKeyValueStore),
558        };
559
560        Ok(KVStoreTypeTarget {
561            kv_store_type: kv_store_info.generic_substitutions,
562            meta: *node_id,
563        })
564    }
565
566    pub fn get_blueprint_type_target(
567        &self,
568        node_id: &NodeId,
569        module_id: ModuleId,
570    ) -> Result<BlueprintTypeTarget, SystemReaderError> {
571        let type_info = self
572            .fetch_substate::<TypeInfoSubstate>(
573                node_id,
574                TYPE_INFO_FIELD_PARTITION,
575                &TypeInfoField::TypeInfo.into(),
576            )
577            .ok_or_else(|| SystemReaderError::NodeIdDoesNotExist)?;
578
579        let object_info = match type_info {
580            TypeInfoSubstate::Object(object_info) => object_info,
581            _ => return Err(SystemReaderError::NotAnObject),
582        };
583
584        let module_id: Option<AttachedModuleId> = module_id.into();
585        let target = if let Some(module_id) = module_id {
586            let blueprint_id = module_id.static_blueprint();
587            match object_info.object_type {
588                ObjectType::Global { modules } => {
589                    if !modules.contains_key(&module_id) {
590                        return Err(SystemReaderError::ModuleDoesNotExist);
591                    }
592                }
593                ObjectType::Owned => return Err(SystemReaderError::ModuleDoesNotExist),
594            }
595
596            let target = BlueprintTypeTarget {
597                blueprint_info: BlueprintInfo {
598                    blueprint_id,
599                    blueprint_version: Default::default(),
600                    outer_obj_info: OuterObjectInfo::None,
601                    features: Default::default(),
602                    generic_substitutions: Default::default(),
603                },
604                meta: SchemaValidationMeta::ExistingObject {
605                    additional_schemas: *node_id,
606                },
607            };
608            target
609        } else {
610            BlueprintTypeTarget {
611                blueprint_info: object_info.blueprint_info,
612                meta: SchemaValidationMeta::ExistingObject {
613                    additional_schemas: *node_id,
614                },
615            }
616        };
617
618        Ok(target)
619    }
620
621    pub fn get_kv_store_payload_schema(
622        &self,
623        target: &KVStoreTypeTarget,
624        key_or_value: KeyOrValue,
625    ) -> Result<ResolvedPayloadSchema, SystemReaderError> {
626        let (substitution, allow_ownership, allow_non_global_refs) = match key_or_value {
627            KeyOrValue::Key => (&target.kv_store_type.key_generic_substitution, false, false),
628            KeyOrValue::Value => (
629                &target.kv_store_type.value_generic_substitution,
630                target.kv_store_type.allow_ownership,
631                false,
632            ),
633        };
634
635        match substitution {
636            GenericSubstitution::Local(local_type_id) => {
637                let schema = self.get_schema(&target.meta, &local_type_id.0)?;
638
639                Ok(ResolvedPayloadSchema {
640                    schema,
641                    type_id: local_type_id.1,
642                    allow_ownership,
643                    allow_non_global_refs,
644                    schema_origin: SchemaOrigin::KeyValueStore,
645                })
646            }
647            GenericSubstitution::Remote(blueprint_type_id) => {
648                let (schema, scoped_type_id) =
649                    self.get_blueprint_type_schema(&blueprint_type_id)?;
650
651                Ok(ResolvedPayloadSchema {
652                    schema,
653                    type_id: scoped_type_id.1,
654                    allow_ownership,
655                    allow_non_global_refs,
656                    schema_origin: SchemaOrigin::KeyValueStore,
657                })
658            }
659        }
660    }
661
662    pub fn get_blueprint_payload_schema_pointer(
663        &self,
664        target: &BlueprintTypeTarget,
665        payload_identifier: &BlueprintPayloadIdentifier,
666    ) -> Result<ObjectSubstateTypeReference, SystemReaderError> {
667        let blueprint_interface = &self
668            .get_blueprint_definition(&target.blueprint_info.blueprint_id)?
669            .interface;
670
671        let (payload_def, ..) = blueprint_interface
672            .get_payload_def(payload_identifier)
673            .ok_or_else(|| SystemReaderError::PayloadDoesNotExist)?;
674
675        let obj_type_reference = match payload_def {
676            BlueprintPayloadDef::Static(type_identifier) => {
677                ObjectSubstateTypeReference::Package(PackageTypeReference {
678                    full_type_id: type_identifier
679                        .under_node(target.blueprint_info.blueprint_id.package_address),
680                })
681            }
682            BlueprintPayloadDef::Generic(instance_index) => {
683                let generic_substitution = target
684                    .blueprint_info
685                    .generic_substitutions
686                    .get(instance_index as usize)
687                    .expect("Missing generic");
688
689                let entity_address = match target.meta {
690                    SchemaValidationMeta::Blueprint | SchemaValidationMeta::NewObject { .. } => {
691                        return Err(SystemReaderError::TargetNotSupported)
692                    }
693                    SchemaValidationMeta::ExistingObject { additional_schemas } => {
694                        additional_schemas
695                    }
696                };
697
698                match generic_substitution {
699                    GenericSubstitution::Local(type_id) => {
700                        ObjectSubstateTypeReference::ObjectInstance(ObjectInstanceTypeReference {
701                            instance_type_id: instance_index,
702                            resolved_full_type_id: type_id.under_node(entity_address),
703                        })
704                    }
705                    GenericSubstitution::Remote(type_id) => {
706                        let (_, scoped_type_id) = self.get_blueprint_type_schema(&type_id)?;
707                        ObjectSubstateTypeReference::Package(PackageTypeReference {
708                            full_type_id: scoped_type_id.under_node(type_id.package_address),
709                        })
710                    }
711                }
712            }
713        };
714
715        Ok(obj_type_reference)
716    }
717
718    // TODO: The logic here is currently copied from system_type_checker.rs get_payload_schema().
719    // It would be nice to use the same underlying code but currently too many refactors are required
720    // to make that happen.
721    pub fn get_blueprint_payload_schema(
722        &self,
723        target: &BlueprintTypeTarget,
724        payload_identifier: &BlueprintPayloadIdentifier,
725    ) -> Result<ResolvedPayloadSchema, SystemReaderError> {
726        let blueprint_interface = &self
727            .get_blueprint_definition(&target.blueprint_info.blueprint_id)?
728            .interface;
729
730        let (payload_def, allow_ownership, allow_non_global_refs) = blueprint_interface
731            .get_payload_def(payload_identifier)
732            .ok_or_else(|| SystemReaderError::PayloadDoesNotExist)?;
733
734        // Given the payload definition, retrieve the info to be able to do schema validation on a payload
735        let (schema, index, schema_origin) = match payload_def {
736            BlueprintPayloadDef::Static(type_identifier) => {
737                let schema = self.get_schema(
738                    target
739                        .blueprint_info
740                        .blueprint_id
741                        .package_address
742                        .as_node_id(),
743                    &type_identifier.0,
744                )?;
745                (
746                    schema,
747                    type_identifier.1,
748                    SchemaOrigin::Blueprint(target.blueprint_info.blueprint_id.clone()),
749                )
750            }
751            BlueprintPayloadDef::Generic(instance_index) => {
752                let generic_substitution = target
753                    .blueprint_info
754                    .generic_substitutions
755                    .get(instance_index as usize)
756                    .expect("Missing generic substitution");
757
758                match generic_substitution {
759                    GenericSubstitution::Local(type_id) => {
760                        let schema = match &target.meta {
761                            SchemaValidationMeta::ExistingObject { additional_schemas } => {
762                                self.get_schema(additional_schemas, &type_id.0)?
763                            }
764                            SchemaValidationMeta::NewObject { .. }
765                            | SchemaValidationMeta::Blueprint => {
766                                return Err(SystemReaderError::TargetNotSupported);
767                            }
768                        };
769
770                        (schema, type_id.1, SchemaOrigin::Instance)
771                    }
772                    GenericSubstitution::Remote(type_id) => {
773                        let (schema, scoped_type_id) = self.get_blueprint_type_schema(&type_id)?;
774                        (
775                            schema,
776                            scoped_type_id.1,
777                            SchemaOrigin::Blueprint(BlueprintId::new(
778                                &type_id.package_address,
779                                type_id.blueprint_name.clone(),
780                            )),
781                        )
782                    }
783                }
784            }
785        };
786
787        Ok(ResolvedPayloadSchema {
788            schema,
789            type_id: index,
790            allow_ownership,
791            allow_non_global_refs,
792            schema_origin,
793        })
794    }
795
796    pub fn get_schema(
797        &self,
798        node_id: &NodeId,
799        schema_hash: &SchemaHash,
800    ) -> Result<Rc<VersionedScryptoSchema>, SystemReaderError> {
801        {
802            if let Some(cache) = self.schema_cache.borrow().get(schema_hash) {
803                return Ok(cache.clone());
804            }
805        }
806
807        let schema = Rc::new(
808            self.fetch_substate::<KeyValueEntrySubstate<VersionedScryptoSchema>>(
809                node_id,
810                SCHEMAS_PARTITION,
811                &SubstateKey::Map(scrypto_encode(schema_hash).unwrap()),
812            )
813            .ok_or_else(|| SystemReaderError::SchemaDoesNotExist)?
814            .into_value()
815            .expect("Schema should exist if substate exists"),
816        );
817
818        self.schema_cache
819            .borrow_mut()
820            .insert(schema_hash.clone(), schema.clone());
821
822        Ok(schema)
823    }
824
825    pub fn get_blueprint_type_schema(
826        &self,
827        type_id: &BlueprintTypeIdentifier,
828    ) -> Result<(Rc<VersionedScryptoSchema>, ScopedTypeId), SystemReaderError> {
829        let BlueprintTypeIdentifier {
830            package_address,
831            blueprint_name,
832            type_name,
833        } = type_id.clone();
834        let definition = self.get_blueprint_payload_def(&BlueprintId {
835            package_address,
836            blueprint_name,
837        })?;
838        let scoped_type_id = definition
839            .interface
840            .types
841            .get(&type_name)
842            .ok_or(SystemReaderError::BlueprintTypeNotFound(type_name.clone()))?;
843        Ok((
844            self.get_schema(package_address.as_node_id(), &scoped_type_id.0)?,
845            scoped_type_id.clone(),
846        ))
847    }
848
849    pub fn get_blueprint_payload_def(
850        &self,
851        blueprint_id: &BlueprintId,
852    ) -> Result<BlueprintDefinition, SystemReaderError> {
853        let bp_version_key = BlueprintVersionKey::new_default(blueprint_id.blueprint_name.clone());
854        let definition = self
855            .fetch_substate::<PackageBlueprintVersionDefinitionEntrySubstate>(
856                blueprint_id.package_address.as_node_id(),
857                MAIN_BASE_PARTITION
858                    .at_offset(PACKAGE_BLUEPRINTS_PARTITION_OFFSET)
859                    .unwrap(),
860                &SubstateKey::Map(scrypto_encode(&bp_version_key).unwrap()),
861            )
862            .ok_or_else(|| SystemReaderError::BlueprintDoesNotExist)?;
863
864        Ok(definition
865            .into_value()
866            .unwrap()
867            .fully_update_and_into_latest_version())
868    }
869
870    pub fn validate_payload<'b>(
871        &'b self,
872        payload: &[u8],
873        payload_schema: &'b ResolvedPayloadSchema,
874        depth_limit: usize,
875    ) -> Result<(), LocatedValidationError<ScryptoCustomExtension>> {
876        let validation_context: Box<dyn ValidationContext<Error = String>> =
877            Box::new(ValidationPayloadCheckerContext {
878                reader: self,
879                schema_origin: payload_schema.schema_origin.clone(),
880                allow_ownership: payload_schema.allow_ownership,
881                allow_non_global_ref: payload_schema.allow_non_global_refs,
882            });
883
884        validate_payload_against_schema::<ScryptoCustomExtension, _>(
885            payload,
886            payload_schema.schema.v1(),
887            payload_schema.type_id,
888            &validation_context,
889            depth_limit,
890        )
891    }
892
893    pub fn fetch_substate<D: ScryptoDecode>(
894        &self,
895        node_id: &NodeId,
896        partition_num: PartitionNumber,
897        key: &SubstateKey,
898    ) -> Option<D> {
899        if let Some(result) =
900            self.fetch_substate_from_state_updates::<D>(node_id, partition_num, key)
901        {
902            // If result can be determined from the state updates.
903            result
904        } else {
905            // Otherwise, read from the substate database.
906            self.fetch_substate_from_database::<D>(node_id, partition_num, key)
907        }
908    }
909
910    pub fn fetch_substate_from_database<D: ScryptoDecode>(
911        &self,
912        node_id: &NodeId,
913        partition_num: PartitionNumber,
914        key: &SubstateKey,
915    ) -> Option<D> {
916        self.substate_db
917            .get_substate::<D>(node_id, partition_num, key)
918    }
919
920    pub fn fetch_substate_from_state_updates<D: ScryptoDecode>(
921        &self,
922        node_id: &NodeId,
923        partition_num: PartitionNumber,
924        substate_key: &SubstateKey,
925    ) -> Option<Option<D>> {
926        if let Some(updates) = self.state_updates {
927            updates
928                .by_node
929                .get(node_id)
930                .and_then(|node_updates| match node_updates {
931                    NodeStateUpdates::Delta { by_partition } => by_partition.get(&partition_num),
932                })
933                .and_then(|partition_updates| match partition_updates {
934                    PartitionStateUpdates::Delta { by_substate } => {
935                        match by_substate.get(substate_key) {
936                            Some(e) => match e {
937                                DatabaseUpdate::Set(value) => {
938                                    Some(Some(scrypto_decode(value).unwrap()))
939                                }
940                                DatabaseUpdate::Delete => {
941                                    // Return `Some(None)` if the substate is deleted.
942                                    Some(None)
943                                }
944                            },
945                            None => None,
946                        }
947                    }
948                    PartitionStateUpdates::Batch(e) => match e {
949                        BatchPartitionStateUpdate::Reset {
950                            new_substate_values,
951                        } => {
952                            // Return `Some(None)` if the substate key isn't in the new value set.
953                            Some(
954                                new_substate_values
955                                    .get(substate_key)
956                                    .map(|value| scrypto_decode(value).unwrap()),
957                            )
958                        }
959                    },
960                })
961        } else {
962            None
963        }
964    }
965}
966
967// Reverse Mapping Functionality
968impl<'a, S: SubstateDatabase> SystemDatabaseReader<'a, S> {
969    pub fn get_partition_descriptors(
970        &self,
971        node_id: &NodeId,
972        partition_num: &PartitionNumber,
973    ) -> Result<Vec<SystemPartitionDescriptor>, SystemReaderError> {
974        let mut descriptors = Vec::new();
975
976        if partition_num.eq(&BOOT_LOADER_PARTITION) {
977            descriptors.push(SystemPartitionDescriptor::BootLoader);
978        }
979
980        if partition_num.eq(&PROTOCOL_UPDATE_STATUS_PARTITION) {
981            descriptors.push(SystemPartitionDescriptor::ProtocolUpdateStatus);
982        }
983
984        if partition_num.eq(&TYPE_INFO_FIELD_PARTITION) {
985            descriptors.push(SystemPartitionDescriptor::TypeInfo);
986        }
987
988        if partition_num.eq(&SCHEMAS_PARTITION) {
989            descriptors.push(SystemPartitionDescriptor::Schema);
990        }
991
992        let type_info = self.get_type_info(node_id)?;
993
994        match type_info {
995            TypeInfoSubstate::Object(object_info) => {
996                let (module_id, partition_offset) = if partition_num.ge(&MAIN_BASE_PARTITION) {
997                    let partition_offset = PartitionOffset(partition_num.0 - MAIN_BASE_PARTITION.0);
998                    (ModuleId::Main, Some(partition_offset))
999                } else {
1000                    match object_info.object_type {
1001                        ObjectType::Global { modules } => {
1002                            if partition_num.ge(&ROLE_ASSIGNMENT_BASE_PARTITION) {
1003                                if modules.contains_key(&AttachedModuleId::RoleAssignment) {
1004                                    let partition_offset = PartitionOffset(
1005                                        partition_num.0 - ROLE_ASSIGNMENT_BASE_PARTITION.0,
1006                                    );
1007                                    (ModuleId::RoleAssignment, Some(partition_offset))
1008                                } else {
1009                                    (ModuleId::Main, None)
1010                                }
1011                            } else if partition_num.ge(&ROYALTY_BASE_PARTITION) {
1012                                if modules.contains_key(&AttachedModuleId::Royalty) {
1013                                    let partition_offset =
1014                                        PartitionOffset(partition_num.0 - ROYALTY_BASE_PARTITION.0);
1015                                    (ModuleId::Royalty, Some(partition_offset))
1016                                } else {
1017                                    (ModuleId::Main, None)
1018                                }
1019                            } else if partition_num.ge(&METADATA_BASE_PARTITION) {
1020                                if modules.contains_key(&AttachedModuleId::Metadata) {
1021                                    let partition_offset = PartitionOffset(
1022                                        partition_num.0 - METADATA_BASE_PARTITION.0,
1023                                    );
1024                                    (ModuleId::Metadata, Some(partition_offset))
1025                                } else {
1026                                    (ModuleId::Main, None)
1027                                }
1028                            } else {
1029                                (ModuleId::Main, None)
1030                            }
1031                        }
1032                        ObjectType::Owned => (ModuleId::Main, None),
1033                    }
1034                };
1035
1036                let blueprint_id = match module_id {
1037                    ModuleId::Main => object_info.blueprint_info.blueprint_id,
1038                    _ => module_id.static_blueprint().unwrap(),
1039                };
1040
1041                let definition = self.get_blueprint_definition(&blueprint_id).unwrap();
1042
1043                let state_schema = &definition.interface.state;
1044                match (&state_schema.fields, &partition_offset) {
1045                    (
1046                        Some((PartitionDescription::Logical(offset), _fields)),
1047                        Some(partition_offset),
1048                    ) => {
1049                        if offset.eq(partition_offset) {
1050                            descriptors.push(SystemPartitionDescriptor::Object(
1051                                module_id,
1052                                ObjectPartitionDescriptor::Fields,
1053                            ));
1054                        }
1055                    }
1056                    _ => {}
1057                }
1058
1059                for (index, (partition_description, schema)) in
1060                    state_schema.collections.iter().enumerate()
1061                {
1062                    let partition_descriptor = match schema {
1063                        BlueprintCollectionSchema::KeyValueStore(..) => {
1064                            ObjectPartitionDescriptor::KeyValueCollection(index as u8)
1065                        }
1066                        BlueprintCollectionSchema::Index(..) => {
1067                            ObjectPartitionDescriptor::IndexCollection(index as u8)
1068                        }
1069                        BlueprintCollectionSchema::SortedIndex(..) => {
1070                            ObjectPartitionDescriptor::SortedIndexCollection(index as u8)
1071                        }
1072                    };
1073
1074                    match (partition_description, &partition_offset) {
1075                        (PartitionDescription::Logical(offset), Some(partition_offset))
1076                            if offset.eq(partition_offset) =>
1077                        {
1078                            descriptors.push(SystemPartitionDescriptor::Object(
1079                                module_id,
1080                                partition_descriptor,
1081                            ))
1082                        }
1083                        (PartitionDescription::Physical(physical_partition), None)
1084                            if physical_partition.eq(&partition_num) =>
1085                        {
1086                            descriptors.push(SystemPartitionDescriptor::Object(
1087                                module_id,
1088                                partition_descriptor,
1089                            ))
1090                        }
1091                        _ => {}
1092                    }
1093                }
1094            }
1095            TypeInfoSubstate::KeyValueStore(..) => {
1096                if partition_num.eq(&MAIN_BASE_PARTITION) {
1097                    descriptors.push(SystemPartitionDescriptor::KeyValueStore);
1098                }
1099            }
1100            _ => {}
1101        }
1102
1103        Ok(descriptors)
1104    }
1105
1106    pub fn field_iter(
1107        &self,
1108        node_id: &NodeId,
1109        partition_number: PartitionNumber,
1110    ) -> Box<dyn Iterator<Item = (FieldKey, Vec<u8>)> + '_> {
1111        if self.state_updates.is_some() {
1112            panic!("fields_iter with overlay not supported.");
1113        }
1114        self.substate_db
1115            .list_field_raw_values(node_id, partition_number, None::<SubstateKey>)
1116    }
1117
1118    pub fn map_iter(
1119        &self,
1120        node_id: &NodeId,
1121        partition_number: PartitionNumber,
1122    ) -> Box<dyn Iterator<Item = (MapKey, Vec<u8>)> + '_> {
1123        if self.state_updates.is_some() {
1124            panic!("map_iter with overlay not supported.");
1125        }
1126        self.substate_db
1127            .list_map_raw_values(node_id, partition_number, None::<SubstateKey>)
1128    }
1129
1130    pub fn sorted_iter(
1131        &self,
1132        node_id: &NodeId,
1133        partition_number: PartitionNumber,
1134    ) -> Box<dyn Iterator<Item = (SortedKey, Vec<u8>)> + '_> {
1135        if self.state_updates.is_some() {
1136            panic!("sorted_iter with overlay not supported.");
1137        }
1138        self.substate_db
1139            .list_sorted_raw_values(node_id, partition_number, None::<SubstateKey>)
1140    }
1141}
1142
1143struct ValidationPayloadCheckerContext<'a, S: SubstateDatabase + ?Sized> {
1144    reader: &'a SystemDatabaseReader<'a, S>,
1145    schema_origin: SchemaOrigin,
1146    allow_non_global_ref: bool,
1147    allow_ownership: bool,
1148}
1149
1150impl<'a, S: SubstateDatabase + ?Sized> ValidationContext
1151    for ValidationPayloadCheckerContext<'a, S>
1152{
1153    type Error = String;
1154
1155    fn get_node_type_info(&self, node_id: &NodeId) -> Result<TypeInfoForValidation, String> {
1156        let type_info = self
1157            .reader
1158            .get_type_info(node_id)
1159            .map_err(|_| "Type Info missing".to_string())?;
1160        let type_info_for_validation = match type_info {
1161            TypeInfoSubstate::Object(object_info) => TypeInfoForValidation::Object {
1162                package: object_info.blueprint_info.blueprint_id.package_address,
1163                blueprint: object_info.blueprint_info.blueprint_id.blueprint_name,
1164            },
1165            TypeInfoSubstate::KeyValueStore(..) => TypeInfoForValidation::KeyValueStore,
1166            TypeInfoSubstate::GlobalAddressReservation(..) => {
1167                TypeInfoForValidation::GlobalAddressReservation
1168            }
1169            TypeInfoSubstate::GlobalAddressPhantom(..) => {
1170                return Err("Found invalid stored address phantom".to_string())
1171            }
1172        };
1173
1174        Ok(type_info_for_validation)
1175    }
1176
1177    fn schema_origin(&self) -> &SchemaOrigin {
1178        &self.schema_origin
1179    }
1180
1181    fn allow_ownership(&self) -> bool {
1182        self.allow_ownership
1183    }
1184
1185    fn allow_non_global_ref(&self) -> bool {
1186        self.allow_non_global_ref
1187    }
1188}
1189
1190impl<'a, S: SubstateDatabase + ListableSubstateDatabase> SystemDatabaseReader<'a, S> {
1191    pub fn partitions_iter(&self) -> Box<dyn Iterator<Item = (NodeId, PartitionNumber)> + '_> {
1192        if self.state_updates.is_some() {
1193            panic!("partitions_iter with overlay not supported.");
1194        }
1195
1196        self.substate_db.read_partition_keys()
1197    }
1198}
1199
1200pub struct SystemDatabaseWriter<'a, S: SubstateDatabase + CommittableSubstateDatabase> {
1201    substate_db: &'a mut S,
1202}
1203
1204impl<'a, S: SubstateDatabase + CommittableSubstateDatabase> SystemDatabaseWriter<'a, S> {
1205    pub fn new(substate_db: &'a mut S) -> Self {
1206        Self { substate_db }
1207    }
1208
1209    pub fn write_typed_object_field<V: ScryptoEncode>(
1210        &mut self,
1211        node_id: &NodeId,
1212        module_id: ModuleId,
1213        field_index: u8,
1214        value: V,
1215    ) -> Result<(), SystemReaderError> {
1216        let reader = SystemDatabaseReader::new(self.substate_db);
1217        let blueprint_id = reader.get_blueprint_id(node_id, module_id)?;
1218        let definition = reader.get_blueprint_definition(&blueprint_id)?;
1219        let partition_description = &definition
1220            .interface
1221            .state
1222            .fields
1223            .as_ref()
1224            .ok_or_else(|| SystemReaderError::FieldDoesNotExist)?
1225            .0;
1226        let partition_number = match partition_description {
1227            PartitionDescription::Logical(offset) => {
1228                let base_partition = match module_id {
1229                    ModuleId::Main => MAIN_BASE_PARTITION,
1230                    ModuleId::Metadata => METADATA_BASE_PARTITION,
1231                    ModuleId::Royalty => ROYALTY_BASE_PARTITION,
1232                    ModuleId::RoleAssignment => ROLE_ASSIGNMENT_BASE_PARTITION,
1233                };
1234                base_partition.at_offset(*offset).unwrap()
1235            }
1236            PartitionDescription::Physical(partition_number) => *partition_number,
1237        };
1238
1239        self.substate_db.update_substate(
1240            node_id,
1241            partition_number,
1242            SubstateKey::Field(field_index),
1243            FieldSubstate::new_field(value, LockStatus::Unlocked),
1244        );
1245
1246        Ok(())
1247    }
1248}