Merge branch 'perm-runtime-510' into perm-client-v0.5.2

This commit is contained in:
Steve Degosserie 2025-11-07 20:47:04 +01:00
commit f65385cee1
No known key found for this signature in database
GPG key ID: 9455A9F1AD80CE80
23 changed files with 216 additions and 30 deletions

1
operator/Cargo.lock generated
View file

@ -3171,6 +3171,7 @@ dependencies = [
"pallet-authorship",
"pallet-balances",
"pallet-evm",
"pallet-evm-chain-id",
"pallet-evm-precompile-proxy",
"pallet-migrations",
"pallet-safe-mode",

View file

@ -3,7 +3,7 @@ use sc_service::ChainType;
use super::ChainSpec;
const EVM_CHAIN_ID: u64 = 1289;
const EVM_CHAIN_ID: u64 = 55930;
const SS58_FORMAT: u16 = EVM_CHAIN_ID as u16;
const TOKEN_DECIMALS: u8 = 18;
const TOKEN_SYMBOL: &str = "HAVE";

View file

@ -3,10 +3,10 @@ use sc_service::ChainType;
use super::ChainSpec;
const EVM_CHAIN_ID: u64 = 1283;
const EVM_CHAIN_ID: u64 = 55932;
const SS58_FORMAT: u16 = EVM_CHAIN_ID as u16;
const TOKEN_DECIMALS: u8 = 18;
const TOKEN_SYMBOL: &str = "HAVE";
const TOKEN_SYMBOL: &str = "STAGE";
pub fn development_chain_spec() -> Result<ChainSpec, String> {
// Give the token a unit name and decimal places

View file

@ -3,10 +3,10 @@ use sc_service::ChainType;
use super::ChainSpec;
const EVM_CHAIN_ID: u64 = 1288;
const EVM_CHAIN_ID: u64 = 55931;
const SS58_FORMAT: u16 = EVM_CHAIN_ID as u16;
const TOKEN_DECIMALS: u8 = 18;
const TOKEN_SYMBOL: &str = "HAVE";
const TOKEN_SYMBOL: &str = "MOCK";
pub fn development_chain_spec() -> Result<ChainSpec, String> {
// Give the token a unit name and decimal places

View file

@ -15,6 +15,7 @@ pallet-authorship = { workspace = true }
pallet-balances = { workspace = true }
pallet-timestamp = { workspace = true }
pallet-evm = { workspace = true }
pallet-evm-chain-id = { workspace = true }
pallet-evm-precompile-proxy = { workspace = true }
pallet-migrations = { workspace = true }
pallet-safe-mode = { workspace = true }
@ -40,6 +41,7 @@ std = [
"pallet-balances/std",
"pallet-timestamp/std",
"pallet-evm/std",
"pallet-evm-chain-id/std",
"pallet-evm-precompile-proxy/std",
"pallet-migrations/std",
"pallet-safe-mode/std",

View file

@ -32,6 +32,101 @@ pub type MigrationStatusHandler = ();
/// Default handler triggered on migration failures.
pub type FailedMigrationHandler = 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<T, const NEW_CHAIN_ID: u64>(PhantomData<T>);
impl<T, const NEW_CHAIN_ID: u64> SteppedMigration for EvmChainIdMigration<T, NEW_CHAIN_ID>
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<Self::Cursor>,
meter: &mut WeightMeter,
) -> Result<Option<Self::Cursor>, 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::<T>::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<Vec<u8>, sp_runtime::TryRuntimeError> {
let old_chain_id = pallet_evm_chain_id::ChainId::<T>::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<u8>) -> 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::<T>::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;
@ -232,6 +327,7 @@ mod tests {
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
Timestamp: pallet_timestamp::{Pallet, Call, Storage},
EVM: pallet_evm::{Pallet, Call, Storage, Config<T>, Event<T>},
EvmChainId: pallet_evm_chain_id::{Pallet, Storage},
}
);
@ -280,6 +376,8 @@ mod tests {
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) {
@ -375,4 +473,77 @@ mod tests {
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::<TestRuntime>::default()
.build_storage()
.unwrap();
pallet_balances::GenesisConfig::<TestRuntime>::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::<TestRuntime>::put(OLD_CHAIN_ID);
assert_eq!(
pallet_evm_chain_id::ChainId::<TestRuntime>::get(),
OLD_CHAIN_ID
);
// Run the migration
let mut meter = WeightMeter::with_limit(Weight::MAX);
let result = EvmChainIdMigration::<TestRuntime, NEW_CHAIN_ID>::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::<TestRuntime>::get(),
NEW_CHAIN_ID
);
});
}
#[test]
fn evm_chain_id_migration_is_idempotent() {
use super::evm_chain_id::EvmChainIdMigration;
let mut storage = frame_system::GenesisConfig::<TestRuntime>::default()
.build_storage()
.unwrap();
pallet_balances::GenesisConfig::<TestRuntime>::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::<TestRuntime, NEW_CHAIN_ID>::step(None, &mut meter);
let mut meter = WeightMeter::with_limit(Weight::MAX);
let result2 = EvmChainIdMigration::<TestRuntime, NEW_CHAIN_ID>::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::<TestRuntime>::get(),
NEW_CHAIN_ID
);
});
}
}

View file

@ -164,7 +164,7 @@ use datahaven_runtime_common::benchmarking::BenchmarkHelper;
pub(crate) use crate::weights as mainnet_weights;
const EVM_CHAIN_ID: u64 = 1289;
const EVM_CHAIN_ID: u64 = 55930;
const SS58_FORMAT: u16 = EVM_CHAIN_ID as u16;
//╔═══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗

View file

@ -16,7 +16,7 @@ use sp_core::{ecdsa, Pair, Public};
use sp_genesis_builder::{self, PresetId};
use sp_runtime::traits::{IdentifyAccount, Verify};
const MAINNET_EVM_CHAIN_ID: u64 = 1289;
const MAINNET_EVM_CHAIN_ID: u64 = 55930;
// Returns the genesis config presets populated with given parameters.
fn testnet_genesis(

View file

@ -123,7 +123,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
// `spec_version`, and `authoring_version` are the same between Wasm and native.
// This value is set to 200 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
// the compatible custom types.
spec_version: 500,
spec_version: 510,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,

View file

@ -1,7 +1,7 @@
#[cfg(all(feature = "std", feature = "metadata-hash"))]
fn main() {
substrate_wasm_builder::WasmBuilder::init_with_defaults()
.enable_metadata_hash("HAVE", 18)
.enable_metadata_hash("STAGE", 18)
.build();
}

View file

@ -164,7 +164,7 @@ use datahaven_runtime_common::benchmarking::BenchmarkHelper;
pub(crate) use crate::weights as stagenet_weights;
const EVM_CHAIN_ID: u64 = 1283;
const EVM_CHAIN_ID: u64 = 55932;
const SS58_FORMAT: u16 = EVM_CHAIN_ID as u16;
//╔═══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
@ -855,7 +855,13 @@ 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<Runtime>;
type Migrations = (
datahaven_runtime_common::migrations::MultiBlockMigrationList<Runtime>,
datahaven_runtime_common::migrations::evm_chain_id::EvmChainIdMigration<
Runtime,
EVM_CHAIN_ID,
>,
);
#[cfg(feature = "runtime-benchmarks")]
type Migrations = datahaven_runtime_common::migrations::MultiBlockMigrationList;
type CursorMaxLen = MigrationCursorMaxLen;

View file

@ -16,7 +16,7 @@ use sp_core::{ecdsa, Pair, Public};
use sp_genesis_builder::{self, PresetId};
use sp_runtime::traits::{IdentifyAccount, Verify};
const STAGENET_EVM_CHAIN_ID: u64 = 1283;
const STAGENET_EVM_CHAIN_ID: u64 = 55932;
// Returns the genesis config presets populated with given parameters.
fn testnet_genesis(

View file

@ -126,7 +126,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
// `spec_version`, and `authoring_version` are the same between Wasm and native.
// This value is set to 200 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
// the compatible custom types.
spec_version: 500,
spec_version: 510,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,

View file

@ -41,11 +41,11 @@ pub struct NativeErc20Metadata;
impl Erc20Metadata for NativeErc20Metadata {
fn name() -> &'static str {
"HAVE"
"STAGE"
}
fn symbol() -> &'static str {
"HAVE"
"STAGE"
}
fn decimals() -> u8 {

View file

@ -205,8 +205,8 @@ pub fn root_origin() -> RuntimeOrigin {
#[allow(dead_code)]
pub fn datahaven_token_metadata() -> snowbridge_core::AssetMetadata {
snowbridge_core::AssetMetadata {
name: b"HAVE".to_vec().try_into().unwrap(),
symbol: b"wHAVE".to_vec().try_into().unwrap(),
name: b"STAGE".to_vec().try_into().unwrap(),
symbol: b"wSTAGE".to_vec().try_into().unwrap(),
decimals: 18,
}
}

View file

@ -1,7 +1,7 @@
#[cfg(all(feature = "std", feature = "metadata-hash"))]
fn main() {
substrate_wasm_builder::WasmBuilder::init_with_defaults()
.enable_metadata_hash("HAVE", 18)
.enable_metadata_hash("MOCK", 18)
.build();
}

View file

@ -164,7 +164,7 @@ use bridge_hub_common::AggregateMessageOrigin;
#[cfg(feature = "runtime-benchmarks")]
use datahaven_runtime_common::benchmarking::BenchmarkHelper;
const EVM_CHAIN_ID: u64 = 1288;
const EVM_CHAIN_ID: u64 = 55931;
const SS58_FORMAT: u16 = EVM_CHAIN_ID as u16;
//╔═══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
@ -858,7 +858,13 @@ 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<Runtime>;
type Migrations = (
datahaven_runtime_common::migrations::MultiBlockMigrationList<Runtime>,
datahaven_runtime_common::migrations::evm_chain_id::EvmChainIdMigration<
Runtime,
EVM_CHAIN_ID,
>,
);
#[cfg(feature = "runtime-benchmarks")]
type Migrations = datahaven_runtime_common::migrations::MultiBlockMigrationList;
type CursorMaxLen = MigrationCursorMaxLen;

View file

@ -16,7 +16,7 @@ use sp_core::{ecdsa, Pair, Public};
use sp_genesis_builder::{self, PresetId};
use sp_runtime::traits::{IdentifyAccount, Verify};
const TESTNET_EVM_CHAIN_ID: u64 = 1288;
const TESTNET_EVM_CHAIN_ID: u64 = 55931;
// Returns the genesis config presets populated with given parameters.
fn testnet_genesis(

View file

@ -122,7 +122,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
// `spec_version`, and `authoring_version` are the same between Wasm and native.
// This value is set to 200 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use
// the compatible custom types.
spec_version: 500,
spec_version: 510,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,

View file

@ -41,11 +41,11 @@ pub struct NativeErc20Metadata;
impl Erc20Metadata for NativeErc20Metadata {
fn name() -> &'static str {
"HAVE"
"MOCK"
}
fn symbol() -> &'static str {
"HAVE"
"MOCK"
}
fn decimals() -> u8 {

View file

@ -205,8 +205,8 @@ pub fn root_origin() -> RuntimeOrigin {
#[allow(dead_code)]
pub fn datahaven_token_metadata() -> snowbridge_core::AssetMetadata {
snowbridge_core::AssetMetadata {
name: b"HAVE".to_vec().try_into().unwrap(),
symbol: b"wHAVE".to_vec().try_into().unwrap(),
name: b"MOCK".to_vec().try_into().unwrap(),
symbol: b"wMOCK".to_vec().try_into().unwrap(),
decimals: 18,
}
}

Binary file not shown.

View file

@ -146,8 +146,8 @@ describe("Native Token Transfer", () => {
sender: { type: "V5", value: { parents: 0, interior: { type: "Here", value: undefined } } },
asset_id: { type: "V5", value: { parents: 0, interior: { type: "Here", value: undefined } } },
metadata: {
name: Binary.fromText("HAVE"),
symbol: Binary.fromText("wHAVE"),
name: Binary.fromText("STAGE"),
symbol: Binary.fromText("wSTAGE"),
decimals: 18
}
});
@ -220,8 +220,8 @@ describe("Native Token Transfer", () => {
}) as Promise<number>
]);
expect(tokenName).toBe("HAVE");
expect(tokenSymbol).toBe("wHAVE");
expect(tokenName).toBe("STAGE");
expect(tokenSymbol).toBe("wSTAGE");
expect(tokenDecimals).toBe(18);
}, 300_000); // 5 minute timeout for registration