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_MTP_HEADERS") {
66 if let Ok(count) = val.parse::<usize>() {
67 config.block_validation.median_time_past_headers = count;
68 }
69 }
70 if let Ok(val) = std::env::var("BLVM_PARALLEL_VALIDATION") {
71 if let Ok(enabled) = val.parse::<bool>() {
72 config.block_validation.enable_parallel_validation = enabled;
73 }
74 }
75 if let Ok(val) = std::env::var("BLVM_COINBASE_MATURITY") {
76 if let Ok(maturity) = val.parse::<u64>() {
77 config.block_validation.coinbase_maturity_override = maturity;
78 }
79 }
80 if let Ok(val) = std::env::var("BLVM_MAX_SIGOPS_COST") {
81 if let Ok(cost) = val.parse::<u64>() {
82 config.block_validation.max_block_sigops_cost_override = cost;
83 }
84 }
85
86 if let Ok(val) = std::env::var("BLVM_MAX_ADDR_ADDRESSES") {
87 if let Ok(limit) = val.parse::<usize>() {
88 config.network_limits.max_addr_addresses = limit;
89 }
90 }
91
92 if let Ok(val) = std::env::var("BLVM_MAX_INV_ITEMS") {
93 if let Ok(limit) = val.parse::<usize>() {
94 config.network_limits.max_inv_items = limit;
95 }
96 }
97
98 if let Ok(val) = std::env::var("BLVM_MAX_HEADERS") {
99 if let Ok(limit) = val.parse::<usize>() {
100 config.network_limits.max_headers = limit;
101 }
102 }
103
104 if let Ok(val) = std::env::var("BLVM_MAX_USER_AGENT_LENGTH") {
105 if let Ok(limit) = val.parse::<usize>() {
106 config.network_limits.max_user_agent_length = limit;
107 }
108 }
109
110 if let Ok(val) = std::env::var("BLVM_MEMPOOL_MB") {
112 if let Ok(mb) = val.parse::<u64>() {
113 config.mempool.max_mempool_mb = mb;
114 }
115 }
116 if let Ok(val) = std::env::var("BLVM_MEMPOOL_TXS") {
117 if let Ok(count) = val.parse::<usize>() {
118 config.mempool.max_mempool_txs = count;
119 }
120 }
121 if let Ok(val) = std::env::var("BLVM_MEMPOOL_EXPIRY_HOURS") {
122 if let Ok(hours) = val.parse::<u64>() {
123 config.mempool.mempool_expiry_hours = hours;
124 }
125 }
126 if let Ok(val) = std::env::var("BLVM_MEMPOOL_MIN_RELAY_FEE") {
127 if let Ok(rate) = val.parse::<u64>() {
128 config.mempool.min_relay_fee_rate = rate;
129 }
130 }
131 if let Ok(val) = std::env::var("BLVM_MEMPOOL_MIN_TX_FEE") {
132 if let Ok(fee) = val.parse::<i64>() {
133 config.mempool.min_tx_fee = fee;
134 }
135 }
136 if let Ok(val) = std::env::var("BLVM_MEMPOOL_RBF_FEE_INCREMENT") {
137 if let Ok(increment) = val.parse::<i64>() {
138 config.mempool.rbf_fee_increment = increment;
139 }
140 }
141
142 if let Ok(val) = std::env::var("BLVM_UTXO_COMMITMENT_MAX_SET_MB") {
144 if let Ok(mb) = val.parse::<u64>() {
145 config.utxo_commitment.max_utxo_commitment_set_mb = mb;
146 }
147 }
148 if let Ok(val) = std::env::var("BLVM_UTXO_COMMITMENT_MAX_UTXO_COUNT") {
149 if let Ok(count) = val.parse::<u64>() {
150 config.utxo_commitment.max_utxo_count = count;
151 }
152 }
153 if let Ok(val) = std::env::var("BLVM_UTXO_COMMITMENT_MAX_HISTORICAL") {
154 if let Ok(count) = val.parse::<usize>() {
155 config.utxo_commitment.max_historical_commitments = count;
156 }
157 }
158 if let Ok(val) = std::env::var("BLVM_UTXO_COMMITMENT_INCREMENTAL") {
159 if let Ok(enabled) = val.parse::<bool>() {
160 config.utxo_commitment.enable_incremental_updates = enabled;
161 }
162 }
163
164 if let Ok(val) = std::env::var("BLVM_SCRIPT_THREADS") {
166 if let Ok(threads) = val.parse::<usize>() {
167 config.performance.script_verification_threads = threads;
168 }
169 }
170 if let Ok(val) = std::env::var("BLVM_PARALLEL_BATCH_SIZE") {
171 if let Ok(size) = val.parse::<usize>() {
172 config.performance.parallel_batch_size = size;
173 }
174 }
175 if let Ok(val) = std::env::var("BLVM_SIMD") {
176 if let Ok(enabled) = val.parse::<bool>() {
177 config.performance.enable_simd_optimizations = enabled;
178 }
179 }
180 if let Ok(val) = std::env::var("BLVM_CACHE_OPTIMIZATIONS") {
181 if let Ok(enabled) = val.parse::<bool>() {
182 config.performance.enable_cache_optimizations = enabled;
183 }
184 }
185 if let Ok(val) = std::env::var("BLVM_BATCH_UTXO_LOOKUPS") {
186 if let Ok(enabled) = val.parse::<bool>() {
187 config.performance.enable_batch_utxo_lookups = enabled;
188 }
189 }
190 if let Ok(val) = std::env::var("BLVM_IBD_CHUNK_THRESHOLD") {
191 if let Ok(n) = val.parse::<usize>() {
192 config.performance.ibd_chunk_threshold = Some(n);
193 }
194 }
195 if let Ok(val) = std::env::var("BLVM_IBD_MIN_CHUNK_SIZE") {
196 if let Ok(n) = val.parse::<usize>() {
197 config.performance.ibd_min_chunk_size = Some(n);
198 }
199 }
200
201 if let Ok(val) = std::env::var("BLVM_CONSENSUS_DEBUG") {
203 let parts: Vec<&str> = val.split(',').map(|s| s.trim()).collect();
204 for p in &parts {
205 match *p {
206 "full" => {
207 config.debug.enable_runtime_assertions = true;
208 config.debug.enable_runtime_invariants = true;
209 config.debug.enable_verbose_logging = true;
210 config.debug.enable_performance_profiling = true;
211 config.debug.log_rejections = true;
212 }
213 "assertions" => config.debug.enable_runtime_assertions = true,
214 "invariants" => config.debug.enable_runtime_invariants = true,
215 "verbose" => config.debug.enable_verbose_logging = true,
216 "profile" => config.debug.enable_performance_profiling = true,
217 "rejections" => config.debug.log_rejections = true,
218 _ => {}
219 }
220 }
221 }
222
223 if let Ok(val) = std::env::var("BLVM_CONSENSUS_FEATURES") {
225 let parts: Vec<&str> = val.split(',').map(|s| s.trim()).collect();
226 for p in &parts {
227 match *p {
228 "full" => {
229 config.features.enable_experimental_optimizations = true;
230 config.features.enable_bounds_check_optimizations = true;
231 config.features.enable_reference_checks = true;
232 config.features.enable_aggressive_caching = true;
233 config.features.enable_batch_tx_id_computation = true;
234 config.features.enable_simd_hash_operations = true;
235 }
236 "experimental" => config.features.enable_experimental_optimizations = true,
237 "bounds_check" => config.features.enable_bounds_check_optimizations = true,
238 "reference_checks" => config.features.enable_reference_checks = true,
239 "aggressive_cache" => config.features.enable_aggressive_caching = true,
240 "batch_txid" => config.features.enable_batch_tx_id_computation = true,
241 "simd_hash" => config.features.enable_simd_hash_operations = true,
242 _ => {}
243 }
244 }
245 }
246
247 if let Ok(val) = std::env::var("BLVM_CUSTOM_CHECKPOINTS") {
249 config.advanced.custom_checkpoints = val
251 .split(',')
252 .filter_map(|s| s.trim().parse::<u64>().ok())
253 .collect();
254 }
255 if let Ok(val) = std::env::var("BLVM_MAX_REORG_DEPTH") {
256 if let Ok(depth) = val.parse::<u64>() {
257 config.advanced.max_reorg_depth = depth;
258 }
259 }
260 if let Ok(val) = std::env::var("BLVM_STRICT_MODE") {
261 if let Ok(enabled) = val.parse::<bool>() {
262 config.advanced.strict_mode = enabled;
263 }
264 }
265 if let Ok(val) = std::env::var("BLVM_MAX_BLOCK_SIZE") {
266 if let Ok(size) = val.parse::<usize>() {
267 config.advanced.max_block_size_override = size;
268 }
269 }
270 if let Ok(val) = std::env::var("BLVM_RBF") {
271 if let Ok(enabled) = val.parse::<bool>() {
272 config.advanced.enable_rbf = enabled;
273 }
274 }
275
276 config
277 }
278
279 #[cfg(feature = "production")]
281 pub fn get_assume_valid_height(&self) -> u64 {
282 #[cfg(feature = "benchmarking")]
284 {
285 use std::sync::atomic::{AtomicU64, Ordering};
286 static OVERRIDE: AtomicU64 = AtomicU64::new(u64::MAX);
287 let override_val = OVERRIDE.load(Ordering::Relaxed);
288 if override_val != u64::MAX {
289 return override_val;
290 }
291 }
292
293 self.block_validation.assume_valid_height
294 }
295
296 #[cfg(not(feature = "production"))]
298 pub fn get_assume_valid_height(&self) -> u64 {
299 self.block_validation.assume_valid_height
300 }
301}
302
303static GLOBAL_CONSENSUS_CONFIG: std::sync::OnceLock<ConsensusConfig> = std::sync::OnceLock::new();
309
310#[allow(dead_code)] pub fn init_consensus_config(config: ConsensusConfig) {
315 let _ = GLOBAL_CONSENSUS_CONFIG.set(config);
316}
317
318pub fn get_consensus_config_ref() -> &'static ConsensusConfig {
322 GLOBAL_CONSENSUS_CONFIG.get_or_init(ConsensusConfig::from_env)
323}
324
325pub fn get_consensus_config() -> ConsensusConfig {
327 get_consensus_config_ref().clone()
328}
329
330#[cfg(all(feature = "production", feature = "benchmarking"))]
334static ASSUME_VALID_OVERRIDE: std::sync::atomic::AtomicU64 =
335 std::sync::atomic::AtomicU64::new(u64::MAX);
336
337pub fn get_assume_valid_height() -> u64 {
339 #[cfg(all(feature = "production", feature = "benchmarking"))]
340 {
341 use std::sync::atomic::Ordering;
342 let v = ASSUME_VALID_OVERRIDE.load(Ordering::Relaxed);
343 if v != u64::MAX {
344 return v;
345 }
346 }
347 get_consensus_config_ref()
348 .block_validation
349 .assume_valid_height
350}
351
352pub fn get_assume_valid_hash() -> Option<[u8; 32]> {
354 get_consensus_config_ref()
355 .block_validation
356 .assume_valid_hash
357}
358
359pub fn get_n_minimum_chain_work() -> u128 {
361 get_consensus_config_ref()
362 .block_validation
363 .n_minimum_chain_work
364}
365
366#[cfg(all(feature = "production", feature = "benchmarking"))]
368pub fn set_assume_valid_height(height: u64) {
369 use std::sync::atomic::Ordering;
370 ASSUME_VALID_OVERRIDE.store(height, Ordering::Relaxed);
371}
372
373#[cfg(all(feature = "production", feature = "benchmarking"))]
375pub fn reset_assume_valid_height() {
376 set_assume_valid_height(u64::MAX);
377}
378
379pub fn use_overlay_delta() -> bool {
383 true
384}
385
386#[cfg(all(feature = "production", feature = "rayon"))]
395pub fn init_rayon_for_script_verification() {
396 use std::sync::Once;
397 static INIT: Once = Once::new();
398 INIT.call_once(|| {
399 let config = get_consensus_config_ref();
400 let n = config.performance.script_verification_threads;
401 if n > 0 {
402 if let Err(e) = rayon::ThreadPoolBuilder::new()
403 .num_threads(n)
404 .build_global()
405 {
406 eprintln!(
407 "Warning: Failed to set Rayon script verification pool to {n} threads: {e}. Using default."
408 );
409 }
410 }
411 });
413}