handle more jsonrpc errors as HTTP 200

This commit is contained in:
Bryan Stitt 2023-06-26 22:40:00 -07:00
parent 009fdbe2cf
commit 917dfc914f
3 changed files with 109 additions and 67 deletions

View File

@ -167,7 +167,7 @@ impl Web3ProxyError {
// TODO: include a unique request id in the data
let (code, err): (StatusCode, JsonRpcErrorData) = match self {
Self::Abi(err) => {
warn!("abi error={:?}", err);
warn!(?err, "abi error");
(
StatusCode::INTERNAL_SERVER_ERROR,
JsonRpcErrorData {
@ -201,12 +201,12 @@ impl Web3ProxyError {
)
}
Self::Anyhow(err) => {
warn!("anyhow. err={:?}", err);
warn!(?err, "anyhow");
(
StatusCode::INTERNAL_SERVER_ERROR,
JsonRpcErrorData {
// TODO: is it safe to expose all of our anyhow strings?
message: err.to_string().into(),
message: "INTERNAL SERVER ERROR".into(),
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
data: None,
},
@ -214,10 +214,10 @@ impl Web3ProxyError {
}
Self::Arc(err) => {
// recurse
return err.as_response_parts::<R>();
return err.as_response_parts();
}
Self::BadRequest(err) => {
trace!("BAD_REQUEST: {}", err);
trace!(?err, "BAD_REQUEST");
(
StatusCode::BAD_REQUEST,
JsonRpcErrorData {
@ -229,7 +229,7 @@ impl Web3ProxyError {
}
Self::BadResponse(err) => {
// TODO: think about this one more. ankr gives us this because ethers fails to parse responses without an id
debug!("BAD_RESPONSE: {:?}", err);
debug!(?err, "BAD_RESPONSE");
(
StatusCode::INTERNAL_SERVER_ERROR,
JsonRpcErrorData {
@ -284,43 +284,52 @@ impl Web3ProxyError {
)
}
Self::EthersHttpClient(err) => {
todo!("how should we handle this error? needs to try into jsonrpcerrordata");
warn!("EthersHttpClientError err={:#?}", err);
(
StatusCode::INTERNAL_SERVER_ERROR,
JsonRpcErrorData {
message: "ether http client error".into(),
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
data: None,
},
)
if let Ok(err) = JsonRpcErrorData::try_from(err) {
trace!(?err, "EthersHttpClient jsonrpc error");
(StatusCode::OK, err)
} else {
warn!(?err, "EthersHttpClient");
(
StatusCode::INTERNAL_SERVER_ERROR,
JsonRpcErrorData {
message: "ethers http client error".into(),
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
data: None,
},
)
}
}
Self::EthersProvider(err) => {
todo!("how should we handle this error? needs to try into jsonrpcerrordata");
warn!("EthersProviderError err={:#?}", err);
(
StatusCode::INTERNAL_SERVER_ERROR,
JsonRpcErrorData {
message: "ether provider error".into(),
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
data: None,
},
)
if let Ok(err) = JsonRpcErrorData::try_from(err) {
trace!(?err, "EthersProvider jsonrpc error");
(StatusCode::OK, err)
} else {
warn!(?err, "EthersProvider");
(
StatusCode::INTERNAL_SERVER_ERROR,
JsonRpcErrorData {
message: "ethers provider error".into(),
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
data: None,
},
)
}
}
Self::EthersWsClient(err) => {
todo!("how should we handle this error? needs to try into jsonrpcerrordata");
warn!("EthersWsClientError err={:#?}", err);
(
StatusCode::INTERNAL_SERVER_ERROR,
JsonRpcErrorData {
message: "ether ws client error".into(),
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
data: None,
},
)
if let Ok(err) = JsonRpcErrorData::try_from(err) {
trace!(?err, "EthersWsClient jsonrpc error");
(StatusCode::OK, err)
} else {
warn!(?err, "EthersWsClient");
(
StatusCode::INTERNAL_SERVER_ERROR,
JsonRpcErrorData {
message: "ethers ws client error".into(),
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
data: None,
},
)
}
}
Self::FlumeRecv(err) => {
warn!("FlumeRecvError err={:#?}", err);

View File

@ -1,6 +1,9 @@
use crate::{errors::Web3ProxyError, jsonrpc::JsonRpcErrorData, rpcs::blockchain::ArcBlock};
use derive_more::From;
use ethers::{providers::ProviderError, types::U64};
use ethers::{
providers::{HttpClientError, JsonRpcError, ProviderError, WsClientError},
types::U64,
};
use hashbrown::hash_map::DefaultHashBuilder;
use moka::future::Cache;
use serde_json::value::RawValue;
@ -139,14 +142,15 @@ impl<R> TryFrom<Web3ProxyError> for JsonRpcResponseEnum<R> {
type Error = Web3ProxyError;
fn try_from(value: Web3ProxyError) -> Result<Self, Self::Error> {
match value {
Web3ProxyError::EthersProvider(provider_err) => {
let err = JsonRpcErrorData::try_from(provider_err)?;
if let Web3ProxyError::EthersProvider(ref err) = value {
if let Ok(x) = JsonRpcErrorData::try_from(err) {
let x = x.into();
Ok(err.into())
return Ok(x);
}
err => Err(err),
}
Err(value)
}
}
@ -193,36 +197,52 @@ impl<R> From<JsonRpcErrorData> for JsonRpcResponseEnum<R> {
}
}
impl TryFrom<ProviderError> for JsonRpcErrorData {
type Error = Web3ProxyError;
impl<'a> From<&'a JsonRpcError> for JsonRpcErrorData {
fn from(value: &'a JsonRpcError) -> Self {
Self {
code: value.code,
message: value.message.clone().into(),
data: value.data.clone(),
}
}
}
fn try_from(e: ProviderError) -> Result<Self, Self::Error> {
// TODO: move turning ClientError into json to a helper function?
let code;
let message: String;
let data;
impl<'a> TryFrom<&'a ProviderError> for JsonRpcErrorData {
type Error = &'a ProviderError;
fn try_from(e: &'a ProviderError) -> Result<Self, Self::Error> {
match e {
ProviderError::JsonRpcClientError(err) => {
if let Some(err) = err.as_error_response() {
code = err.code;
message = err.message.clone();
data = err.data.clone();
} else if let Some(err) = err.as_serde_error() {
// this is not an rpc error. keep it as an error
return Err(Web3ProxyError::BadResponse(err.to_string().into()));
Ok(err.into())
} else {
return Err(anyhow::anyhow!("unexpected ethers error! {:?}", err).into());
Err(e)
}
}
e => return Err(e.into()),
e => Err(e),
}
}
}
Ok(JsonRpcErrorData {
code,
message: message.into(),
data,
})
impl<'a> TryFrom<&'a HttpClientError> for JsonRpcErrorData {
type Error = &'a HttpClientError;
fn try_from(e: &'a HttpClientError) -> Result<Self, Self::Error> {
match e {
HttpClientError::JsonRpcError(err) => Ok(err.into()),
e => Err(e),
}
}
}
impl<'a> TryFrom<&'a WsClientError> for JsonRpcErrorData {
type Error = &'a WsClientError;
fn try_from(e: &'a WsClientError) -> Result<Self, Self::Error> {
match e {
WsClientError::JsonRpcError(err) => Ok(err.into()),
e => Err(e),
}
}
}

View File

@ -946,19 +946,32 @@ impl Web3Rpcs {
.store(is_backup_response, Ordering::Release);
}
if let Some(request_metadata) = request_metadata {
request_metadata
.error_response
.store(false, Ordering::Release);
}
return Ok(response);
}
Err(error) => {
// trace!(?response, "rpc error");
// TODO: separate jsonrpc error and web3 proxy error!
// TODO: separate tracking for jsonrpc error and web3 proxy error!
if let Some(request_metadata) = request_metadata {
request_metadata
.error_response
.store(true, Ordering::Release);
}
let error: JsonRpcErrorData = error.try_into()?;
// TODO: if this is an error, do NOT return. continue to try on another server
let error = match JsonRpcErrorData::try_from(&error) {
Ok(x) => x,
Err(err) => {
warn!(?err, "error from {}", rpc);
continue;
}
};
// some errors should be retried on other nodes
let error_msg = error.message.as_ref();