1use serde::{Deserialize, Serialize};
18
19pub use blvm_consensus::ConsensusProof;
22pub use blvm_consensus::config::NetworkMessageLimits;
23pub use blvm_consensus::error::{ConsensusError, Result as ConsensusResult};
24pub use blvm_consensus::types::{
25 Block, BlockHeader, ByteString, Hash, Integer, Natural, OutPoint, Transaction,
26 TransactionInput, TransactionOutput, UTXO, UtxoSet, ValidationResult, Witness,
27};
28
29#[cfg(all(feature = "production", feature = "benchmarking"))]
30pub use blvm_consensus::config::{reset_assume_valid_height, set_assume_valid_height};
31pub 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#[cfg(feature = "production")]
40pub use smallvec;
41#[cfg(feature = "production")]
43pub use lru;
44#[cfg(feature = "production")]
45pub use rayon;
46
47#[macro_export]
50macro_rules! profile_log {
51 ($($arg:tt)*) => {
52 ::blvm_consensus::profile_log!($($arg)*)
53 };
54}
55
56pub use error::{ProtocolError, Result};
58
59pub 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 #[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
108pub mod script {
110 pub use blvm_consensus::script::*;
111}
112
113pub mod transaction_hash {
115 pub use blvm_consensus::transaction_hash::*;
116}
117
118#[cfg(feature = "production")]
120pub mod optimizations {
121 pub use blvm_consensus::optimizations::*;
122}
123
124pub 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
149pub 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
159pub 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
169pub mod spam_filter;
171pub mod serialization {
172 pub use blvm_consensus::serialization::*;
173}
174pub mod commons;
175pub mod network;
176pub 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#[cfg(all(
188 feature = "bip324",
189 any(target_arch = "x86_64", target_arch = "aarch64")
190))]
191pub mod v2_transport;
192
193pub use commons::{
195 BanListMessage,
196 FilterPreferences,
198 FilteredBlockMessage,
200 GetBanListMessage,
201 GetFilteredBlockMessage,
202 GetUTXOProofMessage,
204 GetUTXOSetMessage,
205 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};
215pub mod wire;
217
218#[cfg(test)]
219mod bip155_serialization_tests;
220pub mod types {
221 pub use blvm_consensus::types::*;
222}
223pub use blvm_consensus::tx_inputs;
225pub use blvm_consensus::tx_outputs;
226pub mod error;
227
228pub use economic::EconomicParameters;
230pub use features::{ActivationMethod, FeatureActivation, FeatureContext, FeatureRegistry};
231
232pub mod config;
233pub mod economic;
234pub mod features;
235pub mod genesis;
236pub mod network_params;
237pub mod validation;
238pub mod variants;
239
240pub mod address; #[cfg(feature = "ctv")]
243pub mod bip119 {
244 pub use blvm_consensus::bip119::*;
245}
246pub mod bip152; pub mod bip157; pub mod bip158; pub mod payment; pub mod time;
251
252pub struct BitcoinProtocolEngine {
257 consensus: ConsensusProof,
258 protocol_version: ProtocolVersion,
259 network_params: NetworkParameters,
260 config: ProtocolConfig,
261}
262
263#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
265pub enum ProtocolVersion {
266 BitcoinV1,
268 Testnet3,
270 Regtest,
272 Signet,
274 Testnet4,
276}
277
278impl ProtocolVersion {
279 pub fn consensus_network(self) -> types::Network {
281 match self {
282 ProtocolVersion::BitcoinV1 => types::Network::Mainnet,
283 ProtocolVersion::Testnet3 => types::Network::Testnet,
284 ProtocolVersion::Regtest => types::Network::Regtest,
285 ProtocolVersion::Signet => types::Network::Signet,
286 ProtocolVersion::Testnet4 => types::Network::Testnet4,
287 }
288 }
289}
290
291#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
293pub struct NetworkParameters {
294 pub magic_bytes: [u8; 4],
296 pub default_port: u16,
298 pub genesis_block: Block,
300 pub max_target: u32,
302 pub halving_interval: u64,
304 pub network_name: String,
306 pub is_testnet: bool,
308 #[serde(default, skip_serializing_if = "Option::is_none")]
310 pub signet_challenge: Option<ByteString>,
311}
312
313impl BitcoinProtocolEngine {
314 pub fn new(version: ProtocolVersion) -> Result<Self> {
316 Self::with_config(version, ProtocolConfig::default())
317 }
318
319 pub fn with_config(version: ProtocolVersion, config: ProtocolConfig) -> Result<Self> {
321 let consensus = ConsensusProof::new();
322 let network_params = NetworkParameters::for_version(version)?;
323
324 Ok(BitcoinProtocolEngine {
325 consensus,
326 protocol_version: version,
327 network_params,
328 config,
329 })
330 }
331
332 pub fn get_config(&self) -> &ProtocolConfig {
334 &self.config
335 }
336
337 pub fn get_config_mut(&mut self) -> &mut ProtocolConfig {
339 &mut self.config
340 }
341
342 pub fn get_protocol_version(&self) -> ProtocolVersion {
344 self.protocol_version
345 }
346
347 pub fn get_network_params(&self) -> &NetworkParameters {
349 &self.network_params
350 }
351
352 pub fn with_signet_challenge(mut self, script: Option<Vec<u8>>) -> Self {
354 self.network_params.signet_challenge = script;
355 self
356 }
357
358 pub fn connect_block_validation_context<H: AsRef<BlockHeader>>(
360 &self,
361 recent_headers: Option<&[H]>,
362 network_time: u64,
363 ) -> block::BlockValidationContext {
364 let mut ctx = block::block_validation_context_for_connect_ibd(
365 recent_headers,
366 network_time,
367 self.protocol_version.consensus_network(),
368 );
369 ctx.signet_challenge = self.network_params.signet_challenge.clone();
370 ctx
371 }
372
373 #[deprecated(
385 since = "0.1.0",
386 note = "Use validate_and_connect_block with explicit witnesses and a ProtocolValidationContext"
387 )]
388 pub fn validate_block(
389 &self,
390 block: &Block,
391 utxos: &UtxoSet,
392 height: u64,
393 ) -> Result<ValidationResult> {
394 let network = self.protocol_version.consensus_network();
395 let witnesses: Vec<Vec<blvm_consensus::segwit::Witness>> = block
399 .transactions
400 .iter()
401 .map(|tx| tx.inputs.iter().map(|_| Vec::new()).collect())
402 .collect();
403 let now_secs = std::time::SystemTime::now()
406 .duration_since(std::time::UNIX_EPOCH)
407 .unwrap_or_default()
408 .as_secs();
409 let time_ctx = blvm_consensus::types::TimeContext {
410 network_time: now_secs,
411 median_time_past: now_secs,
414 };
415 let (result, _) = self
416 .consensus
417 .validate_block_with_time_context(
418 block,
419 &witnesses,
420 utxos.clone(),
421 height,
422 Some(time_ctx),
423 network,
424 )
425 .map_err(ProtocolError::from)?;
426 Ok(result)
427 }
428
429 pub fn validate_transaction(&self, tx: &Transaction) -> Result<ValidationResult> {
431 self.consensus
432 .validate_transaction(tx)
433 .map_err(ProtocolError::from)
434 }
435
436 pub fn validate_and_connect_block(
494 &self,
495 block: &Block,
496 witnesses: &[Vec<segwit::Witness>], utxos: &UtxoSet,
500 height: u64,
501 recent_headers: Option<&[BlockHeader]>,
502 context: &validation::ProtocolValidationContext,
503 ) -> Result<(ValidationResult, UtxoSet)> {
504 self.validate_and_connect_block_with_difficulty(
505 block,
506 witnesses,
507 utxos,
508 height,
509 recent_headers,
510 context,
511 None,
512 )
513 }
514
515 #[allow(clippy::too_many_arguments)]
520 pub fn validate_and_connect_block_with_difficulty(
521 &self,
522 block: &Block,
523 witnesses: &[Vec<segwit::Witness>],
524 utxos: &UtxoSet,
525 height: u64,
526 recent_headers: Option<&[BlockHeader]>,
527 context: &validation::ProtocolValidationContext,
528 difficulty_ancestor: Option<block::DifficultyAncestor>,
529 ) -> Result<(ValidationResult, UtxoSet)> {
530 let protocol_result = self
532 .validate_block_with_protocol_and_witnesses(block, witnesses, utxos, height, context)?;
533 if !matches!(protocol_result, ValidationResult::Valid) {
534 return Ok((protocol_result, utxos.clone()));
535 }
536
537 let network_time = if context.network_time > 0 {
539 context.network_time
540 } else {
541 crate::time::current_timestamp()
542 };
543 let mut consensus_ctx = if context.median_time_past > 0 {
544 block::BlockValidationContext::from_time_context_and_network(
545 Some(blvm_consensus::types::TimeContext {
546 network_time,
547 median_time_past: context.median_time_past,
548 }),
549 self.protocol_version.consensus_network(),
550 None,
551 )
552 } else {
553 self.connect_block_validation_context(recent_headers, network_time)
554 };
555 consensus_ctx.signet_challenge = self.network_params.signet_challenge.clone();
556 consensus_ctx.difficulty_ancestor = difficulty_ancestor;
557 let (result, new_utxo_set, _undo_log) = blvm_consensus::block::connect_block(
558 block,
559 witnesses,
560 utxos.clone(),
561 height,
562 &consensus_ctx,
563 )?;
564
565 Ok((result, new_utxo_set))
566 }
567
568 pub fn supports_feature(&self, feature: &str) -> bool {
570 match self.protocol_version {
571 ProtocolVersion::BitcoinV1 => {
572 matches!(feature, "segwit" | "taproot" | "rbf" | "ctv")
573 }
574 ProtocolVersion::Testnet3 => {
575 matches!(feature, "segwit" | "taproot" | "rbf" | "ctv")
576 }
577 ProtocolVersion::Regtest => {
578 matches!(
579 feature,
580 "segwit" | "taproot" | "rbf" | "ctv" | "fast_mining"
581 )
582 }
583 ProtocolVersion::Signet => {
584 matches!(feature, "segwit" | "taproot" | "rbf" | "ctv" | "signet")
585 }
586 ProtocolVersion::Testnet4 => {
587 matches!(feature, "segwit" | "taproot" | "rbf" | "ctv")
588 }
589 }
590 }
591
592 pub fn is_feature_active(&self, feature: &str, height: u64, timestamp: u64) -> bool {
594 let registry = features::FeatureRegistry::for_protocol(self.protocol_version);
595 registry.is_feature_active(feature, height, timestamp)
596 }
597
598 pub fn get_economic_parameters(&self) -> economic::EconomicParameters {
600 economic::EconomicParameters::for_protocol(self.protocol_version)
601 }
602
603 pub fn get_feature_registry(&self) -> features::FeatureRegistry {
605 features::FeatureRegistry::for_protocol(self.protocol_version)
606 }
607
608 pub fn feature_context(&self, height: u64, timestamp: u64) -> features::FeatureContext {
611 let registry = features::FeatureRegistry::for_protocol(self.protocol_version);
612 registry.create_context(height, timestamp)
613 }
614}
615
616impl NetworkParameters {
617 pub fn for_version(version: ProtocolVersion) -> Result<Self> {
619 match version {
620 ProtocolVersion::BitcoinV1 => Self::mainnet(),
621 ProtocolVersion::Testnet3 => Self::testnet(),
622 ProtocolVersion::Regtest => Self::regtest(),
623 ProtocolVersion::Signet => Self::signet(),
624 ProtocolVersion::Testnet4 => Self::testnet4(),
625 }
626 }
627
628 pub fn mainnet() -> Result<Self> {
630 Ok(NetworkParameters {
631 magic_bytes: [0xf9, 0xbe, 0xb4, 0xd9], default_port: 8333,
633 genesis_block: genesis::mainnet_genesis(),
634 max_target: 0x1d00ffff,
635 halving_interval: blvm_consensus::economic::subsidy_halving_interval(
636 blvm_consensus::types::Network::Mainnet,
637 ),
638 network_name: "mainnet".to_string(),
639 is_testnet: false,
640 signet_challenge: None,
641 })
642 }
643
644 pub fn testnet() -> Result<Self> {
646 Ok(NetworkParameters {
647 magic_bytes: [0x0b, 0x11, 0x09, 0x07], default_port: 18333,
649 genesis_block: genesis::testnet_genesis(),
650 max_target: 0x1d00ffff,
651 halving_interval: blvm_consensus::economic::subsidy_halving_interval(
652 blvm_consensus::types::Network::Testnet,
653 ),
654 network_name: "testnet".to_string(),
655 is_testnet: true,
656 signet_challenge: None,
657 })
658 }
659
660 pub fn regtest() -> Result<Self> {
662 Ok(NetworkParameters {
663 magic_bytes: [0xfa, 0xbf, 0xb5, 0xda], default_port: 18444,
665 genesis_block: genesis::regtest_genesis(),
666 max_target: 0x207fffff, halving_interval: blvm_consensus::economic::subsidy_halving_interval(
668 blvm_consensus::types::Network::Regtest,
669 ),
670 network_name: "regtest".to_string(),
671 is_testnet: true,
672 signet_challenge: None,
673 })
674 }
675
676 pub fn signet() -> Result<Self> {
678 Ok(NetworkParameters {
679 magic_bytes: [0x0f, 0x1b, 0xf2, 0xe1],
680 default_port: 38333,
681 genesis_block: genesis::signet_genesis(),
682 max_target: 0x1e0377ae,
683 halving_interval: blvm_consensus::economic::subsidy_halving_interval(
684 blvm_consensus::types::Network::Signet,
685 ),
686 network_name: "signet".to_string(),
687 is_testnet: true,
688 signet_challenge: None,
689 })
690 }
691
692 pub fn testnet4() -> Result<Self> {
694 Ok(NetworkParameters {
695 magic_bytes: [0x1c, 0x16, 0x3f, 0x28],
696 default_port: 48333,
697 genesis_block: genesis::testnet4_genesis(),
698 max_target: 0x1d00ffff,
699 halving_interval: blvm_consensus::economic::subsidy_halving_interval(
700 blvm_consensus::types::Network::Testnet4,
701 ),
702 network_name: "testnet4".to_string(),
703 is_testnet: true,
704 signet_challenge: None,
705 })
706 }
707}
708
709#[cfg(test)]
710mod tests {
711 use super::*;
712 use blvm_consensus::types::{BlockHeader, OutPoint, TransactionInput, TransactionOutput};
713
714 #[test]
715 fn test_blvm_protocol_creation() {
716 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
717 assert_eq!(engine.get_protocol_version(), ProtocolVersion::BitcoinV1);
718 assert_eq!(engine.get_network_params().network_name, "mainnet");
719 }
720
721 #[test]
722 fn test_blvm_protocol_creation_all_variants() {
723 let mainnet = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
725 assert_eq!(mainnet.get_protocol_version(), ProtocolVersion::BitcoinV1);
726 assert_eq!(mainnet.get_network_params().network_name, "mainnet");
727 assert!(!mainnet.get_network_params().is_testnet);
728
729 let testnet = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
731 assert_eq!(testnet.get_protocol_version(), ProtocolVersion::Testnet3);
732 assert_eq!(testnet.get_network_params().network_name, "testnet");
733 assert!(testnet.get_network_params().is_testnet);
734
735 let regtest = BitcoinProtocolEngine::new(ProtocolVersion::Regtest).unwrap();
737 assert_eq!(regtest.get_protocol_version(), ProtocolVersion::Regtest);
738 assert_eq!(regtest.get_network_params().network_name, "regtest");
739 assert!(regtest.get_network_params().is_testnet);
740
741 let signet = BitcoinProtocolEngine::new(ProtocolVersion::Signet).unwrap();
743 assert_eq!(signet.get_protocol_version(), ProtocolVersion::Signet);
744 assert_eq!(signet.get_network_params().network_name, "signet");
745 assert!(signet.get_network_params().is_testnet);
746 assert_eq!(signet.get_network_params().default_port, 38333);
747 }
748
749 #[test]
750 fn test_network_parameters() {
751 let mainnet = NetworkParameters::mainnet().unwrap();
752 assert_eq!(mainnet.magic_bytes, [0xf9, 0xbe, 0xb4, 0xd9]);
753 assert_eq!(mainnet.default_port, 8333);
754 assert!(!mainnet.is_testnet);
755
756 let testnet = NetworkParameters::testnet().unwrap();
757 assert_eq!(testnet.magic_bytes, [0x0b, 0x11, 0x09, 0x07]);
758 assert_eq!(testnet.default_port, 18333);
759 assert!(testnet.is_testnet);
760
761 let regtest = NetworkParameters::regtest().unwrap();
762 assert_eq!(regtest.magic_bytes, [0xfa, 0xbf, 0xb5, 0xda]);
763 assert_eq!(regtest.default_port, 18444);
764 assert!(regtest.is_testnet);
765 }
766
767 #[test]
768 fn test_network_parameters_consistency() {
769 let mainnet = NetworkParameters::mainnet().unwrap();
770 assert_eq!(mainnet.max_target, 0x1d00ffff);
771 assert_eq!(mainnet.halving_interval, 210000);
772
773 let testnet = NetworkParameters::testnet().unwrap();
774 assert_eq!(testnet.max_target, 0x1d00ffff);
775 assert_eq!(testnet.halving_interval, 210000);
776
777 let regtest = NetworkParameters::regtest().unwrap();
778 assert_eq!(regtest.max_target, 0x207fffff); assert_eq!(regtest.halving_interval, 150); }
781
782 #[test]
783 fn test_feature_support() {
784 let mainnet = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
785 assert!(mainnet.supports_feature("segwit"));
786 assert!(mainnet.supports_feature("taproot"));
787 assert!(mainnet.supports_feature("rbf"));
788 assert!(mainnet.supports_feature("ctv"));
789 assert!(!mainnet.supports_feature("fast_mining"));
790 assert!(!mainnet.supports_feature("nonexistent"));
791
792 let testnet = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
793 assert!(testnet.supports_feature("segwit"));
794 assert!(testnet.supports_feature("taproot"));
795 assert!(testnet.supports_feature("rbf"));
796 assert!(testnet.supports_feature("ctv"));
797 assert!(!testnet.supports_feature("fast_mining"));
798
799 let regtest = BitcoinProtocolEngine::new(ProtocolVersion::Regtest).unwrap();
800 assert!(regtest.supports_feature("segwit"));
801 assert!(regtest.supports_feature("taproot"));
802 assert!(regtest.supports_feature("rbf"));
803 assert!(regtest.supports_feature("ctv"));
804 assert!(regtest.supports_feature("fast_mining"));
805
806 let signet = BitcoinProtocolEngine::new(ProtocolVersion::Signet).unwrap();
807 assert!(signet.supports_feature("segwit"));
808 assert!(signet.supports_feature("taproot"));
809 assert!(signet.supports_feature("signet"));
810 assert!(!signet.supports_feature("fast_mining"));
811 }
812
813 #[test]
814 fn test_signet_challenge_override_on_engine() {
815 let engine = BitcoinProtocolEngine::new(ProtocolVersion::Signet)
816 .unwrap()
817 .with_signet_challenge(Some(vec![0x51]));
818 assert_eq!(
819 engine
820 .get_network_params()
821 .signet_challenge
822 .as_ref()
823 .map(|b| b.as_ref()),
824 Some([0x51].as_slice())
825 );
826 let ctx = engine.connect_block_validation_context(None::<&[BlockHeader]>, 0);
827 assert_eq!(
828 ctx.signet_challenge.as_ref().map(|b| b.as_ref()),
829 Some([0x51].as_slice())
830 );
831 }
832
833 #[test]
834 fn test_block_validation_empty_utxos() {
835 use crate::validation::ProtocolValidationContext;
836 use blvm_consensus::opcodes::OP_1;
837
838 let engine = BitcoinProtocolEngine::new(ProtocolVersion::Regtest).unwrap();
839 let utxos = UtxoSet::default();
840
841 let coinbase_tx = Transaction {
842 version: 2,
843 inputs: blvm_consensus::tx_inputs![TransactionInput {
844 prevout: OutPoint {
845 hash: [0u8; 32],
846 index: 0xffffffff,
847 },
848 script_sig: vec![0x00, 0xff],
849 sequence: 0xffffffff,
850 }],
851 outputs: blvm_consensus::tx_outputs![TransactionOutput {
852 value: 5_000_000_000,
853 script_pubkey: vec![OP_1],
854 }],
855 lock_time: 0,
856 };
857
858 let merkle_root = blvm_consensus::mining::calculate_merkle_root(&[coinbase_tx.clone()])
859 .expect("merkle root");
860
861 let block = Block {
862 header: BlockHeader {
863 version: 4,
864 prev_block_hash: [0u8; 32],
865 merkle_root,
866 timestamp: 1_231_006_505,
867 bits: 0x0300ffff,
868 nonce: 0,
869 },
870 transactions: vec![coinbase_tx].into_boxed_slice(),
871 };
872
873 let witnesses: Vec<Vec<blvm_consensus::segwit::Witness>> = block
874 .transactions
875 .iter()
876 .map(|tx| tx.inputs.iter().map(|_| Vec::new()).collect())
877 .collect();
878 let mut context = ProtocolValidationContext::new(ProtocolVersion::Regtest, 0).unwrap();
879 context.network_time = block.header.timestamp;
880 context.median_time_past = block.header.timestamp - 1;
881
882 let (result, new_utxos) = engine
883 .validate_and_connect_block(&block, &witnesses, &utxos, 0, None, &context)
884 .unwrap();
885 assert_eq!(result, ValidationResult::Valid);
886 assert!(!new_utxos.is_empty());
887 }
888
889 #[test]
890 fn test_transaction_validation() {
891 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
892
893 let tx = Transaction {
895 version: 1,
896 inputs: vec![TransactionInput {
897 prevout: OutPoint {
898 hash: [0u8; 32],
899 index: 0,
900 },
901 script_sig: vec![blvm_consensus::opcodes::PUSH_65_BYTES, 0x04],
902 sequence: 0xffffffff,
903 }]
904 .into(),
905 outputs: vec![TransactionOutput {
906 value: 50_0000_0000,
907 script_pubkey: vec![
908 blvm_consensus::opcodes::OP_DUP,
909 blvm_consensus::opcodes::OP_HASH160,
910 blvm_consensus::opcodes::PUSH_20_BYTES,
911 0x00,
912 0x00,
913 0x00,
914 0x00,
915 0x00,
916 0x00,
917 0x00,
918 0x00,
919 0x00,
920 0x00,
921 0x00,
922 0x00,
923 0x00,
924 0x00,
925 0x00,
926 0x00,
927 0x00,
928 0x00,
929 0x00,
930 0x00,
931 blvm_consensus::opcodes::OP_EQUALVERIFY,
932 blvm_consensus::opcodes::OP_CHECKSIG,
933 ], }]
935 .into(),
936 lock_time: 0,
937 };
938
939 let result = engine.validate_transaction(&tx);
940 assert!(result.is_ok());
941 }
942
943 #[test]
944 fn test_cross_protocol_validation() {
945 let mainnet_engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
946 let testnet_engine = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
947
948 assert_eq!(
950 mainnet_engine.supports_feature("segwit"),
951 testnet_engine.supports_feature("segwit")
952 );
953 assert_eq!(
954 mainnet_engine.supports_feature("taproot"),
955 testnet_engine.supports_feature("taproot")
956 );
957
958 assert_ne!(
960 mainnet_engine.get_network_params().magic_bytes,
961 testnet_engine.get_network_params().magic_bytes
962 );
963 assert_ne!(
964 mainnet_engine.get_network_params().default_port,
965 testnet_engine.get_network_params().default_port
966 );
967 }
968
969 #[test]
970 fn test_protocol_version_switching() {
971 let versions = vec![
973 ProtocolVersion::BitcoinV1,
974 ProtocolVersion::Testnet3,
975 ProtocolVersion::Regtest,
976 ProtocolVersion::Signet,
977 ];
978
979 for version in versions {
980 let engine = BitcoinProtocolEngine::new(version).unwrap();
981 assert_eq!(engine.get_protocol_version(), version);
982 }
983 }
984
985 #[test]
986 fn test_network_parameters_serialization() {
987 let mainnet = NetworkParameters::mainnet().unwrap();
988 let testnet = NetworkParameters::testnet().unwrap();
989 let regtest = NetworkParameters::regtest().unwrap();
990
991 let mainnet_json = serde_json::to_string(&mainnet).unwrap();
993 let mainnet_deserialized: NetworkParameters = serde_json::from_str(&mainnet_json).unwrap();
994 assert_eq!(mainnet.magic_bytes, mainnet_deserialized.magic_bytes);
995 assert_eq!(mainnet.default_port, mainnet_deserialized.default_port);
996 assert_eq!(mainnet.network_name, mainnet_deserialized.network_name);
997 assert_eq!(mainnet.is_testnet, mainnet_deserialized.is_testnet);
998
999 let testnet_json = serde_json::to_string(&testnet).unwrap();
1000 let testnet_deserialized: NetworkParameters = serde_json::from_str(&testnet_json).unwrap();
1001 assert_eq!(testnet.magic_bytes, testnet_deserialized.magic_bytes);
1002
1003 let regtest_json = serde_json::to_string(®test).unwrap();
1004 let regtest_deserialized: NetworkParameters = serde_json::from_str(®test_json).unwrap();
1005 assert_eq!(regtest.magic_bytes, regtest_deserialized.magic_bytes);
1006 }
1007
1008 #[test]
1009 fn test_protocol_version_serialization() {
1010 let versions = vec![
1011 ProtocolVersion::BitcoinV1,
1012 ProtocolVersion::Testnet3,
1013 ProtocolVersion::Regtest,
1014 ProtocolVersion::Signet,
1015 ];
1016
1017 for version in versions {
1018 let json = serde_json::to_string(&version).unwrap();
1019 let deserialized: ProtocolVersion = serde_json::from_str(&json).unwrap();
1020 assert_eq!(version, deserialized);
1021 }
1022 }
1023
1024 #[test]
1025 fn test_network_parameters_equality() {
1026 let mainnet1 = NetworkParameters::mainnet().unwrap();
1027 let mainnet2 = NetworkParameters::mainnet().unwrap();
1028 let testnet = NetworkParameters::testnet().unwrap();
1029
1030 assert_eq!(mainnet1, mainnet2);
1031 assert_ne!(mainnet1, testnet);
1032 }
1033
1034 #[test]
1035 fn test_protocol_version_equality() {
1036 assert_eq!(ProtocolVersion::BitcoinV1, ProtocolVersion::BitcoinV1);
1037 assert_ne!(ProtocolVersion::BitcoinV1, ProtocolVersion::Testnet3);
1038 assert_ne!(ProtocolVersion::Testnet3, ProtocolVersion::Regtest);
1039 }
1040
1041 #[test]
1042 fn test_feature_activation_by_height() {
1043 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
1044
1045 assert!(!engine.is_feature_active("segwit", 481_823, 1503539000));
1047 assert!(engine.is_feature_active("segwit", 481_824, 1503539857));
1048 assert!(engine.is_feature_active("segwit", 500_000, 1504000000));
1049
1050 assert!(!engine.is_feature_active("taproot", 709_631, 1636934000));
1052 assert!(engine.is_feature_active("taproot", 709_632, 1636934400));
1053 assert!(engine.is_feature_active("taproot", 800_000, 1640000000));
1054 }
1055
1056 #[test]
1057 fn test_economic_parameters_access() {
1058 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
1059 let params = engine.get_economic_parameters();
1060
1061 assert_eq!(params.initial_subsidy, 50_0000_0000);
1062 assert_eq!(params.halving_interval, 210_000);
1063 assert_eq!(params.coinbase_maturity, 100);
1064
1065 assert_eq!(params.get_block_subsidy(0), 50_0000_0000);
1067 assert_eq!(params.get_block_subsidy(210_000), 25_0000_0000);
1068 }
1069
1070 #[test]
1071 fn test_feature_registry_access() {
1072 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
1073 let registry = engine.get_feature_registry();
1074
1075 assert!(registry.get_feature("segwit").is_some());
1076 assert!(registry.get_feature("taproot").is_some());
1077 assert!(registry.get_feature("nonexistent").is_none());
1078
1079 let features = registry.list_features();
1080 assert!(features.contains(&"segwit".to_string()));
1081 assert!(features.contains(&"taproot".to_string()));
1082 }
1083}