most of these are for the whole app, not just the frontend
This commit is contained in:
parent
0b62ffcdfc
commit
fd8bba4bdd
2
TODO.md
2
TODO.md
|
@ -519,7 +519,7 @@ These are not yet ordered. There might be duplicates. We might not actually need
|
||||||
- [ ] if user-specific caches have evictions that aren't from timeouts, log a warning
|
- [ ] if user-specific caches have evictions that aren't from timeouts, log a warning
|
||||||
- [ ] make sure the email address is valid. probably have a "verified" column in the database
|
- [ ] make sure the email address is valid. probably have a "verified" column in the database
|
||||||
- [ ] if invalid user id given, we give a 500. should be a different error code instead
|
- [ ] if invalid user id given, we give a 500. should be a different error code instead
|
||||||
- WARN http_request: web3_proxy::frontend::errors: anyhow err=UserKey was not a ULID or UUID id=01GER4VBTS0FDHEBR96D1JRDZF method=POST
|
- WARN http_request: web3_proxy::errors: anyhow err=UserKey was not a ULID or UUID id=01GER4VBTS0FDHEBR96D1JRDZF method=POST
|
||||||
- [ ] admin-only endpoint for seeing a user's stats for support requests
|
- [ ] admin-only endpoint for seeing a user's stats for support requests
|
||||||
- [ ] from what i thought, /status should show hashes > numbers!
|
- [ ] from what i thought, /status should show hashes > numbers!
|
||||||
- but block numbers count is maxed out (10k)
|
- but block numbers count is maxed out (10k)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::app::Web3ProxyApp;
|
use crate::app::Web3ProxyApp;
|
||||||
use crate::frontend::errors::{Web3ProxyError, Web3ProxyResponse};
|
use crate::errors::{Web3ProxyError, Web3ProxyResponse};
|
||||||
use crate::http_params::get_user_id_from_params;
|
use crate::http_params::get_user_id_from_params;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use axum::response::IntoResponse;
|
use axum::response::IntoResponse;
|
||||||
|
|
|
@ -2,10 +2,10 @@ mod ws;
|
||||||
|
|
||||||
use crate::block_number::{block_needed, BlockNeeded};
|
use crate::block_number::{block_needed, BlockNeeded};
|
||||||
use crate::config::{AppConfig, TopConfig};
|
use crate::config::{AppConfig, TopConfig};
|
||||||
|
use crate::errors::{Web3ProxyError, Web3ProxyErrorContext, Web3ProxyResult};
|
||||||
use crate::frontend::authorization::{
|
use crate::frontend::authorization::{
|
||||||
Authorization, RequestMetadata, RequestOrMethod, ResponseOrBytes, RpcSecretKey,
|
Authorization, RequestMetadata, RequestOrMethod, ResponseOrBytes, RpcSecretKey,
|
||||||
};
|
};
|
||||||
use crate::frontend::errors::{Web3ProxyError, Web3ProxyErrorContext, Web3ProxyResult};
|
|
||||||
use crate::frontend::rpc_proxy_ws::ProxyMode;
|
use crate::frontend::rpc_proxy_ws::ProxyMode;
|
||||||
use crate::jsonrpc::{
|
use crate::jsonrpc::{
|
||||||
JsonRpcErrorData, JsonRpcForwardedResponse, JsonRpcForwardedResponseEnum, JsonRpcId,
|
JsonRpcErrorData, JsonRpcForwardedResponse, JsonRpcForwardedResponseEnum, JsonRpcId,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
//! Websocket-specific functions for the Web3ProxyApp
|
//! Websocket-specific functions for the Web3ProxyApp
|
||||||
|
|
||||||
use super::Web3ProxyApp;
|
use super::Web3ProxyApp;
|
||||||
|
use crate::errors::{Web3ProxyError, Web3ProxyResult};
|
||||||
use crate::frontend::authorization::{Authorization, RequestMetadata, RequestOrMethod};
|
use crate::frontend::authorization::{Authorization, RequestMetadata, RequestOrMethod};
|
||||||
use crate::frontend::errors::{Web3ProxyError, Web3ProxyResult};
|
|
||||||
use crate::jsonrpc::JsonRpcForwardedResponse;
|
use crate::jsonrpc::JsonRpcForwardedResponse;
|
||||||
use crate::jsonrpc::JsonRpcRequest;
|
use crate::jsonrpc::JsonRpcRequest;
|
||||||
use crate::response_cache::JsonRpcResponseEnum;
|
use crate::response_cache::JsonRpcResponseEnum;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//! Helper functions for turning ether's BlockNumber into numbers and updating incoming queries to match.
|
//! Helper functions for turning ether's BlockNumber into numbers and updating incoming queries to match.
|
||||||
use crate::frontend::errors::{Web3ProxyError, Web3ProxyResult};
|
use crate::errors::{Web3ProxyError, Web3ProxyResult};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use ethers::{
|
use ethers::{
|
||||||
prelude::{BlockNumber, U64},
|
prelude::{BlockNumber, U64},
|
||||||
|
|
|
@ -0,0 +1,988 @@
|
||||||
|
//! Utlities for logging errors for admins and displaying errors to users.
|
||||||
|
|
||||||
|
use crate::frontend::authorization::Authorization;
|
||||||
|
use crate::jsonrpc::{JsonRpcErrorData, JsonRpcForwardedResponse};
|
||||||
|
use crate::response_cache::JsonRpcResponseEnum;
|
||||||
|
|
||||||
|
use std::error::Error;
|
||||||
|
use std::{borrow::Cow, net::IpAddr};
|
||||||
|
|
||||||
|
use axum::{
|
||||||
|
headers,
|
||||||
|
http::StatusCode,
|
||||||
|
response::{IntoResponse, Response},
|
||||||
|
Json,
|
||||||
|
};
|
||||||
|
use derive_more::{Display, Error, From};
|
||||||
|
use http::header::InvalidHeaderValue;
|
||||||
|
use ipnet::AddrParseError;
|
||||||
|
use log::{debug, error, info, trace, warn};
|
||||||
|
use migration::sea_orm::DbErr;
|
||||||
|
use redis_rate_limiter::redis::RedisError;
|
||||||
|
use reqwest::header::ToStrError;
|
||||||
|
use serde::Serialize;
|
||||||
|
use serde_json::value::RawValue;
|
||||||
|
use tokio::{sync::AcquireError, task::JoinError, time::Instant};
|
||||||
|
|
||||||
|
pub type Web3ProxyResult<T> = Result<T, Web3ProxyError>;
|
||||||
|
// TODO: take "IntoResponse" instead of Response?
|
||||||
|
pub type Web3ProxyResponse = Web3ProxyResult<Response>;
|
||||||
|
|
||||||
|
impl From<Web3ProxyError> for Web3ProxyResult<()> {
|
||||||
|
fn from(value: Web3ProxyError) -> Self {
|
||||||
|
Err(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Display, Error, From)]
|
||||||
|
pub enum Web3ProxyError {
|
||||||
|
AccessDenied,
|
||||||
|
#[error(ignore)]
|
||||||
|
Anyhow(anyhow::Error),
|
||||||
|
#[error(ignore)]
|
||||||
|
#[from(ignore)]
|
||||||
|
BadRequest(String),
|
||||||
|
#[error(ignore)]
|
||||||
|
#[from(ignore)]
|
||||||
|
BadResponse(String),
|
||||||
|
BadRouting,
|
||||||
|
Database(DbErr),
|
||||||
|
#[display(fmt = "{:#?}, {:#?}", _0, _1)]
|
||||||
|
EipVerificationFailed(Box<Web3ProxyError>, Box<Web3ProxyError>),
|
||||||
|
EthersHttpClient(ethers::prelude::HttpClientError),
|
||||||
|
EthersProvider(ethers::prelude::ProviderError),
|
||||||
|
EthersWsClient(ethers::prelude::WsClientError),
|
||||||
|
FlumeRecv(flume::RecvError),
|
||||||
|
GasEstimateNotU256,
|
||||||
|
Headers(headers::Error),
|
||||||
|
HeaderToString(ToStrError),
|
||||||
|
Hyper(hyper::Error),
|
||||||
|
InfluxDb2Request(influxdb2::RequestError),
|
||||||
|
#[display(fmt = "{} > {}", min, max)]
|
||||||
|
#[from(ignore)]
|
||||||
|
InvalidBlockBounds {
|
||||||
|
min: u64,
|
||||||
|
max: u64,
|
||||||
|
},
|
||||||
|
InvalidHeaderValue(InvalidHeaderValue),
|
||||||
|
InvalidEip,
|
||||||
|
InvalidInviteCode,
|
||||||
|
Io(std::io::Error),
|
||||||
|
UnknownReferralCode,
|
||||||
|
InvalidReferer,
|
||||||
|
InvalidSignatureLength,
|
||||||
|
InvalidUserAgent,
|
||||||
|
InvalidUserKey,
|
||||||
|
IpAddrParse(AddrParseError),
|
||||||
|
#[error(ignore)]
|
||||||
|
#[from(ignore)]
|
||||||
|
IpNotAllowed(IpAddr),
|
||||||
|
JoinError(JoinError),
|
||||||
|
#[display(fmt = "{:?}", _0)]
|
||||||
|
#[error(ignore)]
|
||||||
|
JsonRpcErrorData(JsonRpcErrorData),
|
||||||
|
#[display(fmt = "{:?}", _0)]
|
||||||
|
#[error(ignore)]
|
||||||
|
MsgPackEncode(rmp_serde::encode::Error),
|
||||||
|
NoBlockNumberOrHash,
|
||||||
|
NoBlocksKnown,
|
||||||
|
NoConsensusHeadBlock,
|
||||||
|
NoHandleReady,
|
||||||
|
NoServersSynced,
|
||||||
|
#[display(fmt = "{}/{}", num_known, min_head_rpcs)]
|
||||||
|
#[from(ignore)]
|
||||||
|
NotEnoughRpcs {
|
||||||
|
num_known: usize,
|
||||||
|
min_head_rpcs: usize,
|
||||||
|
},
|
||||||
|
#[display(fmt = "{}/{}", available, needed)]
|
||||||
|
#[from(ignore)]
|
||||||
|
NotEnoughSoftLimit {
|
||||||
|
available: u32,
|
||||||
|
needed: u32,
|
||||||
|
},
|
||||||
|
NotFound,
|
||||||
|
NotImplemented,
|
||||||
|
OriginRequired,
|
||||||
|
#[error(ignore)]
|
||||||
|
#[from(ignore)]
|
||||||
|
OriginNotAllowed(headers::Origin),
|
||||||
|
#[display(fmt = "{:?}", _0)]
|
||||||
|
#[error(ignore)]
|
||||||
|
ParseBytesError(Option<ethers::types::ParseBytesError>),
|
||||||
|
ParseMsgError(siwe::ParseError),
|
||||||
|
ParseAddressError,
|
||||||
|
#[display(fmt = "{:?}, {:?}", _0, _1)]
|
||||||
|
RateLimited(Authorization, Option<Instant>),
|
||||||
|
Redis(RedisError),
|
||||||
|
RefererRequired,
|
||||||
|
#[display(fmt = "{:?}", _0)]
|
||||||
|
#[error(ignore)]
|
||||||
|
#[from(ignore)]
|
||||||
|
RefererNotAllowed(headers::Referer),
|
||||||
|
SemaphoreAcquireError(AcquireError),
|
||||||
|
SendAppStatError(flume::SendError<crate::stats::AppStat>),
|
||||||
|
SerdeJson(serde_json::Error),
|
||||||
|
/// simple way to return an error message to the user and an anyhow to our logs
|
||||||
|
#[display(fmt = "{}, {}, {:?}", _0, _1, _2)]
|
||||||
|
StatusCode(StatusCode, String, Option<anyhow::Error>),
|
||||||
|
/// TODO: what should be attached to the timout?
|
||||||
|
#[display(fmt = "{:?}", _0)]
|
||||||
|
#[error(ignore)]
|
||||||
|
Timeout(Option<tokio::time::error::Elapsed>),
|
||||||
|
UlidDecode(ulid::DecodeError),
|
||||||
|
UnknownBlockNumber,
|
||||||
|
UnknownKey,
|
||||||
|
UserAgentRequired,
|
||||||
|
#[error(ignore)]
|
||||||
|
UserAgentNotAllowed(headers::UserAgent),
|
||||||
|
UserIdZero,
|
||||||
|
PaymentRequired,
|
||||||
|
VerificationError(siwe::VerificationError),
|
||||||
|
WatchRecvError(tokio::sync::watch::error::RecvError),
|
||||||
|
WatchSendError,
|
||||||
|
WebsocketOnly,
|
||||||
|
#[display(fmt = "{:?}, {}", _0, _1)]
|
||||||
|
#[error(ignore)]
|
||||||
|
WithContext(Option<Box<Web3ProxyError>>, String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Web3ProxyError {
|
||||||
|
pub fn into_response_parts<R: Serialize>(self) -> (StatusCode, JsonRpcResponseEnum<R>) {
|
||||||
|
// TODO: include a unique request id in the data
|
||||||
|
let (code, err): (StatusCode, JsonRpcErrorData) = match self {
|
||||||
|
Self::AccessDenied => {
|
||||||
|
// TODO: attach something to this trace. probably don't include much in the message though. don't want to leak creds by accident
|
||||||
|
trace!("access denied");
|
||||||
|
(
|
||||||
|
StatusCode::FORBIDDEN,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("FORBIDDEN"),
|
||||||
|
code: StatusCode::FORBIDDEN.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::Anyhow(err) => {
|
||||||
|
warn!("anyhow. err={:?}", err);
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
// TODO: is it safe to expose all of our anyhow strings?
|
||||||
|
message: Cow::Owned(err.to_string()),
|
||||||
|
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::BadRequest(err) => {
|
||||||
|
debug!("BAD_REQUEST: {}", err);
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Owned(format!("bad request: {}", err)),
|
||||||
|
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Owned(format!("bad response: {}", err)),
|
||||||
|
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::BadRouting => {
|
||||||
|
error!("BadRouting");
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("bad routing"),
|
||||||
|
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::Database(err) => {
|
||||||
|
error!("database err={:?}", err);
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("database error!"),
|
||||||
|
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::EipVerificationFailed(err_1, err_191) => {
|
||||||
|
info!(
|
||||||
|
"EipVerificationFailed err_1={:#?} err2={:#?}",
|
||||||
|
err_1, err_191
|
||||||
|
);
|
||||||
|
(
|
||||||
|
StatusCode::UNAUTHORIZED,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Owned(format!(
|
||||||
|
"both the primary and eip191 verification failed: {:#?}; {:#?}",
|
||||||
|
err_1, err_191
|
||||||
|
)),
|
||||||
|
code: StatusCode::UNAUTHORIZED.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::EthersHttpClient(err) => {
|
||||||
|
warn!("EthersHttpClientError err={:?}", err);
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("ether http client error"),
|
||||||
|
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::EthersProvider(err) => {
|
||||||
|
warn!("EthersProviderError err={:?}", err);
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("ether provider error"),
|
||||||
|
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::EthersWsClient(err) => {
|
||||||
|
warn!("EthersWsClientError err={:?}", err);
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("ether ws client error"),
|
||||||
|
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::FlumeRecv(err) => {
|
||||||
|
warn!("FlumeRecvError err={:#?}", err);
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("flume recv error!"),
|
||||||
|
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// Self::JsonRpcForwardedError(x) => (StatusCode::OK, x),
|
||||||
|
Self::GasEstimateNotU256 => {
|
||||||
|
warn!("GasEstimateNotU256");
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("gas estimate result is not an U256"),
|
||||||
|
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::Headers(err) => {
|
||||||
|
warn!("HeadersError {:?}", err);
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Owned(format!("{}", err)),
|
||||||
|
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::Hyper(err) => {
|
||||||
|
warn!("hyper err={:?}", err);
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
// TODO: is it safe to expose these error strings?
|
||||||
|
message: Cow::Owned(err.to_string()),
|
||||||
|
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::InfluxDb2Request(err) => {
|
||||||
|
// TODO: attach a request id to the message and to this error so that if people report problems, we can dig in sentry to find out more
|
||||||
|
error!("influxdb2 err={:?}", err);
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("influxdb2 error!"),
|
||||||
|
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::InvalidBlockBounds { min, max } => {
|
||||||
|
debug!("InvalidBlockBounds min={} max={}", min, max);
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Owned(format!(
|
||||||
|
"Invalid blocks bounds requested. min ({}) > max ({})",
|
||||||
|
min, max
|
||||||
|
)),
|
||||||
|
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::IpAddrParse(err) => {
|
||||||
|
debug!("IpAddrParse err={:?}", err);
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Owned(err.to_string()),
|
||||||
|
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::IpNotAllowed(ip) => {
|
||||||
|
debug!("IpNotAllowed ip={})", ip);
|
||||||
|
(
|
||||||
|
StatusCode::FORBIDDEN,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Owned(format!("IP ({}) is not allowed!", ip)),
|
||||||
|
code: StatusCode::FORBIDDEN.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::InvalidHeaderValue(err) => {
|
||||||
|
debug!("InvalidHeaderValue err={:?}", err);
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Owned(format!("{}", err)),
|
||||||
|
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::InvalidEip => {
|
||||||
|
debug!("InvalidEip");
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("invalid message eip given"),
|
||||||
|
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::InvalidInviteCode => {
|
||||||
|
debug!("InvalidInviteCode");
|
||||||
|
(
|
||||||
|
StatusCode::UNAUTHORIZED,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("invalid invite code"),
|
||||||
|
code: StatusCode::UNAUTHORIZED.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::Io(err) => {
|
||||||
|
warn!("std io err={:?}", err);
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
// TODO: is it safe to expose our io error strings?
|
||||||
|
message: Cow::Owned(err.to_string()),
|
||||||
|
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::UnknownReferralCode => {
|
||||||
|
debug!("UnknownReferralCode");
|
||||||
|
(
|
||||||
|
StatusCode::UNAUTHORIZED,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("invalid referral code"),
|
||||||
|
code: StatusCode::UNAUTHORIZED.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::InvalidReferer => {
|
||||||
|
debug!("InvalidReferer");
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("invalid referer!"),
|
||||||
|
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::InvalidSignatureLength => {
|
||||||
|
debug!("InvalidSignatureLength");
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("invalid signature length"),
|
||||||
|
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::InvalidUserAgent => {
|
||||||
|
debug!("InvalidUserAgent");
|
||||||
|
(
|
||||||
|
StatusCode::FORBIDDEN,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("invalid user agent!"),
|
||||||
|
code: StatusCode::FORBIDDEN.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::InvalidUserKey => {
|
||||||
|
warn!("InvalidUserKey");
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("UserKey was not a ULID or UUID"),
|
||||||
|
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::JoinError(err) => {
|
||||||
|
let code = if err.is_cancelled() {
|
||||||
|
trace!("JoinError. likely shutting down. err={:?}", err);
|
||||||
|
StatusCode::BAD_GATEWAY
|
||||||
|
} else {
|
||||||
|
warn!("JoinError. err={:?}", err);
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR
|
||||||
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
code,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
// TODO: different messages of cancelled or not?
|
||||||
|
message: Cow::Borrowed("Unable to complete request"),
|
||||||
|
code: code.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::JsonRpcErrorData(jsonrpc_error_data) => (StatusCode::OK, jsonrpc_error_data),
|
||||||
|
Self::MsgPackEncode(err) => {
|
||||||
|
warn!("MsgPackEncode Error: {}", err);
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Owned(format!("msgpack encode error: {}", err)),
|
||||||
|
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::NoBlockNumberOrHash => {
|
||||||
|
warn!("NoBlockNumberOrHash");
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("Blocks here must have a number or hash"),
|
||||||
|
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::NoBlocksKnown => {
|
||||||
|
error!("NoBlocksKnown");
|
||||||
|
(
|
||||||
|
StatusCode::BAD_GATEWAY,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("no blocks known"),
|
||||||
|
code: StatusCode::BAD_GATEWAY.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::NoConsensusHeadBlock => {
|
||||||
|
error!("NoConsensusHeadBlock");
|
||||||
|
(
|
||||||
|
StatusCode::BAD_GATEWAY,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("no consensus head block"),
|
||||||
|
code: StatusCode::BAD_GATEWAY.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::NoHandleReady => {
|
||||||
|
error!("NoHandleReady");
|
||||||
|
(
|
||||||
|
StatusCode::BAD_GATEWAY,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("unable to retry for request handle"),
|
||||||
|
code: StatusCode::BAD_GATEWAY.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::NoServersSynced => {
|
||||||
|
warn!("NoServersSynced");
|
||||||
|
(
|
||||||
|
StatusCode::BAD_GATEWAY,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("no servers synced"),
|
||||||
|
code: StatusCode::BAD_GATEWAY.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::NotEnoughRpcs {
|
||||||
|
num_known,
|
||||||
|
min_head_rpcs,
|
||||||
|
} => {
|
||||||
|
error!("NotEnoughRpcs {}/{}", num_known, min_head_rpcs);
|
||||||
|
(
|
||||||
|
StatusCode::BAD_GATEWAY,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Owned(format!(
|
||||||
|
"not enough rpcs connected {}/{}",
|
||||||
|
num_known, min_head_rpcs
|
||||||
|
)),
|
||||||
|
code: StatusCode::BAD_GATEWAY.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::NotEnoughSoftLimit { available, needed } => {
|
||||||
|
error!("NotEnoughSoftLimit {}/{}", available, needed);
|
||||||
|
(
|
||||||
|
StatusCode::BAD_GATEWAY,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Owned(format!(
|
||||||
|
"not enough soft limit available {}/{}",
|
||||||
|
available, needed
|
||||||
|
)),
|
||||||
|
code: StatusCode::BAD_GATEWAY.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::NotFound => {
|
||||||
|
// TODO: emit a stat?
|
||||||
|
// TODO: instead of an error, show a normal html page for 404?
|
||||||
|
(
|
||||||
|
StatusCode::NOT_FOUND,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("not found!"),
|
||||||
|
code: StatusCode::NOT_FOUND.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::NotImplemented => {
|
||||||
|
trace!("NotImplemented");
|
||||||
|
(
|
||||||
|
StatusCode::NOT_IMPLEMENTED,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("work in progress"),
|
||||||
|
code: StatusCode::NOT_IMPLEMENTED.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::OriginRequired => {
|
||||||
|
trace!("OriginRequired");
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("Origin required"),
|
||||||
|
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::OriginNotAllowed(origin) => {
|
||||||
|
trace!("OriginNotAllowed origin={}", origin);
|
||||||
|
(
|
||||||
|
StatusCode::FORBIDDEN,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Owned(format!("Origin ({}) is not allowed!", origin)),
|
||||||
|
code: StatusCode::FORBIDDEN.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::ParseBytesError(err) => {
|
||||||
|
trace!("ParseBytesError err={:?}", err);
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("parse bytes error!"),
|
||||||
|
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::ParseMsgError(err) => {
|
||||||
|
trace!("ParseMsgError err={:?}", err);
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("parse message error!"),
|
||||||
|
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::ParseAddressError => {
|
||||||
|
trace!("ParseAddressError");
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("unable to parse address"),
|
||||||
|
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::PaymentRequired => {
|
||||||
|
trace!("PaymentRequiredError");
|
||||||
|
(
|
||||||
|
StatusCode::PAYMENT_REQUIRED,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("Payment is required and user is not premium"),
|
||||||
|
code: StatusCode::PAYMENT_REQUIRED.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// TODO: this should actually by the id of the key. multiple users might control one key
|
||||||
|
Self::RateLimited(authorization, retry_at) => {
|
||||||
|
// TODO: emit a stat
|
||||||
|
|
||||||
|
let retry_msg = if let Some(retry_at) = retry_at {
|
||||||
|
let retry_in = retry_at.duration_since(Instant::now()).as_secs();
|
||||||
|
|
||||||
|
format!(" Retry in {} seconds", retry_in)
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
// create a string with either the IP or the rpc_key_id
|
||||||
|
let msg = if authorization.checks.rpc_secret_key_id.is_none() {
|
||||||
|
format!("too many requests from {}.{}", authorization.ip, retry_msg)
|
||||||
|
} else {
|
||||||
|
format!(
|
||||||
|
"too many requests from rpc key #{}.{}",
|
||||||
|
authorization.checks.rpc_secret_key_id.unwrap(),
|
||||||
|
retry_msg,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
StatusCode::TOO_MANY_REQUESTS,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Owned(msg),
|
||||||
|
code: StatusCode::TOO_MANY_REQUESTS.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::Redis(err) => {
|
||||||
|
warn!("redis err={:?}", err);
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("redis error!"),
|
||||||
|
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::RefererRequired => {
|
||||||
|
warn!("referer required");
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("Referer required"),
|
||||||
|
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::RefererNotAllowed(referer) => {
|
||||||
|
warn!("referer not allowed referer={:?}", referer);
|
||||||
|
(
|
||||||
|
StatusCode::FORBIDDEN,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Owned(format!("Referer ({:?}) is not allowed", referer)),
|
||||||
|
code: StatusCode::FORBIDDEN.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::SemaphoreAcquireError(err) => {
|
||||||
|
warn!("semaphore acquire err={:?}", err);
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
// TODO: is it safe to expose all of our anyhow strings?
|
||||||
|
message: Cow::Borrowed("semaphore acquire error"),
|
||||||
|
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::SendAppStatError(err) => {
|
||||||
|
error!("SendAppStatError err={:?}", err);
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("error stat_sender sending response_stat"),
|
||||||
|
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::SerdeJson(err) => {
|
||||||
|
warn!("serde json err={:?} source={:?}", err, err.source());
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Owned(format!("de/serialization error! {}", err)),
|
||||||
|
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::StatusCode(status_code, err_msg, err) => {
|
||||||
|
// different status codes should get different error levels. 500s should warn. 400s should stat
|
||||||
|
let code = status_code.as_u16();
|
||||||
|
if (500..600).contains(&code) {
|
||||||
|
warn!("server error {} {:?}: {:?}", code, err_msg, err);
|
||||||
|
} else {
|
||||||
|
trace!("user error {} {:?}: {:?}", code, err_msg, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
(
|
||||||
|
status_code,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Owned(err_msg),
|
||||||
|
code: code.into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::Timeout(x) => (
|
||||||
|
StatusCode::REQUEST_TIMEOUT,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Owned(format!("request timed out: {:?}", x)),
|
||||||
|
code: StatusCode::REQUEST_TIMEOUT.as_u16().into(),
|
||||||
|
// TODO: include the actual id!
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Self::HeaderToString(err) => {
|
||||||
|
// trace!(?err, "HeaderToString");
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Owned(err.to_string()),
|
||||||
|
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::UlidDecode(err) => {
|
||||||
|
// trace!(?err, "UlidDecodeError");
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Owned(format!("{}", err)),
|
||||||
|
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::UnknownBlockNumber => {
|
||||||
|
error!("UnknownBlockNumber");
|
||||||
|
(
|
||||||
|
StatusCode::BAD_GATEWAY,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("no servers synced. unknown eth_blockNumber"),
|
||||||
|
code: StatusCode::BAD_GATEWAY.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// TODO: stat?
|
||||||
|
Self::UnknownKey => (
|
||||||
|
StatusCode::UNAUTHORIZED,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("unknown api key!"),
|
||||||
|
code: StatusCode::UNAUTHORIZED.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Self::UserAgentRequired => {
|
||||||
|
warn!("UserAgentRequired");
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("User agent required"),
|
||||||
|
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::UserAgentNotAllowed(ua) => {
|
||||||
|
warn!("UserAgentNotAllowed ua={}", ua);
|
||||||
|
(
|
||||||
|
StatusCode::FORBIDDEN,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Owned(format!("User agent ({}) is not allowed!", ua)),
|
||||||
|
code: StatusCode::FORBIDDEN.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::UserIdZero => {
|
||||||
|
warn!("UserIdZero");
|
||||||
|
// TODO: this might actually be an application error and not a BAD_REQUEST
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("user ids should always be non-zero"),
|
||||||
|
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::VerificationError(err) => {
|
||||||
|
trace!("VerificationError err={:?}", err);
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("verification error!"),
|
||||||
|
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::WatchRecvError(err) => {
|
||||||
|
error!("WatchRecvError err={:?}", err);
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("watch recv error!"),
|
||||||
|
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::WatchSendError => {
|
||||||
|
error!("WatchSendError");
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed("watch send error!"),
|
||||||
|
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::WebsocketOnly => {
|
||||||
|
trace!("WebsocketOnly");
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Borrowed(
|
||||||
|
"redirect_public_url not set. only websockets work here",
|
||||||
|
),
|
||||||
|
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Self::WithContext(err, msg) => match err {
|
||||||
|
Some(err) => {
|
||||||
|
warn!("{:#?} w/ context {}", err, msg);
|
||||||
|
return err.into_response_parts();
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
warn!("error w/ context {}", msg);
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: Cow::Owned(msg),
|
||||||
|
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
(code, JsonRpcResponseEnum::from(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_response_with_id(self, id: Box<RawValue>) -> Response {
|
||||||
|
let (status_code, response_data) = self.into_response_parts();
|
||||||
|
|
||||||
|
let response = JsonRpcForwardedResponse::from_response_data(response_data, id);
|
||||||
|
|
||||||
|
(status_code, Json(response)).into_response()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ethers::types::ParseBytesError> for Web3ProxyError {
|
||||||
|
fn from(err: ethers::types::ParseBytesError) -> Self {
|
||||||
|
Self::ParseBytesError(Some(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<tokio::time::error::Elapsed> for Web3ProxyError {
|
||||||
|
fn from(err: tokio::time::error::Elapsed) -> Self {
|
||||||
|
Self::Timeout(Some(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoResponse for Web3ProxyError {
|
||||||
|
#[inline]
|
||||||
|
fn into_response(self) -> Response {
|
||||||
|
self.into_response_with_id(Default::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Web3ProxyErrorContext<T> {
|
||||||
|
fn web3_context<S: Into<String>>(self, msg: S) -> Result<T, Web3ProxyError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Web3ProxyErrorContext<T> for Option<T> {
|
||||||
|
fn web3_context<S: Into<String>>(self, msg: S) -> Result<T, Web3ProxyError> {
|
||||||
|
self.ok_or(Web3ProxyError::WithContext(None, msg.into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E> Web3ProxyErrorContext<T> for Result<T, E>
|
||||||
|
where
|
||||||
|
E: Into<Web3ProxyError>,
|
||||||
|
{
|
||||||
|
fn web3_context<S: Into<String>>(self, msg: S) -> Result<T, Web3ProxyError> {
|
||||||
|
self.map_err(|err| Web3ProxyError::WithContext(Some(Box::new(err.into())), msg.into()))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
//! Handle admin helper logic
|
//! Handle admin helper logic
|
||||||
|
|
||||||
use super::authorization::login_is_authorized;
|
use super::authorization::login_is_authorized;
|
||||||
use super::errors::Web3ProxyResponse;
|
|
||||||
use crate::admin_queries::query_admin_modify_usertier;
|
use crate::admin_queries::query_admin_modify_usertier;
|
||||||
use crate::app::Web3ProxyApp;
|
use crate::app::Web3ProxyApp;
|
||||||
use crate::frontend::errors::{Web3ProxyError, Web3ProxyErrorContext};
|
use crate::errors::Web3ProxyResponse;
|
||||||
|
use crate::errors::{Web3ProxyError, Web3ProxyErrorContext};
|
||||||
use crate::user_token::UserBearerToken;
|
use crate::user_token::UserBearerToken;
|
||||||
use crate::PostLogin;
|
use crate::PostLogin;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
//! Utilities for authorization of logged in and anonymous users.
|
//! Utilities for authorization of logged in and anonymous users.
|
||||||
|
|
||||||
use super::errors::{Web3ProxyError, Web3ProxyErrorContext, Web3ProxyResult};
|
|
||||||
use super::rpc_proxy_ws::ProxyMode;
|
use super::rpc_proxy_ws::ProxyMode;
|
||||||
use crate::app::{AuthorizationChecks, Web3ProxyApp, APP_USER_AGENT};
|
use crate::app::{AuthorizationChecks, Web3ProxyApp, APP_USER_AGENT};
|
||||||
|
use crate::errors::{Web3ProxyError, Web3ProxyErrorContext, Web3ProxyResult};
|
||||||
use crate::jsonrpc::{JsonRpcForwardedResponse, JsonRpcRequest};
|
use crate::jsonrpc::{JsonRpcForwardedResponse, JsonRpcRequest};
|
||||||
use crate::rpcs::one::Web3Rpc;
|
use crate::rpcs::one::Web3Rpc;
|
||||||
use crate::stats::{AppStat, BackendRequests, RpcQueryStats};
|
use crate::stats::{AppStat, BackendRequests, RpcQueryStats};
|
||||||
|
|
|
@ -1,993 +1,7 @@
|
||||||
//! Utlities for logging errors for admins and displaying errors to users.
|
use crate::errors::Web3ProxyError;
|
||||||
|
use axum::response::{IntoResponse, Response};
|
||||||
use super::authorization::Authorization;
|
|
||||||
use crate::jsonrpc::{JsonRpcErrorData, JsonRpcForwardedResponse};
|
|
||||||
use crate::response_cache::JsonRpcResponseEnum;
|
|
||||||
|
|
||||||
use std::error::Error;
|
|
||||||
use std::{borrow::Cow, net::IpAddr};
|
|
||||||
|
|
||||||
use axum::{
|
|
||||||
headers,
|
|
||||||
http::StatusCode,
|
|
||||||
response::{IntoResponse, Response},
|
|
||||||
Json,
|
|
||||||
};
|
|
||||||
use derive_more::{Display, Error, From};
|
|
||||||
use http::header::InvalidHeaderValue;
|
|
||||||
use ipnet::AddrParseError;
|
|
||||||
use log::{debug, error, info, trace, warn};
|
|
||||||
use migration::sea_orm::DbErr;
|
|
||||||
use redis_rate_limiter::redis::RedisError;
|
|
||||||
use reqwest::header::ToStrError;
|
|
||||||
use serde::Serialize;
|
|
||||||
use serde_json::value::RawValue;
|
|
||||||
use tokio::{sync::AcquireError, task::JoinError, time::Instant};
|
|
||||||
|
|
||||||
pub type Web3ProxyResult<T> = Result<T, Web3ProxyError>;
|
|
||||||
// TODO: take "IntoResponse" instead of Response?
|
|
||||||
pub type Web3ProxyResponse = Web3ProxyResult<Response>;
|
|
||||||
|
|
||||||
impl From<Web3ProxyError> for Web3ProxyResult<()> {
|
|
||||||
fn from(value: Web3ProxyError) -> Self {
|
|
||||||
Err(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Display, Error, From)]
|
|
||||||
pub enum Web3ProxyError {
|
|
||||||
AccessDenied,
|
|
||||||
#[error(ignore)]
|
|
||||||
Anyhow(anyhow::Error),
|
|
||||||
#[error(ignore)]
|
|
||||||
#[from(ignore)]
|
|
||||||
BadRequest(String),
|
|
||||||
#[error(ignore)]
|
|
||||||
#[from(ignore)]
|
|
||||||
BadResponse(String),
|
|
||||||
BadRouting,
|
|
||||||
Database(DbErr),
|
|
||||||
#[display(fmt = "{:#?}, {:#?}", _0, _1)]
|
|
||||||
EipVerificationFailed(Box<Web3ProxyError>, Box<Web3ProxyError>),
|
|
||||||
EthersHttpClient(ethers::prelude::HttpClientError),
|
|
||||||
EthersProvider(ethers::prelude::ProviderError),
|
|
||||||
EthersWsClient(ethers::prelude::WsClientError),
|
|
||||||
FlumeRecv(flume::RecvError),
|
|
||||||
GasEstimateNotU256,
|
|
||||||
Headers(headers::Error),
|
|
||||||
HeaderToString(ToStrError),
|
|
||||||
Hyper(hyper::Error),
|
|
||||||
InfluxDb2Request(influxdb2::RequestError),
|
|
||||||
#[display(fmt = "{} > {}", min, max)]
|
|
||||||
#[from(ignore)]
|
|
||||||
InvalidBlockBounds {
|
|
||||||
min: u64,
|
|
||||||
max: u64,
|
|
||||||
},
|
|
||||||
InvalidHeaderValue(InvalidHeaderValue),
|
|
||||||
InvalidEip,
|
|
||||||
InvalidInviteCode,
|
|
||||||
Io(std::io::Error),
|
|
||||||
UnknownReferralCode,
|
|
||||||
InvalidReferer,
|
|
||||||
InvalidSignatureLength,
|
|
||||||
InvalidUserAgent,
|
|
||||||
InvalidUserKey,
|
|
||||||
IpAddrParse(AddrParseError),
|
|
||||||
#[error(ignore)]
|
|
||||||
#[from(ignore)]
|
|
||||||
IpNotAllowed(IpAddr),
|
|
||||||
JoinError(JoinError),
|
|
||||||
#[display(fmt = "{:?}", _0)]
|
|
||||||
#[error(ignore)]
|
|
||||||
JsonRpcErrorData(JsonRpcErrorData),
|
|
||||||
#[display(fmt = "{:?}", _0)]
|
|
||||||
#[error(ignore)]
|
|
||||||
MsgPackEncode(rmp_serde::encode::Error),
|
|
||||||
NoBlockNumberOrHash,
|
|
||||||
NoBlocksKnown,
|
|
||||||
NoConsensusHeadBlock,
|
|
||||||
NoHandleReady,
|
|
||||||
NoServersSynced,
|
|
||||||
#[display(fmt = "{}/{}", num_known, min_head_rpcs)]
|
|
||||||
#[from(ignore)]
|
|
||||||
NotEnoughRpcs {
|
|
||||||
num_known: usize,
|
|
||||||
min_head_rpcs: usize,
|
|
||||||
},
|
|
||||||
#[display(fmt = "{}/{}", available, needed)]
|
|
||||||
#[from(ignore)]
|
|
||||||
NotEnoughSoftLimit {
|
|
||||||
available: u32,
|
|
||||||
needed: u32,
|
|
||||||
},
|
|
||||||
NotFound,
|
|
||||||
NotImplemented,
|
|
||||||
OriginRequired,
|
|
||||||
#[error(ignore)]
|
|
||||||
#[from(ignore)]
|
|
||||||
OriginNotAllowed(headers::Origin),
|
|
||||||
#[display(fmt = "{:?}", _0)]
|
|
||||||
#[error(ignore)]
|
|
||||||
ParseBytesError(Option<ethers::types::ParseBytesError>),
|
|
||||||
ParseMsgError(siwe::ParseError),
|
|
||||||
ParseAddressError,
|
|
||||||
#[display(fmt = "{:?}, {:?}", _0, _1)]
|
|
||||||
RateLimited(Authorization, Option<Instant>),
|
|
||||||
Redis(RedisError),
|
|
||||||
RefererRequired,
|
|
||||||
#[display(fmt = "{:?}", _0)]
|
|
||||||
#[error(ignore)]
|
|
||||||
#[from(ignore)]
|
|
||||||
RefererNotAllowed(headers::Referer),
|
|
||||||
SemaphoreAcquireError(AcquireError),
|
|
||||||
SendAppStatError(flume::SendError<crate::stats::AppStat>),
|
|
||||||
SerdeJson(serde_json::Error),
|
|
||||||
/// simple way to return an error message to the user and an anyhow to our logs
|
|
||||||
#[display(fmt = "{}, {}, {:?}", _0, _1, _2)]
|
|
||||||
StatusCode(StatusCode, String, Option<anyhow::Error>),
|
|
||||||
/// TODO: what should be attached to the timout?
|
|
||||||
#[display(fmt = "{:?}", _0)]
|
|
||||||
#[error(ignore)]
|
|
||||||
Timeout(Option<tokio::time::error::Elapsed>),
|
|
||||||
UlidDecode(ulid::DecodeError),
|
|
||||||
UnknownBlockNumber,
|
|
||||||
UnknownKey,
|
|
||||||
UserAgentRequired,
|
|
||||||
#[error(ignore)]
|
|
||||||
UserAgentNotAllowed(headers::UserAgent),
|
|
||||||
UserIdZero,
|
|
||||||
PaymentRequired,
|
|
||||||
VerificationError(siwe::VerificationError),
|
|
||||||
WatchRecvError(tokio::sync::watch::error::RecvError),
|
|
||||||
WatchSendError,
|
|
||||||
WebsocketOnly,
|
|
||||||
#[display(fmt = "{:?}, {}", _0, _1)]
|
|
||||||
#[error(ignore)]
|
|
||||||
WithContext(Option<Box<Web3ProxyError>>, String),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Web3ProxyError {
|
|
||||||
pub fn into_response_parts<R: Serialize>(self) -> (StatusCode, JsonRpcResponseEnum<R>) {
|
|
||||||
// TODO: include a unique request id in the data
|
|
||||||
let (code, err): (StatusCode, JsonRpcErrorData) = match self {
|
|
||||||
Self::AccessDenied => {
|
|
||||||
// TODO: attach something to this trace. probably don't include much in the message though. don't want to leak creds by accident
|
|
||||||
trace!("access denied");
|
|
||||||
(
|
|
||||||
StatusCode::FORBIDDEN,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("FORBIDDEN"),
|
|
||||||
code: StatusCode::FORBIDDEN.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::Anyhow(err) => {
|
|
||||||
warn!("anyhow. err={:?}", err);
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
// TODO: is it safe to expose all of our anyhow strings?
|
|
||||||
message: Cow::Owned(err.to_string()),
|
|
||||||
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::BadRequest(err) => {
|
|
||||||
debug!("BAD_REQUEST: {}", err);
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Owned(format!("bad request: {}", err)),
|
|
||||||
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Owned(format!("bad response: {}", err)),
|
|
||||||
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::BadRouting => {
|
|
||||||
error!("BadRouting");
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("bad routing"),
|
|
||||||
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::Database(err) => {
|
|
||||||
error!("database err={:?}", err);
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("database error!"),
|
|
||||||
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::EipVerificationFailed(err_1, err_191) => {
|
|
||||||
info!(
|
|
||||||
"EipVerificationFailed err_1={:#?} err2={:#?}",
|
|
||||||
err_1, err_191
|
|
||||||
);
|
|
||||||
(
|
|
||||||
StatusCode::UNAUTHORIZED,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Owned(format!(
|
|
||||||
"both the primary and eip191 verification failed: {:#?}; {:#?}",
|
|
||||||
err_1, err_191
|
|
||||||
)),
|
|
||||||
code: StatusCode::UNAUTHORIZED.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::EthersHttpClient(err) => {
|
|
||||||
warn!("EthersHttpClientError err={:?}", err);
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("ether http client error"),
|
|
||||||
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::EthersProvider(err) => {
|
|
||||||
warn!("EthersProviderError err={:?}", err);
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("ether provider error"),
|
|
||||||
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::EthersWsClient(err) => {
|
|
||||||
warn!("EthersWsClientError err={:?}", err);
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("ether ws client error"),
|
|
||||||
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::FlumeRecv(err) => {
|
|
||||||
warn!("FlumeRecvError err={:#?}", err);
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("flume recv error!"),
|
|
||||||
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
// Self::JsonRpcForwardedError(x) => (StatusCode::OK, x),
|
|
||||||
Self::GasEstimateNotU256 => {
|
|
||||||
warn!("GasEstimateNotU256");
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("gas estimate result is not an U256"),
|
|
||||||
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::Headers(err) => {
|
|
||||||
warn!("HeadersError {:?}", err);
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Owned(format!("{}", err)),
|
|
||||||
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::Hyper(err) => {
|
|
||||||
warn!("hyper err={:?}", err);
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
// TODO: is it safe to expose these error strings?
|
|
||||||
message: Cow::Owned(err.to_string()),
|
|
||||||
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::InfluxDb2Request(err) => {
|
|
||||||
// TODO: attach a request id to the message and to this error so that if people report problems, we can dig in sentry to find out more
|
|
||||||
error!("influxdb2 err={:?}", err);
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("influxdb2 error!"),
|
|
||||||
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::InvalidBlockBounds { min, max } => {
|
|
||||||
debug!("InvalidBlockBounds min={} max={}", min, max);
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Owned(format!(
|
|
||||||
"Invalid blocks bounds requested. min ({}) > max ({})",
|
|
||||||
min, max
|
|
||||||
)),
|
|
||||||
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::IpAddrParse(err) => {
|
|
||||||
debug!("IpAddrParse err={:?}", err);
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Owned(err.to_string()),
|
|
||||||
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::IpNotAllowed(ip) => {
|
|
||||||
debug!("IpNotAllowed ip={})", ip);
|
|
||||||
(
|
|
||||||
StatusCode::FORBIDDEN,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Owned(format!("IP ({}) is not allowed!", ip)),
|
|
||||||
code: StatusCode::FORBIDDEN.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::InvalidHeaderValue(err) => {
|
|
||||||
debug!("InvalidHeaderValue err={:?}", err);
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Owned(format!("{}", err)),
|
|
||||||
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::InvalidEip => {
|
|
||||||
debug!("InvalidEip");
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("invalid message eip given"),
|
|
||||||
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::InvalidInviteCode => {
|
|
||||||
debug!("InvalidInviteCode");
|
|
||||||
(
|
|
||||||
StatusCode::UNAUTHORIZED,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("invalid invite code"),
|
|
||||||
code: StatusCode::UNAUTHORIZED.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::Io(err) => {
|
|
||||||
warn!("std io err={:?}", err);
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
// TODO: is it safe to expose our io error strings?
|
|
||||||
message: Cow::Owned(err.to_string()),
|
|
||||||
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::UnknownReferralCode => {
|
|
||||||
debug!("UnknownReferralCode");
|
|
||||||
(
|
|
||||||
StatusCode::UNAUTHORIZED,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("invalid referral code"),
|
|
||||||
code: StatusCode::UNAUTHORIZED.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::InvalidReferer => {
|
|
||||||
debug!("InvalidReferer");
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("invalid referer!"),
|
|
||||||
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::InvalidSignatureLength => {
|
|
||||||
debug!("InvalidSignatureLength");
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("invalid signature length"),
|
|
||||||
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::InvalidUserAgent => {
|
|
||||||
debug!("InvalidUserAgent");
|
|
||||||
(
|
|
||||||
StatusCode::FORBIDDEN,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("invalid user agent!"),
|
|
||||||
code: StatusCode::FORBIDDEN.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::InvalidUserKey => {
|
|
||||||
warn!("InvalidUserKey");
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("UserKey was not a ULID or UUID"),
|
|
||||||
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::JoinError(err) => {
|
|
||||||
let code = if err.is_cancelled() {
|
|
||||||
trace!("JoinError. likely shutting down. err={:?}", err);
|
|
||||||
StatusCode::BAD_GATEWAY
|
|
||||||
} else {
|
|
||||||
warn!("JoinError. err={:?}", err);
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR
|
|
||||||
};
|
|
||||||
|
|
||||||
(
|
|
||||||
code,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
// TODO: different messages of cancelled or not?
|
|
||||||
message: Cow::Borrowed("Unable to complete request"),
|
|
||||||
code: code.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::JsonRpcErrorData(jsonrpc_error_data) => (StatusCode::OK, jsonrpc_error_data),
|
|
||||||
Self::MsgPackEncode(err) => {
|
|
||||||
warn!("MsgPackEncode Error: {}", err);
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Owned(format!("msgpack encode error: {}", err)),
|
|
||||||
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::NoBlockNumberOrHash => {
|
|
||||||
warn!("NoBlockNumberOrHash");
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("Blocks here must have a number or hash"),
|
|
||||||
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::NoBlocksKnown => {
|
|
||||||
error!("NoBlocksKnown");
|
|
||||||
(
|
|
||||||
StatusCode::BAD_GATEWAY,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("no blocks known"),
|
|
||||||
code: StatusCode::BAD_GATEWAY.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::NoConsensusHeadBlock => {
|
|
||||||
error!("NoConsensusHeadBlock");
|
|
||||||
(
|
|
||||||
StatusCode::BAD_GATEWAY,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("no consensus head block"),
|
|
||||||
code: StatusCode::BAD_GATEWAY.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::NoHandleReady => {
|
|
||||||
error!("NoHandleReady");
|
|
||||||
(
|
|
||||||
StatusCode::BAD_GATEWAY,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("unable to retry for request handle"),
|
|
||||||
code: StatusCode::BAD_GATEWAY.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::NoServersSynced => {
|
|
||||||
warn!("NoServersSynced");
|
|
||||||
(
|
|
||||||
StatusCode::BAD_GATEWAY,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("no servers synced"),
|
|
||||||
code: StatusCode::BAD_GATEWAY.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::NotEnoughRpcs {
|
|
||||||
num_known,
|
|
||||||
min_head_rpcs,
|
|
||||||
} => {
|
|
||||||
error!("NotEnoughRpcs {}/{}", num_known, min_head_rpcs);
|
|
||||||
(
|
|
||||||
StatusCode::BAD_GATEWAY,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Owned(format!(
|
|
||||||
"not enough rpcs connected {}/{}",
|
|
||||||
num_known, min_head_rpcs
|
|
||||||
)),
|
|
||||||
code: StatusCode::BAD_GATEWAY.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::NotEnoughSoftLimit { available, needed } => {
|
|
||||||
error!("NotEnoughSoftLimit {}/{}", available, needed);
|
|
||||||
(
|
|
||||||
StatusCode::BAD_GATEWAY,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Owned(format!(
|
|
||||||
"not enough soft limit available {}/{}",
|
|
||||||
available, needed
|
|
||||||
)),
|
|
||||||
code: StatusCode::BAD_GATEWAY.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::NotFound => {
|
|
||||||
// TODO: emit a stat?
|
|
||||||
// TODO: instead of an error, show a normal html page for 404?
|
|
||||||
(
|
|
||||||
StatusCode::NOT_FOUND,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("not found!"),
|
|
||||||
code: StatusCode::NOT_FOUND.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::NotImplemented => {
|
|
||||||
trace!("NotImplemented");
|
|
||||||
(
|
|
||||||
StatusCode::NOT_IMPLEMENTED,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("work in progress"),
|
|
||||||
code: StatusCode::NOT_IMPLEMENTED.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::OriginRequired => {
|
|
||||||
trace!("OriginRequired");
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("Origin required"),
|
|
||||||
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::OriginNotAllowed(origin) => {
|
|
||||||
trace!("OriginNotAllowed origin={}", origin);
|
|
||||||
(
|
|
||||||
StatusCode::FORBIDDEN,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Owned(format!("Origin ({}) is not allowed!", origin)),
|
|
||||||
code: StatusCode::FORBIDDEN.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::ParseBytesError(err) => {
|
|
||||||
trace!("ParseBytesError err={:?}", err);
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("parse bytes error!"),
|
|
||||||
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::ParseMsgError(err) => {
|
|
||||||
trace!("ParseMsgError err={:?}", err);
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("parse message error!"),
|
|
||||||
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::ParseAddressError => {
|
|
||||||
trace!("ParseAddressError");
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("unable to parse address"),
|
|
||||||
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::PaymentRequired => {
|
|
||||||
trace!("PaymentRequiredError");
|
|
||||||
(
|
|
||||||
StatusCode::PAYMENT_REQUIRED,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("Payment is required and user is not premium"),
|
|
||||||
code: StatusCode::PAYMENT_REQUIRED.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
// TODO: this should actually by the id of the key. multiple users might control one key
|
|
||||||
Self::RateLimited(authorization, retry_at) => {
|
|
||||||
// TODO: emit a stat
|
|
||||||
|
|
||||||
let retry_msg = if let Some(retry_at) = retry_at {
|
|
||||||
let retry_in = retry_at.duration_since(Instant::now()).as_secs();
|
|
||||||
|
|
||||||
format!(" Retry in {} seconds", retry_in)
|
|
||||||
} else {
|
|
||||||
"".to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
// create a string with either the IP or the rpc_key_id
|
|
||||||
let msg = if authorization.checks.rpc_secret_key_id.is_none() {
|
|
||||||
format!("too many requests from {}.{}", authorization.ip, retry_msg)
|
|
||||||
} else {
|
|
||||||
format!(
|
|
||||||
"too many requests from rpc key #{}.{}",
|
|
||||||
authorization.checks.rpc_secret_key_id.unwrap(),
|
|
||||||
retry_msg,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
(
|
|
||||||
StatusCode::TOO_MANY_REQUESTS,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Owned(msg),
|
|
||||||
code: StatusCode::TOO_MANY_REQUESTS.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::Redis(err) => {
|
|
||||||
warn!("redis err={:?}", err);
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("redis error!"),
|
|
||||||
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::RefererRequired => {
|
|
||||||
warn!("referer required");
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("Referer required"),
|
|
||||||
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::RefererNotAllowed(referer) => {
|
|
||||||
warn!("referer not allowed referer={:?}", referer);
|
|
||||||
(
|
|
||||||
StatusCode::FORBIDDEN,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Owned(format!("Referer ({:?}) is not allowed", referer)),
|
|
||||||
code: StatusCode::FORBIDDEN.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::SemaphoreAcquireError(err) => {
|
|
||||||
warn!("semaphore acquire err={:?}", err);
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
// TODO: is it safe to expose all of our anyhow strings?
|
|
||||||
message: Cow::Borrowed("semaphore acquire error"),
|
|
||||||
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::SendAppStatError(err) => {
|
|
||||||
error!("SendAppStatError err={:?}", err);
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("error stat_sender sending response_stat"),
|
|
||||||
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::SerdeJson(err) => {
|
|
||||||
warn!("serde json err={:?} source={:?}", err, err.source());
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Owned(format!("de/serialization error! {}", err)),
|
|
||||||
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::StatusCode(status_code, err_msg, err) => {
|
|
||||||
// different status codes should get different error levels. 500s should warn. 400s should stat
|
|
||||||
let code = status_code.as_u16();
|
|
||||||
if (500..600).contains(&code) {
|
|
||||||
warn!("server error {} {:?}: {:?}", code, err_msg, err);
|
|
||||||
} else {
|
|
||||||
trace!("user error {} {:?}: {:?}", code, err_msg, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
(
|
|
||||||
status_code,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Owned(err_msg),
|
|
||||||
code: code.into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::Timeout(x) => (
|
|
||||||
StatusCode::REQUEST_TIMEOUT,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Owned(format!("request timed out: {:?}", x)),
|
|
||||||
code: StatusCode::REQUEST_TIMEOUT.as_u16().into(),
|
|
||||||
// TODO: include the actual id!
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Self::HeaderToString(err) => {
|
|
||||||
// trace!(?err, "HeaderToString");
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Owned(err.to_string()),
|
|
||||||
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::UlidDecode(err) => {
|
|
||||||
// trace!(?err, "UlidDecodeError");
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Owned(format!("{}", err)),
|
|
||||||
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::UnknownBlockNumber => {
|
|
||||||
error!("UnknownBlockNumber");
|
|
||||||
(
|
|
||||||
StatusCode::BAD_GATEWAY,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("no servers synced. unknown eth_blockNumber"),
|
|
||||||
code: StatusCode::BAD_GATEWAY.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
// TODO: stat?
|
|
||||||
Self::UnknownKey => (
|
|
||||||
StatusCode::UNAUTHORIZED,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("unknown api key!"),
|
|
||||||
code: StatusCode::UNAUTHORIZED.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Self::UserAgentRequired => {
|
|
||||||
warn!("UserAgentRequired");
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("User agent required"),
|
|
||||||
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::UserAgentNotAllowed(ua) => {
|
|
||||||
warn!("UserAgentNotAllowed ua={}", ua);
|
|
||||||
(
|
|
||||||
StatusCode::FORBIDDEN,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Owned(format!("User agent ({}) is not allowed!", ua)),
|
|
||||||
code: StatusCode::FORBIDDEN.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::UserIdZero => {
|
|
||||||
warn!("UserIdZero");
|
|
||||||
// TODO: this might actually be an application error and not a BAD_REQUEST
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("user ids should always be non-zero"),
|
|
||||||
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::VerificationError(err) => {
|
|
||||||
trace!("VerificationError err={:?}", err);
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("verification error!"),
|
|
||||||
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::WatchRecvError(err) => {
|
|
||||||
error!("WatchRecvError err={:?}", err);
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("watch recv error!"),
|
|
||||||
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::WatchSendError => {
|
|
||||||
error!("WatchSendError");
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed("watch send error!"),
|
|
||||||
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::WebsocketOnly => {
|
|
||||||
trace!("WebsocketOnly");
|
|
||||||
(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Borrowed(
|
|
||||||
"redirect_public_url not set. only websockets work here",
|
|
||||||
),
|
|
||||||
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::WithContext(err, msg) => match err {
|
|
||||||
Some(err) => {
|
|
||||||
warn!("{:#?} w/ context {}", err, msg);
|
|
||||||
return err.into_response_parts();
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
warn!("error w/ context {}", msg);
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
JsonRpcErrorData {
|
|
||||||
message: Cow::Owned(msg),
|
|
||||||
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
(code, JsonRpcResponseEnum::from(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_response_with_id(self, id: Box<RawValue>) -> Response {
|
|
||||||
let (status_code, response_data) = self.into_response_parts();
|
|
||||||
|
|
||||||
let response = JsonRpcForwardedResponse::from_response_data(response_data, id);
|
|
||||||
|
|
||||||
(status_code, Json(response)).into_response()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ethers::types::ParseBytesError> for Web3ProxyError {
|
|
||||||
fn from(err: ethers::types::ParseBytesError) -> Self {
|
|
||||||
Self::ParseBytesError(Some(err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<tokio::time::error::Elapsed> for Web3ProxyError {
|
|
||||||
fn from(err: tokio::time::error::Elapsed) -> Self {
|
|
||||||
Self::Timeout(Some(err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoResponse for Web3ProxyError {
|
|
||||||
#[inline]
|
|
||||||
fn into_response(self) -> Response {
|
|
||||||
self.into_response_with_id(Default::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn handler_404() -> Response {
|
pub async fn handler_404() -> Response {
|
||||||
Web3ProxyError::NotFound.into_response()
|
Web3ProxyError::NotFound.into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Web3ProxyErrorContext<T> {
|
|
||||||
fn web3_context<S: Into<String>>(self, msg: S) -> Result<T, Web3ProxyError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Web3ProxyErrorContext<T> for Option<T> {
|
|
||||||
fn web3_context<S: Into<String>>(self, msg: S) -> Result<T, Web3ProxyError> {
|
|
||||||
self.ok_or(Web3ProxyError::WithContext(None, msg.into()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, E> Web3ProxyErrorContext<T> for Result<T, E>
|
|
||||||
where
|
|
||||||
E: Into<Web3ProxyError>,
|
|
||||||
{
|
|
||||||
fn web3_context<S: Into<String>>(self, msg: S) -> Result<T, Web3ProxyError> {
|
|
||||||
self.map_err(|err| Web3ProxyError::WithContext(Some(Box::new(err.into())), msg.into()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
//! `frontend` contains HTTP and websocket endpoints for use by a website or web3 wallet.
|
//! `frontend` contains HTTP and websocket endpoints for use by a website or web3 wallet.
|
||||||
//!
|
//!
|
||||||
//! Important reading about axum extractors: <https://docs.rs/axum/latest/axum/extract/index.html#the-order-of-extractors>
|
//! Important reading about axum extractors: <https://docs.rs/axum/latest/axum/extract/index.html#the-order-of-extractors>
|
||||||
|
// TODO: these are only public so docs are generated. What's a better way to do this?
|
||||||
pub mod admin;
|
pub mod admin;
|
||||||
pub mod authorization;
|
pub mod authorization;
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
// TODO: these are only public so docs are generated. What's a better way to do this?
|
|
||||||
pub mod rpc_proxy_http;
|
pub mod rpc_proxy_http;
|
||||||
pub mod rpc_proxy_ws;
|
pub mod rpc_proxy_ws;
|
||||||
pub mod status;
|
pub mod status;
|
||||||
|
@ -28,7 +27,7 @@ use tokio::sync::broadcast;
|
||||||
use tower_http::cors::CorsLayer;
|
use tower_http::cors::CorsLayer;
|
||||||
use tower_http::sensitive_headers::SetSensitiveRequestHeadersLayer;
|
use tower_http::sensitive_headers::SetSensitiveRequestHeadersLayer;
|
||||||
|
|
||||||
use self::errors::Web3ProxyResult;
|
use crate::errors::Web3ProxyResult;
|
||||||
|
|
||||||
/// simple keys for caching responses
|
/// simple keys for caching responses
|
||||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, EnumCount, EnumIter)]
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, EnumCount, EnumIter)]
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
//! Take a user's HTTP JSON-RPC requests and either respond from local data or proxy the request to a backend rpc server.
|
//! Take a user's HTTP JSON-RPC requests and either respond from local data or proxy the request to a backend rpc server.
|
||||||
|
|
||||||
use super::authorization::{ip_is_authorized, key_is_authorized};
|
use super::authorization::{ip_is_authorized, key_is_authorized};
|
||||||
use super::errors::Web3ProxyError;
|
|
||||||
use super::rpc_proxy_ws::ProxyMode;
|
use super::rpc_proxy_ws::ProxyMode;
|
||||||
|
use crate::errors::Web3ProxyError;
|
||||||
use crate::{app::Web3ProxyApp, jsonrpc::JsonRpcRequestEnum};
|
use crate::{app::Web3ProxyApp, jsonrpc::JsonRpcRequestEnum};
|
||||||
use axum::extract::Path;
|
use axum::extract::Path;
|
||||||
use axum::headers::{Origin, Referer, UserAgent};
|
use axum::headers::{Origin, Referer, UserAgent};
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
//! WebSockets are the preferred method of receiving requests, but not all clients have good support.
|
//! WebSockets are the preferred method of receiving requests, but not all clients have good support.
|
||||||
|
|
||||||
use super::authorization::{ip_is_authorized, key_is_authorized, Authorization, RequestMetadata};
|
use super::authorization::{ip_is_authorized, key_is_authorized, Authorization, RequestMetadata};
|
||||||
use super::errors::{Web3ProxyError, Web3ProxyResponse};
|
use crate::errors::{Web3ProxyError, Web3ProxyResponse};
|
||||||
use crate::jsonrpc::JsonRpcId;
|
use crate::jsonrpc::JsonRpcId;
|
||||||
use crate::{
|
use crate::{
|
||||||
app::Web3ProxyApp,
|
app::Web3ProxyApp,
|
||||||
frontend::errors::Web3ProxyResult,
|
errors::Web3ProxyResult,
|
||||||
jsonrpc::{JsonRpcForwardedResponse, JsonRpcForwardedResponseEnum, JsonRpcRequest},
|
jsonrpc::{JsonRpcForwardedResponse, JsonRpcForwardedResponseEnum, JsonRpcRequest},
|
||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! Handle registration, logins, and managing account data.
|
//! Handle registration, logins, and managing account data.
|
||||||
use crate::app::Web3ProxyApp;
|
use crate::app::Web3ProxyApp;
|
||||||
|
use crate::errors::{Web3ProxyError, Web3ProxyErrorContext, Web3ProxyResponse};
|
||||||
use crate::frontend::authorization::{login_is_authorized, RpcSecretKey};
|
use crate::frontend::authorization::{login_is_authorized, RpcSecretKey};
|
||||||
use crate::frontend::errors::{Web3ProxyError, Web3ProxyErrorContext, Web3ProxyResponse};
|
|
||||||
use crate::user_token::UserBearerToken;
|
use crate::user_token::UserBearerToken;
|
||||||
use crate::{PostLogin, PostLoginQuery};
|
use crate::{PostLogin, PostLoginQuery};
|
||||||
use axum::{
|
use axum::{
|
||||||
|
|
|
@ -6,8 +6,8 @@ pub mod rpc_keys;
|
||||||
pub mod stats;
|
pub mod stats;
|
||||||
pub mod subuser;
|
pub mod subuser;
|
||||||
|
|
||||||
use super::errors::{Web3ProxyErrorContext, Web3ProxyResponse};
|
|
||||||
use crate::app::Web3ProxyApp;
|
use crate::app::Web3ProxyApp;
|
||||||
|
use crate::errors::{Web3ProxyErrorContext, Web3ProxyResponse};
|
||||||
|
|
||||||
use axum::{
|
use axum::{
|
||||||
headers::{authorization::Bearer, Authorization},
|
headers::{authorization::Bearer, Authorization},
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::app::Web3ProxyApp;
|
use crate::app::Web3ProxyApp;
|
||||||
use crate::frontend::errors::{Web3ProxyError, Web3ProxyResponse};
|
use crate::errors::{Web3ProxyError, Web3ProxyResponse};
|
||||||
use anyhow::{anyhow, Context};
|
use anyhow::{anyhow, Context};
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::Path,
|
extract::Path,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Handle registration, logins, and managing account data.
|
//! Handle registration, logins, and managing account data.
|
||||||
use crate::app::Web3ProxyApp;
|
use crate::app::Web3ProxyApp;
|
||||||
use crate::frontend::errors::Web3ProxyResponse;
|
use crate::errors::Web3ProxyResponse;
|
||||||
use crate::referral_code::ReferralCode;
|
use crate::referral_code::ReferralCode;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use axum::{
|
use axum::{
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! Handle registration, logins, and managing account data.
|
//! Handle registration, logins, and managing account data.
|
||||||
use super::super::authorization::RpcSecretKey;
|
use super::super::authorization::RpcSecretKey;
|
||||||
use super::super::errors::{Web3ProxyError, Web3ProxyErrorContext, Web3ProxyResponse};
|
|
||||||
use crate::app::Web3ProxyApp;
|
use crate::app::Web3ProxyApp;
|
||||||
|
use crate::errors::{Web3ProxyError, Web3ProxyErrorContext, Web3ProxyResponse};
|
||||||
use axum::headers::{Header, Origin, Referer, UserAgent};
|
use axum::headers::{Header, Origin, Referer, UserAgent};
|
||||||
use axum::{
|
use axum::{
|
||||||
headers::{authorization::Bearer, Authorization},
|
headers::{authorization::Bearer, Authorization},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Handle registration, logins, and managing account data.
|
//! Handle registration, logins, and managing account data.
|
||||||
use crate::app::Web3ProxyApp;
|
use crate::app::Web3ProxyApp;
|
||||||
use crate::frontend::errors::{Web3ProxyErrorContext, Web3ProxyResponse};
|
use crate::errors::{Web3ProxyErrorContext, Web3ProxyResponse};
|
||||||
use crate::http_params::{
|
use crate::http_params::{
|
||||||
get_chain_id_from_params, get_page_from_params, get_query_start_from_params,
|
get_chain_id_from_params, get_page_from_params, get_query_start_from_params,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! Handle subusers, viewing subusers, and viewing accessible rpc-keys
|
//! Handle subusers, viewing subusers, and viewing accessible rpc-keys
|
||||||
use crate::app::Web3ProxyApp;
|
use crate::app::Web3ProxyApp;
|
||||||
|
use crate::errors::{Web3ProxyError, Web3ProxyErrorContext, Web3ProxyResponse};
|
||||||
use crate::frontend::authorization::RpcSecretKey;
|
use crate::frontend::authorization::RpcSecretKey;
|
||||||
use crate::frontend::errors::{Web3ProxyError, Web3ProxyErrorContext, Web3ProxyResponse};
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::Query,
|
extract::Query,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::frontend::errors::{Web3ProxyError, Web3ProxyResult};
|
use crate::errors::{Web3ProxyError, Web3ProxyResult};
|
||||||
use crate::relational_db::{DatabaseConnection, DatabaseReplica};
|
use crate::relational_db::{DatabaseConnection, DatabaseReplica};
|
||||||
use crate::{app::Web3ProxyApp, user_token::UserBearerToken};
|
use crate::{app::Web3ProxyApp, user_token::UserBearerToken};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tokio::sync::broadcast;
|
||||||
|
|
||||||
|
use crate::app::Web3ProxyApp;
|
||||||
|
use crate::errors::Web3ProxyResult;
|
||||||
|
|
||||||
|
/// Start an ipc server that has no rate limits
|
||||||
|
pub async fn serve(
|
||||||
|
socket_path: PathBuf,
|
||||||
|
proxy_app: Arc<Web3ProxyApp>,
|
||||||
|
mut shutdown_receiver: broadcast::Receiver<()>,
|
||||||
|
shutdown_complete_sender: broadcast::Sender<()>,
|
||||||
|
) -> Web3ProxyResult<()> {
|
||||||
|
todo!();
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::frontend::errors::{Web3ProxyError, Web3ProxyResult};
|
use crate::errors::{Web3ProxyError, Web3ProxyResult};
|
||||||
use crate::response_cache::JsonRpcResponseEnum;
|
use crate::response_cache::JsonRpcResponseEnum;
|
||||||
use derive_more::From;
|
use derive_more::From;
|
||||||
use ethers::prelude::ProviderError;
|
use ethers::prelude::ProviderError;
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
use crate::app::Web3ProxyApp;
|
|
||||||
// use crate::frontend::errors::Web3ProxyError;
|
|
||||||
use ethers::providers::{JsonRpcClient, ProviderError};
|
|
||||||
use serde::{de::DeserializeOwned, Serialize};
|
|
||||||
use std::fmt::Debug;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
/// use the app as an ether's JsonRpcClient
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Web3ProxyAppClient(Arc<Web3ProxyApp>);
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl JsonRpcClient for Web3ProxyAppClient {
|
|
||||||
type Error = ProviderError;
|
|
||||||
|
|
||||||
async fn request<T, R>(&self, method: &str, params: T) -> Result<R, Self::Error>
|
|
||||||
where
|
|
||||||
T: Debug + Serialize + Send + Sync,
|
|
||||||
R: DeserializeOwned + Send,
|
|
||||||
{
|
|
||||||
todo!("figure out traits");
|
|
||||||
// match self.0.internal_request(method, ¶ms).await {
|
|
||||||
// Ok(x) => Ok(x),
|
|
||||||
// Err(Web3ProxyError::EthersProvider(err)) => Err(err),
|
|
||||||
// Err(err) => Err(ProviderError::CustomError(format!("{}", err))),
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,10 +4,11 @@ pub mod admin_queries;
|
||||||
pub mod app;
|
pub mod app;
|
||||||
pub mod block_number;
|
pub mod block_number;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
pub mod errors;
|
||||||
pub mod frontend;
|
pub mod frontend;
|
||||||
pub mod http_params;
|
pub mod http_params;
|
||||||
|
pub mod ipc;
|
||||||
pub mod jsonrpc;
|
pub mod jsonrpc;
|
||||||
pub mod jsonrpc_client;
|
|
||||||
pub mod pagerduty;
|
pub mod pagerduty;
|
||||||
pub mod prometheus;
|
pub mod prometheus;
|
||||||
pub mod referral_code;
|
pub mod referral_code;
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::sync::Arc;
|
||||||
use tokio::sync::broadcast;
|
use tokio::sync::broadcast;
|
||||||
|
|
||||||
use crate::app::Web3ProxyApp;
|
use crate::app::Web3ProxyApp;
|
||||||
use crate::frontend::errors::Web3ProxyResult;
|
use crate::errors::Web3ProxyResult;
|
||||||
|
|
||||||
/// Run a prometheus metrics server on the given port.
|
/// Run a prometheus metrics server on the given port.
|
||||||
pub async fn serve(
|
pub async fn serve(
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
use crate::{
|
use crate::{errors::Web3ProxyError, jsonrpc::JsonRpcErrorData, rpcs::blockchain::ArcBlock};
|
||||||
frontend::errors::Web3ProxyError, jsonrpc::JsonRpcErrorData, rpcs::blockchain::ArcBlock,
|
|
||||||
};
|
|
||||||
use derive_more::From;
|
use derive_more::From;
|
||||||
use ethers::{providers::ProviderError, types::U64};
|
use ethers::{providers::ProviderError, types::U64};
|
||||||
use hashbrown::hash_map::DefaultHashBuilder;
|
use hashbrown::hash_map::DefaultHashBuilder;
|
||||||
|
|
|
@ -4,8 +4,8 @@ use super::many::Web3Rpcs;
|
||||||
use super::one::Web3Rpc;
|
use super::one::Web3Rpc;
|
||||||
use super::transactions::TxStatus;
|
use super::transactions::TxStatus;
|
||||||
use crate::config::BlockAndRpc;
|
use crate::config::BlockAndRpc;
|
||||||
|
use crate::errors::{Web3ProxyError, Web3ProxyErrorContext, Web3ProxyResult};
|
||||||
use crate::frontend::authorization::Authorization;
|
use crate::frontend::authorization::Authorization;
|
||||||
use crate::frontend::errors::{Web3ProxyError, Web3ProxyErrorContext, Web3ProxyResult};
|
|
||||||
use derive_more::From;
|
use derive_more::From;
|
||||||
use ethers::prelude::{Block, TxHash, H256, U64};
|
use ethers::prelude::{Block, TxHash, H256, U64};
|
||||||
use log::{debug, trace, warn};
|
use log::{debug, trace, warn};
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use super::blockchain::Web3ProxyBlock;
|
use super::blockchain::Web3ProxyBlock;
|
||||||
use super::many::Web3Rpcs;
|
use super::many::Web3Rpcs;
|
||||||
use super::one::Web3Rpc;
|
use super::one::Web3Rpc;
|
||||||
|
use crate::errors::{Web3ProxyErrorContext, Web3ProxyResult};
|
||||||
use crate::frontend::authorization::Authorization;
|
use crate::frontend::authorization::Authorization;
|
||||||
use crate::frontend::errors::{Web3ProxyErrorContext, Web3ProxyResult};
|
|
||||||
use derive_more::Constructor;
|
use derive_more::Constructor;
|
||||||
use ethers::prelude::{H256, U64};
|
use ethers::prelude::{H256, U64};
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
|
|
|
@ -5,8 +5,8 @@ use super::one::Web3Rpc;
|
||||||
use super::request::{OpenRequestHandle, OpenRequestResult, RequestErrorHandler};
|
use super::request::{OpenRequestHandle, OpenRequestResult, RequestErrorHandler};
|
||||||
use crate::app::{flatten_handle, Web3ProxyApp, Web3ProxyJoinHandle};
|
use crate::app::{flatten_handle, Web3ProxyApp, Web3ProxyJoinHandle};
|
||||||
use crate::config::{BlockAndRpc, TxHashAndRpc, Web3RpcConfig};
|
use crate::config::{BlockAndRpc, TxHashAndRpc, Web3RpcConfig};
|
||||||
|
use crate::errors::{Web3ProxyError, Web3ProxyResult};
|
||||||
use crate::frontend::authorization::{Authorization, RequestMetadata};
|
use crate::frontend::authorization::{Authorization, RequestMetadata};
|
||||||
use crate::frontend::errors::{Web3ProxyError, Web3ProxyResult};
|
|
||||||
use crate::frontend::rpc_proxy_ws::ProxyMode;
|
use crate::frontend::rpc_proxy_ws::ProxyMode;
|
||||||
use crate::jsonrpc::{JsonRpcErrorData, JsonRpcParams, JsonRpcResultData};
|
use crate::jsonrpc::{JsonRpcErrorData, JsonRpcParams, JsonRpcResultData};
|
||||||
use crate::rpcs::transactions::TxStatus;
|
use crate::rpcs::transactions::TxStatus;
|
||||||
|
|
|
@ -4,8 +4,8 @@ use super::provider::{connect_http, connect_ws, EthersHttpProvider, EthersWsProv
|
||||||
use super::request::{OpenRequestHandle, OpenRequestResult};
|
use super::request::{OpenRequestHandle, OpenRequestResult};
|
||||||
use crate::app::{flatten_handle, Web3ProxyJoinHandle};
|
use crate::app::{flatten_handle, Web3ProxyJoinHandle};
|
||||||
use crate::config::{BlockAndRpc, Web3RpcConfig};
|
use crate::config::{BlockAndRpc, Web3RpcConfig};
|
||||||
|
use crate::errors::{Web3ProxyError, Web3ProxyResult};
|
||||||
use crate::frontend::authorization::Authorization;
|
use crate::frontend::authorization::Authorization;
|
||||||
use crate::frontend::errors::{Web3ProxyError, Web3ProxyResult};
|
|
||||||
use crate::jsonrpc::{JsonRpcParams, JsonRpcResultData};
|
use crate::jsonrpc::{JsonRpcParams, JsonRpcResultData};
|
||||||
use crate::rpcs::request::RequestErrorHandler;
|
use crate::rpcs::request::RequestErrorHandler;
|
||||||
use anyhow::{anyhow, Context};
|
use anyhow::{anyhow, Context};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::one::Web3Rpc;
|
use super::one::Web3Rpc;
|
||||||
|
use crate::errors::Web3ProxyResult;
|
||||||
use crate::frontend::authorization::Authorization;
|
use crate::frontend::authorization::Authorization;
|
||||||
use crate::frontend::errors::Web3ProxyResult;
|
|
||||||
use crate::jsonrpc::{JsonRpcParams, JsonRpcResultData};
|
use crate::jsonrpc::{JsonRpcParams, JsonRpcResultData};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
use super::many::Web3Rpcs;
|
use super::many::Web3Rpcs;
|
||||||
use super::one::Web3Rpc;
|
use super::one::Web3Rpc;
|
||||||
use super::request::OpenRequestResult;
|
use super::request::OpenRequestResult;
|
||||||
use crate::frontend::{authorization::Authorization, errors::Web3ProxyResult};
|
use crate::errors::Web3ProxyResult;
|
||||||
|
use crate::frontend::authorization::Authorization;
|
||||||
use ethers::prelude::{ProviderError, Transaction, TxHash};
|
use ethers::prelude::{ProviderError, Transaction, TxHash};
|
||||||
use log::{debug, trace, Level};
|
use log::{debug, trace, Level};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::StatType;
|
use super::StatType;
|
||||||
use crate::app::Web3ProxyApp;
|
use crate::app::Web3ProxyApp;
|
||||||
use crate::frontend::errors::{Web3ProxyError, Web3ProxyResponse, Web3ProxyResult};
|
use crate::errors::{Web3ProxyError, Web3ProxyResponse, Web3ProxyResult};
|
||||||
use crate::http_params::{
|
use crate::http_params::{
|
||||||
get_chain_id_from_params, get_page_from_params, get_query_start_from_params,
|
get_chain_id_from_params, get_page_from_params, get_query_start_from_params,
|
||||||
get_query_window_seconds_from_params, get_user_id_from_params,
|
get_query_window_seconds_from_params, get_user_id_from_params,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use super::StatType;
|
use super::StatType;
|
||||||
use crate::frontend::errors::Web3ProxyErrorContext;
|
use crate::errors::Web3ProxyErrorContext;
|
||||||
use crate::{
|
use crate::{
|
||||||
app::Web3ProxyApp,
|
app::Web3ProxyApp,
|
||||||
frontend::errors::{Web3ProxyError, Web3ProxyResponse},
|
errors::{Web3ProxyError, Web3ProxyResponse},
|
||||||
http_params::{
|
http_params::{
|
||||||
get_chain_id_from_params, get_query_start_from_params, get_query_stop_from_params,
|
get_chain_id_from_params, get_query_start_from_params, get_query_stop_from_params,
|
||||||
get_query_window_seconds_from_params,
|
get_query_window_seconds_from_params,
|
||||||
|
|
|
@ -7,8 +7,8 @@ mod stat_buffer;
|
||||||
pub use stat_buffer::{SpawnedStatBuffer, StatBuffer};
|
pub use stat_buffer::{SpawnedStatBuffer, StatBuffer};
|
||||||
|
|
||||||
use crate::app::RpcSecretKeyCache;
|
use crate::app::RpcSecretKeyCache;
|
||||||
|
use crate::errors::{Web3ProxyError, Web3ProxyResult};
|
||||||
use crate::frontend::authorization::{Authorization, RequestMetadata};
|
use crate::frontend::authorization::{Authorization, RequestMetadata};
|
||||||
use crate::frontend::errors::{Web3ProxyError, Web3ProxyResult};
|
|
||||||
use crate::rpcs::one::Web3Rpc;
|
use crate::rpcs::one::Web3Rpc;
|
||||||
use anyhow::{anyhow, Context};
|
use anyhow::{anyhow, Context};
|
||||||
use axum::headers::Origin;
|
use axum::headers::Origin;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::{AppStat, RpcQueryKey};
|
use super::{AppStat, RpcQueryKey};
|
||||||
use crate::app::{RpcSecretKeyCache, Web3ProxyJoinHandle};
|
use crate::app::{RpcSecretKeyCache, Web3ProxyJoinHandle};
|
||||||
use crate::frontend::errors::Web3ProxyResult;
|
use crate::errors::Web3ProxyResult;
|
||||||
use derive_more::From;
|
use derive_more::From;
|
||||||
use futures::stream;
|
use futures::stream;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
|
Loading…
Reference in New Issue