1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
use std::{error::Error, fmt::Debug};
use thiserror::Error;
use crate::JsonRpcError;
/// An `RpcError` is an abstraction over error types returned by a
/// [`crate::JsonRpcClient`].
///
/// All clients can return [`JsonRpcError`] responses, as
/// well as serde deserialization errors. However, because client errors are
/// typically type-erased via the [`ProviderError`], the error info can be
/// difficult to access. This trait provides convenient access to the
/// underlying error types.
///
/// This trait deals only with behavior that is common to all clients.
/// Client-specific errorvariants cannot be accessed via this trait.
pub trait RpcError: Error + Debug + Send + Sync {
/// Access an underlying JSON-RPC error (if any)
///
/// Attempts to access an underlying [`JsonRpcError`]. If the underlying
/// error is not a JSON-RPC error response, this function will return
/// `None`.
fn as_error_response(&self) -> Option<&JsonRpcError>;
/// Returns `true` if the underlying error is a JSON-RPC error response
fn is_error_response(&self) -> bool {
self.as_error_response().is_some()
}
/// Access an underlying `serde_json` error (if any)
///
/// Attempts to access an underlying [`serde_json::Error`]. If the
/// underlying error is not a serde_json error, this function will return
/// `None`.
///
/// ### Implementor's Note
///
/// When writing a stacked [`crate::JsonRpcClient`] abstraction (e.g. a quorum
/// provider or retrying provider), be sure to account for `serde_json`
/// errors at your layer, as well as at lower layers.
fn as_serde_error(&self) -> Option<&serde_json::Error>;
/// Returns `true` if the underlying error is a serde_json (de)serialization
/// error. This method can be used to identify
fn is_serde_error(&self) -> bool {
self.as_serde_error().is_some()
}
}
/// [`MiddlewareError`] is a companion trait to [`crate::Middleware`]. It
/// describes error behavior that is common to all Middleware errors.
///
/// Like [`crate::Middleware`], it allows moving down through layered errors.
///
/// Like [`RpcError`] it exposes convenient accessors to useful underlying
/// error information.
///
///
/// ## Not to Devs:
/// While this trait includes the same methods as [`RpcError`], it is not a
/// supertrait. This is so that 3rd party developers do not need to learn and
/// implement both traits. We provide default methods that delegate to inner
/// middleware errors on the assumption that it will eventually reach a
/// [`ProviderError`], which has correct behavior. This allows Middleware devs
/// to ignore the methods' presence if they want. Middleware are already plenty
/// complicated and we don't need to make it worse :)
pub trait MiddlewareError: Error + Sized + Send + Sync {
/// The `Inner` type is the next lower middleware layer's error type.
type Inner: MiddlewareError;
/// Convert the next lower middleware layer's error to this layer's error
fn from_err(e: Self::Inner) -> Self;
/// Attempt to convert this error to the next lower middleware's error.
/// Conversion fails if the error is not from an inner layer (i.e. the
/// error originates at this middleware layer)
fn as_inner(&self) -> Option<&Self::Inner>;
/// Returns `true` if the underlying error stems from a lower middleware
/// layer
fn is_inner(&self) -> bool {
self.as_inner().is_some()
}
/// Access an underlying `serde_json` error (if any)
///
/// Attempts to access an underlying [`serde_json::Error`]. If the
/// underlying error is not a serde_json error, this function will return
/// `None`.
///
/// ### Implementor's Note:
///
/// When writing a custom middleware, if your middleware uses `serde_json`
/// we recommend a custom implementation of this method. It should first
/// check your Middleware's error for local `serde_json` errors, and then
/// delegate to inner if none is found. Failing to implement this method may
/// result in missed `serde_json` errors.
fn as_serde_error(&self) -> Option<&serde_json::Error> {
self.as_inner()?.as_serde_error()
}
/// Returns `true` if the underlying error is a serde_json (de)serialization
/// error. This method can be used to identify
fn is_serde_error(&self) -> bool {
self.as_serde_error().is_some()
}
/// Attempts to access an underlying [`ProviderError`], usually by
/// traversing the entire middleware stack. Access fails if the underlying
/// error is not a [`ProviderError`]
fn as_provider_error(&self) -> Option<&ProviderError> {
self.as_inner()?.as_provider_error()
}
/// Convert a [`ProviderError`] to this type, by successively wrapping it
/// in the error types of all lower middleware
fn from_provider_err(p: ProviderError) -> Self {
Self::from_err(Self::Inner::from_provider_err(p))
}
/// Access an underlying JSON-RPC error (if any)
///
/// Attempts to access an underlying [`JsonRpcError`]. If the underlying
/// error is not a JSON-RPC error response, this function will return
/// `None`.
fn as_error_response(&self) -> Option<&JsonRpcError> {
self.as_inner()?.as_error_response()
}
/// Returns `true` if the underlying error is a JSON-RPC error response
fn is_error_response(&self) -> bool {
self.as_error_response().is_some()
}
}
#[derive(Debug, Error)]
/// An error thrown when making a call to the provider
pub enum ProviderError {
/// An internal error in the JSON RPC Client
#[error("{0}")]
JsonRpcClientError(Box<dyn crate::RpcError + Send + Sync>),
/// An error during ENS name resolution
#[error("ens name not found: {0}")]
EnsError(String),
/// Invalid reverse ENS name
#[error("reverse ens name not pointing to itself: {0}")]
EnsNotOwned(String),
/// Error in underlying lib `serde_json`
#[error(transparent)]
SerdeJson(#[from] serde_json::Error),
/// Error in underlying lib `hex`
#[error(transparent)]
HexError(#[from] hex::FromHexError),
/// Error in underlying lib `reqwest`
#[error(transparent)]
HTTPError(#[from] reqwest::Error),
/// Custom error from unknown source
#[error("custom error: {0}")]
CustomError(String),
/// RPC method is not supported by this provider
#[error("unsupported RPC")]
UnsupportedRPC,
/// Node is not supported by this provider
#[error("unsupported node client")]
UnsupportedNodeClient,
/// Signer is not available to this provider.
#[error("Attempted to sign a transaction with no available signer. Hint: did you mean to use a SignerMiddleware?")]
SignerUnavailable,
}
impl RpcError for ProviderError {
fn as_error_response(&self) -> Option<&super::JsonRpcError> {
if let ProviderError::JsonRpcClientError(err) = self {
err.as_error_response()
} else {
None
}
}
fn as_serde_error(&self) -> Option<&serde_json::Error> {
match self {
ProviderError::JsonRpcClientError(e) => e.as_serde_error(),
ProviderError::SerdeJson(e) => Some(e),
_ => None,
}
}
}
// Do not change these implementations, they are critical to proper middleware
// error stack behavior.
impl MiddlewareError for ProviderError {
type Inner = Self;
fn as_error_response(&self) -> Option<&super::JsonRpcError> {
RpcError::as_error_response(self)
}
fn as_serde_error(&self) -> Option<&serde_json::Error> {
RpcError::as_serde_error(self)
}
fn from_err(e: Self::Inner) -> Self {
e
}
fn as_inner(&self) -> Option<&Self::Inner> {
// prevents infinite loops
None
}
}