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

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

@ -1,6 +1,9 @@
use crate::{errors::Web3ProxyError, jsonrpc::JsonRpcErrorData, rpcs::blockchain::ArcBlock}; use crate::{errors::Web3ProxyError, jsonrpc::JsonRpcErrorData, rpcs::blockchain::ArcBlock};
use derive_more::From; 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 hashbrown::hash_map::DefaultHashBuilder;
use moka::future::Cache; use moka::future::Cache;
use serde_json::value::RawValue; use serde_json::value::RawValue;
@ -139,14 +142,15 @@ impl<R> TryFrom<Web3ProxyError> for JsonRpcResponseEnum<R> {
type Error = Web3ProxyError; type Error = Web3ProxyError;
fn try_from(value: Web3ProxyError) -> Result<Self, Self::Error> { fn try_from(value: Web3ProxyError) -> Result<Self, Self::Error> {
match value { if let Web3ProxyError::EthersProvider(ref err) = value {
Web3ProxyError::EthersProvider(provider_err) => { if let Ok(x) = JsonRpcErrorData::try_from(err) {
let err = JsonRpcErrorData::try_from(provider_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 { impl<'a> From<&'a JsonRpcError> for JsonRpcErrorData {
type Error = Web3ProxyError; 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> { impl<'a> TryFrom<&'a ProviderError> for JsonRpcErrorData {
// TODO: move turning ClientError into json to a helper function? type Error = &'a ProviderError;
let code;
let message: String;
let data;
fn try_from(e: &'a ProviderError) -> Result<Self, Self::Error> {
match e { match e {
ProviderError::JsonRpcClientError(err) => { ProviderError::JsonRpcClientError(err) => {
if let Some(err) = err.as_error_response() { if let Some(err) = err.as_error_response() {
code = err.code; Ok(err.into())
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()));
} else { } else {
return Err(anyhow::anyhow!("unexpected ethers error! {:?}", err).into()); Err(e)
} }
} }
e => return Err(e.into()), e => Err(e),
} }
}
}
Ok(JsonRpcErrorData { impl<'a> TryFrom<&'a HttpClientError> for JsonRpcErrorData {
code, type Error = &'a HttpClientError;
message: message.into(),
data, 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),
}
} }
} }

@ -946,19 +946,32 @@ impl Web3Rpcs {
.store(is_backup_response, Ordering::Release); .store(is_backup_response, Ordering::Release);
} }
if let Some(request_metadata) = request_metadata {
request_metadata
.error_response
.store(false, Ordering::Release);
}
return Ok(response); return Ok(response);
} }
Err(error) => { Err(error) => {
// trace!(?response, "rpc 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 { if let Some(request_metadata) = request_metadata {
request_metadata request_metadata
.error_response .error_response
.store(true, Ordering::Release); .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 // some errors should be retried on other nodes
let error_msg = error.message.as_ref(); let error_msg = error.message.as_ref();