Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

State Trie Migration v1 #2907

Merged
merged 68 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
03bded2
init
TarekkMA Aug 20, 2024
8c007a9
migration on idle
TarekkMA Aug 21, 2024
26ce9d2
rustfmt
TarekkMA Aug 21, 2024
3be2f54
add a comment
TarekkMA Aug 21, 2024
252af7f
change state_version
TarekkMA Aug 21, 2024
14c6f0a
fix visibility
TarekkMA Aug 21, 2024
5ba0b8f
count get_next_key
TarekkMA Aug 22, 2024
41e4610
Update runtime/moonbase/src/lib.rs
TarekkMA Aug 23, 2024
6657db1
migrate code
TarekkMA Aug 27, 2024
ea9e4c3
fix
TarekkMA Aug 27, 2024
691c7aa
add pre/post upgrades
TarekkMA Aug 27, 2024
420e6cb
Merge branch 'master' into tarekkma/state_migration
TarekkMA Aug 27, 2024
763f52a
rename
TarekkMA Aug 28, 2024
24e2eca
disable
TarekkMA Aug 28, 2024
6a33771
Revert "disable"
TarekkMA Aug 28, 2024
dffb686
change to state_version 0
TarekkMA Aug 28, 2024
e15dd50
Revert "change to state_version 0"
TarekkMA Aug 28, 2024
c2eaa5f
Update pallets/moonbeam-lazy-migrations/src/lib.rs
TarekkMA Aug 28, 2024
d2139cb
apply review suggestions
TarekkMA Aug 28, 2024
4091bd2
rename
TarekkMA Aug 28, 2024
566b157
remove comment
TarekkMA Aug 28, 2024
7f2e921
fix pov in tests
TarekkMA Aug 28, 2024
2db1a02
fmt & fix pov values
TarekkMA Aug 29, 2024
c022301
pov test values
TarekkMA Aug 29, 2024
626fce0
fix numbers
TarekkMA Aug 29, 2024
b6bce16
rename
TarekkMA Sep 3, 2024
1e318d8
testing
TarekkMA Sep 3, 2024
e3d81c6
fmt
TarekkMA Sep 3, 2024
992b674
tests
TarekkMA Sep 3, 2024
badb543
fmt
TarekkMA Sep 4, 2024
583e1a6
Merge remote-tracking branch 'upstream/master' into tarekkma/state_mi…
TarekkMA Sep 4, 2024
b3410aa
test
TarekkMA Sep 4, 2024
6bd0dd7
Fix D014023T01
TarekkMA Sep 4, 2024
356f624
remove console.log
TarekkMA Sep 4, 2024
ea5e405
fix incorrect Weight for migration
TarekkMA Sep 5, 2024
c8cf5dd
Update pallets/moonbeam-lazy-migrations/src/lib.rs
TarekkMA Sep 5, 2024
bcb0428
add smoke test
TarekkMA Sep 5, 2024
0416f66
format
TarekkMA Sep 5, 2024
ee70136
Merge remote-tracking branch 'upstream/master' into tarekkma/state_mi…
TarekkMA Sep 5, 2024
81f96a0
remove duplicate dep
TarekkMA Sep 5, 2024
f7772b6
remove unused
TarekkMA Sep 5, 2024
f76b44f
fix test status
TarekkMA Sep 5, 2024
527d03e
fix test
TarekkMA Sep 5, 2024
28af3a7
move MigrateCodeToStateTrieV1
TarekkMA Sep 5, 2024
9d61943
remove unused comments
TarekkMA Sep 5, 2024
7d1f489
change how key is being computed
TarekkMA Sep 9, 2024
fe49b2d
comment out code migration
TarekkMA Sep 9, 2024
72066c4
silence migration
TarekkMA Sep 10, 2024
ed4f556
allow dead code
TarekkMA Sep 10, 2024
f9dc8e3
Merge remote-tracking branch 'upstream/master' into tarekkma/state_mi…
TarekkMA Sep 12, 2024
a3e0931
update Cargo.lock
TarekkMA Sep 12, 2024
e02cc66
revert comment
TarekkMA Sep 12, 2024
b4a9b9d
add a zombienet setup script
TarekkMA Sep 12, 2024
6d26eca
chnage state_version for both moonbeam and moonriver
TarekkMA Sep 12, 2024
656d8aa
fmt
TarekkMA Sep 12, 2024
feb1aa5
fix
TarekkMA Sep 12, 2024
3df4962
fix script
TarekkMA Sep 12, 2024
db60dea
test
TarekkMA Sep 12, 2024
381cfa4
keep track of how many keys have been migrated
TarekkMA Sep 16, 2024
1262d88
Merge remote-tracking branch 'origin/master' into tarekkma/state_migr…
TarekkMA Sep 16, 2024
71d1424
format
TarekkMA Sep 16, 2024
2cb1e90
fix tests
TarekkMA Sep 16, 2024
38f9734
Merge branch 'master' into tarekkma/state_migration
noandrea Sep 19, 2024
f9fb256
fix spec version
TarekkMA Sep 20, 2024
3177fa7
tmp fix: use latest release client for zombienet tests
pLabarta Sep 30, 2024
735e50e
update & move zombie setup script into test/scripts
pLabarta Sep 30, 2024
cdd9feb
Merge branch 'master' into tarekkma/state_migration
pLabarta Sep 30, 2024
3a36425
use branch build for RPC tests
pLabarta Sep 30, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,6 @@ cumulus-primitives-parachain-inherent = { git = "https://github.com/moonbeam-fou
cumulus-primitives-timestamp = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false }
cumulus-primitives-utility = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false }
cumulus-test-relay-sproof-builder = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false }
cumulus-primitives-storage-weight-reclaim = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false }
parachain-info = { package = "staging-parachain-info", git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false }
parachains-common = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false }

Expand All @@ -312,6 +311,7 @@ cumulus-relay-chain-inprocess-interface = { git = "https://github.com/moonbeam-f
cumulus-relay-chain-interface = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" }
cumulus-relay-chain-minimal-node = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" }
cumulus-relay-chain-rpc-interface = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0" }
cumulus-primitives-storage-weight-reclaim = { git = "https://github.com/moonbeam-foundation/polkadot-sdk", branch = "moonbeam-polkadot-v1.11.0", default-features = false}

# Polkadot / XCM (wasm)
orml-traits = { git = "https://github.com/moonbeam-foundation/open-runtime-module-library", branch = "moonbeam-polkadot-v1.11.0", default-features = false }
Expand Down
46 changes: 26 additions & 20 deletions pallets/moonbeam-lazy-migrations/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,37 +1,41 @@
[package]
authors = {workspace = true}
authors = { workspace = true }
description = "A pallet for performing migrations from extrinsics"
edition = "2021"
name = "pallet-moonbeam-lazy-migrations"
version = "0.1.0"

[dependencies]
log = {workspace = true}
log = { workspace = true }

# Substrate
frame-support = {workspace = true}
frame-system = {workspace = true}
pallet-scheduler = {workspace = true}
pallet-balances = {workspace = true}
parity-scale-codec = {workspace = true}
scale-info = {workspace = true, features = ["derive"]}
sp-core = {workspace = true}
sp-io = {workspace = true}
sp-runtime = {workspace = true}
sp-std = {workspace = true}
frame-support = { workspace = true }
frame-system = { workspace = true }
pallet-scheduler = { workspace = true }
pallet-assets = { workspace = true }
pallet-balances = { workspace = true }
parity-scale-codec = { workspace = true }
scale-info = { workspace = true, features = ["derive"] }
sp-core = { workspace = true }
sp-io = { workspace = true }
sp-runtime = { workspace = true }
sp-std = { workspace = true }

# Frontier
pallet-evm = {workspace = true, features = ["forbid-evm-reentrancy"]}
pallet-evm = { workspace = true, features = ["forbid-evm-reentrancy"] }

# Runtime Interfaces
cumulus-primitives-storage-weight-reclaim = { workspace = true, default-features = false }

# Benchmarks
frame-benchmarking = {workspace = true, optional = true}
frame-benchmarking = { workspace = true, optional = true }

[dev-dependencies]
frame-benchmarking = {workspace = true, features = ["std"]}
pallet-balances = {workspace = true, features = ["std", "insecure_zero_ed"]}
pallet-timestamp = {workspace = true, features = ["std"]}
rlp = {workspace = true, features = ["std"]}
sp-io = {workspace = true, features = ["std"]}
frame-benchmarking = { workspace = true, features = ["std"] }
pallet-balances = { workspace = true, features = ["std", "insecure_zero_ed"] }
pallet-timestamp = { workspace = true, features = ["std"] }
rlp = { workspace = true, features = ["std"] }
sp-io = { workspace = true, features = ["std"] }

[features]
default = ["std"]
Expand All @@ -47,6 +51,8 @@ std = [
"sp-std/std",
"pallet-evm/std",
"pallet-timestamp/std",
"pallet-assets/std",
"cumulus-primitives-storage-weight-reclaim/std",
"rlp/std",
]
try-runtime = ["frame-support/try-runtime"]
try-runtime = ["frame-support/try-runtime"]
248 changes: 248 additions & 0 deletions pallets/moonbeam-lazy-migrations/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const MAX_CONTRACT_CODE_SIZE: u64 = 25 * 1024;
#[pallet]
pub mod pallet {
use super::*;
use cumulus_primitives_storage_weight_reclaim::get_proof_size;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
use sp_core::H160;
Expand All @@ -53,6 +54,26 @@ pub mod pallet {
/// The total number of suicided contracts that were removed
pub(crate) type SuicidedContractsRemoved<T: Config> = StorageValue<_, u32, ValueQuery>;

#[pallet::storage]
pub(crate) type StateMigrationStatusValue<T: Config> =
StorageValue<_, (StateMigrationStatus, u64), ValueQuery>;

pub(crate) type StorageKey = BoundedVec<u8, ConstU32<1_024>>;

#[derive(Clone, Encode, Decode, scale_info::TypeInfo, PartialEq, Eq, MaxEncodedLen, Debug)]
pub enum StateMigrationStatus {
NotStarted,
Started(StorageKey),
Error(BoundedVec<u8, ConstU32<1024>>),
Complete,
}

impl Default for StateMigrationStatus {
fn default() -> Self {
return StateMigrationStatus::NotStarted;
}
}

/// Configuration trait of this pallet.
#[pallet::config]
pub trait Config: frame_system::Config + pallet_evm::Config + pallet_balances::Config {
Expand All @@ -71,6 +92,233 @@ pub mod pallet {
ContractMetadataAlreadySet,
/// Contract not exist
ContractNotExist,
/// The key lengths exceeds the maximum allowed
KeyTooLong,
}

pub(crate) const MAX_ITEM_PROOF_SIZE: u64 = 30 * 1024; // 30 KB
pub(crate) const PROOF_SIZE_BUFFER: u64 = 100 * 1024; // 100 KB

#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
fn on_idle(_n: BlockNumberFor<T>, remaining_weight: Weight) -> Weight {
let proof_size_before: u64 = get_proof_size().unwrap_or(0);
let res = Pallet::<T>::handle_migration(remaining_weight);
let proof_size_after: u64 = get_proof_size().unwrap_or(0);
let proof_size_diff = proof_size_after.saturating_sub(proof_size_before);

Weight::from_parts(0, proof_size_diff)
.saturating_add(T::DbWeight::get().reads_writes(res.reads, res.writes))
}
}

#[derive(Default, Clone, PartialEq, Eq, Encode, Decode, Debug)]
pub(crate) struct ReadWriteOps {
pub reads: u64,
pub writes: u64,
}

impl ReadWriteOps {
pub fn new() -> Self {
Self {
reads: 0,
writes: 0,
}
}

pub fn add_one_read(&mut self) {
self.reads += 1;
}

pub fn add_one_write(&mut self) {
self.writes += 1;
}

pub fn add_reads(&mut self, reads: u64) {
self.reads += reads;
}

pub fn add_writes(&mut self, writes: u64) {
self.writes += writes;
}
}

#[derive(Clone)]
struct StateMigrationResult {
last_key: Option<StorageKey>,
error: Option<&'static str>,
migrated: u64,
reads: u64,
writes: u64,
}

enum NextKeyResult {
gonzamontiel marked this conversation as resolved.
Show resolved Hide resolved
NextKey(StorageKey),
NoMoreKeys,
Error(&'static str),
}

impl<T: Config> Pallet<T> {
/// Handle the migration of the storage keys, returns the number of read and write operations
pub(crate) fn handle_migration(remaining_weight: Weight) -> ReadWriteOps {
let mut read_write_ops = ReadWriteOps::new();

// maximum number of items that can be migrated in one block
let migration_limit = remaining_weight
.proof_size()
.saturating_sub(PROOF_SIZE_BUFFER)
.saturating_div(MAX_ITEM_PROOF_SIZE);

if migration_limit == 0 {
return read_write_ops;
}

let (status, mut migrated_keys) = StateMigrationStatusValue::<T>::get();
read_write_ops.add_one_read();

let next_key = match &status {
StateMigrationStatus::NotStarted => Default::default(),
StateMigrationStatus::Started(storage_key) => {
let (reads, next_key_result) = Pallet::<T>::get_next_key(storage_key);
read_write_ops.add_reads(reads);
match next_key_result {
NextKeyResult::NextKey(next_key) => next_key,
NextKeyResult::NoMoreKeys => {
StateMigrationStatusValue::<T>::put((
StateMigrationStatus::Complete,
migrated_keys,
));
read_write_ops.add_one_write();
return read_write_ops;
}
NextKeyResult::Error(e) => {
StateMigrationStatusValue::<T>::put((
StateMigrationStatus::Error(
e.as_bytes().to_vec().try_into().unwrap_or_default(),
),
migrated_keys,
));
read_write_ops.add_one_write();
return read_write_ops;
}
}
}
StateMigrationStatus::Complete | StateMigrationStatus::Error(_) => {
return read_write_ops;
}
};

let res = Pallet::<T>::migrate_keys(next_key, migration_limit);
migrated_keys += res.migrated;
read_write_ops.add_reads(res.reads);
read_write_ops.add_writes(res.writes);

match (res.last_key, res.error) {
(None, None) => {
StateMigrationStatusValue::<T>::put((
StateMigrationStatus::Complete,
migrated_keys,
));
read_write_ops.add_one_write();
}
// maybe we should store the previous key in the storage as well
(_, Some(e)) => {
StateMigrationStatusValue::<T>::put((
StateMigrationStatus::Error(
e.as_bytes().to_vec().try_into().unwrap_or_default(),
),
migrated_keys,
));
read_write_ops.add_one_write();
}
(Some(key), None) => {
StateMigrationStatusValue::<T>::put((
StateMigrationStatus::Started(key),
migrated_keys,
));
read_write_ops.add_one_write();
}
}

read_write_ops
}

/// Tries to get the next key in the storage, returns None if there are no more keys to migrate.
/// Returns an error if the key is too long.
fn get_next_key(key: &StorageKey) -> (u64, NextKeyResult) {
if let Some(next) = sp_io::storage::next_key(key) {
let next: Result<StorageKey, _> = next.try_into();
match next {
Ok(next_key) => {
if next_key.as_slice() == sp_core::storage::well_known_keys::CODE {
let (reads, next_key_res) = Pallet::<T>::get_next_key(&next_key);
return (1 + reads, next_key_res);
}
(1, NextKeyResult::NextKey(next_key))
}
Err(_) => (1, NextKeyResult::Error("Key too long")),
}
} else {
(1, NextKeyResult::NoMoreKeys)
}
}

/// Migrate maximum of `limit` keys starting from `start`, returns the next key to migrate
/// Returns None if there are no more keys to migrate.
/// Returns an error if an error occurred during migration.
fn migrate_keys(start: StorageKey, limit: u64) -> StateMigrationResult {
let mut key = start;
let mut migrated = 0;
let mut next_key_reads = 0;
let mut writes = 0;

while migrated < limit {
let data = sp_io::storage::get(&key);
if let Some(data) = data {
sp_io::storage::set(&key, &data);
writes += 1;
}

migrated += 1;

if migrated < limit {
let (reads, next_key_res) = Pallet::<T>::get_next_key(&key);
next_key_reads += reads;

match next_key_res {
NextKeyResult::NextKey(next_key) => {
key = next_key;
}
NextKeyResult::NoMoreKeys => {
return StateMigrationResult {
last_key: None,
error: None,
migrated,
reads: migrated + next_key_reads,
writes,
};
}
NextKeyResult::Error(e) => {
return StateMigrationResult {
last_key: Some(key),
error: Some(e),
migrated,
reads: migrated + next_key_reads,
writes,
};
}
};
}
}

StateMigrationResult {
last_key: Some(key),
error: None,
migrated,
reads: migrated + next_key_reads,
writes,
}
}
}

#[pallet::call]
Expand Down
Loading
Loading