mirror of
https://github.com/datahaven-xyz/datahaven
synced 2026-05-24 09:50:01 +00:00
fix: change pallet_evm alias to EVM to fix eth_getCode (#213)
## Summary
- rename the FRAME alias for `pallet_evm` from `Evm` to `EVM` across the
mainnet, stagenet, and testnet runtimes
- adjust benchmarks, configuration modules, genesis builders, and
runtime tests to rely on the new alias
- keep precompile genesis setup and proxy/precompile tests aligned with
the updated names
## Context
Frontier’s `StorageOverrideHandler` (see
`fc_storage::StorageQuerier::account_code`) reads contract bytecode from
`pallet_evm::AccountCodes` using the constant `PALLET_EVM = b"EVM"` to
build the storage key:
`twox_128("EVM") ++ twox_128("AccountCodes") ++ …`
Our runtimes exported `pallet_evm` as `Evm`, so substrate stored
bytecode under the *camel-cased* prefix (`twox_128("Evm")`). Every call
that ultimately hits the storage override—including `eth_getCode`,
`eth_call`, and state queries during replay—therefore failed to locate
code for *any* account (deployed contracts and precompiles alike).
Renaming the alias to `EVM` realigns the storage prefix with Frontier’s
expectations so the override layers can pull bytecode correctly.
## Testing
- `cargo check -p datahaven-node`
- `cargo build --release -p datahaven-node`
- `eth_getCode 0x0000000000000000000000000000000000000802` → returns
`0x60006000fd`
## Storage Migration
Renaming a pallet alias changes the storage prefix for all pallet data.
Without migration, existing EVM data (smart contracts, account codes,
storage) would become inaccessible.
**Migration details:**
- **Type**: Multi-Block Migration (MBM)
- **Storage migrated**: `AccountCodes`, `AccountCodesMetadata`,
`AccountStorages`
- **Migration ID**: `datahaven-evm-mbm` (version 0 → 1)
**Testing the migration:**
```bash
# Build runtime with try-runtime
cargo build --release --features try-runtime -p
datahaven-stagenet-runtime
# Test against stagenet
try-runtime \
--runtime
./target/release/wbuild/datahaven-stagenet-runtime/datahaven_stagenet_runtime.wasm
\
on-runtime-upgrade \
--blocktime 6000 \
--checks all \
--disable-spec-version-check \
live --uri wss://dh-validator-0.datahaven-kt.xyz
```
Test results from stagenet:
- ✅ Migration completes in 1 block
- ✅ PoV size: ~5.3 KB
- ✅ Weight consumption: <0.1% of block capacity
- ✅ All 39 keys successfully migrated
## ⚠️ Breaking Changes ⚠️
If you are manually computing storage keys for the EVM pallet (e.g., directly querying chain state), you must update your code to use the new storage prefix:
- Old prefix: twox128("Evm") = 0x8b90cb...
- New prefix: twox128("EVM") = 0x6a5e91...
All EVM-facing interfaces remain unchanged.
This commit is contained in:
parent
ba5ce56c5f
commit
55e973b8f0
28 changed files with 423 additions and 50 deletions
3
operator/Cargo.lock
generated
3
operator/Cargo.lock
generated
|
|
@ -3163,12 +3163,14 @@ dependencies = [
|
|||
"fp-account",
|
||||
"frame-support",
|
||||
"frame-system",
|
||||
"log",
|
||||
"pallet-authorship",
|
||||
"pallet-balances",
|
||||
"pallet-evm",
|
||||
"pallet-evm-precompile-proxy",
|
||||
"pallet-migrations",
|
||||
"pallet-safe-mode",
|
||||
"pallet-timestamp",
|
||||
"pallet-treasury",
|
||||
"pallet-tx-pause",
|
||||
"parity-scale-codec",
|
||||
|
|
@ -3177,6 +3179,7 @@ dependencies = [
|
|||
"precompile-utils",
|
||||
"scale-info",
|
||||
"sp-core",
|
||||
"sp-io",
|
||||
"sp-runtime",
|
||||
"sp-std",
|
||||
"staging-xcm",
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ construct_runtime!(
|
|||
pub enum Runtime {
|
||||
System: frame_system,
|
||||
Balances: pallet_balances,
|
||||
Evm: pallet_evm,
|
||||
EVM: pallet_evm,
|
||||
Timestamp: pallet_timestamp,
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -662,7 +662,7 @@ fn evm_batch_some_transfers_enough() {
|
|||
.with_balances(vec![(Alice.into(), 10_000)])
|
||||
.build()
|
||||
.execute_with(|| {
|
||||
assert_ok!(RuntimeCall::Evm(evm_call(
|
||||
assert_ok!(RuntimeCall::EVM(evm_call(
|
||||
Alice,
|
||||
PCall::batch_some {
|
||||
to: vec![Address(Bob.into()), Address(Charlie.into())].into(),
|
||||
|
|
@ -682,7 +682,7 @@ fn evm_batch_some_until_failure_transfers_enough() {
|
|||
.with_balances(vec![(Alice.into(), 10_000)])
|
||||
.build()
|
||||
.execute_with(|| {
|
||||
assert_ok!(RuntimeCall::Evm(evm_call(
|
||||
assert_ok!(RuntimeCall::EVM(evm_call(
|
||||
Alice,
|
||||
PCall::batch_some_until_failure {
|
||||
to: vec![Address(Bob.into()), Address(Charlie.into())].into(),
|
||||
|
|
@ -702,7 +702,7 @@ fn evm_batch_all_transfers_enough() {
|
|||
.with_balances(vec![(Alice.into(), 10_000)])
|
||||
.build()
|
||||
.execute_with(|| {
|
||||
assert_ok!(RuntimeCall::Evm(evm_call(
|
||||
assert_ok!(RuntimeCall::EVM(evm_call(
|
||||
Alice,
|
||||
PCall::batch_all {
|
||||
to: vec![Address(Bob.into()), Address(Charlie.into())].into(),
|
||||
|
|
@ -725,7 +725,7 @@ fn evm_batch_some_transfers_too_much() {
|
|||
.with_balances(vec![(Alice.into(), 10_000)])
|
||||
.build()
|
||||
.execute_with(|| {
|
||||
assert_ok!(RuntimeCall::Evm(evm_call(
|
||||
assert_ok!(RuntimeCall::EVM(evm_call(
|
||||
Alice,
|
||||
PCall::batch_some {
|
||||
to: vec![
|
||||
|
|
@ -760,7 +760,7 @@ fn evm_batch_some_until_failure_transfers_too_much() {
|
|||
.with_balances(vec![(Alice.into(), 10_000)])
|
||||
.build()
|
||||
.execute_with(|| {
|
||||
assert_ok!(RuntimeCall::Evm(evm_call(
|
||||
assert_ok!(RuntimeCall::EVM(evm_call(
|
||||
Alice,
|
||||
PCall::batch_some_until_failure {
|
||||
to: vec![
|
||||
|
|
@ -795,7 +795,7 @@ fn evm_batch_all_transfers_too_much() {
|
|||
.with_balances(vec![(Alice.into(), 10_000)])
|
||||
.build()
|
||||
.execute_with(|| {
|
||||
assert_ok!(RuntimeCall::Evm(evm_call(
|
||||
assert_ok!(RuntimeCall::EVM(evm_call(
|
||||
Alice,
|
||||
PCall::batch_all {
|
||||
to: vec![
|
||||
|
|
@ -830,7 +830,7 @@ fn evm_batch_some_contract_revert() {
|
|||
.with_balances(vec![(Alice.into(), 10_000)])
|
||||
.build()
|
||||
.execute_with(|| {
|
||||
assert_ok!(RuntimeCall::Evm(evm_call(
|
||||
assert_ok!(RuntimeCall::EVM(evm_call(
|
||||
Alice,
|
||||
PCall::batch_some {
|
||||
to: vec![
|
||||
|
|
@ -865,7 +865,7 @@ fn evm_batch_some_until_failure_contract_revert() {
|
|||
.with_balances(vec![(Alice.into(), 10_000)])
|
||||
.build()
|
||||
.execute_with(|| {
|
||||
assert_ok!(RuntimeCall::Evm(evm_call(
|
||||
assert_ok!(RuntimeCall::EVM(evm_call(
|
||||
Alice,
|
||||
PCall::batch_some_until_failure {
|
||||
to: vec![
|
||||
|
|
@ -900,7 +900,7 @@ fn evm_batch_all_contract_revert() {
|
|||
.with_balances(vec![(Alice.into(), 10_000)])
|
||||
.build()
|
||||
.execute_with(|| {
|
||||
assert_ok!(RuntimeCall::Evm(evm_call(
|
||||
assert_ok!(RuntimeCall::EVM(evm_call(
|
||||
Alice,
|
||||
PCall::batch_all {
|
||||
to: vec![
|
||||
|
|
@ -954,7 +954,7 @@ fn evm_batch_recursion_under_limit() {
|
|||
}
|
||||
.into();
|
||||
|
||||
assert_ok!(RuntimeCall::Evm(evm_call(Alice, input)).dispatch(RuntimeOrigin::root()));
|
||||
assert_ok!(RuntimeCall::EVM(evm_call(Alice, input)).dispatch(RuntimeOrigin::root()));
|
||||
|
||||
assert_eq!(balance(Alice), 9_000); // gasprice = 0
|
||||
assert_eq!(balance(Bob), 1_000);
|
||||
|
|
@ -993,7 +993,7 @@ fn evm_batch_recursion_over_limit() {
|
|||
)
|
||||
.into();
|
||||
|
||||
assert_ok!(RuntimeCall::Evm(evm_call(Alice, input)).dispatch(RuntimeOrigin::root()));
|
||||
assert_ok!(RuntimeCall::EVM(evm_call(Alice, input)).dispatch(RuntimeOrigin::root()));
|
||||
|
||||
assert_eq!(balance(Alice), 10_000); // gasprice = 0
|
||||
assert_eq!(balance(Bob), 0);
|
||||
|
|
@ -1030,7 +1030,7 @@ fn batch_is_not_callable_by_dummy_code() {
|
|||
}
|
||||
.into();
|
||||
|
||||
match RuntimeCall::Evm(evm_call(Alice, input)).dispatch(RuntimeOrigin::root()) {
|
||||
match RuntimeCall::EVM(evm_call(Alice, input)).dispatch(RuntimeOrigin::root()) {
|
||||
Err(DispatchErrorWithPostInfo {
|
||||
error:
|
||||
DispatchError::Module(ModuleError {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ construct_runtime!(
|
|||
pub enum Runtime {
|
||||
System: frame_system,
|
||||
Balances: pallet_balances,
|
||||
Evm: pallet_evm,
|
||||
EVM: pallet_evm,
|
||||
Timestamp: pallet_timestamp,
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ construct_runtime!(
|
|||
pub enum Runtime {
|
||||
System: frame_system,
|
||||
Balances: pallet_balances,
|
||||
Evm: pallet_evm,
|
||||
EVM: pallet_evm,
|
||||
Timestamp: pallet_timestamp,
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -565,7 +565,7 @@ fn deposit(data: Vec<u8>) {
|
|||
// Deposit
|
||||
// We need to call using EVM pallet so we can check the EVM correctly sends the amount
|
||||
// to the precompile.
|
||||
Evm::call(
|
||||
EVM::call(
|
||||
RuntimeOrigin::root(),
|
||||
CryptoAlith.into(),
|
||||
Precompile1.into(),
|
||||
|
|
@ -602,7 +602,7 @@ fn deposit(data: Vec<u8>) {
|
|||
amount: 500
|
||||
}),
|
||||
// Log is correctly emited.
|
||||
RuntimeEvent::Evm(pallet_evm::Event::Log {
|
||||
RuntimeEvent::EVM(pallet_evm::Event::Log {
|
||||
log: log2(
|
||||
Precompile1,
|
||||
SELECTOR_LOG_DEPOSIT,
|
||||
|
|
@ -610,7 +610,7 @@ fn deposit(data: Vec<u8>) {
|
|||
solidity::encode_event_data(U256::from(500)),
|
||||
)
|
||||
}),
|
||||
RuntimeEvent::Evm(pallet_evm::Event::Executed {
|
||||
RuntimeEvent::EVM(pallet_evm::Event::Executed {
|
||||
address: Precompile1.into()
|
||||
}),
|
||||
]
|
||||
|
|
@ -681,7 +681,7 @@ fn deposit_zero() {
|
|||
// Deposit
|
||||
// We need to call using EVM pallet so we can check the EVM correctly sends the amount
|
||||
// to the precompile.
|
||||
Evm::call(
|
||||
EVM::call(
|
||||
RuntimeOrigin::root(),
|
||||
CryptoAlith.into(),
|
||||
Precompile1.into(),
|
||||
|
|
@ -697,7 +697,7 @@ fn deposit_zero() {
|
|||
|
||||
assert_eq!(
|
||||
events(),
|
||||
vec![RuntimeEvent::Evm(pallet_evm::Event::ExecutedFailed {
|
||||
vec![RuntimeEvent::EVM(pallet_evm::Event::ExecutedFailed {
|
||||
address: Precompile1.into()
|
||||
}),]
|
||||
);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ construct_runtime!(
|
|||
pub enum Runtime {
|
||||
System: frame_system,
|
||||
Balances: pallet_balances,
|
||||
Evm: pallet_evm,
|
||||
EVM: pallet_evm,
|
||||
Timestamp: pallet_timestamp,
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ construct_runtime!(
|
|||
pub enum Runtime {
|
||||
System: frame_system,
|
||||
Balances: pallet_balances,
|
||||
Evm: pallet_evm,
|
||||
EVM: pallet_evm,
|
||||
Timestamp: pallet_timestamp,
|
||||
Proxy: pallet_proxy,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -541,7 +541,7 @@ fn test_nested_evm_bypass_proxy_should_allow_elevating_proxy_type() {
|
|||
}
|
||||
.into();
|
||||
|
||||
let evm_call = RuntimeCall::Evm(EvmCall::call {
|
||||
let evm_call = RuntimeCall::EVM(EvmCall::call {
|
||||
source: Alice.into(),
|
||||
target: Precompile1.into(),
|
||||
input: add_proxy_precompile,
|
||||
|
|
|
|||
|
|
@ -9,8 +9,10 @@ codec = { workspace = true }
|
|||
fp-account = { workspace = true, features = ["serde"] }
|
||||
frame-support = { workspace = true }
|
||||
frame-system = { workspace = true }
|
||||
log = { workspace = true }
|
||||
pallet-authorship = { workspace = true }
|
||||
pallet-balances = { workspace = true }
|
||||
pallet-timestamp = { workspace = true }
|
||||
pallet-evm = { workspace = true }
|
||||
pallet-evm-precompile-proxy = { workspace = true }
|
||||
pallet-migrations = { workspace = true }
|
||||
|
|
@ -22,6 +24,7 @@ polkadot-runtime-common = { workspace = true }
|
|||
precompile-utils = { workspace = true }
|
||||
scale-info = { workspace = true }
|
||||
sp-core = { workspace = true, features = ["serde"] }
|
||||
sp-io = { workspace = true }
|
||||
sp-runtime = { workspace = true, features = ["serde"] }
|
||||
sp-std = { workspace = true }
|
||||
xcm = { workspace = true }
|
||||
|
|
@ -31,8 +34,10 @@ default = ["std"]
|
|||
std = [
|
||||
"codec/std",
|
||||
"frame-support/std",
|
||||
"log/std",
|
||||
"pallet-authorship/std",
|
||||
"pallet-balances/std",
|
||||
"pallet-timestamp/std",
|
||||
"pallet-evm/std",
|
||||
"pallet-evm-precompile-proxy/std",
|
||||
"pallet-migrations/std",
|
||||
|
|
@ -44,6 +49,7 @@ std = [
|
|||
"precompile-utils/std",
|
||||
"scale-info/std",
|
||||
"sp-core/std",
|
||||
"sp-io/std",
|
||||
"sp-runtime/std",
|
||||
"sp-std/std",
|
||||
"xcm/std",
|
||||
|
|
@ -59,5 +65,15 @@ runtime-benchmarks = [
|
|||
"sp-runtime/runtime-benchmarks",
|
||||
]
|
||||
|
||||
try-runtime = [
|
||||
"frame-support/try-runtime",
|
||||
"pallet-migrations/try-runtime",
|
||||
"pallet-safe-mode/try-runtime",
|
||||
"pallet-tx-pause/try-runtime",
|
||||
"pallet-timestamp/try-runtime",
|
||||
"polkadot-runtime-common/try-runtime",
|
||||
"sp-runtime/try-runtime",
|
||||
]
|
||||
|
||||
# Set timing constants (e.g. session period) to faster versions to speed up testing.
|
||||
fast-runtime = []
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
//! 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.
|
||||
|
||||
use frame_support::pallet_prelude::ConstU32;
|
||||
use frame_support::pallet_prelude::*;
|
||||
|
||||
/// Maximum encoded length permitted for a migration cursor.
|
||||
pub const MIGRATION_CURSOR_MAX_LEN: u32 = 65_536;
|
||||
|
|
@ -20,7 +20,7 @@ pub type MigrationIdentifierMaxLen = ConstU32<MIGRATION_IDENTIFIER_MAX_LEN>;
|
|||
/// 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 = ();
|
||||
pub type MultiBlockMigrationList<T> = (evm_alias::EvmAliasMigration<T>,);
|
||||
|
||||
/// During benchmarking we switch to the pallet-provided mocked migrations to guarantee success.
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
|
|
@ -31,3 +31,348 @@ pub type MigrationStatusHandler = ();
|
|||
|
||||
/// Default handler triggered on migration failures.
|
||||
pub type FailedMigrationHandler = frame_support::migrations::FreezeChainOnFailedMigration;
|
||||
|
||||
/// 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<T>(PhantomData<T>);
|
||||
|
||||
impl<T> SteppedMigration for EvmAliasMigration<T>
|
||||
where
|
||||
T: pallet_evm::Config,
|
||||
{
|
||||
type Cursor = BoundedVec<u8, ConstU32<128>>;
|
||||
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<Self::Cursor>,
|
||||
meter: &mut WeightMeter,
|
||||
) -> Result<Option<Self::Cursor>, 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<u8> = 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<Vec<u8>, 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<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
|
||||
use codec::Decode;
|
||||
|
||||
let snapshot: BTreeMap<Vec<u8>, Vec<u8>> =
|
||||
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<T>, Storage, Event<T>},
|
||||
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>},
|
||||
}
|
||||
);
|
||||
|
||||
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<Self>;
|
||||
type BlockHashCount = BlockHashCount;
|
||||
type AccountData = pallet_balances::AccountData<u64>;
|
||||
}
|
||||
|
||||
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<Self>;
|
||||
type FeeCalculator = FixedGasPrice;
|
||||
type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping<Self>;
|
||||
type Currency = Balances;
|
||||
type Runner = pallet_evm::runner::stack::Runner<Self>;
|
||||
type Timestamp = Timestamp;
|
||||
type PrecompilesType = MockPrecompileSet;
|
||||
type PrecompilesValue = MockPrecompiles;
|
||||
}
|
||||
|
||||
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<pallet_evm::PrecompileResult> {
|
||||
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<H256>) -> Vec<u8> {
|
||||
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::<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(|| {
|
||||
let addresses: Vec<H160> = (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::<TestRuntime>::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::<TestRuntime>::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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ frame_benchmarking::define_benchmarks!(
|
|||
[pallet_tx_pause, TxPause]
|
||||
|
||||
// EVM pallets
|
||||
[pallet_evm, Evm]
|
||||
[pallet_evm, EVM]
|
||||
|
||||
// Governance pallets
|
||||
[pallet_collective_technical_committee, TechnicalCommittee]
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ impl Contains<RuntimeCall> for NormalCallFilter {
|
|||
// See https://github.com/PureStake/sr-moonbeam/issues/30
|
||||
// Note: It is also assumed that EVM calls are only allowed through `Origin::Root` so
|
||||
// this can be seen as an additional security
|
||||
RuntimeCall::Evm(_) => false,
|
||||
RuntimeCall::EVM(_) => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
|
@ -823,6 +823,9 @@ 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>;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type Migrations = datahaven_runtime_common::migrations::MultiBlockMigrationList;
|
||||
type CursorMaxLen = MigrationCursorMaxLen;
|
||||
type IdentifierMaxLen = MigrationIdentifierMaxLen;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
configs::BABE_GENESIS_EPOCH_CONFIG, AccountId, BalancesConfig, EvmConfig, Precompiles,
|
||||
configs::BABE_GENESIS_EPOCH_CONFIG, AccountId, BalancesConfig, EVMConfig, Precompiles,
|
||||
RuntimeGenesisConfig, SessionKeys, Signature, SudoConfig, TechnicalCommitteeConfig,
|
||||
TreasuryCouncilConfig,
|
||||
};
|
||||
|
|
@ -44,7 +44,7 @@ fn testnet_genesis(
|
|||
epoch_config: BABE_GENESIS_EPOCH_CONFIG,
|
||||
..Default::default()
|
||||
},
|
||||
evm: EvmConfig {
|
||||
evm: EVMConfig {
|
||||
// We need _some_ code inserted at the precompile address so that
|
||||
// the evm will actually call the address.
|
||||
accounts: Precompiles::used_addresses()
|
||||
|
|
|
|||
|
|
@ -411,7 +411,7 @@ mod runtime {
|
|||
pub type Ethereum = pallet_ethereum;
|
||||
|
||||
#[runtime::pallet_index(51)]
|
||||
pub type Evm = pallet_evm;
|
||||
pub type EVM = pallet_evm;
|
||||
|
||||
#[runtime::pallet_index(52)]
|
||||
pub type EvmChainId = pallet_evm_chain_id;
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ fn author_does_receive_priority_fee() {
|
|||
Balances::make_free_balance_be(&author, 100 * HAVE);
|
||||
|
||||
// EVM transfer.
|
||||
assert_ok!(RuntimeCall::Evm(pallet_evm::Call::<Runtime>::call {
|
||||
assert_ok!(RuntimeCall::EVM(pallet_evm::Call::<Runtime>::call {
|
||||
source: H160::from(BOB),
|
||||
target: H160::from(ALICE),
|
||||
input: Vec::new(),
|
||||
|
|
@ -105,7 +105,7 @@ fn total_issuance_after_evm_transaction_with_priority_fee() {
|
|||
let _author = get_validator_by_index(0);
|
||||
|
||||
// EVM transfer.
|
||||
assert_ok!(RuntimeCall::Evm(pallet_evm::Call::<Runtime>::call {
|
||||
assert_ok!(RuntimeCall::EVM(pallet_evm::Call::<Runtime>::call {
|
||||
source: H160::from(BOB),
|
||||
target: H160::from(ALICE),
|
||||
input: Vec::new(),
|
||||
|
|
@ -174,7 +174,7 @@ fn total_issuance_after_evm_transaction_without_priority_fee() {
|
|||
set_block_author_by_index(0);
|
||||
let issuance_before = <Runtime as pallet_evm::Config>::Currency::total_issuance();
|
||||
// EVM transfer.
|
||||
assert_ok!(RuntimeCall::Evm(pallet_evm::Call::<Runtime>::call {
|
||||
assert_ok!(RuntimeCall::EVM(pallet_evm::Call::<Runtime>::call {
|
||||
source: H160::from(BOB),
|
||||
target: H160::from(ALICE),
|
||||
input: Vec::new(),
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ frame_benchmarking::define_benchmarks!(
|
|||
[pallet_whitelist, Whitelist]
|
||||
|
||||
// EVM pallets
|
||||
[pallet_evm, Evm]
|
||||
[pallet_evm, EVM]
|
||||
|
||||
// DataHaven custom pallets
|
||||
[pallet_external_validators, ExternalValidators]
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ impl Contains<RuntimeCall> for NormalCallFilter {
|
|||
// See https://github.com/PureStake/sr-moonbeam/issues/30
|
||||
// Note: It is also assumed that EVM calls are only allowed through `Origin::Root` so
|
||||
// this can be seen as an additional security
|
||||
RuntimeCall::Evm(_) => false,
|
||||
RuntimeCall::EVM(_) => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
|
@ -822,6 +822,9 @@ 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>;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type Migrations = datahaven_runtime_common::migrations::MultiBlockMigrationList;
|
||||
type CursorMaxLen = MigrationCursorMaxLen;
|
||||
type IdentifierMaxLen = MigrationIdentifierMaxLen;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
configs::BABE_GENESIS_EPOCH_CONFIG, AccountId, BalancesConfig, EvmConfig, Precompiles,
|
||||
configs::BABE_GENESIS_EPOCH_CONFIG, AccountId, BalancesConfig, EVMConfig, Precompiles,
|
||||
RuntimeGenesisConfig, SessionKeys, Signature, SudoConfig, TechnicalCommitteeConfig,
|
||||
TreasuryCouncilConfig,
|
||||
};
|
||||
|
|
@ -44,7 +44,7 @@ fn testnet_genesis(
|
|||
epoch_config: BABE_GENESIS_EPOCH_CONFIG,
|
||||
..Default::default()
|
||||
},
|
||||
evm: EvmConfig {
|
||||
evm: EVMConfig {
|
||||
// We need _some_ code inserted at the precompile address so that
|
||||
// the evm will actually call the address.
|
||||
accounts: Precompiles::used_addresses()
|
||||
|
|
|
|||
|
|
@ -413,7 +413,7 @@ mod runtime {
|
|||
pub type Ethereum = pallet_ethereum;
|
||||
|
||||
#[runtime::pallet_index(51)]
|
||||
pub type Evm = pallet_evm;
|
||||
pub type EVM = pallet_evm;
|
||||
|
||||
#[runtime::pallet_index(52)]
|
||||
pub type EvmChainId = pallet_evm_chain_id;
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ fn author_does_receive_priority_fee() {
|
|||
Balances::make_free_balance_be(&author, 100 * HAVE);
|
||||
|
||||
// EVM transfer.
|
||||
assert_ok!(RuntimeCall::Evm(pallet_evm::Call::<Runtime>::call {
|
||||
assert_ok!(RuntimeCall::EVM(pallet_evm::Call::<Runtime>::call {
|
||||
source: H160::from(BOB),
|
||||
target: H160::from(ALICE),
|
||||
input: Vec::new(),
|
||||
|
|
@ -105,7 +105,7 @@ fn total_issuance_after_evm_transaction_with_priority_fee() {
|
|||
let _author = get_validator_by_index(0);
|
||||
|
||||
// EVM transfer.
|
||||
assert_ok!(RuntimeCall::Evm(pallet_evm::Call::<Runtime>::call {
|
||||
assert_ok!(RuntimeCall::EVM(pallet_evm::Call::<Runtime>::call {
|
||||
source: H160::from(BOB),
|
||||
target: H160::from(ALICE),
|
||||
input: Vec::new(),
|
||||
|
|
@ -174,7 +174,7 @@ fn total_issuance_after_evm_transaction_without_priority_fee() {
|
|||
set_block_author_by_index(0);
|
||||
let issuance_before = <Runtime as pallet_evm::Config>::Currency::total_issuance();
|
||||
// EVM transfer.
|
||||
assert_ok!(RuntimeCall::Evm(pallet_evm::Call::<Runtime>::call {
|
||||
assert_ok!(RuntimeCall::EVM(pallet_evm::Call::<Runtime>::call {
|
||||
source: H160::from(BOB),
|
||||
target: H160::from(ALICE),
|
||||
input: Vec::new(),
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ frame_benchmarking::define_benchmarks!(
|
|||
[pallet_tx_pause, TxPause]
|
||||
|
||||
// EVM pallets
|
||||
[pallet_evm, Evm]
|
||||
[pallet_evm, EVM]
|
||||
|
||||
// Governance pallets
|
||||
[pallet_collective_technical_committee, TechnicalCommittee]
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ impl Contains<RuntimeCall> for NormalCallFilter {
|
|||
// See https://github.com/PureStake/sr-moonbeam/issues/30
|
||||
// Note: It is also assumed that EVM calls are only allowed through `Origin::Root` so
|
||||
// this can be seen as an additional security
|
||||
RuntimeCall::Evm(_) => false,
|
||||
RuntimeCall::EVM(_) => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
|
@ -822,6 +822,9 @@ 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>;
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type Migrations = datahaven_runtime_common::migrations::MultiBlockMigrationList;
|
||||
type CursorMaxLen = MigrationCursorMaxLen;
|
||||
type IdentifierMaxLen = MigrationIdentifierMaxLen;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
configs::BABE_GENESIS_EPOCH_CONFIG, AccountId, BalancesConfig, EvmConfig, Precompiles,
|
||||
configs::BABE_GENESIS_EPOCH_CONFIG, AccountId, BalancesConfig, EVMConfig, Precompiles,
|
||||
RuntimeGenesisConfig, SessionKeys, Signature, SudoConfig, TechnicalCommitteeConfig,
|
||||
TreasuryCouncilConfig,
|
||||
};
|
||||
|
|
@ -44,7 +44,7 @@ fn testnet_genesis(
|
|||
epoch_config: BABE_GENESIS_EPOCH_CONFIG,
|
||||
..Default::default()
|
||||
},
|
||||
evm: EvmConfig {
|
||||
evm: EVMConfig {
|
||||
// We need _some_ code inserted at the precompile address so that
|
||||
// the evm will actually call the address.
|
||||
accounts: Precompiles::used_addresses()
|
||||
|
|
|
|||
|
|
@ -410,7 +410,7 @@ mod runtime {
|
|||
pub type Ethereum = pallet_ethereum;
|
||||
|
||||
#[runtime::pallet_index(51)]
|
||||
pub type Evm = pallet_evm;
|
||||
pub type EVM = pallet_evm;
|
||||
|
||||
#[runtime::pallet_index(52)]
|
||||
pub type EvmChainId = pallet_evm_chain_id;
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ fn author_does_receive_priority_fee() {
|
|||
Balances::make_free_balance_be(&author, 100 * HAVE);
|
||||
|
||||
// EVM transfer.
|
||||
assert_ok!(RuntimeCall::Evm(pallet_evm::Call::<Runtime>::call {
|
||||
assert_ok!(RuntimeCall::EVM(pallet_evm::Call::<Runtime>::call {
|
||||
source: H160::from(BOB),
|
||||
target: H160::from(ALICE),
|
||||
input: Vec::new(),
|
||||
|
|
@ -104,7 +104,7 @@ fn total_issuance_after_evm_transaction_with_priority_fee() {
|
|||
let _author = get_validator_by_index(0);
|
||||
|
||||
// EVM transfer.
|
||||
assert_ok!(RuntimeCall::Evm(pallet_evm::Call::<Runtime>::call {
|
||||
assert_ok!(RuntimeCall::EVM(pallet_evm::Call::<Runtime>::call {
|
||||
source: H160::from(BOB),
|
||||
target: H160::from(ALICE),
|
||||
input: Vec::new(),
|
||||
|
|
@ -174,7 +174,7 @@ fn total_issuance_after_evm_transaction_without_priority_fee() {
|
|||
set_block_author_by_index(0);
|
||||
let issuance_before = <Runtime as pallet_evm::Config>::Currency::total_issuance();
|
||||
// EVM transfer.
|
||||
assert_ok!(RuntimeCall::Evm(pallet_evm::Call::<Runtime>::call {
|
||||
assert_ok!(RuntimeCall::EVM(pallet_evm::Call::<Runtime>::call {
|
||||
source: H160::from(BOB),
|
||||
target: H160::from(ALICE),
|
||||
input: Vec::new(),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "0.1.0-autogenerated.11494808361211823293",
|
||||
"version": "0.1.0-autogenerated.12438105935477919494",
|
||||
"name": "@polkadot-api/descriptors",
|
||||
"files": [
|
||||
"dist"
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in a new issue