contracts: Multi block migrations (#14045)

* Frame Add translate_next

This works similarly to to `translate` but only translate a single entry.
This function will be useful in the context of multi-block migration.

* Move to lazy migration

* Updates

* simplify MockMigration

* wip

* wip

* add bench

* add bench

* fmt

* fix bench

* add .

* ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts

* Apply suggestions from code review

Co-authored-by: Alexander Theißen <alex.theissen@me.com>

* Scalfold v10 / v11 fix tests

* PR comment

* tweak pub use

* wip

* wip

* wip

* misc merge master

* misc merge master

* wip

* rm tmp stuff

* wip

* wip

* wip

* wip

* wip

* fixes

* add state

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* fix

* fixed compilation

* clean up logs

* wip

* Revert "Frame Add translate_next"

This reverts commit 10318fc95c42b1f7f25efeb35e6d947ea02bed88.

* Fix v10 logic

* Apply suggestions from code review

Co-authored-by: Alexander Theißen <alex.theissen@me.com>

* wip

* fixes

* exercise del_queue

* bump sample size

* fmt

* wip

* blank line

* fix lint

* fix rustdoc job lint

* PR comment do not use dangerous into()

* Ad macros for updating mod visibility

* Add doc

* Add max_weight to integrity_test

* fix compilation

* Add no migration tests

* ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts

* fix clippy

* PR review

* Update frame/contracts/src/lib.rs

Co-authored-by: Sasha Gryaznov <hi@agryaznov.com>

* Fix master merge

* fix merge 2

* fix tryruntime

* fix lint

---------

Co-authored-by: Alexander Theißen <alex.theissen@me.com>
Co-authored-by: command-bot <>
Co-authored-by: Sasha Gryaznov <hi@agryaznov.com>
This commit is contained in:
PG Herveou
2023-05-31 16:19:31 +02:00
committed by GitHub
parent b43a1b0b55
commit c7c5fc709c
10 changed files with 2841 additions and 1482 deletions
@@ -0,0 +1,149 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Update `CodeStorage` with the new `determinism` field.
use crate::{
migration::{IsFinished, Migrate},
weights::WeightInfo,
CodeHash, Config, Determinism, Pallet, Weight, LOG_TARGET,
};
use codec::{Decode, Encode};
use frame_support::{
codec, pallet_prelude::*, storage_alias, BoundedVec, DefaultNoBound, Identity,
};
#[cfg(feature = "try-runtime")]
use sp_runtime::TryRuntimeError;
use sp_std::{marker::PhantomData, prelude::*};
mod old {
use super::*;
#[derive(Encode, Decode)]
pub struct PrefabWasmModule {
#[codec(compact)]
pub instruction_weights_version: u32,
#[codec(compact)]
pub initial: u32,
#[codec(compact)]
pub maximum: u32,
pub code: Vec<u8>,
}
#[storage_alias]
pub type CodeStorage<T: Config> =
StorageMap<Pallet<T>, Identity, CodeHash<T>, PrefabWasmModule>;
}
#[cfg(feature = "runtime-benchmarks")]
pub fn store_old_dummy_code<T: Config>(len: usize) {
use sp_runtime::traits::Hash;
let module = old::PrefabWasmModule {
instruction_weights_version: 0,
initial: 0,
maximum: 0,
code: vec![42u8; len],
};
let hash = T::Hashing::hash(&module.code);
old::CodeStorage::<T>::insert(hash, module);
}
#[derive(Encode, Decode)]
struct PrefabWasmModule {
#[codec(compact)]
pub instruction_weights_version: u32,
#[codec(compact)]
pub initial: u32,
#[codec(compact)]
pub maximum: u32,
pub code: Vec<u8>,
pub determinism: Determinism,
}
#[storage_alias]
type CodeStorage<T: Config> = StorageMap<Pallet<T>, Identity, CodeHash<T>, PrefabWasmModule>;
#[derive(Encode, Decode, MaxEncodedLen, DefaultNoBound)]
pub struct Migration<T: Config> {
last_key: Option<BoundedVec<u8, ConstU32<256>>>,
_phantom: PhantomData<T>,
}
impl<T: Config> Migrate for Migration<T> {
const VERSION: u16 = 9;
fn max_step_weight() -> Weight {
T::WeightInfo::v9_migration_step(T::MaxCodeLen::get())
}
fn step(&mut self) -> (IsFinished, Weight) {
let mut iter = if let Some(last_key) = self.last_key.take() {
old::CodeStorage::<T>::iter_from(last_key.to_vec())
} else {
old::CodeStorage::<T>::iter()
};
if let Some((key, old)) = iter.next() {
log::debug!(target: LOG_TARGET, "Migrating contract code {:?}", key);
let len = old.code.len() as u32;
let module = PrefabWasmModule {
instruction_weights_version: old.instruction_weights_version,
initial: old.initial,
maximum: old.maximum,
code: old.code,
determinism: Determinism::Enforced,
};
CodeStorage::<T>::insert(key, module);
self.last_key = Some(iter.last_raw_key().to_vec().try_into().unwrap());
(IsFinished::No, T::WeightInfo::v9_migration_step(len))
} else {
log::debug!(target: LOG_TARGET, "No more contracts code to migrate");
(IsFinished::Yes, T::WeightInfo::v9_migration_step(0))
}
}
#[cfg(feature = "try-runtime")]
fn pre_upgrade_step() -> Result<Vec<u8>, TryRuntimeError> {
let sample: Vec<_> = old::CodeStorage::<T>::iter().take(100).collect();
log::debug!(target: LOG_TARGET, "Taking sample of {} contract codes", sample.len());
Ok(sample.encode())
}
#[cfg(feature = "try-runtime")]
fn post_upgrade_step(state: Vec<u8>) -> Result<(), TryRuntimeError> {
let sample =
<Vec<(CodeHash<T>, old::PrefabWasmModule)> as Decode>::decode(&mut &state[..]).unwrap();
log::debug!(target: LOG_TARGET, "Validating sample of {} contract codes", sample.len());
for (code_hash, old) in sample {
let module = CodeStorage::<T>::get(&code_hash).unwrap();
ensure!(
module.instruction_weights_version == old.instruction_weights_version,
"invalid isntruction weights version"
);
ensure!(module.determinism == Determinism::Enforced, "invalid determinism");
ensure!(module.initial == old.initial, "invalid initial");
ensure!(module.maximum == old.maximum, "invalid maximum");
ensure!(module.code == old.code, "invalid code");
ensure!(module.maximum == old.maximum, "invalid maximum");
ensure!(module.code == old.code, "invalid code");
}
Ok(())
}
}