mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-29 13:48:00 +00:00
Remove request multiplexer (#3624)
* WIP: Get rid of request multiplexer. * WIP * Receiver for handling of incoming requests. * Get rid of useless `Fault` abstraction. The things the type system let us do are not worth getting abstracted in its own type. Instead error handling is going to be merely a pattern. * Make most things compile again. * Port availability distribution away from request multiplexer. * Formatting. * Port dispute distribution over. * Fixup statement distribution. * Handle request directly in collator protocol. + Only allow fatal errors at top level. * Use direct request channel for availability recovery. * Finally get rid of request multiplexer Fixes #2842 and paves the way for more back pressure possibilities. * Fix overseer and statement distribution tests. * Fix collator protocol and network bridge tests. * Fix tests in availability recovery. * Fix availability distribution tests. * Fix dispute distribution tests. * Add missing dependency * Typos. * Review remarks. * More remarks.
This commit is contained in:
@@ -1,202 +0,0 @@
|
||||
// Copyright 2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Polkadot.
|
||||
|
||||
// Polkadot 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.
|
||||
|
||||
// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Utilities for general error handling in Polkadot.
|
||||
//!
|
||||
//! Goals:
|
||||
//!
|
||||
//! - Ergonomic API with little repetition.
|
||||
//! - Still explicitness where it matters - fatal errors should be visible and justified.
|
||||
//! - Easy recovering from non-fatal errors.
|
||||
//! - Errors start as non-fatal and can be made fatal at the level where it is really clear they
|
||||
//! are fatal. E.g. cancellation of a oneshot might be fatal in one case, but absolutely expected
|
||||
//! in another.
|
||||
//! - Good error messages. Fatal errors don't need to be properly structured (as we won't handle
|
||||
//! them), but should provide good error messages of what is going on.
|
||||
//! - Encourage many error types. One per module or even per function is totally fine - it makes
|
||||
//! error handling robust, if you only need to handle errors that can actually happen, also error
|
||||
//! messages will get better.
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
/// Error abstraction.
|
||||
///
|
||||
/// Errors might either be fatal and should bring the subsystem down or are at least at the point
|
||||
/// of occurrence deemed potentially recoverable.
|
||||
///
|
||||
/// Upper layers might have a better view and might make a non-fatal error of a called function a
|
||||
/// fatal one. The opposite should not happen, therefore don't make an error fatal if you don't
|
||||
/// know it is in all cases.
|
||||
///
|
||||
/// Usage pattern:
|
||||
///
|
||||
/// ```
|
||||
/// use thiserror::Error;
|
||||
/// use polkadot_node_subsystem::errors::RuntimeApiError;
|
||||
/// use polkadot_primitives::v1::SessionIndex;
|
||||
/// use futures::channel::oneshot;
|
||||
/// use polkadot_node_subsystem_util::{Fault, runtime};
|
||||
///
|
||||
/// #[derive(Debug, Error)]
|
||||
/// #[error(transparent)]
|
||||
/// pub struct Error(pub Fault<NonFatal, Fatal>);
|
||||
///
|
||||
/// pub type Result<T> = std::result::Result<T, Error>;
|
||||
/// pub type NonFatalResult<T> = std::result::Result<T, NonFatal>;
|
||||
/// pub type FatalResult<T> = std::result::Result<T, Fatal>;
|
||||
///
|
||||
/// // Make an error from a `NonFatal` one.
|
||||
/// impl From<NonFatal> for Error {
|
||||
/// fn from(e: NonFatal) -> Self {
|
||||
/// Self(Fault::from_non_fatal(e))
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // Make an Error from a `Fatal` one.
|
||||
/// impl From<Fatal> for Error {
|
||||
/// fn from(f: Fatal) -> Self {
|
||||
/// Self(Fault::from_fatal(f))
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // Easy conversion from sub error types from other modules:
|
||||
/// impl From<runtime::Error> for Error {
|
||||
/// fn from(o: runtime::Error) -> Self {
|
||||
/// Self(Fault::from_other(o))
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// #[derive(Debug, Error)]
|
||||
/// pub enum Fatal {
|
||||
/// /// Really fatal stuff.
|
||||
/// #[error("Something fatal happened.")]
|
||||
/// SomeFatalError,
|
||||
/// /// Errors coming from runtime::Runtime.
|
||||
/// #[error("Error while accessing runtime information")]
|
||||
/// Runtime(#[from] runtime::Fatal),
|
||||
/// }
|
||||
///
|
||||
/// #[derive(Debug, Error)]
|
||||
/// pub enum NonFatal {
|
||||
/// /// Some non fatal error.
|
||||
/// /// For example if we prune a block we're requesting info about.
|
||||
/// #[error("Non fatal error happened.")]
|
||||
/// SomeNonFatalError,
|
||||
///
|
||||
/// /// Errors coming from runtime::Runtime.
|
||||
/// #[error("Error while accessing runtime information")]
|
||||
/// Runtime(#[from] runtime::NonFatal),
|
||||
/// }
|
||||
/// ```
|
||||
/// Then mostly use `Error` in functions, you may also use `NonFatal` and `Fatal` directly in
|
||||
/// functions that strictly only fail non-fatal or fatal respectively, as `Fatal` and `NonFatal`
|
||||
/// can automatically converted into the above defined `Error`.
|
||||
/// ```
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Fault<E, F>
|
||||
where
|
||||
E: std::fmt::Debug + std::error::Error + 'static,
|
||||
F: std::fmt::Debug + std::error::Error + 'static,
|
||||
{
|
||||
/// Error is fatal and should be escalated up.
|
||||
///
|
||||
/// While we usually won't want to pattern match on those, a concrete descriptive enum might
|
||||
/// still be a good idea for easy auditing of what can go wrong in a module and also makes for
|
||||
/// good error messages thanks to `thiserror`.
|
||||
#[error("Fatal error occurred.")]
|
||||
Fatal(#[source] F),
|
||||
/// Error that is not fatal, at least not yet at this level of execution.
|
||||
#[error("Non fatal error occurred.")]
|
||||
Err(#[source] E),
|
||||
}
|
||||
|
||||
/// Due to typesystem constraints we cannot implement the following methods as standard
|
||||
/// `From::from` implementations. So no auto conversions by default, a simple `Result::map_err` is
|
||||
/// not too bad though.
|
||||
impl<E, F> Fault<E, F>
|
||||
where
|
||||
E: std::fmt::Debug + std::error::Error + 'static,
|
||||
F: std::fmt::Debug + std::error::Error + 'static,
|
||||
{
|
||||
/// Build an `Fault` from compatible fatal error.
|
||||
pub fn from_fatal<F1: Into<F>>(f: F1) -> Self {
|
||||
Self::Fatal(f.into())
|
||||
}
|
||||
|
||||
/// Build an `Fault` from compatible non-fatal error.
|
||||
pub fn from_non_fatal<E1: Into<E>>(e: E1) -> Self {
|
||||
Self::Err(e.into())
|
||||
}
|
||||
|
||||
/// Build an `Fault` from a compatible other `Fault`.
|
||||
pub fn from_other<E1, F1>(e: Fault<E1, F1>) -> Self
|
||||
where
|
||||
E1: Into<E> + std::fmt::Debug + std::error::Error + 'static,
|
||||
F1: Into<F> + std::fmt::Debug + std::error::Error + 'static,
|
||||
{
|
||||
match e {
|
||||
Fault::Fatal(f) => Self::from_fatal(f),
|
||||
Fault::Err(e) => Self::from_non_fatal(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Unwrap non-fatal error and report fatal one.
|
||||
///
|
||||
/// This function is useful for top level error handling. Fatal errors will be extracted,
|
||||
/// non-fatal error will be returned for handling.
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use thiserror::Error;
|
||||
/// # use polkadot_node_subsystem_util::{Fault, unwrap_non_fatal};
|
||||
/// # use polkadot_node_subsystem::SubsystemError;
|
||||
/// # #[derive(Error, Debug)]
|
||||
/// # enum Fatal {
|
||||
/// # }
|
||||
/// # #[derive(Error, Debug)]
|
||||
/// # enum NonFatal {
|
||||
/// # }
|
||||
/// # fn computation() -> Result<(), Fault<NonFatal, Fatal>> {
|
||||
/// # panic!();
|
||||
/// # }
|
||||
/// #
|
||||
/// // Use run like so:
|
||||
/// // run(ctx)
|
||||
/// // .map_err(|e| SubsystemError::with_origin("subsystem-name", e))
|
||||
/// fn run() -> std::result::Result<(), Fatal> {
|
||||
/// loop {
|
||||
/// // ....
|
||||
/// if let Some(err) = unwrap_non_fatal(computation())? {
|
||||
/// println!("Something bad happened: {}", err);
|
||||
/// continue
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// ```
|
||||
pub fn unwrap_non_fatal<E, F>(result: Result<(), Fault<E, F>>) -> Result<Option<E>, F>
|
||||
where
|
||||
E: std::fmt::Debug + std::error::Error + 'static,
|
||||
F: std::fmt::Debug + std::error::Error + Send + Sync + 'static,
|
||||
{
|
||||
match result {
|
||||
Ok(()) => Ok(None),
|
||||
Err(Fault::Fatal(f)) => Err(f),
|
||||
Err(Fault::Err(e)) => Ok(Some(e)),
|
||||
}
|
||||
}
|
||||
@@ -74,8 +74,6 @@ pub use metered_channel as metered;
|
||||
pub use polkadot_node_network_protocol::MIN_GOSSIP_PEERS;
|
||||
|
||||
pub use determine_new_blocks::determine_new_blocks;
|
||||
/// Error classification.
|
||||
pub use error_handling::{unwrap_non_fatal, Fault};
|
||||
|
||||
/// These reexports are required so that external crates can use the `delegated_subsystem` macro properly.
|
||||
pub mod reexports {
|
||||
@@ -88,7 +86,6 @@ pub mod rolling_session_window;
|
||||
pub mod runtime;
|
||||
|
||||
mod determine_new_blocks;
|
||||
mod error_handling;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
@@ -23,23 +23,16 @@ use thiserror::Error;
|
||||
use polkadot_node_subsystem::errors::RuntimeApiError;
|
||||
use polkadot_primitives::v1::SessionIndex;
|
||||
|
||||
use crate::Fault;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
/// Errors for `Runtime` cache.
|
||||
pub type Error = Fault<NonFatal, Fatal>;
|
||||
|
||||
impl From<NonFatal> for Error {
|
||||
fn from(e: NonFatal) -> Self {
|
||||
Self::from_non_fatal(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Fatal> for Error {
|
||||
fn from(f: Fatal) -> Self {
|
||||
Self::from_fatal(f)
|
||||
}
|
||||
#[derive(Debug, Error, derive_more::From)]
|
||||
#[error(transparent)]
|
||||
pub enum Error {
|
||||
/// All fatal errors.
|
||||
Fatal(Fatal),
|
||||
/// All nonfatal/potentially recoverable errors.
|
||||
NonFatal(NonFatal),
|
||||
}
|
||||
|
||||
/// Fatal runtime errors.
|
||||
|
||||
Reference in New Issue
Block a user