block all admin_ commands
This commit is contained in:
parent
ca1e550370
commit
1d749ed33d
1
TODO.md
1
TODO.md
|
@ -327,6 +327,7 @@ These are not yet ordered. There might be duplicates. We might not actually need
|
||||||
- [x] short lived cache on /health
|
- [x] short lived cache on /health
|
||||||
- [x] cache /status for longer
|
- [x] cache /status for longer
|
||||||
- [x] sort connections during eth_sendRawTransaction
|
- [x] sort connections during eth_sendRawTransaction
|
||||||
|
- [x] block all admin_ rpc commands
|
||||||
- [-] proxy mode for benchmarking all backends
|
- [-] proxy mode for benchmarking all backends
|
||||||
- [-] proxy mode for sending to multiple backends
|
- [-] proxy mode for sending to multiple backends
|
||||||
- [-] let users choose a % of reverts to log (or maybe x/second). someone like curve logging all reverts will be a BIG database very quickly
|
- [-] let users choose a % of reverts to log (or maybe x/second). someone like curve logging all reverts will be a BIG database very quickly
|
||||||
|
|
|
@ -212,7 +212,7 @@ pub struct Web3ProxyApp {
|
||||||
pub db_conn: Option<sea_orm::DatabaseConnection>,
|
pub db_conn: Option<sea_orm::DatabaseConnection>,
|
||||||
pub db_replica: Option<DatabaseReplica>,
|
pub db_replica: Option<DatabaseReplica>,
|
||||||
/// prometheus metrics
|
/// prometheus metrics
|
||||||
app_metrics: Arc<Web3ProxyAppMetrics>,
|
// app_metrics: Arc<Web3ProxyAppMetrics>,
|
||||||
open_request_handle_metrics: Arc<OpenRequestHandleMetrics>,
|
open_request_handle_metrics: Arc<OpenRequestHandleMetrics>,
|
||||||
/// store pending transactions that we've seen so that we don't send duplicates to subscribers
|
/// store pending transactions that we've seen so that we don't send duplicates to subscribers
|
||||||
pub pending_transactions: Cache<TxHash, TxStatus, hashbrown::hash_map::DefaultHashBuilder>,
|
pub pending_transactions: Cache<TxHash, TxStatus, hashbrown::hash_map::DefaultHashBuilder>,
|
||||||
|
@ -365,7 +365,7 @@ pub struct Web3ProxyAppSpawn {
|
||||||
pub background_handles: FuturesUnordered<AnyhowJoinHandle<()>>,
|
pub background_handles: FuturesUnordered<AnyhowJoinHandle<()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[metered(registry = Web3ProxyAppMetrics, registry_expr = self.app_metrics, visibility = pub)]
|
// #[metered(registry = Web3ProxyAppMetrics, registry_expr = self.app_metrics, visibility = pub)]
|
||||||
impl Web3ProxyApp {
|
impl Web3ProxyApp {
|
||||||
/// The main entrypoint.
|
/// The main entrypoint.
|
||||||
pub async fn spawn(
|
pub async fn spawn(
|
||||||
|
@ -396,7 +396,7 @@ impl Web3ProxyApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup metrics
|
// setup metrics
|
||||||
let app_metrics = Default::default();
|
// let app_metrics = Default::default();
|
||||||
let open_request_handle_metrics: Arc<OpenRequestHandleMetrics> = Default::default();
|
let open_request_handle_metrics: Arc<OpenRequestHandleMetrics> = Default::default();
|
||||||
|
|
||||||
let mut db_conn = None::<DatabaseConnection>;
|
let mut db_conn = None::<DatabaseConnection>;
|
||||||
|
@ -736,7 +736,7 @@ impl Web3ProxyApp {
|
||||||
db_conn,
|
db_conn,
|
||||||
db_replica,
|
db_replica,
|
||||||
vredis_pool,
|
vredis_pool,
|
||||||
app_metrics,
|
// app_metrics,
|
||||||
open_request_handle_metrics,
|
open_request_handle_metrics,
|
||||||
rpc_secret_key_cache,
|
rpc_secret_key_cache,
|
||||||
bearer_token_semaphores,
|
bearer_token_semaphores,
|
||||||
|
@ -912,7 +912,7 @@ impl Web3ProxyApp {
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct CombinedMetrics<'a> {
|
struct CombinedMetrics<'a> {
|
||||||
app: &'a Web3ProxyAppMetrics,
|
// app: &'a Web3ProxyAppMetrics,
|
||||||
backend_rpc: &'a OpenRequestHandleMetrics,
|
backend_rpc: &'a OpenRequestHandleMetrics,
|
||||||
recent_ip_counts: RecentCounts,
|
recent_ip_counts: RecentCounts,
|
||||||
recent_user_id_counts: RecentCounts,
|
recent_user_id_counts: RecentCounts,
|
||||||
|
@ -921,7 +921,7 @@ impl Web3ProxyApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
let metrics = CombinedMetrics {
|
let metrics = CombinedMetrics {
|
||||||
app: &self.app_metrics,
|
// app: &self.app_metrics,
|
||||||
backend_rpc: &self.open_request_handle_metrics,
|
backend_rpc: &self.open_request_handle_metrics,
|
||||||
recent_ip_counts,
|
recent_ip_counts,
|
||||||
recent_user_id_counts,
|
recent_user_id_counts,
|
||||||
|
@ -979,7 +979,8 @@ impl Web3ProxyApp {
|
||||||
authorization: &Arc<Authorization>,
|
authorization: &Arc<Authorization>,
|
||||||
requests: Vec<JsonRpcRequest>,
|
requests: Vec<JsonRpcRequest>,
|
||||||
proxy_mode: ProxyMode,
|
proxy_mode: ProxyMode,
|
||||||
) -> anyhow::Result<(Vec<JsonRpcForwardedResponse>, Vec<Arc<Web3Connection>>)> {
|
) -> Result<(Vec<JsonRpcForwardedResponse>, Vec<Arc<Web3Connection>>), FrontendErrorResponse>
|
||||||
|
{
|
||||||
// TODO: we should probably change ethers-rs to support this directly. they pushed this off to v2 though
|
// TODO: we should probably change ethers-rs to support this directly. they pushed this off to v2 though
|
||||||
let num_requests = requests.len();
|
let num_requests = requests.len();
|
||||||
|
|
||||||
|
@ -1031,13 +1032,13 @@ impl Web3ProxyApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[measure([ErrorCount, HitCount, ResponseTime, Throughput])]
|
// #[measure([ErrorCount, HitCount, ResponseTime, Throughput])]
|
||||||
async fn proxy_cached_request(
|
async fn proxy_cached_request(
|
||||||
self: &Arc<Self>,
|
self: &Arc<Self>,
|
||||||
authorization: &Arc<Authorization>,
|
authorization: &Arc<Authorization>,
|
||||||
mut request: JsonRpcRequest,
|
mut request: JsonRpcRequest,
|
||||||
proxy_mode: ProxyMode,
|
proxy_mode: ProxyMode,
|
||||||
) -> anyhow::Result<(JsonRpcForwardedResponse, Vec<Arc<Web3Connection>>)> {
|
) -> Result<(JsonRpcForwardedResponse, Vec<Arc<Web3Connection>>), FrontendErrorResponse> {
|
||||||
// trace!("Received request: {:?}", request);
|
// trace!("Received request: {:?}", request);
|
||||||
|
|
||||||
let request_metadata = Arc::new(RequestMetadata::new(REQUEST_PERIOD, request.num_bytes())?);
|
let request_metadata = Arc::new(RequestMetadata::new(REQUEST_PERIOD, request.num_bytes())?);
|
||||||
|
@ -1051,13 +1052,7 @@ impl Web3ProxyApp {
|
||||||
// TODO: don't clone?
|
// TODO: don't clone?
|
||||||
let partial_response: serde_json::Value = match request_method.as_ref() {
|
let partial_response: serde_json::Value = match request_method.as_ref() {
|
||||||
// lots of commands are blocked
|
// lots of commands are blocked
|
||||||
method @ ("admin_addPeer"
|
method @ ("db_getHex"
|
||||||
| "admin_datadir"
|
|
||||||
| "admin_startRPC"
|
|
||||||
| "admin_startWS"
|
|
||||||
| "admin_stopRPC"
|
|
||||||
| "admin_stopWS"
|
|
||||||
| "db_getHex"
|
|
||||||
| "db_getString"
|
| "db_getString"
|
||||||
| "db_putHex"
|
| "db_putHex"
|
||||||
| "db_putString"
|
| "db_putString"
|
||||||
|
@ -1157,9 +1152,10 @@ impl Web3ProxyApp {
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// TODO: what does geth do if this happens?
|
// TODO: what does geth do if this happens?
|
||||||
return Err(anyhow::anyhow!(
|
// TODO: i think we want a 502 so that haproxy retries on another server
|
||||||
"no servers synced. unknown eth_blockNumber"
|
return Err(
|
||||||
));
|
anyhow::anyhow!("no servers synced. unknown eth_blockNumber").into(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1395,12 +1391,16 @@ impl Web3ProxyApp {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: don't return with ? here. send a jsonrpc invalid request
|
|
||||||
let param = Bytes::from_str(
|
let param = Bytes::from_str(
|
||||||
params[0]
|
params[0]
|
||||||
.as_str()
|
.as_str()
|
||||||
.context("parsing params 0 into str then bytes")?,
|
.context("parsing params 0 into str then bytes")?,
|
||||||
)?;
|
)
|
||||||
|
.map_err(|x| {
|
||||||
|
FrontendErrorResponse::BadRequest(
|
||||||
|
"param 0 could not be read as H256".to_string(),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
let hash = H256::from(keccak256(param));
|
let hash = H256::from(keccak256(param));
|
||||||
|
|
||||||
|
@ -1432,6 +1432,11 @@ impl Web3ProxyApp {
|
||||||
}
|
}
|
||||||
// anything else gets sent to backend rpcs and cached
|
// anything else gets sent to backend rpcs and cached
|
||||||
method => {
|
method => {
|
||||||
|
if method.starts_with("admin_") {
|
||||||
|
// TODO: emit a stat? will probably just be noise
|
||||||
|
return Err(FrontendErrorResponse::AccessDenied);
|
||||||
|
}
|
||||||
|
|
||||||
// emit stats
|
// emit stats
|
||||||
|
|
||||||
// TODO: if no servers synced, wait for them to be synced? probably better to error and let haproxy retry another server
|
// TODO: if no servers synced, wait for them to be synced? probably better to error and let haproxy retry another server
|
||||||
|
|
|
@ -11,7 +11,7 @@ use axum::{
|
||||||
use derive_more::From;
|
use derive_more::From;
|
||||||
use http::header::InvalidHeaderValue;
|
use http::header::InvalidHeaderValue;
|
||||||
use ipnet::AddrParseError;
|
use ipnet::AddrParseError;
|
||||||
use log::{trace, warn};
|
use log::{debug, trace, warn};
|
||||||
use migration::sea_orm::DbErr;
|
use migration::sea_orm::DbErr;
|
||||||
use redis_rate_limiter::redis::RedisError;
|
use redis_rate_limiter::redis::RedisError;
|
||||||
use reqwest::header::ToStrError;
|
use reqwest::header::ToStrError;
|
||||||
|
@ -25,6 +25,7 @@ pub type FrontendResult = Result<Response, FrontendErrorResponse>;
|
||||||
pub enum FrontendErrorResponse {
|
pub enum FrontendErrorResponse {
|
||||||
AccessDenied,
|
AccessDenied,
|
||||||
Anyhow(anyhow::Error),
|
Anyhow(anyhow::Error),
|
||||||
|
BadRequest(String),
|
||||||
SemaphoreAcquireError(AcquireError),
|
SemaphoreAcquireError(AcquireError),
|
||||||
Database(DbErr),
|
Database(DbErr),
|
||||||
HeadersError(headers::Error),
|
HeadersError(headers::Error),
|
||||||
|
@ -71,18 +72,17 @@ impl FrontendErrorResponse {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// Self::(err) => {
|
Self::BadRequest(err) => {
|
||||||
// warn!("boxed err={:?}", err);
|
debug!("BAD_REQUEST: {}", err);
|
||||||
// (
|
(
|
||||||
// StatusCode::INTERNAL_SERVER_ERROR,
|
StatusCode::BAD_REQUEST,
|
||||||
// JsonRpcForwardedResponse::from_str(
|
JsonRpcForwardedResponse::from_str(
|
||||||
// // TODO: make this better. maybe include the error type?
|
&format!("bad request: {}", err),
|
||||||
// "boxed error!",
|
Some(StatusCode::BAD_REQUEST.as_u16().into()),
|
||||||
// Some(StatusCode::INTERNAL_SERVER_ERROR.as_u16().into()),
|
None,
|
||||||
// None,
|
),
|
||||||
// ),
|
)
|
||||||
// )
|
}
|
||||||
// }
|
|
||||||
Self::Database(err) => {
|
Self::Database(err) => {
|
||||||
warn!("database err={:?}", err);
|
warn!("database err={:?}", err);
|
||||||
(
|
(
|
||||||
|
|
Loading…
Reference in New Issue