Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions runtime/parachains/src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub use pallet::*;

pub mod migration;

#[allow(dead_code)]
const LOG_TARGET: &str = "runtime::configuration";

/// All configuration of the runtime with respect to parachains and parathreads.
Expand Down
292 changes: 3 additions & 289 deletions runtime/parachains/src/configuration/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,299 +16,13 @@

//! A module that is responsible for migration of storage.

use crate::configuration::{self, Config, Pallet, Store};
use frame_support::{pallet_prelude::*, traits::StorageVersion, weights::Weight};
use frame_system::pallet_prelude::BlockNumberFor;
use crate::configuration::Config;
use frame_support::{traits::StorageVersion, weights::Weight};

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

/// Migrates the pallet storage to the most recent version, checking and setting the `StorageVersion`.
pub fn migrate_to_latest<T: Config>() -> Weight {
let mut weight = 0;

if StorageVersion::get::<Pallet<T>>() == 0 {
weight += migrate_to_v1::<T>();
StorageVersion::new(1).put::<Pallet<T>>();
}

weight
}

mod v0 {
use super::*;
use primitives::v1::{Balance, SessionIndex};

#[derive(parity_scale_codec::Encode, parity_scale_codec::Decode, Debug)]
pub struct HostConfiguration<BlockNumber> {
pub max_code_size: u32,
pub max_head_data_size: u32,
pub max_upward_queue_count: u32,
pub max_upward_queue_size: u32,
pub max_upward_message_size: u32,
pub max_upward_message_num_per_candidate: u32,
pub hrmp_max_message_num_per_candidate: u32,
pub validation_upgrade_frequency: BlockNumber,
pub validation_upgrade_delay: BlockNumber,
pub max_pov_size: u32,
pub max_downward_message_size: u32,
pub ump_service_total_weight: Weight,
pub hrmp_max_parachain_outbound_channels: u32,
pub hrmp_max_parathread_outbound_channels: u32,
pub _hrmp_open_request_ttl: u32,
pub hrmp_sender_deposit: Balance,
pub hrmp_recipient_deposit: Balance,
pub hrmp_channel_max_capacity: u32,
pub hrmp_channel_max_total_size: u32,
pub hrmp_max_parachain_inbound_channels: u32,
pub hrmp_max_parathread_inbound_channels: u32,
pub hrmp_channel_max_message_size: u32,
pub code_retention_period: BlockNumber,
pub parathread_cores: u32,
pub parathread_retries: u32,
pub group_rotation_frequency: BlockNumber,
pub chain_availability_period: BlockNumber,
pub thread_availability_period: BlockNumber,
pub scheduling_lookahead: u32,
pub max_validators_per_core: Option<u32>,
pub max_validators: Option<u32>,
pub dispute_period: SessionIndex,
pub dispute_post_conclusion_acceptance_period: BlockNumber,
pub dispute_max_spam_slots: u32,
pub dispute_conclusion_by_time_out_period: BlockNumber,
pub no_show_slots: u32,
pub n_delay_tranches: u32,
pub zeroth_delay_tranche_width: u32,
pub needed_approvals: u32,
pub relay_vrf_modulo_samples: u32,
}

impl<BlockNumber: Default + From<u32>> Default for HostConfiguration<BlockNumber> {
fn default() -> Self {
HostConfiguration {
group_rotation_frequency: 1u32.into(),
chain_availability_period: 1u32.into(),
thread_availability_period: 1u32.into(),
no_show_slots: 1u32.into(),
validation_upgrade_frequency: Default::default(),
validation_upgrade_delay: Default::default(),
code_retention_period: Default::default(),
max_code_size: Default::default(),
max_pov_size: Default::default(),
max_head_data_size: Default::default(),
parathread_cores: Default::default(),
parathread_retries: Default::default(),
scheduling_lookahead: Default::default(),
max_validators_per_core: Default::default(),
max_validators: None,
dispute_period: 6,
dispute_post_conclusion_acceptance_period: 100.into(),
dispute_max_spam_slots: 2,
dispute_conclusion_by_time_out_period: 200.into(),
n_delay_tranches: Default::default(),
zeroth_delay_tranche_width: Default::default(),
needed_approvals: Default::default(),
relay_vrf_modulo_samples: Default::default(),
max_upward_queue_count: Default::default(),
max_upward_queue_size: Default::default(),
max_downward_message_size: Default::default(),
ump_service_total_weight: Default::default(),
max_upward_message_size: Default::default(),
max_upward_message_num_per_candidate: Default::default(),
_hrmp_open_request_ttl: Default::default(),
hrmp_sender_deposit: Default::default(),
hrmp_recipient_deposit: Default::default(),
hrmp_channel_max_capacity: Default::default(),
hrmp_channel_max_total_size: Default::default(),
hrmp_max_parachain_inbound_channels: Default::default(),
hrmp_max_parathread_inbound_channels: Default::default(),
hrmp_channel_max_message_size: Default::default(),
hrmp_max_parachain_outbound_channels: Default::default(),
hrmp_max_parathread_outbound_channels: Default::default(),
hrmp_max_message_num_per_candidate: Default::default(),
}
}
}
}

/// Migrates the `HostConfiguration` from v0 (with deprecated `hrmp_open_request_ttl` and without
/// `ump_max_individual_weight`) to v1 (without HRMP TTL and with max individual weight).
/// Uses the `Default` implementation of `HostConfiguration` to choose a value for `ump_max_individual_weight`.
///
/// NOTE: Only use this function if you know what you are doing. Default to using `migrate_to_latest`.
pub fn migrate_to_v1<T: Config>() -> Weight {
// Unusual formatting is justified:
// - make it easier to verify that fields assign what they supposed to assign.
// - this code is transient and will be removed after all migrations are done.
// - this code is important enough to optimize for legibility sacrificing consistency.
#[rustfmt::skip]
let translate =
|pre: v0::HostConfiguration<BlockNumberFor<T>>| -> configuration::HostConfiguration<BlockNumberFor<T>>
{
super::HostConfiguration {

max_code_size : pre.max_code_size,
max_head_data_size : pre.max_head_data_size,
max_upward_queue_count : pre.max_upward_queue_count,
max_upward_queue_size : pre.max_upward_queue_size,
max_upward_message_size : pre.max_upward_message_size,
max_upward_message_num_per_candidate : pre.max_upward_message_num_per_candidate,
hrmp_max_message_num_per_candidate : pre.hrmp_max_message_num_per_candidate,
validation_upgrade_frequency : pre.validation_upgrade_frequency,
validation_upgrade_delay : pre.validation_upgrade_delay,
max_pov_size : pre.max_pov_size,
max_downward_message_size : pre.max_downward_message_size,
ump_service_total_weight : pre.ump_service_total_weight,
hrmp_max_parachain_outbound_channels : pre.hrmp_max_parachain_outbound_channels,
hrmp_max_parathread_outbound_channels : pre.hrmp_max_parathread_outbound_channels,
hrmp_sender_deposit : pre.hrmp_sender_deposit,
hrmp_recipient_deposit : pre.hrmp_recipient_deposit,
hrmp_channel_max_capacity : pre.hrmp_channel_max_capacity,
hrmp_channel_max_total_size : pre.hrmp_channel_max_total_size,
hrmp_max_parachain_inbound_channels : pre.hrmp_max_parachain_inbound_channels,
hrmp_max_parathread_inbound_channels : pre.hrmp_max_parathread_inbound_channels,
hrmp_channel_max_message_size : pre.hrmp_channel_max_message_size,
code_retention_period : pre.code_retention_period,
parathread_cores : pre.parathread_cores,
parathread_retries : pre.parathread_retries,
group_rotation_frequency : pre.group_rotation_frequency,
chain_availability_period : pre.chain_availability_period,
thread_availability_period : pre.thread_availability_period,
scheduling_lookahead : pre.scheduling_lookahead,
max_validators_per_core : pre.max_validators_per_core,
max_validators : pre.max_validators,
dispute_period : pre.dispute_period,
dispute_post_conclusion_acceptance_period: pre.dispute_post_conclusion_acceptance_period,
dispute_max_spam_slots : pre.dispute_max_spam_slots,
dispute_conclusion_by_time_out_period : pre.dispute_conclusion_by_time_out_period,
no_show_slots : pre.no_show_slots,
n_delay_tranches : pre.n_delay_tranches,
zeroth_delay_tranche_width : pre.zeroth_delay_tranche_width,
needed_approvals : pre.needed_approvals,
relay_vrf_modulo_samples : pre.relay_vrf_modulo_samples,

ump_max_individual_weight: <configuration::HostConfiguration<BlockNumberFor<T>>>::default().ump_max_individual_weight,
}
};

if let Err(_) = <Pallet<T> as Store>::ActiveConfig::translate(|pre| pre.map(translate)) {
// `Err` is returned when the pre-migration type cannot be deserialized. This
// cannot happen if the migration runs correctly, i.e. against the expected version.
//
// This happening almost surely will lead to a panic somewhere else. Corruption seems
// to be unlikely to be caused by this. So we just log. Maybe it'll work out still?
log::error!(
target: configuration::LOG_TARGET,
"unexpected error when performing translation of the configuration type during storage upgrade to v1."
);
}

T::DbWeight::get().reads_writes(1, 1)
}

#[cfg(test)]
mod tests {
use super::*;
use crate::mock::{new_test_ext, Test};

#[test]
fn v0_deserialized_from_actual_data() {
// Fetched at Kusama 9,207,703 (0xbfe5227324c08b3ab67e0473a360acbce43efbd7b42041d0033adaf9ff2c5330)
//
// This exceeds the maximal line width length, but that's fine, since this is not code and
// doesn't need to be read and also leaving it as one line allows to easily copy it.
let raw_config = hex_literal::hex!["0000a000005000000a00000000c8000000c800000a0000000a00000040380000580200000000500000c8000000e87648170000000a0000000000000048000000c09e5d9a2f3d00000000000000000000c09e5d9a2f3d00000000000000000000e8030000009001000a00000000000000009001008070000000000000000000000a0000000a0000000a00000001000000010500000001c8000000060000005802000002000000580200000200000059000000000000001e00000028000000"];

let v0 = v0::HostConfiguration::<primitives::v1::BlockNumber>::decode(&mut &raw_config[..])
.unwrap();

// We check only a sample of the values here. If we missed any fields or messed up data types
// that would skew all the fields coming after.
assert_eq!(v0.max_code_size, 10_485_760);
assert_eq!(v0.validation_upgrade_frequency, 14_400);
assert_eq!(v0.max_pov_size, 5_242_880);
assert_eq!(v0._hrmp_open_request_ttl, 72);
assert_eq!(v0.hrmp_channel_max_message_size, 102_400);
assert_eq!(v0.dispute_max_spam_slots, 2);
assert_eq!(v0.n_delay_tranches, 89);
assert_eq!(v0.relay_vrf_modulo_samples, 40);
}

#[test]
fn test_migrate_to_v1() {
// Host configuration has lots of fields. However, in this migration we add one and remove one
// field. The most important part to check are a couple of the last fields. We also pick
// extra fields to check arbitrarily, e.g. depending on their position (i.e. the middle) and
// also their type.
//
// We specify only the picked fields and the rest should be provided by the `Default`
// implementation. That implementation is copied over between the two types and should work
// fine.
let v0 = v0::HostConfiguration::<primitives::v1::BlockNumber> {
relay_vrf_modulo_samples: 0xFEEDBEEFu32,
needed_approvals: 69,
thread_availability_period: 55,
hrmp_recipient_deposit: 1337,
max_pov_size: 1111,
..Default::default()
};

new_test_ext(Default::default()).execute_with(|| {
// Implant the v0 version in the state.
frame_support::storage::unhashed::put_raw(
&configuration::ActiveConfig::<Test>::hashed_key(),
&v0.encode(),
);

migrate_to_v1::<Test>();

let v1 = configuration::ActiveConfig::<Test>::get();

// The same motivation as for the migration code. See `migrate_to_v1`.
#[rustfmt::skip]
{
assert_eq!(v0.max_code_size , v1.max_code_size);
assert_eq!(v0.max_head_data_size , v1.max_head_data_size);
assert_eq!(v0.max_upward_queue_count , v1.max_upward_queue_count);
assert_eq!(v0.max_upward_queue_size , v1.max_upward_queue_size);
assert_eq!(v0.max_upward_message_size , v1.max_upward_message_size);
assert_eq!(v0.max_upward_message_num_per_candidate , v1.max_upward_message_num_per_candidate);
assert_eq!(v0.hrmp_max_message_num_per_candidate , v1.hrmp_max_message_num_per_candidate);
assert_eq!(v0.validation_upgrade_frequency , v1.validation_upgrade_frequency);
assert_eq!(v0.validation_upgrade_delay , v1.validation_upgrade_delay);
assert_eq!(v0.max_pov_size , v1.max_pov_size);
assert_eq!(v0.max_downward_message_size , v1.max_downward_message_size);
assert_eq!(v0.ump_service_total_weight , v1.ump_service_total_weight);
assert_eq!(v0.hrmp_max_parachain_outbound_channels , v1.hrmp_max_parachain_outbound_channels);
assert_eq!(v0.hrmp_max_parathread_outbound_channels , v1.hrmp_max_parathread_outbound_channels);
assert_eq!(v0.hrmp_sender_deposit , v1.hrmp_sender_deposit);
assert_eq!(v0.hrmp_recipient_deposit , v1.hrmp_recipient_deposit);
assert_eq!(v0.hrmp_channel_max_capacity , v1.hrmp_channel_max_capacity);
assert_eq!(v0.hrmp_channel_max_total_size , v1.hrmp_channel_max_total_size);
assert_eq!(v0.hrmp_max_parachain_inbound_channels , v1.hrmp_max_parachain_inbound_channels);
assert_eq!(v0.hrmp_max_parathread_inbound_channels , v1.hrmp_max_parathread_inbound_channels);
assert_eq!(v0.hrmp_channel_max_message_size , v1.hrmp_channel_max_message_size);
assert_eq!(v0.code_retention_period , v1.code_retention_period);
assert_eq!(v0.parathread_cores , v1.parathread_cores);
assert_eq!(v0.parathread_retries , v1.parathread_retries);
assert_eq!(v0.group_rotation_frequency , v1.group_rotation_frequency);
assert_eq!(v0.chain_availability_period , v1.chain_availability_period);
assert_eq!(v0.thread_availability_period , v1.thread_availability_period);
assert_eq!(v0.scheduling_lookahead , v1.scheduling_lookahead);
assert_eq!(v0.max_validators_per_core , v1.max_validators_per_core);
assert_eq!(v0.max_validators , v1.max_validators);
assert_eq!(v0.dispute_period , v1.dispute_period);
assert_eq!(v0.dispute_post_conclusion_acceptance_period, v1.dispute_post_conclusion_acceptance_period);
assert_eq!(v0.dispute_max_spam_slots , v1.dispute_max_spam_slots);
assert_eq!(v0.dispute_conclusion_by_time_out_period , v1.dispute_conclusion_by_time_out_period);
assert_eq!(v0.no_show_slots , v1.no_show_slots);
assert_eq!(v0.n_delay_tranches , v1.n_delay_tranches);
assert_eq!(v0.zeroth_delay_tranche_width , v1.zeroth_delay_tranche_width);
assert_eq!(v0.needed_approvals , v1.needed_approvals);
assert_eq!(v0.relay_vrf_modulo_samples , v1.relay_vrf_modulo_samples);

assert_eq!(v1.ump_max_individual_weight, 20_000_000_000);
}; // ; makes this a statement. `rustfmt::skip` cannot be put on an expression.
});
}
0
}
20 changes: 20 additions & 0 deletions runtime/polkadot/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1543,6 +1543,26 @@ impl OnRuntimeUpgrade for SetInitialHostConfiguration {
Configuration::force_set_active_config(active_config);
}

{
// At the moment, the `parachains_configuration` crate has already had one runtime
// storage migration (performed as part of [#3575]). As the result a call to
// `StorageVersion::get::<Configuration>` will return `Some(1)`
//
// However, Polkadot is just about to have its first version of parachains runtime
// pallets and thus there is no existing storage which needs to be migrated. Above
// we just have set the active configuration of the actual version, i.e. the same as the
// version 1 on Kusama.
//
// The caveat here is when we deploy a module for the first time, it's runtime version
// will be empty and thus it will be considered as version 0. Since we want to avoid
// the situation where the same storage structure has version 0 on Polkadot and
// version 1 on Kusama we need to set the storage version explicitly.
//
// [#3575]: https://github.com/paritytech/polkadot/pull/3575
use frame_support::traits::StorageVersion;
StorageVersion::new(1).put::<Configuration>();
}

RocksDbWeight::get().reads(1) + RocksDbWeight::get().writes(1)
}
}
Expand Down