feat(rpc): limit block_range by 100_000 per eth_getLogs request (#5243)

Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
Co-authored-by: Alexey Shekhirin <a.shekhirin@gmail.com>
This commit is contained in:
kaliubuntu0206
2023-11-02 23:29:03 +09:00
committed by GitHub
parent 24fade37ec
commit 0449c5eca6
9 changed files with 200 additions and 29 deletions

View File

@ -31,7 +31,7 @@ pub use stage_args::StageEnum;
mod gas_price_oracle_args;
pub use gas_price_oracle_args::GasPriceOracleArgs;
/// TxPoolArgs for congiguring the transaction pool
/// TxPoolArgs for configuring the transaction pool
mod txpool_args;
pub use txpool_args::TxPoolArgs;
@ -44,3 +44,5 @@ mod pruning_args;
pub use pruning_args::PruningArgs;
pub mod utils;
pub mod types;

View File

@ -1,7 +1,7 @@
//! clap [Args](clap::Args) for RPC related arguments.
use crate::{
args::GasPriceOracleArgs,
args::{types::ZeroAsNone, GasPriceOracleArgs},
cli::{
components::{RethNodeComponents, RethRpcComponents, RethRpcServerHandles},
config::RethRpcConfig,
@ -140,9 +140,13 @@ pub struct RpcServerArgs {
#[arg(long, value_name = "COUNT", default_value_t = constants::DEFAULT_MAX_TRACING_REQUESTS)]
pub rpc_max_tracing_requests: u32,
/// Maximum number of logs that can be returned in a single response.
#[arg(long, value_name = "COUNT", default_value_t = constants::DEFAULT_MAX_LOGS_PER_RESPONSE)]
pub rpc_max_logs_per_response: usize,
/// Maximum number of blocks that could be scanned per filter request. (0 = entire chain)
#[arg(long, value_name = "COUNT", default_value_t = ZeroAsNone::new(constants::DEFAULT_MAX_BLOCKS_PER_FILTER))]
pub rpc_max_blocks_per_filter: ZeroAsNone,
/// Maximum number of logs that can be returned in a single response. (0 = no limit)
#[arg(long, value_name = "COUNT", default_value_t = ZeroAsNone::new(constants::DEFAULT_MAX_LOGS_PER_RESPONSE as u64))]
pub rpc_max_logs_per_response: ZeroAsNone,
/// Maximum gas limit for `eth_call` and call tracing RPC methods.
#[arg(
@ -326,7 +330,8 @@ impl RethRpcConfig for RpcServerArgs {
fn eth_config(&self) -> EthConfig {
EthConfig::default()
.max_tracing_requests(self.rpc_max_tracing_requests)
.max_logs_per_response(self.rpc_max_logs_per_response)
.max_blocks_per_filter(self.rpc_max_blocks_per_filter.unwrap_or_max())
.max_logs_per_response(self.rpc_max_logs_per_response.unwrap_or_max() as usize)
.rpc_gas_cap(self.rpc_gas_cap)
.gpo_config(self.gas_price_oracle_config())
}
@ -598,4 +603,36 @@ mod tests {
);
assert_eq!(config.ipc_endpoint().unwrap().path(), constants::DEFAULT_IPC_ENDPOINT);
}
#[test]
fn test_zero_filter_limits() {
let args = CommandParser::<RpcServerArgs>::parse_from([
"reth",
"--rpc-max-blocks-per-filter",
"0",
"--rpc-max-logs-per-response",
"0",
])
.args;
let config = args.eth_config().filter_config();
assert_eq!(config.max_blocks_per_filter, Some(u64::MAX));
assert_eq!(config.max_logs_per_response, Some(usize::MAX));
}
#[test]
fn test_custom_filter_limits() {
let args = CommandParser::<RpcServerArgs>::parse_from([
"reth",
"--rpc-max-blocks-per-filter",
"100",
"--rpc-max-logs-per-response",
"200",
])
.args;
let config = args.eth_config().filter_config();
assert_eq!(config.max_blocks_per_filter, Some(100));
assert_eq!(config.max_logs_per_response, Some(200));
}
}

View File

@ -0,0 +1,49 @@
//! Additional helper types for CLI parsing.
use std::{fmt, str::FromStr};
/// A helper type that maps `0` to `None` when parsing CLI arguments.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ZeroAsNone(pub Option<u64>);
impl ZeroAsNone {
/// Returns the inner value.
pub const fn new(value: u64) -> Self {
Self(Some(value))
}
/// Returns the inner value or `u64::MAX` if `None`.
pub fn unwrap_or_max(self) -> u64 {
self.0.unwrap_or(u64::MAX)
}
}
impl fmt::Display for ZeroAsNone {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {
Some(value) => write!(f, "{}", value),
None => write!(f, "0"),
}
}
}
impl FromStr for ZeroAsNone {
type Err = std::num::ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let value = s.parse::<u64>()?;
Ok(Self(if value == 0 { None } else { Some(value) }))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_zero_parse() {
let val = "0".parse::<ZeroAsNone>().unwrap();
assert_eq!(val, ZeroAsNone(None));
assert_eq!(val.unwrap_or_max(), u64::MAX);
}
}