radix_engine/updates/
cuttlefish.rs

1use super::*;
2use crate::blueprints::account::*;
3use crate::blueprints::consensus_manager::*;
4use crate::blueprints::resource::*;
5use crate::internal_prelude::*;
6use crate::kernel::kernel::KernelBoot;
7use crate::object_modules::metadata::*;
8use crate::system::system_callback::*;
9use crate::system::system_db_reader::*;
10use crate::vm::*;
11use radix_engine_interface::blueprints::account::*;
12use radix_engine_interface::blueprints::identity::*;
13use radix_transactions::validation::*;
14
15#[derive(Clone, ScryptoSbor)]
16pub struct CuttlefishPart1Settings {
17    /// Add configuration for system logic versioning
18    pub system_logic_update: UpdateSetting<NoSettings>,
19    /// Updating the always visible global nodes to include the account locker package.
20    pub kernel_version_update: UpdateSetting<NoSettings>,
21    /// Add transaction validation changes
22    pub transaction_validation_update: UpdateSetting<NoSettings>,
23    /// Adds assert worktop resources methods for the worktop blueprint.
24    pub assert_worktop_resources_methods: UpdateSetting<NoSettings>,
25    /// Adds getter methods for the account blueprint.
26    pub account_getter_methods: UpdateSetting<NoSettings>,
27    /// Update the metadata for cuttlefish
28    pub update_metadata: UpdateSetting<NoSettings>,
29    /// updates the min number of rounds per epoch.
30    pub update_number_of_min_rounds_per_epoch:
31        UpdateSetting<UpdateNumberOfMinRoundsPerEpochSettings>,
32    /// Update identity blueprint to not create a royalty module.
33    pub update_identity_to_not_create_royalty_module: UpdateSetting<NoSettings>,
34    /// Introduces Crypto Utils v2 with support for
35    /// - Blake2b-256,
36    /// - Secp256k1 ECDSA verification
37    /// - Ed25519 verification
38    pub vm_boot_to_enable_crypto_utils_v2: UpdateSetting<NoSettings>,
39}
40
41impl UpdateSettings for CuttlefishPart1Settings {
42    type UpdateGenerator = CuttlefishPart1Generator;
43
44    fn protocol_version() -> ProtocolVersion {
45        ProtocolVersion::CuttlefishPart1
46    }
47
48    fn all_enabled_as_default_for_network(network: &NetworkDefinition) -> Self {
49        Self {
50            system_logic_update: UpdateSetting::enabled_as_default_for_network(network),
51            kernel_version_update: UpdateSetting::enabled_as_default_for_network(network),
52            transaction_validation_update: UpdateSetting::enabled_as_default_for_network(network),
53            assert_worktop_resources_methods: UpdateSetting::enabled_as_default_for_network(
54                network,
55            ),
56            account_getter_methods: UpdateSetting::enabled_as_default_for_network(network),
57            update_metadata: UpdateSetting::enabled_as_default_for_network(network),
58            update_number_of_min_rounds_per_epoch: UpdateSetting::enabled_as_default_for_network(
59                network,
60            ),
61            update_identity_to_not_create_royalty_module:
62                UpdateSetting::enabled_as_default_for_network(network),
63            vm_boot_to_enable_crypto_utils_v2: UpdateSetting::enabled_as_default_for_network(
64                network,
65            ),
66        }
67    }
68
69    fn all_disabled() -> Self {
70        Self {
71            system_logic_update: UpdateSetting::Disabled,
72            kernel_version_update: UpdateSetting::Disabled,
73            transaction_validation_update: UpdateSetting::Disabled,
74            assert_worktop_resources_methods: UpdateSetting::Disabled,
75            account_getter_methods: UpdateSetting::Disabled,
76            update_metadata: UpdateSetting::Disabled,
77            update_number_of_min_rounds_per_epoch: UpdateSetting::Disabled,
78            update_identity_to_not_create_royalty_module: UpdateSetting::Disabled,
79            vm_boot_to_enable_crypto_utils_v2: UpdateSetting::Disabled,
80        }
81    }
82
83    fn create_generator(&self) -> Self::UpdateGenerator {
84        Self::UpdateGenerator {
85            settings: self.clone(),
86        }
87    }
88}
89
90/// We had to separate Cuttlefish into two parts, because we noticed an issue
91/// after CuttlefishPart1 was deployed to stokenet.
92#[derive(Clone, ScryptoSbor)]
93pub struct CuttlefishPart2Settings {
94    /// Add configuration for system logic versioning
95    pub another_system_logic_update: UpdateSetting<NoSettings>,
96}
97
98impl UpdateSettings for CuttlefishPart2Settings {
99    type UpdateGenerator = CuttlefishPart2Generator;
100
101    fn protocol_version() -> ProtocolVersion {
102        ProtocolVersion::CuttlefishPart2
103    }
104
105    fn all_enabled_as_default_for_network(network: &NetworkDefinition) -> Self {
106        Self {
107            another_system_logic_update: UpdateSetting::enabled_as_default_for_network(network),
108        }
109    }
110
111    fn all_disabled() -> Self {
112        Self {
113            another_system_logic_update: UpdateSetting::Disabled,
114        }
115    }
116
117    fn create_generator(&self) -> Self::UpdateGenerator {
118        Self::UpdateGenerator {
119            settings: self.clone(),
120        }
121    }
122}
123
124#[derive(Clone, Copy, Debug, Sbor)]
125pub enum UpdateNumberOfMinRoundsPerEpochSettings {
126    Set { value: u64 },
127    SetIfEquals { if_equals: u64, to_value: u64 },
128}
129
130impl Default for UpdateNumberOfMinRoundsPerEpochSettings {
131    fn default() -> Self {
132        Self::SetIfEquals {
133            if_equals: 500,
134            to_value: 100,
135        }
136    }
137}
138
139impl UpdateSettingContent for UpdateNumberOfMinRoundsPerEpochSettings {
140    fn default_setting(_: &NetworkDefinition) -> Self {
141        Self::default()
142    }
143}
144
145pub struct CuttlefishPart1Generator {
146    settings: CuttlefishPart1Settings,
147}
148
149impl ProtocolUpdateGenerator for CuttlefishPart1Generator {
150    fn batch_groups(&self) -> Vec<Box<dyn ProtocolUpdateBatchGroupGenerator + '_>> {
151        vec![FixedBatchGroupGenerator::named("principal")
152            .add_batch("primary", |store| {
153                generate_part1_batch(store, &self.settings)
154            })
155            .build()]
156    }
157}
158
159pub struct CuttlefishPart2Generator {
160    settings: CuttlefishPart2Settings,
161}
162
163impl ProtocolUpdateGenerator for CuttlefishPart2Generator {
164    fn batch_groups(&self) -> Vec<Box<dyn ProtocolUpdateBatchGroupGenerator + '_>> {
165        vec![FixedBatchGroupGenerator::named("principal")
166            .add_batch("primary", |store| {
167                generate_part2_batch(store, &self.settings)
168            })
169            .build()]
170    }
171}
172
173#[deny(unused_variables)]
174fn generate_part1_batch(
175    store: &dyn SubstateDatabase,
176    CuttlefishPart1Settings {
177        system_logic_update,
178        kernel_version_update,
179        transaction_validation_update,
180        assert_worktop_resources_methods,
181        account_getter_methods,
182        update_metadata,
183        update_number_of_min_rounds_per_epoch,
184        update_identity_to_not_create_royalty_module,
185        vm_boot_to_enable_crypto_utils_v2,
186    }: &CuttlefishPart1Settings,
187) -> ProtocolUpdateBatch {
188    let mut batch = ProtocolUpdateBatch::empty();
189
190    if let UpdateSetting::Enabled(NoSettings) = &system_logic_update {
191        batch.mut_add_flash(
192            "cuttlefish-protocol-system-logic-updates",
193            generate_system_logic_v2_updates(store),
194        );
195    }
196
197    if let UpdateSetting::Enabled(NoSettings) = &kernel_version_update {
198        batch.mut_add_flash(
199            "cuttlefish-protocol-kernel-version-update",
200            generate_always_visible_global_nodes_updates(store),
201        );
202    }
203
204    if let UpdateSetting::Enabled(NoSettings) = &transaction_validation_update {
205        batch.mut_add_flash(
206            "cuttlefish-transaction-validation-updates",
207            generate_cuttlefish_transaction_validation_updates(),
208        );
209    }
210    if let UpdateSetting::Enabled(NoSettings) = &assert_worktop_resources_methods {
211        batch.mut_add_flash(
212            "cuttlefish-assert-worktop-resources-methods",
213            generate_cuttlefish_worktop_methods_extension_state_updates(store),
214        );
215    }
216    if let UpdateSetting::Enabled(NoSettings) = &account_getter_methods {
217        batch.mut_add_flash(
218            "cuttlefish-account-getter-methods",
219            generate_cuttlefish_account_getters_extension_state_updates(store),
220        );
221    }
222
223    if let UpdateSetting::Enabled(NoSettings) = &update_metadata {
224        batch.mut_add_flash(
225            "cuttlefish-update-metadata",
226            generate_cuttlefish_metadata_fix(store),
227        );
228    }
229    if let UpdateSetting::Enabled(settings) = &update_number_of_min_rounds_per_epoch {
230        batch.mut_add_flash(
231            "cuttlefish-update-number-of-min-rounds-per-epoch",
232            generate_cuttlefish_update_min_rounds_per_epoch(store, *settings),
233        );
234    }
235
236    if let UpdateSetting::Enabled(NoSettings) = &update_identity_to_not_create_royalty_module {
237        batch.mut_add_flash(
238            "cuttlefish-update-identity-to-not-create-royalty-module",
239            generate_cuttlefish_update_identity_to_not_create_royalty_module(store),
240        );
241    }
242
243    if let UpdateSetting::Enabled(NoSettings) = &vm_boot_to_enable_crypto_utils_v2 {
244        batch.mut_add_flash(
245            "cuttlefish-vm-boot-to-enable-crypto-utils-v2",
246            generate_vm_boot_to_enable_crypto_utils_v2(),
247        );
248    }
249
250    batch
251}
252
253fn generate_part2_batch(
254    store: &dyn SubstateDatabase,
255    CuttlefishPart2Settings {
256        another_system_logic_update: system_logic_update,
257    }: &CuttlefishPart2Settings,
258) -> ProtocolUpdateBatch {
259    let mut batch = ProtocolUpdateBatch::empty();
260
261    if let UpdateSetting::Enabled(NoSettings) = &system_logic_update {
262        batch.mut_add_flash(
263            "cuttlefish-part2-protocol-system-logic-updates",
264            generate_system_logic_v3_updates(store),
265        );
266    }
267
268    batch
269}
270
271fn generate_system_logic_v2_updates<S: SubstateDatabase + ?Sized>(db: &S) -> StateUpdates {
272    let existing_system_boot: SystemBoot = db.get_existing_substate(
273        TRANSACTION_TRACKER,
274        BOOT_LOADER_PARTITION,
275        BootLoaderField::SystemBoot,
276    );
277
278    StateUpdates::empty().set_substate(
279        TRANSACTION_TRACKER,
280        BOOT_LOADER_PARTITION,
281        BootLoaderField::SystemBoot,
282        SystemBoot::cuttlefish_part1_for_previous_parameters(
283            existing_system_boot.into_parameters(),
284        ),
285    )
286}
287
288fn generate_system_logic_v3_updates<S: SubstateDatabase + ?Sized>(db: &S) -> StateUpdates {
289    let existing_system_boot: SystemBoot = db.get_existing_substate(
290        TRANSACTION_TRACKER,
291        BOOT_LOADER_PARTITION,
292        BootLoaderField::SystemBoot,
293    );
294
295    StateUpdates::empty().set_substate(
296        TRANSACTION_TRACKER,
297        BOOT_LOADER_PARTITION,
298        BootLoaderField::SystemBoot,
299        SystemBoot::cuttlefish_part2_for_previous_parameters(
300            existing_system_boot.into_parameters(),
301        ),
302    )
303}
304
305fn generate_always_visible_global_nodes_updates<S: SubstateDatabase + ?Sized>(
306    db: &S,
307) -> StateUpdates {
308    let KernelBoot::V1 = db.get_existing_substate::<KernelBoot>(
309        TRANSACTION_TRACKER,
310        BOOT_LOADER_PARTITION,
311        BootLoaderField::KernelBoot,
312    ) else {
313        panic!("Unexpected KernelBoot version")
314    };
315
316    StateUpdates::empty().set_substate(
317        TRANSACTION_TRACKER,
318        BOOT_LOADER_PARTITION,
319        BootLoaderField::KernelBoot,
320        KernelBoot::cuttlefish(),
321    )
322}
323
324fn generate_cuttlefish_transaction_validation_updates() -> StateUpdates {
325    StateUpdates::empty().set_substate(
326        TRANSACTION_TRACKER,
327        BOOT_LOADER_PARTITION,
328        BootLoaderField::TransactionValidationConfiguration,
329        TransactionValidationConfigurationSubstate::new(
330            TransactionValidationConfigurationVersions::V1(
331                TransactionValidationConfigV1::cuttlefish(),
332            ),
333        ),
334    )
335}
336
337fn generate_cuttlefish_worktop_methods_extension_state_updates<S: SubstateDatabase + ?Sized>(
338    db: &S,
339) -> StateUpdates {
340    let (added_functions, schema) = WorktopBlueprintCuttlefishExtension::added_functions_schema();
341    let auth_config = WorktopBlueprint::get_definition().auth_config;
342
343    add_public_functions_to_blueprint(
344        db,
345        RESOURCE_PACKAGE,
346        WORKTOP_BLUEPRINT,
347        NativeCodeId::ResourceCode2,
348        added_functions,
349        schema,
350        auth_config,
351    )
352}
353
354fn generate_cuttlefish_account_getters_extension_state_updates<S: SubstateDatabase + ?Sized>(
355    db: &S,
356) -> StateUpdates {
357    let (added_functions, schema) = AccountBlueprintCuttlefishExtension::added_functions_schema();
358
359    // Update the auth config of the account blueprint to have these added methods and have them be
360    // public.
361    let auth_config = {
362        let mut auth_config = AccountBlueprint::get_definition().auth_config;
363        let MethodAuthTemplate::StaticRoleDefinition(StaticRoleDefinition {
364            ref mut methods, ..
365        }) = auth_config.method_auth
366        else {
367            panic!("Doesn't have a static role definition")
368        };
369        methods.extend(
370            added_functions
371                .keys()
372                .map(ToOwned::to_owned)
373                .map(|ident| MethodKey { ident })
374                .map(|key| (key, MethodAccessibility::Public)),
375        );
376        auth_config
377    };
378
379    add_public_functions_to_blueprint(
380        db,
381        ACCOUNT_PACKAGE,
382        ACCOUNT_BLUEPRINT,
383        NativeCodeId::AccountCode3,
384        added_functions,
385        schema,
386        auth_config,
387    )
388}
389
390fn generate_cuttlefish_metadata_fix<S: SubstateDatabase + ?Sized>(db: &S) -> StateUpdates {
391    struct MetadataUpdates {
392        pub name: Option<MetadataValue>,
393        pub description: Option<MetadataValue>,
394        pub icon_url: Option<MetadataValue>,
395    }
396
397    impl MetadataUpdates {
398        pub fn into_map(self) -> IndexMap<String, MetadataValue> {
399            [
400                self.name.map(|value| ("name", value)),
401                self.description.map(|value| ("description", value)),
402                self.icon_url.map(|value| ("icon_url", value)),
403            ]
404            .into_iter()
405            .flatten()
406            .map(|(k, v)| (k.to_owned(), v))
407            .collect()
408        }
409    }
410
411    let reader = SystemDatabaseReader::new(db);
412
413    // The metadata entries that we would like to update and the values that we would like to update
414    // them to be.
415    let metadata_updates = indexmap! {
416        XRD => MetadataUpdates {
417            name: None,
418            description: None,
419            icon_url: Some(MetadataValue::Url(UncheckedUrl("https://assets.radixdlt.com/icons/icon-xrd.png".into())))
420        },
421        PACKAGE_OF_DIRECT_CALLER_RESOURCE => MetadataUpdates {
422            name: Some(MetadataValue::String("Package of Direct Caller Resource".into())),
423            description: Some(MetadataValue::String("This is an implicit proof resource, intended for verifying access by specific code. See the info_url for further information.".into())),
424            icon_url: Some(MetadataValue::Url(UncheckedUrl("https://assets.radixdlt.com/icons/icon-package_of_direct_caller_resource.png".into())))
425        },
426        GLOBAL_CALLER_RESOURCE => MetadataUpdates {
427            name: Some(MetadataValue::String("Global Caller Resource".into())),
428            description: Some(MetadataValue::String("This is an implicit proof resource, intended for verifying access by a specific global caller. In cases where you wish to find out the global caller, you can require the caller to pass their claimed global address into the method, and then verify it with this rule. See the info_url for further information.".into())),
429            icon_url: Some(MetadataValue::Url(UncheckedUrl("https://assets.radixdlt.com/icons/icon-global_caller_resource.png".into())))
430        },
431        SECP256K1_SIGNATURE_RESOURCE => MetadataUpdates {
432            name: Some(MetadataValue::String("ECDSA Secp256k1 Signature Resource".into())),
433            description: Some(MetadataValue::String("This is an implicit proof resource, intended for verifying access by a manifest signed with the given ECDSA Secp256k1 key hash. See the info_url for further information.".into())),
434            icon_url: Some(MetadataValue::Url(UncheckedUrl("https://assets.radixdlt.com/icons/icon-ecdsa_secp256k1_signature_resource.png".into())))
435        },
436        ED25519_SIGNATURE_RESOURCE => MetadataUpdates {
437            name: Some(MetadataValue::String("EdDSA Ed25519 Signature Resource".into())),
438            description: Some(MetadataValue::String("This is an implicit proof resource, intended for verifying access by a manifest signed with the given EdDSA Ed25519 key hash. See the info_url for further information.".into())),
439            icon_url: Some(MetadataValue::Url(UncheckedUrl("https://assets.radixdlt.com/icons/icon-eddsa_ed25519_signature_resource.png".into())))
440        },
441        SYSTEM_EXECUTION_RESOURCE => MetadataUpdates {
442            name: Some(MetadataValue::String("System Execution Resource".into())),
443            description: Some(MetadataValue::String("This is an implicit proof resource, intended for verifying access by a manifest of a certain type of system transaction, such as a protocol update or a validator transaction. See the info_url for further information.".into())),
444            icon_url: Some(MetadataValue::Url(UncheckedUrl("https://assets.radixdlt.com/icons/icon-system_execution_resource.png".into())))
445        },
446    };
447
448    // We would like to add an `info_url` entry for the various entities that we have. The this is
449    // the mapping that we're using.
450    let info_url_metadata = [
451        (XRD.into_node_id(), "https://www.radixdlt.com/info-url/xrd"),
452        (
453            SECP256K1_SIGNATURE_RESOURCE.into_node_id(),
454            "https://www.radixdlt.com/info-url/secp256k1-signature-resource",
455        ),
456        (
457            ED25519_SIGNATURE_RESOURCE.into_node_id(),
458            "https://www.radixdlt.com/info-url/ed25519-signature-resource",
459        ),
460        (
461            PACKAGE_OF_DIRECT_CALLER_RESOURCE.into_node_id(),
462            "https://www.radixdlt.com/info-url/package-of-direct-caller-resource",
463        ),
464        (
465            GLOBAL_CALLER_RESOURCE.into_node_id(),
466            "https://www.radixdlt.com/info-url/global-caller-resource",
467        ),
468        (
469            SYSTEM_EXECUTION_RESOURCE.into_node_id(),
470            "https://www.radixdlt.com/info-url/system-execution-resource",
471        ),
472        (
473            PACKAGE_OWNER_BADGE.into_node_id(),
474            "https://www.radixdlt.com/info-url/package-owner-badge",
475        ),
476        (
477            VALIDATOR_OWNER_BADGE.into_node_id(),
478            "https://www.radixdlt.com/info-url/validator-owner-badge",
479        ),
480        (
481            ACCOUNT_OWNER_BADGE.into_node_id(),
482            "https://www.radixdlt.com/info-url/account-owner-badge",
483        ),
484        (
485            IDENTITY_OWNER_BADGE.into_node_id(),
486            "https://www.radixdlt.com/info-url/identity-owner-badge",
487        ),
488        (
489            PACKAGE_PACKAGE.into_node_id(),
490            "https://www.radixdlt.com/info-url/package-package",
491        ),
492        (
493            RESOURCE_PACKAGE.into_node_id(),
494            "https://www.radixdlt.com/info-url/resource-package",
495        ),
496        (
497            ACCOUNT_PACKAGE.into_node_id(),
498            "https://www.radixdlt.com/info-url/account-package",
499        ),
500        (
501            IDENTITY_PACKAGE.into_node_id(),
502            "https://www.radixdlt.com/info-url/identity-package",
503        ),
504        (
505            CONSENSUS_MANAGER_PACKAGE.into_node_id(),
506            "https://www.radixdlt.com/info-url/consensus-manager-package",
507        ),
508        (
509            ACCESS_CONTROLLER_PACKAGE.into_node_id(),
510            "https://www.radixdlt.com/info-url/access-controller-package",
511        ),
512        (
513            POOL_PACKAGE.into_node_id(),
514            "https://www.radixdlt.com/info-url/pool-package",
515        ),
516        (
517            TRANSACTION_PROCESSOR_PACKAGE.into_node_id(),
518            "https://www.radixdlt.com/info-url/transaction-processor-package",
519        ),
520        (
521            METADATA_MODULE_PACKAGE.into_node_id(),
522            "https://www.radixdlt.com/info-url/metadata-module-package",
523        ),
524        (
525            ROYALTY_MODULE_PACKAGE.into_node_id(),
526            "https://www.radixdlt.com/info-url/royalty-module-package",
527        ),
528        (
529            ROLE_ASSIGNMENT_MODULE_PACKAGE.into_node_id(),
530            "https://www.radixdlt.com/info-url/role-assignment-module-package",
531        ),
532        (
533            TEST_UTILS_PACKAGE.into_node_id(),
534            "https://www.radixdlt.com/info-url/test-utils-package",
535        ),
536        (
537            GENESIS_HELPER_PACKAGE.into_node_id(),
538            "https://www.radixdlt.com/info-url/genesis-helper-package",
539        ),
540        (
541            FAUCET_PACKAGE.into_node_id(),
542            "https://www.radixdlt.com/info-url/faucet-package",
543        ),
544        (
545            TRANSACTION_TRACKER_PACKAGE.into_node_id(),
546            "https://www.radixdlt.com/info-url/transaction-tracker-package",
547        ),
548        (
549            LOCKER_PACKAGE.into_node_id(),
550            "https://www.radixdlt.com/info-url/locker-package",
551        ),
552        (
553            CONSENSUS_MANAGER.into_node_id(),
554            "https://www.radixdlt.com/info-url/consensus-manager",
555        ),
556        (
557            GENESIS_HELPER.into_node_id(),
558            "https://www.radixdlt.com/info-url/genesis-helper",
559        ),
560        (
561            FAUCET.into_node_id(),
562            "https://www.radixdlt.com/info-url/faucet",
563        ),
564        (
565            TRANSACTION_TRACKER.into_node_id(),
566            "https://www.radixdlt.com/info-url/transaction-tracker",
567        ),
568    ];
569
570    let mut state_updates = StateUpdates::empty();
571    for (resource_address, metadata_updates) in metadata_updates.into_iter() {
572        for (key, value) in metadata_updates.into_map().into_iter() {
573            let partition_number = reader
574                .get_partition_of_collection(
575                    resource_address.as_node_id(),
576                    ModuleId::Metadata,
577                    MetadataCollection::EntryKeyValue.collection_index(),
578                )
579                .unwrap();
580
581            state_updates = state_updates.set_substate(
582                resource_address,
583                partition_number,
584                SubstateKey::Map(
585                    scrypto_encode(&MetadataEntryKeyPayload { content: key }).unwrap(),
586                ),
587                value.into_locked_substate(),
588            );
589        }
590    }
591    for (node_id, info_url) in info_url_metadata.into_iter() {
592        let partition_number = reader
593            .get_partition_of_collection(
594                &node_id,
595                ModuleId::Metadata,
596                MetadataCollection::EntryKeyValue.collection_index(),
597            )
598            .unwrap();
599
600        state_updates = state_updates.set_substate(
601            node_id,
602            partition_number,
603            SubstateKey::Map(
604                scrypto_encode(&MetadataEntryKeyPayload {
605                    content: "info_url".to_owned(),
606                })
607                .unwrap(),
608            ),
609            MetadataValue::Url(UncheckedUrl(info_url.into())).into_locked_substate(),
610        );
611    }
612
613    state_updates
614}
615
616fn generate_cuttlefish_update_min_rounds_per_epoch<S: SubstateDatabase + ?Sized>(
617    db: &S,
618    settings: UpdateNumberOfMinRoundsPerEpochSettings,
619) -> StateUpdates {
620    let mut consensus_manager_config = db
621        .get_existing_substate::<FieldSubstate<VersionedConsensusManagerConfiguration>>(
622            CONSENSUS_MANAGER,
623            MAIN_BASE_PARTITION,
624            ConsensusManagerField::Configuration,
625        )
626        .into_payload()
627        .fully_update_and_into_latest_version();
628    let min_rounds_per_epoch = &mut consensus_manager_config
629        .config
630        .epoch_change_condition
631        .min_round_count;
632
633    match settings {
634        UpdateNumberOfMinRoundsPerEpochSettings::Set { value } => *min_rounds_per_epoch = value,
635        UpdateNumberOfMinRoundsPerEpochSettings::SetIfEquals {
636            if_equals,
637            to_value,
638        } => {
639            if *min_rounds_per_epoch == if_equals {
640                *min_rounds_per_epoch = to_value
641            }
642        }
643    }
644
645    StateUpdates::empty().set_substate(
646        CONSENSUS_MANAGER,
647        MAIN_BASE_PARTITION,
648        ConsensusManagerField::Configuration,
649        consensus_manager_config.into_locked_substate(),
650    )
651}
652
653fn generate_cuttlefish_update_identity_to_not_create_royalty_module<
654    S: SubstateDatabase + ?Sized,
655>(
656    db: &S,
657) -> StateUpdates {
658    let reader = SystemDatabaseReader::new(db);
659    let node_id = IDENTITY_PACKAGE.into_node_id();
660    let blueprint_version_key = BlueprintVersionKey {
661        blueprint: IDENTITY_BLUEPRINT.to_string(),
662        version: Default::default(),
663    };
664
665    // Create substates for the new code.
666    let (code_hash, (code_substate, vm_type_substate)) = {
667        let original_code = (NativeCodeId::IdentityCode2 as u64).to_be_bytes().to_vec();
668
669        let code_hash = CodeHash::from_hash(hash(&original_code));
670        let code_substate = PackageCodeOriginalCodeV1 {
671            code: original_code,
672        }
673        .into_locked_substate();
674        let vm_type_substate = PackageCodeVmTypeV1 {
675            vm_type: VmType::Native,
676        }
677        .into_locked_substate();
678
679        (code_hash, (code_substate, vm_type_substate))
680    };
681
682    // Update the definition of the existing blueprint so that new code is used
683    let blueprint_definition_substate = {
684        let mut blueprint_definition = reader
685            .read_object_collection_entry::<_, VersionedPackageBlueprintVersionDefinition>(
686                &node_id,
687                ObjectModuleId::Main,
688                ObjectCollectionKey::KeyValue(
689                    PackageCollection::BlueprintVersionDefinitionKeyValue.collection_index(),
690                    &blueprint_version_key,
691                ),
692            )
693            .unwrap()
694            .unwrap()
695            .fully_update_and_into_latest_version();
696
697        for function_name in [IDENTITY_CREATE_ADVANCED_IDENT, IDENTITY_CREATE_IDENT] {
698            blueprint_definition
699                .function_exports
700                .get_mut(function_name)
701                .expect("This function must exist")
702                .code_hash = code_hash;
703        }
704
705        blueprint_definition
706            .hook_exports
707            .get_mut(&BlueprintHook::OnVirtualize)
708            .expect("Identity::OnVirtualize hook must exist")
709            .code_hash = code_hash;
710
711        blueprint_definition.into_locked_substate()
712    };
713
714    let [blueprint_version_definition_partition_number, code_vm_type_partition_number, code_original_code_partition_number] =
715        [
716            PackageCollection::BlueprintVersionDefinitionKeyValue,
717            PackageCollection::CodeVmTypeKeyValue,
718            PackageCollection::CodeOriginalCodeKeyValue,
719        ]
720        .map(|package_collection| {
721            reader
722                .get_partition_of_collection(
723                    &node_id,
724                    ObjectModuleId::Main,
725                    package_collection.collection_index(),
726                )
727                .unwrap()
728        });
729
730    // Generate state updates
731    StateUpdates::empty().set_node_updates(
732        node_id,
733        NodeStateUpdates::empty()
734            .set_substate(
735                blueprint_version_definition_partition_number,
736                SubstateKey::map(&blueprint_version_key),
737                blueprint_definition_substate,
738            )
739            .set_substate(
740                code_vm_type_partition_number,
741                SubstateKey::map(&code_hash),
742                vm_type_substate,
743            )
744            .set_substate(
745                code_original_code_partition_number,
746                SubstateKey::map(&code_hash),
747                code_substate,
748            ),
749    )
750}
751
752fn generate_vm_boot_to_enable_crypto_utils_v2() -> StateUpdates {
753    StateUpdates::empty().set_substate(
754        TRANSACTION_TRACKER,
755        BOOT_LOADER_PARTITION,
756        BootLoaderField::VmBoot,
757        VmBoot::V1 {
758            scrypto_version: ScryptoVmVersion::crypto_utils_v2().into(),
759        },
760    )
761}
762
763fn add_public_functions_to_blueprint<S: SubstateDatabase + ?Sized>(
764    db: &S,
765    package: PackageAddress,
766    blueprint: &str,
767    native_code_id: NativeCodeId,
768    added_functions: IndexMap<String, FunctionSchemaInit>,
769    schema: VersionedSchema<ScryptoCustomSchema>,
770    auth_config: AuthConfig,
771) -> StateUpdates {
772    let reader = SystemDatabaseReader::new(db);
773    let node_id = package.into_node_id();
774    let blueprint_version_key = BlueprintVersionKey {
775        blueprint: blueprint.to_string(),
776        version: Default::default(),
777    };
778
779    // Creating the original code substates for extension.
780    let (code_hash, (code_substate, vm_type_substate)) = {
781        let original_code = (native_code_id as u64).to_be_bytes().to_vec();
782
783        let code_hash = CodeHash::from_hash(hash(&original_code));
784        let code_substate = PackageCodeOriginalCodeV1 {
785            code: original_code,
786        }
787        .into_versioned()
788        .into_locked_substate();
789        let vm_type_substate = PackageCodeVmTypeV1 {
790            vm_type: VmType::Native,
791        }
792        .into_locked_substate();
793
794        (code_hash, (code_substate, vm_type_substate))
795    };
796
797    // Creating the new schema substate with the methods added by the extension
798    let (schema_hash, schema_substate) =
799        (schema.generate_schema_hash(), schema.into_locked_substate());
800
801    // Updating the blueprint definition of the existing blueprint with the added functions.
802    let blueprint_definition_substate = {
803        let mut blueprint_definition = reader
804            .read_object_collection_entry::<_, VersionedPackageBlueprintVersionDefinition>(
805                &node_id,
806                ObjectModuleId::Main,
807                ObjectCollectionKey::KeyValue(
808                    PackageCollection::BlueprintVersionDefinitionKeyValue.collection_index(),
809                    &blueprint_version_key,
810                ),
811            )
812            .unwrap()
813            .unwrap()
814            .fully_update_and_into_latest_version();
815
816        for (function_name, added_function) in added_functions.into_iter() {
817            let TypeRef::Static(input_local_id) = added_function.input else {
818                unreachable!()
819            };
820            let TypeRef::Static(output_local_id) = added_function.output else {
821                unreachable!()
822            };
823
824            blueprint_definition.function_exports.insert(
825                function_name.clone(),
826                PackageExport {
827                    code_hash,
828                    export_name: function_name.clone(),
829                },
830            );
831            blueprint_definition.interface.functions.insert(
832                function_name,
833                FunctionSchema {
834                    receiver: added_function.receiver,
835                    input: BlueprintPayloadDef::Static(ScopedTypeId(schema_hash, input_local_id)),
836                    output: BlueprintPayloadDef::Static(ScopedTypeId(schema_hash, output_local_id)),
837                },
838            );
839        }
840
841        blueprint_definition.into_locked_substate()
842    };
843
844    // Getting the partition number of the various collections that we're updating
845    let blueprint_version_definition_partition_number =
846        PackagePartitionOffset::BlueprintVersionDefinitionKeyValue.as_main_partition();
847    let code_vm_type_partition_number =
848        PackagePartitionOffset::CodeVmTypeKeyValue.as_main_partition();
849    let code_original_code_partition_number =
850        PackagePartitionOffset::CodeOriginalCodeKeyValue.as_main_partition();
851    let schema_partition_number = SCHEMAS_PARTITION.at_offset(PartitionOffset(0)).unwrap();
852    let blueprint_version_auth_config_partition_number =
853        PackagePartitionOffset::BlueprintVersionAuthConfigKeyValue.as_main_partition();
854
855    // Generating the state updates
856    StateUpdates::empty().set_node_updates(
857        node_id,
858        NodeStateUpdates::empty()
859            .set_substate(
860                blueprint_version_definition_partition_number,
861                SubstateKey::map(&blueprint_version_key),
862                blueprint_definition_substate,
863            )
864            .set_substate(
865                code_vm_type_partition_number,
866                SubstateKey::map(&code_hash),
867                vm_type_substate,
868            )
869            .set_substate(
870                code_original_code_partition_number,
871                SubstateKey::map(&code_hash),
872                code_substate,
873            )
874            .set_substate(
875                schema_partition_number,
876                SubstateKey::map(&schema_hash),
877                schema_substate,
878            )
879            .set_substate(
880                blueprint_version_auth_config_partition_number,
881                SubstateKey::map(&blueprint_version_key),
882                auth_config.into_locked_substate(),
883            ),
884    )
885}