From e32983095bcc5720a25cb9ccad5faf0fe5992314 Mon Sep 17 00:00:00 2001 From: Benjamin Gallois <business@gallois.cc> Date: Wed, 18 Dec 2024 13:26:34 +0100 Subject: [PATCH] Fix #264: Distance inherent data provider should not fail (nodes/rust/duniter-v2s!294) * inherent data provider cannot fail * remove unused errors --- client/distance/src/lib.rs | 116 ++++++++++++++++++--------------- node/src/service.rs | 4 +- primitives/distance/src/lib.rs | 36 +++------- 3 files changed, 75 insertions(+), 81 deletions(-) diff --git a/client/distance/src/lib.rs b/client/distance/src/lib.rs index c36091612..88d15b88f 100644 --- a/client/distance/src/lib.rs +++ b/client/distance/src/lib.rs @@ -59,37 +59,35 @@ pub fn create_distance_inherent_data_provider<B, C, Backend>( parent: B::Hash, distance_dir: PathBuf, owner_keys: &[sp_core::sr25519::Public], -) -> Result<sp_distance::InherentDataProvider<IdtyIndex>, sc_client_api::blockchain::Error> +) -> sp_distance::InherentDataProvider<IdtyIndex> where B: BlockT, C: ProvideUncles<B> + StorageProvider<B, Backend>, Backend: sc_client_api::Backend<B>, IdtyIndex: Decode + Encode + PartialEq + TypeInfo, { - // Retrieve the period_index from storage. If storage is inaccessible or the data is corrupted, - // return the appropriate error. + // Retrieve the period_index from storage. let period_index = client .storage( parent, &StorageKey( frame_support::storage::storage_prefix(b"Distance", b"CurrentPeriodIndex").to_vec(), ), - )? - .map_or_else( - || { - Err(sc_client_api::blockchain::Error::Storage( - "CurrentPeriodIndex value not found".to_string(), - )) - }, - |raw| { - u32::decode(&mut &raw.0[..]) - .map_err(|e| sc_client_api::blockchain::Error::from_state(Box::new(e))) - }, - )?; + ) + .ok() + .flatten() + .and_then(|raw| u32::decode(&mut &raw.0[..]).ok()); + + // Return early if the storage is inaccessible or the data is corrupted. + let period_index = match period_index { + Some(index) => index, + None => { + log::error!("🧙 [distance inherent] PeriodIndex decoding failed."); + return sp_distance::InherentDataProvider::<IdtyIndex>::new(None); + } + }; // Retrieve the published_results from storage. - // Return an error if the storage is inaccessible. - // If accessible, continue execution. If None, it means there are no published_results at this block. let published_results = client .storage( parent, @@ -105,47 +103,61 @@ where ) .to_vec(), ), - )? + ) + .ok() + .flatten() .and_then(|raw| { pallet_distance::EvaluationPool::<AccountId32, IdtyIndex>::decode(&mut &raw.0[..]).ok() }); - // Have we already published a result for this period? - if let Some(results) = published_results { - // Find the account associated with the BABE key that is in our owner keys. - let mut local_account = None; - for key in owner_keys { - // Session::KeyOwner is StorageMap<_, Twox64Concat, (KeyTypeId, Vec<u8>), AccountId32, OptionQuery> - // Slices (variable length) and array (fixed length) are encoded differently, so the `.as_slice()` is needed - let item_key = (sp_runtime::KeyTypeId(*b"babe"), key.0.as_slice()).encode(); - let mut storage_key = - frame_support::storage::storage_prefix(b"Session", b"KeyOwner").to_vec(); - storage_key.extend_from_slice(&sp_core::twox_64(&item_key)); - storage_key.extend_from_slice(&item_key); + // Return early if the storage is inaccessible or the data is corrupted. + let published_results = match published_results { + Some(published_results) => published_results, + None => { + log::info!("🧙 [distance inherent] No published result at this block."); + return sp_distance::InherentDataProvider::<IdtyIndex>::new(None); + } + }; - if let Some(raw_data) = client.storage(parent, &StorageKey(storage_key))? { - if let Ok(key_owner) = AccountId32::decode(&mut &raw_data.0[..]) { - local_account = Some(key_owner); - break; - } else { - log::warn!("🧙 [distance oracle] Cannot decode key owner value"); - } + // Find the account associated with the BABE key that is in our owner keys. + let mut local_account = None; + for key in owner_keys { + // Session::KeyOwner is StorageMap<_, Twox64Concat, (KeyTypeId, Vec<u8>), AccountId32, OptionQuery> + // Slices (variable length) and array (fixed length) are encoded differently, so the `.as_slice()` is needed + let item_key = (sp_runtime::KeyTypeId(*b"babe"), key.0.as_slice()).encode(); + let mut storage_key = + frame_support::storage::storage_prefix(b"Session", b"KeyOwner").to_vec(); + storage_key.extend_from_slice(&sp_core::twox_64(&item_key)); + storage_key.extend_from_slice(&item_key); + + if let Some(raw_data) = client + .storage(parent, &StorageKey(storage_key)) + .ok() + .flatten() + { + if let Ok(key_owner) = AccountId32::decode(&mut &raw_data.0[..]) { + local_account = Some(key_owner); + break; + } else { + log::warn!("🧙 [distance inherent] Cannot decode key owner value"); } } - if let Some(local_account) = local_account { - if results.evaluators.contains(&local_account) { - log::debug!("🧙 [distance oracle] Already published a result for this period"); - return Ok(sp_distance::InherentDataProvider::<IdtyIndex>::new(None)); - } - } else { - log::error!("🧙 [distance oracle] Cannot find our BABE owner key"); - return Ok(sp_distance::InherentDataProvider::<IdtyIndex>::new(None)); + } + + // Have we already published a result for this period? + if let Some(local_account) = local_account { + if published_results.evaluators.contains(&local_account) { + log::debug!("🧙 [distance inherent] Already published a result for this period"); + return sp_distance::InherentDataProvider::<IdtyIndex>::new(None); } + } else { + log::error!("🧙 [distance inherent] Cannot find our BABE owner key"); + return sp_distance::InherentDataProvider::<IdtyIndex>::new(None); } // Read evaluation result from file, if it exists log::debug!( - "🧙 [distance oracle] Reading evaluation result from file {:?}", + "🧙 [distance inherent] Reading evaluation result from file {:?}", distance_dir.clone().join(period_index.to_string()) ); let evaluation_result = match std::fs::read( @@ -155,20 +167,20 @@ where Err(e) => { match e.kind() { std::io::ErrorKind::NotFound => { - log::debug!("🧙 [distance oracle] Evaluation result file not found. Please ensure that the oracle version matches {}", VERSION_PREFIX); + log::debug!("🧙 [distance inherent] Evaluation result file not found. Please ensure that the oracle version matches {}", VERSION_PREFIX); } _ => { log::error!( - "🧙 [distance oracle] Cannot read distance evaluation result file: {e:?}" + "🧙 [distance inherent] Cannot read distance evaluation result file: {e:?}" ); } } - return Ok(sp_distance::InherentDataProvider::<IdtyIndex>::new(None)); + return sp_distance::InherentDataProvider::<IdtyIndex>::new(None); } }; - log::info!("🧙 [distance oracle] Providing evaluation result"); - Ok(sp_distance::InherentDataProvider::<IdtyIndex>::new(Some( + log::info!("🧙 [distance inherent] Providing evaluation result"); + sp_distance::InherentDataProvider::<IdtyIndex>::new(Some( sp_distance::ComputationResult::decode(&mut evaluation_result.as_slice()).unwrap(), - ))) + )) } diff --git a/node/src/service.rs b/node/src/service.rs index 894644308..0593f8fe5 100644 --- a/node/src/service.rs +++ b/node/src/service.rs @@ -503,7 +503,7 @@ where FullBackend, >( &*client, parent, distance_dir, &babe_owner_keys.clone() - )?; + ); Ok((timestamp, babe, distance)) } }, @@ -549,7 +549,7 @@ where FullBackend, >( &*client, parent, distance_dir, &babe_owner_keys.clone() - )?; + ); Ok((slot, timestamp, storage_proof, distance)) } diff --git a/primitives/distance/src/lib.rs b/primitives/distance/src/lib.rs index acaf53c38..c447da102 100644 --- a/primitives/distance/src/lib.rs +++ b/primitives/distance/src/lib.rs @@ -35,29 +35,14 @@ pub struct ComputationResult { pub distances: scale_info::prelude::vec::Vec<Perbill>, } +/// Errors that can occur while checking the inherent data in `ProvideInherent::check_inherent` from pallet-distance. #[derive(Encode, sp_runtime::RuntimeDebug)] #[cfg_attr(feature = "std", derive(Decode, thiserror::Error))] -pub enum InherentError { - #[cfg_attr(feature = "std", error("InvalidComputationResultFile"))] - InvalidComputationResultFile, -} +pub enum InherentError {} impl IsFatalError for InherentError { fn is_fatal_error(&self) -> bool { - match self { - InherentError::InvalidComputationResultFile => false, - } - } -} - -impl InherentError { - #[cfg(feature = "std")] - pub fn try_from(id: &InherentIdentifier, mut data: &[u8]) -> Option<Self> { - if id == &INHERENT_IDENTIFIER { - <InherentError as codec::Decode>::decode(&mut data).ok() - } else { - None - } + false } } @@ -94,15 +79,12 @@ impl<IdtyIndex: Decode + Encode + PartialEq + TypeInfo + Send + Sync> async fn try_handle_error( &self, - identifier: &InherentIdentifier, - error: &[u8], + _identifier: &InherentIdentifier, + _error: &[u8], ) -> Option<Result<(), sp_inherents::Error>> { - if *identifier != INHERENT_IDENTIFIER { - return None; - } - - Some(Err(sp_inherents::Error::Application(Box::from( - InherentError::try_from(&INHERENT_IDENTIFIER, error)?, - )))) + // No errors occur here. + // Errors handled here are emitted in the `ProvideInherent::check_inherent` + // (from pallet-distance) which is not implemented. + None } } -- GitLab