Skip to content

Commit

Permalink
Runtime Upgrade ref docs and Single Block Migration example pallet (p…
Browse files Browse the repository at this point in the history
…aritytech#1554)

Closes paritytech/polkadot-sdk-docs#55

- Changes 'current storage version' terminology to less ambiguous
'in-code storage version' (suggestion by @ggwpez)
- Adds a new example pallet `pallet-example-single-block-migrations`
- Adds a new reference doc to replace
https://docs.substrate.io/maintain/runtime-upgrades/ (temporarily living
in the pallet while we wait for developer hub PR to merge)
- Adds documentation for the `storage_alias` macro
- Improves `trait Hooks` docs 
- Improves `trait GetStorageVersion` docs
- Update the suggested patterns for using `VersionedMigration`, so that
version unchecked migrations are never exported
- Prevents accidental usage of version unchecked migrations in runtimes

paritytech/substrate#14421 (comment)
- Unversioned migration code is kept inside `mod version_unchecked`,
versioned code is kept in `pub mod versioned`
- It is necessary to use modules to limit visibility because the inner
migration must be `pub`. See
rust-lang/rust#30905 and

https://internals.rust-lang.org/t/lang-team-minutes-private-in-public-rules/4504/40
for more.

### todo

- [x] move to reference docs to proper place within sdk-docs (now that
paritytech#2102 is merged)
- [x] prdoc

---------

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
Co-authored-by: Juan <juangirini@gmail.com>
Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Co-authored-by: command-bot <>
Co-authored-by: gupnik <nikhilgupta.iitk@gmail.com>
  • Loading branch information
5 people authored Feb 28, 2024
1 parent 4fbe140 commit 0cf9a38
Show file tree
Hide file tree
Showing 62 changed files with 998 additions and 319 deletions.
14 changes: 7 additions & 7 deletions substrate/client/executor/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ where
runtime_code,
ext,
heap_alloc_strategy,
|_, mut instance, _onchain_version, mut ext| {
|_, mut instance, _on_chain_version, mut ext| {
with_externalities_safe(&mut **ext, move || instance.call_export(method, data))
},
);
Expand Down Expand Up @@ -682,18 +682,18 @@ impl<D: NativeExecutionDispatch + 'static> CodeExecutor for NativeElseWasmExecut
runtime_code,
ext,
heap_alloc_strategy,
|_, mut instance, onchain_version, mut ext| {
let onchain_version =
onchain_version.ok_or_else(|| Error::ApiError("Unknown version".into()))?;
|_, mut instance, on_chain_version, mut ext| {
let on_chain_version =
on_chain_version.ok_or_else(|| Error::ApiError("Unknown version".into()))?;

let can_call_with =
onchain_version.can_call_with(&self.native_version.runtime_version);
on_chain_version.can_call_with(&self.native_version.runtime_version);

if use_native && can_call_with {
tracing::trace!(
target: "executor",
native = %self.native_version.runtime_version,
chain = %onchain_version,
chain = %on_chain_version,
"Request for native execution succeeded",
);

Expand All @@ -705,7 +705,7 @@ impl<D: NativeExecutionDispatch + 'static> CodeExecutor for NativeElseWasmExecut
tracing::trace!(
target: "executor",
native = %self.native_version.runtime_version,
chain = %onchain_version,
chain = %on_chain_version,
"Request for native execution failed",
);
}
Expand Down
8 changes: 4 additions & 4 deletions substrate/frame/alliance/src/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@ use crate::{Config, Pallet, Weight, LOG_TARGET};
use frame_support::{pallet_prelude::*, storage::migration, traits::OnRuntimeUpgrade};
use log;

/// The current storage version.
/// The in-code storage version.
pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(2);

/// Wrapper for all migrations of this pallet.
pub fn migrate<T: Config<I>, I: 'static>() -> Weight {
let onchain_version = Pallet::<T, I>::on_chain_storage_version();
let on_chain_version = Pallet::<T, I>::on_chain_storage_version();
let mut weight: Weight = Weight::zero();

if onchain_version < 1 {
if on_chain_version < 1 {
weight = weight.saturating_add(v0_to_v1::migrate::<T, I>());
}

if onchain_version < 2 {
if on_chain_version < 2 {
weight = weight.saturating_add(v1_to_v2::migrate::<T, I>());
}

Expand Down
2 changes: 1 addition & 1 deletion substrate/frame/assets/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ pub mod pallet {
};
use frame_system::pallet_prelude::*;

/// The current storage version.
/// The in-code storage version.
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);

#[pallet::pallet]
Expand Down
20 changes: 10 additions & 10 deletions substrate/frame/assets/src/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ pub mod v1 {
pub struct MigrateToV1<T>(core::marker::PhantomData<T>);
impl<T: Config> OnRuntimeUpgrade for MigrateToV1<T> {
fn on_runtime_upgrade() -> Weight {
let current_version = Pallet::<T>::current_storage_version();
let onchain_version = Pallet::<T>::on_chain_storage_version();
if onchain_version == 0 && current_version == 1 {
let in_code_version = Pallet::<T>::in_code_storage_version();
let on_chain_version = Pallet::<T>::on_chain_storage_version();
if on_chain_version == 0 && in_code_version == 1 {
let mut translated = 0u64;
Asset::<T>::translate::<
OldAssetDetails<T::Balance, T::AccountId, DepositBalanceOf<T>>,
Expand All @@ -78,12 +78,12 @@ pub mod v1 {
translated.saturating_inc();
Some(old_value.migrate_to_v1())
});
current_version.put::<Pallet<T>>();
in_code_version.put::<Pallet<T>>();
log::info!(
target: LOG_TARGET,
"Upgraded {} pools, storage to version {:?}",
translated,
current_version
in_code_version
);
T::DbWeight::get().reads_writes(translated + 1, translated + 1)
} else {
Expand Down Expand Up @@ -116,13 +116,13 @@ pub mod v1 {
"the asset count before and after the migration should be the same"
);

let current_version = Pallet::<T>::current_storage_version();
let onchain_version = Pallet::<T>::on_chain_storage_version();
let in_code_version = Pallet::<T>::in_code_storage_version();
let on_chain_version = Pallet::<T>::on_chain_storage_version();

frame_support::ensure!(current_version == 1, "must_upgrade");
frame_support::ensure!(in_code_version == 1, "must_upgrade");
ensure!(
current_version == onchain_version,
"after migration, the current_version and onchain_version should be the same"
in_code_version == on_chain_version,
"after migration, the in_code_version and on_chain_version should be the same"
);

Asset::<T>::iter().try_for_each(|(_id, asset)| -> Result<(), TryRuntimeError> {
Expand Down
2 changes: 1 addition & 1 deletion substrate/frame/balances/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ pub mod pallet {
type MaxFreezes: Get<u32>;
}

/// The current storage version.
/// The in-code storage version.
const STORAGE_VERSION: frame_support::traits::StorageVersion =
frame_support::traits::StorageVersion::new(1);

Expand Down
8 changes: 4 additions & 4 deletions substrate/frame/balances/src/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ use frame_support::{
};

fn migrate_v0_to_v1<T: Config<I>, I: 'static>(accounts: &[T::AccountId]) -> Weight {
let onchain_version = Pallet::<T, I>::on_chain_storage_version();
let on_chain_version = Pallet::<T, I>::on_chain_storage_version();

if onchain_version == 0 {
if on_chain_version == 0 {
let total = accounts
.iter()
.map(|a| Pallet::<T, I>::total_balance(a))
Expand Down Expand Up @@ -76,9 +76,9 @@ impl<T: Config<I>, A: Get<Vec<T::AccountId>>, I: 'static> OnRuntimeUpgrade
pub struct ResetInactive<T, I = ()>(PhantomData<(T, I)>);
impl<T: Config<I>, I: 'static> OnRuntimeUpgrade for ResetInactive<T, I> {
fn on_runtime_upgrade() -> Weight {
let onchain_version = Pallet::<T, I>::on_chain_storage_version();
let on_chain_version = Pallet::<T, I>::on_chain_storage_version();

if onchain_version == 1 {
if on_chain_version == 1 {
// Remove the old `StorageVersion` type.
frame_support::storage::unhashed::kill(&frame_support::storage::storage_prefix(
Pallet::<T, I>::name().as_bytes(),
Expand Down
2 changes: 1 addition & 1 deletion substrate/frame/collective/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ pub mod pallet {
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;

/// The current storage version.
/// The in-code storage version.
const STORAGE_VERSION: StorageVersion = StorageVersion::new(4);

#[pallet::pallet]
Expand Down
2 changes: 1 addition & 1 deletion substrate/frame/contracts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ pub mod pallet {
use frame_system::pallet_prelude::*;
use sp_runtime::Perbill;

/// The current storage version.
/// The in-code storage version.
pub(crate) const STORAGE_VERSION: StorageVersion = StorageVersion::new(15);

#[pallet::pallet]
Expand Down
20 changes: 10 additions & 10 deletions substrate/frame/contracts/src/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,10 @@ impl<T: Config, const TEST_ALL_STEPS: bool> Migration<T, TEST_ALL_STEPS> {
impl<T: Config, const TEST_ALL_STEPS: bool> OnRuntimeUpgrade for Migration<T, TEST_ALL_STEPS> {
fn on_runtime_upgrade() -> Weight {
let name = <Pallet<T>>::name();
let current_version = <Pallet<T>>::current_storage_version();
let in_code_version = <Pallet<T>>::in_code_storage_version();
let on_chain_version = <Pallet<T>>::on_chain_storage_version();

if on_chain_version == current_version {
if on_chain_version == in_code_version {
log::warn!(
target: LOG_TARGET,
"{name}: No Migration performed storage_version = latest_version = {:?}",
Expand All @@ -289,7 +289,7 @@ impl<T: Config, const TEST_ALL_STEPS: bool> OnRuntimeUpgrade for Migration<T, TE

log::info!(
target: LOG_TARGET,
"{name}: Upgrading storage from {on_chain_version:?} to {current_version:?}.",
"{name}: Upgrading storage from {on_chain_version:?} to {in_code_version:?}.",
);

let cursor = T::Migrations::new(on_chain_version + 1);
Expand All @@ -309,21 +309,21 @@ impl<T: Config, const TEST_ALL_STEPS: bool> OnRuntimeUpgrade for Migration<T, TE
// Instead, we call the migrations `pre_upgrade` and `post_upgrade` hooks when we iterate
// over our migrations.
let on_chain_version = <Pallet<T>>::on_chain_storage_version();
let current_version = <Pallet<T>>::current_storage_version();
let in_code_version = <Pallet<T>>::in_code_storage_version();

if on_chain_version == current_version {
if on_chain_version == in_code_version {
return Ok(Default::default())
}

log::debug!(
target: LOG_TARGET,
"Requested migration of {} from {:?}(on-chain storage version) to {:?}(current storage version)",
<Pallet<T>>::name(), on_chain_version, current_version
"Requested migration of {} from {:?}(on-chain storage version) to {:?}(in-code storage version)",
<Pallet<T>>::name(), on_chain_version, in_code_version
);

ensure!(
T::Migrations::is_upgrade_supported(on_chain_version, current_version),
"Unsupported upgrade: VERSION_RANGE should be (on-chain storage version + 1, current storage version)"
T::Migrations::is_upgrade_supported(on_chain_version, in_code_version),
"Unsupported upgrade: VERSION_RANGE should be (on-chain storage version + 1, in-code storage version)"
);

Ok(Default::default())
Expand Down Expand Up @@ -421,7 +421,7 @@ impl<T: Config, const TEST_ALL_STEPS: bool> Migration<T, TEST_ALL_STEPS> {
},
StepResult::Completed { steps_done } => {
in_progress_version.put::<Pallet<T>>();
if <Pallet<T>>::current_storage_version() != in_progress_version {
if <Pallet<T>>::in_code_storage_version() != in_progress_version {
log::info!(
target: LOG_TARGET,
"{name}: Next migration is {:?},",
Expand Down
14 changes: 7 additions & 7 deletions substrate/frame/contracts/src/migration/v09.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use frame_support::{pallet_prelude::*, storage_alias, DefaultNoBound, Identity};
use sp_runtime::TryRuntimeError;
use sp_std::prelude::*;

mod old {
mod v8 {
use super::*;

#[derive(Encode, Decode)]
Expand All @@ -50,14 +50,14 @@ mod old {
#[cfg(feature = "runtime-benchmarks")]
pub fn store_old_dummy_code<T: Config>(len: usize) {
use sp_runtime::traits::Hash;
let module = old::PrefabWasmModule {
let module = v8::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);
v8::CodeStorage::<T>::insert(hash, module);
}

#[derive(Encode, Decode)]
Expand Down Expand Up @@ -89,9 +89,9 @@ impl<T: Config> MigrationStep for Migration<T> {

fn step(&mut self) -> (IsFinished, Weight) {
let mut iter = if let Some(last_key) = self.last_code_hash.take() {
old::CodeStorage::<T>::iter_from(old::CodeStorage::<T>::hashed_key_for(last_key))
v8::CodeStorage::<T>::iter_from(v8::CodeStorage::<T>::hashed_key_for(last_key))
} else {
old::CodeStorage::<T>::iter()
v8::CodeStorage::<T>::iter()
};

if let Some((key, old)) = iter.next() {
Expand All @@ -115,15 +115,15 @@ impl<T: Config> MigrationStep for Migration<T> {

#[cfg(feature = "try-runtime")]
fn pre_upgrade_step() -> Result<Vec<u8>, TryRuntimeError> {
let sample: Vec<_> = old::CodeStorage::<T>::iter().take(100).collect();
let sample: Vec<_> = v8::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[..])
let sample = <Vec<(CodeHash<T>, v8::PrefabWasmModule)> as Decode>::decode(&mut &state[..])
.expect("pre_upgrade_step provides a valid state; qed");

log::debug!(target: LOG_TARGET, "Validating sample of {} contract codes", sample.len());
Expand Down
24 changes: 12 additions & 12 deletions substrate/frame/contracts/src/migration/v10.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ use sp_runtime::{
};
use sp_std::prelude::*;

mod old {
mod v9 {
use super::*;

pub type BalanceOf<T, OldCurrency> = <OldCurrency as frame_support::traits::Currency<
Expand Down Expand Up @@ -85,7 +85,7 @@ pub fn store_old_contract_info<T: Config, OldCurrency>(
) where
OldCurrency: ReservableCurrency<<T as frame_system::Config>::AccountId> + 'static,
{
let info = old::ContractInfo {
let info = v9::ContractInfo {
trie_id: info.trie_id,
code_hash: info.code_hash,
storage_bytes: Default::default(),
Expand All @@ -94,7 +94,7 @@ pub fn store_old_contract_info<T: Config, OldCurrency>(
storage_item_deposit: Default::default(),
storage_base_deposit: Default::default(),
};
old::ContractInfoOf::<T, OldCurrency>::insert(account, info);
v9::ContractInfoOf::<T, OldCurrency>::insert(account, info);
}

#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebugNoBound, TypeInfo, MaxEncodedLen)]
Expand All @@ -120,9 +120,9 @@ where
pub code_hash: CodeHash<T>,
storage_bytes: u32,
storage_items: u32,
pub storage_byte_deposit: old::BalanceOf<T, OldCurrency>,
storage_item_deposit: old::BalanceOf<T, OldCurrency>,
storage_base_deposit: old::BalanceOf<T, OldCurrency>,
pub storage_byte_deposit: v9::BalanceOf<T, OldCurrency>,
storage_item_deposit: v9::BalanceOf<T, OldCurrency>,
storage_base_deposit: v9::BalanceOf<T, OldCurrency>,
}

#[derive(Encode, Decode, MaxEncodedLen, DefaultNoBound)]
Expand Down Expand Up @@ -152,7 +152,7 @@ fn deposit_address<T: Config>(
impl<T: Config, OldCurrency: 'static> MigrationStep for Migration<T, OldCurrency>
where
OldCurrency: ReservableCurrency<<T as frame_system::Config>::AccountId>
+ Inspect<<T as frame_system::Config>::AccountId, Balance = old::BalanceOf<T, OldCurrency>>,
+ Inspect<<T as frame_system::Config>::AccountId, Balance = v9::BalanceOf<T, OldCurrency>>,
{
const VERSION: u16 = 10;

Expand All @@ -162,11 +162,11 @@ where

fn step(&mut self) -> (IsFinished, Weight) {
let mut iter = if let Some(last_account) = self.last_account.take() {
old::ContractInfoOf::<T, OldCurrency>::iter_from(
old::ContractInfoOf::<T, OldCurrency>::hashed_key_for(last_account),
v9::ContractInfoOf::<T, OldCurrency>::iter_from(
v9::ContractInfoOf::<T, OldCurrency>::hashed_key_for(last_account),
)
} else {
old::ContractInfoOf::<T, OldCurrency>::iter()
v9::ContractInfoOf::<T, OldCurrency>::iter()
};

if let Some((account, contract)) = iter.next() {
Expand Down Expand Up @@ -276,15 +276,15 @@ where

#[cfg(feature = "try-runtime")]
fn pre_upgrade_step() -> Result<Vec<u8>, TryRuntimeError> {
let sample: Vec<_> = old::ContractInfoOf::<T, OldCurrency>::iter().take(10).collect();
let sample: Vec<_> = v9::ContractInfoOf::<T, OldCurrency>::iter().take(10).collect();

log::debug!(target: LOG_TARGET, "Taking sample of {} contracts", sample.len());
Ok(sample.encode())
}

#[cfg(feature = "try-runtime")]
fn post_upgrade_step(state: Vec<u8>) -> Result<(), TryRuntimeError> {
let sample = <Vec<(T::AccountId, old::ContractInfo<T, OldCurrency>)> as Decode>::decode(
let sample = <Vec<(T::AccountId, v9::ContractInfo<T, OldCurrency>)> as Decode>::decode(
&mut &state[..],
)
.expect("pre_upgrade_step provides a valid state; qed");
Expand Down
Loading

0 comments on commit 0cf9a38

Please sign in to comment.