// Copyright (C) Parity Technologies (UK) Ltd. and Dijital Kurdistan Tech Institute // This file is part of Pezkuwi. // Pezkuwi 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. // Pezkuwi 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 Pezkuwi. If not, see . // //! Error handling related code and Error/Result definitions. use fatality::Nested; use pezkuwi_node_network_protocol::request_response::outgoing::RequestError; use pezkuwi_primitives::SessionIndex; use futures::channel::oneshot; use pezkuwi_node_subsystem::{ChainApiError, RuntimeApiError, SubsystemError}; use pezkuwi_node_subsystem_util::runtime; use crate::LOG_TARGET; #[allow(missing_docs)] #[fatality::fatality(splitable)] pub enum Error { #[fatal] #[error("Spawning subsystem task failed: {0}")] SpawnTask(#[source] SubsystemError), #[fatal] #[error("Erasure chunk requester stream exhausted")] RequesterExhausted, #[fatal] #[error("Receive channel closed: {0}")] IncomingMessageChannel(#[source] SubsystemError), #[fatal(forward)] #[error("Error while accessing runtime information: {0}")] Runtime(#[from] runtime::Error), #[fatal] #[error("Oneshot for receiving response from Chain API got cancelled")] ChainApiSenderDropped(#[from] oneshot::Canceled), #[fatal] #[error("Retrieving response from Chain API unexpectedly failed with error: {0}")] ChainApi(#[from] ChainApiError), #[error("Failed to get node features from the runtime")] FailedNodeFeatures(#[source] RuntimeApiError), // av-store will drop the sender on any error that happens. #[error("Response channel to obtain chunk failed")] QueryChunkResponseChannel(#[source] oneshot::Canceled), // av-store will drop the sender on any error that happens. #[error("Response channel to obtain available data failed")] QueryAvailableDataResponseChannel(#[source] oneshot::Canceled), // We tried accessing a session that was not cached. #[error("Session {missing_session} is not cached, cached sessions: {available_sessions:?}.")] NoSuchCachedSession { available_sessions: Vec, missing_session: SessionIndex }, // Sending request response failed (Can happen on timeouts for example). #[error("Sending a request's response failed.")] SendResponse, #[error("FetchPoV request error: {0}")] FetchPoV(#[source] RequestError), #[error("Fetched PoV does not match expected hash")] UnexpectedPoV, #[error("Remote responded with `NoSuchPoV`")] NoSuchPoV, #[error("Given validator index could not be found in current session")] InvalidValidatorIndex, #[error("Erasure coding error: {0}")] ErasureCoding(#[from] pezkuwi_erasure_coding::Error), } /// General result abbreviation type alias. pub type Result = std::result::Result; /// Utility for eating top level errors and log them. /// /// We basically always want to try and continue on error. This utility function is meant to /// consume top-level errors by simply logging them pub fn log_error( result: Result<()>, ctx: &'static str, warn_freq: &mut gum::Freq, ) -> std::result::Result<(), FatalError> { match result.into_nested()? { Ok(()) => Ok(()), Err(jfyi) => { match jfyi { JfyiError::UnexpectedPoV | JfyiError::InvalidValidatorIndex | JfyiError::NoSuchCachedSession { .. } | JfyiError::QueryAvailableDataResponseChannel(_) | JfyiError::QueryChunkResponseChannel(_) | JfyiError::FailedNodeFeatures(_) | JfyiError::ErasureCoding(_) => gum::warn!(target: LOG_TARGET, error = %jfyi, ctx), JfyiError::FetchPoV(_) | JfyiError::SendResponse | JfyiError::NoSuchPoV | JfyiError::Runtime(_) => { gum::warn_if_frequent!(freq: warn_freq, max_rate: gum::Times::PerHour(100), target: LOG_TARGET, error = ?jfyi, ctx) }, } Ok(()) }, } }