Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Fix migrations (#7340) #7349

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 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
101 changes: 50 additions & 51 deletions node/core/dispute-coordinator/src/initialized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,62 +214,61 @@ impl Initialized {
gum::trace!(target: LOG_TARGET, "Waiting for message");
let mut overlay_db = OverlayedBackend::new(backend);
let default_confirm = Box::new(|| Ok(()));
let confirm_write = match MuxedMessage::receive(ctx, &mut self.participation_receiver)
.await?
{
MuxedMessage::Participation(msg) => {
gum::trace!(target: LOG_TARGET, "MuxedMessage::Participation");
let ParticipationStatement {
session,
candidate_hash,
candidate_receipt,
outcome,
} = self.participation.get_participation_result(ctx, msg).await?;
if let Some(valid) = outcome.validity() {
gum::trace!(
target: LOG_TARGET,
?session,
?candidate_hash,
?valid,
"Issuing local statement based on participation outcome."
);
self.issue_local_statement(
ctx,
&mut overlay_db,
let confirm_write =
match MuxedMessage::receive(ctx, &mut self.participation_receiver).await? {
MuxedMessage::Participation(msg) => {
gum::trace!(target: LOG_TARGET, "MuxedMessage::Participation");
let ParticipationStatement {
session,
candidate_hash,
candidate_receipt,
session,
valid,
clock.now(),
)
.await?;
} else {
gum::warn!(target: LOG_TARGET, ?outcome, "Dispute participation failed");
}
default_confirm
},
MuxedMessage::Subsystem(msg) => match msg {
FromOrchestra::Signal(OverseerSignal::Conclude) => return Ok(()),
FromOrchestra::Signal(OverseerSignal::ActiveLeaves(update)) => {
gum::trace!(target: LOG_TARGET, "OverseerSignal::ActiveLeaves");
self.process_active_leaves_update(
ctx,
&mut overlay_db,
update,
clock.now(),
)
.await?;
outcome,
} = self.participation.get_participation_result(ctx, msg).await?;
if let Some(valid) = outcome.validity() {
gum::trace!(
target: LOG_TARGET,
?session,
?candidate_hash,
?valid,
"Issuing local statement based on participation outcome."
);
self.issue_local_statement(
ctx,
&mut overlay_db,
candidate_hash,
candidate_receipt,
session,
valid,
clock.now(),
)
.await?;
} else {
gum::warn!(target: LOG_TARGET, ?outcome, "Dispute participation failed");
}
default_confirm
},
FromOrchestra::Signal(OverseerSignal::BlockFinalized(_, n)) => {
gum::trace!(target: LOG_TARGET, "OverseerSignal::BlockFinalized");
self.scraper.process_finalized_block(&n);
default_confirm
MuxedMessage::Subsystem(msg) => match msg {
FromOrchestra::Signal(OverseerSignal::Conclude) => return Ok(()),
FromOrchestra::Signal(OverseerSignal::ActiveLeaves(update)) => {
gum::trace!(target: LOG_TARGET, "OverseerSignal::ActiveLeaves");
self.process_active_leaves_update(
ctx,
&mut overlay_db,
update,
clock.now(),
)
.await?;
default_confirm
},
FromOrchestra::Signal(OverseerSignal::BlockFinalized(_, n)) => {
gum::trace!(target: LOG_TARGET, "OverseerSignal::BlockFinalized");
self.scraper.process_finalized_block(&n);
default_confirm
},
FromOrchestra::Communication { msg } =>
self.handle_incoming(ctx, &mut overlay_db, msg, clock.now()).await?,
},
FromOrchestra::Communication { msg } =>
self.handle_incoming(ctx, &mut overlay_db, msg, clock.now()).await?,
},
};
};

if !overlay_db.is_empty() {
let ops = overlay_db.into_write_ops();
Expand Down
73 changes: 41 additions & 32 deletions runtime/parachains/src/configuration/migration/v5.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,27 +127,35 @@ pub struct V5HostConfiguration<BlockNumber> {
pub minimum_validation_upgrade_delay: BlockNumber,
}

#[frame_support::storage_alias]
pub(crate) type V4ActiveConfig<T: Config> =
StorageValue<Pallet<T>, V4HostConfiguration<BlockNumberFor<T>>, OptionQuery>;

#[frame_support::storage_alias]
pub(crate) type V4PendingConfigs<T: Config> = StorageValue<
Pallet<T>,
Vec<(SessionIndex, V4HostConfiguration<BlockNumberFor<T>>)>,
OptionQuery,
>;

#[frame_support::storage_alias]
pub(crate) type V5ActiveConfig<T: Config> =
StorageValue<Pallet<T>, V5HostConfiguration<BlockNumberFor<T>>, OptionQuery>;

#[frame_support::storage_alias]
pub(crate) type V5PendingConfigs<T: Config> = StorageValue<
Pallet<T>,
Vec<(SessionIndex, V5HostConfiguration<BlockNumberFor<T>>)>,
OptionQuery,
>;
mod v4 {
use super::*;

#[frame_support::storage_alias]
pub(crate) type ActiveConfig<T: Config> =
StorageValue<Pallet<T>, V4HostConfiguration<BlockNumberFor<T>>, OptionQuery>;

#[frame_support::storage_alias]
pub(crate) type PendingConfigs<T: Config> = StorageValue<
Pallet<T>,
Vec<(SessionIndex, V4HostConfiguration<BlockNumberFor<T>>)>,
OptionQuery,
>;
}

mod v5 {
use super::*;

#[frame_support::storage_alias]
pub(crate) type ActiveConfig<T: Config> =
StorageValue<Pallet<T>, V5HostConfiguration<BlockNumberFor<T>>, OptionQuery>;

#[frame_support::storage_alias]
pub(crate) type PendingConfigs<T: Config> = StorageValue<
Pallet<T>,
Vec<(SessionIndex, V5HostConfiguration<BlockNumberFor<T>>)>,
OptionQuery,
>;
}

impl<BlockNumber: Default + From<u32>> Default for V4HostConfiguration<BlockNumber> {
fn default() -> Self {
Expand Down Expand Up @@ -266,6 +274,7 @@ impl<T: Config> OnRuntimeUpgrade for MigrateToV5<T> {
}

fn on_runtime_upgrade() -> Weight {
log::info!(target: configuration::LOG_TARGET, "MigrateToV5 started");
if StorageVersion::get::<Pallet<T>>() == 4 {
let weight_consumed = migrate_to_v5::<T>();

Expand Down Expand Up @@ -352,13 +361,13 @@ executor_params : Default::default(),
}
};

let v4 = V4ActiveConfig::<T>::get()
let v4 = v4::ActiveConfig::<T>::get()
.defensive_proof("Could not decode old config")
.unwrap_or_default();
let v5 = translate(v4);
V5ActiveConfig::<T>::set(Some(v5));
v5::ActiveConfig::<T>::set(Some(v5));

let pending_v4 = V4PendingConfigs::<T>::get()
let pending_v4 = v4::PendingConfigs::<T>::get()
.defensive_proof("Could not decode old pending")
.unwrap_or_default();
let mut pending_v5 = Vec::new();
Expand All @@ -367,7 +376,7 @@ executor_params : Default::default(),
let v5 = translate(v4);
pending_v5.push((session, v5));
}
V5PendingConfigs::<T>::set(Some(pending_v5.clone()));
v5::PendingConfigs::<T>::set(Some(pending_v5.clone()));

let num_configs = (pending_v5.len() + 1) as u64;
T::DbWeight::get().reads_writes(num_configs, num_configs)
Expand Down Expand Up @@ -397,8 +406,8 @@ mod tests {
// doesn't need to be read and also leaving it as one line allows to easily copy it.
let raw_config = hex_literal::hex!["0000a000005000000a00000000c8000000c800000a0000000a000000100e0000580200000000500000c800000700e8764817020040011e00000000000000005039278c0400000000000000000000005039278c0400000000000000000000e8030000009001001e00000000000000009001008070000000000000000000000a0000000a0000000a00000001000000010500000001c80000000600000058020000580200000200000059000000000000001e000000280000000700c817a80402004001010200000014000000"];

let v4 = v5::V4HostConfiguration::<primitives::BlockNumber>::decode(&mut &raw_config[..])
.unwrap();
let v4 =
V4HostConfiguration::<primitives::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.
Expand All @@ -421,7 +430,7 @@ mod tests {
// 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 v4 = v5::V4HostConfiguration::<primitives::BlockNumber> {
let v4 = V4HostConfiguration::<primitives::BlockNumber> {
ump_max_individual_weight: Weight::from_parts(0x71616e6f6e0au64, 0x71616e6f6e0au64),
needed_approvals: 69,
thread_availability_period: 55,
Expand All @@ -438,13 +447,13 @@ mod tests {

new_test_ext(Default::default()).execute_with(|| {
// Implant the v4 version in the state.
V4ActiveConfig::<Test>::set(Some(v4));
V4PendingConfigs::<Test>::set(Some(pending_configs));
v4::ActiveConfig::<Test>::set(Some(v4));
v4::PendingConfigs::<Test>::set(Some(pending_configs));

migrate_to_v5::<Test>();

let v5 = V5ActiveConfig::<Test>::get().unwrap();
let mut configs_to_check = V5PendingConfigs::<Test>::get().unwrap();
let v5 = v5::ActiveConfig::<Test>::get().unwrap();
let mut configs_to_check = v5::PendingConfigs::<Test>::get().unwrap();
configs_to_check.push((0, v5.clone()));

for (_, v4) in configs_to_check {
Expand Down
76 changes: 43 additions & 33 deletions runtime/parachains/src/configuration/migration/v6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,27 +34,35 @@ use super::v5::V5HostConfiguration;
// Change this once there is V7.
type V6HostConfiguration<BlockNumber> = configuration::HostConfiguration<BlockNumber>;

#[frame_support::storage_alias]
pub(crate) type V5ActiveConfig<T: Config> =
StorageValue<Pallet<T>, V5HostConfiguration<BlockNumberFor<T>>, OptionQuery>;

#[frame_support::storage_alias]
pub(crate) type V5PendingConfigs<T: Config> = StorageValue<
Pallet<T>,
Vec<(SessionIndex, V5HostConfiguration<BlockNumberFor<T>>)>,
OptionQuery,
>;

#[frame_support::storage_alias]
pub(crate) type V6ActiveConfig<T: Config> =
StorageValue<Pallet<T>, V6HostConfiguration<BlockNumberFor<T>>, OptionQuery>;

#[frame_support::storage_alias]
pub(crate) type V6PendingConfigs<T: Config> = StorageValue<
Pallet<T>,
Vec<(SessionIndex, V6HostConfiguration<BlockNumberFor<T>>)>,
OptionQuery,
>;
mod v5 {
use super::*;

#[frame_support::storage_alias]
pub(crate) type ActiveConfig<T: Config> =
StorageValue<Pallet<T>, V5HostConfiguration<BlockNumberFor<T>>, OptionQuery>;

#[frame_support::storage_alias]
pub(crate) type PendingConfigs<T: Config> = StorageValue<
Pallet<T>,
Vec<(SessionIndex, V5HostConfiguration<BlockNumberFor<T>>)>,
OptionQuery,
>;
}

mod v6 {
use super::*;

#[frame_support::storage_alias]
pub(crate) type ActiveConfig<T: Config> =
StorageValue<Pallet<T>, V6HostConfiguration<BlockNumberFor<T>>, OptionQuery>;

#[frame_support::storage_alias]
pub(crate) type PendingConfigs<T: Config> = StorageValue<
Pallet<T>,
Vec<(SessionIndex, V6HostConfiguration<BlockNumberFor<T>>)>,
OptionQuery,
>;
}

pub struct MigrateToV6<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> OnRuntimeUpgrade for MigrateToV6<T> {
Expand All @@ -65,6 +73,7 @@ impl<T: Config> OnRuntimeUpgrade for MigrateToV6<T> {
}

fn on_runtime_upgrade() -> Weight {
log::info!(target: configuration::LOG_TARGET, "MigrateToV6 started");
if StorageVersion::get::<Pallet<T>>() == 5 {
let weight_consumed = migrate_to_v6::<T>();

Expand Down Expand Up @@ -145,24 +154,24 @@ executor_params : pre.executor_params,
}
};

let v5 = V5ActiveConfig::<T>::get()
let v5 = v5::ActiveConfig::<T>::get()
.defensive_proof("Could not decode old config")
.unwrap_or_default();
let v6 = translate(v5);
V6ActiveConfig::<T>::set(Some(v6));
v6::ActiveConfig::<T>::set(Some(v6));

let pending_v4 = V5PendingConfigs::<T>::get()
let pending_v5 = v5::PendingConfigs::<T>::get()
.defensive_proof("Could not decode old pending")
.unwrap_or_default();
let mut pending_v5 = Vec::new();
let mut pending_v6 = Vec::new();

for (session, v5) in pending_v4.into_iter() {
for (session, v5) in pending_v5.into_iter() {
let v6 = translate(v5);
pending_v5.push((session, v6));
pending_v6.push((session, v6));
}
V6PendingConfigs::<T>::set(Some(pending_v5.clone()));
v6::PendingConfigs::<T>::set(Some(pending_v6.clone()));

let num_configs = (pending_v5.len() + 1) as u64;
let num_configs = (pending_v6.len() + 1) as u64;
T::DbWeight::get().reads_writes(num_configs, num_configs)
}

Expand Down Expand Up @@ -201,6 +210,7 @@ mod tests {
assert_eq!(v5.n_delay_tranches, 40);
assert_eq!(v5.ump_max_individual_weight, Weight::from_parts(20_000_000_000, 5_242_880));
assert_eq!(v5.minimum_validation_upgrade_delay, 15); // This is the last field in the struct.
assert_eq!(v5.group_rotation_frequency, 10);
}

#[test]
Expand Down Expand Up @@ -230,13 +240,13 @@ mod tests {

new_test_ext(Default::default()).execute_with(|| {
// Implant the v5 version in the state.
V5ActiveConfig::<Test>::set(Some(v5));
V5PendingConfigs::<Test>::set(Some(pending_configs));
v5::ActiveConfig::<Test>::set(Some(v5));
v5::PendingConfigs::<Test>::set(Some(pending_configs));

migrate_to_v6::<Test>();

let v6 = V6ActiveConfig::<Test>::get().unwrap();
let mut configs_to_check = V6PendingConfigs::<Test>::get().unwrap();
let v6 = v6::ActiveConfig::<Test>::get().unwrap();
let mut configs_to_check = v6::PendingConfigs::<Test>::get().unwrap();
configs_to_check.push((0, v6.clone()));

for (_, v5) in configs_to_check {
Expand Down
21 changes: 20 additions & 1 deletion runtime/parachains/src/configuration/migration_ump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,29 @@ pub mod latest {
"Last pending HostConfig upgrade:\n\n{:#?}\n",
pending.last()
);
let Some(last) = pending.last() else {
return Err("There must be a new pending upgrade enqueued".into());
};
ensure!(
pending.len() == old_pending as usize + 1,
"There must be a new pending upgrade enqueued"
"There must be exactly one new pending upgrade enqueued"
);
if let Err(err) = last.1.check_consistency() {
log::error!(
target: LOG_TARGET,
"Last PendingConfig is invalidity {:?}", err,
);

return Err("Pending upgrade must be sane but was not".into())
}
if let Err(err) = ActiveConfig::<T>::get().check_consistency() {
log::error!(
target: LOG_TARGET,
"ActiveConfig is invalid: {:?}", err,
);

return Err("Active upgrade must be sane but was not".into())
}

Ok(())
}
Expand Down