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}