Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/gas_limiter/args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use clap::Args;

#[derive(Debug, Clone, Default, PartialEq, Eq, Args)]
pub struct GasLimiterArgs {
/// Enable address-based gas rate limiting
#[arg(long = "gas-limiter.enabled", env)]
pub gas_limiter_enabled: bool,

/// Maximum gas per address in token bucket. Defaults to 10 million gas.
#[arg(
long = "gas-limiter.max-gas-per-address",
env,
default_value = "10000000"
)]
pub max_gas_per_address: u64,

/// Gas refill rate per block. Defaults to 1 million gas per block.
#[arg(
long = "gas-limiter.refill-rate-per-block",
env,
default_value = "1000000"
)]
pub refill_rate_per_block: u64,

/// How many blocks to wait before cleaning up stale buckets for addresses.
#[arg(long = "gas-limiter.cleanup-interval", env, default_value = "100")]
pub cleanup_interval_blocks: u64,
}
13 changes: 13 additions & 0 deletions src/gas_limiter/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use alloy_primitives::Address;

#[derive(Debug, thiserror::Error)]
pub enum GasLimitError {
#[error(
"Address {address} exceeded gas limit: {requested} gwei requested, {available} gwei available"
)]
AddressLimitExceeded {
address: Address,
requested: u64,
available: u64,
},
}
46 changes: 46 additions & 0 deletions src/gas_limiter/metrics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use std::time::Duration;

use metrics::{Counter, Gauge, Histogram};

use crate::prelude::*;
use crate::gas_limiter::error::GasLimitError;

#[derive(MetricsSet)]
pub(super) struct GasLimiterMetrics {
/// Transactions rejected by gas limits Labeled by reason: "per_address",
/// "global", "burst"
pub rejections: Counter,

/// Time spent in rate limiting logic
pub check_time: Histogram,

/// Number of addresses with active budgets
pub active_address_count: Gauge,

/// Time to refill buckets
pub refresh_duration: Histogram,
}

impl GasLimiterMetrics {
pub(super) fn record_gas_check(
&self,
check_result: &Result<bool, GasLimitError>,
duration: Duration,
) {
if let Ok(created_new_bucket) = check_result {
if *created_new_bucket {
self.active_address_count.increment(1);
}
} else {
self.rejections.increment(1);
}

self.check_time.record(duration);
}

pub(super) fn record_refresh(&self, removed_addresses: usize, duration: Duration) {
self.active_address_count
.decrement(removed_addresses as f64);
self.refresh_duration.record(duration);
}
}
Loading
Loading