From c4aa597516fe37146abe4d1be4efb58992d3afbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Wed, 1 Apr 2020 18:43:34 +0100 Subject: [PATCH] babe: restore epoch changes migration code (#5487) This was removed in https://github.com/paritytech/substrate/pull/5291 but is still too early to do it as it requires nodes still on Polkadot v0.7.26 to resync from scratch. --- .../client/consensus/babe/src/aux_schema.rs | 77 ++++++++++++++++++- substrate/client/consensus/epochs/src/lib.rs | 2 + .../client/consensus/epochs/src/migration.rs | 55 +++++++++++++ 3 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 substrate/client/consensus/epochs/src/migration.rs diff --git a/substrate/client/consensus/babe/src/aux_schema.rs b/substrate/client/consensus/babe/src/aux_schema.rs index 3ca2f560d4..6f69e65940 100644 --- a/substrate/client/consensus/babe/src/aux_schema.rs +++ b/substrate/client/consensus/babe/src/aux_schema.rs @@ -25,7 +25,7 @@ use sc_client_api::backend::AuxStore; use sp_blockchain::{Result as ClientResult, Error as ClientError}; use sp_runtime::traits::Block as BlockT; use sp_consensus_babe::BabeBlockWeight; -use sc_consensus_epochs::{EpochChangesFor, SharedEpochChanges}; +use sc_consensus_epochs::{EpochChangesFor, SharedEpochChanges, migration::EpochChangesForV0}; use crate::Epoch; const BABE_EPOCH_CHANGES_VERSION: &[u8] = b"babe_epoch_changes_version"; @@ -57,7 +57,11 @@ pub(crate) fn load_epoch_changes( let version = load_decode::<_, u32>(backend, BABE_EPOCH_CHANGES_VERSION)?; let maybe_epoch_changes = match version { - None | Some(BABE_EPOCH_CHANGES_CURRENT_VERSION) => load_decode::<_, EpochChangesFor>( + None => load_decode::<_, EpochChangesForV0>( + backend, + BABE_EPOCH_CHANGES_KEY, + )?.map(|v0| v0.migrate()), + Some(BABE_EPOCH_CHANGES_CURRENT_VERSION) => load_decode::<_, EpochChangesFor>( backend, BABE_EPOCH_CHANGES_KEY, )?, @@ -123,3 +127,72 @@ pub(crate) fn load_block_weight( ) -> ClientResult> { load_decode(backend, block_weight_key(block_hash).as_slice()) } + +#[cfg(test)] +mod test { + use super::*; + use crate::Epoch; + use fork_tree::ForkTree; + use substrate_test_runtime_client; + use sp_core::H256; + use sp_runtime::traits::NumberFor; + use sc_consensus_epochs::{PersistedEpoch, PersistedEpochHeader, EpochHeader}; + use sp_consensus::Error as ConsensusError; + use sc_network_test::Block as TestBlock; + + #[test] + fn load_decode_from_v0_epoch_changes() { + let epoch = Epoch { + start_slot: 0, + authorities: vec![], + randomness: [0; 32], + epoch_index: 1, + duration: 100, + }; + let client = substrate_test_runtime_client::new(); + let mut v0_tree = ForkTree::, _>::new(); + v0_tree.import::<_, ConsensusError>( + Default::default(), + Default::default(), + PersistedEpoch::Regular(epoch), + &|_, _| Ok(false), // Test is single item only so this can be set to false. + ).unwrap(); + + client.insert_aux( + &[(BABE_EPOCH_CHANGES_KEY, + &EpochChangesForV0::::from_raw(v0_tree).encode()[..])], + &[], + ).unwrap(); + + assert_eq!( + load_decode::<_, u32>(&client, BABE_EPOCH_CHANGES_VERSION).unwrap(), + None, + ); + + let epoch_changes = load_epoch_changes::(&client).unwrap(); + + assert!( + epoch_changes.lock() + .tree() + .iter() + .map(|(_, _, epoch)| epoch.clone()) + .collect::>() == + vec![PersistedEpochHeader::Regular(EpochHeader { + start_slot: 0, + end_slot: 100, + })], + ); // PersistedEpochHeader does not implement Debug, so we use assert! directly. + + write_epoch_changes::( + &epoch_changes.lock(), + |values| { + client.insert_aux(values, &[]).unwrap(); + }, + ); + + assert_eq!( + load_decode::<_, u32>(&client, BABE_EPOCH_CHANGES_VERSION).unwrap(), + Some(1), + ); + } +} diff --git a/substrate/client/consensus/epochs/src/lib.rs b/substrate/client/consensus/epochs/src/lib.rs index d5816d960c..001c172b34 100644 --- a/substrate/client/consensus/epochs/src/lib.rs +++ b/substrate/client/consensus/epochs/src/lib.rs @@ -16,6 +16,8 @@ //! Generic utilities for epoch-based consensus engines. +pub mod migration; + use std::{sync::Arc, ops::Add, collections::BTreeMap, borrow::{Borrow, BorrowMut}}; use parking_lot::Mutex; use codec::{Encode, Decode}; diff --git a/substrate/client/consensus/epochs/src/migration.rs b/substrate/client/consensus/epochs/src/migration.rs new file mode 100644 index 0000000000..e4717b5584 --- /dev/null +++ b/substrate/client/consensus/epochs/src/migration.rs @@ -0,0 +1,55 @@ +// Copyright 2019-2020 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Migration types for epoch changes. + +use std::collections::BTreeMap; +use codec::{Encode, Decode}; +use fork_tree::ForkTree; +use sp_runtime::traits::{Block as BlockT, NumberFor}; +use crate::{Epoch, EpochChanges, PersistedEpoch, PersistedEpochHeader}; + +/// Legacy definition of epoch changes. +#[derive(Clone, Encode, Decode)] +pub struct EpochChangesV0 { + inner: ForkTree>, +} + +/// Type alias for legacy definition of epoch changes. +pub type EpochChangesForV0 = EpochChangesV0<::Hash, NumberFor, Epoch>; + +impl EpochChangesV0 where + Hash: PartialEq + Ord + Copy, + Number: Ord + Copy, +{ + /// Create a new value of this type from raw. + pub fn from_raw(inner: ForkTree>) -> Self { + Self { inner } + } + + /// Migrate the type into current epoch changes definition. + pub fn migrate(self) -> EpochChanges { + let mut epochs = BTreeMap::new(); + + let inner = self.inner.map(&mut |hash, number, data| { + let header = PersistedEpochHeader::from(&data); + epochs.insert((*hash, *number), data); + header + }); + + EpochChanges { inner, epochs } + } +}