mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-22 03:21:03 +00:00
fatality based errors (#4448)
* seed commit for fatality based errors * fatality * first draft of fatality * cleanup * differnt approach * simplify * first working version for enums, with documentation * add split * fix simple split test case * extend README.md * update fatality impl * make tests passed * apply fatality to first subsystem * fatality fixes * use fatality in a subsystem * fix subsystemg * fixup proc macro * fix/test: log::*! do not execute when log handler is missing * fix spelling * rename Runtime2 to something sane * allow nested split with `forward` annotations * add free license * enable and fixup all tests * use external fatality Makes this more reviewable. * bump fatality dep Avoid duplicate expander compilations. * migrate availability distribution * more fatality usage * chore: bump fatality to 0.0.6 * fixup remaining subsystems * chore: fmt * make cargo spellcheck happy * remove single instance of `#[fatal(false)]` * last quality sweep * fixup
This commit is contained in:
committed by
GitHub
parent
85fa087405
commit
d946582707
@@ -17,100 +17,55 @@
|
||||
|
||||
//! Error handling related code and Error/Result definitions.
|
||||
|
||||
use thiserror::Error;
|
||||
use fatality::Nested;
|
||||
|
||||
use polkadot_node_network_protocol::{request_response::incoming, PeerId};
|
||||
use polkadot_node_subsystem_util::runtime;
|
||||
|
||||
use crate::LOG_TARGET;
|
||||
|
||||
#[derive(Debug, Error, derive_more::From)]
|
||||
#[error(transparent)]
|
||||
#[allow(missing_docs)]
|
||||
#[fatality::fatality(splitable)]
|
||||
pub enum Error {
|
||||
/// All fatal errors.
|
||||
Fatal(Fatal),
|
||||
/// All nonfatal/potentially recoverable errors.
|
||||
NonFatal(NonFatal),
|
||||
}
|
||||
|
||||
impl From<runtime::Error> for Error {
|
||||
fn from(o: runtime::Error) -> Self {
|
||||
match o {
|
||||
runtime::Error::Fatal(f) => Self::Fatal(Fatal::Runtime(f)),
|
||||
runtime::Error::NonFatal(f) => Self::NonFatal(NonFatal::Runtime(f)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<incoming::Error> for Error {
|
||||
fn from(o: incoming::Error) -> Self {
|
||||
match o {
|
||||
incoming::Error::Fatal(f) => Self::Fatal(Fatal::IncomingRequest(f)),
|
||||
incoming::Error::NonFatal(f) => Self::NonFatal(NonFatal::IncomingRequest(f)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Fatal errors of this subsystem.
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Fatal {
|
||||
/// Errors coming from runtime::Runtime.
|
||||
#[fatal(forward)]
|
||||
#[error("Error while accessing runtime information")]
|
||||
Runtime(#[from] runtime::Fatal),
|
||||
Runtime(#[from] runtime::Error),
|
||||
|
||||
/// Errors coming from receiving incoming requests.
|
||||
#[fatal(forward)]
|
||||
#[error("Retrieving next incoming request failed.")]
|
||||
IncomingRequest(#[from] incoming::Fatal),
|
||||
}
|
||||
IncomingRequest(#[from] incoming::Error),
|
||||
|
||||
/// Non-fatal errors of this subsystem.
|
||||
#[derive(Debug, Error)]
|
||||
pub enum NonFatal {
|
||||
/// Answering request failed.
|
||||
#[error("Sending back response to peer {0} failed.")]
|
||||
SendResponse(PeerId),
|
||||
|
||||
/// Setting reputation for peer failed.
|
||||
#[error("Changing peer's ({0}) reputation failed.")]
|
||||
SetPeerReputation(PeerId),
|
||||
|
||||
/// Peer sent us request with invalid signature.
|
||||
#[error("Dispute request with invalid signatures, from peer {0}.")]
|
||||
InvalidSignature(PeerId),
|
||||
|
||||
/// Import oneshot got canceled.
|
||||
#[error("Import of dispute got canceled for peer {0} - import failed for some reason.")]
|
||||
ImportCanceled(PeerId),
|
||||
|
||||
/// Non validator tried to participate in dispute.
|
||||
#[error("Peer {0} is not a validator.")]
|
||||
#[error("Peer {0} attempted to participate in dispute and is not a validator.")]
|
||||
NotAValidator(PeerId),
|
||||
|
||||
/// Errors coming from runtime::Runtime.
|
||||
#[error("Error while accessing runtime information")]
|
||||
Runtime(#[from] runtime::NonFatal),
|
||||
|
||||
/// Errors coming from receiving incoming requests.
|
||||
#[error("Retrieving next incoming request failed.")]
|
||||
IncomingRequest(#[from] incoming::NonFatal),
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
pub type NonFatalResult<T> = std::result::Result<T, NonFatal>;
|
||||
pub type JfyiErrorResult<T> = std::result::Result<T, JfyiError>;
|
||||
|
||||
/// 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<()>) -> std::result::Result<(), Fatal> {
|
||||
match result {
|
||||
Err(Error::Fatal(f)) => Err(f),
|
||||
Err(Error::NonFatal(error @ NonFatal::ImportCanceled(_))) => {
|
||||
pub fn log_error(result: Result<()>) -> std::result::Result<(), FatalError> {
|
||||
match result.into_nested()? {
|
||||
Err(error @ JfyiError::ImportCanceled(_)) => {
|
||||
tracing::debug!(target: LOG_TARGET, error = ?error);
|
||||
Ok(())
|
||||
},
|
||||
Err(Error::NonFatal(error)) => {
|
||||
Err(error) => {
|
||||
tracing::warn!(target: LOG_TARGET, error = ?error);
|
||||
Ok(())
|
||||
},
|
||||
|
||||
@@ -32,7 +32,7 @@ use lru::LruCache;
|
||||
use polkadot_node_network_protocol::{
|
||||
authority_discovery::AuthorityDiscovery,
|
||||
request_response::{
|
||||
incoming::{OutgoingResponse, OutgoingResponseSender},
|
||||
incoming::{self, OutgoingResponse, OutgoingResponseSender},
|
||||
v1::{DisputeRequest, DisputeResponse},
|
||||
IncomingRequest, IncomingRequestReceiver,
|
||||
},
|
||||
@@ -51,7 +51,7 @@ use crate::{
|
||||
};
|
||||
|
||||
mod error;
|
||||
use self::error::{log_error, NonFatal, NonFatalResult, Result};
|
||||
use self::error::{log_error, JfyiError, JfyiErrorResult, Result};
|
||||
|
||||
const COST_INVALID_REQUEST: Rep = Rep::CostMajor("Received message could not be decoded.");
|
||||
const COST_INVALID_SIGNATURE: Rep = Rep::Malicious("Signatures were invalid.");
|
||||
@@ -101,7 +101,7 @@ enum MuxedMessage {
|
||||
/// - We need to make sure responses are actually sent (therefore we need to await futures
|
||||
/// promptly).
|
||||
/// - We need to update `banned_peers` accordingly to the result.
|
||||
ConfirmedImport(NonFatalResult<(PeerId, ImportStatementsResult)>),
|
||||
ConfirmedImport(JfyiErrorResult<(PeerId, ImportStatementsResult)>),
|
||||
|
||||
/// A new request has arrived and should be handled.
|
||||
NewRequest(IncomingRequest<DisputeRequest>),
|
||||
@@ -117,7 +117,7 @@ impl MuxedMessage {
|
||||
pin_mut!(next_req);
|
||||
if let Poll::Ready(r) = next_req.poll(ctx) {
|
||||
return match r {
|
||||
Err(e) => Poll::Ready(Err(e.into())),
|
||||
Err(e) => Poll::Ready(Err(incoming::Error::from(e).into())),
|
||||
Ok(v) => Poll::Ready(Ok(Self::NewRequest(v))),
|
||||
}
|
||||
}
|
||||
@@ -204,9 +204,9 @@ where
|
||||
reputation_changes: vec![COST_NOT_A_VALIDATOR],
|
||||
sent_feedback: None,
|
||||
})
|
||||
.map_err(|_| NonFatal::SendResponse(peer))?;
|
||||
.map_err(|_| JfyiError::SendResponse(peer))?;
|
||||
|
||||
return Err(NonFatal::NotAValidator(peer).into())
|
||||
return Err(JfyiError::NotAValidator(peer).into())
|
||||
}
|
||||
|
||||
// Immediately drop requests from peers that already have requests in flight or have
|
||||
@@ -255,9 +255,9 @@ where
|
||||
reputation_changes: vec![COST_INVALID_SIGNATURE],
|
||||
sent_feedback: None,
|
||||
})
|
||||
.map_err(|_| NonFatal::SetPeerReputation(peer))?;
|
||||
.map_err(|_| JfyiError::SetPeerReputation(peer))?;
|
||||
|
||||
return Err(From::from(NonFatal::InvalidSignature(peer)))
|
||||
return Err(From::from(JfyiError::InvalidSignature(peer)))
|
||||
},
|
||||
Ok(votes) => votes,
|
||||
};
|
||||
@@ -285,8 +285,8 @@ where
|
||||
/// In addition we report import metrics.
|
||||
fn ban_bad_peer(
|
||||
&mut self,
|
||||
result: NonFatalResult<(PeerId, ImportStatementsResult)>,
|
||||
) -> NonFatalResult<()> {
|
||||
result: JfyiErrorResult<(PeerId, ImportStatementsResult)>,
|
||||
) -> JfyiErrorResult<()> {
|
||||
match result? {
|
||||
(_, ImportStatementsResult::ValidImport) => {
|
||||
self.metrics.on_imported(SUCCEEDED);
|
||||
@@ -303,7 +303,8 @@ where
|
||||
/// Manage pending imports in a way that preserves invariants.
|
||||
struct PendingImports {
|
||||
/// Futures in flight.
|
||||
futures: FuturesUnordered<BoxFuture<'static, (PeerId, NonFatalResult<ImportStatementsResult>)>>,
|
||||
futures:
|
||||
FuturesUnordered<BoxFuture<'static, (PeerId, JfyiErrorResult<ImportStatementsResult>)>>,
|
||||
/// Peers whose requests are currently in flight.
|
||||
peers: HashSet<PeerId>,
|
||||
}
|
||||
@@ -341,7 +342,7 @@ impl PendingImports {
|
||||
}
|
||||
|
||||
impl Stream for PendingImports {
|
||||
type Item = NonFatalResult<(PeerId, ImportStatementsResult)>;
|
||||
type Item = JfyiErrorResult<(PeerId, ImportStatementsResult)>;
|
||||
fn poll_next(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||
match Pin::new(&mut self.futures).poll_next(ctx) {
|
||||
Poll::Pending => Poll::Pending,
|
||||
@@ -368,8 +369,8 @@ async fn respond_to_request(
|
||||
peer: PeerId,
|
||||
handled: oneshot::Receiver<ImportStatementsResult>,
|
||||
pending_response: OutgoingResponseSender<DisputeRequest>,
|
||||
) -> NonFatalResult<ImportStatementsResult> {
|
||||
let result = handled.await.map_err(|_| NonFatal::ImportCanceled(peer))?;
|
||||
) -> JfyiErrorResult<ImportStatementsResult> {
|
||||
let result = handled.await.map_err(|_| JfyiError::ImportCanceled(peer))?;
|
||||
|
||||
let response = match result {
|
||||
ImportStatementsResult::ValidImport => OutgoingResponse {
|
||||
@@ -386,7 +387,7 @@ async fn respond_to_request(
|
||||
|
||||
pending_response
|
||||
.send_outgoing_response(response)
|
||||
.map_err(|_| NonFatal::SendResponse(peer))?;
|
||||
.map_err(|_| JfyiError::SendResponse(peer))?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user