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 (result, _) = self
346            .consensus
347            .validate_block(block, utxos.clone(), height)
348            .map_err(ProtocolError::from)?;
349        Ok(result)
350    }
351
352    /// Validate a transaction using this protocol's rules
353    pub fn validate_transaction(&self, tx: &Transaction) -> Result<ValidationResult> {
354        self.consensus
355            .validate_transaction(tx)
356            .map_err(ProtocolError::from)
357    }
358
359    /// Validate block with protocol rules and update UTXO set
360    ///
361    /// This method combines protocol validation (size limits, feature flags)
362    /// with consensus validation and UTXO set updates. This is the recommended
363    /// method for node implementations that need both validation and state updates.
364    ///
365    /// # Arguments
366    ///
367    /// * `block` - The block to validate and connect
368    /// * `witnesses` - Witness data for each transaction in the block
369    /// * `utxos` - Current UTXO set (will be cloned, not mutated)
370    /// * `height` - Current block height
371    /// * `recent_headers` - Optional recent block headers for median time-past calculation (BIP113)
372    /// * `context` - Protocol validation context
373    ///
374    /// # Returns
375    ///
376    /// Returns `(ValidationResult, UtxoSet)` where:
377    /// - `ValidationResult` indicates if the block is valid
378    /// - `UtxoSet` is the updated UTXO set after applying the block's transactions
379    ///
380    /// # Example
381    ///
382    /// ```rust,no_run
383    /// use blvm_protocol::{BitcoinProtocolEngine, ProtocolVersion};
384    /// use blvm_protocol::validation::ProtocolValidationContext;
385    /// use blvm_protocol::{Block, UtxoSet};
386    ///
387    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
388    /// let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1)?;
389    /// let context = ProtocolValidationContext::new(ProtocolVersion::BitcoinV1, 0)?;
390    /// // Create a test block
391    /// let block = Block {
392    ///     header: blvm_consensus::BlockHeader {
393    ///         version: 1,
394    ///         prev_block_hash: [0u8; 32],
395    ///         merkle_root: [0u8; 32],
396    ///         timestamp: 1231006505,
397    ///         bits: 0x1d00ffff,
398    ///         nonce: 0,
399    ///     },
400    ///     transactions: vec![].into_boxed_slice(),
401    /// };
402    /// let witnesses = vec![];
403    /// let utxos = UtxoSet::default();
404    ///
405    /// let (result, new_utxo_set) = engine.validate_and_connect_block(
406    ///     &block,
407    ///     &witnesses,
408    ///     &utxos,
409    ///     0,
410    ///     None,
411    ///     &context,
412    /// )?;
413    /// # Ok(())
414    /// # }
415    /// ```
416    pub fn validate_and_connect_block(
417        &self,
418        block: &Block,
419        witnesses: &[Vec<segwit::Witness>], // CRITICAL FIX: Changed from &[Witness] to &[Vec<Witness>]
420        // witnesses is now Vec<Vec<Witness>> where each Vec<Witness> is for one transaction
421        // and each Witness is for one input
422        utxos: &UtxoSet,
423        height: u64,
424        recent_headers: Option<&[BlockHeader]>,
425        context: &validation::ProtocolValidationContext,
426    ) -> Result<(ValidationResult, UtxoSet)> {
427        // First, protocol validation (size limits, feature flags)
428        let protocol_result = self.validate_block_with_protocol(block, utxos, height, context)?;
429        if !matches!(protocol_result, ValidationResult::Valid) {
430            return Ok((protocol_result, utxos.clone()));
431        }
432
433        // Then, consensus validation with UTXO update
434        // Convert protocol version to network type
435        let network = match self.protocol_version {
436            ProtocolVersion::BitcoinV1 => types::Network::Mainnet,
437            ProtocolVersion::Testnet3 => types::Network::Testnet,
438            ProtocolVersion::Regtest => types::Network::Regtest,
439        };
440        let network_time = crate::time::current_timestamp();
441        let context = crate::block::block_validation_context_for_connect_ibd(
442            recent_headers,
443            network_time,
444            network,
445        );
446        let (result, new_utxo_set, _undo_log) = blvm_consensus::block::connect_block(
447            block,
448            witnesses,
449            utxos.clone(),
450            height,
451            &context,
452        )?;
453
454        Ok((result, new_utxo_set))
455    }
456
457    /// Check if this protocol supports a specific feature
458    pub fn supports_feature(&self, feature: &str) -> bool {
459        match self.protocol_version {
460            ProtocolVersion::BitcoinV1 => {
461                matches!(feature, "segwit" | "taproot" | "rbf" | "ctv")
462            }
463            ProtocolVersion::Testnet3 => {
464                matches!(feature, "segwit" | "taproot" | "rbf" | "ctv")
465            }
466            ProtocolVersion::Regtest => {
467                matches!(
468                    feature,
469                    "segwit" | "taproot" | "rbf" | "ctv" | "fast_mining"
470                )
471            }
472        }
473    }
474
475    /// Check if a feature is active at a specific block height and timestamp
476    pub fn is_feature_active(&self, feature: &str, height: u64, timestamp: u64) -> bool {
477        let registry = features::FeatureRegistry::for_protocol(self.protocol_version);
478        registry.is_feature_active(feature, height, timestamp)
479    }
480
481    /// Get economic parameters for this protocol
482    pub fn get_economic_parameters(&self) -> economic::EconomicParameters {
483        economic::EconomicParameters::for_protocol(self.protocol_version)
484    }
485
486    /// Get feature activation registry for this protocol
487    pub fn get_feature_registry(&self) -> features::FeatureRegistry {
488        features::FeatureRegistry::for_protocol(self.protocol_version)
489    }
490
491    /// Create a feature context for a specific block height and timestamp
492    /// This consolidates all feature activation checks into a single context
493    pub fn feature_context(&self, height: u64, timestamp: u64) -> features::FeatureContext {
494        let registry = features::FeatureRegistry::for_protocol(self.protocol_version);
495        registry.create_context(height, timestamp)
496    }
497}
498
499impl NetworkParameters {
500    /// Create network parameters for a specific protocol version
501    pub fn for_version(version: ProtocolVersion) -> Result<Self> {
502        match version {
503            ProtocolVersion::BitcoinV1 => Self::mainnet(),
504            ProtocolVersion::Testnet3 => Self::testnet(),
505            ProtocolVersion::Regtest => Self::regtest(),
506        }
507    }
508
509    /// Bitcoin mainnet parameters
510    pub fn mainnet() -> Result<Self> {
511        Ok(NetworkParameters {
512            magic_bytes: [0xf9, 0xbe, 0xb4, 0xd9], // Bitcoin mainnet magic
513            default_port: 8333,
514            genesis_block: genesis::mainnet_genesis(),
515            max_target: 0x1d00ffff,
516            halving_interval: 210000,
517            network_name: "mainnet".to_string(),
518            is_testnet: false,
519        })
520    }
521
522    /// Bitcoin testnet parameters
523    pub fn testnet() -> Result<Self> {
524        Ok(NetworkParameters {
525            magic_bytes: [0x0b, 0x11, 0x09, 0x07], // Bitcoin testnet magic
526            default_port: 18333,
527            genesis_block: genesis::testnet_genesis(),
528            max_target: 0x1d00ffff,
529            halving_interval: 210000,
530            network_name: "testnet".to_string(),
531            is_testnet: true,
532        })
533    }
534
535    /// Bitcoin regtest parameters
536    pub fn regtest() -> Result<Self> {
537        Ok(NetworkParameters {
538            magic_bytes: [0xfa, 0xbf, 0xb5, 0xda], // Bitcoin regtest magic
539            default_port: 18444,
540            genesis_block: genesis::regtest_genesis(),
541            max_target: 0x207fffff, // Easier difficulty for testing
542            halving_interval: 150,  // Faster halving for testing
543            network_name: "regtest".to_string(),
544            is_testnet: true,
545        })
546    }
547}
548
549#[cfg(test)]
550mod tests {
551    use super::*;
552    use blvm_consensus::types::{BlockHeader, OutPoint, TransactionInput, TransactionOutput};
553
554    #[test]
555    fn test_blvm_protocol_creation() {
556        let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
557        assert_eq!(engine.get_protocol_version(), ProtocolVersion::BitcoinV1);
558        assert_eq!(engine.get_network_params().network_name, "mainnet");
559    }
560
561    #[test]
562    fn test_blvm_protocol_creation_all_variants() {
563        // Test mainnet
564        let mainnet = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
565        assert_eq!(mainnet.get_protocol_version(), ProtocolVersion::BitcoinV1);
566        assert_eq!(mainnet.get_network_params().network_name, "mainnet");
567        assert!(!mainnet.get_network_params().is_testnet);
568
569        // Test testnet
570        let testnet = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
571        assert_eq!(testnet.get_protocol_version(), ProtocolVersion::Testnet3);
572        assert_eq!(testnet.get_network_params().network_name, "testnet");
573        assert!(testnet.get_network_params().is_testnet);
574
575        // Test regtest
576        let regtest = BitcoinProtocolEngine::new(ProtocolVersion::Regtest).unwrap();
577        assert_eq!(regtest.get_protocol_version(), ProtocolVersion::Regtest);
578        assert_eq!(regtest.get_network_params().network_name, "regtest");
579        assert!(regtest.get_network_params().is_testnet);
580    }
581
582    #[test]
583    fn test_network_parameters() {
584        let mainnet = NetworkParameters::mainnet().unwrap();
585        assert_eq!(mainnet.magic_bytes, [0xf9, 0xbe, 0xb4, 0xd9]);
586        assert_eq!(mainnet.default_port, 8333);
587        assert!(!mainnet.is_testnet);
588
589        let testnet = NetworkParameters::testnet().unwrap();
590        assert_eq!(testnet.magic_bytes, [0x0b, 0x11, 0x09, 0x07]);
591        assert_eq!(testnet.default_port, 18333);
592        assert!(testnet.is_testnet);
593
594        let regtest = NetworkParameters::regtest().unwrap();
595        assert_eq!(regtest.magic_bytes, [0xfa, 0xbf, 0xb5, 0xda]);
596        assert_eq!(regtest.default_port, 18444);
597        assert!(regtest.is_testnet);
598    }
599
600    #[test]
601    fn test_network_parameters_consistency() {
602        let mainnet = NetworkParameters::mainnet().unwrap();
603        assert_eq!(mainnet.max_target, 0x1d00ffff);
604        assert_eq!(mainnet.halving_interval, 210000);
605
606        let testnet = NetworkParameters::testnet().unwrap();
607        assert_eq!(testnet.max_target, 0x1d00ffff);
608        assert_eq!(testnet.halving_interval, 210000);
609
610        let regtest = NetworkParameters::regtest().unwrap();
611        assert_eq!(regtest.max_target, 0x207fffff); // Easier difficulty
612        assert_eq!(regtest.halving_interval, 150); // Faster halving
613    }
614
615    #[test]
616    fn test_feature_support() {
617        let mainnet = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
618        assert!(mainnet.supports_feature("segwit"));
619        assert!(mainnet.supports_feature("taproot"));
620        assert!(mainnet.supports_feature("rbf"));
621        assert!(mainnet.supports_feature("ctv"));
622        assert!(!mainnet.supports_feature("fast_mining"));
623        assert!(!mainnet.supports_feature("nonexistent"));
624
625        let testnet = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
626        assert!(testnet.supports_feature("segwit"));
627        assert!(testnet.supports_feature("taproot"));
628        assert!(testnet.supports_feature("rbf"));
629        assert!(testnet.supports_feature("ctv"));
630        assert!(!testnet.supports_feature("fast_mining"));
631
632        let regtest = BitcoinProtocolEngine::new(ProtocolVersion::Regtest).unwrap();
633        assert!(regtest.supports_feature("segwit"));
634        assert!(regtest.supports_feature("taproot"));
635        assert!(regtest.supports_feature("rbf"));
636        assert!(regtest.supports_feature("ctv"));
637        assert!(regtest.supports_feature("fast_mining"));
638    }
639
640    #[test]
641    fn test_block_validation_empty_utxos() {
642        let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
643        let utxos = UtxoSet::default();
644
645        // Create a simple block with just a coinbase transaction
646        let coinbase_tx = Transaction {
647            version: 1,
648            inputs: blvm_consensus::tx_inputs![TransactionInput {
649                prevout: OutPoint {
650                    hash: [0u8; 32],
651                    index: 0xffffffff,
652                },
653                script_sig: vec![0x01, 0x00], // Height 0
654                sequence: 0xffffffff,
655            }],
656            outputs: blvm_consensus::tx_outputs![TransactionOutput {
657                value: 50_0000_0000,
658                script_pubkey: vec![
659                    blvm_consensus::opcodes::OP_DUP,
660                    blvm_consensus::opcodes::OP_HASH160,
661                    blvm_consensus::opcodes::PUSH_20_BYTES,
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                    0x00,
681                    0x00,
682                    blvm_consensus::opcodes::OP_EQUALVERIFY,
683                    blvm_consensus::opcodes::OP_CHECKSIG,
684                ], // P2PKH
685            }],
686            lock_time: 0,
687        };
688
689        // Calculate proper merkle root
690        let merkle_root = blvm_consensus::mining::calculate_merkle_root(&[coinbase_tx.clone()])
691            .expect("Should calculate merkle root");
692
693        let block = Block {
694            header: BlockHeader {
695                version: 1,
696                prev_block_hash: [0u8; 32],
697                merkle_root,
698                timestamp: 1231006505,
699                bits: 0x1d00ffff,
700                nonce: 0,
701            },
702            transactions: vec![coinbase_tx].into_boxed_slice(),
703        };
704
705        // This should pass validation for a genesis block
706        let result = engine.validate_block(&block, &utxos, 0);
707        assert!(result.is_ok());
708    }
709
710    #[test]
711    fn test_transaction_validation() {
712        let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
713
714        // Create a simple transaction
715        let tx = Transaction {
716            version: 1,
717            inputs: vec![TransactionInput {
718                prevout: OutPoint {
719                    hash: [0u8; 32],
720                    index: 0,
721                },
722                script_sig: vec![blvm_consensus::opcodes::PUSH_65_BYTES, 0x04],
723                sequence: 0xffffffff,
724            }]
725            .into(),
726            outputs: vec![TransactionOutput {
727                value: 50_0000_0000,
728                script_pubkey: vec![
729                    blvm_consensus::opcodes::OP_DUP,
730                    blvm_consensus::opcodes::OP_HASH160,
731                    blvm_consensus::opcodes::PUSH_20_BYTES,
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                    0x00,
751                    0x00,
752                    blvm_consensus::opcodes::OP_EQUALVERIFY,
753                    blvm_consensus::opcodes::OP_CHECKSIG,
754                ], // P2PKH
755            }]
756            .into(),
757            lock_time: 0,
758        };
759
760        let result = engine.validate_transaction(&tx);
761        assert!(result.is_ok());
762    }
763
764    #[test]
765    fn test_cross_protocol_validation() {
766        let mainnet_engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
767        let testnet_engine = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
768
769        // Both engines should support the same features
770        assert_eq!(
771            mainnet_engine.supports_feature("segwit"),
772            testnet_engine.supports_feature("segwit")
773        );
774        assert_eq!(
775            mainnet_engine.supports_feature("taproot"),
776            testnet_engine.supports_feature("taproot")
777        );
778
779        // But they should have different network parameters
780        assert_ne!(
781            mainnet_engine.get_network_params().magic_bytes,
782            testnet_engine.get_network_params().magic_bytes
783        );
784        assert_ne!(
785            mainnet_engine.get_network_params().default_port,
786            testnet_engine.get_network_params().default_port
787        );
788    }
789
790    #[test]
791    fn test_protocol_version_switching() {
792        // Test that we can create engines for different protocol versions
793        let versions = vec![
794            ProtocolVersion::BitcoinV1,
795            ProtocolVersion::Testnet3,
796            ProtocolVersion::Regtest,
797        ];
798
799        for version in versions {
800            let engine = BitcoinProtocolEngine::new(version).unwrap();
801            assert_eq!(engine.get_protocol_version(), version);
802        }
803    }
804
805    #[test]
806    fn test_network_parameters_serialization() {
807        let mainnet = NetworkParameters::mainnet().unwrap();
808        let testnet = NetworkParameters::testnet().unwrap();
809        let regtest = NetworkParameters::regtest().unwrap();
810
811        // Test that parameters can be serialized and deserialized
812        let mainnet_json = serde_json::to_string(&mainnet).unwrap();
813        let mainnet_deserialized: NetworkParameters = serde_json::from_str(&mainnet_json).unwrap();
814        assert_eq!(mainnet.magic_bytes, mainnet_deserialized.magic_bytes);
815        assert_eq!(mainnet.default_port, mainnet_deserialized.default_port);
816        assert_eq!(mainnet.network_name, mainnet_deserialized.network_name);
817        assert_eq!(mainnet.is_testnet, mainnet_deserialized.is_testnet);
818
819        let testnet_json = serde_json::to_string(&testnet).unwrap();
820        let testnet_deserialized: NetworkParameters = serde_json::from_str(&testnet_json).unwrap();
821        assert_eq!(testnet.magic_bytes, testnet_deserialized.magic_bytes);
822
823        let regtest_json = serde_json::to_string(&regtest).unwrap();
824        let regtest_deserialized: NetworkParameters = serde_json::from_str(&regtest_json).unwrap();
825        assert_eq!(regtest.magic_bytes, regtest_deserialized.magic_bytes);
826    }
827
828    #[test]
829    fn test_protocol_version_serialization() {
830        let versions = vec![
831            ProtocolVersion::BitcoinV1,
832            ProtocolVersion::Testnet3,
833            ProtocolVersion::Regtest,
834        ];
835
836        for version in versions {
837            let json = serde_json::to_string(&version).unwrap();
838            let deserialized: ProtocolVersion = serde_json::from_str(&json).unwrap();
839            assert_eq!(version, deserialized);
840        }
841    }
842
843    #[test]
844    fn test_network_parameters_equality() {
845        let mainnet1 = NetworkParameters::mainnet().unwrap();
846        let mainnet2 = NetworkParameters::mainnet().unwrap();
847        let testnet = NetworkParameters::testnet().unwrap();
848
849        assert_eq!(mainnet1, mainnet2);
850        assert_ne!(mainnet1, testnet);
851    }
852
853    #[test]
854    fn test_protocol_version_equality() {
855        assert_eq!(ProtocolVersion::BitcoinV1, ProtocolVersion::BitcoinV1);
856        assert_ne!(ProtocolVersion::BitcoinV1, ProtocolVersion::Testnet3);
857        assert_ne!(ProtocolVersion::Testnet3, ProtocolVersion::Regtest);
858    }
859
860    #[test]
861    fn test_feature_activation_by_height() {
862        let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
863
864        // SegWit activates at block 481,824
865        assert!(!engine.is_feature_active("segwit", 481_823, 1503539000));
866        assert!(engine.is_feature_active("segwit", 481_824, 1503539857));
867        assert!(engine.is_feature_active("segwit", 500_000, 1504000000));
868
869        // Taproot activates at block 709,632
870        assert!(!engine.is_feature_active("taproot", 709_631, 1636934000));
871        assert!(engine.is_feature_active("taproot", 709_632, 1636934400));
872        assert!(engine.is_feature_active("taproot", 800_000, 1640000000));
873    }
874
875    #[test]
876    fn test_economic_parameters_access() {
877        let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
878        let params = engine.get_economic_parameters();
879
880        assert_eq!(params.initial_subsidy, 50_0000_0000);
881        assert_eq!(params.halving_interval, 210_000);
882        assert_eq!(params.coinbase_maturity, 100);
883
884        // Test block subsidy calculation
885        assert_eq!(params.get_block_subsidy(0), 50_0000_0000);
886        assert_eq!(params.get_block_subsidy(210_000), 25_0000_0000);
887    }
888
889    #[test]
890    fn test_feature_registry_access() {
891        let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
892        let registry = engine.get_feature_registry();
893
894        assert!(registry.get_feature("segwit").is_some());
895        assert!(registry.get_feature("taproot").is_some());
896        assert!(registry.get_feature("nonexistent").is_none());
897
898        let features = registry.list_features();
899        assert!(features.contains(&"segwit".to_string()));
900        assert!(features.contains(&"taproot".to_string()));
901    }
902}