1use crate::internal_prelude::*;
2use crate::system::system_db_reader::*;
3use crate::system::system_type_checker::BlueprintTypeTarget;
4use crate::system::type_info::TypeInfoSubstate;
5use radix_engine_interface::blueprints::package::*;
6use radix_substate_store_interface::interface::SubstateDatabase;
7
8#[derive(Debug, Clone, ScryptoSbor, PartialEq, Eq)]
9pub enum SubstateSystemStructure {
10 SystemField(SystemFieldStructure),
11 SystemSchema,
12 KeyValueStoreEntry(KeyValueStoreEntryStructure),
14 ObjectField(FieldStructure),
16 ObjectKeyValuePartitionEntry(KeyValuePartitionEntryStructure),
17 ObjectIndexPartitionEntry(IndexPartitionEntryStructure),
18 ObjectSortedIndexPartitionEntry(SortedIndexPartitionEntryStructure),
19}
20
21#[derive(Debug, Clone, ScryptoSbor, PartialEq, Eq)]
22pub struct SystemFieldStructure {
23 pub field_kind: SystemFieldKind,
24}
25
26#[derive(Debug, Copy, Clone, ScryptoSbor, PartialEq, Eq)]
27pub enum SystemFieldKind {
28 TypeInfo,
29 VmBoot,
30 SystemBoot,
31 KernelBoot,
32 TransactionValidationConfiguration,
33 ProtocolUpdateStatusSummary,
34}
35
36#[derive(Debug, Clone, ScryptoSbor, PartialEq, Eq)]
37pub struct KeyValueStoreEntryStructure {
38 pub key_full_type_id: FullyScopedTypeId<NodeId>,
39 pub value_full_type_id: FullyScopedTypeId<NodeId>,
40}
41
42#[derive(Debug, Clone, ScryptoSbor, PartialEq, Eq)]
43pub struct FieldStructure {
44 pub value_schema: ObjectSubstateTypeReference,
45}
46
47#[derive(Debug, Clone, ScryptoSbor, PartialEq, Eq)]
48pub struct KeyValuePartitionEntryStructure {
49 pub key_schema: ObjectSubstateTypeReference,
50 pub value_schema: ObjectSubstateTypeReference,
51}
52
53#[derive(Debug, Clone, ScryptoSbor, PartialEq, Eq)]
54pub struct IndexPartitionEntryStructure {
55 pub key_schema: ObjectSubstateTypeReference,
56 pub value_schema: ObjectSubstateTypeReference,
57}
58
59#[derive(Debug, Clone, ScryptoSbor, PartialEq, Eq)]
60pub struct SortedIndexPartitionEntryStructure {
61 pub key_schema: ObjectSubstateTypeReference,
62 pub value_schema: ObjectSubstateTypeReference,
63}
64
65#[derive(Debug, Clone, ScryptoSbor, PartialEq, Eq)]
66pub enum ObjectSubstateTypeReference {
67 Package(PackageTypeReference),
68 ObjectInstance(ObjectInstanceTypeReference),
69}
70
71#[derive(Debug, Clone, ScryptoSbor, PartialEq, Eq)]
72pub struct PackageTypeReference {
73 pub full_type_id: FullyScopedTypeId<PackageAddress>,
74}
75
76#[derive(Debug, Clone, ScryptoSbor, PartialEq, Eq)]
77pub struct ObjectInstanceTypeReference {
78 pub instance_type_id: u8,
79 pub resolved_full_type_id: FullyScopedTypeId<NodeId>,
80}
81
82#[derive(Debug, Clone, ScryptoSbor, PartialEq, Eq)]
83pub struct EventSystemStructure {
84 pub package_type_reference: PackageTypeReference,
85}
86
87pub type SubstateSystemStructures =
88 IndexMap<NodeId, IndexMap<PartitionNumber, IndexMap<SubstateKey, SubstateSystemStructure>>>;
89
90#[derive(Default, Debug, Clone, ScryptoSbor, PartialEq, Eq)]
91pub struct SystemStructure {
92 pub substate_system_structures: SubstateSystemStructures,
93 pub event_system_structures: IndexMap<EventTypeIdentifier, EventSystemStructure>,
94}
95
96impl SystemStructure {
97 pub fn resolve<S: SubstateDatabase>(
98 substate_db: &S,
99 state_updates: &StateUpdates,
100 application_events: &Vec<(EventTypeIdentifier, Vec<u8>)>,
101 ) -> Self {
102 let mut substate_schema_mapper = SubstateSchemaMapper::new(
103 SystemDatabaseReader::new_with_overlay(substate_db, state_updates),
104 );
105 substate_schema_mapper.add_substate_structures(state_updates);
106 let substate_system_structures = substate_schema_mapper.done();
107
108 let event_system_structures =
109 EventSchemaMapper::new(substate_db, state_updates, application_events).run();
110
111 SystemStructure {
112 substate_system_structures,
113 event_system_structures,
114 }
115 }
116}
117
118pub struct SubstateSchemaMapper<'a, S: SubstateDatabase> {
123 system_reader: SystemDatabaseReader<'a, S>,
125 substate_structures: SubstateSystemStructures,
127}
128
129impl<'a, S: SubstateDatabase> SubstateSchemaMapper<'a, S> {
130 pub fn new(system_reader: SystemDatabaseReader<'a, S>) -> Self {
132 Self {
133 system_reader,
134 substate_structures: index_map_new(),
135 }
136 }
137
138 pub fn add_substate_structure(
140 &mut self,
141 node_id: &NodeId,
142 partition_num: &PartitionNumber,
143 key: &SubstateKey,
144 ) {
145 let partition_descriptors = self
146 .system_reader
147 .get_partition_descriptors(node_id, partition_num)
148 .unwrap();
149 let substate_structure =
150 self.resolve_substate_structure(node_id, partition_descriptors, key);
151 self.substate_structures
152 .entry(node_id.clone())
153 .or_insert_with(|| index_map_new())
154 .entry(partition_num.clone())
155 .or_insert_with(|| index_map_new())
156 .insert(key.clone(), substate_structure);
157 }
158
159 pub fn add_substate_structures(&mut self, state_updates: &StateUpdates) {
162 for (node_id, node_updates) in &state_updates.by_node {
163 let NodeStateUpdates::Delta { by_partition } = &node_updates;
164
165 for (partition_num, partition_update) in by_partition {
166 match partition_update {
167 PartitionStateUpdates::Delta { by_substate } => {
168 for substate_key in by_substate.keys() {
169 self.add_substate_structure(node_id, partition_num, substate_key);
170 }
171 }
172 PartitionStateUpdates::Batch(_) => {
173 }
175 }
176 }
177 }
178 }
179
180 pub fn add_for_all_individually_updated(&mut self, updates: &StateUpdates) {
184 for (node_id, node_state_updates) in &updates.by_node {
185 match node_state_updates {
186 NodeStateUpdates::Delta { by_partition } => {
187 for (partition_num, partition_state_updates) in by_partition {
188 let substate_keys = match partition_state_updates {
189 PartitionStateUpdates::Delta { by_substate } => {
190 by_substate.keys().collect::<Vec<_>>()
191 }
192 PartitionStateUpdates::Batch(BatchPartitionStateUpdate::Reset {
193 new_substate_values,
194 }) => new_substate_values.keys().collect::<Vec<_>>(),
195 };
196 for substate_key in substate_keys {
197 self.add_substate_structure(node_id, partition_num, substate_key);
198 }
199 }
200 }
201 }
202 }
203 }
204
205 pub fn done(self) -> SubstateSystemStructures {
207 self.substate_structures
208 }
209
210 fn resolve_substate_structure(
211 &self,
212 node_id: &NodeId,
213 partition_descriptors: Vec<SystemPartitionDescriptor>,
214 key: &SubstateKey,
215 ) -> SubstateSystemStructure {
216 match &partition_descriptors[0] {
217 SystemPartitionDescriptor::BootLoader => {
218 SubstateSystemStructure::SystemField(SystemFieldStructure {
219 field_kind: {
220 let field = BootLoaderField::try_from(key)
221 .unwrap_or_else(|()| panic!("Unknown boot loader field: {key:?}"));
222 match field {
223 BootLoaderField::KernelBoot => SystemFieldKind::KernelBoot,
224 BootLoaderField::SystemBoot => SystemFieldKind::SystemBoot,
225 BootLoaderField::VmBoot => SystemFieldKind::VmBoot,
226 BootLoaderField::TransactionValidationConfiguration => {
227 SystemFieldKind::TransactionValidationConfiguration
228 }
229 }
230 },
231 })
232 }
233 SystemPartitionDescriptor::ProtocolUpdateStatus => {
234 SubstateSystemStructure::SystemField(SystemFieldStructure {
235 field_kind: {
236 let field = ProtocolUpdateStatusField::try_from(key).unwrap_or_else(|()| {
237 panic!("Unknown protocol update status field: {key:?}")
238 });
239 match field {
240 ProtocolUpdateStatusField::Summary => {
241 SystemFieldKind::ProtocolUpdateStatusSummary
242 }
243 }
244 },
245 })
246 }
247 SystemPartitionDescriptor::TypeInfo => {
248 SubstateSystemStructure::SystemField(SystemFieldStructure {
249 field_kind: {
250 let field = TypeInfoField::try_from(key)
251 .unwrap_or_else(|()| panic!("Unknown type info field: {key:?}"));
252 match field {
253 TypeInfoField::TypeInfo => SystemFieldKind::TypeInfo,
254 }
255 },
256 })
257 }
258 SystemPartitionDescriptor::Schema => SubstateSystemStructure::SystemSchema,
259 SystemPartitionDescriptor::KeyValueStore => {
260 let info = self
261 .system_reader
262 .get_kv_store_type_target(node_id)
263 .unwrap_or_else(|_| panic!("Could not get type info for node {node_id:?}"));
264
265 let key_full_type_id = match info.kv_store_type.key_generic_substitution {
266 GenericSubstitution::Local(type_id) => type_id.under_node(*node_id),
267 GenericSubstitution::Remote(type_id) => self
268 .system_reader
269 .get_blueprint_type_schema(&type_id)
270 .map(|x| x.1.under_node(type_id.package_address.into_node_id()))
271 .unwrap_or_else(|_| panic!("Could not get type info {type_id:?}")),
272 };
273 let value_full_type_id = match info.kv_store_type.value_generic_substitution {
274 GenericSubstitution::Local(type_id) => type_id.under_node(*node_id),
275 GenericSubstitution::Remote(type_id) => self
276 .system_reader
277 .get_blueprint_type_schema(&type_id)
278 .map(|x| x.1.under_node(type_id.package_address.into_node_id()))
279 .unwrap_or_else(|_| panic!("Could not get type info {type_id:?}")),
280 };
281 SubstateSystemStructure::KeyValueStoreEntry(KeyValueStoreEntryStructure {
282 key_full_type_id,
283 value_full_type_id,
284 })
285 }
286 SystemPartitionDescriptor::Object(module_id, object_partition_descriptor) => {
287 let bp_type_target = self
288 .system_reader
289 .get_blueprint_type_target(node_id, *module_id)
290 .unwrap_or_else(|_| panic!("Could not get type info for node {node_id:?}"));
291
292 self.resolve_object_substate_structure(
293 &bp_type_target,
294 object_partition_descriptor,
295 key,
296 )
297 }
298 }
299 }
300
301 fn resolve_object_substate_structure(
302 &self,
303 bp_type_target: &BlueprintTypeTarget,
304 object_partition_descriptor: &ObjectPartitionDescriptor,
305 key: &SubstateKey,
306 ) -> SubstateSystemStructure {
307 match object_partition_descriptor {
308 ObjectPartitionDescriptor::Fields => {
309 let field_index = match key {
310 SubstateKey::Field(field_index) => field_index,
311 _ => panic!("Invalid field key"),
312 };
313
314 let payload_identifier = BlueprintPayloadIdentifier::Field(*field_index);
315 let type_reference = self
316 .system_reader
317 .get_blueprint_payload_schema_pointer(&bp_type_target, &payload_identifier)
318 .expect("Could not resolve to type reference");
319 return SubstateSystemStructure::ObjectField(FieldStructure {
320 value_schema: type_reference,
321 });
322 }
323
324 ObjectPartitionDescriptor::KeyValueCollection(collection_index) => {
325 let key_identifier =
326 BlueprintPayloadIdentifier::KeyValueEntry(*collection_index, KeyOrValue::Key);
327 let value_identifier =
328 BlueprintPayloadIdentifier::KeyValueEntry(*collection_index, KeyOrValue::Value);
329 let key_type_reference = self
330 .system_reader
331 .get_blueprint_payload_schema_pointer(&bp_type_target, &key_identifier)
332 .expect("Could not resolve to type reference");
333 let value_type_reference = self
334 .system_reader
335 .get_blueprint_payload_schema_pointer(&bp_type_target, &value_identifier)
336 .expect("Could not resolve to type reference");
337 SubstateSystemStructure::ObjectKeyValuePartitionEntry(
338 KeyValuePartitionEntryStructure {
339 key_schema: key_type_reference,
340 value_schema: value_type_reference,
341 },
342 )
343 }
344
345 ObjectPartitionDescriptor::IndexCollection(collection_index) => {
346 let key_identifier =
347 BlueprintPayloadIdentifier::IndexEntry(*collection_index, KeyOrValue::Key);
348 let value_identifier =
349 BlueprintPayloadIdentifier::IndexEntry(*collection_index, KeyOrValue::Value);
350 let key_type_reference = self
351 .system_reader
352 .get_blueprint_payload_schema_pointer(&bp_type_target, &key_identifier)
353 .expect("Could not resolve to type reference");
354 let value_type_reference = self
355 .system_reader
356 .get_blueprint_payload_schema_pointer(&bp_type_target, &value_identifier)
357 .expect("Could not resolve to type reference");
358 SubstateSystemStructure::ObjectIndexPartitionEntry(IndexPartitionEntryStructure {
359 key_schema: key_type_reference,
360 value_schema: value_type_reference,
361 })
362 }
363
364 ObjectPartitionDescriptor::SortedIndexCollection(collection_index) => {
365 let key_identifier = BlueprintPayloadIdentifier::SortedIndexEntry(
366 *collection_index,
367 KeyOrValue::Key,
368 );
369 let value_identifier = BlueprintPayloadIdentifier::SortedIndexEntry(
370 *collection_index,
371 KeyOrValue::Value,
372 );
373 let key_type_reference = self
374 .system_reader
375 .get_blueprint_payload_schema_pointer(&bp_type_target, &key_identifier)
376 .expect("Could not resolve to type reference");
377 let value_type_reference = self
378 .system_reader
379 .get_blueprint_payload_schema_pointer(&bp_type_target, &value_identifier)
380 .expect("Could not resolve to type reference");
381 SubstateSystemStructure::ObjectSortedIndexPartitionEntry(
382 SortedIndexPartitionEntryStructure {
383 key_schema: key_type_reference,
384 value_schema: value_type_reference,
385 },
386 )
387 }
388 }
389 }
390}
391
392pub struct EventSchemaMapper<'a, S: SubstateDatabase> {
396 system_reader: SystemDatabaseReader<'a, S>,
397 application_events: &'a Vec<(EventTypeIdentifier, Vec<u8>)>,
398}
399
400impl<'a, S: SubstateDatabase> EventSchemaMapper<'a, S> {
401 pub fn new(
402 substate_db: &'a S,
403 state_updates: &'a StateUpdates,
404 application_events: &'a Vec<(EventTypeIdentifier, Vec<u8>)>,
405 ) -> Self {
406 Self {
407 system_reader: SystemDatabaseReader::new_with_overlay(substate_db, state_updates),
408 application_events,
409 }
410 }
411
412 pub fn run(&self) -> IndexMap<EventTypeIdentifier, EventSystemStructure> {
413 let mut event_system_structures = index_map_new();
414 for (event_type_identifier, _) in self.application_events {
415 if event_system_structures.contains_key(event_type_identifier) {
416 continue;
417 }
418 let blueprint_id = match &event_type_identifier.0 {
419 Emitter::Function(blueprint_id) => blueprint_id.clone(),
420 Emitter::Method(node_id, module_id) => {
421 if let ModuleId::Main = module_id {
422 let main_type_info = self.system_reader.get_type_info(node_id).unwrap();
423 match main_type_info {
424 TypeInfoSubstate::Object(info) => info.blueprint_info.blueprint_id,
425 _ => panic!("Unexpected Type Info {:?}", main_type_info),
426 }
427 } else {
428 module_id.static_blueprint().unwrap()
429 }
430 }
431 };
432
433 let blueprint_definition = self
434 .system_reader
435 .get_blueprint_definition(&blueprint_id)
436 .unwrap();
437
438 let type_pointer = blueprint_definition
439 .interface
440 .get_event_payload_def(event_type_identifier.1.as_str())
441 .unwrap();
442
443 let BlueprintPayloadDef::Static(type_identifier) = type_pointer else {
444 panic!("Event identifier type pointer cannot be an instance type pointer");
445 };
446
447 let event_system_structure = EventSystemStructure {
448 package_type_reference: PackageTypeReference {
449 full_type_id: type_identifier.under_node(blueprint_id.package_address),
450 },
451 };
452
453 event_system_structures.insert(event_type_identifier.clone(), event_system_structure);
454 }
455
456 event_system_structures
457 }
458}