radix_engine/system/
bootstrap.rs

1use crate::blueprints::account::AccountOwnerBadgeData;
2use crate::blueprints::identity::IdentityOwnerBadgeData;
3use crate::blueprints::native_schema::*;
4use crate::blueprints::package::*;
5use crate::blueprints::transaction_tracker::*;
6use crate::internal_prelude::*;
7use crate::system::system_db_reader::SystemDatabaseReader;
8use crate::transaction::*;
9use crate::updates::*;
10use crate::vm::VmBoot;
11use lazy_static::lazy_static;
12use radix_common::crypto::Secp256k1PublicKey;
13use radix_common::math::traits::*;
14use radix_common::types::ComponentAddress;
15use radix_engine_interface::blueprints::consensus_manager::*;
16use radix_engine_interface::blueprints::package::*;
17use radix_engine_interface::blueprints::resource::*;
18use radix_engine_interface::blueprints::transaction_tracker::*;
19use radix_engine_interface::object_modules::metadata::{MetadataValue, UncheckedUrl};
20use radix_engine_interface::object_modules::ModuleConfig;
21use radix_engine_interface::*;
22use radix_substate_store_interface::interface::*;
23use radix_transactions::model::*;
24use radix_transactions::prelude::*;
25
26lazy_static! {
27    pub static ref DEFAULT_TESTING_FAUCET_SUPPLY: Decimal = dec!("100000000000000000");
28    pub static ref DEFAULT_VALIDATOR_USD_COST: Decimal = dec!("100");
29    pub static ref DEFAULT_VALIDATOR_XRD_COST: Decimal = DEFAULT_VALIDATOR_USD_COST
30        .checked_mul(Decimal::try_from(USD_PRICE_IN_XRD).unwrap())
31        .unwrap();  // NOTE: Decimal arithmetic operation safe unwrap.
32                    // No chance to overflow.
33                    // The chance to overflow will be decreasing over time since USD price in XRD will only get lower ;)
34}
35
36//==========================================================================================
37// GENESIS CHUNK MODELS
38// - These are used by the node (and in Java) so they need to implement ScryptoEncode so
39//   that they can go over the JNI boundary
40// - The models which use ManifestSbor are also included in the transaction itself, and must
41//   match the corresponding models in the `genesis_helper` component
42//==========================================================================================
43
44#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor, ManifestEncode, ManifestCategorize)]
45pub struct GenesisValidator {
46    pub key: Secp256k1PublicKey,
47    pub accept_delegated_stake: bool,
48    pub is_registered: bool,
49    pub fee_factor: Decimal,
50    pub metadata: Vec<(String, MetadataValue)>,
51    pub owner: ComponentAddress,
52}
53
54impl From<Secp256k1PublicKey> for GenesisValidator {
55    fn from(key: Secp256k1PublicKey) -> Self {
56        // Re-using the validator key for its owner
57        let default_owner_address = ComponentAddress::preallocated_account_from_public_key(&key);
58        GenesisValidator {
59            key,
60            accept_delegated_stake: true,
61            is_registered: true,
62            fee_factor: Decimal::ONE,
63            metadata: vec![(
64                "url".to_string(),
65                MetadataValue::Url(UncheckedUrl::of(format!(
66                    "http://test.local?validator={:?}",
67                    key
68                ))),
69            )],
70            owner: default_owner_address,
71        }
72    }
73}
74
75#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoSbor)]
76pub struct GenesisStakeAllocation {
77    pub account_index: u32,
78    pub xrd_amount: Decimal,
79}
80
81// Note - this gets mapped into the ManifestGenesisResource by replacing the reservation
82#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor)]
83pub struct GenesisResource {
84    pub reserved_resource_address: ResourceAddress,
85    pub metadata: Vec<(String, MetadataValue)>,
86    pub owner: Option<ComponentAddress>,
87}
88
89#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoSbor)]
90pub struct GenesisResourceAllocation {
91    pub account_index: u32,
92    pub amount: Decimal,
93}
94
95// Note - this gets mapped into the ManifestGenesisResource for inclusion in the transaction
96#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor)]
97pub enum GenesisDataChunk {
98    Validators(Vec<GenesisValidator>),
99    Stakes {
100        accounts: Vec<ComponentAddress>,
101        allocations: Vec<(Secp256k1PublicKey, Vec<GenesisStakeAllocation>)>,
102    },
103    Resources(Vec<GenesisResource>),
104    ResourceBalances {
105        accounts: Vec<ComponentAddress>,
106        allocations: Vec<(ResourceAddress, Vec<GenesisResourceAllocation>)>,
107    },
108    XrdBalances(Vec<(ComponentAddress, Decimal)>),
109}
110
111//==========================================================================================
112// MANIFEST-SPECIFIC GENESIS CHUNK MODELS
113// - These must match the corresponding models in the `genesis_helper` component
114//==========================================================================================
115
116#[derive(Debug, Clone, Eq, PartialEq, ManifestEncode, ManifestCategorize)]
117pub enum ManifestGenesisDataChunk {
118    Validators(Vec<GenesisValidator>),
119    Stakes {
120        accounts: Vec<ComponentAddress>,
121        allocations: Vec<(Secp256k1PublicKey, Vec<GenesisStakeAllocation>)>,
122    },
123    Resources(Vec<ManifestGenesisResource>),
124    ResourceBalances {
125        accounts: Vec<ComponentAddress>,
126        allocations: Vec<(ResourceAddress, Vec<GenesisResourceAllocation>)>,
127    },
128    XrdBalances(Vec<(ComponentAddress, Decimal)>),
129}
130
131#[derive(Debug, Clone, Eq, PartialEq, ManifestEncode, ManifestCategorize)]
132pub struct ManifestGenesisResource {
133    pub resource_address_reservation: ManifestAddressReservation,
134    pub metadata: Vec<(String, MetadataValue)>,
135    pub owner: Option<ComponentAddress>,
136}
137
138//==========================================================================================
139// BOOTSTRAPPER
140// Various helper utilities for constructing and executing genesis
141//==========================================================================================
142
143#[derive(Debug, Clone)]
144pub struct GenesisReceipts {
145    pub system_flash_receipt: TransactionReceipt,
146    pub system_bootstrap_receipt: TransactionReceipt,
147    pub data_ingestion_receipts: Vec<TransactionReceipt>,
148    pub wrap_up_receipt: TransactionReceipt,
149}
150
151#[derive(Default)]
152pub struct GenesisReceiptExtractionHooks {
153    bootstrap_receipts: Vec<TransactionReceipt>,
154    data_ingestion_receipts: Vec<TransactionReceipt>,
155    wrap_up_receipts: Vec<TransactionReceipt>,
156}
157
158impl GenesisReceiptExtractionHooks {
159    pub fn new() -> Self {
160        Default::default()
161    }
162
163    pub fn into_genesis_receipts(self) -> GenesisReceipts {
164        let [system_flash_receipt, system_bootstrap_receipt] = self
165            .bootstrap_receipts
166            .try_into()
167            .expect("Expected two bootstrap receipts (flash and transaction)");
168        let [wrap_up_receipt] = self
169            .wrap_up_receipts
170            .try_into()
171            .expect("Expected one wrap-up receipt");
172        GenesisReceipts {
173            system_flash_receipt,
174            system_bootstrap_receipt,
175            data_ingestion_receipts: self.data_ingestion_receipts,
176            wrap_up_receipt,
177        }
178    }
179}
180
181impl ProtocolUpdateExecutionHooks for GenesisReceiptExtractionHooks {
182    fn on_transaction_executed(&mut self, event: OnProtocolTransactionExecuted) {
183        let OnProtocolTransactionExecuted {
184            protocol_version,
185            batch_group_index,
186            receipt,
187            ..
188        } = event;
189        if protocol_version == ProtocolVersion::GENESIS {
190            match batch_group_index {
191                0 => self.bootstrap_receipts.push(receipt.clone()),
192                1 => self.data_ingestion_receipts.push(receipt.clone()),
193                2 => self.wrap_up_receipts.push(receipt.clone()),
194                _ => panic!("Unexpected bootstrap batch group index: {batch_group_index}"),
195            }
196        }
197    }
198}
199
200#[derive(Debug, Clone, ScryptoSbor)]
201pub struct FlashReceipt {
202    pub state_updates: StateUpdates,
203    pub state_update_summary: StateUpdateSummary,
204    pub substate_system_structures: SubstateSystemStructures,
205}
206
207impl From<FlashReceipt> for TransactionReceipt {
208    fn from(value: FlashReceipt) -> Self {
209        // This is used by the node for allowing the flash to execute before the
210        // genesis bootstrap transaction
211        let mut commit_result =
212            CommitResult::empty_with_outcome(TransactionOutcome::Success(vec![]));
213        commit_result.state_updates = value.state_updates;
214        commit_result.state_update_summary = value.state_update_summary;
215        commit_result.system_structure.substate_system_structures =
216            value.substate_system_structures;
217        TransactionReceipt::empty_with_commit(commit_result)
218    }
219}
220
221impl FlashReceipt {
222    pub fn from_state_updates(
223        state_updates: StateUpdates,
224        before_store: &impl SubstateDatabase,
225    ) -> Self {
226        let state_updates = state_updates.rebuild_without_empty_entries();
227        let state_update_summary =
228            StateUpdateSummary::new_from_state_updates_on_db(before_store, &state_updates);
229        let substate_system_structures = {
230            let after_store = SystemDatabaseReader::new_with_overlay(before_store, &state_updates);
231            let mut substate_schema_mapper = SubstateSchemaMapper::new(after_store);
232            substate_schema_mapper.add_for_all_individually_updated(&state_updates);
233            substate_schema_mapper.done()
234        };
235        Self {
236            state_updates,
237            state_update_summary,
238            substate_system_structures,
239        }
240    }
241}
242
243pub fn create_system_bootstrap_flash_state_updates() -> StateUpdates {
244    // The slightly weird order is so that it matches the historic order when this
245    // used to be ordered by a BTreeMap over the node ids.
246    let package_flashes = [
247        (
248            PACKAGE_PACKAGE,
249            PACKAGE_PACKAGE_DEFINITION.clone(),
250            NativeCodeId::PackageCode1 as u64,
251            metadata_init! {
252                "name" => "Package Package".to_owned(), locked;
253                "description" => "A native package that is called to create a new package on the network.".to_owned(), locked;
254            },
255            // Maps the application layer schema collection index to the system layer schema partition
256            btreemap! {
257                PACKAGE_BLUEPRINT.to_string() => vec![SystemInstruction::MapCollectionToPhysicalPartition {
258                    collection_index: PackageCollection::SchemaKeyValue.collection_index(),
259                    partition_num: SCHEMAS_PARTITION,
260                }],
261            },
262        ),
263        (
264            ROYALTY_MODULE_PACKAGE,
265            ROYALTY_PACKAGE_DEFINITION.clone(),
266            NativeCodeId::RoyaltyCode1 as u64,
267            metadata_init! {
268                "name" => "Royalty Package".to_owned(), locked;
269                "description" => "A native package that defines the logic of the royalty module used by components.".to_owned(), locked;
270            },
271            btreemap!(),
272        ),
273        (
274            RESOURCE_PACKAGE,
275            RESOURCE_PACKAGE_DEFINITION.clone(),
276            NativeCodeId::ResourceCode1 as u64,
277            metadata_init! {
278                "name" => "Resource Package".to_owned(), locked;
279                "description" => "A native package that is called to create a new resource manager on the network.".to_owned(), locked;
280            },
281            btreemap!(),
282        ),
283        (
284            TRANSACTION_PROCESSOR_PACKAGE,
285            TRANSACTION_PROCESSOR_PACKAGE_DEFINITION.clone(),
286            NativeCodeId::TransactionProcessorCode1 as u64,
287            metadata_init! {
288                "name" => "Transaction Processor Package".to_owned(), locked;
289                "description" => "A native package that defines the logic of the processing of manifest instructions and transaction runtime.".to_owned(), locked;
290            },
291            btreemap!(),
292        ),
293        (
294            METADATA_MODULE_PACKAGE,
295            METADATA_PACKAGE_DEFINITION.clone(),
296            NativeCodeId::MetadataCode1 as u64,
297            metadata_init! {
298                "name" => "Metadata Package".to_owned(), locked;
299                "description" => "A native package that defines the logic of the metadata module that is used by resources, components, and packages.".to_owned(), locked;
300            },
301            btreemap!(),
302        ),
303        (
304            ROLE_ASSIGNMENT_MODULE_PACKAGE,
305            ROLE_ASSIGNMENT_PACKAGE_DEFINITION.clone(),
306            NativeCodeId::RoleAssignmentCode1 as u64,
307            metadata_init! {
308                "name" => "Access Rules Package".to_owned(), locked;
309                "description" => "A native package that defines the logic of the access rules module that is used by resources, components, and packages.".to_owned(), locked;
310            },
311            btreemap!(),
312        ),
313        (
314            TEST_UTILS_PACKAGE,
315            TEST_UTILS_PACKAGE_DEFINITION.clone(),
316            NativeCodeId::TestUtilsCode1 as u64,
317            metadata_init! {
318                "name" => "Test Utils Package".to_owned(), locked;
319                "description" => "A native package that contains a set of useful functions to use in testing.".to_owned(), locked;
320            },
321            btreemap!(),
322        ),
323    ];
324
325    let mut to_flash = StateUpdates::empty();
326
327    for (address, definition, native_code_id, metadata_init, system_instructions) in package_flashes
328    {
329        let partitions = {
330            let package_structure = PackageNativePackage::validate_and_build_package_structure(
331                definition,
332                VmType::Native,
333                native_code_id.to_be_bytes().to_vec(),
334                system_instructions,
335                false,
336                &VmBoot::babylon_genesis(),
337            )
338            .unwrap_or_else(|err| {
339                panic!(
340                    "Invalid flashed Package definition with native_code_id {}: {:?}",
341                    native_code_id, err
342                )
343            });
344
345            create_package_partition_substates(package_structure, metadata_init, None)
346        };
347
348        for (partition_num, partition_substates) in partitions {
349            let partition_updates: IndexMap<_, _> = partition_substates
350                .into_iter()
351                .map(|(key, value)| (key, DatabaseUpdate::Set(value.into())))
352                .collect();
353
354            // To avoid creating wasted structure in StateUpdates, only create this partition if a change exists.
355            if !partition_updates.is_empty() {
356                to_flash
357                    .of_node(address)
358                    .of_partition(partition_num)
359                    .mut_update_substates(partition_updates);
360            }
361        }
362    }
363
364    to_flash
365}
366
367pub fn create_substate_flash_for_genesis() -> FlashReceipt {
368    let state_updates = create_system_bootstrap_flash_state_updates();
369    FlashReceipt::from_state_updates(state_updates, &EmptySubstateDatabase)
370}
371
372struct EmptySubstateDatabase;
373
374impl SubstateDatabase for EmptySubstateDatabase {
375    fn get_raw_substate_by_db_key(
376        &self,
377        _partition_key: &DbPartitionKey,
378        _sort_key: &DbSortKey,
379    ) -> Option<DbSubstateValue> {
380        None
381    }
382
383    fn list_raw_values_from_db_key(
384        &self,
385        _partition_key: &DbPartitionKey,
386        _from_sort_key: Option<&DbSortKey>,
387    ) -> Box<dyn Iterator<Item = PartitionEntry> + '_> {
388        Box::new(core::iter::empty())
389    }
390}
391
392pub fn create_system_bootstrap_transaction(
393    initial_epoch: Epoch,
394    initial_config: ConsensusManagerConfig,
395    initial_time_ms: i64,
396    initial_current_leader: Option<ValidatorIndex>,
397    faucet_supply: Decimal,
398) -> SystemTransactionV1 {
399    let mut manifest_builder = ManifestBuilder::new_system_v1();
400    let lookup = manifest_builder.name_lookup();
401
402    // XRD Token
403    {
404        let xrd_reservation = manifest_builder.use_preallocated_address(
405            XRD,
406            RESOURCE_PACKAGE,
407            FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
408        );
409        manifest_builder = manifest_builder.call_function(
410            RESOURCE_PACKAGE,
411            FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
412            FUNGIBLE_RESOURCE_MANAGER_CREATE_WITH_INITIAL_SUPPLY_IDENT,
413            FungibleResourceManagerCreateWithInitialSupplyManifestInput {
414                owner_role: OwnerRole::Fixed(rule!(require(system_execution(SystemExecution::Protocol)))).into(),
415                track_total_supply: false,
416                divisibility: 18,
417                resource_roles: FungibleResourceRoles {
418                    mint_roles: mint_roles! {
419                        minter => rule!(require(global_caller(CONSENSUS_MANAGER)));
420                        minter_updater => rule!(deny_all);
421                    },
422                    burn_roles: burn_roles! {
423                        burner => rule!(require(global_caller(CONSENSUS_MANAGER)));
424                        burner_updater => rule!(deny_all);
425                    },
426                    ..Default::default()
427                }.into(),
428                metadata: metadata! {
429                    init {
430                        "symbol" => "XRD".to_owned(), locked;
431                        "name" => "Radix".to_owned(), locked;
432                        "description" => "The Radix Public Network's native token, used to pay the network's required transaction fees and to secure the network through staking to its validator nodes.".to_owned(), locked;
433                        "icon_url" => UncheckedUrl::of("https://assets.radixdlt.com/icons/icon-xrd-32x32.png"), locked;
434                        "info_url" => UncheckedUrl::of("https://tokens.radixdlt.com"), locked;
435                        "tags" => Vec::<String>::new(), locked;
436                    }
437                }.into(),
438                initial_supply: Decimal::zero(),
439                address_reservation: Some(xrd_reservation),
440            },
441        );
442    }
443
444    // Package of Direct Caller
445    {
446        let reservation = manifest_builder.use_preallocated_address(
447            PACKAGE_OF_DIRECT_CALLER_RESOURCE,
448            RESOURCE_PACKAGE,
449            NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
450        );
451        manifest_builder = manifest_builder.call_function(
452            RESOURCE_PACKAGE,
453            NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
454            NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_IDENT,
455            NonFungibleResourceManagerCreateManifestInput {
456                owner_role: OwnerRole::Fixed(rule!(require(system_execution(SystemExecution::Protocol)))).into(),
457                id_type: NonFungibleIdType::Bytes,
458                track_total_supply: false,
459                non_fungible_schema: NonFungibleDataSchema::new_local_without_self_package_replacement::<()>(),
460                resource_roles: NonFungibleResourceRoles {
461                    withdraw_roles: withdraw_roles! {
462                        withdrawer => rule!(deny_all);
463                        withdrawer_updater => rule!(deny_all);
464                    },
465                    ..Default::default()
466                }.into(),
467                metadata: metadata! {
468                    init {
469                        "name" => "Package Virtual Badges".to_owned(), locked;
470                        "description" => "Virtual badges generated automatically by the Radix system to represent the authority of the package for a direct caller. These badges cease to exist at the end of their transaction.".to_owned(), locked;
471                        "tags" => vec!["badge".to_owned()], locked;
472                        "icon_url" => UncheckedUrl::of("https://assets.radixdlt.com/icons/icon-package_of_direct_caller_virtual_badge.png"), locked;
473                    }
474                }
475                .into(),
476                address_reservation: Some(reservation),
477            },
478        );
479    }
480
481    // Global Caller Resource
482    {
483        let reservation = manifest_builder.use_preallocated_address(
484            GLOBAL_CALLER_RESOURCE,
485            RESOURCE_PACKAGE,
486            NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
487        );
488        manifest_builder = manifest_builder.call_function(
489            RESOURCE_PACKAGE,
490            NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
491            NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_IDENT,
492            NonFungibleResourceManagerCreateManifestInput {
493                owner_role: OwnerRole::Fixed(rule!(require(system_execution(SystemExecution::Protocol)))).into(),
494                id_type: NonFungibleIdType::Bytes,
495                track_total_supply: false,
496                non_fungible_schema: NonFungibleDataSchema::new_local_without_self_package_replacement::<()>(),
497                resource_roles: NonFungibleResourceRoles {
498                    withdraw_roles: withdraw_roles! {
499                        withdrawer => rule!(deny_all);
500                        withdrawer_updater => rule!(deny_all);
501                    },
502                    ..Default::default()
503                }.into(),
504                metadata: metadata! {
505                    init {
506                        "name" => "Global Caller Virtual Badges".to_owned(), locked;
507                        "description" => "Virtual badges generated automatically by the Radix system to represent the authority of a global caller. These badges cease to exist at the end of their transaction.".to_owned(), locked;
508                        "tags" => vec!["badge".to_owned()], locked;
509                        "icon_url" => UncheckedUrl::of("https://assets.radixdlt.com/icons/icon-global_caller_virtual_badge.png"), locked;
510                    }
511                }.into(),
512                address_reservation: Some(reservation),
513            },
514        );
515    }
516
517    // Package Owner Resource
518    {
519        let reservation = manifest_builder.use_preallocated_address(
520            PACKAGE_OWNER_BADGE,
521            RESOURCE_PACKAGE,
522            NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
523        );
524        manifest_builder = manifest_builder.call_function(
525            RESOURCE_PACKAGE,
526            NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
527            NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_IDENT,
528            NonFungibleResourceManagerCreateManifestInput {
529                owner_role: OwnerRole::Fixed(rule!(require(global_caller(PACKAGE_PACKAGE)))).into(),
530                id_type: NonFungibleIdType::Bytes,
531                track_total_supply: false,
532                non_fungible_schema: NonFungibleDataSchema::new_local_without_self_package_replacement::<PackageOwnerBadgeData>(),
533                resource_roles: NonFungibleResourceRoles {
534                    mint_roles: mint_roles! {
535                        minter => rule!(require(package_of_direct_caller(PACKAGE_PACKAGE)));
536                        minter_updater => rule!(deny_all);
537                    },
538                    ..Default::default()
539                }.into(),
540                metadata: metadata! {
541                    init {
542                        "name" => "Package Owner Badges".to_owned(), locked;
543                        "description" => "Badges created by the Radix system that provide individual control over blueprint packages deployed by developers.".to_owned(), locked;
544                        "tags" => vec!["badge".to_owned(), "package".to_owned()], locked;
545                        "icon_url" => UncheckedUrl::of("https://assets.radixdlt.com/icons/icon-package_owner_badge.png"), locked;
546                    }
547                }.into(),
548                address_reservation: Some(reservation),
549            },
550        );
551    }
552
553    // Identity
554    {
555        let badge_reservation = manifest_builder.use_preallocated_address(
556            IDENTITY_OWNER_BADGE,
557            RESOURCE_PACKAGE,
558            NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
559        );
560        manifest_builder = manifest_builder.call_function(
561            RESOURCE_PACKAGE,
562            NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
563            NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_IDENT,
564            NonFungibleResourceManagerCreateManifestInput {
565                owner_role: OwnerRole::Fixed(rule!(require(global_caller(IDENTITY_PACKAGE)))).into(),
566                id_type: NonFungibleIdType::Bytes,
567                track_total_supply: false,
568                non_fungible_schema: NonFungibleDataSchema::new_local_without_self_package_replacement::<IdentityOwnerBadgeData>(),
569                resource_roles: NonFungibleResourceRoles {
570                    mint_roles: mint_roles! {
571                        minter => rule!(require(package_of_direct_caller(IDENTITY_PACKAGE)));
572                        minter_updater => rule!(deny_all);
573                    },
574                    ..Default::default()
575                }.into(),
576                metadata: metadata! {
577                    init {
578                        "name" => "Identity Owner Badges".to_owned(), locked;
579                        "description" => "Badges created by the Radix system that provide individual control over identity components.".to_owned(), locked;
580                        "tags" => vec!["badge".to_owned(), "identity".to_owned()], locked;
581                        "icon_url" => UncheckedUrl::of("https://assets.radixdlt.com/icons/icon-identity_owner_badge.png"), locked;
582                    }
583                }.into(),
584                address_reservation: Some(badge_reservation),
585            },
586        );
587
588        let package_reservation = manifest_builder.use_preallocated_address(
589            IDENTITY_PACKAGE,
590            PACKAGE_PACKAGE,
591            PACKAGE_BLUEPRINT,
592        );
593        manifest_builder = manifest_builder.call_function(
594            PACKAGE_PACKAGE,
595            PACKAGE_BLUEPRINT,
596            PACKAGE_PUBLISH_NATIVE_IDENT,
597            PackagePublishNativeManifestInput {
598                package_address: Some(package_reservation),
599                definition: IDENTITY_PACKAGE_DEFINITION.clone().into(),
600                native_package_code_id: NativeCodeId::IdentityCode1 as u64,
601                metadata: metadata_init! {
602                    "name" => "Identity Package".to_owned(), locked;
603                    "description" => "A native package that defines the logic of identity components.".to_owned(), locked;
604                }.into(),
605            },
606        );
607    }
608
609    // ConsensusManager Package
610    {
611        let reservation = manifest_builder.use_preallocated_address(
612            CONSENSUS_MANAGER_PACKAGE,
613            PACKAGE_PACKAGE,
614            PACKAGE_BLUEPRINT,
615        );
616        manifest_builder = manifest_builder.call_function(
617            PACKAGE_PACKAGE,
618            PACKAGE_BLUEPRINT,
619            PACKAGE_PUBLISH_NATIVE_IDENT,
620            PackagePublishNativeManifestInput {
621                package_address: Some(reservation),
622                definition: CONSENSUS_MANAGER_PACKAGE_DEFINITION.clone().into(),
623                native_package_code_id: NativeCodeId::ConsensusManagerCode1 as u64,
624                metadata: metadata_init! {
625                    "name" => "Consensus Manager Package".to_owned(), locked;
626                    "description" => "A native package that may be used to get network consensus information.".to_owned(), locked;
627                }.into(),
628            },
629        );
630    }
631
632    // Account Package
633    {
634        let badge_reservation = manifest_builder.use_preallocated_address(
635            ACCOUNT_OWNER_BADGE,
636            RESOURCE_PACKAGE,
637            NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
638        );
639        manifest_builder = manifest_builder.call_function(
640            RESOURCE_PACKAGE,
641            NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
642            NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_IDENT,
643            NonFungibleResourceManagerCreateManifestInput {
644                owner_role: OwnerRole::Fixed(rule!(require(global_caller(ACCOUNT_PACKAGE)))).into(),
645                id_type: NonFungibleIdType::Bytes,
646                track_total_supply: false,
647                non_fungible_schema: NonFungibleDataSchema::new_local_without_self_package_replacement::<AccountOwnerBadgeData>(),
648                resource_roles: NonFungibleResourceRoles {
649                    mint_roles: mint_roles! {
650                        minter => rule!(require(package_of_direct_caller(ACCOUNT_PACKAGE)));
651                        minter_updater => rule!(deny_all);
652                    },
653                    ..Default::default()
654                }.into(),
655                metadata: metadata! {
656                    init {
657                        "name" => "Account Owner Badges".to_owned(), locked;
658                        "description" => "Badges created by the Radix system that provide individual control over account components.".to_owned(), locked;
659                        "tags" => vec![
660                            "badge".to_owned(),
661                            "account".to_owned(),
662                        ], locked;
663                        "icon_url" => UncheckedUrl::of("https://assets.radixdlt.com/icons/icon-account_owner_badge.png"), locked;
664                    }
665                }.into(),
666                address_reservation: Some(badge_reservation),
667            },
668        );
669
670        let package_reservation = manifest_builder.use_preallocated_address(
671            ACCOUNT_PACKAGE,
672            PACKAGE_PACKAGE,
673            PACKAGE_BLUEPRINT,
674        );
675        manifest_builder = manifest_builder.call_function(
676            PACKAGE_PACKAGE,
677            PACKAGE_BLUEPRINT,
678            PACKAGE_PUBLISH_NATIVE_IDENT,
679            PackagePublishNativeManifestInput {
680                package_address: Some(package_reservation),
681                definition: ACCOUNT_PACKAGE_DEFINITION.clone().into(),
682                native_package_code_id: NativeCodeId::AccountCode1 as u64,
683                metadata: metadata_init! {
684                    "name" => "Account Package".to_owned(), locked;
685                    "description" => "A native package that defines the logic of account components.".to_owned(), locked;
686                }.into(),
687            },
688        );
689    }
690
691    // AccessController Package
692    {
693        let reservation = manifest_builder.use_preallocated_address(
694            ACCESS_CONTROLLER_PACKAGE,
695            PACKAGE_PACKAGE,
696            PACKAGE_BLUEPRINT,
697        );
698        manifest_builder = manifest_builder.call_function(
699            PACKAGE_PACKAGE,
700            PACKAGE_BLUEPRINT,
701            PACKAGE_PUBLISH_NATIVE_IDENT,
702            PackagePublishNativeManifestInput {
703                package_address: Some(reservation),
704                definition: ACCESS_CONTROLLER_PACKAGE_DEFINITION_V1_0.clone().into(),
705                metadata: metadata_init! {
706                    "name" => "Access Controller Package".to_owned(), locked;
707                    "description" => "A native package that defines the logic of access controller components.".to_owned(), locked;
708                }.into(),
709                native_package_code_id: NativeCodeId::AccessControllerCode1 as u64,
710            },
711        );
712    }
713
714    // Pool Package
715    {
716        let reservation = manifest_builder.use_preallocated_address(
717            POOL_PACKAGE,
718            PACKAGE_PACKAGE,
719            PACKAGE_BLUEPRINT,
720        );
721        manifest_builder = manifest_builder.call_function(
722            PACKAGE_PACKAGE,
723            PACKAGE_BLUEPRINT,
724            PACKAGE_PUBLISH_NATIVE_IDENT,
725            PackagePublishNativeManifestInput {
726                package_address: Some(reservation),
727                definition: POOL_PACKAGE_DEFINITION_V1_0.clone().into(),
728                metadata: metadata_init! {
729                    "name" => "Pool Package".to_owned(), locked;
730                    "description" => "A native package that defines the logic for a selection of pool components.".to_owned(), locked;
731                }.into(),
732                native_package_code_id: NativeCodeId::PoolCode1 as u64,
733            },
734        );
735    }
736
737    // ECDSA Secp256k1
738    {
739        let reservation = manifest_builder.use_preallocated_address(
740            SECP256K1_SIGNATURE_RESOURCE,
741            RESOURCE_PACKAGE,
742            NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
743        );
744        manifest_builder = manifest_builder.call_function(
745            RESOURCE_PACKAGE,
746            NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
747            NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_IDENT,
748            NonFungibleResourceManagerCreateManifestInput {
749                owner_role: OwnerRole::Fixed(rule!(require(system_execution(SystemExecution::Protocol)))).into(),
750                id_type: NonFungibleIdType::Bytes,
751                track_total_supply: false,
752                non_fungible_schema: NonFungibleDataSchema::new_local_without_self_package_replacement::<()>(),
753                resource_roles: NonFungibleResourceRoles::default().into(),
754                metadata: metadata! {
755                    init {
756                        "name" => "ECDSA secp256k1 Virtual Badges".to_owned(), locked;
757                        "description" => "Virtual badges generated automatically by the Radix system to represent ECDSA secp256k1 signatures applied to transactions. These badges cease to exist at the end of their transaction.".to_owned(), locked;
758                        "tags" => vec!["badge".to_owned()], locked;
759                        "icon_url" => UncheckedUrl::of("https://assets.radixdlt.com/icons/icon-ecdsa_secp256k1_signature_virtual_badge.png"), locked;
760                    }
761                }.into(),
762                address_reservation: Some(reservation),
763            }
764        );
765    }
766
767    // Ed25519
768    {
769        let reservation = manifest_builder.use_preallocated_address(
770            ED25519_SIGNATURE_RESOURCE,
771            RESOURCE_PACKAGE,
772            NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
773        );
774        manifest_builder = manifest_builder.call_function(
775            RESOURCE_PACKAGE,
776            NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
777            NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_IDENT,
778            NonFungibleResourceManagerCreateManifestInput {
779                owner_role: OwnerRole::Fixed(rule!(require(system_execution(SystemExecution::Protocol)))).into(),
780                id_type: NonFungibleIdType::Bytes,
781                track_total_supply: false,
782                non_fungible_schema: NonFungibleDataSchema::new_local_without_self_package_replacement::<()>(),
783                resource_roles: NonFungibleResourceRoles::default().into(),
784                metadata: metadata! {
785                    init {
786                        "name" => "EdDSA Ed25519 Virtual Badges".to_owned(), locked;
787                        "description" => "Virtual badges generated automatically by the Radix system to represent EdDSA Ed25519 signatures applied to transactions. These badges cease to exist at the end of their transaction.".to_owned(), locked;
788                        "tags" => vec!["badge".to_owned()], locked;
789                        "icon_url" => UncheckedUrl::of("https://assets.radixdlt.com/icons/icon-eddsa_ed25519_signature_virtual_badge.png"), locked;
790                    }
791                }.into(),
792                address_reservation: Some(reservation),
793            },
794        );
795    }
796
797    // System Execution Resource
798    {
799        let reservation = manifest_builder.use_preallocated_address(
800            SYSTEM_EXECUTION_RESOURCE,
801            RESOURCE_PACKAGE,
802            NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
803        );
804        manifest_builder = manifest_builder.call_function(
805            RESOURCE_PACKAGE,
806            NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
807            NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_IDENT,
808            NonFungibleResourceManagerCreateManifestInput {
809                owner_role: OwnerRole::Fixed(rule!(require(system_execution(SystemExecution::Protocol)))).into(),
810                id_type: NonFungibleIdType::Integer,
811                track_total_supply: false,
812                non_fungible_schema: NonFungibleDataSchema::new_local_without_self_package_replacement::<()>(),
813                resource_roles: NonFungibleResourceRoles::default().into(),
814                metadata: metadata! {
815                    init {
816                        "name" => "System Transaction Badge".to_owned(), locked;
817                        "description" => "Virtual badges are created under this resource to represent the Radix system's authority at genesis and to affect changes to system entities during protocol updates, or to represent the Radix system's authority in the regularly occurring system transactions including round and epoch changes.".to_owned(), locked;
818                        "tags" => vec!["badge".to_owned(), "system badge".to_owned()], locked;
819                        "icon_url" => UncheckedUrl::of("https://assets.radixdlt.com/icons/icon-system_transaction_badge.png"), locked;
820                    }
821                }.into(),
822                address_reservation: Some(reservation),
823            },
824        );
825    }
826
827    // Faucet Package
828    {
829        let reservation: ManifestAddressReservation = manifest_builder.use_preallocated_address(
830            FAUCET_PACKAGE,
831            PACKAGE_PACKAGE,
832            PACKAGE_BLUEPRINT,
833        );
834        manifest_builder = manifest_builder.publish_package_advanced(
835            reservation,
836            include_bytes!("../../assets/faucet.wasm").to_vec(),
837            manifest_decode::<ManifestPackageDefinition>(include_bytes!("../../assets/faucet.rpd")).unwrap().try_into_typed().unwrap(),
838            metadata_init!{
839                "name" => "Faucet Package".to_owned(), locked;
840                "description" => "A package that defines the logic of a simple faucet component for testing purposes.".to_owned(), locked;
841            },
842            OwnerRole::None
843        );
844    }
845
846    // Genesis helper package
847    {
848        let reservation = manifest_builder.use_preallocated_address(
849            GENESIS_HELPER_PACKAGE,
850            PACKAGE_PACKAGE,
851            PACKAGE_BLUEPRINT,
852        );
853        manifest_builder = manifest_builder.publish_package_advanced(
854            reservation,
855            include_bytes!("../../assets/genesis_helper.wasm").to_vec(),
856            manifest_decode::<ManifestPackageDefinition>(include_bytes!("../../assets/genesis_helper.rpd")).unwrap().try_into_typed().unwrap(),
857            metadata_init! {
858                "name" => "Genesis Helper Package".to_owned(), locked;
859                "description" => "A package that defines the logic of the genesis helper which includes various utility and helper functions used in the creation of the Babylon Genesis.".to_owned(), locked;
860            },
861            OwnerRole::None,
862        );
863    }
864
865    // Create ConsensusManager
866    {
867        let badge_reservation = manifest_builder.use_preallocated_address(
868            VALIDATOR_OWNER_BADGE,
869            RESOURCE_PACKAGE,
870            NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
871        );
872        let manager_reservation = manifest_builder.use_preallocated_address(
873            CONSENSUS_MANAGER,
874            CONSENSUS_MANAGER_PACKAGE,
875            CONSENSUS_MANAGER_BLUEPRINT,
876        );
877        manifest_builder = manifest_builder.call_function(
878            CONSENSUS_MANAGER_PACKAGE,
879            CONSENSUS_MANAGER_BLUEPRINT,
880            CONSENSUS_MANAGER_CREATE_IDENT,
881            ConsensusManagerCreateManifestInput {
882                validator_owner_token_address: badge_reservation,
883                component_address: manager_reservation,
884                initial_epoch,
885                initial_config,
886                initial_time_ms,
887                initial_current_leader,
888            },
889        );
890    }
891
892    // Create GenesisHelper
893    {
894        let reservation = manifest_builder.use_preallocated_address(
895            GENESIS_HELPER,
896            GENESIS_HELPER_PACKAGE,
897            GENESIS_HELPER_BLUEPRINT,
898        );
899        manifest_builder = manifest_builder.call_function(
900            GENESIS_HELPER_PACKAGE,
901            GENESIS_HELPER_BLUEPRINT,
902            "new",
903            (
904                reservation,
905                CONSENSUS_MANAGER,
906                system_execution(SystemExecution::Protocol),
907            ),
908        );
909    }
910
911    // Transaction tracker package
912    {
913        let reservation = manifest_builder.use_preallocated_address(
914            TRANSACTION_TRACKER_PACKAGE,
915            PACKAGE_PACKAGE,
916            PACKAGE_BLUEPRINT,
917        );
918        manifest_builder = manifest_builder.call_function(
919            PACKAGE_PACKAGE,
920            PACKAGE_BLUEPRINT,
921            PACKAGE_PUBLISH_NATIVE_IDENT,
922            PackagePublishNativeManifestInput {
923                package_address: Some(reservation),
924                native_package_code_id: NativeCodeId::TransactionTrackerCode1 as u64,
925                definition: TRANSACTION_TRACKER_PACKAGE_DEFINITION.clone().into(),
926                metadata: metadata_init!().into(),
927            },
928        );
929    }
930
931    // Intent Hash Store component
932    {
933        let reservation = manifest_builder.use_preallocated_address(
934            TRANSACTION_TRACKER,
935            TRANSACTION_TRACKER_PACKAGE,
936            TRANSACTION_TRACKER_BLUEPRINT,
937        );
938        manifest_builder = manifest_builder.call_function(
939            TRANSACTION_TRACKER_PACKAGE,
940            TRANSACTION_TRACKER_BLUEPRINT,
941            TRANSACTION_TRACKER_CREATE_IDENT,
942            (reservation,),
943        );
944    }
945
946    // Faucet
947    // Note - the faucet is now created as part of bootstrap instead of wrap-up, to enable
948    // transaction scenarios to be injected into the ledger in the node before genesis wrap-up occurs
949    {
950        let reservation =
951            manifest_builder.use_preallocated_address(FAUCET, FAUCET_PACKAGE, FAUCET_BLUEPRINT);
952        // Mint XRD for the faucet, and then deposit it into the new faucet
953        // Note - on production environments, the faucet will be empty
954        manifest_builder = manifest_builder
955            .mint_fungible(XRD, faucet_supply)
956            .take_from_worktop(XRD, faucet_supply, "faucet_xrd")
957            .call_function(
958                FAUCET_PACKAGE,
959                FAUCET_BLUEPRINT,
960                "new",
961                (reservation, lookup.bucket("faucet_xrd")),
962            );
963    }
964
965    manifest_builder
966        .build()
967        .into_transaction(hash("Genesis Bootstrap"))
968}
969
970pub fn create_genesis_data_ingestion_transaction(
971    chunk: GenesisDataChunk,
972    chunk_index: usize,
973) -> SystemTransactionV1 {
974    map_address_allocations_for_manifest(chunk)
975        .into_transaction(hash(format!("Genesis Data Chunk: {}", chunk_index)))
976}
977
978fn map_address_allocations_for_manifest(
979    genesis_data_chunk: GenesisDataChunk,
980) -> SystemTransactionManifestV1 {
981    let mut manifest_builder = SystemManifestV1Builder::new_system_v1();
982    let data_chunk = match genesis_data_chunk {
983        GenesisDataChunk::Validators(content) => ManifestGenesisDataChunk::Validators(content),
984        GenesisDataChunk::Stakes {
985            accounts,
986            allocations,
987        } => ManifestGenesisDataChunk::Stakes {
988            accounts,
989            allocations,
990        },
991        GenesisDataChunk::Resources(genesis_resources) => {
992            let resources = genesis_resources
993                .into_iter()
994                .map(|genesis_resource| ManifestGenesisResource {
995                    resource_address_reservation: manifest_builder.use_preallocated_address(
996                        genesis_resource.reserved_resource_address,
997                        RESOURCE_PACKAGE,
998                        FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
999                    ),
1000                    metadata: genesis_resource.metadata,
1001                    owner: genesis_resource.owner,
1002                })
1003                .collect();
1004            ManifestGenesisDataChunk::Resources(resources)
1005        }
1006        GenesisDataChunk::ResourceBalances {
1007            accounts,
1008            allocations,
1009        } => ManifestGenesisDataChunk::ResourceBalances {
1010            accounts,
1011            allocations,
1012        },
1013        GenesisDataChunk::XrdBalances(content) => ManifestGenesisDataChunk::XrdBalances(content),
1014    };
1015    manifest_builder
1016        .call_method(GENESIS_HELPER, "ingest_data_chunk", (data_chunk,))
1017        .build()
1018}
1019
1020pub fn create_genesis_wrap_up_transaction() -> SystemTransactionV1 {
1021    let manifest = ManifestBuilder::new_system_v1()
1022        .call_method(GENESIS_HELPER, "wrap_up", ())
1023        .build();
1024
1025    manifest.into_transaction(hash("Genesis Wrap Up"))
1026}