radix_engine/system/
bootstrap.rs

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