Skip to main content

reth_prune/
builder.rs

1use crate::{segments::SegmentSet, Pruner};
2use alloy_eips::eip2718::Encodable2718;
3use reth_config::PruneConfig;
4use reth_db_api::{table::Value, transaction::DbTxMut};
5use reth_exex_types::FinishedExExHeight;
6use reth_primitives_traits::NodePrimitives;
7use reth_provider::{
8    providers::StaticFileProvider, BlockReader, ChainStateBlockReader, DBProvider,
9    DatabaseProviderFactory, NodePrimitivesProvider, PruneCheckpointReader, PruneCheckpointWriter,
10    RocksDBProviderFactory, StageCheckpointReader, StaticFileProviderFactory,
11};
12use reth_prune_types::PruneModes;
13use reth_storage_api::{ChangeSetReader, StorageChangeSetReader, StorageSettingsCache};
14use std::time::Duration;
15use tokio::sync::watch;
16
17/// Contains the information required to build a pruner
18#[derive(Debug, Clone)]
19pub struct PrunerBuilder {
20    /// Minimum pruning interval measured in blocks.
21    block_interval: usize,
22    /// Pruning configuration for every part of the data that can be pruned.
23    segments: PruneModes,
24    /// The delete limit for pruner, per run.
25    delete_limit: usize,
26    /// Time a pruner job can run before timing out.
27    timeout: Option<Duration>,
28    /// Optional override for the minimum pruning distance.
29    minimum_pruning_distance: Option<u64>,
30    /// The finished height of all `ExEx`'s.
31    finished_exex_height: watch::Receiver<FinishedExExHeight>,
32}
33
34impl PrunerBuilder {
35    /// Creates a new [`PrunerBuilder`] from the given [`PruneConfig`].
36    pub fn new(pruner_config: PruneConfig) -> Self {
37        let min_distance = pruner_config.minimum_pruning_distance;
38        let mut builder = Self::default()
39            .block_interval(pruner_config.block_interval)
40            .segments(pruner_config.segments);
41        if min_distance != reth_prune_types::MINIMUM_UNWIND_SAFE_DISTANCE {
42            builder.minimum_pruning_distance = Some(min_distance);
43        }
44        builder
45    }
46
47    /// Sets the minimum pruning interval measured in blocks.
48    pub const fn block_interval(mut self, block_interval: usize) -> Self {
49        self.block_interval = block_interval;
50        self
51    }
52
53    /// Sets the configuration for every part of the data that can be pruned.
54    pub fn segments(mut self, segments: PruneModes) -> Self {
55        self.segments = segments;
56        self
57    }
58
59    /// Sets the delete limit for pruner, per run.
60    pub const fn delete_limit(mut self, prune_delete_limit: usize) -> Self {
61        self.delete_limit = prune_delete_limit;
62        self
63    }
64
65    /// Sets the timeout for pruner, per run.
66    ///
67    /// CAUTION: Account and Storage History prune segments treat this timeout as a soft limit,
68    /// meaning they can go beyond it.
69    pub const fn timeout(mut self, timeout: Duration) -> Self {
70        self.timeout = Some(timeout);
71        self
72    }
73
74    /// Sets the receiver for the finished height of all `ExEx`'s.
75    pub fn finished_exex_height(
76        mut self,
77        finished_exex_height: watch::Receiver<FinishedExExHeight>,
78    ) -> Self {
79        self.finished_exex_height = finished_exex_height;
80        self
81    }
82
83    /// Builds a [Pruner] from the current configuration with the given provider factory.
84    pub fn build_with_provider_factory<PF>(self, provider_factory: PF) -> Pruner<PF::ProviderRW, PF>
85    where
86        PF: DatabaseProviderFactory<
87                ProviderRW: PruneCheckpointWriter
88                                + PruneCheckpointReader
89                                + BlockReader<Transaction: Encodable2718>
90                                + ChainStateBlockReader
91                                + StorageSettingsCache
92                                + StageCheckpointReader
93                                + ChangeSetReader
94                                + StorageChangeSetReader
95                                + RocksDBProviderFactory
96                                + StaticFileProviderFactory<
97                    Primitives: NodePrimitives<SignedTx: Value, Receipt: Value, BlockHeader: Value>,
98                >,
99            > + StaticFileProviderFactory<
100                Primitives = <PF::ProviderRW as NodePrimitivesProvider>::Primitives,
101            >,
102    {
103        let segments =
104            SegmentSet::from_components(provider_factory.static_file_provider(), self.segments);
105
106        let mut pruner = Pruner::new_with_factory(
107            provider_factory,
108            segments.into_vec(),
109            self.block_interval,
110            self.delete_limit,
111            self.timeout,
112            self.finished_exex_height,
113        );
114        if let Some(distance) = self.minimum_pruning_distance {
115            pruner = pruner.with_minimum_pruning_distance(distance);
116        }
117        pruner
118    }
119
120    /// Builds a [Pruner] from the current configuration with the given static file provider.
121    pub fn build<Provider>(
122        self,
123        static_file_provider: StaticFileProvider<Provider::Primitives>,
124    ) -> Pruner<Provider, ()>
125    where
126        Provider: StaticFileProviderFactory<
127                Primitives: NodePrimitives<SignedTx: Value, Receipt: Value, BlockHeader: Value>,
128            > + DBProvider<Tx: DbTxMut>
129            + BlockReader<Transaction: Encodable2718>
130            + ChainStateBlockReader
131            + PruneCheckpointWriter
132            + PruneCheckpointReader
133            + StorageSettingsCache
134            + StageCheckpointReader
135            + ChangeSetReader
136            + StorageChangeSetReader
137            + RocksDBProviderFactory,
138    {
139        let segments = SegmentSet::<Provider>::from_components(static_file_provider, self.segments);
140
141        let mut pruner = Pruner::new(
142            segments.into_vec(),
143            self.block_interval,
144            self.delete_limit,
145            self.timeout,
146            self.finished_exex_height,
147        );
148        if let Some(distance) = self.minimum_pruning_distance {
149            pruner = pruner.with_minimum_pruning_distance(distance);
150        }
151        pruner
152    }
153}
154
155impl Default for PrunerBuilder {
156    fn default() -> Self {
157        Self {
158            block_interval: 5,
159            segments: PruneModes::default(),
160            delete_limit: usize::MAX,
161            timeout: None,
162            minimum_pruning_distance: None,
163            finished_exex_height: watch::channel(FinishedExExHeight::NoExExs).1,
164        }
165    }
166}