Skip to main content

reth_prune/
builder.rs

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