radix_engine/updates/
anemone.rs

1use super::*;
2use crate::blueprints::consensus_manager::*;
3use crate::blueprints::models::KeyValueEntryContentSource;
4use crate::blueprints::package::*;
5use crate::blueprints::pool::v1::constants::*;
6use crate::internal_prelude::*;
7use crate::system::system_db_reader::*;
8use crate::vm::*;
9use sbor::{generate_full_schema, TypeAggregator};
10
11#[derive(Clone, ScryptoSbor)]
12pub struct AnemoneSettings {
13    /// Changes the cost associated with validator creation.
14    pub validator_fee_fix: UpdateSetting<AnemoneValidatorCreationFee>,
15
16    /// Exposes second-precision timestamp.
17    pub seconds_precision: UpdateSetting<NoSettings>,
18
19    /// Introduces BLS12-381 and Keccak-256 features.
20    pub vm_boot_to_enable_bls128_and_keccak256: UpdateSetting<NoSettings>,
21
22    /// Increases the math precision with native pool implementations.
23    pub pools_update: UpdateSetting<NoSettings>,
24}
25
26impl UpdateSettings for AnemoneSettings {
27    type UpdateGenerator = AnemoneGenerator;
28
29    fn protocol_version() -> ProtocolVersion {
30        ProtocolVersion::Anemone
31    }
32
33    fn all_enabled_as_default_for_network(network: &NetworkDefinition) -> Self {
34        Self {
35            validator_fee_fix: UpdateSetting::enabled_as_default_for_network(network),
36            seconds_precision: UpdateSetting::enabled_as_default_for_network(network),
37            vm_boot_to_enable_bls128_and_keccak256: UpdateSetting::enabled_as_default_for_network(
38                network,
39            ),
40            pools_update: UpdateSetting::enabled_as_default_for_network(network),
41        }
42    }
43
44    fn all_disabled() -> Self {
45        Self {
46            validator_fee_fix: UpdateSetting::Disabled,
47            seconds_precision: UpdateSetting::Disabled,
48            vm_boot_to_enable_bls128_and_keccak256: UpdateSetting::Disabled,
49            pools_update: UpdateSetting::Disabled,
50        }
51    }
52
53    fn create_generator(&self) -> Self::UpdateGenerator {
54        AnemoneGenerator {
55            settings: self.clone(),
56        }
57    }
58}
59
60#[derive(Debug, Clone, ScryptoSbor)]
61pub struct AnemoneValidatorCreationFee {
62    pub usd_fee: Decimal,
63}
64
65impl UpdateSettingContent for AnemoneValidatorCreationFee {
66    fn default_setting(network_definition: &NetworkDefinition) -> Self {
67        let usd_fee = match network_definition.id {
68            241 => dec!(1), // Node integration test network
69            _ => dec!(100), // All others including mainnet
70        };
71        Self { usd_fee }
72    }
73}
74
75pub struct AnemoneGenerator {
76    settings: AnemoneSettings,
77}
78
79impl ProtocolUpdateGenerator for AnemoneGenerator {
80    fn insert_status_tracking_flash_transactions(&self) -> bool {
81        // This was launched without status tracking, so we can't add it in later to avoid divergence
82        false
83    }
84
85    fn batch_groups(&self) -> Vec<Box<dyn ProtocolUpdateBatchGroupGenerator + '_>> {
86        vec![FixedBatchGroupGenerator::named("principal")
87            .add_batch("primary", |store| generate_batch(store, &self.settings))
88            .build()]
89    }
90}
91
92#[deny(unused_variables)]
93fn generate_batch(
94    store: &dyn SubstateDatabase,
95    AnemoneSettings {
96        validator_fee_fix,
97        seconds_precision,
98        vm_boot_to_enable_bls128_and_keccak256,
99        pools_update,
100    }: &AnemoneSettings,
101) -> ProtocolUpdateBatch {
102    let mut batch = ProtocolUpdateBatch::empty();
103
104    if let UpdateSetting::Enabled(creation_fee) = &validator_fee_fix {
105        batch.mut_add_flash(
106            "anemone-validator-fee-fix",
107            generate_validator_creation_fee_fix_state_updates(store, creation_fee),
108        );
109    }
110
111    if let UpdateSetting::Enabled(NoSettings) = &seconds_precision {
112        batch.mut_add_flash(
113            "anemone-seconds-precision",
114            generate_seconds_precision_timestamp_state_updates(store),
115        );
116    }
117
118    if let UpdateSetting::Enabled(NoSettings) = &vm_boot_to_enable_bls128_and_keccak256 {
119        batch.mut_add_flash(
120            "anemone-vm-boot",
121            generate_vm_boot_for_bls128_and_keccak256_state_updates(),
122        );
123    }
124
125    if let UpdateSetting::Enabled(NoSettings) = &pools_update {
126        batch.mut_add_flash(
127            "anemone-pools",
128            generate_pool_math_precision_fix_state_updates(store),
129        );
130    }
131
132    batch
133}
134
135fn generate_validator_creation_fee_fix_state_updates<S: SubstateDatabase + ?Sized>(
136    db: &S,
137    validator_creation_fee: &AnemoneValidatorCreationFee,
138) -> StateUpdates {
139    let reader = SystemDatabaseReader::new(db);
140    let consensus_mgr_node_id = CONSENSUS_MANAGER.into_node_id();
141
142    let versioned_config: VersionedConsensusManagerConfiguration = reader
143        .read_typed_object_field(
144            &consensus_mgr_node_id,
145            ModuleId::Main,
146            ConsensusManagerField::Configuration.field_index(),
147        )
148        .unwrap();
149
150    let mut config = versioned_config.fully_update_and_into_latest_version();
151    config.config.validator_creation_usd_cost = validator_creation_fee.usd_fee;
152
153    let updated_substate = config.into_locked_substate();
154
155    StateUpdates {
156        by_node: indexmap!(
157            consensus_mgr_node_id => NodeStateUpdates::Delta {
158                by_partition: indexmap! {
159                    MAIN_BASE_PARTITION => PartitionStateUpdates::Delta {
160                        by_substate: indexmap! {
161                            SubstateKey::Field(ConsensusManagerField::Configuration.field_index()) => DatabaseUpdate::Set(
162                                scrypto_encode(&updated_substate).unwrap()
163                            )
164                        }
165                    },
166                }
167            }
168        ),
169    }
170}
171
172/// Generates the state updates required for updating the Consensus Manager blueprint
173/// to use seconds precision
174fn generate_seconds_precision_timestamp_state_updates<S: SubstateDatabase + ?Sized>(
175    db: &S,
176) -> StateUpdates {
177    let reader = SystemDatabaseReader::new(db);
178    let consensus_mgr_pkg_node_id = CONSENSUS_MANAGER_PACKAGE.into_node_id();
179    let bp_version_key = BlueprintVersionKey {
180        blueprint: CONSENSUS_MANAGER_BLUEPRINT.to_string(),
181        version: BlueprintVersion::default(),
182    };
183
184    // Generate the new code substates
185    let (new_code_substate, new_vm_type_substate, code_hash) = {
186        let original_code = (NativeCodeId::ConsensusManagerCode2 as u64)
187            .to_be_bytes()
188            .to_vec();
189
190        let code_hash = CodeHash::from_hash(hash(&original_code));
191        let code_substate = PackageCodeOriginalCodeV1 {
192            code: original_code,
193        }
194        .into_versioned()
195        .into_locked_substate();
196        let vm_type_substate = PackageCodeVmTypeV1 {
197            vm_type: VmType::Native,
198        }
199        .into_versioned()
200        .into_locked_substate();
201        (
202            scrypto_encode(&code_substate).unwrap(),
203            scrypto_encode(&vm_type_substate).unwrap(),
204            code_hash,
205        )
206    };
207
208    // Generate the new schema substate
209    let (
210        new_schema_substate,
211        get_current_time_input_v2_type_id,
212        compare_current_time_input_v2_type_id,
213        new_schema_hash,
214    ) = {
215        let mut aggregator = TypeAggregator::<ScryptoCustomTypeKind>::new();
216        let get_current_time_input_v2 =
217            aggregator.add_child_type_and_descendents::<ConsensusManagerGetCurrentTimeInputV2>();
218        let compare_current_time_input_v2 = aggregator
219            .add_child_type_and_descendents::<ConsensusManagerCompareCurrentTimeInputV2>();
220        let schema = generate_full_schema(aggregator);
221        let schema_hash = schema.generate_schema_hash();
222        let schema_substate = schema.into_locked_substate();
223        (
224            scrypto_encode(&schema_substate).unwrap(),
225            get_current_time_input_v2,
226            compare_current_time_input_v2,
227            schema_hash,
228        )
229    };
230
231    // Generate the blueprint definition substate updates
232    let updated_bp_definition_substate = {
233        let versioned_definition: VersionedPackageBlueprintVersionDefinition = reader
234            .read_object_collection_entry(
235                &consensus_mgr_pkg_node_id,
236                ObjectModuleId::Main,
237                ObjectCollectionKey::KeyValue(
238                    PackageCollection::BlueprintVersionDefinitionKeyValue.collection_index(),
239                    &bp_version_key,
240                ),
241            )
242            .unwrap()
243            .unwrap();
244
245        let mut definition = versioned_definition.fully_update_and_into_latest_version();
246
247        let export = definition
248            .function_exports
249            .get_mut(CONSENSUS_MANAGER_GET_CURRENT_TIME_IDENT)
250            .unwrap();
251        export.code_hash = code_hash;
252        let function_schema = definition
253            .interface
254            .functions
255            .get_mut(CONSENSUS_MANAGER_GET_CURRENT_TIME_IDENT)
256            .unwrap();
257        function_schema.input = BlueprintPayloadDef::Static(ScopedTypeId(
258            new_schema_hash,
259            get_current_time_input_v2_type_id,
260        ));
261
262        let export = definition
263            .function_exports
264            .get_mut(CONSENSUS_MANAGER_COMPARE_CURRENT_TIME_IDENT)
265            .unwrap();
266        export.code_hash = code_hash;
267        let function_schema = definition
268            .interface
269            .functions
270            .get_mut(CONSENSUS_MANAGER_COMPARE_CURRENT_TIME_IDENT)
271            .unwrap();
272        function_schema.input = BlueprintPayloadDef::Static(ScopedTypeId(
273            new_schema_hash,
274            compare_current_time_input_v2_type_id,
275        ));
276
277        scrypto_encode(
278            &PackageBlueprintVersionDefinitionVersions::V1(definition)
279                .into_versioned()
280                .into_locked_substate(),
281        )
282        .unwrap()
283    };
284
285    let bp_definition_partition_num = reader
286        .get_partition_of_collection(
287            &consensus_mgr_pkg_node_id,
288            ObjectModuleId::Main,
289            PackageCollection::BlueprintVersionDefinitionKeyValue.collection_index(),
290        )
291        .unwrap();
292
293    let code_vm_type_partition_num = reader
294        .get_partition_of_collection(
295            &consensus_mgr_pkg_node_id,
296            ObjectModuleId::Main,
297            PackageCollection::CodeVmTypeKeyValue.collection_index(),
298        )
299        .unwrap();
300
301    let code_partition_num = reader
302        .get_partition_of_collection(
303            &consensus_mgr_pkg_node_id,
304            ObjectModuleId::Main,
305            PackageCollection::CodeOriginalCodeKeyValue.collection_index(),
306        )
307        .unwrap();
308
309    let schema_partition_num = reader
310        .get_partition_of_collection(
311            &consensus_mgr_pkg_node_id,
312            ObjectModuleId::Main,
313            PackageCollection::SchemaKeyValue.collection_index(),
314        )
315        .unwrap();
316
317    StateUpdates {
318        by_node: indexmap!(
319            consensus_mgr_pkg_node_id => NodeStateUpdates::Delta {
320                by_partition: indexmap! {
321                    bp_definition_partition_num => PartitionStateUpdates::Delta {
322                        by_substate: indexmap! {
323                            SubstateKey::Map(scrypto_encode(&bp_version_key).unwrap()) => DatabaseUpdate::Set(
324                                updated_bp_definition_substate
325                            )
326                        }
327                    },
328                    code_vm_type_partition_num => PartitionStateUpdates::Delta {
329                        by_substate: indexmap! {
330                            SubstateKey::Map(scrypto_encode(&code_hash).unwrap()) => DatabaseUpdate::Set(new_vm_type_substate)
331                        }
332                    },
333                    code_partition_num => PartitionStateUpdates::Delta {
334                        by_substate: indexmap! {
335                            SubstateKey::Map(scrypto_encode(&code_hash).unwrap()) => DatabaseUpdate::Set(new_code_substate)
336                        }
337                    },
338                    schema_partition_num => PartitionStateUpdates::Delta {
339                        by_substate: indexmap! {
340                            SubstateKey::Map(scrypto_encode(&new_schema_hash).unwrap()) => DatabaseUpdate::Set(new_schema_substate)
341                        }
342                    }
343                }
344            }
345        ),
346    }
347}
348
349fn generate_vm_boot_for_bls128_and_keccak256_state_updates() -> StateUpdates {
350    StateUpdates::empty().set_substate(
351        TRANSACTION_TRACKER,
352        BOOT_LOADER_PARTITION,
353        BootLoaderField::VmBoot,
354        VmBoot::V1 {
355            scrypto_version: ScryptoVmVersion::crypto_utils_v1().into(),
356        },
357    )
358}
359
360/// Generates the state updates required to update the pool package from the v1.0 to the v1.1
361/// logic. No schema changes took place, just a change of logic. It produces the following
362/// updates:
363///
364/// * Removes the old code_hash => vm_type substate.
365/// * Adds a new code_hash => vm_type substate.
366/// * Removes the old code_hash => original_code substate.
367/// * Adds a new code_hash => original_code substate.
368/// * Updates the function exports in the blueprint definitions to point to the new code hash.
369fn generate_pool_math_precision_fix_state_updates<S: SubstateDatabase + ?Sized>(
370    db: &S,
371) -> StateUpdates {
372    let reader = SystemDatabaseReader::new(db);
373
374    let pool_package_node_id = POOL_PACKAGE.into_node_id();
375
376    // The old and new code hashes
377    let old_code_id = NativeCodeId::PoolCode1;
378    let new_code_id = NativeCodeId::PoolCode2;
379
380    let old_code = (old_code_id as u64).to_be_bytes().to_vec();
381    let new_code = (new_code_id as u64).to_be_bytes().to_vec();
382
383    let old_code_hash = CodeHash::from_hash(hash(&old_code));
384    let new_code_hash = CodeHash::from_hash(hash(&new_code));
385
386    // New code substate created from the new code
387    let new_code_substate = PackageCodeOriginalCodeV1 { code: new_code }
388        .into_versioned()
389        .into_payload()
390        .into_locked_substate();
391
392    // New VM substate, which we will map the new code hash to.
393    let new_vm_type_substate = PackageCodeVmTypeV1 {
394        vm_type: VmType::Native,
395    }
396    .into_versioned()
397    .into_payload()
398    .into_locked_substate();
399
400    // Update the function exports in the blueprint definition.
401    let [(one_resource_pool_blueprint_key, one_resource_pool_blueprint_definition), (two_resource_pool_blueprint_key, two_resource_pool_blueprint_definition), (multi_resource_pool_blueprint_key, multi_resource_pool_blueprint_definition)] =
402        [
403            ONE_RESOURCE_POOL_BLUEPRINT_IDENT,
404            TWO_RESOURCE_POOL_BLUEPRINT_IDENT,
405            MULTI_RESOURCE_POOL_BLUEPRINT_IDENT,
406        ]
407        .map(|blueprint_name| {
408            let blueprint_version_key = BlueprintVersionKey {
409                blueprint: blueprint_name.to_owned(),
410                version: BlueprintVersion::default(),
411            };
412
413            let versioned_definition: VersionedPackageBlueprintVersionDefinition = reader
414                .read_object_collection_entry(
415                    &pool_package_node_id,
416                    ObjectModuleId::Main,
417                    ObjectCollectionKey::KeyValue(
418                        PackageCollection::BlueprintVersionDefinitionKeyValue.collection_index(),
419                        &blueprint_version_key,
420                    ),
421                )
422                .unwrap()
423                .unwrap();
424            let mut blueprint_definition =
425                versioned_definition.fully_update_and_into_latest_version();
426
427            for (_, export) in blueprint_definition.function_exports.iter_mut() {
428                export.code_hash = new_code_hash
429            }
430
431            (
432                blueprint_version_key,
433                PackageBlueprintVersionDefinitionVersions::V1(blueprint_definition)
434                    .into_versioned()
435                    .into_payload()
436                    .into_locked_substate(),
437            )
438        });
439
440    let original_code_partition_number = reader
441        .get_partition_of_collection(
442            &pool_package_node_id,
443            ObjectModuleId::Main,
444            PackageCollection::CodeOriginalCodeKeyValue.collection_index(),
445        )
446        .unwrap();
447
448    let code_vm_type_partition_number = reader
449        .get_partition_of_collection(
450            &pool_package_node_id,
451            ObjectModuleId::Main,
452            PackageCollection::CodeVmTypeKeyValue.collection_index(),
453        )
454        .unwrap();
455
456    let blueprint_definition_partition_number = reader
457        .get_partition_of_collection(
458            &pool_package_node_id,
459            ObjectModuleId::Main,
460            PackageCollection::BlueprintVersionDefinitionKeyValue.collection_index(),
461        )
462        .unwrap();
463
464    StateUpdates {
465        by_node: indexmap! {
466            pool_package_node_id => NodeStateUpdates::Delta {
467                by_partition: indexmap! {
468                    original_code_partition_number => PartitionStateUpdates::Delta {
469                        by_substate: indexmap! {
470                            SubstateKey::Map(scrypto_encode(&old_code_hash).unwrap())
471                                => DatabaseUpdate::Delete,
472                            SubstateKey::Map(scrypto_encode(&new_code_hash).unwrap())
473                                => DatabaseUpdate::Set(scrypto_encode(&new_code_substate).unwrap()),
474                        }
475                    },
476                    code_vm_type_partition_number => PartitionStateUpdates::Delta {
477                        by_substate: indexmap! {
478                            SubstateKey::Map(scrypto_encode(&old_code_hash).unwrap())
479                                => DatabaseUpdate::Delete,
480                            SubstateKey::Map(scrypto_encode(&new_code_hash).unwrap())
481                                => DatabaseUpdate::Set(scrypto_encode(&new_vm_type_substate).unwrap()),
482                        }
483                    },
484                    blueprint_definition_partition_number => PartitionStateUpdates::Delta {
485                        by_substate: indexmap! {
486                            SubstateKey::Map(scrypto_encode(&one_resource_pool_blueprint_key).unwrap())
487                                => DatabaseUpdate::Set(scrypto_encode(&one_resource_pool_blueprint_definition).unwrap()),
488                            SubstateKey::Map(scrypto_encode(&two_resource_pool_blueprint_key).unwrap())
489                                => DatabaseUpdate::Set(scrypto_encode(&two_resource_pool_blueprint_definition).unwrap()),
490                            SubstateKey::Map(scrypto_encode(&multi_resource_pool_blueprint_key).unwrap())
491                                => DatabaseUpdate::Set(scrypto_encode(&multi_resource_pool_blueprint_definition).unwrap()),
492                        }
493                    }
494                }
495            }
496        },
497    }
498}