mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-20 19:51:02 +00:00
TryDecodeEntireState check for storage types and pallets (#1805)
### This PR is a port of this [PR for substrate](https://github.com/paritytech/substrate/pull/13013) by @kianenigma Add infrastructure needed to have a Pallet::decode_entire_state(), which makes sure all "typed" storage items defined in the pallet are decode-able. This is not enforced in any way at the moment. Teams who wish to integrate/use this in the try-runtime feature flag should add frame_support::storage::migration::EnsureStateDecodes as the LAST ITEM of the runtime's custom migrations, and pass it to frame-executive. This will make it usable in try-runtime on-runtime-upgrade. This now catches cases like https://github.com/paritytech/polkadot-sdk/pull/1969: ```pre ERROR runtime::executive] failed to decode the value at key: Failed to decode value at key: 0x94eadf0156a8ad5156507773d0471e4ab8ebad86f546c7e0b135a4212aace339. Storage info StorageInfo { pallet_name: Ok("ParaScheduler"), storage_name: Ok("AvailabilityCores"), prefix: Err(Utf8Error { valid_up_to: 0, error_len: Some(1) }), max_values: Some(1), max_size: None }. Raw value: Some("0x0c010101010101") ``` ... or:  Closes #241 --------- Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: Liam Aharon <liam.aharon@hotmail.com>
This commit is contained in:
@@ -139,9 +139,15 @@ use sp_runtime::{
|
||||
use sp_std::{marker::PhantomData, prelude::*};
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
use log;
|
||||
#[cfg(feature = "try-runtime")]
|
||||
use sp_runtime::TryRuntimeError;
|
||||
use ::{
|
||||
frame_support::{
|
||||
traits::{TryDecodeEntireStorage, TryDecodeEntireStorageError, TryState},
|
||||
StorageNoopGuard,
|
||||
},
|
||||
frame_try_runtime::{TryStateSelect, UpgradeCheckSelect},
|
||||
log,
|
||||
sp_runtime::TryRuntimeError,
|
||||
};
|
||||
|
||||
#[allow(dead_code)]
|
||||
const LOG_TARGET: &str = "runtime::executive";
|
||||
@@ -229,7 +235,8 @@ impl<
|
||||
+ OnIdle<BlockNumberFor<System>>
|
||||
+ OnFinalize<BlockNumberFor<System>>
|
||||
+ OffchainWorker<BlockNumberFor<System>>
|
||||
+ frame_support::traits::TryState<BlockNumberFor<System>>,
|
||||
+ TryState<BlockNumberFor<System>>
|
||||
+ TryDecodeEntireStorage,
|
||||
COnRuntimeUpgrade: OnRuntimeUpgrade,
|
||||
> Executive<System, Block, Context, UnsignedValidator, AllPalletsWithSystem, COnRuntimeUpgrade>
|
||||
where
|
||||
@@ -308,11 +315,15 @@ where
|
||||
let _guard = frame_support::StorageNoopGuard::default();
|
||||
<AllPalletsWithSystem as frame_support::traits::TryState<
|
||||
BlockNumberFor<System>,
|
||||
>>::try_state(*header.number(), select)
|
||||
>>::try_state(*header.number(), select.clone())
|
||||
.map_err(|e| {
|
||||
log::error!(target: LOG_TARGET, "failure: {:?}", e);
|
||||
e
|
||||
})?;
|
||||
if select.any() {
|
||||
let res = AllPalletsWithSystem::try_decode_entire_state();
|
||||
Self::log_decode_result(res)?;
|
||||
}
|
||||
drop(_guard);
|
||||
|
||||
// do some of the checks that would normally happen in `final_checks`, but perhaps skip
|
||||
@@ -352,26 +363,61 @@ where
|
||||
/// Execute all `OnRuntimeUpgrade` of this runtime.
|
||||
///
|
||||
/// The `checks` param determines whether to execute `pre/post_upgrade` and `try_state` hooks.
|
||||
pub fn try_runtime_upgrade(
|
||||
checks: frame_try_runtime::UpgradeCheckSelect,
|
||||
) -> Result<Weight, TryRuntimeError> {
|
||||
pub fn try_runtime_upgrade(checks: UpgradeCheckSelect) -> Result<Weight, TryRuntimeError> {
|
||||
let weight =
|
||||
<(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::try_on_runtime_upgrade(
|
||||
checks.pre_and_post(),
|
||||
)?;
|
||||
// Nothing should modify the state after the migrations ran:
|
||||
let _guard = StorageNoopGuard::default();
|
||||
|
||||
// The state must be decodable:
|
||||
if checks.any() {
|
||||
let res = AllPalletsWithSystem::try_decode_entire_state();
|
||||
Self::log_decode_result(res)?;
|
||||
}
|
||||
|
||||
// Check all storage invariants:
|
||||
if checks.try_state() {
|
||||
let _guard = frame_support::StorageNoopGuard::default();
|
||||
<AllPalletsWithSystem as frame_support::traits::TryState<
|
||||
BlockNumberFor<System>,
|
||||
>>::try_state(
|
||||
AllPalletsWithSystem::try_state(
|
||||
frame_system::Pallet::<System>::block_number(),
|
||||
frame_try_runtime::TryStateSelect::All,
|
||||
TryStateSelect::All,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(weight)
|
||||
}
|
||||
|
||||
/// Logs the result of trying to decode the entire state.
|
||||
fn log_decode_result(
|
||||
res: Result<usize, Vec<TryDecodeEntireStorageError>>,
|
||||
) -> Result<(), TryRuntimeError> {
|
||||
match res {
|
||||
Ok(bytes) => {
|
||||
log::debug!(
|
||||
target: LOG_TARGET,
|
||||
"decoded the entire state ({bytes} bytes)",
|
||||
);
|
||||
|
||||
Ok(())
|
||||
},
|
||||
Err(errors) => {
|
||||
log::error!(
|
||||
target: LOG_TARGET,
|
||||
"`try_decode_entire_state` failed with {} errors",
|
||||
errors.len(),
|
||||
);
|
||||
|
||||
for (i, err) in errors.iter().enumerate() {
|
||||
// We log the short version to `error` and then the full debug info to `debug`:
|
||||
log::error!(target: LOG_TARGET, "- {i}. error: {err}");
|
||||
log::debug!(target: LOG_TARGET, "- {i}. error: {err:?}");
|
||||
}
|
||||
|
||||
Err("`try_decode_entire_state` failed".into())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
|
||||
Reference in New Issue
Block a user