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(feature = "bip324")]
188pub mod v2_transport;
189
190// Re-export commonly used types for convenience
191pub use commons::{
192    BanListMessage,
193    // Filtered block types
194    FilterPreferences,
195    // Commons-only types kept in blvm-protocol for bridge layers
196    FilteredBlockMessage,
197    GetBanListMessage,
198    GetFilteredBlockMessage,
199    // UTXO proof types
200    GetUTXOProofMessage,
201    GetUTXOSetMessage,
202    // UTXO commitment protocol types
203    UTXOCommitment,
204    UTXOProofMessage,
205    UTXOSetMessage,
206};
207pub use config::{
208    ProtocolConfig, ProtocolFeaturesConfig, ProtocolValidationConfig, ServiceFlagsConfig,
209};
210pub use network::{BlockMessage, CompactBlockMessage, TxMessage};
211pub use service_flags::{commons as service_flags_commons, standard as service_flags_standard};
212// Wire format module - Bitcoin P2P wire protocol serialization
213pub mod wire;
214
215#[cfg(test)]
216mod bip155_serialization_tests;
217pub mod types {
218    pub use blvm_consensus::types::*;
219}
220// Re-export macros from blvm-consensus for convenience
221#[cfg(feature = "production")]
222pub use blvm_consensus::tx_inputs;
223#[cfg(not(feature = "production"))]
224pub use blvm_consensus::tx_inputs;
225#[cfg(feature = "production")]
226pub use blvm_consensus::tx_outputs;
227#[cfg(not(feature = "production"))]
228pub use blvm_consensus::tx_outputs;
229pub mod error;
230
231// Re-export feature and economic modules for convenience
232pub use economic::EconomicParameters;
233pub use features::{ActivationMethod, FeatureActivation, FeatureContext, FeatureRegistry};
234
235pub mod config;
236pub mod economic;
237pub mod features;
238pub mod genesis;
239pub mod network_params;
240pub mod validation;
241pub mod variants;
242
243// Protocol-level BIP implementations
244pub mod address; // BIP173/350/351: Bech32/Bech32m address encoding
245#[cfg(feature = "ctv")]
246pub mod bip119 {
247    pub use blvm_consensus::bip119::*;
248}
249pub mod bip152; // BIP152: Compact block relay (wire types)
250pub mod bip157; // BIP157: Client-side block filtering network protocol
251pub mod bip158; // BIP158: Compact block filters
252pub mod fibre;
253pub mod payment; // BIP70: Payment protocol (P2P variant) // FIBRE: Fast Internet Bitcoin Relay Engine protocol definitions
254pub mod time;
255
256/// Bitcoin Protocol Engine
257///
258/// Provides protocol abstraction for different Bitcoin variants and evolution.
259/// Acts as a bridge between blvm-consensus (pure math) and blvm-node (implementation).
260pub struct BitcoinProtocolEngine {
261    consensus: ConsensusProof,
262    protocol_version: ProtocolVersion,
263    network_params: NetworkParameters,
264    config: ProtocolConfig,
265}
266
267/// Bitcoin protocol versions
268#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
269pub enum ProtocolVersion {
270    /// Current Bitcoin mainnet protocol
271    BitcoinV1,
272    /// Bitcoin testnet protocol
273    Testnet3,
274    /// Regression test network protocol
275    Regtest,
276}
277
278/// Network parameters for different Bitcoin variants
279#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
280pub struct NetworkParameters {
281    /// Network magic bytes for P2P protocol
282    pub magic_bytes: [u8; 4],
283    /// Default P2P port
284    pub default_port: u16,
285    /// Genesis block for this network
286    pub genesis_block: Block,
287    /// Maximum proof-of-work target
288    pub max_target: u32,
289    /// Block subsidy halving interval
290    pub halving_interval: u64,
291    /// Network name for identification
292    pub network_name: String,
293    /// Whether this is a test network
294    pub is_testnet: bool,
295}
296
297impl BitcoinProtocolEngine {
298    /// Create a new protocol engine for the specified variant with default configuration
299    pub fn new(version: ProtocolVersion) -> Result<Self> {
300        Self::with_config(version, ProtocolConfig::default())
301    }
302
303    /// Create a new protocol engine with custom configuration
304    pub fn with_config(version: ProtocolVersion, config: ProtocolConfig) -> Result<Self> {
305        let consensus = ConsensusProof::new();
306        let network_params = NetworkParameters::for_version(version)?;
307
308        Ok(BitcoinProtocolEngine {
309            consensus,
310            protocol_version: version,
311            network_params,
312            config,
313        })
314    }
315
316    /// Get the protocol configuration
317    pub fn get_config(&self) -> &ProtocolConfig {
318        &self.config
319    }
320
321    /// Get mutable reference to protocol configuration
322    pub fn get_config_mut(&mut self) -> &mut ProtocolConfig {
323        &mut self.config
324    }
325
326    /// Get the current protocol version
327    pub fn get_protocol_version(&self) -> ProtocolVersion {
328        self.protocol_version
329    }
330
331    /// Get network parameters for this protocol
332    pub fn get_network_params(&self) -> &NetworkParameters {
333        &self.network_params
334    }
335
336    /// Validate a block using this protocol's rules
337    pub fn validate_block(
338        &self,
339        block: &Block,
340        utxos: &UtxoSet,
341        height: u64,
342    ) -> Result<ValidationResult> {
343        let (result, _) = self
344            .consensus
345            .validate_block(block, utxos.clone(), height)
346            .map_err(ProtocolError::from)?;
347        Ok(result)
348    }
349
350    /// Validate a transaction using this protocol's rules
351    pub fn validate_transaction(&self, tx: &Transaction) -> Result<ValidationResult> {
352        self.consensus
353            .validate_transaction(tx)
354            .map_err(ProtocolError::from)
355    }
356
357    /// Validate block with protocol rules and update UTXO set
358    ///
359    /// This method combines protocol validation (size limits, feature flags)
360    /// with consensus validation and UTXO set updates. This is the recommended
361    /// method for node implementations that need both validation and state updates.
362    ///
363    /// # Arguments
364    ///
365    /// * `block` - The block to validate and connect
366    /// * `witnesses` - Witness data for each transaction in the block
367    /// * `utxos` - Current UTXO set (will be cloned, not mutated)
368    /// * `height` - Current block height
369    /// * `recent_headers` - Optional recent block headers for median time-past calculation (BIP113)
370    /// * `context` - Protocol validation context
371    ///
372    /// # Returns
373    ///
374    /// Returns `(ValidationResult, UtxoSet)` where:
375    /// - `ValidationResult` indicates if the block is valid
376    /// - `UtxoSet` is the updated UTXO set after applying the block's transactions
377    ///
378    /// # Example
379    ///
380    /// ```rust,no_run
381    /// use blvm_protocol::{BitcoinProtocolEngine, ProtocolVersion};
382    /// use blvm_protocol::validation::ProtocolValidationContext;
383    /// use blvm_protocol::{Block, UtxoSet};
384    ///
385    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
386    /// let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1)?;
387    /// let context = ProtocolValidationContext::new(ProtocolVersion::BitcoinV1, 0)?;
388    /// // Create a test block
389    /// let block = Block {
390    ///     header: blvm_consensus::BlockHeader {
391    ///         version: 1,
392    ///         prev_block_hash: [0u8; 32],
393    ///         merkle_root: [0u8; 32],
394    ///         timestamp: 1231006505,
395    ///         bits: 0x1d00ffff,
396    ///         nonce: 0,
397    ///     },
398    ///     transactions: vec![].into_boxed_slice(),
399    /// };
400    /// let witnesses = vec![];
401    /// let utxos = UtxoSet::default();
402    ///
403    /// let (result, new_utxo_set) = engine.validate_and_connect_block(
404    ///     &block,
405    ///     &witnesses,
406    ///     &utxos,
407    ///     0,
408    ///     None,
409    ///     &context,
410    /// )?;
411    /// # Ok(())
412    /// # }
413    /// ```
414    pub fn validate_and_connect_block(
415        &self,
416        block: &Block,
417        witnesses: &[Vec<segwit::Witness>], // CRITICAL FIX: Changed from &[Witness] to &[Vec<Witness>]
418        // witnesses is now Vec<Vec<Witness>> where each Vec<Witness> is for one transaction
419        // and each Witness is for one input
420        utxos: &UtxoSet,
421        height: u64,
422        recent_headers: Option<&[BlockHeader]>,
423        context: &validation::ProtocolValidationContext,
424    ) -> Result<(ValidationResult, UtxoSet)> {
425        // First, protocol validation (size limits, feature flags)
426        let protocol_result = self.validate_block_with_protocol(block, utxos, height, context)?;
427        if !matches!(protocol_result, ValidationResult::Valid) {
428            return Ok((protocol_result, utxos.clone()));
429        }
430
431        // Then, consensus validation with UTXO update
432        // Convert protocol version to network type
433        let network = match self.protocol_version {
434            ProtocolVersion::BitcoinV1 => types::Network::Mainnet,
435            ProtocolVersion::Testnet3 => types::Network::Testnet,
436            ProtocolVersion::Regtest => types::Network::Regtest,
437        };
438        let network_time = crate::time::current_timestamp();
439        let context = crate::block::block_validation_context_for_connect_ibd(
440            recent_headers,
441            network_time,
442            network,
443        );
444        let (result, new_utxo_set, _undo_log) = blvm_consensus::block::connect_block(
445            block,
446            witnesses,
447            utxos.clone(),
448            height,
449            &context,
450        )?;
451
452        Ok((result, new_utxo_set))
453    }
454
455    /// Check if this protocol supports a specific feature
456    pub fn supports_feature(&self, feature: &str) -> bool {
457        match self.protocol_version {
458            ProtocolVersion::BitcoinV1 => {
459                matches!(feature, "segwit" | "taproot" | "rbf" | "ctv")
460            }
461            ProtocolVersion::Testnet3 => {
462                matches!(feature, "segwit" | "taproot" | "rbf" | "ctv")
463            }
464            ProtocolVersion::Regtest => {
465                matches!(
466                    feature,
467                    "segwit" | "taproot" | "rbf" | "ctv" | "fast_mining"
468                )
469            }
470        }
471    }
472
473    /// Check if a feature is active at a specific block height and timestamp
474    pub fn is_feature_active(&self, feature: &str, height: u64, timestamp: u64) -> bool {
475        let registry = features::FeatureRegistry::for_protocol(self.protocol_version);
476        registry.is_feature_active(feature, height, timestamp)
477    }
478
479    /// Get economic parameters for this protocol
480    pub fn get_economic_parameters(&self) -> economic::EconomicParameters {
481        economic::EconomicParameters::for_protocol(self.protocol_version)
482    }
483
484    /// Get feature activation registry for this protocol
485    pub fn get_feature_registry(&self) -> features::FeatureRegistry {
486        features::FeatureRegistry::for_protocol(self.protocol_version)
487    }
488
489    /// Create a feature context for a specific block height and timestamp
490    /// This consolidates all feature activation checks into a single context
491    pub fn feature_context(&self, height: u64, timestamp: u64) -> features::FeatureContext {
492        let registry = features::FeatureRegistry::for_protocol(self.protocol_version);
493        registry.create_context(height, timestamp)
494    }
495}
496
497impl NetworkParameters {
498    /// Create network parameters for a specific protocol version
499    pub fn for_version(version: ProtocolVersion) -> Result<Self> {
500        match version {
501            ProtocolVersion::BitcoinV1 => Self::mainnet(),
502            ProtocolVersion::Testnet3 => Self::testnet(),
503            ProtocolVersion::Regtest => Self::regtest(),
504        }
505    }
506
507    /// Bitcoin mainnet parameters
508    pub fn mainnet() -> Result<Self> {
509        Ok(NetworkParameters {
510            magic_bytes: [0xf9, 0xbe, 0xb4, 0xd9], // Bitcoin mainnet magic
511            default_port: 8333,
512            genesis_block: genesis::mainnet_genesis(),
513            max_target: 0x1d00ffff,
514            halving_interval: 210000,
515            network_name: "mainnet".to_string(),
516            is_testnet: false,
517        })
518    }
519
520    /// Bitcoin testnet parameters
521    pub fn testnet() -> Result<Self> {
522        Ok(NetworkParameters {
523            magic_bytes: [0x0b, 0x11, 0x09, 0x07], // Bitcoin testnet magic
524            default_port: 18333,
525            genesis_block: genesis::testnet_genesis(),
526            max_target: 0x1d00ffff,
527            halving_interval: 210000,
528            network_name: "testnet".to_string(),
529            is_testnet: true,
530        })
531    }
532
533    /// Bitcoin regtest parameters
534    pub fn regtest() -> Result<Self> {
535        Ok(NetworkParameters {
536            magic_bytes: [0xfa, 0xbf, 0xb5, 0xda], // Bitcoin regtest magic
537            default_port: 18444,
538            genesis_block: genesis::regtest_genesis(),
539            max_target: 0x207fffff, // Easier difficulty for testing
540            halving_interval: 150,  // Faster halving for testing
541            network_name: "regtest".to_string(),
542            is_testnet: true,
543        })
544    }
545}
546
547#[cfg(test)]
548mod tests {
549    use super::*;
550    use blvm_consensus::types::{BlockHeader, OutPoint, TransactionInput, TransactionOutput};
551
552    #[test]
553    fn test_blvm_protocol_creation() {
554        let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
555        assert_eq!(engine.get_protocol_version(), ProtocolVersion::BitcoinV1);
556        assert_eq!(engine.get_network_params().network_name, "mainnet");
557    }
558
559    #[test]
560    fn test_blvm_protocol_creation_all_variants() {
561        // Test mainnet
562        let mainnet = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
563        assert_eq!(mainnet.get_protocol_version(), ProtocolVersion::BitcoinV1);
564        assert_eq!(mainnet.get_network_params().network_name, "mainnet");
565        assert!(!mainnet.get_network_params().is_testnet);
566
567        // Test testnet
568        let testnet = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
569        assert_eq!(testnet.get_protocol_version(), ProtocolVersion::Testnet3);
570        assert_eq!(testnet.get_network_params().network_name, "testnet");
571        assert!(testnet.get_network_params().is_testnet);
572
573        // Test regtest
574        let regtest = BitcoinProtocolEngine::new(ProtocolVersion::Regtest).unwrap();
575        assert_eq!(regtest.get_protocol_version(), ProtocolVersion::Regtest);
576        assert_eq!(regtest.get_network_params().network_name, "regtest");
577        assert!(regtest.get_network_params().is_testnet);
578    }
579
580    #[test]
581    fn test_network_parameters() {
582        let mainnet = NetworkParameters::mainnet().unwrap();
583        assert_eq!(mainnet.magic_bytes, [0xf9, 0xbe, 0xb4, 0xd9]);
584        assert_eq!(mainnet.default_port, 8333);
585        assert!(!mainnet.is_testnet);
586
587        let testnet = NetworkParameters::testnet().unwrap();
588        assert_eq!(testnet.magic_bytes, [0x0b, 0x11, 0x09, 0x07]);
589        assert_eq!(testnet.default_port, 18333);
590        assert!(testnet.is_testnet);
591
592        let regtest = NetworkParameters::regtest().unwrap();
593        assert_eq!(regtest.magic_bytes, [0xfa, 0xbf, 0xb5, 0xda]);
594        assert_eq!(regtest.default_port, 18444);
595        assert!(regtest.is_testnet);
596    }
597
598    #[test]
599    fn test_network_parameters_consistency() {
600        let mainnet = NetworkParameters::mainnet().unwrap();
601        assert_eq!(mainnet.max_target, 0x1d00ffff);
602        assert_eq!(mainnet.halving_interval, 210000);
603
604        let testnet = NetworkParameters::testnet().unwrap();
605        assert_eq!(testnet.max_target, 0x1d00ffff);
606        assert_eq!(testnet.halving_interval, 210000);
607
608        let regtest = NetworkParameters::regtest().unwrap();
609        assert_eq!(regtest.max_target, 0x207fffff); // Easier difficulty
610        assert_eq!(regtest.halving_interval, 150); // Faster halving
611    }
612
613    #[test]
614    fn test_feature_support() {
615        let mainnet = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
616        assert!(mainnet.supports_feature("segwit"));
617        assert!(mainnet.supports_feature("taproot"));
618        assert!(mainnet.supports_feature("rbf"));
619        assert!(mainnet.supports_feature("ctv"));
620        assert!(!mainnet.supports_feature("fast_mining"));
621        assert!(!mainnet.supports_feature("nonexistent"));
622
623        let testnet = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
624        assert!(testnet.supports_feature("segwit"));
625        assert!(testnet.supports_feature("taproot"));
626        assert!(testnet.supports_feature("rbf"));
627        assert!(testnet.supports_feature("ctv"));
628        assert!(!testnet.supports_feature("fast_mining"));
629
630        let regtest = BitcoinProtocolEngine::new(ProtocolVersion::Regtest).unwrap();
631        assert!(regtest.supports_feature("segwit"));
632        assert!(regtest.supports_feature("taproot"));
633        assert!(regtest.supports_feature("rbf"));
634        assert!(regtest.supports_feature("ctv"));
635        assert!(regtest.supports_feature("fast_mining"));
636    }
637
638    #[test]
639    fn test_block_validation_empty_utxos() {
640        let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
641        let utxos = UtxoSet::default();
642
643        // Create a simple block with just a coinbase transaction
644        let coinbase_tx = Transaction {
645            version: 1,
646            inputs: blvm_consensus::tx_inputs![TransactionInput {
647                prevout: OutPoint {
648                    hash: [0u8; 32],
649                    index: 0xffffffff,
650                },
651                script_sig: vec![0x01, 0x00], // Height 0
652                sequence: 0xffffffff,
653            }],
654            outputs: blvm_consensus::tx_outputs![TransactionOutput {
655                value: 50_0000_0000,
656                script_pubkey: vec![
657                    blvm_consensus::opcodes::OP_DUP,
658                    blvm_consensus::opcodes::OP_HASH160,
659                    blvm_consensus::opcodes::PUSH_20_BYTES,
660                    0x00,
661                    0x00,
662                    0x00,
663                    0x00,
664                    0x00,
665                    0x00,
666                    0x00,
667                    0x00,
668                    0x00,
669                    0x00,
670                    0x00,
671                    0x00,
672                    0x00,
673                    0x00,
674                    0x00,
675                    0x00,
676                    0x00,
677                    0x00,
678                    0x00,
679                    0x00,
680                    blvm_consensus::opcodes::OP_EQUALVERIFY,
681                    blvm_consensus::opcodes::OP_CHECKSIG,
682                ], // P2PKH
683            }],
684            lock_time: 0,
685        };
686
687        // Calculate proper merkle root
688        let merkle_root = blvm_consensus::mining::calculate_merkle_root(&[coinbase_tx.clone()])
689            .expect("Should calculate merkle root");
690
691        let block = Block {
692            header: BlockHeader {
693                version: 1,
694                prev_block_hash: [0u8; 32],
695                merkle_root,
696                timestamp: 1231006505,
697                bits: 0x1d00ffff,
698                nonce: 0,
699            },
700            transactions: vec![coinbase_tx].into_boxed_slice(),
701        };
702
703        // This should pass validation for a genesis block
704        let result = engine.validate_block(&block, &utxos, 0);
705        assert!(result.is_ok());
706    }
707
708    #[test]
709    fn test_transaction_validation() {
710        let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
711
712        // Create a simple transaction
713        let tx = Transaction {
714            version: 1,
715            inputs: vec![TransactionInput {
716                prevout: OutPoint {
717                    hash: [0u8; 32],
718                    index: 0,
719                },
720                script_sig: vec![blvm_consensus::opcodes::PUSH_65_BYTES, 0x04],
721                sequence: 0xffffffff,
722            }]
723            .into(),
724            outputs: vec![TransactionOutput {
725                value: 50_0000_0000,
726                script_pubkey: vec![
727                    blvm_consensus::opcodes::OP_DUP,
728                    blvm_consensus::opcodes::OP_HASH160,
729                    blvm_consensus::opcodes::PUSH_20_BYTES,
730                    0x00,
731                    0x00,
732                    0x00,
733                    0x00,
734                    0x00,
735                    0x00,
736                    0x00,
737                    0x00,
738                    0x00,
739                    0x00,
740                    0x00,
741                    0x00,
742                    0x00,
743                    0x00,
744                    0x00,
745                    0x00,
746                    0x00,
747                    0x00,
748                    0x00,
749                    0x00,
750                    blvm_consensus::opcodes::OP_EQUALVERIFY,
751                    blvm_consensus::opcodes::OP_CHECKSIG,
752                ], // P2PKH
753            }]
754            .into(),
755            lock_time: 0,
756        };
757
758        let result = engine.validate_transaction(&tx);
759        assert!(result.is_ok());
760    }
761
762    #[test]
763    fn test_cross_protocol_validation() {
764        let mainnet_engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
765        let testnet_engine = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
766
767        // Both engines should support the same features
768        assert_eq!(
769            mainnet_engine.supports_feature("segwit"),
770            testnet_engine.supports_feature("segwit")
771        );
772        assert_eq!(
773            mainnet_engine.supports_feature("taproot"),
774            testnet_engine.supports_feature("taproot")
775        );
776
777        // But they should have different network parameters
778        assert_ne!(
779            mainnet_engine.get_network_params().magic_bytes,
780            testnet_engine.get_network_params().magic_bytes
781        );
782        assert_ne!(
783            mainnet_engine.get_network_params().default_port,
784            testnet_engine.get_network_params().default_port
785        );
786    }
787
788    #[test]
789    fn test_protocol_version_switching() {
790        // Test that we can create engines for different protocol versions
791        let versions = vec![
792            ProtocolVersion::BitcoinV1,
793            ProtocolVersion::Testnet3,
794            ProtocolVersion::Regtest,
795        ];
796
797        for version in versions {
798            let engine = BitcoinProtocolEngine::new(version).unwrap();
799            assert_eq!(engine.get_protocol_version(), version);
800        }
801    }
802
803    #[test]
804    fn test_network_parameters_serialization() {
805        let mainnet = NetworkParameters::mainnet().unwrap();
806        let testnet = NetworkParameters::testnet().unwrap();
807        let regtest = NetworkParameters::regtest().unwrap();
808
809        // Test that parameters can be serialized and deserialized
810        let mainnet_json = serde_json::to_string(&mainnet).unwrap();
811        let mainnet_deserialized: NetworkParameters = serde_json::from_str(&mainnet_json).unwrap();
812        assert_eq!(mainnet.magic_bytes, mainnet_deserialized.magic_bytes);
813        assert_eq!(mainnet.default_port, mainnet_deserialized.default_port);
814        assert_eq!(mainnet.network_name, mainnet_deserialized.network_name);
815        assert_eq!(mainnet.is_testnet, mainnet_deserialized.is_testnet);
816
817        let testnet_json = serde_json::to_string(&testnet).unwrap();
818        let testnet_deserialized: NetworkParameters = serde_json::from_str(&testnet_json).unwrap();
819        assert_eq!(testnet.magic_bytes, testnet_deserialized.magic_bytes);
820
821        let regtest_json = serde_json::to_string(&regtest).unwrap();
822        let regtest_deserialized: NetworkParameters = serde_json::from_str(&regtest_json).unwrap();
823        assert_eq!(regtest.magic_bytes, regtest_deserialized.magic_bytes);
824    }
825
826    #[test]
827    fn test_protocol_version_serialization() {
828        let versions = vec![
829            ProtocolVersion::BitcoinV1,
830            ProtocolVersion::Testnet3,
831            ProtocolVersion::Regtest,
832        ];
833
834        for version in versions {
835            let json = serde_json::to_string(&version).unwrap();
836            let deserialized: ProtocolVersion = serde_json::from_str(&json).unwrap();
837            assert_eq!(version, deserialized);
838        }
839    }
840
841    #[test]
842    fn test_network_parameters_equality() {
843        let mainnet1 = NetworkParameters::mainnet().unwrap();
844        let mainnet2 = NetworkParameters::mainnet().unwrap();
845        let testnet = NetworkParameters::testnet().unwrap();
846
847        assert_eq!(mainnet1, mainnet2);
848        assert_ne!(mainnet1, testnet);
849    }
850
851    #[test]
852    fn test_protocol_version_equality() {
853        assert_eq!(ProtocolVersion::BitcoinV1, ProtocolVersion::BitcoinV1);
854        assert_ne!(ProtocolVersion::BitcoinV1, ProtocolVersion::Testnet3);
855        assert_ne!(ProtocolVersion::Testnet3, ProtocolVersion::Regtest);
856    }
857
858    #[test]
859    fn test_feature_activation_by_height() {
860        let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
861
862        // SegWit activates at block 481,824
863        assert!(!engine.is_feature_active("segwit", 481_823, 1503539000));
864        assert!(engine.is_feature_active("segwit", 481_824, 1503539857));
865        assert!(engine.is_feature_active("segwit", 500_000, 1504000000));
866
867        // Taproot activates at block 709,632
868        assert!(!engine.is_feature_active("taproot", 709_631, 1636934000));
869        assert!(engine.is_feature_active("taproot", 709_632, 1636934400));
870        assert!(engine.is_feature_active("taproot", 800_000, 1640000000));
871    }
872
873    #[test]
874    fn test_economic_parameters_access() {
875        let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
876        let params = engine.get_economic_parameters();
877
878        assert_eq!(params.initial_subsidy, 50_0000_0000);
879        assert_eq!(params.halving_interval, 210_000);
880        assert_eq!(params.coinbase_maturity, 100);
881
882        // Test block subsidy calculation
883        assert_eq!(params.get_block_subsidy(0), 50_0000_0000);
884        assert_eq!(params.get_block_subsidy(210_000), 25_0000_0000);
885    }
886
887    #[test]
888    fn test_feature_registry_access() {
889        let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
890        let registry = engine.get_feature_registry();
891
892        assert!(registry.get_feature("segwit").is_some());
893        assert!(registry.get_feature("taproot").is_some());
894        assert!(registry.get_feature("nonexistent").is_none());
895
896        let features = registry.list_features();
897        assert!(features.contains(&"segwit".to_string()));
898        assert!(features.contains(&"taproot".to_string()));
899    }
900}