1use serde::{Deserialize, Serialize};
8
9pub use blvm_primitives::config::{
11 AdvancedConfig, BlockValidationConfig, DebugConfig, FeatureFlagsConfig, MempoolConfig,
12 NetworkMessageLimits, PerformanceConfig, UtxoCommitmentConfig,
13};
14
15#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
17pub struct ConsensusConfig {
18 #[serde(default)]
20 pub network_limits: NetworkMessageLimits,
21
22 #[serde(default)]
24 pub block_validation: BlockValidationConfig,
25
26 #[serde(default)]
28 pub mempool: MempoolConfig,
29
30 #[serde(default)]
32 pub utxo_commitment: UtxoCommitmentConfig,
33
34 #[serde(default)]
36 pub performance: PerformanceConfig,
37
38 #[serde(default)]
40 pub debug: DebugConfig,
41
42 #[serde(default)]
44 pub features: FeatureFlagsConfig,
45
46 #[serde(default)]
48 pub advanced: AdvancedConfig,
49}
50
51impl ConsensusConfig {
52 pub fn from_env() -> Self {
56 let mut config = Self::default();
57
58 if let Ok(val) = std::env::var("BLVM_ASSUME_VALID_HEIGHT") {
60 if let Ok(height) = val.parse::<u64>() {
61 config.block_validation.assume_valid_height = height;
62 }
63 }
64
65 if let Ok(val) = std::env::var("BLVM_MAX_ADDR_ADDRESSES") {
66 if let Ok(limit) = val.parse::<usize>() {
67 config.network_limits.max_addr_addresses = limit;
68 }
69 }
70
71 if let Ok(val) = std::env::var("BLVM_MAX_INV_ITEMS") {
72 if let Ok(limit) = val.parse::<usize>() {
73 config.network_limits.max_inv_items = limit;
74 }
75 }
76
77 if let Ok(val) = std::env::var("BLVM_MAX_HEADERS") {
78 if let Ok(limit) = val.parse::<usize>() {
79 config.network_limits.max_headers = limit;
80 }
81 }
82
83 if let Ok(val) = std::env::var("BLVM_MAX_USER_AGENT_LENGTH") {
84 if let Ok(limit) = val.parse::<usize>() {
85 config.network_limits.max_user_agent_length = limit;
86 }
87 }
88
89 if let Ok(val) = std::env::var("BLVM_MEMPOOL_MB") {
91 if let Ok(mb) = val.parse::<u64>() {
92 config.mempool.max_mempool_mb = mb;
93 }
94 }
95 if let Ok(val) = std::env::var("BLVM_MEMPOOL_TXS") {
96 if let Ok(count) = val.parse::<usize>() {
97 config.mempool.max_mempool_txs = count;
98 }
99 }
100 if let Ok(val) = std::env::var("BLVM_MEMPOOL_EXPIRY_HOURS") {
101 if let Ok(hours) = val.parse::<u64>() {
102 config.mempool.mempool_expiry_hours = hours;
103 }
104 }
105 if let Ok(val) = std::env::var("BLVM_MEMPOOL_MIN_RELAY_FEE") {
106 if let Ok(rate) = val.parse::<u64>() {
107 config.mempool.min_relay_fee_rate = rate;
108 }
109 }
110 if let Ok(val) = std::env::var("BLVM_MEMPOOL_MIN_TX_FEE") {
111 if let Ok(fee) = val.parse::<i64>() {
112 config.mempool.min_tx_fee = fee;
113 }
114 }
115 if let Ok(val) = std::env::var("BLVM_MEMPOOL_RBF_FEE_INCREMENT") {
116 if let Ok(increment) = val.parse::<i64>() {
117 config.mempool.rbf_fee_increment = increment;
118 }
119 }
120
121 if let Ok(val) = std::env::var("BLVM_UTXO_COMMITMENT_MAX_SET_MB") {
123 if let Ok(mb) = val.parse::<u64>() {
124 config.utxo_commitment.max_utxo_commitment_set_mb = mb;
125 }
126 }
127 if let Ok(val) = std::env::var("BLVM_UTXO_COMMITMENT_MAX_UTXO_COUNT") {
128 if let Ok(count) = val.parse::<u64>() {
129 config.utxo_commitment.max_utxo_count = count;
130 }
131 }
132 if let Ok(val) = std::env::var("BLVM_UTXO_COMMITMENT_MAX_HISTORICAL") {
133 if let Ok(count) = val.parse::<usize>() {
134 config.utxo_commitment.max_historical_commitments = count;
135 }
136 }
137 if let Ok(val) = std::env::var("BLVM_UTXO_COMMITMENT_INCREMENTAL") {
138 if let Ok(enabled) = val.parse::<bool>() {
139 config.utxo_commitment.enable_incremental_updates = enabled;
140 }
141 }
142
143 if let Ok(val) = std::env::var("BLVM_SCRIPT_THREADS") {
145 if let Ok(threads) = val.parse::<usize>() {
146 config.performance.script_verification_threads = threads;
147 }
148 }
149 if let Ok(val) = std::env::var("BLVM_PARALLEL_BATCH_SIZE") {
150 if let Ok(size) = val.parse::<usize>() {
151 config.performance.parallel_batch_size = size;
152 }
153 }
154 if let Ok(val) = std::env::var("BLVM_SIMD") {
155 if let Ok(enabled) = val.parse::<bool>() {
156 config.performance.enable_simd_optimizations = enabled;
157 }
158 }
159 if let Ok(val) = std::env::var("BLVM_CACHE_OPTIMIZATIONS") {
160 if let Ok(enabled) = val.parse::<bool>() {
161 config.performance.enable_cache_optimizations = enabled;
162 }
163 }
164 if let Ok(val) = std::env::var("BLVM_BATCH_UTXO_LOOKUPS") {
165 if let Ok(enabled) = val.parse::<bool>() {
166 config.performance.enable_batch_utxo_lookups = enabled;
167 }
168 }
169 if let Ok(val) = std::env::var("BLVM_IBD_CHUNK_THRESHOLD") {
170 if let Ok(n) = val.parse::<usize>() {
171 config.performance.ibd_chunk_threshold = Some(n);
172 }
173 }
174 if let Ok(val) = std::env::var("BLVM_IBD_MIN_CHUNK_SIZE") {
175 if let Ok(n) = val.parse::<usize>() {
176 config.performance.ibd_min_chunk_size = Some(n);
177 }
178 }
179
180 if let Ok(val) = std::env::var("BLVM_CONSENSUS_DEBUG") {
182 let parts: Vec<&str> = val.split(',').map(|s| s.trim()).collect();
183 for p in &parts {
184 match *p {
185 "full" => {
186 config.debug.enable_runtime_assertions = true;
187 config.debug.enable_runtime_invariants = true;
188 config.debug.enable_verbose_logging = true;
189 config.debug.enable_performance_profiling = true;
190 config.debug.log_rejections = true;
191 }
192 "assertions" => config.debug.enable_runtime_assertions = true,
193 "invariants" => config.debug.enable_runtime_invariants = true,
194 "verbose" => config.debug.enable_verbose_logging = true,
195 "profile" => config.debug.enable_performance_profiling = true,
196 "rejections" => config.debug.log_rejections = true,
197 _ => {}
198 }
199 }
200 }
201
202 if let Ok(val) = std::env::var("BLVM_CONSENSUS_FEATURES") {
204 let parts: Vec<&str> = val.split(',').map(|s| s.trim()).collect();
205 for p in &parts {
206 match *p {
207 "full" => {
208 config.features.enable_experimental_optimizations = true;
209 config.features.enable_bounds_check_optimizations = true;
210 config.features.enable_reference_checks = true;
211 config.features.enable_aggressive_caching = true;
212 config.features.enable_batch_tx_id_computation = true;
213 config.features.enable_simd_hash_operations = true;
214 }
215 "experimental" => config.features.enable_experimental_optimizations = true,
216 "bounds_check" => config.features.enable_bounds_check_optimizations = true,
217 "reference_checks" => config.features.enable_reference_checks = true,
218 "aggressive_cache" => config.features.enable_aggressive_caching = true,
219 "batch_txid" => config.features.enable_batch_tx_id_computation = true,
220 "simd_hash" => config.features.enable_simd_hash_operations = true,
221 _ => {}
222 }
223 }
224 }
225
226 if let Ok(val) = std::env::var("BLVM_CUSTOM_CHECKPOINTS") {
228 config.advanced.custom_checkpoints = val
230 .split(',')
231 .filter_map(|s| s.trim().parse::<u64>().ok())
232 .collect();
233 }
234 if let Ok(val) = std::env::var("BLVM_MAX_REORG_DEPTH") {
235 if let Ok(depth) = val.parse::<u64>() {
236 config.advanced.max_reorg_depth = depth;
237 }
238 }
239 if let Ok(val) = std::env::var("BLVM_STRICT_MODE") {
240 if let Ok(enabled) = val.parse::<bool>() {
241 config.advanced.strict_mode = enabled;
242 }
243 }
244 if let Ok(val) = std::env::var("BLVM_MAX_BLOCK_SIZE") {
245 if let Ok(size) = val.parse::<usize>() {
246 config.advanced.max_block_size_override = size;
247 }
248 }
249 if let Ok(val) = std::env::var("BLVM_RBF") {
250 if let Ok(enabled) = val.parse::<bool>() {
251 config.advanced.enable_rbf = enabled;
252 }
253 }
254
255 config
256 }
257
258 #[cfg(feature = "production")]
260 pub fn get_assume_valid_height(&self) -> u64 {
261 #[cfg(feature = "benchmarking")]
263 {
264 use std::sync::atomic::{AtomicU64, Ordering};
265 static OVERRIDE: AtomicU64 = AtomicU64::new(u64::MAX);
266 let override_val = OVERRIDE.load(Ordering::Relaxed);
267 if override_val != u64::MAX {
268 return override_val;
269 }
270 }
271
272 self.block_validation.assume_valid_height
273 }
274
275 #[cfg(not(feature = "production"))]
277 pub fn get_assume_valid_height(&self) -> u64 {
278 self.block_validation.assume_valid_height
279 }
280}
281
282static GLOBAL_CONSENSUS_CONFIG: std::sync::OnceLock<ConsensusConfig> = std::sync::OnceLock::new();
288
289pub fn init_consensus_config(config: ConsensusConfig) {
293 let _ = GLOBAL_CONSENSUS_CONFIG.set(config);
294}
295
296pub fn get_consensus_config_ref() -> &'static ConsensusConfig {
300 GLOBAL_CONSENSUS_CONFIG.get_or_init(ConsensusConfig::from_env)
301}
302
303pub fn get_consensus_config() -> ConsensusConfig {
305 get_consensus_config_ref().clone()
306}
307
308#[cfg(all(feature = "production", feature = "benchmarking"))]
312static ASSUME_VALID_OVERRIDE: std::sync::atomic::AtomicU64 =
313 std::sync::atomic::AtomicU64::new(u64::MAX);
314
315pub fn get_assume_valid_height() -> u64 {
317 #[cfg(all(feature = "production", feature = "benchmarking"))]
318 {
319 use std::sync::atomic::Ordering;
320 let v = ASSUME_VALID_OVERRIDE.load(Ordering::Relaxed);
321 if v != u64::MAX {
322 return v;
323 }
324 }
325 get_consensus_config_ref()
326 .block_validation
327 .assume_valid_height
328}
329
330pub fn get_assume_valid_hash() -> Option<[u8; 32]> {
332 get_consensus_config_ref()
333 .block_validation
334 .assume_valid_hash
335}
336
337pub fn get_n_minimum_chain_work() -> u128 {
339 get_consensus_config_ref()
340 .block_validation
341 .n_minimum_chain_work
342}
343
344#[cfg(all(feature = "production", feature = "benchmarking"))]
346pub fn set_assume_valid_height(height: u64) {
347 use std::sync::atomic::Ordering;
348 ASSUME_VALID_OVERRIDE.store(height, Ordering::Relaxed);
349}
350
351#[cfg(all(feature = "production", feature = "benchmarking"))]
353pub fn reset_assume_valid_height() {
354 set_assume_valid_height(u64::MAX);
355}
356
357pub fn use_overlay_delta() -> bool {
361 true
362}
363
364#[cfg(all(feature = "production", feature = "rayon"))]
373pub fn init_rayon_for_script_verification() {
374 use std::sync::Once;
375 static INIT: Once = Once::new();
376 INIT.call_once(|| {
377 let config = get_consensus_config_ref();
378 let n = config.performance.script_verification_threads;
379 if n > 0 {
380 if let Err(e) = rayon::ThreadPoolBuilder::new()
381 .num_threads(n)
382 .build_global()
383 {
384 eprintln!(
385 "Warning: Failed to set Rayon script verification pool to {n} threads: {e}. Using default."
386 );
387 }
388 }
389 });
391}