mirror of
https://github.com/datahaven-xyz/datahaven
synced 2026-05-24 09:50:01 +00:00
feat: ✨ Update chain IDs & native token tickers for all 3 environments (#280)
Update the 3 DataHaven environments' chain IDs & native token ticker as follows: * **Mainnet** * **Chain ID**: 55930 * **Ticker**: HAVE * **TestNet** * **Chain ID**: 55931 * **Ticker**: MOCK * **Stagenet** * **Chain ID**: 55932 * **Ticker**: STAGE The PR includes a storage migration for the Stagenet & Testnet environments, that are already live, to update the EVM Chain ID stored in the `pallet-evm-chain-id` pallet. Note: the token symbol will only be updated with the genesis config presets or newly generated chain specs. For already live networks, the existing chain spec must be updated (i.e. the tokenSymbol property changed) and used by all nodes in the network. This change in the chain spec will not alter the chain genesis so it safe to do (in the very early stages of the chain obviously). --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
parent
45cc9101ea
commit
a97f0547a9
20 changed files with 213 additions and 27 deletions
1
operator/Cargo.lock
generated
1
operator/Cargo.lock
generated
|
|
@ -3171,6 +3171,7 @@ dependencies = [
|
|||
"pallet-authorship",
|
||||
"pallet-balances",
|
||||
"pallet-evm",
|
||||
"pallet-evm-chain-id",
|
||||
"pallet-evm-precompile-proxy",
|
||||
"pallet-migrations",
|
||||
"pallet-safe-mode",
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
//╔═══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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.
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue