reth_node_core/args/
txpool.rs

1//! Transaction pool arguments
2
3use crate::cli::config::RethTransactionPoolConfig;
4use alloy_eips::eip1559::{ETHEREUM_BLOCK_GAS_LIMIT_30M, MIN_PROTOCOL_BASE_FEE};
5use alloy_primitives::Address;
6use clap::{builder::Resettable, Args};
7use reth_cli_util::{parse_duration_from_secs_or_ms, parsers::format_duration_as_secs_or_ms};
8use reth_transaction_pool::{
9    blobstore::disk::DEFAULT_MAX_CACHED_BLOBS,
10    maintain::MAX_QUEUED_TRANSACTION_LIFETIME,
11    pool::{NEW_TX_LISTENER_BUFFER_SIZE, PENDING_TX_LISTENER_BUFFER_SIZE},
12    validate::DEFAULT_MAX_TX_INPUT_BYTES,
13    LocalTransactionConfig, PoolConfig, PriceBumpConfig, SubPoolLimit, DEFAULT_PRICE_BUMP,
14    DEFAULT_TXPOOL_ADDITIONAL_VALIDATION_TASKS, MAX_NEW_PENDING_TXS_NOTIFICATIONS,
15    REPLACE_BLOB_PRICE_BUMP, TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER,
16    TXPOOL_SUBPOOL_MAX_SIZE_MB_DEFAULT, TXPOOL_SUBPOOL_MAX_TXS_DEFAULT,
17};
18use std::{path::PathBuf, sync::OnceLock, time::Duration};
19
20/// Global static transaction pool defaults
21static TXPOOL_DEFAULTS: OnceLock<DefaultTxPoolValues> = OnceLock::new();
22
23/// Default values for transaction pool that can be customized
24///
25/// Global defaults can be set via [`DefaultTxPoolValues::try_init`].
26#[derive(Debug, Clone)]
27pub struct DefaultTxPoolValues {
28    pending_max_count: usize,
29    pending_max_size: usize,
30    basefee_max_count: usize,
31    basefee_max_size: usize,
32    queued_max_count: usize,
33    queued_max_size: usize,
34    blobpool_max_count: usize,
35    blobpool_max_size: usize,
36    blob_cache_size: Option<u32>,
37    disable_blobs_support: bool,
38    max_account_slots: usize,
39    price_bump: u128,
40    minimal_protocol_basefee: u64,
41    minimum_priority_fee: Option<u128>,
42    enforced_gas_limit: u64,
43    max_tx_gas_limit: Option<u64>,
44    blob_transaction_price_bump: u128,
45    max_tx_input_bytes: usize,
46    max_cached_entries: u32,
47    no_locals: bool,
48    locals: Vec<Address>,
49    no_local_transactions_propagation: bool,
50    additional_validation_tasks: usize,
51    pending_tx_listener_buffer_size: usize,
52    new_tx_listener_buffer_size: usize,
53    max_new_pending_txs_notifications: usize,
54    max_queued_lifetime: Duration,
55    transactions_backup_path: Option<PathBuf>,
56    disable_transactions_backup: bool,
57    max_batch_size: usize,
58}
59
60impl DefaultTxPoolValues {
61    /// Initialize the global transaction pool defaults with this configuration
62    pub fn try_init(self) -> Result<(), Self> {
63        TXPOOL_DEFAULTS.set(self)
64    }
65
66    /// Get a reference to the global transaction pool defaults
67    pub fn get_global() -> &'static Self {
68        TXPOOL_DEFAULTS.get_or_init(Self::default)
69    }
70
71    /// Set the default pending sub-pool max transaction count
72    pub const fn with_pending_max_count(mut self, v: usize) -> Self {
73        self.pending_max_count = v;
74        self
75    }
76
77    /// Set the default pending sub-pool max size in MB
78    pub const fn with_pending_max_size(mut self, v: usize) -> Self {
79        self.pending_max_size = v;
80        self
81    }
82
83    /// Set the default basefee sub-pool max transaction count
84    pub const fn with_basefee_max_count(mut self, v: usize) -> Self {
85        self.basefee_max_count = v;
86        self
87    }
88
89    /// Set the default basefee sub-pool max size in MB
90    pub const fn with_basefee_max_size(mut self, v: usize) -> Self {
91        self.basefee_max_size = v;
92        self
93    }
94
95    /// Set the default queued sub-pool max transaction count
96    pub const fn with_queued_max_count(mut self, v: usize) -> Self {
97        self.queued_max_count = v;
98        self
99    }
100
101    /// Set the default queued sub-pool max size in MB
102    pub const fn with_queued_max_size(mut self, v: usize) -> Self {
103        self.queued_max_size = v;
104        self
105    }
106
107    /// Set the default blobpool max transaction count
108    pub const fn with_blobpool_max_count(mut self, v: usize) -> Self {
109        self.blobpool_max_count = v;
110        self
111    }
112
113    /// Set the default blobpool max size in MB
114    pub const fn with_blobpool_max_size(mut self, v: usize) -> Self {
115        self.blobpool_max_size = v;
116        self
117    }
118
119    /// Set the default blob cache size
120    pub const fn with_blob_cache_size(mut self, v: Option<u32>) -> Self {
121        self.blob_cache_size = v;
122        self
123    }
124
125    /// Set whether to disable blob transaction support by default
126    pub const fn with_disable_blobs_support(mut self, v: bool) -> Self {
127        self.disable_blobs_support = v;
128        self
129    }
130
131    /// Set the default max account slots
132    pub const fn with_max_account_slots(mut self, v: usize) -> Self {
133        self.max_account_slots = v;
134        self
135    }
136
137    /// Set the default price bump percentage
138    pub const fn with_price_bump(mut self, v: u128) -> Self {
139        self.price_bump = v;
140        self
141    }
142
143    /// Set the default minimal protocol base fee
144    pub const fn with_minimal_protocol_basefee(mut self, v: u64) -> Self {
145        self.minimal_protocol_basefee = v;
146        self
147    }
148
149    /// Set the default minimum priority fee
150    pub const fn with_minimum_priority_fee(mut self, v: Option<u128>) -> Self {
151        self.minimum_priority_fee = v;
152        self
153    }
154
155    /// Set the default enforced gas limit
156    pub const fn with_enforced_gas_limit(mut self, v: u64) -> Self {
157        self.enforced_gas_limit = v;
158        self
159    }
160
161    /// Set the default max transaction gas limit
162    pub const fn with_max_tx_gas_limit(mut self, v: Option<u64>) -> Self {
163        self.max_tx_gas_limit = v;
164        self
165    }
166
167    /// Set the default blob transaction price bump
168    pub const fn with_blob_transaction_price_bump(mut self, v: u128) -> Self {
169        self.blob_transaction_price_bump = v;
170        self
171    }
172
173    /// Set the default max transaction input bytes
174    pub const fn with_max_tx_input_bytes(mut self, v: usize) -> Self {
175        self.max_tx_input_bytes = v;
176        self
177    }
178
179    /// Set the default max cached entries
180    pub const fn with_max_cached_entries(mut self, v: u32) -> Self {
181        self.max_cached_entries = v;
182        self
183    }
184
185    /// Set whether to disable local transaction exemptions by default
186    pub const fn with_no_locals(mut self, v: bool) -> Self {
187        self.no_locals = v;
188        self
189    }
190
191    /// Set the default local addresses
192    pub fn with_locals(mut self, v: Vec<Address>) -> Self {
193        self.locals = v;
194        self
195    }
196
197    /// Set whether to disable local transaction propagation by default
198    pub const fn with_no_local_transactions_propagation(mut self, v: bool) -> Self {
199        self.no_local_transactions_propagation = v;
200        self
201    }
202
203    /// Set the default additional validation tasks
204    pub const fn with_additional_validation_tasks(mut self, v: usize) -> Self {
205        self.additional_validation_tasks = v;
206        self
207    }
208
209    /// Set the default pending transaction listener buffer size
210    pub const fn with_pending_tx_listener_buffer_size(mut self, v: usize) -> Self {
211        self.pending_tx_listener_buffer_size = v;
212        self
213    }
214
215    /// Set the default new transaction listener buffer size
216    pub const fn with_new_tx_listener_buffer_size(mut self, v: usize) -> Self {
217        self.new_tx_listener_buffer_size = v;
218        self
219    }
220
221    /// Set the default max new pending transactions notifications
222    pub const fn with_max_new_pending_txs_notifications(mut self, v: usize) -> Self {
223        self.max_new_pending_txs_notifications = v;
224        self
225    }
226
227    /// Set the default max queued lifetime
228    pub const fn with_max_queued_lifetime(mut self, v: Duration) -> Self {
229        self.max_queued_lifetime = v;
230        self
231    }
232
233    /// Set the default transactions backup path
234    pub fn with_transactions_backup_path(mut self, v: Option<PathBuf>) -> Self {
235        self.transactions_backup_path = v;
236        self
237    }
238
239    /// Set whether to disable transaction backup by default
240    pub const fn with_disable_transactions_backup(mut self, v: bool) -> Self {
241        self.disable_transactions_backup = v;
242        self
243    }
244
245    /// Set the default max batch size
246    pub const fn with_max_batch_size(mut self, v: usize) -> Self {
247        self.max_batch_size = v;
248        self
249    }
250}
251
252impl Default for DefaultTxPoolValues {
253    fn default() -> Self {
254        Self {
255            pending_max_count: TXPOOL_SUBPOOL_MAX_TXS_DEFAULT,
256            pending_max_size: TXPOOL_SUBPOOL_MAX_SIZE_MB_DEFAULT,
257            basefee_max_count: TXPOOL_SUBPOOL_MAX_TXS_DEFAULT,
258            basefee_max_size: TXPOOL_SUBPOOL_MAX_SIZE_MB_DEFAULT,
259            queued_max_count: TXPOOL_SUBPOOL_MAX_TXS_DEFAULT,
260            queued_max_size: TXPOOL_SUBPOOL_MAX_SIZE_MB_DEFAULT,
261            blobpool_max_count: TXPOOL_SUBPOOL_MAX_TXS_DEFAULT,
262            blobpool_max_size: TXPOOL_SUBPOOL_MAX_SIZE_MB_DEFAULT,
263            blob_cache_size: None,
264            disable_blobs_support: false,
265            max_account_slots: TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER,
266            price_bump: DEFAULT_PRICE_BUMP,
267            minimal_protocol_basefee: MIN_PROTOCOL_BASE_FEE,
268            minimum_priority_fee: None,
269            enforced_gas_limit: ETHEREUM_BLOCK_GAS_LIMIT_30M,
270            max_tx_gas_limit: None,
271            blob_transaction_price_bump: REPLACE_BLOB_PRICE_BUMP,
272            max_tx_input_bytes: DEFAULT_MAX_TX_INPUT_BYTES,
273            max_cached_entries: DEFAULT_MAX_CACHED_BLOBS,
274            no_locals: false,
275            locals: Vec::new(),
276            no_local_transactions_propagation: false,
277            additional_validation_tasks: DEFAULT_TXPOOL_ADDITIONAL_VALIDATION_TASKS,
278            pending_tx_listener_buffer_size: PENDING_TX_LISTENER_BUFFER_SIZE,
279            new_tx_listener_buffer_size: NEW_TX_LISTENER_BUFFER_SIZE,
280            max_new_pending_txs_notifications: MAX_NEW_PENDING_TXS_NOTIFICATIONS,
281            max_queued_lifetime: MAX_QUEUED_TRANSACTION_LIFETIME,
282            transactions_backup_path: None,
283            disable_transactions_backup: false,
284            max_batch_size: 1,
285        }
286    }
287}
288
289/// Parameters for debugging purposes
290#[derive(Debug, Clone, Args, PartialEq, Eq)]
291#[command(next_help_heading = "TxPool")]
292pub struct TxPoolArgs {
293    /// Max number of transaction in the pending sub-pool.
294    #[arg(long = "txpool.pending-max-count", alias = "txpool.pending_max_count", default_value_t = DefaultTxPoolValues::get_global().pending_max_count)]
295    pub pending_max_count: usize,
296    /// Max size of the pending sub-pool in megabytes.
297    #[arg(long = "txpool.pending-max-size", alias = "txpool.pending_max_size", default_value_t = DefaultTxPoolValues::get_global().pending_max_size)]
298    pub pending_max_size: usize,
299
300    /// Max number of transaction in the basefee sub-pool
301    #[arg(long = "txpool.basefee-max-count", alias = "txpool.basefee_max_count", default_value_t = DefaultTxPoolValues::get_global().basefee_max_count)]
302    pub basefee_max_count: usize,
303    /// Max size of the basefee sub-pool in megabytes.
304    #[arg(long = "txpool.basefee-max-size", alias = "txpool.basefee_max_size", default_value_t = DefaultTxPoolValues::get_global().basefee_max_size)]
305    pub basefee_max_size: usize,
306
307    /// Max number of transaction in the queued sub-pool
308    #[arg(long = "txpool.queued-max-count", alias = "txpool.queued_max_count", default_value_t = DefaultTxPoolValues::get_global().queued_max_count)]
309    pub queued_max_count: usize,
310    /// Max size of the queued sub-pool in megabytes.
311    #[arg(long = "txpool.queued-max-size", alias = "txpool.queued_max_size", default_value_t = DefaultTxPoolValues::get_global().queued_max_size)]
312    pub queued_max_size: usize,
313
314    /// Max number of transaction in the blobpool
315    #[arg(long = "txpool.blobpool-max-count", alias = "txpool.blobpool_max_count", default_value_t = DefaultTxPoolValues::get_global().blobpool_max_count)]
316    pub blobpool_max_count: usize,
317    /// Max size of the blobpool in megabytes.
318    #[arg(long = "txpool.blobpool-max-size", alias = "txpool.blobpool_max_size", default_value_t = DefaultTxPoolValues::get_global().blobpool_max_size)]
319    pub blobpool_max_size: usize,
320
321    /// Max number of entries for the in memory cache of the blob store.
322    #[arg(long = "txpool.blob-cache-size", alias = "txpool.blob_cache_size", default_value = Resettable::from(DefaultTxPoolValues::get_global().blob_cache_size.map(|v| v.to_string().into())))]
323    pub blob_cache_size: Option<u32>,
324
325    /// Disable EIP-4844 blob transaction support
326    #[arg(long = "txpool.disable-blobs-support", alias = "txpool.disable_blobs_support", default_value_t = DefaultTxPoolValues::get_global().disable_blobs_support, conflicts_with_all = ["blobpool_max_count", "blobpool_max_size", "blob_cache_size", "blob_transaction_price_bump"])]
327    pub disable_blobs_support: bool,
328
329    /// Max number of executable transaction slots guaranteed per account
330    #[arg(long = "txpool.max-account-slots", alias = "txpool.max_account_slots", default_value_t = DefaultTxPoolValues::get_global().max_account_slots)]
331    pub max_account_slots: usize,
332
333    /// Price bump (in %) for the transaction pool underpriced check.
334    #[arg(long = "txpool.pricebump", default_value_t = DefaultTxPoolValues::get_global().price_bump)]
335    pub price_bump: u128,
336
337    /// Minimum base fee required by the protocol.
338    #[arg(long = "txpool.minimal-protocol-fee", default_value_t = DefaultTxPoolValues::get_global().minimal_protocol_basefee)]
339    pub minimal_protocol_basefee: u64,
340
341    /// Minimum priority fee required for transaction acceptance into the pool.
342    /// Transactions with priority fee below this value will be rejected.
343    #[arg(long = "txpool.minimum-priority-fee", default_value = Resettable::from(DefaultTxPoolValues::get_global().minimum_priority_fee.map(|v| v.to_string().into())))]
344    pub minimum_priority_fee: Option<u128>,
345
346    /// The default enforced gas limit for transactions entering the pool
347    #[arg(long = "txpool.gas-limit", default_value_t = DefaultTxPoolValues::get_global().enforced_gas_limit)]
348    pub enforced_gas_limit: u64,
349
350    /// Maximum gas limit for individual transactions. Transactions exceeding this limit will be
351    /// rejected by the transaction pool
352    #[arg(long = "txpool.max-tx-gas", default_value = Resettable::from(DefaultTxPoolValues::get_global().max_tx_gas_limit.map(|v| v.to_string().into())))]
353    pub max_tx_gas_limit: Option<u64>,
354
355    /// Price bump percentage to replace an already existing blob transaction
356    #[arg(long = "blobpool.pricebump", default_value_t = DefaultTxPoolValues::get_global().blob_transaction_price_bump)]
357    pub blob_transaction_price_bump: u128,
358
359    /// Max size in bytes of a single transaction allowed to enter the pool
360    #[arg(long = "txpool.max-tx-input-bytes", alias = "txpool.max_tx_input_bytes", default_value_t = DefaultTxPoolValues::get_global().max_tx_input_bytes)]
361    pub max_tx_input_bytes: usize,
362
363    /// The maximum number of blobs to keep in the in memory blob cache.
364    #[arg(long = "txpool.max-cached-entries", alias = "txpool.max_cached_entries", default_value_t = DefaultTxPoolValues::get_global().max_cached_entries)]
365    pub max_cached_entries: u32,
366
367    /// Flag to disable local transaction exemptions.
368    #[arg(long = "txpool.nolocals", default_value_t = DefaultTxPoolValues::get_global().no_locals)]
369    pub no_locals: bool,
370    /// Flag to allow certain addresses as local.
371    #[arg(long = "txpool.locals", default_values = DefaultTxPoolValues::get_global().locals.iter().map(ToString::to_string))]
372    pub locals: Vec<Address>,
373    /// Flag to toggle local transaction propagation.
374    #[arg(long = "txpool.no-local-transactions-propagation", default_value_t = DefaultTxPoolValues::get_global().no_local_transactions_propagation)]
375    pub no_local_transactions_propagation: bool,
376
377    /// Number of additional transaction validation tasks to spawn.
378    #[arg(long = "txpool.additional-validation-tasks", alias = "txpool.additional_validation_tasks", default_value_t = DefaultTxPoolValues::get_global().additional_validation_tasks)]
379    pub additional_validation_tasks: usize,
380
381    /// Maximum number of pending transactions from the network to buffer
382    #[arg(long = "txpool.max-pending-txns", alias = "txpool.max_pending_txns", default_value_t = DefaultTxPoolValues::get_global().pending_tx_listener_buffer_size)]
383    pub pending_tx_listener_buffer_size: usize,
384
385    /// Maximum number of new transactions to buffer
386    #[arg(long = "txpool.max-new-txns", alias = "txpool.max_new_txns", default_value_t = DefaultTxPoolValues::get_global().new_tx_listener_buffer_size)]
387    pub new_tx_listener_buffer_size: usize,
388
389    /// How many new pending transactions to buffer and send to in progress pending transaction
390    /// iterators.
391    #[arg(long = "txpool.max-new-pending-txs-notifications", alias = "txpool.max-new-pending-txs-notifications", default_value_t = DefaultTxPoolValues::get_global().max_new_pending_txs_notifications)]
392    pub max_new_pending_txs_notifications: usize,
393
394    /// Maximum amount of time non-executable transaction are queued.
395    #[arg(long = "txpool.lifetime", value_parser = parse_duration_from_secs_or_ms, value_name = "DURATION", default_value = format_duration_as_secs_or_ms(DefaultTxPoolValues::get_global().max_queued_lifetime))]
396    pub max_queued_lifetime: Duration,
397
398    /// Path to store the local transaction backup at, to survive node restarts.
399    #[arg(long = "txpool.transactions-backup", alias = "txpool.journal", value_name = "PATH", default_value = Resettable::from(DefaultTxPoolValues::get_global().transactions_backup_path.as_ref().map(|v| v.to_string_lossy().into())))]
400    pub transactions_backup_path: Option<PathBuf>,
401
402    /// Disables transaction backup to disk on node shutdown.
403    #[arg(
404        long = "txpool.disable-transactions-backup",
405        alias = "txpool.disable-journal",
406        conflicts_with = "transactions_backup_path",
407        default_value_t = DefaultTxPoolValues::get_global().disable_transactions_backup
408    )]
409    pub disable_transactions_backup: bool,
410
411    /// Max batch size for transaction pool insertions
412    #[arg(long = "txpool.max-batch-size", default_value_t = DefaultTxPoolValues::get_global().max_batch_size)]
413    pub max_batch_size: usize,
414}
415
416impl TxPoolArgs {
417    /// Sets the minimal protocol base fee to 0, effectively disabling checks that enforce that a
418    /// transaction's fee must be higher than the [`MIN_PROTOCOL_BASE_FEE`] which is the lowest
419    /// value the ethereum EIP-1559 base fee can reach.
420    pub const fn with_disabled_protocol_base_fee(self) -> Self {
421        self.with_protocol_base_fee(0)
422    }
423
424    /// Configures the minimal protocol base fee that should be enforced.
425    ///
426    /// Ethereum's EIP-1559 base fee can't drop below [`MIN_PROTOCOL_BASE_FEE`] hence this is
427    /// enforced by default in the pool.
428    pub const fn with_protocol_base_fee(mut self, protocol_base_fee: u64) -> Self {
429        self.minimal_protocol_basefee = protocol_base_fee;
430        self
431    }
432}
433
434impl Default for TxPoolArgs {
435    fn default() -> Self {
436        let DefaultTxPoolValues {
437            pending_max_count,
438            pending_max_size,
439            basefee_max_count,
440            basefee_max_size,
441            queued_max_count,
442            queued_max_size,
443            blobpool_max_count,
444            blobpool_max_size,
445            blob_cache_size,
446            disable_blobs_support,
447            max_account_slots,
448            price_bump,
449            minimal_protocol_basefee,
450            minimum_priority_fee,
451            enforced_gas_limit,
452            max_tx_gas_limit,
453            blob_transaction_price_bump,
454            max_tx_input_bytes,
455            max_cached_entries,
456            no_locals,
457            locals,
458            no_local_transactions_propagation,
459            additional_validation_tasks,
460            pending_tx_listener_buffer_size,
461            new_tx_listener_buffer_size,
462            max_new_pending_txs_notifications,
463            max_queued_lifetime,
464            transactions_backup_path,
465            disable_transactions_backup,
466            max_batch_size,
467        } = DefaultTxPoolValues::get_global().clone();
468        Self {
469            pending_max_count,
470            pending_max_size,
471            basefee_max_count,
472            basefee_max_size,
473            queued_max_count,
474            queued_max_size,
475            blobpool_max_count,
476            blobpool_max_size,
477            blob_cache_size,
478            disable_blobs_support,
479            max_account_slots,
480            price_bump,
481            minimal_protocol_basefee,
482            minimum_priority_fee,
483            enforced_gas_limit,
484            max_tx_gas_limit,
485            blob_transaction_price_bump,
486            max_tx_input_bytes,
487            max_cached_entries,
488            no_locals,
489            locals,
490            no_local_transactions_propagation,
491            additional_validation_tasks,
492            pending_tx_listener_buffer_size,
493            new_tx_listener_buffer_size,
494            max_new_pending_txs_notifications,
495            max_queued_lifetime,
496            transactions_backup_path,
497            disable_transactions_backup,
498            max_batch_size,
499        }
500    }
501}
502
503impl RethTransactionPoolConfig for TxPoolArgs {
504    /// Returns transaction pool configuration.
505    fn pool_config(&self) -> PoolConfig {
506        let default_config = PoolConfig::default();
507        PoolConfig {
508            local_transactions_config: LocalTransactionConfig {
509                no_exemptions: self.no_locals,
510                local_addresses: self.locals.clone().into_iter().collect(),
511                propagate_local_transactions: !self.no_local_transactions_propagation,
512            },
513            pending_limit: SubPoolLimit {
514                max_txs: self.pending_max_count,
515                max_size: self.pending_max_size.saturating_mul(1024 * 1024),
516            },
517            basefee_limit: SubPoolLimit {
518                max_txs: self.basefee_max_count,
519                max_size: self.basefee_max_size.saturating_mul(1024 * 1024),
520            },
521            queued_limit: SubPoolLimit {
522                max_txs: self.queued_max_count,
523                max_size: self.queued_max_size.saturating_mul(1024 * 1024),
524            },
525            blob_limit: SubPoolLimit {
526                max_txs: self.blobpool_max_count,
527                max_size: self.blobpool_max_size.saturating_mul(1024 * 1024),
528            },
529            blob_cache_size: self.blob_cache_size,
530            max_account_slots: self.max_account_slots,
531            price_bumps: PriceBumpConfig {
532                default_price_bump: self.price_bump,
533                replace_blob_tx_price_bump: self.blob_transaction_price_bump,
534            },
535            minimal_protocol_basefee: self.minimal_protocol_basefee,
536            minimum_priority_fee: self.minimum_priority_fee,
537            gas_limit: self.enforced_gas_limit,
538            pending_tx_listener_buffer_size: self.pending_tx_listener_buffer_size,
539            new_tx_listener_buffer_size: self.new_tx_listener_buffer_size,
540            max_new_pending_txs_notifications: self.max_new_pending_txs_notifications,
541            max_queued_lifetime: self.max_queued_lifetime,
542            max_inflight_delegated_slot_limit: default_config.max_inflight_delegated_slot_limit,
543        }
544    }
545
546    /// Returns max batch size for transaction batch insertion.
547    fn max_batch_size(&self) -> usize {
548        self.max_batch_size
549    }
550}
551
552#[cfg(test)]
553mod tests {
554    use super::*;
555    use alloy_primitives::address;
556    use clap::Parser;
557
558    /// A helper type to parse Args more easily
559    #[derive(Parser)]
560    struct CommandParser<T: Args> {
561        #[command(flatten)]
562        args: T,
563    }
564
565    #[test]
566    fn txpool_args_default_sanity_test() {
567        let default_args = TxPoolArgs::default();
568        let args = CommandParser::<TxPoolArgs>::parse_from(["reth"]).args;
569        assert_eq!(args, default_args);
570    }
571
572    #[test]
573    fn txpool_parse_max_tx_lifetime() {
574        // Test with a custom duration
575        let args =
576            CommandParser::<TxPoolArgs>::parse_from(["reth", "--txpool.lifetime", "300"]).args;
577        assert_eq!(args.max_queued_lifetime, Duration::from_secs(300));
578
579        // Test with the default value
580        let args = CommandParser::<TxPoolArgs>::parse_from(["reth"]).args;
581        assert_eq!(args.max_queued_lifetime, Duration::from_secs(3 * 60 * 60)); // Default is 3h
582    }
583
584    #[test]
585    fn txpool_parse_max_tx_lifetime_invalid() {
586        let result =
587            CommandParser::<TxPoolArgs>::try_parse_from(["reth", "--txpool.lifetime", "invalid"]);
588
589        assert!(result.is_err(), "Expected an error for invalid duration");
590    }
591
592    #[test]
593    fn txpool_args() {
594        let args = TxPoolArgs {
595            pending_max_count: 1000,
596            pending_max_size: 200,
597            basefee_max_count: 2000,
598            basefee_max_size: 300,
599            queued_max_count: 3000,
600            queued_max_size: 400,
601            blobpool_max_count: 4000,
602            blobpool_max_size: 500,
603            blob_cache_size: Some(100),
604            disable_blobs_support: false,
605            max_account_slots: 20,
606            price_bump: 15,
607            minimal_protocol_basefee: 1000000000,
608            minimum_priority_fee: Some(2000000000),
609            enforced_gas_limit: 40000000,
610            max_tx_gas_limit: Some(50000000),
611            blob_transaction_price_bump: 25,
612            max_tx_input_bytes: 131072,
613            max_cached_entries: 200,
614            no_locals: true,
615            locals: vec![
616                address!("0x0000000000000000000000000000000000000001"),
617                address!("0x0000000000000000000000000000000000000002"),
618            ],
619            no_local_transactions_propagation: true,
620            additional_validation_tasks: 4,
621            pending_tx_listener_buffer_size: 512,
622            new_tx_listener_buffer_size: 256,
623            max_new_pending_txs_notifications: 128,
624            max_queued_lifetime: Duration::from_secs(7200),
625            transactions_backup_path: Some(PathBuf::from("/tmp/txpool-backup")),
626            disable_transactions_backup: false,
627            max_batch_size: 10,
628        };
629
630        let parsed_args = CommandParser::<TxPoolArgs>::parse_from([
631            "reth",
632            "--txpool.pending-max-count",
633            "1000",
634            "--txpool.pending-max-size",
635            "200",
636            "--txpool.basefee-max-count",
637            "2000",
638            "--txpool.basefee-max-size",
639            "300",
640            "--txpool.queued-max-count",
641            "3000",
642            "--txpool.queued-max-size",
643            "400",
644            "--txpool.blobpool-max-count",
645            "4000",
646            "--txpool.blobpool-max-size",
647            "500",
648            "--txpool.blob-cache-size",
649            "100",
650            "--txpool.max-account-slots",
651            "20",
652            "--txpool.pricebump",
653            "15",
654            "--txpool.minimal-protocol-fee",
655            "1000000000",
656            "--txpool.minimum-priority-fee",
657            "2000000000",
658            "--txpool.gas-limit",
659            "40000000",
660            "--txpool.max-tx-gas",
661            "50000000",
662            "--blobpool.pricebump",
663            "25",
664            "--txpool.max-tx-input-bytes",
665            "131072",
666            "--txpool.max-cached-entries",
667            "200",
668            "--txpool.nolocals",
669            "--txpool.locals",
670            "0x0000000000000000000000000000000000000001",
671            "--txpool.locals",
672            "0x0000000000000000000000000000000000000002",
673            "--txpool.no-local-transactions-propagation",
674            "--txpool.additional-validation-tasks",
675            "4",
676            "--txpool.max-pending-txns",
677            "512",
678            "--txpool.max-new-txns",
679            "256",
680            "--txpool.max-new-pending-txs-notifications",
681            "128",
682            "--txpool.lifetime",
683            "7200",
684            "--txpool.transactions-backup",
685            "/tmp/txpool-backup",
686            "--txpool.max-batch-size",
687            "10",
688        ])
689        .args;
690
691        assert_eq!(parsed_args, args);
692    }
693}