feat(bin, prune): pass prune segments from CLI & refactor modes (#4964)

This commit is contained in:
Alexey Shekhirin
2023-10-12 14:49:28 +03:00
committed by GitHub
parent d2a967d4b5
commit 2dbd142d60
27 changed files with 395 additions and 332 deletions

View File

@@ -53,7 +53,7 @@ impl ReceiptsLogPruneConfig {
// Reminder, that we increment because the [`BlockNumber`] key of the new map should be
// viewed as `PruneMode::Before(block)`
let block = (pruned_block + 1).max(
mode.prune_target_block(tip, MINIMUM_PRUNING_DISTANCE, PruneSegment::ContractLogs)?
mode.prune_target_block(tip, PruneSegment::ContractLogs)?
.map(|(block, _)| block)
.unwrap_or_default() +
1,
@@ -75,11 +75,9 @@ impl ReceiptsLogPruneConfig {
for (_, mode) in self.0.iter() {
if let PruneMode::Distance(_) = mode {
if let Some((block, _)) = mode.prune_target_block(
tip,
MINIMUM_PRUNING_DISTANCE,
PruneSegment::ContractLogs,
)? {
if let Some((block, _)) =
mode.prune_target_block(tip, PruneSegment::ContractLogs)?
{
lowest = Some(lowest.unwrap_or(u64::MAX).min(block));
}
}

View File

@@ -20,17 +20,16 @@ impl PruneMode {
pub fn prune_target_block(
&self,
tip: BlockNumber,
min_blocks: u64,
segment: PruneSegment,
) -> Result<Option<(BlockNumber, PruneMode)>, PruneSegmentError> {
let result = match self {
PruneMode::Full if min_blocks == 0 => Some((tip, *self)),
PruneMode::Full if segment.min_blocks() == 0 => Some((tip, *self)),
PruneMode::Distance(distance) if *distance > tip => None, // Nothing to prune yet
PruneMode::Distance(distance) if *distance >= min_blocks => {
PruneMode::Distance(distance) if *distance >= segment.min_blocks() => {
Some((tip - distance, *self))
}
PruneMode::Before(n) if *n > tip => None, // Nothing to prune yet
PruneMode::Before(n) if tip - n >= min_blocks => Some((n - 1, *self)),
PruneMode::Before(n) if tip - n >= segment.min_blocks() => Some((n - 1, *self)),
_ => return Err(PruneSegmentError::Configuration(segment)),
};
Ok(result)
@@ -72,7 +71,6 @@ mod tests {
#[test]
fn test_prune_target_block() {
let tip = 20000;
let min_blocks = MINIMUM_PRUNING_DISTANCE;
let segment = PruneSegment::Receipts;
let tests = vec![
@@ -80,7 +78,10 @@ mod tests {
(PruneMode::Full, Err(PruneSegmentError::Configuration(segment))),
// Nothing to prune
(PruneMode::Distance(tip + 1), Ok(None)),
(PruneMode::Distance(min_blocks + 1), Ok(Some(tip - (min_blocks + 1)))),
(
PruneMode::Distance(segment.min_blocks() + 1),
Ok(Some(tip - (segment.min_blocks() + 1))),
),
// Nothing to prune
(PruneMode::Before(tip + 1), Ok(None)),
(
@@ -96,7 +97,7 @@ mod tests {
for (index, (mode, expected_result)) in tests.into_iter().enumerate() {
assert_eq!(
mode.prune_target_block(tip, min_blocks, segment),
mode.prune_target_block(tip, segment),
expected_result.map(|r| r.map(|b| (b, mode))),
"Test {} failed",
index + 1,
@@ -105,7 +106,7 @@ mod tests {
// Test for a scenario where there are no minimum blocks and Full can be used
assert_eq!(
PruneMode::Full.prune_target_block(tip, 0, segment),
PruneMode::Full.prune_target_block(tip, PruneSegment::Transactions),
Ok(Some((tip, PruneMode::Full))),
);
}

View File

@@ -1,3 +1,4 @@
use crate::MINIMUM_PRUNING_DISTANCE;
use derive_more::Display;
use reth_codecs::{main_codec, Compact};
use thiserror::Error;
@@ -24,6 +25,20 @@ pub enum PruneSegment {
Transactions,
}
impl PruneSegment {
/// Returns minimum number of blocks to left in the database for this segment.
pub fn min_blocks(&self) -> u64 {
match self {
Self::SenderRecovery | Self::TransactionLookup | Self::Headers | Self::Transactions => {
0
}
Self::Receipts | Self::ContractLogs | Self::AccountHistory | Self::StorageHistory => {
MINIMUM_PRUNING_DISTANCE
}
}
}
}
/// PruneSegment error type.
#[derive(Debug, Error, PartialEq, Eq, Clone)]
pub enum PruneSegmentError {

View File

@@ -1,8 +1,6 @@
use crate::{
prune::PruneSegmentError, serde_helper::deserialize_opt_prune_mode_with_min_blocks,
BlockNumber, PruneMode, PruneSegment, ReceiptsLogPruneConfig,
serde_helper::deserialize_opt_prune_mode_with_min_blocks, PruneMode, ReceiptsLogPruneConfig,
};
use paste::paste;
use serde::{Deserialize, Serialize};
/// Minimum distance from the tip necessary for the node to work correctly:
@@ -44,69 +42,26 @@ pub struct PruneModes {
/// Receipts pruning configuration by retaining only those receipts that contain logs emitted
/// by the specified addresses, discarding others. This setting is overridden by `receipts`.
///
/// The [`BlockNumber`] represents the starting block from which point onwards the receipts are
/// preserved.
/// The [BlockNumber](`crate::BlockNumber`) represents the starting block from which point
/// onwards the receipts are preserved.
pub receipts_log_filter: ReceiptsLogPruneConfig,
}
macro_rules! impl_prune_segments {
($(($segment:ident, $variant:ident, $min_blocks:expr)),+) => {
$(
paste! {
#[doc = concat!(
"Check if ",
stringify!($variant),
" should be pruned at the target block according to the provided tip."
)]
pub fn [<should_prune_ $segment>](&self, block: BlockNumber, tip: BlockNumber) -> bool {
if let Some(mode) = &self.$segment {
return mode.should_prune(block, tip)
}
false
}
}
)+
$(
paste! {
#[doc = concat!(
"Returns block up to which ",
stringify!($variant),
" pruning needs to be done, inclusive, according to the provided tip."
)]
pub fn [<prune_target_block_ $segment>](&self, tip: BlockNumber) -> Result<Option<(BlockNumber, PruneMode)>, PruneSegmentError> {
match self.$segment {
Some(mode) => mode.prune_target_block(tip, $min_blocks.unwrap_or_default(), PruneSegment::$variant),
None => Ok(None)
}
}
}
)+
/// Sets pruning to all targets.
pub fn all() -> Self {
Self {
$(
$segment: Some(PruneMode::Full),
)+
receipts_log_filter: Default::default()
}
}
};
}
impl PruneModes {
/// Sets pruning to no target.
pub fn none() -> Self {
PruneModes::default()
}
impl_prune_segments!(
(sender_recovery, SenderRecovery, None),
(transaction_lookup, TransactionLookup, None),
(receipts, Receipts, Some(MINIMUM_PRUNING_DISTANCE)),
(account_history, AccountHistory, Some(MINIMUM_PRUNING_DISTANCE)),
(storage_history, StorageHistory, Some(MINIMUM_PRUNING_DISTANCE))
);
/// Sets pruning to all targets.
pub fn all() -> Self {
Self {
sender_recovery: Some(PruneMode::Full),
transaction_lookup: Some(PruneMode::Full),
receipts: Some(PruneMode::Full),
account_history: Some(PruneMode::Full),
storage_history: Some(PruneMode::Full),
receipts_log_filter: Default::default(),
}
}
}