change some error codes jsonrpc error handling
This commit is contained in:
parent
b5ed0c4710
commit
b1120e635a
8
TODO.md
8
TODO.md
@ -399,6 +399,8 @@ These are not yet ordered. There might be duplicates. We might not actually need
|
||||
- [x] improve "archive_needed" boolean. change to "block_depth"
|
||||
- [x] keep score of new_head timings for all rpcs
|
||||
- [x] having the whole block in /status is very verbose. trim it down
|
||||
- [x] maybe we shouldn't route eth_getLogs to syncing nodes. serving queries slows down sync significantly
|
||||
- change the send_best function to only include servers that are at least close to fully synced
|
||||
- [-] proxy mode for benchmarking all backends
|
||||
- [-] proxy mode for sending to multiple backends
|
||||
- [-] let users choose a % of reverts to log (or maybe x/second). someone like curve logging all reverts will be a BIG database very quickly
|
||||
@ -416,9 +418,11 @@ These are not yet ordered. There might be duplicates. We might not actually need
|
||||
- then sites like curve.fi don't have to worry about their user count
|
||||
- it does mean we will have a harder time capacity planning from the number of keys
|
||||
- [ ] have the healthcheck get the block over http. if it errors, or doesn't match what the websocket says, something is wrong (likely a deadlock in the websocket code)
|
||||
- [ ] has_block_data is too simple. it needs to know what kind of data is being requested
|
||||
- all nodes have all blocks
|
||||
- most nodes have all receipts
|
||||
- only archives have old state
|
||||
- [ ] don't use new_head_provider anywhere except new head subscription
|
||||
- [x] maybe we shouldn't route eth_getLogs to syncing nodes. serving queries slows down sync significantly
|
||||
- change the send_best function to only include servers that are at least close to fully synced
|
||||
- [ ] enable mev protected transactions with either a /protect/ url (instead of /private/) or the database (when on /rpc/)
|
||||
- [-] have private transactions be enabled by a url setting rather than a setting on the key
|
||||
- [ ] eth_sendRawTransaction should only forward if the chain_id matches what we are running
|
||||
|
@ -143,7 +143,8 @@ fn main() -> anyhow::Result<()> {
|
||||
vec![
|
||||
"info",
|
||||
"ethers=debug",
|
||||
"ethers_providers=warn",
|
||||
// TODO: even error is too verbose for our purposes. how can we turn off this logging entirely?
|
||||
"ethers_providers=error",
|
||||
"redis_rate_limit=debug",
|
||||
"web3_proxy=debug",
|
||||
"web3_proxy_cli=debug",
|
||||
@ -229,6 +230,8 @@ fn main() -> anyhow::Result<()> {
|
||||
};
|
||||
|
||||
log::set_max_level(max_level);
|
||||
|
||||
info!("RUST_LOG={}", rust_log);
|
||||
}
|
||||
|
||||
info!("{}", APP_USER_AGENT);
|
||||
|
@ -67,7 +67,9 @@ pub enum Web3ProxyError {
|
||||
JoinError(JoinError),
|
||||
#[display(fmt = "{:?}", _0)]
|
||||
#[error(ignore)]
|
||||
JsonRpc(crate::jsonrpc::JsonRpcErrorData),
|
||||
JsonRpcForwardedError(JsonRpcForwardedResponse),
|
||||
#[display(fmt = "{:?}", _0)]
|
||||
#[error(ignore)]
|
||||
MsgPackEncode(rmp_serde::encode::Error),
|
||||
NoBlockNumberOrHash,
|
||||
NoBlocksKnown,
|
||||
@ -247,6 +249,7 @@ impl Web3ProxyError {
|
||||
),
|
||||
)
|
||||
}
|
||||
Self::JsonRpcForwardedError(x) => (StatusCode::OK, x),
|
||||
Self::GasEstimateNotU256 => {
|
||||
warn!("GasEstimateNotU256");
|
||||
(
|
||||
@ -413,24 +416,13 @@ impl Web3ProxyError {
|
||||
),
|
||||
)
|
||||
}
|
||||
Self::JsonRpc(err) => {
|
||||
debug!("JsonRpc err={:?}", err);
|
||||
(
|
||||
StatusCode::BAD_REQUEST,
|
||||
JsonRpcForwardedResponse::from_str(
|
||||
"json rpc error!",
|
||||
Some(StatusCode::BAD_REQUEST.as_u16().into()),
|
||||
None,
|
||||
),
|
||||
)
|
||||
}
|
||||
Self::MsgPackEncode(err) => {
|
||||
debug!("MsgPackEncode Error: {}", err);
|
||||
warn!("MsgPackEncode Error: {}", err);
|
||||
(
|
||||
StatusCode::BAD_REQUEST,
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
JsonRpcForwardedResponse::from_str(
|
||||
&format!("msgpack encode error: {}", err),
|
||||
Some(StatusCode::BAD_REQUEST.as_u16().into()),
|
||||
Some(StatusCode::INTERNAL_SERVER_ERROR.as_u16().into()),
|
||||
None,
|
||||
),
|
||||
)
|
||||
@ -438,10 +430,10 @@ impl Web3ProxyError {
|
||||
Self::NoBlockNumberOrHash => {
|
||||
warn!("NoBlockNumberOrHash");
|
||||
(
|
||||
StatusCode::BAD_REQUEST,
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
JsonRpcForwardedResponse::from_str(
|
||||
"Blocks here must have a number or hash",
|
||||
Some(StatusCode::BAD_REQUEST.as_u16().into()),
|
||||
Some(StatusCode::INTERNAL_SERVER_ERROR.as_u16().into()),
|
||||
None,
|
||||
),
|
||||
)
|
||||
@ -449,10 +441,10 @@ impl Web3ProxyError {
|
||||
Self::NoBlocksKnown => {
|
||||
error!("NoBlocksKnown");
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
StatusCode::BAD_GATEWAY,
|
||||
JsonRpcForwardedResponse::from_str(
|
||||
"no blocks known",
|
||||
Some(StatusCode::INTERNAL_SERVER_ERROR.as_u16().into()),
|
||||
Some(StatusCode::BAD_GATEWAY.as_u16().into()),
|
||||
None,
|
||||
),
|
||||
)
|
||||
@ -460,10 +452,10 @@ impl Web3ProxyError {
|
||||
Self::NoConsensusHeadBlock => {
|
||||
error!("NoConsensusHeadBlock");
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
StatusCode::BAD_GATEWAY,
|
||||
JsonRpcForwardedResponse::from_str(
|
||||
"no consensus head block",
|
||||
Some(StatusCode::INTERNAL_SERVER_ERROR.as_u16().into()),
|
||||
Some(StatusCode::BAD_GATEWAY.as_u16().into()),
|
||||
None,
|
||||
),
|
||||
)
|
||||
@ -506,7 +498,7 @@ impl Web3ProxyError {
|
||||
}
|
||||
Self::NotFound => {
|
||||
// TODO: emit a stat?
|
||||
// TODO: instead of an error, show a normal html page for 404
|
||||
// TODO: instead of an error, show a normal html page for 404?
|
||||
(
|
||||
StatusCode::NOT_FOUND,
|
||||
JsonRpcForwardedResponse::from_str(
|
||||
@ -528,7 +520,7 @@ impl Web3ProxyError {
|
||||
)
|
||||
}
|
||||
Self::OriginRequired => {
|
||||
warn!("OriginRequired");
|
||||
trace!("OriginRequired");
|
||||
(
|
||||
StatusCode::BAD_REQUEST,
|
||||
JsonRpcForwardedResponse::from_str(
|
||||
@ -539,7 +531,7 @@ impl Web3ProxyError {
|
||||
)
|
||||
}
|
||||
Self::OriginNotAllowed(origin) => {
|
||||
warn!("OriginNotAllowed origin={}", origin);
|
||||
trace!("OriginNotAllowed origin={}", origin);
|
||||
(
|
||||
StatusCode::FORBIDDEN,
|
||||
JsonRpcForwardedResponse::from_string(
|
||||
@ -550,7 +542,7 @@ impl Web3ProxyError {
|
||||
)
|
||||
}
|
||||
Self::ParseBytesError(err) => {
|
||||
warn!("ParseBytesError err={:?}", err);
|
||||
trace!("ParseBytesError err={:?}", err);
|
||||
(
|
||||
StatusCode::BAD_REQUEST,
|
||||
JsonRpcForwardedResponse::from_str(
|
||||
@ -561,7 +553,7 @@ impl Web3ProxyError {
|
||||
)
|
||||
}
|
||||
Self::ParseMsgError(err) => {
|
||||
warn!("ParseMsgError err={:?}", err);
|
||||
trace!("ParseMsgError err={:?}", err);
|
||||
(
|
||||
StatusCode::BAD_REQUEST,
|
||||
JsonRpcForwardedResponse::from_str(
|
||||
@ -572,9 +564,9 @@ impl Web3ProxyError {
|
||||
)
|
||||
}
|
||||
Self::ParseAddressError => {
|
||||
warn!("ParseAddressError");
|
||||
trace!("ParseAddressError");
|
||||
(
|
||||
StatusCode::UNAUTHORIZED,
|
||||
StatusCode::BAD_REQUEST,
|
||||
JsonRpcForwardedResponse::from_str(
|
||||
"unable to parse address",
|
||||
Some(StatusCode::BAD_REQUEST.as_u16().into()),
|
||||
@ -775,6 +767,7 @@ impl Web3ProxyError {
|
||||
}
|
||||
Self::UserIdZero => {
|
||||
warn!("UserIdZero");
|
||||
// TODO: this might actually be an application error and not a BAD_REQUEST
|
||||
(
|
||||
StatusCode::BAD_REQUEST,
|
||||
JsonRpcForwardedResponse::from_str(
|
||||
@ -785,7 +778,7 @@ impl Web3ProxyError {
|
||||
)
|
||||
}
|
||||
Self::VerificationError(err) => {
|
||||
warn!("VerificationError err={:?}", err);
|
||||
trace!("VerificationError err={:?}", err);
|
||||
(
|
||||
StatusCode::BAD_REQUEST,
|
||||
JsonRpcForwardedResponse::from_str(
|
||||
@ -818,7 +811,7 @@ impl Web3ProxyError {
|
||||
)
|
||||
}
|
||||
Self::WebsocketOnly => {
|
||||
warn!("WebsocketOnly");
|
||||
trace!("WebsocketOnly");
|
||||
(
|
||||
StatusCode::BAD_REQUEST,
|
||||
JsonRpcForwardedResponse::from_str(
|
||||
@ -828,20 +821,23 @@ impl Web3ProxyError {
|
||||
),
|
||||
)
|
||||
}
|
||||
Self::WithContext(err, msg) => {
|
||||
info!("in context: {}", msg);
|
||||
match err {
|
||||
Some(err) => err.into_response_parts(),
|
||||
None => (
|
||||
Self::WithContext(err, msg) => match err {
|
||||
Some(err) => {
|
||||
warn!("{:#?} w/ context {}", err, msg);
|
||||
err.into_response_parts()
|
||||
}
|
||||
None => {
|
||||
warn!("error w/ context {}", msg);
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
JsonRpcForwardedResponse::from_string(
|
||||
msg,
|
||||
Some(StatusCode::INTERNAL_SERVER_ERROR.as_u16().into()),
|
||||
None,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
use super::authorization::{ip_is_authorized, key_is_authorized, Authorization, RequestMetadata};
|
||||
use super::errors::{Web3ProxyError, Web3ProxyResponse};
|
||||
use crate::jsonrpc::JsonRpcId;
|
||||
use crate::stats::RpcQueryStats;
|
||||
use crate::{
|
||||
app::Web3ProxyApp,
|
||||
@ -29,7 +30,6 @@ use hashbrown::HashMap;
|
||||
use http::StatusCode;
|
||||
use log::{info, trace, warn};
|
||||
use serde_json::json;
|
||||
use serde_json::value::to_raw_value;
|
||||
use std::sync::Arc;
|
||||
use std::{str::from_utf8_mut, sync::atomic::AtomicUsize};
|
||||
use tokio::sync::{broadcast, OwnedSemaphorePermit, RwLock};
|
||||
@ -420,9 +420,7 @@ async fn handle_socket_payload(
|
||||
(id, response)
|
||||
}
|
||||
Err(err) => {
|
||||
// TODO: move this logic somewhere else and just set id to None here
|
||||
let id =
|
||||
to_raw_value(&json!(None::<Option::<()>>)).expect("None can always be a RawValue");
|
||||
let id = JsonRpcId::None.to_raw_value();
|
||||
(id, Err(err.into()))
|
||||
}
|
||||
};
|
||||
|
@ -7,8 +7,6 @@ use serde_json::json;
|
||||
use serde_json::value::{to_raw_value, RawValue};
|
||||
use std::fmt;
|
||||
|
||||
// this is used by serde
|
||||
#[allow(dead_code)]
|
||||
fn default_jsonrpc() -> String {
|
||||
"2.0".to_string()
|
||||
}
|
||||
@ -24,6 +22,45 @@ pub struct JsonRpcRequest {
|
||||
pub params: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
#[derive(From)]
|
||||
pub enum JsonRpcId {
|
||||
None,
|
||||
Number(u64),
|
||||
String(String),
|
||||
}
|
||||
|
||||
impl JsonRpcId {
|
||||
pub fn to_raw_value(&self) -> Box<RawValue> {
|
||||
// TODO: is this a good way to do this? we should probably use references
|
||||
match self {
|
||||
Self::None => {
|
||||
to_raw_value(&json!(None::<Option<()>>)).expect("null id should always work")
|
||||
}
|
||||
Self::Number(x) => {
|
||||
serde_json::from_value(json!(x)).expect("number id should always work")
|
||||
}
|
||||
Self::String(x) => serde_json::from_str(x).expect("string id should always work"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl JsonRpcRequest {
|
||||
pub fn new(
|
||||
id: JsonRpcId,
|
||||
method: String,
|
||||
params: Option<serde_json::Value>,
|
||||
) -> anyhow::Result<Self> {
|
||||
let x = Self {
|
||||
jsonrpc: default_jsonrpc(),
|
||||
id: id.to_raw_value(),
|
||||
method,
|
||||
params,
|
||||
};
|
||||
|
||||
Ok(x)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for JsonRpcRequest {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// TODO: the default formatter takes forever to write. this is too quiet though
|
||||
@ -206,9 +243,7 @@ impl JsonRpcForwardedResponse {
|
||||
// TODO: can we somehow get the initial request here? if we put that into a tracing span, will things slow down a ton?
|
||||
JsonRpcForwardedResponse {
|
||||
jsonrpc: "2.0".to_string(),
|
||||
id: id.unwrap_or_else(|| {
|
||||
to_raw_value(&json!(None::<Option<()>>)).expect("null id should always work")
|
||||
}),
|
||||
id: id.unwrap_or_else(|| JsonRpcId::None.to_raw_value()),
|
||||
result: None,
|
||||
error: Some(JsonRpcErrorData {
|
||||
code: code.unwrap_or(-32099),
|
||||
|
@ -251,8 +251,8 @@ impl Web3Rpcs {
|
||||
)
|
||||
.await?;
|
||||
|
||||
if let Some(err) = response.error {
|
||||
return Err(err).web3_context("failed fetching block");
|
||||
if response.error.is_some() {
|
||||
return Err(response.into());
|
||||
}
|
||||
|
||||
let block = response
|
||||
@ -347,8 +347,8 @@ impl Web3Rpcs {
|
||||
.try_send_best_consensus_head_connection(authorization, request, None, Some(num), None)
|
||||
.await?;
|
||||
|
||||
if let Some(err) = response.error {
|
||||
debug!("could not find canonical block {}: {:?}", num, err);
|
||||
if response.error.is_some() {
|
||||
return Err(response.into());
|
||||
}
|
||||
|
||||
let raw_block = response.result.web3_context("no cannonical block result")?;
|
||||
|
Loading…
Reference in New Issue
Block a user