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