subcoin_mempool/
options.rs

1use std::time::Duration;
2
3/** Default for -maxmempool, maximum megabytes of mempool memory usage */
4const DEFAULT_MAX_MEMPOOL_SIZE_MB: usize = 300;
5
6/** Default for -mempoolexpiry, expiration time for mempool transactions in hours */
7const DEFAULT_MEMPOOL_EXPIRY_HOURS: u32 = 336;
8
9/** Default for -acceptnonstdtxn */
10#[allow(dead_code)]
11const DEFAULT_ACCEPT_NON_STD_TXN: bool = false;
12
13/// Default setting for -datacarriersize.
14/// 80 bytes of data, +1 for OP_RETURN, +2 for the pushdata opcodes.
15pub const MAX_OP_RETURN_RELAY: usize = 83;
16
17/// Configuration options for the transaction memory pool.
18#[derive(Clone, Debug)]
19pub struct MemPoolLimits {
20    /// Maximum number of ancestors for a transaction
21    pub max_ancestors: usize,
22
23    /// Maximum size (in virtual bytes) of all ancestors for a transaction
24    pub max_ancestor_size_vbytes: usize,
25
26    /// Maximum number of descendants for a transaction
27    pub max_descendants: usize,
28
29    /// Maximum size (in virtual bytes) of all descendants for a transaction
30    pub max_descendant_size_vbytes: usize,
31}
32
33impl Default for MemPoolLimits {
34    fn default() -> Self {
35        Self {
36            max_ancestors: 25,
37            max_ancestor_size_vbytes: 101_000,
38            max_descendants: 25,
39            max_descendant_size_vbytes: 101_000,
40        }
41    }
42}
43
44/// Configuration options for the transaction memory pool.
45#[derive(Clone, Debug)]
46pub struct MemPoolOptions {
47    /// Maximum size of the mempool in bytes (default: 300 * 1_000_000)
48    pub max_size_bytes: usize,
49
50    /// Number of seconds to keep transactions in the mempool (default: 336 * 60 * 60)
51    pub expiry_seconds: u32,
52
53    /// Minimum fee rate in satoshis per KB for a transaction to be accepted.
54    pub min_relay_feerate: u64,
55
56    /// Minimum fee rate in satoshis per KB for a transaction to be accepted.
57    pub dust_relay_feerate: u64,
58
59    /// > A data carrying output is an unspendable output containing data. The script
60    /// > type is designated as TxoutType::NULL_DATA.
61    /// >
62    /// > Maximum size of TxoutType::NULL_DATA scripts that this node considers standard.
63    /// > If nullopt, any size is nonstandard.
64    pub max_datacarrier_bytes: usize,
65
66    /// Whether to require standard transactions
67    pub permit_bare_multisig: bool,
68
69    /// Whether to require standard transactions
70    pub require_standard: bool,
71
72    /// Maximum script verification cache size
73    pub max_script_cache_size: usize,
74
75    pub limits: MemPoolLimits,
76
77    /// Whether to enable RBF (BIP125).
78    pub enable_rbf: bool,
79
80    /// Maximum number of transactions that can be replaced (BIP125 Rule 6).
81    pub max_replacement_txs: usize,
82
83    /// Enable package relay/CPFP.
84    pub enable_package_relay: bool,
85
86    /// Maximum number of transactions in a package.
87    pub max_package_count: usize,
88
89    /// Maximum total virtual size of package in vbytes.
90    pub max_package_vsize: u64,
91}
92
93impl Default for MemPoolOptions {
94    fn default() -> Self {
95        Self {
96            max_size_bytes: DEFAULT_MAX_MEMPOOL_SIZE_MB * 1_000_000,
97            expiry_seconds: DEFAULT_MEMPOOL_EXPIRY_HOURS * 60 * 60, // 2 weeks
98            min_relay_feerate: 1000,                                // 1 sat/byte
99            dust_relay_feerate: 1000,                               // 1 sat/byte
100            max_datacarrier_bytes: MAX_OP_RETURN_RELAY,
101            permit_bare_multisig: true,
102            require_standard: true,
103            max_script_cache_size: 32 << 20, // 32 MB
104            limits: MemPoolLimits::default(),
105            enable_rbf: true,
106            max_replacement_txs: 100,
107            enable_package_relay: true,
108            max_package_count: 25,
109            max_package_vsize: 101_000,
110        }
111    }
112}
113
114impl MemPoolOptions {
115    /// Create new mempool options with default values
116    pub fn new() -> Self {
117        Self::default()
118    }
119
120    /// Create a builder for configuring mempool options
121    pub fn builder() -> MemPoolOptionsBuilder {
122        MemPoolOptionsBuilder::default()
123    }
124
125    /// Get the maximum size of the mempool in bytes
126    pub fn max_size_bytes(&self) -> usize {
127        self.max_size_bytes * 1_000_000
128    }
129
130    /// Get the expiry duration
131    pub fn expiry_duration(&self) -> Duration {
132        Duration::from_secs(self.expiry_seconds as u64 * 3600)
133    }
134
135    /// Get maximum number of ancestors
136    pub fn max_ancestors(&self) -> usize {
137        self.limits.max_ancestors
138    }
139
140    /// Get maximum ancestor size
141    pub fn max_ancestor_size(&self) -> i64 {
142        self.limits.max_ancestor_size_vbytes as i64
143    }
144
145    /// Get maximum number of descendants
146    pub fn max_descendants(&self) -> u64 {
147        self.limits.max_descendants as u64
148    }
149
150    /// Get maximum descendant size
151    pub fn max_descendant_size(&self) -> i64 {
152        self.limits.max_descendant_size_vbytes as i64
153    }
154
155    /// Get the minimum relay fee rate as FeeRate
156    pub fn min_relay_fee_rate(&self) -> crate::types::FeeRate {
157        crate::types::FeeRate::from_sat_per_kvb(self.min_relay_feerate)
158    }
159}
160
161/// Builder pattern for MemPoolOptions
162#[derive(Default)]
163pub struct MemPoolOptionsBuilder {
164    options: MemPoolOptions,
165}
166
167impl MemPoolOptionsBuilder {
168    /// Set maximum size of the mempool in MB
169    pub fn max_size_bytes(mut self, size: usize) -> Self {
170        self.options.max_size_bytes = size;
171        self
172    }
173
174    /// Set minimum relay fee rate
175    pub fn min_relay_feerate(mut self, rate: u64) -> Self {
176        self.options.min_relay_feerate = rate;
177        self
178    }
179
180    /// Set expiry time in hours
181    pub fn expiry_seconds(mut self, hours: u32) -> Self {
182        self.options.expiry_seconds = hours;
183        self
184    }
185
186    /// Set maximum number of ancestors
187    pub fn max_ancestors(mut self, count: usize) -> Self {
188        self.options.limits.max_ancestors = count;
189        self
190    }
191
192    /// Set maximum ancestor size
193    pub fn max_ancestor_size_vbytes(mut self, size: usize) -> Self {
194        self.options.limits.max_ancestor_size_vbytes = size;
195        self
196    }
197
198    /// Set maximum number of descendants
199    pub fn max_descendants(mut self, count: usize) -> Self {
200        self.options.limits.max_descendants = count;
201        self
202    }
203
204    /// Set maximum descendant size
205    pub fn max_descendant_size_vbytes(mut self, size: usize) -> Self {
206        self.options.limits.max_descendant_size_vbytes = size;
207        self
208    }
209
210    /// Set whether to require standard transactions
211    pub fn require_standard(mut self, require: bool) -> Self {
212        self.options.require_standard = require;
213        self
214    }
215
216    /// Build the final MemPoolOptions
217    pub fn build(self) -> MemPoolOptions {
218        self.options
219    }
220}
221
222#[cfg(test)]
223mod tests {
224    use super::*;
225
226    #[test]
227    fn test_mempool_options_builder() {
228        let options = MemPoolOptions::builder()
229            .max_size_bytes(500)
230            .min_relay_feerate(2000)
231            .expiry_seconds(168) // 1 week
232            .max_ancestors(50)
233            .build();
234
235        assert_eq!(options.max_size_bytes, 500);
236        assert_eq!(options.min_relay_feerate, 2000);
237        assert_eq!(options.expiry_seconds, 168);
238        assert_eq!(options.limits.max_ancestors, 50);
239    }
240
241    #[test]
242    fn test_mempool_options_defaults() {
243        let options = MemPoolOptions::default();
244
245        assert_eq!(options.max_size_bytes, 300_000_000);
246        assert_eq!(options.min_relay_feerate, 1000);
247        assert_eq!(options.expiry_seconds, 336 * 60 * 60);
248        assert_eq!(options.limits.max_ancestors, 25);
249    }
250}