blvm-consensus 0.1.12

Bitcoin Commons BLVM: Direct mathematical implementation of Bitcoin consensus rules from the Orange Paper
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
//! # Consensus-Proof
//!
//! Direct mathematical implementation of Bitcoin consensus rules from the Orange Paper.
//!
//! This crate provides pure, side-effect-free functions that implement the mathematical
//! specifications defined in the Orange Paper. It serves as the mathematical foundation
//! for Bitcoin consensus validation.
//!
//! ## Architecture
//!
//! The system follows a layered architecture:
//! - Orange Paper (mathematical specifications)
//! - Consensus Proof (this crate - direct implementation)
//! - Reference Node (minimal Bitcoin implementation)
//! - Developer SDK (developer-friendly interface)
//!
//! ## Design Principles
//!
//! 1. **Pure Functions**: All functions are deterministic and side-effect-free
//! 2. **Mathematical Accuracy**: Direct implementation of Orange Paper specifications
//! 3. **Exact Version Pinning**: All consensus-critical dependencies pinned to exact versions
//! 4. **No Consensus Rule Interpretation**: Only mathematical implementation
//!
//! ## Usage
//!
//! ```rust
//! use blvm_consensus::transaction::check_transaction;
//! use blvm_consensus::types::*;
//!
//! let transaction = Transaction {
//!     version: 1,
//!     inputs: vec![].into(),
//!     outputs: vec![TransactionOutput {
//!         value: 1000,
//!         script_pubkey: vec![0x51],
//!     }]
//!     .into(),
//!     lock_time: 0,
//! };
//! let result = check_transaction(&transaction).unwrap();
//! ```

#![allow(unused_doc_comments)] // Allow doc comments before macros (proptest, etc.)
#![allow(unused_variables, unused_assignments, dead_code)] // Many paths are feature-gated or used conditionally
#![allow(
    clippy::too_many_arguments,  // Script/block have 8–17 args; struct refactor is large
    clippy::type_complexity,     // Performance-critical types (OnceLock<RwLock<LruCache<...>>>)
    clippy::large_enum_variant,  // NetworkResponse::SendMessage; boxing changes layout
)]

pub mod script;
pub mod transaction;
pub mod transaction_hash;

use blvm_spec_lock::spec_locked;
#[cfg(all(feature = "production", feature = "benchmarking"))]
pub use config::{reset_assume_valid_height, set_assume_valid_height};
#[cfg(feature = "production")]
pub use script::batch_verify_signatures;
#[cfg(all(feature = "production", feature = "benchmarking"))]
pub use script::{
    clear_all_caches, clear_hash_cache, clear_script_cache, clear_stack_pool, disable_caching,
    reset_benchmarking_state,
};
#[cfg(all(feature = "production", feature = "benchmarking"))]
pub use transaction_hash::clear_sighash_templates;

// Re-export from blvm-primitives for backward compatibility
pub use blvm_primitives::constants;
pub use blvm_primitives::crypto;
pub use blvm_primitives::opcodes;
pub use blvm_primitives::serialization;
pub use blvm_primitives::{error, types};
pub use blvm_primitives::{tx_inputs, tx_outputs};
pub use constants::*;
pub use error::ConsensusError;
pub use types::*;

/// Orange Paper Section 4 symbols (C, H, M_MAX, etc.) — re-export from primitives constants.
pub mod orange_paper_constants {
    pub use crate::constants::{C, H, L_ELEMENT, L_OPS, L_SCRIPT, L_STACK, M_MAX, R, S_MAX, W_MAX};
}

/// Spec-lock / property-test helpers only — not a supported production API.
/// Functions in this module `panic!` or `unimplemented!` when called outside their
/// intended spec-validation context. Do **not** call from production code.
#[doc(hidden)]
pub mod orange_paper_property_helpers;

pub mod config;

pub mod activation;
pub mod bip113;
#[cfg(feature = "ctv")]
pub mod bip119;
#[cfg(any(feature = "csfs", feature = "production"))]
pub mod bip348;
pub mod bip_validation;
pub mod block;
#[cfg(all(feature = "production", feature = "rayon"))]
pub mod checkqueue;
pub mod economic;
pub mod locktime;
pub mod mempool;
pub mod mining;
pub mod optimizations;
pub mod pow;
pub mod reorganization;
#[cfg(all(feature = "production", feature = "rayon"))]
pub(crate) mod script_exec_cache;
pub mod secp256k1_backend;
pub mod segwit;
pub mod sequence_locks;
pub mod sigop;
pub mod taproot;
pub mod utxo_overlay;
pub mod version_bits;
pub mod witness;

// Integration tests link this crate without `cfg(test)` on the library, so `test_utils` cannot be
// gated only on `test`. Fixture helpers are small; `property-tests`/`proptest` stays gated inside the module.
pub mod test_utils;

#[cfg(feature = "profile")]
pub mod profile_log;
#[cfg(all(feature = "production", feature = "profile"))]
pub mod script_profile;

/// Consensus Proof - wrapper struct for consensus validation functions
///
/// This struct provides a convenient API for accessing all consensus validation
/// functions. All methods delegate to the corresponding module functions.
#[derive(Debug, Clone, Copy, Default)]
pub struct ConsensusProof;

impl ConsensusProof {
    /// Create a new ConsensusProof instance
    pub fn new() -> Self {
        Self
    }

    /// Validate a transaction according to consensus rules
    #[spec_locked("5.1")]
    pub fn validate_transaction(
        &self,
        tx: &types::Transaction,
    ) -> error::Result<types::ValidationResult> {
        transaction::check_transaction(tx)
    }

    /// Validate transaction inputs against UTXO set
    #[spec_locked("5.1")]
    pub fn validate_tx_inputs(
        &self,
        tx: &types::Transaction,
        utxo_set: &types::UtxoSet,
        height: types::Natural,
    ) -> error::Result<(types::ValidationResult, types::Integer)> {
        transaction::check_tx_inputs(tx, utxo_set, height)
    }

    /// Validate a complete block
    #[spec_locked("5.3")]
    pub fn validate_block(
        &self,
        block: &types::Block,
        utxo_set: types::UtxoSet,
        height: types::Natural,
    ) -> error::Result<(types::ValidationResult, types::UtxoSet)> {
        // Create empty witnesses for backward compatibility
        let witnesses: Vec<Vec<segwit::Witness>> =
            block.transactions.iter().map(|_| Vec::new()).collect();
        let network_time = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap_or(std::time::Duration::ZERO)
            .as_secs();
        let context = block::block_validation_context_for_connect_ibd(
            None::<&[types::BlockHeader]>,
            network_time,
            types::Network::Mainnet,
        );
        let (result, new_utxo_set, _undo_log) =
            block::connect_block(block, &witnesses, utxo_set, height, &context)?;
        Ok((result, new_utxo_set))
    }

    /// Validate a complete block with witness data and time context
    #[spec_locked("5.3")]
    pub fn validate_block_with_time_context(
        &self,
        block: &types::Block,
        witnesses: &[Vec<segwit::Witness>],
        utxo_set: types::UtxoSet,
        height: types::Natural,
        time_context: Option<types::TimeContext>,
        network: types::Network,
    ) -> error::Result<(types::ValidationResult, types::UtxoSet)> {
        let context = block::BlockValidationContext::from_time_context_and_network(
            time_context,
            network,
            None,
        );
        let (result, new_utxo_set, _undo_log) =
            block::connect_block(block, witnesses, utxo_set, height, &context)?;
        Ok((result, new_utxo_set))
    }

    /// Verify script execution
    #[spec_locked("5.2")]
    pub fn verify_script(
        &self,
        script_sig: &types::ByteString,
        script_pubkey: &types::ByteString,
        witness: Option<&types::ByteString>,
        flags: u32,
    ) -> error::Result<bool> {
        script::verify_script(script_sig, script_pubkey, witness, flags)
    }

    /// Check proof of work
    #[spec_locked("7.2")]
    pub fn check_proof_of_work(&self, header: &types::BlockHeader) -> error::Result<bool> {
        pow::check_proof_of_work(header)
    }

    /// Get block subsidy for height
    #[spec_locked("6.1")]
    pub fn get_block_subsidy(&self, height: types::Natural) -> types::Integer {
        economic::get_block_subsidy(height)
    }

    /// Calculate total supply at height
    #[spec_locked("6.2")]
    pub fn total_supply(&self, height: types::Natural) -> types::Integer {
        economic::total_supply(height)
    }

    /// Get next work required for difficulty adjustment
    #[spec_locked("7.1")]
    pub fn get_next_work_required(
        &self,
        current_header: &types::BlockHeader,
        prev_headers: &[types::BlockHeader],
    ) -> error::Result<types::Natural> {
        pow::get_next_work_required(current_header, prev_headers)
    }

    /// Accept transaction to memory pool
    #[spec_locked("9.1")]
    pub fn accept_to_memory_pool(
        &self,
        tx: &types::Transaction,
        utxo_set: &types::UtxoSet,
        mempool: &mempool::Mempool,
        height: types::Natural,
        time_context: Option<types::TimeContext>,
    ) -> error::Result<mempool::MempoolResult> {
        mempool::accept_to_memory_pool(tx, None, utxo_set, mempool, height, time_context)
    }

    /// Check if transaction is standard
    #[spec_locked("9.2")]
    pub fn is_standard_tx(&self, tx: &types::Transaction) -> error::Result<bool> {
        mempool::is_standard_tx(tx)
    }

    /// Check if transaction can replace existing one (RBF)
    #[spec_locked("9.3")]
    pub fn replacement_checks(
        &self,
        new_tx: &types::Transaction,
        existing_tx: &types::Transaction,
        utxo_set: &types::UtxoSet,
        mempool: &mempool::Mempool,
    ) -> error::Result<bool> {
        mempool::replacement_checks(new_tx, existing_tx, utxo_set, mempool)
    }

    /// Create new block from mempool transactions
    #[allow(clippy::too_many_arguments)]
    #[spec_locked("12.1")]
    pub fn create_new_block(
        &self,
        utxo_set: &types::UtxoSet,
        mempool_txs: &[types::Transaction],
        height: types::Natural,
        prev_header: &types::BlockHeader,
        prev_headers: &[types::BlockHeader],
        coinbase_script: &types::ByteString,
        coinbase_address: &types::ByteString,
    ) -> error::Result<types::Block> {
        mining::create_new_block(
            utxo_set,
            mempool_txs,
            height,
            prev_header,
            prev_headers,
            coinbase_script,
            coinbase_address,
        )
    }

    /// Mine a block by finding valid nonce
    #[spec_locked("12.3")]
    pub fn mine_block(
        &self,
        block: types::Block,
        max_attempts: types::Natural,
    ) -> error::Result<(types::Block, mining::MiningResult)> {
        mining::mine_block(block, max_attempts)
    }

    /// Create block template for mining
    #[allow(clippy::too_many_arguments)]
    #[spec_locked("12.1")]
    pub fn create_block_template(
        &self,
        utxo_set: &types::UtxoSet,
        mempool_txs: &[types::Transaction],
        height: types::Natural,
        prev_header: &types::BlockHeader,
        prev_headers: &[types::BlockHeader],
        coinbase_script: &types::ByteString,
        coinbase_address: &types::ByteString,
    ) -> error::Result<mining::BlockTemplate> {
        mining::create_block_template(
            utxo_set,
            mempool_txs,
            height,
            prev_header,
            prev_headers,
            coinbase_script,
            coinbase_address,
        )
    }

    /// Reorganize chain when longer chain is found
    #[spec_locked("11.3")]
    pub fn reorganize_chain(
        &self,
        new_chain: &[types::Block],
        current_chain: &[types::Block],
        current_utxo_set: types::UtxoSet,
        current_height: types::Natural,
        network: types::Network,
    ) -> error::Result<reorganization::ReorganizationResult> {
        reorganization::reorganize_chain(
            new_chain,
            current_chain,
            current_utxo_set,
            current_height,
            network,
        )
    }

    /// Check if reorganization is beneficial
    #[spec_locked("11.3")]
    pub fn should_reorganize(
        &self,
        new_chain: &[types::Block],
        current_chain: &[types::Block],
    ) -> error::Result<bool> {
        reorganization::should_reorganize(new_chain, current_chain)
    }

    /// Calculate transaction weight for SegWit
    #[spec_locked("11.1.1")]
    pub fn calculate_transaction_weight(
        &self,
        tx: &types::Transaction,
        witness: Option<&segwit::Witness>,
    ) -> error::Result<types::Natural> {
        segwit::calculate_transaction_weight(tx, witness)
    }

    /// Validate SegWit block
    #[spec_locked("11.1.7")]
    pub fn validate_segwit_block(
        &self,
        block: &types::Block,
        witnesses: &[segwit::Witness],
        max_block_weight: types::Natural,
    ) -> error::Result<bool> {
        segwit::validate_segwit_block(block, witnesses, max_block_weight)
    }

    /// Validate Taproot transaction
    #[spec_locked("11.2.5")]
    pub fn validate_taproot_transaction(
        &self,
        tx: &types::Transaction,
        witness: Option<&segwit::Witness>,
    ) -> error::Result<bool> {
        taproot::validate_taproot_transaction(tx, witness)
    }

    /// Check if transaction output is Taproot
    #[spec_locked("11.2.1")]
    pub fn is_taproot_output(&self, output: &types::TransactionOutput) -> bool {
        taproot::is_taproot_output(output)
    }
}

#[cfg(test)]
mod tests {
    use crate::transaction::check_transaction;
    use crate::types::Transaction;

    #[test]
    fn test_validate_transaction() {
        let tx = Transaction {
            version: 1,
            inputs: vec![].into(),
            outputs: vec![].into(),
            lock_time: 0,
        };
        let result = check_transaction(&tx);
        assert!(result.is_ok());
    }
}