cuprate_txpool/
config.rs

1//! The transaction pool [`Config`].
2use std::{borrow::Cow, path::PathBuf};
3
4#[cfg(feature = "serde")]
5use serde::{Deserialize, Serialize};
6
7use cuprate_database::{
8    config::{Config as DbConfig, SyncMode},
9    resize::ResizeAlgorithm,
10};
11use cuprate_database_service::ReaderThreads;
12use cuprate_helper::{
13    fs::{txpool_path, CUPRATE_DATA_DIR},
14    network::Network,
15};
16
17/// The default transaction pool weight limit.
18const DEFAULT_TXPOOL_WEIGHT_LIMIT: usize = 600 * 1024 * 1024;
19
20//---------------------------------------------------------------------------------------------------- ConfigBuilder
21/// Builder for [`Config`].
22///
23// SOMEDAY: there's are many more options to add in the future.
24#[derive(Debug, Clone, PartialEq, PartialOrd)]
25#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
26pub struct ConfigBuilder {
27    network: Network,
28
29    data_dir: Option<PathBuf>,
30
31    /// [`Config::cuprate_database_config`].
32    db_config: cuprate_database::config::ConfigBuilder,
33
34    /// [`Config::reader_threads`].
35    reader_threads: Option<ReaderThreads>,
36
37    /// [`Config::max_txpool_weight`].
38    max_txpool_weight: Option<usize>,
39}
40
41impl ConfigBuilder {
42    /// Create a new [`ConfigBuilder`].
43    ///
44    /// [`ConfigBuilder::build`] can be called immediately
45    /// after this function to use default values.
46    pub fn new() -> Self {
47        Self {
48            network: Network::default(),
49            data_dir: None,
50            db_config: cuprate_database::config::ConfigBuilder::new(Cow::Owned(txpool_path(
51                &CUPRATE_DATA_DIR,
52                Network::Mainnet,
53            ))),
54            reader_threads: None,
55            max_txpool_weight: None,
56        }
57    }
58
59    /// Build into a [`Config`].
60    ///
61    /// # Default values
62    /// If [`ConfigBuilder::data_directory`] was not called,
63    /// [`txpool_path`] with [`CUPRATE_DATA_DIR`] and [`Network::Mainnet`] will be used.
64    ///
65    /// For all other values, [`Default::default`] is used.
66    pub fn build(self) -> Config {
67        // INVARIANT: all PATH safety checks are done
68        // in `helper::fs`. No need to do them here.
69        let data_dir = self
70            .data_dir
71            .unwrap_or_else(|| CUPRATE_DATA_DIR.to_path_buf());
72
73        let reader_threads = self.reader_threads.unwrap_or_default();
74
75        let max_txpool_weight = self
76            .max_txpool_weight
77            .unwrap_or(DEFAULT_TXPOOL_WEIGHT_LIMIT);
78
79        let db_config = self
80            .db_config
81            .db_directory(Cow::Owned(txpool_path(&data_dir, self.network)))
82            .reader_threads(reader_threads.as_threads())
83            .build();
84
85        Config {
86            db_config,
87            reader_threads,
88            max_txpool_weight,
89        }
90    }
91
92    /// Change the network this database is for.
93    #[must_use]
94    pub const fn network(mut self, network: Network) -> Self {
95        self.network = network;
96        self
97    }
98
99    /// Sets a new maximum weight for the transaction pool.
100    #[must_use]
101    pub const fn max_txpool_weight(mut self, max_txpool_weight: usize) -> Self {
102        self.max_txpool_weight = Some(max_txpool_weight);
103        self
104    }
105
106    /// Set a custom data directory [`PathBuf`].
107    #[must_use]
108    pub fn data_directory(mut self, db_directory: PathBuf) -> Self {
109        self.data_dir = Some(db_directory);
110        self
111    }
112
113    /// Calls [`cuprate_database::config::ConfigBuilder::sync_mode`].
114    #[must_use]
115    pub fn sync_mode(mut self, sync_mode: SyncMode) -> Self {
116        self.db_config = self.db_config.sync_mode(sync_mode);
117        self
118    }
119
120    /// Calls [`cuprate_database::config::ConfigBuilder::resize_algorithm`].
121    #[must_use]
122    pub fn resize_algorithm(mut self, resize_algorithm: ResizeAlgorithm) -> Self {
123        self.db_config = self.db_config.resize_algorithm(resize_algorithm);
124        self
125    }
126
127    /// Set a custom [`ReaderThreads`].
128    #[must_use]
129    pub const fn reader_threads(mut self, reader_threads: ReaderThreads) -> Self {
130        self.reader_threads = Some(reader_threads);
131        self
132    }
133
134    /// Tune the [`ConfigBuilder`] for the highest performing,
135    /// but also most resource-intensive & maybe risky settings.
136    ///
137    /// Good default for testing, and resource-available machines.
138    #[must_use]
139    pub fn fast(mut self) -> Self {
140        self.db_config = self.db_config.fast();
141
142        self.reader_threads = Some(ReaderThreads::OnePerThread);
143        self
144    }
145
146    /// Tune the [`ConfigBuilder`] for the lowest performing,
147    /// but also least resource-intensive settings.
148    ///
149    /// Good default for resource-limited machines, e.g. a cheap VPS.
150    #[must_use]
151    pub fn low_power(mut self) -> Self {
152        self.db_config = self.db_config.low_power();
153
154        self.reader_threads = Some(ReaderThreads::One);
155        self
156    }
157}
158
159impl Default for ConfigBuilder {
160    fn default() -> Self {
161        Self {
162            network: Network::default(),
163            data_dir: Some(CUPRATE_DATA_DIR.to_path_buf()),
164            db_config: cuprate_database::config::ConfigBuilder::new(Cow::Owned(txpool_path(
165                &CUPRATE_DATA_DIR,
166                Network::Mainnet,
167            ))),
168            reader_threads: Some(ReaderThreads::default()),
169            max_txpool_weight: Some(DEFAULT_TXPOOL_WEIGHT_LIMIT),
170        }
171    }
172}
173
174//---------------------------------------------------------------------------------------------------- Config
175/// `cuprate_txpool` configuration.
176///
177/// This is a configuration built on-top of [`DbConfig`].
178///
179/// It contains configuration specific to this crate, plus the database config.
180///
181/// For construction, either use [`ConfigBuilder`] or [`Config::default`].
182#[derive(Debug, Clone, PartialEq, PartialOrd)]
183pub struct Config {
184    /// The database configuration.
185    pub db_config: DbConfig,
186
187    /// Database reader thread count.
188    pub reader_threads: ReaderThreads,
189
190    /// The maximum weight of the transaction pool, after which we will start dropping transactions.
191    // TODO: enforce this max size.
192    pub max_txpool_weight: usize,
193}
194
195impl Config {
196    /// Create a new [`Config`] with sane default settings.
197    ///
198    /// The [`DbConfig::db_directory`]
199    /// will be set to [`txpool_path`] with [`CUPRATE_DATA_DIR`] and [`Network::Mainnet`].
200    ///
201    /// All other values will be [`Default::default`].
202    ///
203    /// Same as [`Config::default`].
204    ///
205    /// ```rust
206    /// use cuprate_database::{
207    ///     config::SyncMode,
208    ///     resize::ResizeAlgorithm,
209    ///     DATABASE_DATA_FILENAME,
210    /// };
211    /// use cuprate_database_service::ReaderThreads;
212    /// use cuprate_helper::{fs::*, network::Network};
213    ///
214    /// use cuprate_txpool::Config;
215    ///
216    /// let config = Config::new();
217    ///
218    /// assert_eq!(config.db_config.db_directory(), txpool_path(&CUPRATE_DATA_DIR, Network::Mainnet).as_path());
219    /// assert!(config.db_config.db_file().starts_with(&*CUPRATE_DATA_DIR));
220    /// assert!(config.db_config.db_file().ends_with(DATABASE_DATA_FILENAME));
221    /// assert_eq!(config.db_config.sync_mode, SyncMode::default());
222    /// assert_eq!(config.db_config.resize_algorithm, ResizeAlgorithm::default());
223    /// assert_eq!(config.reader_threads, ReaderThreads::default());
224    /// ```
225    pub fn new() -> Self {
226        ConfigBuilder::new().build()
227    }
228}
229
230impl Default for Config {
231    /// Same as [`Config::new`].
232    ///
233    /// ```rust
234    /// # use cuprate_txpool::Config;
235    /// assert_eq!(Config::default(), Config::new());
236    /// ```
237    fn default() -> Self {
238        Self::new()
239    }
240}