Unify error enums in substrate and ethereum clients with thiserror (#1094)

* Unify error enums in substrate and ethereum clients with `thiserror`

Related to https://github.com/paritytech/parity-bridges-common/issues/857

* Add license pre-amble

* rustfmt

* Fix spelling
This commit is contained in:
Vladislav
2021-10-22 13:15:50 +03:00
committed by Bastian Köcher
parent 7b4f1c2236
commit 5842968273
48 changed files with 482 additions and 381 deletions
@@ -15,6 +15,7 @@ log = "0.4.11"
num-traits = "0.2"
rand = "0.7"
tokio = "1.8"
thiserror = "1.0.26"
# Bridge dependencies
+16 -67
View File
@@ -20,78 +20,54 @@ use jsonrpsee_ws_client::types::Error as RpcError;
use relay_utils::MaybeConnectionError;
use sc_rpc_api::system::Health;
use sp_runtime::transaction_validity::TransactionValidityError;
use thiserror::Error;
/// Result type used by Substrate client.
pub type Result<T> = std::result::Result<T, Error>;
/// Errors that can occur only when interacting with
/// a Substrate node through RPC.
#[derive(Debug)]
#[derive(Error, Debug)]
pub enum Error {
/// IO error.
Io(std::io::Error),
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
/// An error that can occur when making a request to
/// an JSON-RPC server.
RpcError(RpcError),
#[error("RPC error: {0}")]
RpcError(#[from] RpcError),
/// The response from the server could not be SCALE decoded.
ResponseParseFailed(codec::Error),
#[error("Response parse failed: {0}")]
ResponseParseFailed(#[from] codec::Error),
/// The Substrate bridge pallet has not yet been initialized.
#[error("The Substrate bridge pallet has not been initialized yet.")]
UninitializedBridgePallet,
/// Account does not exist on the chain.
#[error("Account does not exist on the chain.")]
AccountDoesNotExist,
/// Runtime storage is missing mandatory ":code:" entry.
#[error("Mandatory :code: entry is missing from runtime storage.")]
MissingMandatoryCodeEntry,
/// The client we're connected to is not synced, so we can't rely on its state.
#[error("Substrate client is not synced {0}.")]
ClientNotSynced(Health),
/// An error has happened when we have tried to parse storage proof.
#[error("Error when parsing storage proof: {0:?}.")]
StorageProofError(bp_runtime::StorageProofError),
/// The Substrate transaction is invalid.
TransactionInvalid(TransactionValidityError),
#[error("Substrate transaction is invalid: {0:?}")]
TransactionInvalid(#[from] TransactionValidityError),
/// Custom logic error.
#[error("{0}")]
Custom(String),
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Io(ref e) => Some(e),
Self::RpcError(ref e) => Some(e),
Self::ResponseParseFailed(ref e) => Some(e),
Self::UninitializedBridgePallet => None,
Self::AccountDoesNotExist => None,
Self::MissingMandatoryCodeEntry => None,
Self::ClientNotSynced(_) => None,
Self::StorageProofError(_) => None,
Self::TransactionInvalid(_) => None,
Self::Custom(_) => None,
}
}
}
impl From<RpcError> for Error {
fn from(error: RpcError) -> Self {
Error::RpcError(error)
}
}
impl From<std::io::Error> for Error {
fn from(error: std::io::Error) -> Self {
Error::Io(error)
}
}
impl From<tokio::task::JoinError> for Error {
fn from(error: tokio::task::JoinError) -> Self {
Error::Custom(format!("Failed to wait tokio task: {}", error))
}
}
impl From<TransactionValidityError> for Error {
fn from(error: TransactionValidityError) -> Self {
Error::TransactionInvalid(error)
}
}
impl MaybeConnectionError for Error {
fn is_connection_error(&self) -> bool {
matches!(
@@ -105,30 +81,3 @@ impl MaybeConnectionError for Error {
)
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let s = match self {
Self::Io(e) => e.to_string(),
Self::RpcError(e) => e.to_string(),
Self::ResponseParseFailed(e) => e.to_string(),
Self::UninitializedBridgePallet =>
"The Substrate bridge pallet has not been initialized yet.".into(),
Self::AccountDoesNotExist => "Account does not exist on the chain".into(),
Self::MissingMandatoryCodeEntry =>
"Mandatory :code: entry is missing from runtime storage".into(),
Self::StorageProofError(e) => format!("Error when parsing storage proof: {:?}", e),
Self::ClientNotSynced(health) => format!("Substrate client is not synced: {}", health),
Self::TransactionInvalid(e) => format!("Substrate transaction is invalid: {:?}", e),
Self::Custom(e) => e.clone(),
};
write!(f, "{}", s)
}
}
impl From<Error> for String {
fn from(error: Error) -> String {
error.to_string()
}
}
+25 -11
View File
@@ -17,23 +17,30 @@
//! Pallet provides a set of guard functions that are running in background threads
//! and are aborting process if some condition fails.
use crate::{Chain, ChainWithBalances, Client};
use crate::{error::Error, Chain, ChainWithBalances, Client};
use async_trait::async_trait;
use num_traits::CheckedSub;
use sp_version::RuntimeVersion;
use std::{
collections::VecDeque,
fmt::Display,
time::{Duration, Instant},
};
/// Guards environment.
#[async_trait]
pub trait Environment<C: ChainWithBalances>: Send + Sync + 'static {
/// Error type.
type Error: Display + Send + Sync + 'static;
/// Return current runtime version.
async fn runtime_version(&mut self) -> Result<RuntimeVersion, String>;
async fn runtime_version(&mut self) -> Result<RuntimeVersion, Self::Error>;
/// Return free native balance of the account on the chain.
async fn free_native_balance(&mut self, account: C::AccountId) -> Result<C::Balance, String>;
async fn free_native_balance(
&mut self,
account: C::AccountId,
) -> Result<C::Balance, Self::Error>;
/// Return current time.
fn now(&self) -> Instant {
@@ -74,7 +81,7 @@ pub fn abort_on_spec_version_change<C: ChainWithBalances>(
},
Err(error) => log::warn!(
target: "bridge-guard",
"Failed to read {} runtime version: {:?}. Relay may need to be stopped manually",
"Failed to read {} runtime version: {}. Relay may need to be stopped manually",
C::NAME,
error,
),
@@ -137,7 +144,7 @@ pub fn abort_when_account_balance_decreased<C: ChainWithBalances>(
Err(error) => {
log::warn!(
target: "bridge-guard",
"Failed to read {} account {:?} balance: {:?}. Relay may need to be stopped manually",
"Failed to read {} account {:?} balance: {}. Relay may need to be stopped manually",
C::NAME,
account_id,
error,
@@ -157,12 +164,17 @@ fn conditions_check_delay<C: Chain>() -> Duration {
#[async_trait]
impl<C: ChainWithBalances> Environment<C> for Client<C> {
async fn runtime_version(&mut self) -> Result<RuntimeVersion, String> {
Client::<C>::runtime_version(self).await.map_err(|e| e.to_string())
type Error = Error;
async fn runtime_version(&mut self) -> Result<RuntimeVersion, Self::Error> {
Client::<C>::runtime_version(self).await
}
async fn free_native_balance(&mut self, account: C::AccountId) -> Result<C::Balance, String> {
Client::<C>::free_native_balance(self, account).await.map_err(|e| e.to_string())
async fn free_native_balance(
&mut self,
account: C::AccountId,
) -> Result<C::Balance, Self::Error> {
Client::<C>::free_native_balance(self, account).await
}
}
@@ -220,11 +232,13 @@ mod tests {
#[async_trait]
impl Environment<TestChain> for TestEnvironment {
async fn runtime_version(&mut self) -> Result<RuntimeVersion, String> {
type Error = Error;
async fn runtime_version(&mut self) -> Result<RuntimeVersion, Self::Error> {
Ok(self.runtime_version_rx.next().await.unwrap_or_default())
}
async fn free_native_balance(&mut self, _account: u32) -> Result<u32, String> {
async fn free_native_balance(&mut self, _account: u32) -> Result<u32, Self::Error> {
Ok(self.free_native_balance_rx.next().await.unwrap_or_default())
}