Skip to main content

blvm_consensus/
lib.rs

1//! # Consensus-Proof
2//!
3//! Direct mathematical implementation of Bitcoin consensus rules from the Orange Paper.
4//!
5//! This crate provides pure, side-effect-free functions that implement the mathematical
6//! specifications defined in the Orange Paper. It serves as the mathematical foundation
7//! for Bitcoin consensus validation.
8//!
9//! ## Architecture
10//!
11//! The system follows a layered architecture:
12//! - Orange Paper (mathematical specifications)
13//! - Consensus Proof (this crate - direct implementation)
14//! - Reference Node (minimal Bitcoin implementation)
15//! - Developer SDK (developer-friendly interface)
16//!
17//! ## Design Principles
18//!
19//! 1. **Pure Functions**: All functions are deterministic and side-effect-free
20//! 2. **Mathematical Accuracy**: Direct implementation of Orange Paper specifications
21//! 3. **Exact Version Pinning**: All consensus-critical dependencies pinned to exact versions
22//! 4. **No Consensus Rule Interpretation**: Only mathematical implementation
23//!
24//! ## Usage
25//!
26//! ```rust
27//! use blvm_consensus::transaction::check_transaction;
28//! use blvm_consensus::types::*;
29//!
30//! let transaction = Transaction {
31//!     version: 1,
32//!     inputs: vec![].into(),
33//!     outputs: vec![TransactionOutput {
34//!         value: 1000,
35//!         script_pubkey: vec![0x51],
36//!     }]
37//!     .into(),
38//!     lock_time: 0,
39//! };
40//! let result = check_transaction(&transaction).unwrap();
41//! ```
42
43#![allow(unused_doc_comments)] // Allow doc comments before macros (proptest, etc.)
44#![allow(unused_variables, unused_assignments, dead_code)] // Many paths are feature-gated or used conditionally
45#![allow(
46    clippy::too_many_arguments,  // Script/block have 8–17 args; struct refactor is large
47    clippy::type_complexity,     // Performance-critical types (OnceLock<RwLock<LruCache<...>>>)
48    clippy::large_enum_variant,  // NetworkResponse::SendMessage; boxing changes layout
49)]
50
51pub mod script;
52pub mod transaction;
53pub mod transaction_hash;
54
55use blvm_spec_lock::spec_locked;
56#[cfg(all(feature = "production", feature = "benchmarking"))]
57pub use config::{reset_assume_valid_height, set_assume_valid_height};
58#[cfg(feature = "production")]
59pub use script::batch_verify_signatures;
60#[cfg(all(feature = "production", feature = "benchmarking"))]
61pub use script::{
62    clear_all_caches, clear_hash_cache, clear_script_cache, clear_stack_pool, disable_caching,
63    reset_benchmarking_state,
64};
65#[cfg(all(feature = "production", feature = "benchmarking"))]
66pub use transaction_hash::clear_sighash_templates;
67
68// Re-export from blvm-primitives for backward compatibility
69pub use blvm_primitives::constants;
70pub use blvm_primitives::crypto;
71pub use blvm_primitives::opcodes;
72pub use blvm_primitives::serialization;
73pub use blvm_primitives::{error, types};
74pub use blvm_primitives::{tx_inputs, tx_outputs};
75pub use constants::*;
76pub use error::ConsensusError;
77pub use types::*;
78
79/// Orange Paper Section 4 symbols (C, H, M_MAX, etc.) — re-export from primitives constants.
80pub mod orange_paper_constants {
81    pub use crate::constants::{C, H, L_ELEMENT, L_OPS, L_SCRIPT, L_STACK, M_MAX, R, S_MAX, W_MAX};
82}
83
84pub mod orange_paper_property_helpers;
85
86pub mod config;
87
88pub mod activation;
89pub mod bip113;
90#[cfg(feature = "ctv")]
91pub mod bip119;
92#[cfg(any(feature = "csfs", feature = "production"))]
93pub mod bip348;
94pub mod bip_validation;
95pub mod block;
96#[cfg(all(feature = "production", feature = "rayon"))]
97pub mod checkqueue;
98pub mod economic;
99pub mod locktime;
100pub mod mempool;
101pub mod mining;
102pub mod optimizations;
103pub mod pow;
104pub mod reorganization;
105#[cfg(all(feature = "production", feature = "rayon"))]
106pub(crate) mod script_exec_cache;
107pub mod secp256k1_backend;
108pub mod segwit;
109pub mod sequence_locks;
110pub mod sigop;
111pub mod taproot;
112pub mod utxo_overlay;
113pub mod version_bits;
114pub mod witness;
115
116// Integration tests link this crate without `cfg(test)` on the library, so `test_utils` cannot be
117// gated only on `test`. Fixture helpers are small; `property-tests`/`proptest` stays gated inside the module.
118pub mod test_utils;
119
120#[cfg(feature = "profile")]
121pub mod profile_log;
122#[cfg(all(feature = "production", feature = "profile"))]
123pub mod script_profile;
124
125/// Consensus Proof - wrapper struct for consensus validation functions
126///
127/// This struct provides a convenient API for accessing all consensus validation
128/// functions. All methods delegate to the corresponding module functions.
129#[derive(Debug, Clone, Copy, Default)]
130pub struct ConsensusProof;
131
132impl ConsensusProof {
133    /// Create a new ConsensusProof instance
134    pub fn new() -> Self {
135        Self
136    }
137
138    /// Validate a transaction according to consensus rules
139    #[spec_locked("5.1")]
140    pub fn validate_transaction(
141        &self,
142        tx: &types::Transaction,
143    ) -> error::Result<types::ValidationResult> {
144        transaction::check_transaction(tx)
145    }
146
147    /// Validate transaction inputs against UTXO set
148    #[spec_locked("5.1")]
149    pub fn validate_tx_inputs(
150        &self,
151        tx: &types::Transaction,
152        utxo_set: &types::UtxoSet,
153        height: types::Natural,
154    ) -> error::Result<(types::ValidationResult, types::Integer)> {
155        transaction::check_tx_inputs(tx, utxo_set, height)
156    }
157
158    /// Validate a complete block
159    #[spec_locked("5.3")]
160    pub fn validate_block(
161        &self,
162        block: &types::Block,
163        utxo_set: types::UtxoSet,
164        height: types::Natural,
165    ) -> error::Result<(types::ValidationResult, types::UtxoSet)> {
166        // Create empty witnesses for backward compatibility
167        let witnesses: Vec<Vec<segwit::Witness>> =
168            block.transactions.iter().map(|_| Vec::new()).collect();
169        let network_time = std::time::SystemTime::now()
170            .duration_since(std::time::UNIX_EPOCH)
171            .unwrap()
172            .as_secs();
173        let context = block::BlockValidationContext::from_connect_block_ibd_args(
174            None::<&[types::BlockHeader]>,
175            network_time,
176            types::Network::Mainnet,
177            None,
178            None,
179        );
180        let (result, new_utxo_set, _undo_log) =
181            block::connect_block(block, &witnesses, utxo_set, height, &context)?;
182        Ok((result, new_utxo_set))
183    }
184
185    /// Validate a complete block with witness data and time context
186    #[spec_locked("5.3")]
187    pub fn validate_block_with_time_context(
188        &self,
189        block: &types::Block,
190        witnesses: &[Vec<segwit::Witness>],
191        utxo_set: types::UtxoSet,
192        height: types::Natural,
193        time_context: Option<types::TimeContext>,
194        network: types::Network,
195    ) -> error::Result<(types::ValidationResult, types::UtxoSet)> {
196        let context = block::BlockValidationContext::from_time_context_and_network(
197            time_context,
198            network,
199            None,
200        );
201        let (result, new_utxo_set, _undo_log) =
202            block::connect_block(block, witnesses, utxo_set, height, &context)?;
203        Ok((result, new_utxo_set))
204    }
205
206    /// Verify script execution
207    #[spec_locked("5.2")]
208    pub fn verify_script(
209        &self,
210        script_sig: &types::ByteString,
211        script_pubkey: &types::ByteString,
212        witness: Option<&types::ByteString>,
213        flags: u32,
214    ) -> error::Result<bool> {
215        script::verify_script(script_sig, script_pubkey, witness, flags)
216    }
217
218    /// Check proof of work
219    #[spec_locked("7.2")]
220    pub fn check_proof_of_work(&self, header: &types::BlockHeader) -> error::Result<bool> {
221        pow::check_proof_of_work(header)
222    }
223
224    /// Get block subsidy for height
225    #[spec_locked("6.1")]
226    pub fn get_block_subsidy(&self, height: types::Natural) -> types::Integer {
227        economic::get_block_subsidy(height)
228    }
229
230    /// Calculate total supply at height
231    #[spec_locked("6.2")]
232    pub fn total_supply(&self, height: types::Natural) -> types::Integer {
233        economic::total_supply(height)
234    }
235
236    /// Get next work required for difficulty adjustment
237    #[spec_locked("7.1")]
238    pub fn get_next_work_required(
239        &self,
240        current_header: &types::BlockHeader,
241        prev_headers: &[types::BlockHeader],
242    ) -> error::Result<types::Natural> {
243        pow::get_next_work_required(current_header, prev_headers)
244    }
245
246    /// Accept transaction to memory pool
247    #[spec_locked("9.1")]
248    pub fn accept_to_memory_pool(
249        &self,
250        tx: &types::Transaction,
251        utxo_set: &types::UtxoSet,
252        mempool: &mempool::Mempool,
253        height: types::Natural,
254        time_context: Option<types::TimeContext>,
255    ) -> error::Result<mempool::MempoolResult> {
256        mempool::accept_to_memory_pool(tx, None, utxo_set, mempool, height, time_context)
257    }
258
259    /// Check if transaction is standard
260    #[spec_locked("9.2")]
261    pub fn is_standard_tx(&self, tx: &types::Transaction) -> error::Result<bool> {
262        mempool::is_standard_tx(tx)
263    }
264
265    /// Check if transaction can replace existing one (RBF)
266    #[spec_locked("9.3")]
267    pub fn replacement_checks(
268        &self,
269        new_tx: &types::Transaction,
270        existing_tx: &types::Transaction,
271        utxo_set: &types::UtxoSet,
272        mempool: &mempool::Mempool,
273    ) -> error::Result<bool> {
274        mempool::replacement_checks(new_tx, existing_tx, utxo_set, mempool)
275    }
276
277    /// Create new block from mempool transactions
278    #[allow(clippy::too_many_arguments)]
279    #[spec_locked("12.1")]
280    pub fn create_new_block(
281        &self,
282        utxo_set: &types::UtxoSet,
283        mempool_txs: &[types::Transaction],
284        height: types::Natural,
285        prev_header: &types::BlockHeader,
286        prev_headers: &[types::BlockHeader],
287        coinbase_script: &types::ByteString,
288        coinbase_address: &types::ByteString,
289    ) -> error::Result<types::Block> {
290        mining::create_new_block(
291            utxo_set,
292            mempool_txs,
293            height,
294            prev_header,
295            prev_headers,
296            coinbase_script,
297            coinbase_address,
298        )
299    }
300
301    /// Mine a block by finding valid nonce
302    #[spec_locked("12.3")]
303    pub fn mine_block(
304        &self,
305        block: types::Block,
306        max_attempts: types::Natural,
307    ) -> error::Result<(types::Block, mining::MiningResult)> {
308        mining::mine_block(block, max_attempts)
309    }
310
311    /// Create block template for mining
312    #[allow(clippy::too_many_arguments)]
313    #[spec_locked("12.1")]
314    pub fn create_block_template(
315        &self,
316        utxo_set: &types::UtxoSet,
317        mempool_txs: &[types::Transaction],
318        height: types::Natural,
319        prev_header: &types::BlockHeader,
320        prev_headers: &[types::BlockHeader],
321        coinbase_script: &types::ByteString,
322        coinbase_address: &types::ByteString,
323    ) -> error::Result<mining::BlockTemplate> {
324        mining::create_block_template(
325            utxo_set,
326            mempool_txs,
327            height,
328            prev_header,
329            prev_headers,
330            coinbase_script,
331            coinbase_address,
332        )
333    }
334
335    /// Reorganize chain when longer chain is found
336    #[spec_locked("11.3")]
337    pub fn reorganize_chain(
338        &self,
339        new_chain: &[types::Block],
340        current_chain: &[types::Block],
341        current_utxo_set: types::UtxoSet,
342        current_height: types::Natural,
343        network: types::Network,
344    ) -> error::Result<reorganization::ReorganizationResult> {
345        reorganization::reorganize_chain(
346            new_chain,
347            current_chain,
348            current_utxo_set,
349            current_height,
350            network,
351        )
352    }
353
354    /// Check if reorganization is beneficial
355    #[spec_locked("11.3")]
356    pub fn should_reorganize(
357        &self,
358        new_chain: &[types::Block],
359        current_chain: &[types::Block],
360    ) -> error::Result<bool> {
361        reorganization::should_reorganize(new_chain, current_chain)
362    }
363
364    /// Calculate transaction weight for SegWit
365    #[spec_locked("11.1.1")]
366    pub fn calculate_transaction_weight(
367        &self,
368        tx: &types::Transaction,
369        witness: Option<&segwit::Witness>,
370    ) -> error::Result<types::Natural> {
371        segwit::calculate_transaction_weight(tx, witness)
372    }
373
374    /// Validate SegWit block
375    #[spec_locked("11.1.7")]
376    pub fn validate_segwit_block(
377        &self,
378        block: &types::Block,
379        witnesses: &[segwit::Witness],
380        max_block_weight: types::Natural,
381    ) -> error::Result<bool> {
382        segwit::validate_segwit_block(block, witnesses, max_block_weight)
383    }
384
385    /// Validate Taproot transaction
386    #[spec_locked("11.2.5")]
387    pub fn validate_taproot_transaction(
388        &self,
389        tx: &types::Transaction,
390        witness: Option<&segwit::Witness>,
391    ) -> error::Result<bool> {
392        taproot::validate_taproot_transaction(tx, witness)
393    }
394
395    /// Check if transaction output is Taproot
396    #[spec_locked("11.2.1")]
397    pub fn is_taproot_output(&self, output: &types::TransactionOutput) -> bool {
398        taproot::is_taproot_output(output)
399    }
400}
401
402#[cfg(test)]
403mod tests {
404    use super::*;
405    use crate::transaction::check_transaction;
406    use crate::types::Transaction;
407
408    #[test]
409    fn test_validate_transaction() {
410        let tx = Transaction {
411            version: 1,
412            inputs: vec![].into(),
413            outputs: vec![].into(),
414            lock_time: 0,
415        };
416        let result = check_transaction(&tx);
417        assert!(result.is_ok());
418    }
419}