Skip to main content

blvm_protocol/
config.rs

1//! Configuration for blvm-protocol
2//!
3//! Provides configurable parameters for protocol-level settings, service flags,
4//! protocol validation rules, and Commons-specific extensions. These settings
5//! complement blvm-consensus configuration by focusing on protocol abstraction
6//! rather than consensus validation.
7//!
8//! Operational limits and sub-configs align with [`blvm_consensus::config`] (which builds on
9//! `blvm-primitives` for foundational types). [`ConsensusConfig`](crate::consensus_config::ConsensusConfig)
10//! remains the full consensus aggregate in `blvm-consensus`.
11
12pub use blvm_consensus::config::{
13    AdvancedConfig, BlockValidationConfig, DebugConfig, FeatureFlagsConfig, MempoolConfig,
14    NetworkMessageLimits, PerformanceConfig, UtxoCommitmentConfig,
15};
16
17use crate::ProtocolVersion;
18use serde::{Deserialize, Serialize};
19
20/// Protocol validation rules configuration
21///
22/// Controls protocol-specific size limits and feature enablement.
23/// These are protocol-level rules that may differ from consensus rules.
24#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
25pub struct ProtocolValidationConfig {
26    /// Maximum block size for protocol validation (bytes)
27    /// Default: 4,000,000 (4MB)
28    #[serde(default = "default_max_block_size")]
29    pub max_block_size: u32,
30
31    /// Maximum transaction size for protocol validation (bytes)
32    /// Default: 1,000,000 (1MB)
33    #[serde(default = "default_max_tx_size")]
34    pub max_tx_size: u32,
35
36    /// Maximum script size for protocol validation (bytes)
37    /// Default: 10,000 (10KB)
38    #[serde(default = "default_max_script_size")]
39    pub max_script_size: u32,
40
41    /// Maximum transactions per block (protocol limit)
42    /// Default: 10,000
43    #[serde(default = "default_max_txs_per_block")]
44    pub max_txs_per_block: usize,
45
46    /// Maximum block locator hashes in GetHeaders/GetBlocks
47    /// Default: 100
48    #[serde(default = "default_max_locator_hashes")]
49    pub max_locator_hashes: usize,
50}
51
52fn default_max_block_size() -> u32 {
53    4_000_000
54}
55
56fn default_max_tx_size() -> u32 {
57    1_000_000
58}
59
60fn default_max_script_size() -> u32 {
61    10_000
62}
63
64fn default_max_txs_per_block() -> usize {
65    10_000
66}
67
68fn default_max_locator_hashes() -> usize {
69    100
70}
71
72impl Default for ProtocolValidationConfig {
73    fn default() -> Self {
74        Self {
75            max_block_size: 4_000_000,
76            max_tx_size: 1_000_000,
77            max_script_size: 10_000,
78            max_txs_per_block: 10_000,
79            max_locator_hashes: 100,
80        }
81    }
82}
83
84/// Service flags configuration
85///
86/// Controls which service capabilities are advertised to peers.
87#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
88pub struct ServiceFlagsConfig {
89    /// Advertise NODE_NETWORK capability
90    /// Default: true (always enabled)
91    #[serde(default = "default_true")]
92    pub node_network: bool,
93
94    /// Advertise NODE_WITNESS capability (SegWit support)
95    /// Default: true
96    #[serde(default = "default_true")]
97    pub node_witness: bool,
98
99    /// Advertise NODE_COMPACT_FILTERS capability (BIP157/158)
100    /// Default: false
101    #[serde(default = "default_false")]
102    pub node_compact_filters: bool,
103
104    /// Advertise NODE_NETWORK_LIMITED capability
105    /// Default: false
106    #[serde(default = "default_false")]
107    pub node_network_limited: bool,
108
109    /// Advertise Commons NODE_FIBRE capability
110    /// Default: false
111    #[serde(default = "default_false")]
112    pub node_fibre: bool,
113
114    /// Advertise Commons NODE_DANDELION capability
115    /// Default: false
116    #[serde(default = "default_false")]
117    pub node_dandelion: bool,
118
119    /// Advertise Commons NODE_PACKAGE_RELAY capability (BIP331)
120    /// Default: false
121    #[serde(default = "default_false")]
122    pub node_package_relay: bool,
123
124    /// Advertise Commons NODE_UTXO_COMMITMENTS capability
125    /// Default: false (requires utxo-commitments feature)
126    #[serde(default = "default_false")]
127    pub node_utxo_commitments: bool,
128
129    /// Advertise Commons NODE_BAN_LIST_SHARING capability
130    /// Default: false
131    #[serde(default = "default_false")]
132    pub node_ban_list_sharing: bool,
133
134    /// Advertise NODE_V2_TRANSPORT capability (BIP324)
135    /// Default: false (requires bip324 feature)
136    #[cfg(feature = "bip324")]
137    #[serde(default = "default_false")]
138    pub node_v2_transport: bool,
139
140    /// Advertise Commons NODE_GOVERNANCE capability (governance message relay)
141    /// Default: false
142    #[serde(default = "default_false")]
143    pub node_governance: bool,
144}
145
146fn default_true() -> bool {
147    true
148}
149
150fn default_false() -> bool {
151    false
152}
153
154impl Default for ServiceFlagsConfig {
155    fn default() -> Self {
156        Self {
157            node_network: true,
158            node_witness: true,
159            node_compact_filters: false,
160            node_network_limited: false,
161            node_fibre: false,
162            node_dandelion: false,
163            node_package_relay: false,
164            node_utxo_commitments: false,
165            node_ban_list_sharing: false,
166            node_governance: false,
167            #[cfg(feature = "bip324")]
168            node_v2_transport: false,
169        }
170    }
171}
172
173/// Protocol feature configuration
174///
175/// Controls which protocol features are enabled.
176#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
177pub struct ProtocolFeaturesConfig {
178    /// Enable SegWit (Segregated Witness)
179    /// Default: true
180    #[serde(default = "default_true")]
181    pub segwit: bool,
182
183    /// Enable Taproot
184    /// Default: true
185    #[serde(default = "default_true")]
186    pub taproot: bool,
187
188    /// Enable RBF (Replace-By-Fee)
189    /// Default: true
190    #[serde(default = "default_true")]
191    pub rbf: bool,
192
193    /// Enable CTV (CheckTemplateVerify, BIP119)
194    /// Default: false
195    #[serde(default = "default_false")]
196    pub ctv: bool,
197
198    /// Enable BIP152 Compact Block Relay
199    /// Default: true
200    #[serde(default = "default_true")]
201    pub compact_blocks: bool,
202
203    /// Enable BIP157/158 Compact Block Filters
204    /// Default: false
205    #[serde(default = "default_false")]
206    pub compact_filters: bool,
207}
208
209impl Default for ProtocolFeaturesConfig {
210    fn default() -> Self {
211        Self {
212            segwit: true,
213            taproot: true,
214            rbf: true,
215            ctv: false,
216            compact_blocks: true,
217            compact_filters: false,
218        }
219    }
220}
221
222/// Fee rate configuration
223///
224/// Controls protocol-level fee rate limits and validation.
225#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
226pub struct FeeRateConfig {
227    /// Minimum transaction fee rate (satoshis per virtual byte)
228    /// Default: 1 sat/vB
229    #[serde(default = "default_min_fee_rate")]
230    pub min_fee_rate: u64,
231
232    /// Maximum transaction fee rate (satoshis per virtual byte)
233    /// Default: 1,000,000 sat/vB
234    #[serde(default = "default_max_fee_rate")]
235    pub max_fee_rate: u64,
236}
237
238fn default_min_fee_rate() -> u64 {
239    1
240}
241
242fn default_max_fee_rate() -> u64 {
243    1_000_000
244}
245
246impl Default for FeeRateConfig {
247    fn default() -> Self {
248        Self {
249            min_fee_rate: 1,
250            max_fee_rate: 1_000_000,
251        }
252    }
253}
254
255/// BIP152 Compact Block Relay configuration
256#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
257pub struct CompactBlockConfig {
258    /// Enable compact block relay
259    /// Default: true
260    #[serde(default = "default_true")]
261    pub enabled: bool,
262
263    /// Preferred compact block version (1 or 2)
264    /// Default: 2 (latest)
265    #[serde(default = "default_compact_block_version")]
266    pub preferred_version: u64,
267
268    /// Maximum transaction indices in GetBlockTxn
269    /// Default: 10,000
270    #[serde(default = "default_max_blocktxn_indices")]
271    pub max_blocktxn_indices: usize,
272}
273
274fn default_compact_block_version() -> u64 {
275    2
276}
277
278fn default_max_blocktxn_indices() -> usize {
279    10_000
280}
281
282impl Default for CompactBlockConfig {
283    fn default() -> Self {
284        Self {
285            enabled: true,
286            preferred_version: 2,
287            max_blocktxn_indices: 10_000,
288        }
289    }
290}
291
292/// Commons-specific protocol extensions configuration
293#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
294pub struct CommonsExtensionsConfig {
295    /// Enable UTXO commitments protocol
296    /// Default: false (requires utxo-commitments feature)
297    #[serde(default = "default_false")]
298    pub utxo_commitments: bool,
299
300    /// Enable filtered block relay (spam filtering)
301    /// Default: false
302    #[serde(default = "default_false")]
303    pub filtered_blocks: bool,
304
305    /// Enable ban list sharing
306    /// Default: false
307    #[serde(default = "default_false")]
308    pub ban_list_sharing: bool,
309
310    /// Default filter preferences for filtered blocks
311    #[serde(default)]
312    pub default_filter_preferences: FilterPreferencesConfig,
313}
314
315/// Filter preferences configuration for spam filtering
316#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
317pub struct FilterPreferencesConfig {
318    /// Filter Ordinals/Inscriptions
319    /// Default: false
320    #[serde(default = "default_false")]
321    pub filter_ordinals: bool,
322
323    /// Filter dust outputs (< 546 satoshis)
324    /// Default: false
325    #[serde(default = "default_false")]
326    pub filter_dust: bool,
327
328    /// Filter BRC-20 patterns
329    /// Default: false
330    #[serde(default = "default_false")]
331    pub filter_brc20: bool,
332
333    /// Minimum output value to include (satoshis)
334    /// Default: 0 (no minimum)
335    #[serde(default)]
336    pub min_output_value: u64,
337}
338
339/// Complete protocol configuration
340#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
341pub struct ProtocolConfig {
342    /// Protocol version to use
343    /// Default: BitcoinV1 (mainnet)
344    #[serde(default = "default_protocol_version")]
345    pub protocol_version: ProtocolVersion,
346
347    /// Network message limits (from blvm-consensus to avoid duplication)
348    /// These limits protect against DoS attacks by bounding message sizes
349    #[serde(default)]
350    pub network_limits: NetworkMessageLimits,
351
352    /// Protocol validation rules
353    #[serde(default)]
354    pub validation: ProtocolValidationConfig,
355
356    /// Service flags configuration
357    #[serde(default)]
358    pub service_flags: ServiceFlagsConfig,
359
360    /// Protocol features configuration
361    #[serde(default)]
362    pub features: ProtocolFeaturesConfig,
363
364    /// Fee rate configuration
365    #[serde(default)]
366    pub fee_rates: FeeRateConfig,
367
368    /// BIP152 Compact Block Relay configuration
369    #[serde(default)]
370    pub compact_blocks: CompactBlockConfig,
371
372    /// Commons-specific extensions configuration
373    #[serde(default)]
374    pub commons: CommonsExtensionsConfig,
375}
376
377fn default_protocol_version() -> ProtocolVersion {
378    ProtocolVersion::BitcoinV1
379}
380
381impl Default for ProtocolConfig {
382    fn default() -> Self {
383        Self {
384            protocol_version: ProtocolVersion::BitcoinV1,
385            network_limits: NetworkMessageLimits::default(),
386            validation: ProtocolValidationConfig::default(),
387            service_flags: ServiceFlagsConfig::default(),
388            features: ProtocolFeaturesConfig::default(),
389            fee_rates: FeeRateConfig::default(),
390            compact_blocks: CompactBlockConfig::default(),
391            commons: CommonsExtensionsConfig::default(),
392        }
393    }
394}
395
396impl ProtocolConfig {
397    /// Load configuration from environment variables
398    ///
399    /// Uses short names aligned with blvm-consensus where applicable.
400    /// Examples: `BLVM_PROTOCOL_VERSION=Testnet3`, `BLVM_MAX_BLOCK_SIZE=4000000`
401    pub fn from_env() -> Self {
402        let mut config = Self::default();
403
404        // Protocol version
405        if let Ok(val) = std::env::var("BLVM_PROTOCOL_VERSION") {
406            config.protocol_version = match val.as_str() {
407                "Testnet3" | "testnet" => ProtocolVersion::Testnet3,
408                "Regtest" | "regtest" => ProtocolVersion::Regtest,
409                _ => ProtocolVersion::BitcoinV1,
410            };
411        }
412
413        // Network limits (same vars as blvm-consensus)
414        if let Ok(val) = std::env::var("BLVM_MAX_ADDR_ADDRESSES") {
415            if let Ok(count) = val.parse::<usize>() {
416                config.network_limits.max_addr_addresses = count;
417            }
418        }
419        if let Ok(val) = std::env::var("BLVM_MAX_INV_ITEMS") {
420            if let Ok(count) = val.parse::<usize>() {
421                config.network_limits.max_inv_items = count;
422            }
423        }
424        if let Ok(val) = std::env::var("BLVM_MAX_HEADERS") {
425            if let Ok(count) = val.parse::<usize>() {
426                config.network_limits.max_headers = count;
427            }
428        }
429        if let Ok(val) = std::env::var("BLVM_MAX_USER_AGENT_LENGTH") {
430            if let Ok(length) = val.parse::<usize>() {
431                config.network_limits.max_user_agent_length = length;
432            }
433        }
434
435        // Validation
436        if let Ok(val) = std::env::var("BLVM_MAX_BLOCK_SIZE") {
437            if let Ok(size) = val.parse::<u32>() {
438                config.validation.max_block_size = size;
439            }
440        }
441        if let Ok(val) = std::env::var("BLVM_MAX_TX_SIZE") {
442            if let Ok(size) = val.parse::<u32>() {
443                config.validation.max_tx_size = size;
444            }
445        }
446        if let Ok(val) = std::env::var("BLVM_MAX_TXS_PER_BLOCK") {
447            if let Ok(count) = val.parse::<usize>() {
448                config.validation.max_txs_per_block = count;
449            }
450        }
451        if let Ok(val) = std::env::var("BLVM_MAX_LOCATOR_HASHES") {
452            if let Ok(count) = val.parse::<usize>() {
453                config.validation.max_locator_hashes = count;
454            }
455        }
456
457        // Service flags
458        if let Ok(val) = std::env::var("BLVM_SERVICE_FIBRE") {
459            if let Ok(enabled) = val.parse::<bool>() {
460                config.service_flags.node_fibre = enabled;
461            }
462        }
463        if let Ok(val) = std::env::var("BLVM_SERVICE_UTXO_COMMITMENTS") {
464            if let Ok(enabled) = val.parse::<bool>() {
465                config.service_flags.node_utxo_commitments = enabled;
466            }
467        }
468        if let Ok(val) = std::env::var("BLVM_SERVICE_BAN_LIST_SHARING") {
469            if let Ok(enabled) = val.parse::<bool>() {
470                config.service_flags.node_ban_list_sharing = enabled;
471            }
472        }
473
474        // Features
475        if let Ok(val) = std::env::var("BLVM_FEATURE_COMPACT_BLOCKS") {
476            if let Ok(enabled) = val.parse::<bool>() {
477                config.features.compact_blocks = enabled;
478            }
479        }
480
481        // Commons extensions
482        if let Ok(val) = std::env::var("BLVM_UTXO_COMMITMENTS") {
483            if let Ok(enabled) = val.parse::<bool>() {
484                config.commons.utxo_commitments = enabled;
485            }
486        }
487
488        config
489    }
490
491    /// Get service flags value from configuration
492    pub fn get_service_flags(&self) -> u64 {
493        use crate::service_flags::{commons, set_flag, standard};
494        let mut flags = 0u64;
495
496        if self.service_flags.node_network {
497            set_flag(&mut flags, standard::NODE_NETWORK);
498        }
499        if self.service_flags.node_witness {
500            set_flag(&mut flags, standard::NODE_WITNESS);
501        }
502        if self.service_flags.node_compact_filters {
503            set_flag(&mut flags, standard::NODE_COMPACT_FILTERS);
504        }
505        if self.service_flags.node_network_limited {
506            set_flag(&mut flags, standard::NODE_NETWORK_LIMITED);
507        }
508        if self.service_flags.node_fibre {
509            set_flag(&mut flags, commons::NODE_FIBRE);
510        }
511        if self.service_flags.node_dandelion {
512            set_flag(&mut flags, commons::NODE_DANDELION);
513        }
514        if self.service_flags.node_package_relay {
515            set_flag(&mut flags, commons::NODE_PACKAGE_RELAY);
516        }
517        #[cfg(feature = "utxo-commitments")]
518        if self.service_flags.node_utxo_commitments {
519            set_flag(&mut flags, commons::NODE_UTXO_COMMITMENTS);
520        }
521        if self.service_flags.node_ban_list_sharing {
522            set_flag(&mut flags, commons::NODE_BAN_LIST_SHARING);
523        }
524        if self.service_flags.node_governance {
525            set_flag(&mut flags, commons::NODE_GOVERNANCE);
526        }
527
528        flags
529    }
530}