Skip to main content

blvm_protocol/
lib.rs

1//! Bitcoin Protocol Engine
2//!
3//! This crate provides a Bitcoin protocol abstraction layer that enables:
4//! - Multiple Bitcoin variants (mainnet, testnet, regtest, educational)
5//! - Protocol evolution support (Bitcoin V1, V2, etc.)
6//! - Economic model abstraction (PoW, future variants)
7//! - Educational and research-friendly interfaces
8//!
9//! This is Tier 3 of the 5-tier BTCDecoded architecture:
10//!
11//! 1. Orange Paper (mathematical foundation)
12//! 2. blvm-consensus (pure math implementation)
13//! 3. blvm-protocol (Bitcoin abstraction) ← THIS CRATE
14//! 4. blvm-node (full Bitcoin node)
15//! 5. blvm-sdk (ergonomic API)
16
17use serde::{Deserialize, Serialize};
18
19// Re-export commonly used types for convenience
20// This allows upper layers (like blvm-node) to depend only on blvm-protocol
21pub use blvm_consensus::config::NetworkMessageLimits;
22pub use blvm_consensus::error::{ConsensusError, Result as ConsensusResult};
23pub use blvm_consensus::types::{
24    Block, BlockHeader, ByteString, Hash, Integer, Natural, OutPoint, Transaction,
25    TransactionInput, TransactionOutput, UtxoSet, ValidationResult, Witness, UTXO,
26};
27pub use blvm_consensus::ConsensusProof;
28
29#[cfg(all(feature = "production", feature = "benchmarking"))]
30pub use blvm_consensus::config::{reset_assume_valid_height, set_assume_valid_height};
31/// Buried deployment heights (Core chainparams) for RPC / tooling without a direct `blvm-consensus` dep.
32pub use blvm_consensus::{
33    BIP112_CSV_ACTIVATION_MAINNET, BIP112_CSV_ACTIVATION_REGTEST, BIP112_CSV_ACTIVATION_TESTNET,
34    GENESIS_BLOCK_HASH_INTERNAL, SEGWIT_ACTIVATION_MAINNET, SEGWIT_ACTIVATION_TESTNET,
35    TAPROOT_ACTIVATION_MAINNET, TAPROOT_ACTIVATION_TESTNET,
36};
37
38// Re-export smallvec for macro use when production feature is enabled
39#[cfg(feature = "production")]
40pub use smallvec;
41// Re-export lru and rayon for production caches and parallel validation
42#[cfg(feature = "production")]
43pub use lru;
44#[cfg(feature = "production")]
45pub use rayon;
46
47/// Forwards to `blvm_consensus::profile_log!` so upper layers avoid naming `blvm-consensus` directly.
48/// When the `profile` feature is off on consensus, the inner macro expands to a no-op.
49#[macro_export]
50macro_rules! profile_log {
51    ($($arg:tt)*) => {
52        ::blvm_consensus::profile_log!($($arg)*)
53    };
54}
55
56// Protocol-specific Result type
57pub use error::{ProtocolError, Result};
58
59// Re-export commonly used modules
60pub mod mempool {
61    pub use blvm_consensus::mempool::*;
62}
63pub mod segwit {
64    pub use blvm_consensus::segwit::*;
65}
66pub mod block {
67    pub use blvm_consensus::block::*;
68
69    use crate::types::{BlockHeader, Network};
70
71    /// Forwards to [`BlockValidationContext::from_connect_block_ibd_args`] with no BIP54 activation
72    /// override and no boundary timestamps. Does not invent time or headers; pass the same values
73    /// you would pass to the underlying constructor.
74    #[inline]
75    pub fn block_validation_context_for_connect_ibd<H: AsRef<BlockHeader>>(
76        recent_headers: Option<&[H]>,
77        network_time: u64,
78        network: Network,
79    ) -> BlockValidationContext {
80        BlockValidationContext::from_connect_block_ibd_args(
81            recent_headers,
82            network_time,
83            network,
84            None,
85            None,
86        )
87    }
88}
89pub mod mining {
90    pub use blvm_consensus::mining::*;
91}
92pub mod pow {
93    pub use blvm_consensus::pow::*;
94}
95
96pub mod witness {
97    pub use blvm_consensus::witness::*;
98}
99
100pub mod crypto {
101    pub use blvm_consensus::crypto::*;
102}
103
104pub mod transaction {
105    pub use blvm_consensus::transaction::*;
106}
107
108/// Script interpreter (consensus). Exposed so benches/node avoid a direct `blvm-consensus` dep where possible.
109pub mod script {
110    pub use blvm_consensus::script::*;
111}
112
113/// Transaction sighash / txid helpers from consensus.
114pub mod transaction_hash {
115    pub use blvm_consensus::transaction_hash::*;
116}
117
118/// Production-only batch hashing, preallocation, and related optimization helpers from consensus.
119#[cfg(feature = "production")]
120pub mod optimizations {
121    pub use blvm_consensus::optimizations::*;
122}
123
124/// Consensus constants (`blvm-primitives` / Orange Paper symbols) — same as `blvm_consensus::constants`.
125pub mod constants {
126    pub use blvm_consensus::constants::*;
127}
128
129pub mod bip113 {
130    pub use blvm_consensus::bip113::*;
131}
132
133pub mod bip_validation {
134    pub use blvm_consensus::bip_validation::*;
135}
136
137pub mod utxo_overlay {
138    pub use blvm_consensus::utxo_overlay::*;
139}
140
141pub mod version_bits {
142    pub use blvm_consensus::version_bits::*;
143}
144
145pub mod activation {
146    pub use blvm_consensus::activation::*;
147}
148
149/// Consensus runtime configuration from `blvm-consensus` (distinct from this crate's [`config`] module).
150pub mod consensus_config {
151    pub use blvm_consensus::config::*;
152}
153
154#[cfg(feature = "test-utils")]
155pub mod test_utils {
156    pub use blvm_consensus::test_utils::*;
157}
158
159/// Script opcodes (re-exported from consensus / primitives) for callers that should not name `blvm-consensus` directly.
160pub use blvm_consensus::opcodes;
161
162pub mod sigop {
163    pub use blvm_consensus::sigop::*;
164}
165
166#[cfg(feature = "utxo-commitments")]
167pub mod utxo_commitments;
168
169// Spam filter is always available (not behind utxo-commitments feature)
170pub mod spam_filter;
171pub mod serialization {
172    pub use blvm_consensus::serialization::*;
173}
174pub mod commons;
175pub mod network;
176/// Framed TCP P2P (mainnet magic, command allowlist supplied by the node). Not BIP324 v2 transport.
177pub mod node_tcp;
178
179pub use node_tcp::{ProtocolMessage, TcpFramedParser};
180pub mod p2p_commands;
181pub mod p2p_frame;
182pub mod p2p_framing;
183pub mod service_flags;
184pub mod varint;
185
186// BIP324: v2 encrypted transport
187#[cfg(all(
188    feature = "bip324",
189    any(target_arch = "x86_64", target_arch = "aarch64")
190))]
191pub mod v2_transport;
192
193// Re-export commonly used types for convenience
194pub use commons::{
195    BanListMessage,
196    // Filtered block types
197    FilterPreferences,
198    // Commons-only types kept in blvm-protocol for bridge layers
199    FilteredBlockMessage,
200    GetBanListMessage,
201    GetFilteredBlockMessage,
202    // UTXO proof types
203    GetUTXOProofMessage,
204    GetUTXOSetMessage,
205    // UTXO commitment protocol types
206    UTXOCommitment,
207    UTXOProofMessage,
208    UTXOSetMessage,
209};
210pub use config::{
211    ProtocolConfig, ProtocolFeaturesConfig, ProtocolValidationConfig, ServiceFlagsConfig,
212};
213pub use network::{BlockMessage, CompactBlockMessage, TxMessage};
214pub use service_flags::{commons as service_flags_commons, standard as service_flags_standard};
215// Wire format module - Bitcoin P2P wire protocol serialization
216pub mod wire;
217
218#[cfg(test)]
219mod bip155_serialization_tests;
220pub mod types {
221    pub use blvm_consensus::types::*;
222}
223// Re-export macros from blvm-consensus for convenience
224#[cfg(feature = "production")]
225pub use blvm_consensus::tx_inputs;
226#[cfg(not(feature = "production"))]
227pub use blvm_consensus::tx_inputs;
228#[cfg(feature = "production")]
229pub use blvm_consensus::tx_outputs;
230#[cfg(not(feature = "production"))]
231pub use blvm_consensus::tx_outputs;
232pub mod error;
233
234// Re-export feature and economic modules for convenience
235pub use economic::EconomicParameters;
236pub use features::{ActivationMethod, FeatureActivation, FeatureContext, FeatureRegistry};
237
238pub mod config;
239pub mod economic;
240pub mod features;
241pub mod genesis;
242pub mod network_params;
243pub mod validation;
244pub mod variants;
245
246// Protocol-level BIP implementations
247pub mod address; // BIP173/350/351: Bech32/Bech32m address encoding
248#[cfg(feature = "ctv")]
249pub mod bip119 {
250    pub use blvm_consensus::bip119::*;
251}
252pub mod bip152; // BIP152: Compact block relay (wire types)
253pub mod bip157; // BIP157: Client-side block filtering network protocol
254pub mod bip158; // BIP158: Compact block filters
255pub mod payment; // BIP70: Payment protocol (P2P variant)
256pub mod time;
257
258/// Bitcoin Protocol Engine
259///
260/// Provides protocol abstraction for different Bitcoin variants and evolution.
261/// Acts as a bridge between blvm-consensus (pure math) and blvm-node (implementation).
262pub struct BitcoinProtocolEngine {
263    consensus: ConsensusProof,
264    protocol_version: ProtocolVersion,
265    network_params: NetworkParameters,
266    config: ProtocolConfig,
267}
268
269/// Bitcoin protocol versions
270#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
271pub enum ProtocolVersion {
272    /// Current Bitcoin mainnet protocol
273    BitcoinV1,
274    /// Bitcoin testnet protocol
275    Testnet3,
276    /// Regression test network protocol
277    Regtest,
278}
279
280/// Network parameters for different Bitcoin variants
281#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
282pub struct NetworkParameters {
283    /// Network magic bytes for P2P protocol
284    pub magic_bytes: [u8; 4],
285    /// Default P2P port
286    pub default_port: u16,
287    /// Genesis block for this network
288    pub genesis_block: Block,
289    /// Maximum proof-of-work target
290    pub max_target: u32,
291    /// Block subsidy halving interval
292    pub halving_interval: u64,
293    /// Network name for identification
294    pub network_name: String,
295    /// Whether this is a test network
296    pub is_testnet: bool,
297}
298
299impl BitcoinProtocolEngine {
300    /// Create a new protocol engine for the specified variant with default configuration
301    pub fn new(version: ProtocolVersion) -> Result<Self> {
302        Self::with_config(version, ProtocolConfig::default())
303    }
304
305    /// Create a new protocol engine with custom configuration
306    pub fn with_config(version: ProtocolVersion, config: ProtocolConfig) -> Result<Self> {
307        let consensus = ConsensusProof::new();
308        let network_params = NetworkParameters::for_version(version)?;
309
310        Ok(BitcoinProtocolEngine {
311            consensus,
312            protocol_version: version,
313            network_params,
314            config,
315        })
316    }
317
318    /// Get the protocol configuration
319    pub fn get_config(&self) -> &ProtocolConfig {
320        &self.config
321    }
322
323    /// Get mutable reference to protocol configuration
324    pub fn get_config_mut(&mut self) -> &mut ProtocolConfig {
325        &mut self.config
326    }
327
328    /// Get the current protocol version
329    pub fn get_protocol_version(&self) -> ProtocolVersion {
330        self.protocol_version
331    }
332
333    /// Get network parameters for this protocol
334    pub fn get_network_params(&self) -> &NetworkParameters {
335        &self.network_params
336    }
337
338    /// Validate a block using this protocol's rules
339    pub fn validate_block(
340        &self,
341        block: &Block,
342        utxos: &UtxoSet,
343        height: u64,
344    ) -> Result<ValidationResult> {
345        let network = match self.protocol_version {
346            ProtocolVersion::BitcoinV1 => types::Network::Mainnet,
347            ProtocolVersion::Testnet3 => types::Network::Testnet,
348            ProtocolVersion::Regtest => types::Network::Regtest,
349        };
350        let witnesses: Vec<Vec<blvm_consensus::segwit::Witness>> = block
351            .transactions
352            .iter()
353            .map(|tx| tx.inputs.iter().map(|_| Vec::new()).collect())
354            .collect();
355        let (result, _) = self
356            .consensus
357            .validate_block_with_time_context(
358                block,
359                &witnesses,
360                utxos.clone(),
361                height,
362                None,
363                network,
364            )
365            .map_err(ProtocolError::from)?;
366        Ok(result)
367    }
368
369    /// Validate a transaction using this protocol's rules
370    pub fn validate_transaction(&self, tx: &Transaction) -> Result<ValidationResult> {
371        self.consensus
372            .validate_transaction(tx)
373            .map_err(ProtocolError::from)
374    }
375
376    /// Validate block with protocol rules and update UTXO set
377    ///
378    /// This method combines protocol validation (size limits, feature flags)
379    /// with consensus validation and UTXO set updates. This is the recommended
380    /// method for node implementations that need both validation and state updates.
381    ///
382    /// # Arguments
383    ///
384    /// * `block` - The block to validate and connect
385    /// * `witnesses` - Witness data for each transaction in the block
386    /// * `utxos` - Current UTXO set (will be cloned, not mutated)
387    /// * `height` - Current block height
388    /// * `recent_headers` - Optional recent block headers for median time-past calculation (BIP113)
389    /// * `context` - Protocol validation context
390    ///
391    /// # Returns
392    ///
393    /// Returns `(ValidationResult, UtxoSet)` where:
394    /// - `ValidationResult` indicates if the block is valid
395    /// - `UtxoSet` is the updated UTXO set after applying the block's transactions
396    ///
397    /// # Example
398    ///
399    /// ```rust,no_run
400    /// use blvm_protocol::{BitcoinProtocolEngine, ProtocolVersion};
401    /// use blvm_protocol::validation::ProtocolValidationContext;
402    /// use blvm_protocol::{Block, UtxoSet};
403    ///
404    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
405    /// let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1)?;
406    /// let context = ProtocolValidationContext::new(ProtocolVersion::BitcoinV1, 0)?;
407    /// // Create a test block
408    /// let block = Block {
409    ///     header: blvm_consensus::BlockHeader {
410    ///         version: 1,
411    ///         prev_block_hash: [0u8; 32],
412    ///         merkle_root: [0u8; 32],
413    ///         timestamp: 1231006505,
414    ///         bits: 0x1d00ffff,
415    ///         nonce: 0,
416    ///     },
417    ///     transactions: vec![].into_boxed_slice(),
418    /// };
419    /// let witnesses = vec![];
420    /// let utxos = UtxoSet::default();
421    ///
422    /// let (result, new_utxo_set) = engine.validate_and_connect_block(
423    ///     &block,
424    ///     &witnesses,
425    ///     &utxos,
426    ///     0,
427    ///     None,
428    ///     &context,
429    /// )?;
430    /// # Ok(())
431    /// # }
432    /// ```
433    pub fn validate_and_connect_block(
434        &self,
435        block: &Block,
436        witnesses: &[Vec<segwit::Witness>], // CRITICAL FIX: Changed from &[Witness] to &[Vec<Witness>]
437        // witnesses is now Vec<Vec<Witness>> where each Vec<Witness> is for one transaction
438        // and each Witness is for one input
439        utxos: &UtxoSet,
440        height: u64,
441        recent_headers: Option<&[BlockHeader]>,
442        context: &validation::ProtocolValidationContext,
443    ) -> Result<(ValidationResult, UtxoSet)> {
444        // First, protocol validation (size limits, feature flags)
445        let protocol_result = self.validate_block_with_protocol(block, utxos, height, context)?;
446        if !matches!(protocol_result, ValidationResult::Valid) {
447            return Ok((protocol_result, utxos.clone()));
448        }
449
450        // Then, consensus validation with UTXO update
451        // Convert protocol version to network type
452        let network = match self.protocol_version {
453            ProtocolVersion::BitcoinV1 => types::Network::Mainnet,
454            ProtocolVersion::Testnet3 => types::Network::Testnet,
455            ProtocolVersion::Regtest => types::Network::Regtest,
456        };
457        let network_time = crate::time::current_timestamp();
458        let context = crate::block::block_validation_context_for_connect_ibd(
459            recent_headers,
460            network_time,
461            network,
462        );
463        let (result, new_utxo_set, _undo_log) = blvm_consensus::block::connect_block(
464            block,
465            witnesses,
466            utxos.clone(),
467            height,
468            &context,
469        )?;
470
471        Ok((result, new_utxo_set))
472    }
473
474    /// Check if this protocol supports a specific feature
475    pub fn supports_feature(&self, feature: &str) -> bool {
476        match self.protocol_version {
477            ProtocolVersion::BitcoinV1 => {
478                matches!(feature, "segwit" | "taproot" | "rbf" | "ctv")
479            }
480            ProtocolVersion::Testnet3 => {
481                matches!(feature, "segwit" | "taproot" | "rbf" | "ctv")
482            }
483            ProtocolVersion::Regtest => {
484                matches!(
485                    feature,
486                    "segwit" | "taproot" | "rbf" | "ctv" | "fast_mining"
487                )
488            }
489        }
490    }
491
492    /// Check if a feature is active at a specific block height and timestamp
493    pub fn is_feature_active(&self, feature: &str, height: u64, timestamp: u64) -> bool {
494        let registry = features::FeatureRegistry::for_protocol(self.protocol_version);
495        registry.is_feature_active(feature, height, timestamp)
496    }
497
498    /// Get economic parameters for this protocol
499    pub fn get_economic_parameters(&self) -> economic::EconomicParameters {
500        economic::EconomicParameters::for_protocol(self.protocol_version)
501    }
502
503    /// Get feature activation registry for this protocol
504    pub fn get_feature_registry(&self) -> features::FeatureRegistry {
505        features::FeatureRegistry::for_protocol(self.protocol_version)
506    }
507
508    /// Create a feature context for a specific block height and timestamp
509    /// This consolidates all feature activation checks into a single context
510    pub fn feature_context(&self, height: u64, timestamp: u64) -> features::FeatureContext {
511        let registry = features::FeatureRegistry::for_protocol(self.protocol_version);
512        registry.create_context(height, timestamp)
513    }
514}
515
516impl NetworkParameters {
517    /// Create network parameters for a specific protocol version
518    pub fn for_version(version: ProtocolVersion) -> Result<Self> {
519        match version {
520            ProtocolVersion::BitcoinV1 => Self::mainnet(),
521            ProtocolVersion::Testnet3 => Self::testnet(),
522            ProtocolVersion::Regtest => Self::regtest(),
523        }
524    }
525
526    /// Bitcoin mainnet parameters
527    pub fn mainnet() -> Result<Self> {
528        Ok(NetworkParameters {
529            magic_bytes: [0xf9, 0xbe, 0xb4, 0xd9], // Bitcoin mainnet magic
530            default_port: 8333,
531            genesis_block: genesis::mainnet_genesis(),
532            max_target: 0x1d00ffff,
533            halving_interval: 210000,
534            network_name: "mainnet".to_string(),
535            is_testnet: false,
536        })
537    }
538
539    /// Bitcoin testnet parameters
540    pub fn testnet() -> Result<Self> {
541        Ok(NetworkParameters {
542            magic_bytes: [0x0b, 0x11, 0x09, 0x07], // Bitcoin testnet magic
543            default_port: 18333,
544            genesis_block: genesis::testnet_genesis(),
545            max_target: 0x1d00ffff,
546            halving_interval: 210000,
547            network_name: "testnet".to_string(),
548            is_testnet: true,
549        })
550    }
551
552    /// Bitcoin regtest parameters
553    pub fn regtest() -> Result<Self> {
554        Ok(NetworkParameters {
555            magic_bytes: [0xfa, 0xbf, 0xb5, 0xda], // Bitcoin regtest magic
556            default_port: 18444,
557            genesis_block: genesis::regtest_genesis(),
558            max_target: 0x207fffff, // Easier difficulty for testing
559            halving_interval: 150,  // Faster halving for testing
560            network_name: "regtest".to_string(),
561            is_testnet: true,
562        })
563    }
564}
565
566#[cfg(test)]
567mod tests {
568    use super::*;
569    use blvm_consensus::types::{BlockHeader, OutPoint, TransactionInput, TransactionOutput};
570
571    #[test]
572    fn test_blvm_protocol_creation() {
573        let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
574        assert_eq!(engine.get_protocol_version(), ProtocolVersion::BitcoinV1);
575        assert_eq!(engine.get_network_params().network_name, "mainnet");
576    }
577
578    #[test]
579    fn test_blvm_protocol_creation_all_variants() {
580        // Test mainnet
581        let mainnet = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
582        assert_eq!(mainnet.get_protocol_version(), ProtocolVersion::BitcoinV1);
583        assert_eq!(mainnet.get_network_params().network_name, "mainnet");
584        assert!(!mainnet.get_network_params().is_testnet);
585
586        // Test testnet
587        let testnet = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
588        assert_eq!(testnet.get_protocol_version(), ProtocolVersion::Testnet3);
589        assert_eq!(testnet.get_network_params().network_name, "testnet");
590        assert!(testnet.get_network_params().is_testnet);
591
592        // Test regtest
593        let regtest = BitcoinProtocolEngine::new(ProtocolVersion::Regtest).unwrap();
594        assert_eq!(regtest.get_protocol_version(), ProtocolVersion::Regtest);
595        assert_eq!(regtest.get_network_params().network_name, "regtest");
596        assert!(regtest.get_network_params().is_testnet);
597    }
598
599    #[test]
600    fn test_network_parameters() {
601        let mainnet = NetworkParameters::mainnet().unwrap();
602        assert_eq!(mainnet.magic_bytes, [0xf9, 0xbe, 0xb4, 0xd9]);
603        assert_eq!(mainnet.default_port, 8333);
604        assert!(!mainnet.is_testnet);
605
606        let testnet = NetworkParameters::testnet().unwrap();
607        assert_eq!(testnet.magic_bytes, [0x0b, 0x11, 0x09, 0x07]);
608        assert_eq!(testnet.default_port, 18333);
609        assert!(testnet.is_testnet);
610
611        let regtest = NetworkParameters::regtest().unwrap();
612        assert_eq!(regtest.magic_bytes, [0xfa, 0xbf, 0xb5, 0xda]);
613        assert_eq!(regtest.default_port, 18444);
614        assert!(regtest.is_testnet);
615    }
616
617    #[test]
618    fn test_network_parameters_consistency() {
619        let mainnet = NetworkParameters::mainnet().unwrap();
620        assert_eq!(mainnet.max_target, 0x1d00ffff);
621        assert_eq!(mainnet.halving_interval, 210000);
622
623        let testnet = NetworkParameters::testnet().unwrap();
624        assert_eq!(testnet.max_target, 0x1d00ffff);
625        assert_eq!(testnet.halving_interval, 210000);
626
627        let regtest = NetworkParameters::regtest().unwrap();
628        assert_eq!(regtest.max_target, 0x207fffff); // Easier difficulty
629        assert_eq!(regtest.halving_interval, 150); // Faster halving
630    }
631
632    #[test]
633    fn test_feature_support() {
634        let mainnet = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
635        assert!(mainnet.supports_feature("segwit"));
636        assert!(mainnet.supports_feature("taproot"));
637        assert!(mainnet.supports_feature("rbf"));
638        assert!(mainnet.supports_feature("ctv"));
639        assert!(!mainnet.supports_feature("fast_mining"));
640        assert!(!mainnet.supports_feature("nonexistent"));
641
642        let testnet = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
643        assert!(testnet.supports_feature("segwit"));
644        assert!(testnet.supports_feature("taproot"));
645        assert!(testnet.supports_feature("rbf"));
646        assert!(testnet.supports_feature("ctv"));
647        assert!(!testnet.supports_feature("fast_mining"));
648
649        let regtest = BitcoinProtocolEngine::new(ProtocolVersion::Regtest).unwrap();
650        assert!(regtest.supports_feature("segwit"));
651        assert!(regtest.supports_feature("taproot"));
652        assert!(regtest.supports_feature("rbf"));
653        assert!(regtest.supports_feature("ctv"));
654        assert!(regtest.supports_feature("fast_mining"));
655    }
656
657    #[test]
658    fn test_block_validation_empty_utxos() {
659        let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
660        let utxos = UtxoSet::default();
661
662        // Create a simple block with just a coinbase transaction
663        let coinbase_tx = Transaction {
664            version: 1,
665            inputs: blvm_consensus::tx_inputs![TransactionInput {
666                prevout: OutPoint {
667                    hash: [0u8; 32],
668                    index: 0xffffffff,
669                },
670                script_sig: vec![0x01, 0x00], // Height 0
671                sequence: 0xffffffff,
672            }],
673            outputs: blvm_consensus::tx_outputs![TransactionOutput {
674                value: 50_0000_0000,
675                script_pubkey: vec![
676                    blvm_consensus::opcodes::OP_DUP,
677                    blvm_consensus::opcodes::OP_HASH160,
678                    blvm_consensus::opcodes::PUSH_20_BYTES,
679                    0x00,
680                    0x00,
681                    0x00,
682                    0x00,
683                    0x00,
684                    0x00,
685                    0x00,
686                    0x00,
687                    0x00,
688                    0x00,
689                    0x00,
690                    0x00,
691                    0x00,
692                    0x00,
693                    0x00,
694                    0x00,
695                    0x00,
696                    0x00,
697                    0x00,
698                    0x00,
699                    blvm_consensus::opcodes::OP_EQUALVERIFY,
700                    blvm_consensus::opcodes::OP_CHECKSIG,
701                ], // P2PKH
702            }],
703            lock_time: 0,
704        };
705
706        // Calculate proper merkle root
707        let merkle_root = blvm_consensus::mining::calculate_merkle_root(&[coinbase_tx.clone()])
708            .expect("Should calculate merkle root");
709
710        let block = Block {
711            header: BlockHeader {
712                version: 1,
713                prev_block_hash: [0u8; 32],
714                merkle_root,
715                timestamp: 1231006505,
716                bits: 0x1d00ffff,
717                nonce: 0,
718            },
719            transactions: vec![coinbase_tx].into_boxed_slice(),
720        };
721
722        // This should pass validation for a genesis block
723        let result = engine.validate_block(&block, &utxos, 0);
724        assert!(result.is_ok());
725    }
726
727    #[test]
728    fn test_transaction_validation() {
729        let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
730
731        // Create a simple transaction
732        let tx = Transaction {
733            version: 1,
734            inputs: vec![TransactionInput {
735                prevout: OutPoint {
736                    hash: [0u8; 32],
737                    index: 0,
738                },
739                script_sig: vec![blvm_consensus::opcodes::PUSH_65_BYTES, 0x04],
740                sequence: 0xffffffff,
741            }]
742            .into(),
743            outputs: vec![TransactionOutput {
744                value: 50_0000_0000,
745                script_pubkey: vec![
746                    blvm_consensus::opcodes::OP_DUP,
747                    blvm_consensus::opcodes::OP_HASH160,
748                    blvm_consensus::opcodes::PUSH_20_BYTES,
749                    0x00,
750                    0x00,
751                    0x00,
752                    0x00,
753                    0x00,
754                    0x00,
755                    0x00,
756                    0x00,
757                    0x00,
758                    0x00,
759                    0x00,
760                    0x00,
761                    0x00,
762                    0x00,
763                    0x00,
764                    0x00,
765                    0x00,
766                    0x00,
767                    0x00,
768                    0x00,
769                    blvm_consensus::opcodes::OP_EQUALVERIFY,
770                    blvm_consensus::opcodes::OP_CHECKSIG,
771                ], // P2PKH
772            }]
773            .into(),
774            lock_time: 0,
775        };
776
777        let result = engine.validate_transaction(&tx);
778        assert!(result.is_ok());
779    }
780
781    #[test]
782    fn test_cross_protocol_validation() {
783        let mainnet_engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
784        let testnet_engine = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
785
786        // Both engines should support the same features
787        assert_eq!(
788            mainnet_engine.supports_feature("segwit"),
789            testnet_engine.supports_feature("segwit")
790        );
791        assert_eq!(
792            mainnet_engine.supports_feature("taproot"),
793            testnet_engine.supports_feature("taproot")
794        );
795
796        // But they should have different network parameters
797        assert_ne!(
798            mainnet_engine.get_network_params().magic_bytes,
799            testnet_engine.get_network_params().magic_bytes
800        );
801        assert_ne!(
802            mainnet_engine.get_network_params().default_port,
803            testnet_engine.get_network_params().default_port
804        );
805    }
806
807    #[test]
808    fn test_protocol_version_switching() {
809        // Test that we can create engines for different protocol versions
810        let versions = vec![
811            ProtocolVersion::BitcoinV1,
812            ProtocolVersion::Testnet3,
813            ProtocolVersion::Regtest,
814        ];
815
816        for version in versions {
817            let engine = BitcoinProtocolEngine::new(version).unwrap();
818            assert_eq!(engine.get_protocol_version(), version);
819        }
820    }
821
822    #[test]
823    fn test_network_parameters_serialization() {
824        let mainnet = NetworkParameters::mainnet().unwrap();
825        let testnet = NetworkParameters::testnet().unwrap();
826        let regtest = NetworkParameters::regtest().unwrap();
827
828        // Test that parameters can be serialized and deserialized
829        let mainnet_json = serde_json::to_string(&mainnet).unwrap();
830        let mainnet_deserialized: NetworkParameters = serde_json::from_str(&mainnet_json).unwrap();
831        assert_eq!(mainnet.magic_bytes, mainnet_deserialized.magic_bytes);
832        assert_eq!(mainnet.default_port, mainnet_deserialized.default_port);
833        assert_eq!(mainnet.network_name, mainnet_deserialized.network_name);
834        assert_eq!(mainnet.is_testnet, mainnet_deserialized.is_testnet);
835
836        let testnet_json = serde_json::to_string(&testnet).unwrap();
837        let testnet_deserialized: NetworkParameters = serde_json::from_str(&testnet_json).unwrap();
838        assert_eq!(testnet.magic_bytes, testnet_deserialized.magic_bytes);
839
840        let regtest_json = serde_json::to_string(&regtest).unwrap();
841        let regtest_deserialized: NetworkParameters = serde_json::from_str(&regtest_json).unwrap();
842        assert_eq!(regtest.magic_bytes, regtest_deserialized.magic_bytes);
843    }
844
845    #[test]
846    fn test_protocol_version_serialization() {
847        let versions = vec![
848            ProtocolVersion::BitcoinV1,
849            ProtocolVersion::Testnet3,
850            ProtocolVersion::Regtest,
851        ];
852
853        for version in versions {
854            let json = serde_json::to_string(&version).unwrap();
855            let deserialized: ProtocolVersion = serde_json::from_str(&json).unwrap();
856            assert_eq!(version, deserialized);
857        }
858    }
859
860    #[test]
861    fn test_network_parameters_equality() {
862        let mainnet1 = NetworkParameters::mainnet().unwrap();
863        let mainnet2 = NetworkParameters::mainnet().unwrap();
864        let testnet = NetworkParameters::testnet().unwrap();
865
866        assert_eq!(mainnet1, mainnet2);
867        assert_ne!(mainnet1, testnet);
868    }
869
870    #[test]
871    fn test_protocol_version_equality() {
872        assert_eq!(ProtocolVersion::BitcoinV1, ProtocolVersion::BitcoinV1);
873        assert_ne!(ProtocolVersion::BitcoinV1, ProtocolVersion::Testnet3);
874        assert_ne!(ProtocolVersion::Testnet3, ProtocolVersion::Regtest);
875    }
876
877    #[test]
878    fn test_feature_activation_by_height() {
879        let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
880
881        // SegWit activates at block 481,824
882        assert!(!engine.is_feature_active("segwit", 481_823, 1503539000));
883        assert!(engine.is_feature_active("segwit", 481_824, 1503539857));
884        assert!(engine.is_feature_active("segwit", 500_000, 1504000000));
885
886        // Taproot activates at block 709,632
887        assert!(!engine.is_feature_active("taproot", 709_631, 1636934000));
888        assert!(engine.is_feature_active("taproot", 709_632, 1636934400));
889        assert!(engine.is_feature_active("taproot", 800_000, 1640000000));
890    }
891
892    #[test]
893    fn test_economic_parameters_access() {
894        let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
895        let params = engine.get_economic_parameters();
896
897        assert_eq!(params.initial_subsidy, 50_0000_0000);
898        assert_eq!(params.halving_interval, 210_000);
899        assert_eq!(params.coinbase_maturity, 100);
900
901        // Test block subsidy calculation
902        assert_eq!(params.get_block_subsidy(0), 50_0000_0000);
903        assert_eq!(params.get_block_subsidy(210_000), 25_0000_0000);
904    }
905
906    #[test]
907    fn test_feature_registry_access() {
908        let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
909        let registry = engine.get_feature_registry();
910
911        assert!(registry.get_feature("segwit").is_some());
912        assert!(registry.get_feature("taproot").is_some());
913        assert!(registry.get_feature("nonexistent").is_none());
914
915        let features = registry.list_features();
916        assert!(features.contains(&"segwit".to_string()));
917        assert!(features.contains(&"taproot".to_string()));
918    }
919}