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)
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)
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 as usize)?;
484 Some(field_schema.field)
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 as usize)?;
489 match schema {
490 BlueprintCollectionSchema::KeyValueStore(key_value_store) => Some(key_value_store.key),
491 _ => None,
492 }
493 }
494
495 pub fn get_kv_value_payload_def(
496 &self,
497 collection_index: u8,
498 ) -> Option<(BlueprintPayloadDef, bool)> {
499 let (_partition, schema) = self.collections.get(collection_index as usize)?;
500 match schema {
501 BlueprintCollectionSchema::KeyValueStore(key_value_store) => {
502 Some((key_value_store.value, key_value_store.allow_ownership))
503 }
504 _ => None,
505 }
506 }
507
508 pub fn get_index_payload_def_key(&self, collection_index: u8) -> Option<BlueprintPayloadDef> {
509 let (_partition, schema) = self.collections.get(collection_index as usize)?;
510 match schema {
511 BlueprintCollectionSchema::Index(index) => Some(index.key),
512 _ => None,
513 }
514 }
515
516 pub fn get_index_payload_def_value(&self, collection_index: u8) -> Option<BlueprintPayloadDef> {
517 let (_partition, schema) = self.collections.get(collection_index as usize)?;
518 match schema {
519 BlueprintCollectionSchema::Index(index) => Some(index.value),
520 _ => None,
521 }
522 }
523
524 pub fn get_sorted_index_payload_def_key(
525 &self,
526 collection_index: u8,
527 ) -> Option<BlueprintPayloadDef> {
528 let (_partition, schema) = self.collections.get(collection_index as usize)?;
529 match schema {
530 BlueprintCollectionSchema::SortedIndex(index) => Some(index.key),
531 _ => None,
532 }
533 }
534
535 pub fn get_sorted_index_payload_def_value(
536 &self,
537 collection_index: u8,
538 ) -> Option<BlueprintPayloadDef> {
539 let (_partition, schema) = self.collections.get(collection_index as usize)?;
540 match schema {
541 BlueprintCollectionSchema::SortedIndex(index) => Some(index.value),
542 _ => None,
543 }
544 }
545
546 pub fn fields_partition(&self) -> Option<PartitionDescription> {
547 match &self.fields {
548 Some((partition, ..)) => Some(*partition),
549 _ => None,
550 }
551 }
552
553 pub fn field(
554 &self,
555 field_index: u8,
556 ) -> Option<(PartitionDescription, FieldSchema<BlueprintPayloadDef>)> {
557 match &self.fields {
558 Some((partition, fields)) => {
559 let field_index: usize = field_index.into();
560 fields.get(field_index).cloned().map(|f| (*partition, f))
561 }
562 _ => None,
563 }
564 }
565}