mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-04-08 03:01:12 -04:00
chore: expose PruneConfig in CLI args (#10639)
Co-authored-by: garwah <garwah@garwah> Co-authored-by: Emilia Hane <elsaemiliaevahane@gmail.com>
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -7673,6 +7673,7 @@ dependencies = [
|
||||
"shellexpand",
|
||||
"strum",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"toml",
|
||||
"tracing",
|
||||
|
||||
55
book/cli/reth/node.md
vendored
55
book/cli/reth/node.md
vendored
@@ -580,7 +580,60 @@ Dev testnet:
|
||||
|
||||
Pruning:
|
||||
--full
|
||||
Run full node. Only the most recent [`MINIMUM_PRUNING_DISTANCE`] block states are stored. This flag takes priority over pruning configuration in reth.toml
|
||||
Run full node. Only the most recent [`MINIMUM_PRUNING_DISTANCE`] block states are stored
|
||||
|
||||
--block-interval <BLOCK_INTERVAL>
|
||||
Minimum pruning interval measured in blocks
|
||||
|
||||
[default: 0]
|
||||
|
||||
--prune.senderrecovery.full
|
||||
Prunes all sender recovery data
|
||||
|
||||
--prune.senderrecovery.distance <BLOCKS>
|
||||
Prune sender recovery data before the `head-N` block number. In other words, keep last N + 1 blocks
|
||||
|
||||
--prune.senderrecovery.before <BLOCK_NUMBER>
|
||||
Prune sender recovery data before the specified block number. The specified block number is not pruned
|
||||
|
||||
--prune.transactionlookup.full
|
||||
Prunes all transaction lookup data
|
||||
|
||||
--prune.transactionlookup.distance <BLOCKS>
|
||||
Prune transaction lookup data before the `head-N` block number. In other words, keep last N + 1 blocks
|
||||
|
||||
--prune.transactionlookup.before <BLOCK_NUMBER>
|
||||
Prune transaction lookup data before the specified block number. The specified block number is not pruned
|
||||
|
||||
--prune.receipts.full
|
||||
Prunes all receipt data
|
||||
|
||||
--prune.receipts.distance <BLOCKS>
|
||||
Prune receipts before the `head-N` block number. In other words, keep last N + 1 blocks
|
||||
|
||||
--prune.receipts.before <BLOCK_NUMBER>
|
||||
Prune receipts before the specified block number. The specified block number is not pruned
|
||||
|
||||
--prune.accounthistory.full
|
||||
Prunes all account history
|
||||
|
||||
--prune.accounthistory.distance <BLOCKS>
|
||||
Prune account before the `head-N` block number. In other words, keep last N + 1 blocks
|
||||
|
||||
--prune.accounthistory.before <BLOCK_NUMBER>
|
||||
Prune account history before the specified block number. The specified block number is not pruned
|
||||
|
||||
--prune.storagehistory.full
|
||||
Prunes all storage history data
|
||||
|
||||
--prune.storagehistory.distance <BLOCKS>
|
||||
Prune storage history before the `head-N` block number. In other words, keep last N + 1 blocks
|
||||
|
||||
--prune.storagehistory.before <BLOCK_NUMBER>
|
||||
Prune storage history before the specified block number. The specified block number is not pruned
|
||||
|
||||
--prune.receiptslogfilter <FILTER_CONFIG>
|
||||
Configure receipts log filter. Format: <`address`>:<`prune_mode`>[,<`address`>:<`prune_mode`>...] Where <`prune_mode`> can be 'full', 'distance:<`blocks`>', or 'before:<`block_number`>'
|
||||
|
||||
Engine:
|
||||
--engine.experimental
|
||||
|
||||
@@ -979,8 +979,29 @@ mod tests {
|
||||
fn test_save_prune_config() {
|
||||
with_tempdir("prune-store-test", |config_path| {
|
||||
let mut reth_config = Config::default();
|
||||
let node_config =
|
||||
NodeConfig { pruning: PruningArgs { full: true }, ..NodeConfig::test() };
|
||||
let node_config = NodeConfig {
|
||||
pruning: PruningArgs {
|
||||
full: true,
|
||||
block_interval: 0,
|
||||
sender_recovery_full: false,
|
||||
sender_recovery_distance: None,
|
||||
sender_recovery_before: None,
|
||||
transaction_lookup_full: false,
|
||||
transaction_lookup_distance: None,
|
||||
transaction_lookup_before: None,
|
||||
receipts_full: false,
|
||||
receipts_distance: None,
|
||||
receipts_before: None,
|
||||
account_history_full: false,
|
||||
account_history_distance: None,
|
||||
account_history_before: None,
|
||||
storage_history_full: false,
|
||||
storage_history_distance: None,
|
||||
storage_history_before: None,
|
||||
receipts_log_filter: vec![],
|
||||
},
|
||||
..NodeConfig::test()
|
||||
};
|
||||
LaunchContext::save_pruning_config_if_full_node(
|
||||
&mut reth_config,
|
||||
&node_config,
|
||||
|
||||
@@ -57,6 +57,7 @@ derive_more.workspace = true
|
||||
toml.workspace = true
|
||||
serde.workspace = true
|
||||
strum = { workspace = true, features = ["derive"] }
|
||||
thiserror.workspace = true
|
||||
|
||||
# io
|
||||
dirs-next = "2.0.0"
|
||||
|
||||
22
crates/node/core/src/args/error.rs
Normal file
22
crates/node/core/src/args/error.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
use std::num::ParseIntError;
|
||||
|
||||
/// Error while parsing a `ReceiptsLogPruneConfig`
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
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),
|
||||
}
|
||||
@@ -58,4 +58,5 @@ pub use benchmark_args::BenchmarkArgs;
|
||||
|
||||
pub mod utils;
|
||||
|
||||
mod error;
|
||||
pub mod types;
|
||||
|
||||
@@ -1,51 +1,250 @@
|
||||
//! Pruning and full node arguments
|
||||
|
||||
use crate::args::error::ReceiptsLogError;
|
||||
use clap::Args;
|
||||
use reth_chainspec::ChainSpec;
|
||||
use reth_config::config::PruneConfig;
|
||||
use reth_primitives::{Address, BlockNumber};
|
||||
use reth_prune_types::{PruneMode, PruneModes, ReceiptsLogPruneConfig, MINIMUM_PRUNING_DISTANCE};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// Parameters for pruning and full node
|
||||
#[derive(Debug, Clone, Args, PartialEq, Eq, Default)]
|
||||
#[command(next_help_heading = "Pruning")]
|
||||
pub struct PruningArgs {
|
||||
/// Run full node. Only the most recent [`MINIMUM_PRUNING_DISTANCE`] block states are stored.
|
||||
/// This flag takes priority over pruning configuration in reth.toml.
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub full: bool,
|
||||
|
||||
/// Minimum pruning interval measured in blocks.
|
||||
#[arg(long, default_value_t = 0)]
|
||||
pub block_interval: u64,
|
||||
|
||||
// Sender Recovery
|
||||
/// Prunes all sender recovery data.
|
||||
#[arg(long = "prune.senderrecovery.full", conflicts_with_all = &["sender_recovery_distance", "sender_recovery_before"])]
|
||||
pub sender_recovery_full: bool,
|
||||
/// Prune sender recovery data before the `head-N` block number. In other words, keep last N +
|
||||
/// 1 blocks.
|
||||
#[arg(long = "prune.senderrecovery.distance", value_name = "BLOCKS", conflicts_with_all = &["sender_recovery_full", "sender_recovery_before"])]
|
||||
pub sender_recovery_distance: Option<u64>,
|
||||
/// Prune sender recovery data before the specified block number. The specified block number is
|
||||
/// not pruned.
|
||||
#[arg(long = "prune.senderrecovery.before", value_name = "BLOCK_NUMBER", conflicts_with_all = &["sender_recovery_full", "sender_recovery_distance"])]
|
||||
pub sender_recovery_before: Option<BlockNumber>,
|
||||
|
||||
// Transaction Lookup
|
||||
/// Prunes all transaction lookup data.
|
||||
#[arg(long = "prune.transactionlookup.full", conflicts_with_all = &["transaction_lookup_distance", "transaction_lookup_before"])]
|
||||
pub transaction_lookup_full: bool,
|
||||
/// Prune transaction lookup data before the `head-N` block number. In other words, keep last N
|
||||
/// + 1 blocks.
|
||||
#[arg(long = "prune.transactionlookup.distance", value_name = "BLOCKS", conflicts_with_all = &["transaction_lookup_full", "transaction_lookup_before"])]
|
||||
pub transaction_lookup_distance: Option<u64>,
|
||||
/// Prune transaction lookup data before the specified block number. The specified block number
|
||||
/// is not pruned.
|
||||
#[arg(long = "prune.transactionlookup.before", value_name = "BLOCK_NUMBER", conflicts_with_all = &["transaction_lookup_full", "transaction_lookup_distance"])]
|
||||
pub transaction_lookup_before: Option<BlockNumber>,
|
||||
|
||||
// Receipts
|
||||
/// Prunes all receipt data.
|
||||
#[arg(long = "prune.receipts.full", conflicts_with_all = &["receipts_distance", "receipts_before"])]
|
||||
pub receipts_full: bool,
|
||||
/// Prune receipts before the `head-N` block number. In other words, keep last N + 1 blocks.
|
||||
#[arg(long = "prune.receipts.distance", value_name = "BLOCKS", conflicts_with_all = &["receipts_full", "receipts_before"])]
|
||||
pub receipts_distance: Option<u64>,
|
||||
/// Prune receipts before the specified block number. The specified block number is not pruned.
|
||||
#[arg(long = "prune.receipts.before", value_name = "BLOCK_NUMBER", conflicts_with_all = &["receipts_full", "receipts_distance"])]
|
||||
pub receipts_before: Option<BlockNumber>,
|
||||
|
||||
// Account History
|
||||
/// Prunes all account history.
|
||||
#[arg(long = "prune.accounthistory.full", conflicts_with_all = &["account_history_distance", "account_history_before"])]
|
||||
pub account_history_full: bool,
|
||||
/// Prune account before the `head-N` block number. In other words, keep last N + 1 blocks.
|
||||
#[arg(long = "prune.accounthistory.distance", value_name = "BLOCKS", conflicts_with_all = &["account_history_full", "account_history_before"])]
|
||||
pub account_history_distance: Option<u64>,
|
||||
/// Prune account history before the specified block number. The specified block number is not
|
||||
/// pruned.
|
||||
#[arg(long = "prune.accounthistory.before", value_name = "BLOCK_NUMBER", conflicts_with_all = &["account_history_full", "account_history_distance"])]
|
||||
pub account_history_before: Option<BlockNumber>,
|
||||
|
||||
// Storage History
|
||||
/// Prunes all storage history data.
|
||||
#[arg(long = "prune.storagehistory.full", conflicts_with_all = &["storage_history_distance", "storage_history_before"])]
|
||||
pub storage_history_full: bool,
|
||||
/// Prune storage history before the `head-N` block number. In other words, keep last N + 1
|
||||
/// blocks.
|
||||
#[arg(long = "prune.storagehistory.distance", value_name = "BLOCKS", conflicts_with_all = &["storage_history_full", "storage_history_before"])]
|
||||
pub storage_history_distance: Option<u64>,
|
||||
/// Prune storage history before the specified block number. The specified block number is not
|
||||
/// pruned.
|
||||
#[arg(long = "prune.storagehistory.before", value_name = "BLOCK_NUMBER", conflicts_with_all = &["storage_history_full", "storage_history_distance"])]
|
||||
pub storage_history_before: Option<BlockNumber>,
|
||||
|
||||
// Receipts Log Filter
|
||||
/// Configure receipts log filter. Format:
|
||||
/// <`address`>:<`prune_mode`>[,<`address`>:<`prune_mode`>...] Where <`prune_mode`> can be
|
||||
/// 'full', 'distance:<`blocks`>', or 'before:<`block_number`>'
|
||||
#[arg(long = "prune.receiptslogfilter", value_name = "FILTER_CONFIG", value_delimiter = ',', value_parser = parse_receipts_log_filter)]
|
||||
pub receipts_log_filter: Vec<String>,
|
||||
}
|
||||
|
||||
impl PruningArgs {
|
||||
/// Returns pruning configuration.
|
||||
pub fn prune_config(&self, chain_spec: &ChainSpec) -> Option<PruneConfig> {
|
||||
if !self.full {
|
||||
return None
|
||||
}
|
||||
// Initialise with a default prune configuration.
|
||||
let mut config = PruneConfig::default();
|
||||
|
||||
Some(PruneConfig {
|
||||
block_interval: 5,
|
||||
segments: PruneModes {
|
||||
sender_recovery: Some(PruneMode::Full),
|
||||
transaction_lookup: None,
|
||||
// prune all receipts if chain doesn't have deposit contract specified in chain spec
|
||||
receipts: chain_spec
|
||||
.deposit_contract
|
||||
.as_ref()
|
||||
.map(|contract| PruneMode::Before(contract.block))
|
||||
.or(Some(PruneMode::Distance(MINIMUM_PRUNING_DISTANCE))),
|
||||
account_history: Some(PruneMode::Distance(MINIMUM_PRUNING_DISTANCE)),
|
||||
storage_history: Some(PruneMode::Distance(MINIMUM_PRUNING_DISTANCE)),
|
||||
receipts_log_filter: ReceiptsLogPruneConfig(
|
||||
chain_spec
|
||||
// If --full is set, use full node defaults.
|
||||
if self.full {
|
||||
config = PruneConfig {
|
||||
block_interval: 5,
|
||||
segments: PruneModes {
|
||||
sender_recovery: Some(PruneMode::Full),
|
||||
transaction_lookup: None,
|
||||
// prune all receipts if chain doesn't have deposit contract specified in chain
|
||||
// spec
|
||||
receipts: chain_spec
|
||||
.deposit_contract
|
||||
.as_ref()
|
||||
.map(|contract| (contract.address, PruneMode::Before(contract.block)))
|
||||
.into_iter()
|
||||
.collect(),
|
||||
),
|
||||
},
|
||||
})
|
||||
.map(|contract| PruneMode::Before(contract.block))
|
||||
.or(Some(PruneMode::Distance(MINIMUM_PRUNING_DISTANCE))),
|
||||
account_history: Some(PruneMode::Distance(MINIMUM_PRUNING_DISTANCE)),
|
||||
storage_history: Some(PruneMode::Distance(MINIMUM_PRUNING_DISTANCE)),
|
||||
receipts_log_filter: ReceiptsLogPruneConfig(
|
||||
chain_spec
|
||||
.deposit_contract
|
||||
.as_ref()
|
||||
.map(|contract| (contract.address, PruneMode::Before(contract.block)))
|
||||
.into_iter()
|
||||
.collect(),
|
||||
),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Override with any explicitly set prune.* flags.
|
||||
if let Some(mode) = self.sender_recovery_prune_mode() {
|
||||
config.segments.sender_recovery = Some(mode);
|
||||
}
|
||||
if let Some(mode) = self.transaction_lookup_prune_mode() {
|
||||
config.segments.transaction_lookup = Some(mode);
|
||||
}
|
||||
if let Some(mode) = self.receipts_prune_mode() {
|
||||
config.segments.receipts = Some(mode);
|
||||
}
|
||||
if let Some(mode) = self.account_history_prune_mode() {
|
||||
config.segments.account_history = Some(mode);
|
||||
}
|
||||
if let Some(mode) = self.storage_history_prune_mode() {
|
||||
config.segments.storage_history = Some(mode);
|
||||
}
|
||||
|
||||
Some(config)
|
||||
}
|
||||
const fn sender_recovery_prune_mode(&self) -> Option<PruneMode> {
|
||||
if self.sender_recovery_full {
|
||||
Some(PruneMode::Full)
|
||||
} else if let Some(distance) = self.sender_recovery_distance {
|
||||
Some(PruneMode::Distance(distance))
|
||||
} else if let Some(block_number) = self.sender_recovery_before {
|
||||
Some(PruneMode::Before(block_number))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
const fn transaction_lookup_prune_mode(&self) -> Option<PruneMode> {
|
||||
if self.transaction_lookup_full {
|
||||
Some(PruneMode::Full)
|
||||
} else if let Some(distance) = self.transaction_lookup_distance {
|
||||
Some(PruneMode::Distance(distance))
|
||||
} else if let Some(block_number) = self.transaction_lookup_before {
|
||||
Some(PruneMode::Before(block_number))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
const fn receipts_prune_mode(&self) -> Option<PruneMode> {
|
||||
if self.receipts_full {
|
||||
Some(PruneMode::Full)
|
||||
} else if let Some(distance) = self.receipts_distance {
|
||||
Some(PruneMode::Distance(distance))
|
||||
} else if let Some(block_number) = self.receipts_before {
|
||||
Some(PruneMode::Before(block_number))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
const fn account_history_prune_mode(&self) -> Option<PruneMode> {
|
||||
if self.account_history_full {
|
||||
Some(PruneMode::Full)
|
||||
} else if let Some(distance) = self.account_history_distance {
|
||||
Some(PruneMode::Distance(distance))
|
||||
} else if let Some(block_number) = self.account_history_before {
|
||||
Some(PruneMode::Before(block_number))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
const fn storage_history_prune_mode(&self) -> Option<PruneMode> {
|
||||
if self.storage_history_full {
|
||||
Some(PruneMode::Full)
|
||||
} else if let Some(distance) = self.storage_history_distance {
|
||||
Some(PruneMode::Distance(distance))
|
||||
} else if let Some(block_number) = self.storage_history_before {
|
||||
Some(PruneMode::Before(block_number))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn parse_receipts_log_filter(
|
||||
value: &str,
|
||||
) -> Result<ReceiptsLogPruneConfig, ReceiptsLogError> {
|
||||
let mut config = BTreeMap::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::<BlockNumber>()
|
||||
.map_err(ReceiptsLogError::InvalidBlockNumber)?;
|
||||
PruneMode::Before(block_number)
|
||||
}
|
||||
_ => return Err(ReceiptsLogError::InvalidPruneMode(parts[1].to_string())),
|
||||
};
|
||||
config.insert(address, prune_mode);
|
||||
}
|
||||
Ok(ReceiptsLogPruneConfig(config))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -66,4 +265,62 @@ mod tests {
|
||||
let args = CommandParser::<PruningArgs>::parse_from(["reth"]).args;
|
||||
assert_eq!(args, default_args);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_receipts_log_filter() {
|
||||
let filter1 = "0x0000000000000000000000000000000000000001:full";
|
||||
let filter2 = "0x0000000000000000000000000000000000000002:distance:1000";
|
||||
let filter3 = "0x0000000000000000000000000000000000000003:before:5000000";
|
||||
let filters = [filter1, filter2, filter3].join(",");
|
||||
|
||||
// Args can be parsed.
|
||||
let result = parse_receipts_log_filter(&filters);
|
||||
assert!(result.is_ok());
|
||||
let config = result.unwrap();
|
||||
assert_eq!(config.0.len(), 3);
|
||||
|
||||
// Check that the args were parsed correctly.
|
||||
let addr1: Address = "0x0000000000000000000000000000000000000001".parse().unwrap();
|
||||
let addr2: Address = "0x0000000000000000000000000000000000000002".parse().unwrap();
|
||||
let addr3: Address = "0x0000000000000000000000000000000000000003".parse().unwrap();
|
||||
|
||||
assert_eq!(config.0.get(&addr1), Some(&PruneMode::Full));
|
||||
assert_eq!(config.0.get(&addr2), Some(&PruneMode::Distance(1000)));
|
||||
assert_eq!(config.0.get(&addr3), Some(&PruneMode::Before(5000000)));
|
||||
}
|
||||
|
||||
#[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(_))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +229,7 @@ impl NodeConfig {
|
||||
}
|
||||
|
||||
/// Set the pruning args for the node
|
||||
pub const fn with_pruning(mut self, pruning: PruningArgs) -> Self {
|
||||
pub fn with_pruning(mut self, pruning: PruningArgs) -> Self {
|
||||
self.pruning = pruning;
|
||||
self
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user