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
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 15 additions & 8 deletions crates/config/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub struct Config {

impl Config {
/// Sets the pruning configuration.
pub const fn set_prune_config(&mut self, prune_config: PruneConfig) {
pub fn set_prune_config(&mut self, prune_config: PruneConfig) {
self.prune = prune_config;
}
}
Expand Down Expand Up @@ -458,7 +458,6 @@ impl PruneConfig {
/// Merges another `PruneConfig` into this one, taking values from the other config if and only
/// if the corresponding value in this config is not set.
pub fn merge(&mut self, other: Self) {
#[expect(deprecated)]
let Self {
block_interval,
segments:
Expand All @@ -470,7 +469,7 @@ impl PruneConfig {
storage_history,
bodies_history,
merkle_changesets,
receipts_log_filter: (),
receipts_log_filter,
},
} = other;

Expand All @@ -488,6 +487,9 @@ impl PruneConfig {
self.segments.bodies_history = self.segments.bodies_history.or(bodies_history);
// Merkle changesets is not optional, so we just replace it if provided
self.segments.merkle_changesets = merkle_changesets;
if self.segments.receipts_log_filter.0.is_empty() && !receipts_log_filter.0.is_empty() {
self.segments.receipts_log_filter = receipts_log_filter;
}
}
}

Expand All @@ -514,9 +516,10 @@ where
mod tests {
use super::{Config, EXTENSION};
use crate::PruneConfig;
use alloy_primitives::Address;
use reth_network_peers::TrustedPeer;
use reth_prune_types::{PruneMode, PruneModes};
use std::{path::Path, str::FromStr, time::Duration};
use std::{collections::BTreeMap, path::Path, str::FromStr, time::Duration};

fn with_tempdir(filename: &str, proc: fn(&std::path::Path)) {
let temp_dir = tempfile::tempdir().unwrap();
Expand Down Expand Up @@ -1005,8 +1008,7 @@ receipts = 'full'
storage_history: Some(PruneMode::Before(5000)),
bodies_history: None,
merkle_changesets: PruneMode::Before(0),
#[expect(deprecated)]
receipts_log_filter: (),
receipts_log_filter: BTreeMap::from([(Address::random(), PruneMode::Full)]).into(),
},
};

Expand All @@ -1020,11 +1022,15 @@ receipts = 'full'
storage_history: Some(PruneMode::Distance(3000)),
bodies_history: None,
merkle_changesets: PruneMode::Distance(10000),
#[expect(deprecated)]
receipts_log_filter: (),
receipts_log_filter: BTreeMap::from([
(Address::random(), PruneMode::Distance(1000)),
(Address::random(), PruneMode::Before(2000)),
])
.into(),
},
};

let original_receipts_log_filter = config1.segments.receipts_log_filter.clone();
config1.merge(config2);

// Check that the configuration has been merged. Any configuration present in config1
Expand All @@ -1036,6 +1042,7 @@ receipts = 'full'
assert_eq!(config1.segments.account_history, Some(PruneMode::Distance(2000)));
assert_eq!(config1.segments.storage_history, Some(PruneMode::Before(5000)));
assert_eq!(config1.segments.merkle_changesets, PruneMode::Distance(10000));
assert_eq!(config1.segments.receipts_log_filter, original_receipts_log_filter);
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion crates/exex/exex/src/backfill/factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ impl<E, P> BackfillJobFactory<E, P> {
}

/// Sets the prune modes
pub const fn with_prune_modes(mut self, prune_modes: PruneModes) -> Self {
pub fn with_prune_modes(mut self, prune_modes: PruneModes) -> Self {
self.prune_modes = prune_modes;
self
}
Expand Down
1 change: 0 additions & 1 deletion crates/node/builder/src/launch/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1172,7 +1172,6 @@ mod tests {
storage_history_before: None,
bodies_pre_merge: false,
bodies_distance: None,
#[expect(deprecated)]
receipts_log_filter: None,
bodies_before: None,
},
Expand Down
7 changes: 4 additions & 3 deletions crates/node/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,15 @@ alloy-consensus.workspace = true
alloy-eips.workspace = true

# misc
eyre.workspace = true
clap = { workspace = true, features = ["derive", "env"] }
derive_more.workspace = true
eyre.workspace = true
humantime.workspace = true
rand.workspace = true
derive_more.workspace = true
toml.workspace = true
serde.workspace = true
strum = { workspace = true, features = ["derive"] }
thiserror.workspace = true
toml.workspace = true
url.workspace = true

# io
Expand Down
206 changes: 185 additions & 21 deletions crates/node/core/src/args/pruning.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
//! Pruning and full node arguments

use std::ops::Not;
use std::{num::ParseIntError, ops::Not};

use crate::primitives::EthereumHardfork;
use alloy_primitives::BlockNumber;
use alloy_primitives::{Address, BlockNumber};
use clap::{builder::RangedU64ValueParser, Args};
use reth_chainspec::EthereumHardforks;
use reth_config::config::PruneConfig;
use reth_prune_types::{PruneMode, PruneModes, MINIMUM_PRUNING_DISTANCE};
use reth_prune_types::{
PruneMode, PruneModes, PruneSegmentError, ReceiptsLogPruneConfig, MINIMUM_PRUNING_DISTANCE,
};

/// Parameters for pruning and full node
#[derive(Debug, Clone, Args, PartialEq, Eq, Default)]
Expand Down Expand Up @@ -61,14 +63,8 @@ pub struct PruningArgs {
#[arg(long = "prune.receipts.before", value_name = "BLOCK_NUMBER", conflicts_with_all = &["receipts_full", "receipts_pre_merge", "receipts_distance"])]
pub receipts_before: Option<BlockNumber>,
/// Receipts Log Filter
#[arg(
long = "prune.receipts-log-filter",
alias = "prune.receiptslogfilter",
value_name = "FILTER_CONFIG",
hide = true
)]
#[deprecated]
pub receipts_log_filter: Option<String>,
#[arg(long = "prune.receiptslogfilter", value_name = "FILTER_CONFIG", conflicts_with_all = &["receipts_full", "receipts_pre_merge", "receipts_distance", "receipts_before"], value_parser = parse_receipts_log_filter)]
pub receipts_log_filter: Option<ReceiptsLogPruneConfig>,

// Account History
/// Prunes all account history.
Expand Down Expand Up @@ -136,8 +132,7 @@ impl PruningArgs {
.block_number()
.map(PruneMode::Before),
merkle_changesets: PruneMode::Distance(MINIMUM_PRUNING_DISTANCE),
#[expect(deprecated)]
receipts_log_filter: (),
receipts_log_filter: ReceiptsLogPruneConfig::new(),
},
}
}
Expand All @@ -164,14 +159,13 @@ impl PruningArgs {
if let Some(mode) = self.storage_history_prune_mode() {
config.segments.storage_history = Some(mode);
}

// Log warning if receipts_log_filter is set (deprecated feature)
#[expect(deprecated)]
if self.receipts_log_filter.is_some() {
tracing::warn!(
target: "reth::cli",
"The --prune.receiptslogfilter flag is deprecated and has no effect. It will be removed in a future release."
);
if let Some(receipt_logs) =
self.receipts_log_filter.as_ref().filter(|c| !c.is_empty()).cloned()
{
config.segments.receipts_log_filter = receipt_logs;
// need to remove the receipts segment filter entirely because that takes precedence
// over the logs filter
config.segments.receipts.take();
}

config.is_default().not().then_some(config)
Expand Down Expand Up @@ -259,3 +253,173 @@ impl PruningArgs {
}
}
}

/// Error while parsing a `[ReceiptsLogPruneConfig`]
#[derive(thiserror::Error, Debug)]
pub(crate) enum ReceiptsLogError {
/// The format of the filter is invalid.
#[error("invalid filter format: {0}")]
InvalidFilterFormat(String),
/// Address is invalid.
#[error("address is invalid: {0}")]
InvalidAddress(String),
/// The prune mode is not one of full, distance, before.
#[error("prune mode is invalid: {0}")]
InvalidPruneMode(String),
/// The distance value supplied is invalid.
#[error("distance is invalid: {0}")]
InvalidDistance(ParseIntError),
/// The block number supplied is invalid.
#[error("block number is invalid: {0}")]
InvalidBlockNumber(ParseIntError),
#[error(transparent)]
PruneSegment(#[from] PruneSegmentError),
}

/// Parses `,` separated pruning info into [`ReceiptsLogPruneConfig`].
pub(crate) fn parse_receipts_log_filter(
value: &str,
) -> Result<ReceiptsLogPruneConfig, ReceiptsLogError> {
let mut config = ReceiptsLogPruneConfig::new();
// Split out each of the filters.
let filters = value.split(',');
for filter in filters {
let parts: Vec<&str> = filter.split(':').collect();
if parts.len() < 2 {
return Err(ReceiptsLogError::InvalidFilterFormat(filter.to_string()));
}
// Parse the address
let address = parts[0]
.parse::<Address>()
.map_err(|_| ReceiptsLogError::InvalidAddress(parts[0].to_string()))?;

// Parse the prune mode
let prune_mode = match parts[1] {
"full" => PruneMode::Full,
s if s.starts_with("distance") => {
if parts.len() < 3 {
return Err(ReceiptsLogError::InvalidFilterFormat(filter.to_string()));
}
let distance =
parts[2].parse::<u64>().map_err(ReceiptsLogError::InvalidDistance)?;
PruneMode::Distance(distance)
}
s if s.starts_with("before") => {
if parts.len() < 3 {
return Err(ReceiptsLogError::InvalidFilterFormat(filter.to_string()));
}
let block_number =
parts[2].parse::<u64>().map_err(ReceiptsLogError::InvalidBlockNumber)?;
PruneMode::Before(block_number)
}
_ => return Err(ReceiptsLogError::InvalidPruneMode(parts[1].to_string())),
};
config.insert(address, prune_mode);
}

let errors = config.validate_and_fix();
for error in errors {
reth_tracing::tracing::warn!("Receipt log pruning CLI arguments error: {}", error);
}

Ok(config)
}

#[cfg(test)]
mod tests {
use std::collections::BTreeMap;

use super::*;
use alloy_primitives::address;
use clap::Parser;

/// A helper type to parse Args more easily
#[derive(Parser)]
struct CommandParser<T: Args> {
#[command(flatten)]
args: T,
}

#[test]
fn pruning_args_sanity_check() {
let args = CommandParser::<PruningArgs>::parse_from([
"reth",
"--prune.receiptslogfilter",
"0x0000000000000000000000000000000000000003:before:5000000",
])
.args;
let mut config = ReceiptsLogPruneConfig::default();
config.insert(
address!("0x0000000000000000000000000000000000000003"),
PruneMode::Before(5000000),
);
assert_eq!(args.receipts_log_filter, Some(config));
}

#[test]
fn parse_receiptslogfilter() {
let default_args = PruningArgs::default();
let args = CommandParser::<PruningArgs>::parse_from(["reth"]).args;
assert_eq!(args, default_args);
}

#[test]
fn test_parse_receipts_log_filter() {
let addr1 = address!("0x0000000000000000000000000000000000000001");
let addr2 = address!("0x0000000000000000000000000000000000000002");
let addr3 = address!("0x0000000000000000000000000000000000000003");

let filters = [
format!("{addr1}:full"),
format!("{addr2}:distance:1000"),
format!("{addr3}:before:5000000"),
]
.join(",");

// Args can be parsed.
let result = parse_receipts_log_filter(&filters);
assert!(result.is_ok());
let config = result.unwrap();

// Check that the args were parsed correctly.
assert_eq!(
config,
BTreeMap::from([(addr1, PruneMode::Full), (addr3, PruneMode::Before(5000000))]).into()
);
}

#[test]
fn test_parse_receipts_log_filter_invalid_filter_format() {
let result = parse_receipts_log_filter("invalid_format");
assert!(matches!(result, Err(ReceiptsLogError::InvalidFilterFormat(_))));
}

#[test]
fn test_parse_receipts_log_filter_invalid_address() {
let result = parse_receipts_log_filter("invalid_address:full");
assert!(matches!(result, Err(ReceiptsLogError::InvalidAddress(_))));
}

#[test]
fn test_parse_receipts_log_filter_invalid_prune_mode() {
let result =
parse_receipts_log_filter("0x0000000000000000000000000000000000000000:invalid_mode");
assert!(matches!(result, Err(ReceiptsLogError::InvalidPruneMode(_))));
}

#[test]
fn test_parse_receipts_log_filter_invalid_distance() {
let result = parse_receipts_log_filter(
"0x0000000000000000000000000000000000000000:distance:invalid_distance",
);
assert!(matches!(result, Err(ReceiptsLogError::InvalidDistance(_))));
}

#[test]
fn test_parse_receipts_log_filter_invalid_block_number() {
let result = parse_receipts_log_filter(
"0x0000000000000000000000000000000000000000:before:invalid_block",
);
assert!(matches!(result, Err(ReceiptsLogError::InvalidBlockNumber(_))));
}
}
2 changes: 1 addition & 1 deletion crates/prune/prune/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ impl PrunerBuilder {
}

/// Sets the configuration for every part of the data that can be pruned.
pub const fn segments(mut self, segments: PruneModes) -> Self {
pub fn segments(mut self, segments: PruneModes) -> Self {
self.segments = segments;
self
}
Expand Down
Loading
Loading