Skip to main content

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