1use crate::blueprints::package::BlueprintType;
2use crate::internal_prelude::*;
3use radix_blueprint_schema_init::*;
4use strum::FromRepr;
5
6#[derive(FromRepr)]
7#[repr(u64)]
8pub enum NativeCodeId {
9 PackageCode1 = 0u64,
13
14 PackageCode2 = 22u64,
18
19 ResourceCode1 = 1u64,
23
24 ResourceCode2 = 26u64,
28
29 IdentityCode1 = 2u64,
33
34 IdentityCode2 = 25u64,
38
39 ConsensusManagerCode1 = 3u64,
43
44 ConsensusManagerCode2 = 16u64,
48
49 AccountCode1 = 5u64,
53
54 AccountCode2 = 20u64,
58
59 AccountCode3 = 24u64,
63
64 AccessControllerCode1 = 6u64,
68
69 AccessControllerCode2 = 23u64,
73
74 PoolCode1 = 13u64,
78
79 PoolCode2 = 17u64,
83
84 TransactionTrackerCode1 = 14u64,
88
89 TestUtilsCode1 = 15u64,
93
94 LockerCode1 = 19u64,
98
99 TransactionProcessorCode1 = 7u64,
103
104 TransactionProcessorCode2 = 21u64,
108
109 MetadataCode1 = 10u64,
113
114 RoyaltyCode1 = 11u64,
118
119 RoleAssignmentCode1 = 12u64,
123
124 RoleAssignmentCode2 = 18u64,
128}
129
130pub const PACKAGE_FIELDS_PARTITION_OFFSET: PartitionOffset = PartitionOffset(0u8);
131pub const PACKAGE_BLUEPRINTS_PARTITION_OFFSET: PartitionOffset = PartitionOffset(1u8);
132pub const PACKAGE_BLUEPRINT_DEPENDENCIES_PARTITION_OFFSET: PartitionOffset = PartitionOffset(2u8);
133pub const PACKAGE_ROYALTY_PARTITION_OFFSET: PartitionOffset = PartitionOffset(3u8);
135pub const PACKAGE_AUTH_TEMPLATE_PARTITION_OFFSET: PartitionOffset = PartitionOffset(4u8);
136pub const PACKAGE_VM_TYPE_PARTITION_OFFSET: PartitionOffset = PartitionOffset(5u8);
137pub const PACKAGE_ORIGINAL_CODE_PARTITION_OFFSET: PartitionOffset = PartitionOffset(6u8);
138pub const PACKAGE_INSTRUMENTED_CODE_PARTITION_OFFSET: PartitionOffset = PartitionOffset(7u8);
139
140define_wrapped_hash!(
141 CodeHash
143);
144
145#[derive(Copy, Debug, Clone, PartialEq, Eq, Sbor)]
146pub enum VmType {
147 Native,
148 ScryptoV1,
149}
150
151#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Sbor)]
152pub enum BlueprintPayloadDef {
153 Static(ScopedTypeId), Generic(u8), }
157
158impl BlueprintPayloadDef {
159 pub fn from_type_ref(type_ref: TypeRef<LocalTypeId>, schema_hash: SchemaHash) -> Self {
160 match type_ref {
161 TypeRef::Static(type_id) => {
162 BlueprintPayloadDef::Static(ScopedTypeId(schema_hash, type_id))
163 }
164 TypeRef::Generic(index) => BlueprintPayloadDef::Generic(index),
165 }
166 }
167}
168
169#[derive(Debug, Clone, PartialEq, Eq, Sbor)]
170pub struct FunctionSchema {
171 pub receiver: Option<ReceiverInfo>,
172 pub input: BlueprintPayloadDef,
173 pub output: BlueprintPayloadDef,
174}
175
176#[derive(Debug, Clone, Copy, PartialEq, Eq, ScryptoSbor, Ord, PartialOrd, Hash)]
177pub struct BlueprintVersion {
178 pub major: u32,
179 pub minor: u32,
180 pub patch: u32,
181}
182
183impl Default for BlueprintVersion {
184 fn default() -> Self {
185 Self {
186 major: 1,
187 minor: 0,
188 patch: 0,
189 }
190 }
191}
192
193#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor, Ord, PartialOrd, Hash)]
194pub struct CanonicalBlueprintId {
195 pub address: PackageAddress,
196 pub blueprint: String,
197 pub version: BlueprintVersion,
198}
199
200#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor, Ord, PartialOrd, Hash)]
201pub struct BlueprintVersionKey {
202 pub blueprint: String,
203 pub version: BlueprintVersion,
204}
205
206impl BlueprintVersionKey {
207 pub fn new_default<S: ToString>(blueprint: S) -> Self {
208 Self {
209 blueprint: blueprint.to_string(),
210 version: BlueprintVersion::default(),
211 }
212 }
213}
214
215#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
216#[sbor(transparent)]
217pub struct BlueprintDependencies {
218 pub dependencies: IndexSet<GlobalAddress>,
219}
220
221#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
222pub struct PackageExport {
223 pub code_hash: CodeHash,
224 pub export_name: String,
225}
226
227#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
228pub struct BlueprintDefinition {
229 pub interface: BlueprintInterface,
231
232 pub function_exports: IndexMap<String, PackageExport>,
238 pub hook_exports: IndexMap<BlueprintHook, PackageExport>,
239}
240
241#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
242pub enum KeyOrValue {
243 Key,
244 Value,
245}
246
247#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
248pub enum InputOrOutput {
249 Input,
250 Output,
251}
252
253#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
254pub enum BlueprintPayloadIdentifier {
255 Function(String, InputOrOutput),
256 Event(String),
257 Field(u8),
258 KeyValueEntry(u8, KeyOrValue),
259 IndexEntry(u8, KeyOrValue),
260 SortedIndexEntry(u8, KeyOrValue),
261}
262
263#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
264pub enum BlueprintPartitionType {
265 KeyValueCollection,
266 IndexCollection,
267 SortedIndexCollection,
268}
269
270#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor, ManifestSbor)]
271pub struct BlueprintInterface {
272 pub blueprint_type: BlueprintType,
273 pub is_transient: bool,
274 pub generics: Vec<GenericBound>,
275 pub feature_set: IndexSet<String>,
276 pub state: IndexedStateSchema,
277 pub functions: IndexMap<String, FunctionSchema>,
278 pub events: IndexMap<String, BlueprintPayloadDef>,
279 pub types: IndexMap<String, ScopedTypeId>,
280}
281
282impl BlueprintInterface {
283 pub fn get_field_payload_def(&self, field_index: u8) -> Option<BlueprintPayloadDef> {
284 self.state.get_field_payload_def(field_index)
285 }
286
287 pub fn get_kv_key_payload_def(&self, collection_index: u8) -> Option<BlueprintPayloadDef> {
288 self.state.get_kv_key_payload_def(collection_index)
289 }
290
291 pub fn find_function(&self, ident: &str) -> Option<FunctionSchema> {
292 if let Some(x) = self.functions.get(ident) {
293 if x.receiver.is_none() {
294 return Some(x.clone());
295 }
296 }
297 None
298 }
299
300 pub fn find_method(&self, ident: &str) -> Option<FunctionSchema> {
301 if let Some(x) = self.functions.get(ident) {
302 if x.receiver.is_some() {
303 return Some(x.clone());
304 }
305 }
306 None
307 }
308
309 pub fn get_function_input_payload_def(&self, ident: &str) -> Option<BlueprintPayloadDef> {
310 let schema = self.functions.get(ident)?;
311 Some(schema.input.clone())
312 }
313
314 pub fn get_function_output_payload_def(&self, ident: &str) -> Option<BlueprintPayloadDef> {
315 let schema = self.functions.get(ident)?;
316 Some(schema.output.clone())
317 }
318
319 pub fn get_event_payload_def(&self, event_name: &str) -> Option<BlueprintPayloadDef> {
320 self.events.get(event_name).cloned()
321 }
322
323 pub fn get_payload_def(
324 &self,
325 payload_identifier: &BlueprintPayloadIdentifier,
326 ) -> Option<(BlueprintPayloadDef, bool, bool)> {
327 match payload_identifier {
328 BlueprintPayloadIdentifier::Function(function_ident, InputOrOutput::Input) => {
329 let payload_def = self.get_function_input_payload_def(function_ident.as_str())?;
330 Some((payload_def, true, true))
331 }
332 BlueprintPayloadIdentifier::Function(function_ident, InputOrOutput::Output) => {
333 let payload_def = self.get_function_output_payload_def(function_ident.as_str())?;
334 Some((payload_def, true, true))
335 }
336 BlueprintPayloadIdentifier::Field(field_index) => {
337 let payload_def = self.get_field_payload_def(*field_index)?;
338 Some((payload_def, true, self.is_transient))
339 }
340 BlueprintPayloadIdentifier::KeyValueEntry(collection_index, KeyOrValue::Key) => {
341 let payload_def = self.get_kv_key_payload_def(*collection_index)?;
342 Some((payload_def, false, self.is_transient))
343 }
344 BlueprintPayloadIdentifier::KeyValueEntry(collection_index, KeyOrValue::Value) => {
345 let (payload_def, allow_ownership) =
346 self.state.get_kv_value_payload_def(*collection_index)?;
347 Some((payload_def, allow_ownership, self.is_transient))
348 }
349 BlueprintPayloadIdentifier::IndexEntry(collection_index, KeyOrValue::Key) => {
350 let type_pointer = self.state.get_index_payload_def_key(*collection_index)?;
351 Some((type_pointer, false, self.is_transient))
352 }
353 BlueprintPayloadIdentifier::IndexEntry(collection_index, KeyOrValue::Value) => {
354 let type_pointer = self.state.get_index_payload_def_value(*collection_index)?;
355 Some((type_pointer, false, self.is_transient))
356 }
357 BlueprintPayloadIdentifier::SortedIndexEntry(collection_index, KeyOrValue::Key) => {
358 let type_pointer = self
359 .state
360 .get_sorted_index_payload_def_key(*collection_index)?;
361 Some((type_pointer, false, self.is_transient))
362 }
363 BlueprintPayloadIdentifier::SortedIndexEntry(collection_index, KeyOrValue::Value) => {
364 let type_pointer = self
365 .state
366 .get_sorted_index_payload_def_value(*collection_index)?;
367 Some((type_pointer, false, self.is_transient))
368 }
369 BlueprintPayloadIdentifier::Event(event_name) => {
370 let type_pointer = self.get_event_payload_def(event_name.as_str())?;
371 Some((type_pointer, false, false))
372 }
373 }
374 }
375}
376
377#[derive(Debug, Copy, Clone, PartialEq, Eq)]
378pub enum SystemInstruction {
379 MapCollectionToPhysicalPartition {
380 collection_index: u8,
381 partition_num: PartitionNumber,
382 },
383}
384
385#[derive(Debug, Copy, Clone, PartialEq, Eq, ScryptoSbor, ManifestSbor, PartialOrd, Ord, Hash)]
386pub enum PartitionDescription {
387 Logical(PartitionOffset),
388 Physical(PartitionNumber),
389}
390
391#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor, ManifestSbor)]
392pub struct IndexedStateSchema {
393 pub fields: Option<(PartitionDescription, Vec<FieldSchema<BlueprintPayloadDef>>)>,
394 pub collections: Vec<(
395 PartitionDescription,
396 BlueprintCollectionSchema<BlueprintPayloadDef>,
397 )>,
398 pub num_logical_partitions: u8,
399}
400
401impl IndexedStateSchema {
402 pub fn from_schema(
403 schema_hash: SchemaHash,
404 schema: BlueprintStateSchemaInit,
405 system_mappings: IndexMap<usize, PartitionNumber>,
406 ) -> Self {
407 let mut partition_offset = 0u8;
408
409 let mut fields = None;
410 if !schema.fields.is_empty() {
411 let schema_fields = schema
412 .fields
413 .into_iter()
414 .map(|field_schema| FieldSchema {
415 field: BlueprintPayloadDef::from_type_ref(field_schema.field, schema_hash),
416 condition: field_schema.condition,
417 transience: field_schema.transience,
418 })
419 .collect();
420 fields = Some((
421 PartitionDescription::Logical(PartitionOffset(partition_offset)),
422 schema_fields,
423 ));
424 partition_offset += 1;
425 };
426
427 let mut collections = Vec::new();
428 for (collection_index, collection_schema) in schema.collections.into_iter().enumerate() {
429 let schema = collection_schema
430 .map(|type_ref| BlueprintPayloadDef::from_type_ref(type_ref, schema_hash));
431
432 if let Some(partition_num) = system_mappings.get(&collection_index) {
433 collections.push((PartitionDescription::Physical(*partition_num), schema));
434 } else {
435 collections.push((
436 PartitionDescription::Logical(PartitionOffset(partition_offset)),
437 schema,
438 ));
439 partition_offset += 1;
440 }
441 }
442
443 Self {
444 fields,
445 collections,
446 num_logical_partitions: partition_offset,
447 }
448 }
449
450 pub fn num_logical_partitions(&self) -> u8 {
451 self.num_logical_partitions
452 }
453
454 pub fn num_fields(&self) -> usize {
455 match &self.fields {
456 Some((_, indices)) => indices.len(),
457 _ => 0usize,
458 }
459 }
460
461 pub fn get_partition(
462 &self,
463 collection_index: u8,
464 ) -> Option<(PartitionDescription, BlueprintPartitionType)> {
465 self.collections
466 .get(collection_index as usize)
467 .map(|(partition, schema)| {
468 let partition_type = match schema {
469 BlueprintCollectionSchema::KeyValueStore(..) => {
470 BlueprintPartitionType::KeyValueCollection
471 }
472 BlueprintCollectionSchema::Index(..) => BlueprintPartitionType::IndexCollection,
473 BlueprintCollectionSchema::SortedIndex(..) => {
474 BlueprintPartitionType::SortedIndexCollection
475 }
476 };
477 (*partition, partition_type)
478 })
479 }
480
481 pub fn get_field_payload_def(&self, field_index: u8) -> Option<BlueprintPayloadDef> {
482 let (_partition, fields) = self.fields.clone()?;
483 let field_schema = fields.get(field_index.clone() as usize)?;
484 Some(field_schema.field.clone())
485 }
486
487 pub fn get_kv_key_payload_def(&self, collection_index: u8) -> Option<BlueprintPayloadDef> {
488 let (_partition, schema) = self.collections.get(collection_index.clone() as usize)?;
489 match schema {
490 BlueprintCollectionSchema::KeyValueStore(key_value_store) => {
491 Some(key_value_store.key.clone())
492 }
493 _ => None,
494 }
495 }
496
497 pub fn get_kv_value_payload_def(
498 &self,
499 collection_index: u8,
500 ) -> Option<(BlueprintPayloadDef, bool)> {
501 let (_partition, schema) = self.collections.get(collection_index.clone() as usize)?;
502 match schema {
503 BlueprintCollectionSchema::KeyValueStore(key_value_store) => Some((
504 key_value_store.value.clone(),
505 key_value_store.allow_ownership,
506 )),
507 _ => None,
508 }
509 }
510
511 pub fn get_index_payload_def_key(&self, collection_index: u8) -> Option<BlueprintPayloadDef> {
512 let (_partition, schema) = self.collections.get(collection_index.clone() as usize)?;
513 match schema {
514 BlueprintCollectionSchema::Index(index) => Some(index.key.clone()),
515 _ => None,
516 }
517 }
518
519 pub fn get_index_payload_def_value(&self, collection_index: u8) -> Option<BlueprintPayloadDef> {
520 let (_partition, schema) = self.collections.get(collection_index.clone() as usize)?;
521 match schema {
522 BlueprintCollectionSchema::Index(index) => Some(index.value.clone()),
523 _ => None,
524 }
525 }
526
527 pub fn get_sorted_index_payload_def_key(
528 &self,
529 collection_index: u8,
530 ) -> Option<BlueprintPayloadDef> {
531 let (_partition, schema) = self.collections.get(collection_index.clone() as usize)?;
532 match schema {
533 BlueprintCollectionSchema::SortedIndex(index) => Some(index.key.clone()),
534 _ => None,
535 }
536 }
537
538 pub fn get_sorted_index_payload_def_value(
539 &self,
540 collection_index: u8,
541 ) -> Option<BlueprintPayloadDef> {
542 let (_partition, schema) = self.collections.get(collection_index.clone() as usize)?;
543 match schema {
544 BlueprintCollectionSchema::SortedIndex(index) => Some(index.value.clone()),
545 _ => None,
546 }
547 }
548
549 pub fn fields_partition(&self) -> Option<PartitionDescription> {
550 match &self.fields {
551 Some((partition, ..)) => Some(partition.clone()),
552 _ => None,
553 }
554 }
555
556 pub fn field(
557 &self,
558 field_index: u8,
559 ) -> Option<(PartitionDescription, FieldSchema<BlueprintPayloadDef>)> {
560 match &self.fields {
561 Some((partition, fields)) => {
562 let field_index: usize = field_index.into();
563 fields
564 .get(field_index)
565 .cloned()
566 .map(|f| (partition.clone(), f))
567 }
568 _ => None,
569 }
570 }
571}