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
84/// Spec-lock / property-test helpers only — not a supported production API.
85/// Functions in this module `panic!` or `unimplemented!` when called outside their
86/// intended spec-validation context. Do **not** call from production code.
87#[doc(hidden)]
88pub mod orange_paper_property_helpers;
89
90pub mod config;
91
92pub mod activation;
93pub mod bip113;
94#[cfg(feature = "ctv")]
95pub mod bip119;
96#[cfg(any(feature = "csfs", feature = "production"))]
97pub mod bip348;
98pub mod bip_validation;
99pub mod block;
100#[cfg(all(feature = "production", feature = "rayon"))]
101pub mod checkqueue;
102pub mod economic;
103pub mod locktime;
104pub mod mempool;
105pub mod mining;
106pub mod optimizations;
107pub mod pow;
108pub mod reorganization;
109#[cfg(all(feature = "production", feature = "rayon"))]
110pub(crate) mod script_exec_cache;
111pub mod secp256k1_backend;
112pub mod segwit;
113pub mod sequence_locks;
114pub mod sigop;
115pub mod taproot;
116pub mod utxo_overlay;
117pub mod version_bits;
118pub mod witness;
119
120// Integration tests link this crate without `cfg(test)` on the library, so `test_utils` cannot be
121// gated only on `test`. Fixture helpers are small; `property-tests`/`proptest` stays gated inside the module.
122pub mod test_utils;
123
124#[cfg(feature = "profile")]
125pub mod profile_log;
126#[cfg(all(feature = "production", feature = "profile"))]
127pub mod script_profile;
128
129/// Consensus Proof - wrapper struct for consensus validation functions
130///
131/// This struct provides a convenient API for accessing all consensus validation
132/// functions. All methods delegate to the corresponding module functions.
133#[derive(Debug, Clone, Copy, Default)]
134pub struct ConsensusProof;
135
136impl ConsensusProof {
137    /// Create a new ConsensusProof instance
138    pub fn new() -> Self {
139        Self
140    }
141
142    /// Validate a transaction according to consensus rules
143    #[spec_locked("5.1")]
144    pub fn validate_transaction(
145        &self,
146        tx: &types::Transaction,
147    ) -> error::Result<types::ValidationResult> {
148        transaction::check_transaction(tx)
149    }
150
151    /// Validate transaction inputs against UTXO set
152    #[spec_locked("5.1")]
153    pub fn validate_tx_inputs(
154        &self,
155        tx: &types::Transaction,
156        utxo_set: &types::UtxoSet,
157        height: types::Natural,
158    ) -> error::Result<(types::ValidationResult, types::Integer)> {
159        transaction::check_tx_inputs(tx, utxo_set, height)
160    }
161
162    /// Validate a complete block
163    #[spec_locked("5.3")]
164    pub fn validate_block(
165        &self,
166        block: &types::Block,
167        utxo_set: types::UtxoSet,
168        height: types::Natural,
169    ) -> error::Result<(types::ValidationResult, types::UtxoSet)> {
170        // Create empty witnesses for backward compatibility
171        let witnesses: Vec<Vec<segwit::Witness>> =
172            block.transactions.iter().map(|_| Vec::new()).collect();
173        let network_time = std::time::SystemTime::now()
174            .duration_since(std::time::UNIX_EPOCH)
175            .unwrap_or(std::time::Duration::ZERO)
176            .as_secs();
177        let context = block::block_validation_context_for_connect_ibd(
178            None::<&[types::BlockHeader]>,
179            network_time,
180            types::Network::Mainnet,
181        );
182        let (result, new_utxo_set, _undo_log) =
183            block::connect_block(block, &witnesses, utxo_set, height, &context)?;
184        Ok((result, new_utxo_set))
185    }
186
187    /// Validate a complete block with witness data and time context
188    #[spec_locked("5.3")]
189    pub fn validate_block_with_time_context(
190        &self,
191        block: &types::Block,
192        witnesses: &[Vec<segwit::Witness>],
193        utxo_set: types::UtxoSet,
194        height: types::Natural,
195        time_context: Option<types::TimeContext>,
196        network: types::Network,
197    ) -> error::Result<(types::ValidationResult, types::UtxoSet)> {
198        let context = block::BlockValidationContext::from_time_context_and_network(
199            time_context,
200            network,
201            None,
202        );
203        let (result, new_utxo_set, _undo_log) =
204            block::connect_block(block, witnesses, utxo_set, height, &context)?;
205        Ok((result, new_utxo_set))
206    }
207
208    /// Verify script execution
209    #[spec_locked("5.2")]
210    pub fn verify_script(
211        &self,
212        script_sig: &types::ByteString,
213        script_pubkey: &types::ByteString,
214        witness: Option<&types::ByteString>,
215        flags: u32,
216    ) -> error::Result<bool> {
217        script::verify_script(script_sig, script_pubkey, witness, flags)
218    }
219
220    /// Check proof of work
221    #[spec_locked("7.2")]
222    pub fn check_proof_of_work(&self, header: &types::BlockHeader) -> error::Result<bool> {
223        pow::check_proof_of_work(header)
224    }
225
226    /// Get block subsidy for height
227    #[spec_locked("6.1")]
228    pub fn get_block_subsidy(&self, height: types::Natural) -> types::Integer {
229        economic::get_block_subsidy(height)
230    }
231
232    /// Calculate total supply at height
233    #[spec_locked("6.2")]
234    pub fn total_supply(&self, height: types::Natural) -> types::Integer {
235        economic::total_supply(height)
236    }
237
238    /// Get next work required for difficulty adjustment
239    #[spec_locked("7.1")]
240    pub fn get_next_work_required(
241        &self,
242        current_header: &types::BlockHeader,
243        prev_headers: &[types::BlockHeader],
244    ) -> error::Result<types::Natural> {
245        pow::get_next_work_required(current_header, prev_headers)
246    }
247
248    /// Accept transaction to memory pool
249    #[spec_locked("9.1")]
250    pub fn accept_to_memory_pool(
251        &self,
252        tx: &types::Transaction,
253        utxo_set: &types::UtxoSet,
254        mempool: &mempool::Mempool,
255        height: types::Natural,
256        time_context: Option<types::TimeContext>,
257    ) -> error::Result<mempool::MempoolResult> {
258        mempool::accept_to_memory_pool(tx, None, utxo_set, mempool, height, time_context)
259    }
260
261    /// Check if transaction is standard
262    #[spec_locked("9.2")]
263    pub fn is_standard_tx(&self, tx: &types::Transaction) -> error::Result<bool> {
264        mempool::is_standard_tx(tx)
265    }
266
267    /// Check if transaction can replace existing one (RBF)
268    #[spec_locked("9.3")]
269    pub fn replacement_checks(
270        &self,
271        new_tx: &types::Transaction,
272        existing_tx: &types::Transaction,
273        utxo_set: &types::UtxoSet,
274        mempool: &mempool::Mempool,
275    ) -> error::Result<bool> {
276        mempool::replacement_checks(new_tx, existing_tx, utxo_set, mempool)
277    }
278
279    /// Create new block from mempool transactions
280    #[allow(clippy::too_many_arguments)]
281    #[spec_locked("12.1")]
282    pub fn create_new_block(
283        &self,
284        utxo_set: &types::UtxoSet,
285        mempool_txs: &[types::Transaction],
286        height: types::Natural,
287        prev_header: &types::BlockHeader,
288        prev_headers: &[types::BlockHeader],
289        coinbase_script: &types::ByteString,
290        coinbase_address: &types::ByteString,
291    ) -> error::Result<types::Block> {
292        mining::create_new_block(
293            utxo_set,
294            mempool_txs,
295            height,
296            prev_header,
297            prev_headers,
298            coinbase_script,
299            coinbase_address,
300        )
301    }
302
303    /// Mine a block by finding valid nonce
304    #[spec_locked("12.3")]
305    pub fn mine_block(
306        &self,
307        block: types::Block,
308        max_attempts: types::Natural,
309    ) -> error::Result<(types::Block, mining::MiningResult)> {
310        mining::mine_block(block, max_attempts)
311    }
312
313    /// Create block template for mining
314    #[allow(clippy::too_many_arguments)]
315    #[spec_locked("12.1")]
316    pub fn create_block_template(
317        &self,
318        utxo_set: &types::UtxoSet,
319        mempool_txs: &[types::Transaction],
320        height: types::Natural,
321        prev_header: &types::BlockHeader,
322        prev_headers: &[types::BlockHeader],
323        coinbase_script: &types::ByteString,
324        coinbase_address: &types::ByteString,
325    ) -> error::Result<mining::BlockTemplate> {
326        mining::create_block_template(
327            utxo_set,
328            mempool_txs,
329            height,
330            prev_header,
331            prev_headers,
332            coinbase_script,
333            coinbase_address,
334        )
335    }
336
337    /// Reorganize chain when longer chain is found
338    #[spec_locked("11.3")]
339    pub fn reorganize_chain(
340        &self,
341        new_chain: &[types::Block],
342        current_chain: &[types::Block],
343        current_utxo_set: types::UtxoSet,
344        current_height: types::Natural,
345        network: types::Network,
346    ) -> error::Result<reorganization::ReorganizationResult> {
347        reorganization::reorganize_chain(
348            new_chain,
349            current_chain,
350            current_utxo_set,
351            current_height,
352            network,
353        )
354    }
355
356    /// Check if reorganization is beneficial
357    #[spec_locked("11.3")]
358    pub fn should_reorganize(
359        &self,
360        new_chain: &[types::Block],
361        current_chain: &[types::Block],
362    ) -> error::Result<bool> {
363        reorganization::should_reorganize(new_chain, current_chain)
364    }
365
366    /// Calculate transaction weight for SegWit
367    #[spec_locked("11.1.1")]
368    pub fn calculate_transaction_weight(
369        &self,
370        tx: &types::Transaction,
371        witness: Option<&segwit::Witness>,
372    ) -> error::Result<types::Natural> {
373        segwit::calculate_transaction_weight(tx, witness)
374    }
375
376    /// Validate SegWit block
377    #[spec_locked("11.1.7")]
378    pub fn validate_segwit_block(
379        &self,
380        block: &types::Block,
381        witnesses: &[segwit::Witness],
382        max_block_weight: types::Natural,
383    ) -> error::Result<bool> {
384        segwit::validate_segwit_block(block, witnesses, max_block_weight)
385    }
386
387    /// Validate Taproot transaction
388    #[spec_locked("11.2.5")]
389    pub fn validate_taproot_transaction(
390        &self,
391        tx: &types::Transaction,
392        witness: Option<&segwit::Witness>,
393    ) -> error::Result<bool> {
394        taproot::validate_taproot_transaction(tx, witness)
395    }
396
397    /// Check if transaction output is Taproot
398    #[spec_locked("11.2.1")]
399    pub fn is_taproot_output(&self, output: &types::TransactionOutput) -> bool {
400        taproot::is_taproot_output(output)
401    }
402}
403
404#[cfg(test)]
405mod tests {
406    use super::*;
407    use crate::transaction::check_transaction;
408    use crate::types::Transaction;
409
410    #[test]
411    fn test_validate_transaction() {
412        let tx = Transaction {
413            version: 1,
414            inputs: vec![].into(),
415            outputs: vec![].into(),
416            lock_time: 0,
417        };
418        let result = check_transaction(&tx);
419        assert!(result.is_ok());
420    }
421}