From 92d3c42f79cc54dd2d5d046fcd8e9730b3ccd0a1 Mon Sep 17 00:00:00 2001 From: Steve Degosserie <723552+stiiifff@users.noreply.github.com> Date: Tue, 25 Nov 2025 18:44:06 +0100 Subject: [PATCH] =?UTF-8?q?chore:=20=E2=99=BB=EF=B8=8F=20=20Remove=20execu?= =?UTF-8?q?ted=20runtime=20migrations=20(#318)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Removes old runtime migrations that have already been executed on Stagenet and Testnet environments, reducing code complexity and maintenance burden. ## Changes ### Migration Cleanup - **Removed `evm_alias::EvmAliasMigration`** (~532 lines) - Multi-block migration that renamed the Frontier EVM pallet alias from `Evm` to `EVM` - Migrated AccountCodes, AccountCodesMetadata, and AccountStorages - **Removed `evm_chain_id::EvmChainIdMigration`** - Single-step migration that updated stored EVM chain IDs to match new configuration - Applied to testnet (55931) and stagenet (55932) ### Runtime Updates - **Simplified `MultiBlockMigrationList`** to empty tuple `()` in `runtime/common/src/migrations.rs` - **Updated all runtime configs** to use simplified migration list: - `runtime/mainnet/src/configs/mod.rs` - `runtime/stagenet/src/configs/mod.rs` - `runtime/testnet/src/configs/mod.rs` - Removed `Runtime` type parameter from migration configurations ### What Remains - `pallet_migrations` infrastructure stays in place for future migrations - Migration test file (`mainnet/tests/migrations.rs`) preserved for testing pallet administrative functions - Configuration types and constants (cursor/identifier lengths, handlers) ## Impact - **Code reduction**: 532 lines removed - **No functional change**: These migrations have already executed successfully - **Future-ready**: Migration infrastructure remains for new migrations when needed Co-authored-by: Claude Co-authored-by: Ahmad Kaouk <56095276+ahmadkaouk@users.noreply.github.com> --- operator/runtime/common/src/migrations.rs | 554 ++----------------- operator/runtime/mainnet/src/configs/mod.rs | 2 +- operator/runtime/stagenet/src/configs/mod.rs | 8 +- operator/runtime/testnet/src/configs/mod.rs | 8 +- 4 files changed, 40 insertions(+), 532 deletions(-) diff --git a/operator/runtime/common/src/migrations.rs b/operator/runtime/common/src/migrations.rs index 6b342519..3eed8295 100644 --- a/operator/runtime/common/src/migrations.rs +++ b/operator/runtime/common/src/migrations.rs @@ -18,6 +18,42 @@ //! //! The types and constants defined here keep the pallet configuration consistent between //! networks while leaving each runtime free to decide which migrations should actually run. +//! +//! ## Migration History +//! +//! This section documents migrations that have been executed and subsequently removed from the +//! codebase. The migration framework tracks completed migrations on-chain, preventing re-execution. +//! +//! ### Executed Migrations (Code Removed) +//! +//! #### 1. EVM Pallet Alias Migration +//! - **Migration ID**: `datahaven-evm-mbm` (version 0 → 1) +//! - **Type**: Multi-block stepped migration +//! - **Original PR**: [#213](https://github.com/datahaven-xyz/datahaven/pull/213) +//! - **Intent**: Fixed `eth_getCode` and other Ethereum RPC calls by renaming the pallet_evm +//! FRAME alias from `Evm` to `EVM`. Frontier's `StorageOverrideHandler` hardcodes the storage +//! prefix as `twox_128("EVM")`, but our runtimes used `Evm`, causing all contract bytecode +//! lookups to fail. This migration realigned the storage prefix with Frontier's expectations. +//! - **Storage Migrated**: +//! - `Evm::AccountCodes` → `EVM::AccountCodes` +//! - `Evm::AccountCodesMetadata` → `EVM::AccountCodesMetadata` +//! - `Evm::AccountStorages` → `EVM::AccountStorages` +//! - **Execution**: Successfully executed on Testnet and Stagenet (39 keys migrated, <0.1% block weight) +//! - **Removed**: 2025-01 ([PR #318](https://github.com/datahaven-xyz/datahaven/pull/318)) +//! +//! #### 2. EVM Chain ID Migration +//! - **Migration ID**: `dh-evm-chain-id-v1` (version 0 → 1) +//! - **Type**: Single-step migration +//! - **Original PR**: [#280](https://github.com/datahaven-xyz/datahaven/pull/280) +//! - **Intent**: Updated chain IDs for all three DataHaven environments to their final assigned +//! values. The stored EVM chain ID in `pallet_evm_chain_id::ChainId` was migrated to match +//! the configured constants after chain ID assignments were finalized. +//! - **Networks**: +//! - Mainnet: Chain ID 55930 (no migration needed, set at genesis) +//! - Testnet: Migrated to chain ID 55931 +//! - Stagenet: Migrated to chain ID 55932 +//! - **Execution**: Successfully executed on Testnet and Stagenet +//! - **Removed**: 2025-01 ([PR #318](https://github.com/datahaven-xyz/datahaven/pull/318)) use frame_support::pallet_prelude::*; @@ -36,7 +72,7 @@ pub type MigrationIdentifierMaxLen = ConstU32; /// The tuple starts empty and can be extended with concrete migrations over time. Keeping it in a /// shared module reduces duplication once we coordinate migrations across networks. #[cfg(not(feature = "runtime-benchmarks"))] -pub type MultiBlockMigrationList = (evm_alias::EvmAliasMigration,); +pub type MultiBlockMigrationList = (); /// During benchmarking we switch to the pallet-provided mocked migrations to guarantee success. #[cfg(feature = "runtime-benchmarks")] @@ -58,519 +94,3 @@ pub type FailedMigrationHandler = SafeMode, frame_support::migrations::FreezeChainOnFailedMigration, >; - -/// Multi-block migration for updating the EVM chain ID to the new value. -pub mod evm_chain_id { - use core::marker::PhantomData; - use frame_support::{ - migrations::{MigrationId, SteppedMigration, SteppedMigrationError}, - pallet_prelude::*, - weights::WeightMeter, - }; - - #[cfg(feature = "try-runtime")] - use codec::Encode; - - /// Multi-block migration that updates the stored EVM chain ID to match the new configuration. - pub struct EvmChainIdMigration(PhantomData); - - impl SteppedMigration for EvmChainIdMigration - where - T: pallet_evm_chain_id::Config, - { - type Cursor = (); - type Identifier = MigrationId<20>; - - fn id() -> Self::Identifier { - MigrationId { - pallet_id: *b"dh-evm-chain-id-v1 ", - version_from: 0, - version_to: 1, - } - } - - fn step( - cursor: Option, - meter: &mut WeightMeter, - ) -> Result, SteppedMigrationError> { - // This migration completes in a single step - if cursor.is_some() { - return Ok(None); - } - - let required = T::DbWeight::get().reads_writes(1, 1); - if meter.try_consume(required).is_err() { - return Err(SteppedMigrationError::InsufficientWeight { required }); - } - - log::info!( - "🔄 [EVM Chain ID Migration] Updating chain ID to {}", - NEW_CHAIN_ID - ); - - // Update the chain ID storage - pallet_evm_chain_id::ChainId::::put(NEW_CHAIN_ID); - - log::info!( - "✅ [EVM Chain ID Migration] Successfully updated chain ID to {}", - NEW_CHAIN_ID - ); - - Ok(None) - } - - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { - let old_chain_id = pallet_evm_chain_id::ChainId::::get(); - log::info!( - "📋 [EVM Chain ID Migration] Current chain ID: {}", - old_chain_id - ); - Ok(old_chain_id.encode()) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { - use codec::Decode; - - let old_chain_id = - u64::decode(&mut &state[..]).map_err(|_| "Failed to decode old chain ID")?; - let new_chain_id = pallet_evm_chain_id::ChainId::::get(); - - log::info!( - "🔍 [EVM Chain ID Migration] Chain ID updated from {} to {}", - old_chain_id, - new_chain_id - ); - - if new_chain_id != NEW_CHAIN_ID { - return Err(sp_runtime::TryRuntimeError::Other( - "Chain ID was not updated correctly", - )); - } - - Ok(()) - } - } -} - -/// Multi-block migration for renaming the EVM pallet alias. -pub mod evm_alias { - use core::marker::PhantomData; - use frame_support::{ - migrations::{MigrationId, SteppedMigration, SteppedMigrationError}, - pallet_prelude::*, - weights::WeightMeter, - BoundedVec, StorageHasher, - }; - use sp_io::storage; - use sp_std::{convert::TryFrom, vec::Vec}; - - #[cfg(feature = "try-runtime")] - use sp_std::collections::btree_map::BTreeMap; - - /// Multi-block migration that renames the Frontier EVM pallet alias from `Evm` to `EVM`. - pub struct EvmAliasMigration(PhantomData); - - impl SteppedMigration for EvmAliasMigration - where - T: pallet_evm::Config, - { - type Cursor = BoundedVec>; - type Identifier = MigrationId<17>; - - fn id() -> Self::Identifier { - MigrationId { - pallet_id: *b"datahaven-evm-mbm", - version_from: 0, - version_to: 1, - } - } - - fn step( - cursor: Option, - meter: &mut WeightMeter, - ) -> Result, SteppedMigrationError> { - if cursor.is_none() { - log::info!( - "🚀 [EVM Migration] Starting pallet alias migration from 'Evm' to 'EVM'" - ); - } - - let old_prefix = Twox128::hash(b"Evm"); - let new_prefix = Twox128::hash(b"EVM"); - let mut current_key: Vec = cursor - .map(Into::into) - .unwrap_or_else(|| old_prefix.to_vec()); - let mut processed = 0u32; - let required = T::DbWeight::get().reads_writes(1, 2); - - loop { - let next_key = match storage::next_key(¤t_key) { - Some(next) if next.starts_with(&old_prefix) => next, - _ => { - log::info!( - "✅ [EVM Migration] Completed! Processed {} keys in this step", - processed - ); - return Ok(None); - } - }; - - if meter.try_consume(required).is_err() { - if processed == 0 { - log::warn!( - "⚠️ [EVM Migration] Insufficient weight for even one key migration" - ); - return Err(SteppedMigrationError::InsufficientWeight { required }); - } - log::info!( - "⏸️ [EVM Migration] Pausing after migrating {} keys (weight limit reached)", - processed - ); - return BoundedVec::try_from(current_key) - .map(Some) - .map_err(|_| SteppedMigrationError::Failed); - } - - if let Some(value) = storage::get(&next_key) { - let mut new_key = Vec::with_capacity(next_key.len()); - new_key.extend_from_slice(&new_prefix); - new_key.extend_from_slice(&next_key[16..]); - storage::set(&new_key, &value); - } - storage::clear(&next_key); - - processed = processed.saturating_add(1); - current_key = next_key; - } - } - - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { - use codec::Encode; - - let storage_prefix = |item: &[u8]| { - let mut key = [0u8; 32]; - key[0..16].copy_from_slice(&Twox128::hash(b"Evm")); - key[16..32].copy_from_slice(&Twox128::hash(item)); - key - }; - - let mut counts = BTreeMap::new(); - - for name in [ - b"AccountCodes" as &[u8], - b"AccountCodesMetadata", - b"AccountStorages", - ] { - let count = count_keys(&storage_prefix(name)); - counts.insert(name.to_vec(), count.encode()); - } - - Ok(counts.encode()) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { - use codec::Decode; - - let snapshot: BTreeMap, Vec> = - Decode::decode(&mut &state[..]).expect("Failed to decode snapshot"); - - let old_storage = |item: &[u8]| { - let mut key = [0u8; 32]; - key[0..16].copy_from_slice(&Twox128::hash(b"Evm")); - key[16..32].copy_from_slice(&Twox128::hash(item)); - key - }; - - let new_storage = |item: &[u8]| { - let mut key = [0u8; 32]; - key[0..16].copy_from_slice(&Twox128::hash(b"EVM")); - key[16..32].copy_from_slice(&Twox128::hash(item)); - key - }; - - for name in [ - b"AccountCodes" as &[u8], - b"AccountCodesMetadata", - b"AccountStorages", - ] { - let old_count = count_keys(&old_storage(name)); - assert_eq!(old_count, 0, "Old Evm prefix still present after migration"); - - let expected = snapshot - .get(name) - .and_then(|v| u32::decode(&mut &v[..]).ok()) - .unwrap_or(0); - let actual = count_keys(&new_storage(name)); - - assert_eq!(expected, actual, "Migrated entry count mismatch"); - } - - Ok(()) - } - } - - /// Helper function to count storage keys with a given prefix. - #[cfg(any(feature = "try-runtime", test))] - pub(crate) fn count_keys(prefix: &[u8]) -> u32 { - let mut count = 0u32; - let mut cursor = prefix.to_vec(); - loop { - match storage::next_key(&cursor) { - Some(next) if next.starts_with(prefix) => { - count = count.saturating_add(1); - cursor = next; - } - _ => break, - } - } - count - } -} - -#[cfg(test)] -mod tests { - use super::evm_alias::{count_keys, EvmAliasMigration}; - use codec::Encode; - use frame_support::{ - derive_impl, - migrations::SteppedMigration, - parameter_types, - weights::{constants::RocksDbWeight, Weight, WeightMeter}, - StorageHasher, Twox128, - }; - use pallet_evm::AccountCodes; - use sp_core::{H160, H256, U256}; - use sp_io::storage; - use sp_runtime::BuildStorage; - use sp_std::vec; - - frame_support::construct_runtime!( - pub enum TestRuntime { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - Timestamp: pallet_timestamp::{Pallet, Call, Storage}, - EVM: pallet_evm::{Pallet, Call, Storage, Config, Event}, - EvmChainId: pallet_evm_chain_id::{Pallet, Storage}, - } - ); - - parameter_types! { - pub const BlockHashCount: u64 = 250; - pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1024, 0)); - } - - #[derive_impl(frame_system::config_preludes::SolochainDefaultConfig as frame_system::DefaultConfig)] - impl frame_system::Config for TestRuntime { - type Nonce = u64; - type Block = frame_system::mocking::MockBlock; - type BlockHashCount = BlockHashCount; - type AccountData = pallet_balances::AccountData; - } - - parameter_types! { - pub const ExistentialDeposit: u64 = 0; - } - - #[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] - impl pallet_balances::Config for TestRuntime { - type RuntimeHoldReason = (); - type Balance = u64; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - } - - #[derive_impl(pallet_timestamp::config_preludes::TestDefaultConfig)] - impl pallet_timestamp::Config for TestRuntime {} - - parameter_types! { - pub MockPrecompiles: MockPrecompileSet = MockPrecompileSet; - } - - #[derive_impl(pallet_evm::config_preludes::TestDefaultConfig)] - impl pallet_evm::Config for TestRuntime { - type AccountProvider = pallet_evm::FrameSystemAccountProvider; - type FeeCalculator = FixedGasPrice; - type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; - type Currency = Balances; - type Runner = pallet_evm::runner::stack::Runner; - type Timestamp = Timestamp; - type PrecompilesType = MockPrecompileSet; - type PrecompilesValue = MockPrecompiles; - } - - impl pallet_evm_chain_id::Config for TestRuntime {} - - pub struct FixedGasPrice; - impl pallet_evm::FeeCalculator for FixedGasPrice { - fn min_gas_price() -> (U256, Weight) { - (1_000_000_000u128.into(), Weight::from_parts(1_000, 0)) - } - } - - pub struct MockPrecompileSet; - impl pallet_evm::PrecompileSet for MockPrecompileSet { - fn execute( - &self, - _handle: &mut impl pallet_evm::PrecompileHandle, - ) -> Option { - None - } - - fn is_precompile(&self, _address: H160, _gas: u64) -> pallet_evm::IsPrecompileResult { - pallet_evm::IsPrecompileResult::Answer { - is_precompile: false, - extra_cost: 0, - } - } - } - - fn old_storage_prefix(item: &[u8]) -> [u8; 32] { - let mut key = [0u8; 32]; - key[0..16].copy_from_slice(&Twox128::hash(b"Evm")); - key[16..32].copy_from_slice(&Twox128::hash(item)); - key - } - - fn raw_key(storage_name: &[u8], address: H160, index: Option) -> Vec { - let mut key = old_storage_prefix(storage_name).to_vec(); - key.extend_from_slice(&sp_io::hashing::blake2_128(&address.encode())); - key.extend_from_slice(address.as_bytes()); - if let Some(idx) = index { - key.extend_from_slice(&sp_io::hashing::blake2_128(&idx.encode())); - key.extend_from_slice(idx.as_bytes()); - } - key - } - - #[test] - fn multi_block_evm_alias_migration_moves_all_entries() { - let mut storage = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap(); - pallet_balances::GenesisConfig::::default() - .assimilate_storage(&mut storage) - .unwrap(); - let mut ext = sp_io::TestExternalities::new(storage); - ext.execute_with(|| { - let addresses: Vec = (1u64..=3).map(H160::from_low_u64_be).collect(); - - for (idx, &address) in addresses.iter().enumerate() { - storage::set( - &raw_key(b"AccountCodes", address, None), - &vec![idx as u8; 3].encode(), - ); - storage::set( - &raw_key(b"AccountCodesMetadata", address, None), - &(42u64 + idx as u64, H256::repeat_byte(idx as u8)).encode(), - ); - storage::set( - &raw_key( - b"AccountStorages", - address, - Some(H256::repeat_byte(0xAA + idx as u8)), - ), - &H256::repeat_byte(idx as u8).encode(), - ); - } - - let mut cursor = None; - loop { - let mut meter = WeightMeter::with_limit(RocksDbWeight::get().reads_writes(1, 2)); - match EvmAliasMigration::::step(cursor, &mut meter) { - Ok(None) => break, - Ok(Some(next)) => cursor = Some(next), - Err(err) => panic!("migration failed: {:?}", err), - } - } - - for address in addresses { - assert!(!AccountCodes::::get(address).is_empty()); - } - - assert_eq!(count_keys(&old_storage_prefix(b"AccountCodes")[..]), 0); - assert_eq!( - count_keys(&old_storage_prefix(b"AccountCodesMetadata")[..]), - 0 - ); - assert_eq!(count_keys(&old_storage_prefix(b"AccountStorages")[..]), 0); - }); - } - - #[test] - fn evm_chain_id_migration_updates_storage() { - use super::evm_chain_id::EvmChainIdMigration; - - let mut storage = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap(); - pallet_balances::GenesisConfig::::default() - .assimilate_storage(&mut storage) - .unwrap(); - let mut ext = sp_io::TestExternalities::new(storage); - - ext.execute_with(|| { - // Set an old chain ID value - const OLD_CHAIN_ID: u64 = 12345; - const NEW_CHAIN_ID: u64 = 55931; - - pallet_evm_chain_id::ChainId::::put(OLD_CHAIN_ID); - assert_eq!( - pallet_evm_chain_id::ChainId::::get(), - OLD_CHAIN_ID - ); - - // Run the migration - let mut meter = WeightMeter::with_limit(Weight::MAX); - let result = EvmChainIdMigration::::step(None, &mut meter); - - // Verify migration succeeded and completed in one step - assert!(result.is_ok()); - assert_eq!(result.unwrap(), None); - - // Verify the chain ID was updated - assert_eq!( - pallet_evm_chain_id::ChainId::::get(), - NEW_CHAIN_ID - ); - }); - } - - #[test] - fn evm_chain_id_migration_is_idempotent() { - use super::evm_chain_id::EvmChainIdMigration; - - let mut storage = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap(); - pallet_balances::GenesisConfig::::default() - .assimilate_storage(&mut storage) - .unwrap(); - let mut ext = sp_io::TestExternalities::new(storage); - - ext.execute_with(|| { - const NEW_CHAIN_ID: u64 = 55932; - - // Run the migration twice - let mut meter = WeightMeter::with_limit(Weight::MAX); - let result1 = EvmChainIdMigration::::step(None, &mut meter); - - let mut meter = WeightMeter::with_limit(Weight::MAX); - let result2 = EvmChainIdMigration::::step(None, &mut meter); - - // Both should succeed - assert!(result1.is_ok()); - assert!(result2.is_ok()); - - // Chain ID should be set correctly - assert_eq!( - pallet_evm_chain_id::ChainId::::get(), - NEW_CHAIN_ID - ); - }); - } -} diff --git a/operator/runtime/mainnet/src/configs/mod.rs b/operator/runtime/mainnet/src/configs/mod.rs index 344b5154..fcbc5361 100644 --- a/operator/runtime/mainnet/src/configs/mod.rs +++ b/operator/runtime/mainnet/src/configs/mod.rs @@ -848,7 +848,7 @@ impl pallet_parameters::Config for Runtime { impl pallet_migrations::Config for Runtime { type RuntimeEvent = RuntimeEvent; #[cfg(not(feature = "runtime-benchmarks"))] - type Migrations = datahaven_runtime_common::migrations::MultiBlockMigrationList; + type Migrations = datahaven_runtime_common::migrations::MultiBlockMigrationList; #[cfg(feature = "runtime-benchmarks")] type Migrations = datahaven_runtime_common::migrations::MultiBlockMigrationList; type CursorMaxLen = MigrationCursorMaxLen; diff --git a/operator/runtime/stagenet/src/configs/mod.rs b/operator/runtime/stagenet/src/configs/mod.rs index 893d2feb..cc32e7d2 100644 --- a/operator/runtime/stagenet/src/configs/mod.rs +++ b/operator/runtime/stagenet/src/configs/mod.rs @@ -845,13 +845,7 @@ impl pallet_parameters::Config for Runtime { impl pallet_migrations::Config for Runtime { type RuntimeEvent = RuntimeEvent; #[cfg(not(feature = "runtime-benchmarks"))] - type Migrations = ( - datahaven_runtime_common::migrations::MultiBlockMigrationList, - datahaven_runtime_common::migrations::evm_chain_id::EvmChainIdMigration< - Runtime, - EVM_CHAIN_ID, - >, - ); + type Migrations = datahaven_runtime_common::migrations::MultiBlockMigrationList; #[cfg(feature = "runtime-benchmarks")] type Migrations = datahaven_runtime_common::migrations::MultiBlockMigrationList; type CursorMaxLen = MigrationCursorMaxLen; diff --git a/operator/runtime/testnet/src/configs/mod.rs b/operator/runtime/testnet/src/configs/mod.rs index 2f7bc6e7..3cac0126 100644 --- a/operator/runtime/testnet/src/configs/mod.rs +++ b/operator/runtime/testnet/src/configs/mod.rs @@ -848,13 +848,7 @@ impl pallet_parameters::Config for Runtime { impl pallet_migrations::Config for Runtime { type RuntimeEvent = RuntimeEvent; #[cfg(not(feature = "runtime-benchmarks"))] - type Migrations = ( - datahaven_runtime_common::migrations::MultiBlockMigrationList, - datahaven_runtime_common::migrations::evm_chain_id::EvmChainIdMigration< - Runtime, - EVM_CHAIN_ID, - >, - ); + type Migrations = datahaven_runtime_common::migrations::MultiBlockMigrationList; #[cfg(feature = "runtime-benchmarks")] type Migrations = datahaven_runtime_common::migrations::MultiBlockMigrationList; type CursorMaxLen = MigrationCursorMaxLen;