diff --git a/substrate/frame/executive/src/lib.rs b/substrate/frame/executive/src/lib.rs index b351819f612b..f2cc3b631688 100644 --- a/substrate/frame/executive/src/lib.rs +++ b/substrate/frame/executive/src/lib.rs @@ -409,9 +409,10 @@ where ) -> Result<(), TryRuntimeError> { match res { Ok(bytes) => { - log::debug!( + log::info!( target: LOG_TARGET, - "decoded the entire state ({bytes} bytes)", + "✅ Entire runtime state decodes without error. {} bytes total.", + bytes ); Ok(()) diff --git a/substrate/frame/support/src/traits/try_runtime/decode_entire_state.rs b/substrate/frame/support/src/traits/try_runtime/decode_entire_state.rs index afbf291a0bbb..d5dc93fcf28f 100644 --- a/substrate/frame/support/src/traits/try_runtime/decode_entire_state.rs +++ b/substrate/frame/support/src/traits/try_runtime/decode_entire_state.rs @@ -67,7 +67,7 @@ impl TryDecodeEntireStorage for Tuple { } /// A value could not be decoded. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq)] pub struct TryDecodeEntireStorageError { /// The key of the undecodable value. pub key: Vec, @@ -81,9 +81,22 @@ impl core::fmt::Display for TryDecodeEntireStorageError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!( f, - "Failed to decode storage item `{}::{}`", + "`{}::{}` key `{}` is undecodable", &sp_std::str::from_utf8(&self.info.pallet_name).unwrap_or(""), &sp_std::str::from_utf8(&self.info.storage_name).unwrap_or(""), + array_bytes::bytes2hex("0x", &self.key) + ) + } +} + +impl core::fmt::Debug for TryDecodeEntireStorageError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "key: {} value: {} info: {:?}", + array_bytes::bytes2hex("0x", &self.key), + array_bytes::bytes2hex("0x", self.raw.clone().unwrap_or_default()), + self.info ) } } @@ -96,7 +109,6 @@ impl core::fmt::Display for TryDecodeEntireStorageError { fn decode_storage_info( info: StorageInfo, ) -> Result> { - let mut next_key = info.prefix.clone(); let mut decoded = 0; let decode_key = |key: &[u8]| match sp_io::storage::get(key) { @@ -104,29 +116,39 @@ fn decode_storage_info( Some(bytes) => { let len = bytes.len(); let _ = ::decode_all(&mut bytes.as_ref()).map_err(|_| { - vec![TryDecodeEntireStorageError { + TryDecodeEntireStorageError { key: key.to_vec(), raw: Some(bytes.to_vec()), info: info.clone(), - }] + } })?; - Ok::>(len) + Ok::(len) }, }; - decoded += decode_key(&next_key)?; + let mut errors = vec![]; + let mut next_key = Some(info.prefix.clone()); loop { - match sp_io::storage::next_key(&next_key) { + match next_key { Some(key) if key.starts_with(&info.prefix) => { - decoded += decode_key(&key)?; - next_key = key; + match decode_key(&key) { + Ok(bytes) => { + decoded += bytes; + }, + Err(e) => errors.push(e), + }; + next_key = sp_io::storage::next_key(&key); }, _ => break, } } - Ok(decoded) + if errors.is_empty() { + Ok(decoded) + } else { + Err(errors) + } } impl TryDecodeEntireStorage @@ -353,6 +375,12 @@ mod tests { // two bytes, cannot be decoded into u32. sp_io::storage::set(&Map::hashed_key_for(2), &[0u8, 1]); assert!(Map::try_decode_entire_state().is_err()); + assert_eq!(Map::try_decode_entire_state().unwrap_err().len(), 1); + + // multiple errs in the same map are be detected + sp_io::storage::set(&Map::hashed_key_for(3), &[0u8, 1]); + assert!(Map::try_decode_entire_state().is_err()); + assert_eq!(Map::try_decode_entire_state().unwrap_err().len(), 2); }) }