diff --git a/teerex/src/lib.rs b/teerex/src/lib.rs index 0766d3a8..71e92037 100644 --- a/teerex/src/lib.rs +++ b/teerex/src/lib.rs @@ -44,7 +44,7 @@ const SGX_RA_PROOF_MAX_LEN: usize = 5000; const MAX_URL_LEN: usize = 256; -const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); +const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); #[frame_support::pallet] pub mod pallet { diff --git a/teerex/src/migrations.rs b/teerex/src/migrations.rs index 4cc3924f..8497a504 100644 --- a/teerex/src/migrations.rs +++ b/teerex/src/migrations.rs @@ -37,40 +37,50 @@ mod v0 { pub mod v1 { use super::*; + #[derive( + Encode, Decode, Default, Copy, Clone, PartialEq, Eq, sp_core::RuntimeDebug, TypeInfo, + )] + pub struct SgxTcbInfoOnChainV1 { + pub issue_date: u64, + pub next_update: u64, + } + + #[storage_alias] + pub type SgxTcbInfo = + StorageMap, Blake2_128Concat, Fmspc, SgxTcbInfoOnChainV1, OptionQuery>; + pub struct MigrateV0toV1(sp_std::marker::PhantomData); impl OnRuntimeUpgrade for MigrateV0toV1 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, &'static str> { - let current_version = Pallet::::current_storage_version(); let onchain_version = Pallet::::on_chain_storage_version(); - ensure!(onchain_version == 0 && current_version == 1, "only migration from v0 to v1"); let enclave_count = v0::EnclaveCount::::get() as u64; - log::info!(target: TARGET, "{} enclaves will be purged", enclave_count,); + log::info!( + "teerexV1: {} v0 enclaves are present before eventual upgrade", + enclave_count, + ); let allow_debug_mode = v0::AllowSGXDebugMode::::get(); - log::info!(target: TARGET, "SGX debug mode was allowed: {}", allow_debug_mode); - Ok((enclave_count, allow_debug_mode).encode()) + log::info!("teerexV1: SGX debug mode was allowed pre_upgrade: {}", allow_debug_mode); + Ok((onchain_version, enclave_count, allow_debug_mode).encode()) } /// we simply purge the enclave registry as it renews within 24h anyway fn on_runtime_upgrade() -> Weight { - let current_version = Pallet::::current_storage_version(); + let current_version = StorageVersion::new(1); let onchain_version = Pallet::::on_chain_storage_version(); log::info!( - target: TARGET, - "Running migration with current storage version {:?} / onchain {:?}", + "teerexV1: Running migration with current storage version {:?} / onchain {:?}", current_version, onchain_version ); let mut purged_keys = 0u64; if onchain_version >= current_version { - log::warn!( - target: TARGET, - "skipping on_runtime_upgrade: executed on wrong storage version." + log::warn!("teerexV1: skipping on_runtime_upgrade: executed on same or newer storage version." ); return T::DbWeight::get().reads(1) } @@ -89,10 +99,18 @@ pub mod v1 { #[cfg(feature = "try-runtime")] fn post_upgrade(state: Vec) -> Result<(), &'static str> { - assert_eq!(Pallet::::on_chain_storage_version(), 1, "must upgrade"); + let (pre_onchain_version, _enclave_count, allow_debug_mode): ( + StorageVersion, + u64, + bool, + ) = Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed"); + let post_onchain_version = Pallet::::on_chain_storage_version(); + if pre_onchain_version >= post_onchain_version { + log::info!("teerexV1: migration was skipped because onchain version was greater or equal to the target version of this migration step"); + return Ok(()) + } - let (_enclave_count, allow_debug_mode): (u64, bool) = - Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed"); + assert_eq!(Pallet::::on_chain_storage_version(), 1, "must upgrade"); let new_enclave_count = v0::EnclaveCount::::get() as u64; let new_allow_debug_mode = crate::SgxAllowDebugMode::::get() as bool; @@ -103,17 +121,73 @@ pub mod v1 { } } +pub mod v2 { + use super::*; + + pub struct MigrateV1toV2(sp_std::marker::PhantomData); + + impl OnRuntimeUpgrade for MigrateV1toV2 { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + let current_version = Pallet::::current_storage_version(); + let onchain_version = Pallet::::on_chain_storage_version(); + ensure!(onchain_version == 1 && current_version == 2, "only migration from v1 to v2"); + + let tcb_info_count = v1::SgxTcbInfo::::iter_keys().count() as u64; + log::info!("teerexV2: TCB info for {} fmspc entries will be purged", tcb_info_count); + Ok((tcb_info_count).encode()) + } + + /// we simply purge the enclave registry as it renews within 24h anyway + fn on_runtime_upgrade() -> Weight { + let current_version = Pallet::::current_storage_version(); + let onchain_version = Pallet::::on_chain_storage_version(); + + log::info!( + "teerexV2: Running migration with current storage version {:?} / onchain {:?}", + current_version, + onchain_version + ); + + let mut purged_keys = 0u64; + if onchain_version >= current_version { + log::warn!( + "teerexV2: skipping on_runtime_upgrade: executed on wrong storage version." + ); + return T::DbWeight::get().reads(1) + } + + purged_keys += v1::SgxTcbInfo::::clear(u32::MAX, None).unique as u64; + + StorageVersion::new(2).put::>(); + T::DbWeight::get().reads_writes(purged_keys + 1, purged_keys + 3) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), &'static str> { + assert_eq!(Pallet::::on_chain_storage_version(), 2, "must upgrade"); + + let _: u64 = + Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed"); + let new_tcb_info_count = v1::SgxTcbInfo::::iter_keys().count() as u64; + + assert_eq!(new_tcb_info_count, 0, "must purge all TCB info entries"); + Ok(()) + } + } +} + #[cfg(test)] #[cfg(feature = "try-runtime")] mod test { use super::*; - use crate::migrations::v0::EnclaveV0; - use frame_support::traits::OnRuntimeUpgrade; + use crate::migrations::{v0::EnclaveV0, v1::SgxTcbInfoOnChainV1}; + use frame_support::{assert_storage_noop, traits::OnRuntimeUpgrade}; use mock::{new_test_ext, Test as TestRuntime}; #[allow(deprecated)] #[test] - fn migration_v0_to_v1_works() { + fn migration_v0_to_v2_works() { new_test_ext().execute_with(|| { StorageVersion::new(0).put::>(); @@ -133,13 +207,16 @@ mod test { v0::EnclaveCount::::put(1); v0::AllowSGXDebugMode::::put(true); - // Migrate. + // Migrate V0 to V1. let state = v1::MigrateV0toV1::::pre_upgrade().unwrap(); let _weight = v1::MigrateV0toV1::::on_runtime_upgrade(); v1::MigrateV0toV1::::post_upgrade(state).unwrap(); + // Migrate V1 to V2 + let state = v2::MigrateV1toV2::::pre_upgrade().unwrap(); + let _weight = v2::MigrateV1toV2::::on_runtime_upgrade(); + v2::MigrateV1toV2::::post_upgrade(state).unwrap(); // Check that all values got migrated. - assert_eq!(v0::EnclaveCount::::get(), 0); assert_eq!(crate::SgxAllowDebugMode::::get(), true); assert_eq!(v0::EnclaveRegistry::::iter_keys().count(), 0); @@ -147,4 +224,52 @@ mod test { assert_eq!(v0::AllowSGXDebugMode::::get(), false); }); } + + #[allow(deprecated)] + #[test] + fn migration_v1_to_v2_works() { + new_test_ext().execute_with(|| { + StorageVersion::new(1).put::>(); + assert_eq!(Pallet::::on_chain_storage_version(), 1); + + // Insert some values into the v1 storage: + v1::SgxTcbInfo::::insert(Fmspc::default(), SgxTcbInfoOnChainV1::default()); + + // Migrate. + let state = v2::MigrateV1toV2::::pre_upgrade().unwrap(); + let _weight = v2::MigrateV1toV2::::on_runtime_upgrade(); + v2::MigrateV1toV2::::post_upgrade(state).unwrap(); + + // Check that all values got migrated. + assert_eq!(v1::SgxTcbInfo::::iter_keys().count(), 0); + }); + } + #[allow(deprecated)] + #[test] + fn migration_v1_to_v1_is_noop() { + new_test_ext().execute_with(|| { + StorageVersion::new(1).put::>(); + + // Insert some values into the v1 storage: + v1::SgxTcbInfo::::insert(Fmspc::default(), SgxTcbInfoOnChainV1::default()); + // introduce outdated stuff that would be migrated if the migration would not be a noop + v0::EnclaveRegistry::::insert( + 0, + EnclaveV0 { + pubkey: [0u8; 32].into(), + mr_enclave: MrEnclave::default(), + timestamp: 0, + url: "".into(), + sgx_mode: SgxBuildMode::default(), + }, + ); + v0::EnclaveIndex::::insert(AccountId::::from([0u8; 32]), 0); + v0::EnclaveCount::::put(1); + v0::AllowSGXDebugMode::::put(true); + + let state = v1::MigrateV0toV1::::pre_upgrade().unwrap(); + assert_storage_noop!(v1::MigrateV0toV1::::on_runtime_upgrade()); + v1::MigrateV0toV1::::post_upgrade(state).unwrap(); + }); + } }