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 locktime {
134 pub use blvm_consensus::locktime::*;
135}
136
137pub mod bip_validation {
138 pub use blvm_consensus::bip_validation::*;
139}
140
141pub mod utxo_overlay {
142 pub use blvm_consensus::utxo_overlay::*;
143}
144
145pub mod version_bits {
146 pub use blvm_consensus::version_bits::*;
147}
148
149pub mod activation {
150 pub use blvm_consensus::activation::*;
151}
152
153pub mod consensus_config {
155 pub use blvm_consensus::config::*;
156}
157
158#[cfg(feature = "test-utils")]
159pub mod test_utils {
160 pub use blvm_consensus::test_utils::*;
161}
162
163pub use blvm_consensus::opcodes;
165
166pub mod sigop {
167 pub use blvm_consensus::sigop::*;
168}
169
170#[cfg(feature = "utxo-commitments")]
171pub mod utxo_commitments;
172
173pub mod spam_filter;
175pub mod serialization {
176 pub use blvm_consensus::serialization::*;
177}
178pub mod commons;
179pub mod network;
180pub mod node_tcp;
182
183pub use node_tcp::{ProtocolMessage, TcpFramedParser};
184pub mod p2p_commands;
185pub mod p2p_frame;
186pub mod p2p_framing;
187pub mod service_flags;
188pub mod varint;
189
190#[cfg(all(
192 feature = "bip324",
193 any(target_arch = "x86_64", target_arch = "aarch64")
194))]
195pub mod v2_transport;
196
197pub use commons::{
199 BanListMessage,
200 FilterPreferences,
202 FilteredBlockMessage,
204 GetBanListMessage,
205 GetFilteredBlockMessage,
206 GetUTXOProofMessage,
208 GetUTXOSetMessage,
209 UTXOCommitment,
211 UTXOProofMessage,
212 UTXOSetMessage,
213};
214pub use config::{
215 ProtocolConfig, ProtocolFeaturesConfig, ProtocolValidationConfig, ServiceFlagsConfig,
216};
217pub use network::{BlockMessage, CompactBlockMessage, TxMessage};
218pub use service_flags::{commons as service_flags_commons, standard as service_flags_standard};
219pub mod wire;
221
222#[cfg(test)]
223mod bip155_serialization_tests;
224pub mod types {
225 pub use blvm_consensus::types::*;
226}
227pub use blvm_consensus::tx_inputs;
229pub use blvm_consensus::tx_outputs;
230pub mod error;
231
232pub use economic::EconomicParameters;
234pub use features::{ActivationMethod, FeatureActivation, FeatureContext, FeatureRegistry};
235
236pub mod config;
237pub mod economic;
238pub mod features;
239pub mod genesis;
240pub mod network_params;
241pub mod validation;
242pub mod variants;
243
244pub mod address; #[cfg(feature = "ctv")]
247pub mod bip119 {
248 pub use blvm_consensus::bip119::*;
249}
250pub mod bip152; pub mod bip157; pub mod bip158; pub mod payment; pub mod time;
255
256pub struct BitcoinProtocolEngine {
261 consensus: ConsensusProof,
262 protocol_version: ProtocolVersion,
263 network_params: NetworkParameters,
264 config: ProtocolConfig,
265}
266
267#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
269pub enum ProtocolVersion {
270 BitcoinV1,
272 Testnet3,
274 Regtest,
276 Signet,
278 Testnet4,
280}
281
282impl ProtocolVersion {
283 pub fn consensus_network(self) -> types::Network {
285 match self {
286 ProtocolVersion::BitcoinV1 => types::Network::Mainnet,
287 ProtocolVersion::Testnet3 => types::Network::Testnet,
288 ProtocolVersion::Regtest => types::Network::Regtest,
289 ProtocolVersion::Signet => types::Network::Signet,
290 ProtocolVersion::Testnet4 => types::Network::Testnet4,
291 }
292 }
293}
294
295#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
297pub struct NetworkParameters {
298 pub magic_bytes: [u8; 4],
300 pub default_port: u16,
302 pub genesis_block: Block,
304 pub max_target: u32,
306 pub halving_interval: u64,
308 pub network_name: String,
310 pub is_testnet: bool,
312 #[serde(default, skip_serializing_if = "Option::is_none")]
314 pub signet_challenge: Option<ByteString>,
315}
316
317impl BitcoinProtocolEngine {
318 pub fn new(version: ProtocolVersion) -> Result<Self> {
320 Self::with_config(version, ProtocolConfig::default())
321 }
322
323 pub fn with_config(version: ProtocolVersion, config: ProtocolConfig) -> Result<Self> {
325 let consensus = ConsensusProof::new();
326 let network_params = NetworkParameters::for_version(version)?;
327
328 Ok(BitcoinProtocolEngine {
329 consensus,
330 protocol_version: version,
331 network_params,
332 config,
333 })
334 }
335
336 pub fn get_config(&self) -> &ProtocolConfig {
338 &self.config
339 }
340
341 pub fn get_config_mut(&mut self) -> &mut ProtocolConfig {
343 &mut self.config
344 }
345
346 pub fn get_protocol_version(&self) -> ProtocolVersion {
348 self.protocol_version
349 }
350
351 pub fn get_network_params(&self) -> &NetworkParameters {
353 &self.network_params
354 }
355
356 pub fn with_signet_challenge(mut self, script: Option<Vec<u8>>) -> Self {
358 self.network_params.signet_challenge = script;
359 self
360 }
361
362 pub fn connect_block_validation_context<H: AsRef<BlockHeader>>(
364 &self,
365 recent_headers: Option<&[H]>,
366 network_time: u64,
367 ) -> block::BlockValidationContext {
368 let mut ctx = block::block_validation_context_for_connect_ibd(
369 recent_headers,
370 network_time,
371 self.protocol_version.consensus_network(),
372 );
373 ctx.signet_challenge = self.network_params.signet_challenge.clone();
374 ctx
375 }
376
377 #[deprecated(
389 since = "0.1.0",
390 note = "Use validate_and_connect_block with explicit witnesses and a ProtocolValidationContext"
391 )]
392 pub fn validate_block(
393 &self,
394 block: &Block,
395 utxos: &UtxoSet,
396 height: u64,
397 ) -> Result<ValidationResult> {
398 let network = self.protocol_version.consensus_network();
399 let witnesses: Vec<Vec<blvm_consensus::segwit::Witness>> = block
403 .transactions
404 .iter()
405 .map(|tx| tx.inputs.iter().map(|_| Vec::new()).collect())
406 .collect();
407 let now_secs = std::time::SystemTime::now()
410 .duration_since(std::time::UNIX_EPOCH)
411 .unwrap_or_default()
412 .as_secs();
413 let time_ctx = blvm_consensus::types::TimeContext {
414 network_time: now_secs,
415 median_time_past: now_secs,
418 };
419 let (result, _) = self
420 .consensus
421 .validate_block_with_time_context(
422 block,
423 &witnesses,
424 utxos.clone(),
425 height,
426 Some(time_ctx),
427 network,
428 )
429 .map_err(ProtocolError::from)?;
430 Ok(result)
431 }
432
433 pub fn validate_transaction(&self, tx: &Transaction) -> Result<ValidationResult> {
435 self.consensus
436 .validate_transaction(tx)
437 .map_err(ProtocolError::from)
438 }
439
440 pub fn validate_and_connect_block(
498 &self,
499 block: &Block,
500 witnesses: &[Vec<segwit::Witness>], utxos: &UtxoSet,
504 height: u64,
505 recent_headers: Option<&[BlockHeader]>,
506 context: &validation::ProtocolValidationContext,
507 ) -> Result<(ValidationResult, UtxoSet)> {
508 self.validate_and_connect_block_with_difficulty(
509 block,
510 witnesses,
511 utxos,
512 height,
513 recent_headers,
514 context,
515 None,
516 )
517 }
518
519 #[allow(clippy::too_many_arguments)]
524 pub fn validate_and_connect_block_with_difficulty(
525 &self,
526 block: &Block,
527 witnesses: &[Vec<segwit::Witness>],
528 utxos: &UtxoSet,
529 height: u64,
530 recent_headers: Option<&[BlockHeader]>,
531 context: &validation::ProtocolValidationContext,
532 difficulty_ancestor: Option<block::DifficultyAncestor>,
533 ) -> Result<(ValidationResult, UtxoSet)> {
534 let protocol_result = self
536 .validate_block_with_protocol_and_witnesses(block, witnesses, utxos, height, context)?;
537 if !matches!(protocol_result, ValidationResult::Valid) {
538 return Ok((protocol_result, utxos.clone()));
539 }
540
541 let network_time = if context.network_time > 0 {
543 context.network_time
544 } else {
545 crate::time::current_timestamp()
546 };
547 let mut consensus_ctx = if context.median_time_past > 0 {
548 block::BlockValidationContext::from_time_context_and_network(
549 Some(blvm_consensus::types::TimeContext {
550 network_time,
551 median_time_past: context.median_time_past,
552 }),
553 self.protocol_version.consensus_network(),
554 None,
555 )
556 } else {
557 self.connect_block_validation_context(recent_headers, network_time)
558 };
559 consensus_ctx.signet_challenge = self.network_params.signet_challenge.clone();
560 consensus_ctx.difficulty_ancestor = difficulty_ancestor;
561 let (result, new_utxo_set, _undo_log) = blvm_consensus::block::connect_block(
562 block,
563 witnesses,
564 utxos.clone(),
565 height,
566 &consensus_ctx,
567 )?;
568
569 Ok((result, new_utxo_set))
570 }
571
572 pub fn supports_feature(&self, feature: &str) -> bool {
574 match self.protocol_version {
575 ProtocolVersion::BitcoinV1 => {
576 matches!(feature, "segwit" | "taproot" | "rbf" | "ctv")
577 }
578 ProtocolVersion::Testnet3 => {
579 matches!(feature, "segwit" | "taproot" | "rbf" | "ctv")
580 }
581 ProtocolVersion::Regtest => {
582 matches!(
583 feature,
584 "segwit" | "taproot" | "rbf" | "ctv" | "fast_mining"
585 )
586 }
587 ProtocolVersion::Signet => {
588 matches!(feature, "segwit" | "taproot" | "rbf" | "ctv" | "signet")
589 }
590 ProtocolVersion::Testnet4 => {
591 matches!(feature, "segwit" | "taproot" | "rbf" | "ctv")
592 }
593 }
594 }
595
596 pub fn is_feature_active(&self, feature: &str, height: u64, timestamp: u64) -> bool {
598 let registry = features::FeatureRegistry::for_protocol(self.protocol_version);
599 registry.is_feature_active(feature, height, timestamp)
600 }
601
602 pub fn get_economic_parameters(&self) -> economic::EconomicParameters {
604 economic::EconomicParameters::for_protocol(self.protocol_version)
605 }
606
607 pub fn get_feature_registry(&self) -> features::FeatureRegistry {
609 features::FeatureRegistry::for_protocol(self.protocol_version)
610 }
611
612 pub fn feature_context(&self, height: u64, timestamp: u64) -> features::FeatureContext {
615 let registry = features::FeatureRegistry::for_protocol(self.protocol_version);
616 registry.create_context(height, timestamp)
617 }
618}
619
620impl NetworkParameters {
621 pub fn for_version(version: ProtocolVersion) -> Result<Self> {
623 match version {
624 ProtocolVersion::BitcoinV1 => Self::mainnet(),
625 ProtocolVersion::Testnet3 => Self::testnet(),
626 ProtocolVersion::Regtest => Self::regtest(),
627 ProtocolVersion::Signet => Self::signet(),
628 ProtocolVersion::Testnet4 => Self::testnet4(),
629 }
630 }
631
632 pub fn mainnet() -> Result<Self> {
634 Ok(NetworkParameters {
635 magic_bytes: [0xf9, 0xbe, 0xb4, 0xd9], default_port: 8333,
637 genesis_block: genesis::mainnet_genesis(),
638 max_target: 0x1d00ffff,
639 halving_interval: blvm_consensus::economic::subsidy_halving_interval(
640 blvm_consensus::types::Network::Mainnet,
641 ),
642 network_name: "mainnet".to_string(),
643 is_testnet: false,
644 signet_challenge: None,
645 })
646 }
647
648 pub fn testnet() -> Result<Self> {
650 Ok(NetworkParameters {
651 magic_bytes: [0x0b, 0x11, 0x09, 0x07], default_port: 18333,
653 genesis_block: genesis::testnet_genesis(),
654 max_target: 0x1d00ffff,
655 halving_interval: blvm_consensus::economic::subsidy_halving_interval(
656 blvm_consensus::types::Network::Testnet,
657 ),
658 network_name: "testnet".to_string(),
659 is_testnet: true,
660 signet_challenge: None,
661 })
662 }
663
664 pub fn regtest() -> Result<Self> {
666 Ok(NetworkParameters {
667 magic_bytes: [0xfa, 0xbf, 0xb5, 0xda], default_port: 18444,
669 genesis_block: genesis::regtest_genesis(),
670 max_target: 0x207fffff, halving_interval: blvm_consensus::economic::subsidy_halving_interval(
672 blvm_consensus::types::Network::Regtest,
673 ),
674 network_name: "regtest".to_string(),
675 is_testnet: true,
676 signet_challenge: None,
677 })
678 }
679
680 pub fn signet() -> Result<Self> {
682 Ok(NetworkParameters {
683 magic_bytes: [0x0f, 0x1b, 0xf2, 0xe1],
684 default_port: 38333,
685 genesis_block: genesis::signet_genesis(),
686 max_target: 0x1e0377ae,
687 halving_interval: blvm_consensus::economic::subsidy_halving_interval(
688 blvm_consensus::types::Network::Signet,
689 ),
690 network_name: "signet".to_string(),
691 is_testnet: true,
692 signet_challenge: None,
693 })
694 }
695
696 pub fn testnet4() -> Result<Self> {
698 Ok(NetworkParameters {
699 magic_bytes: [0x1c, 0x16, 0x3f, 0x28],
700 default_port: 48333,
701 genesis_block: genesis::testnet4_genesis(),
702 max_target: 0x1d00ffff,
703 halving_interval: blvm_consensus::economic::subsidy_halving_interval(
704 blvm_consensus::types::Network::Testnet4,
705 ),
706 network_name: "testnet4".to_string(),
707 is_testnet: true,
708 signet_challenge: None,
709 })
710 }
711}
712
713#[cfg(test)]
714mod tests {
715 use super::*;
716 use blvm_consensus::types::{BlockHeader, OutPoint, TransactionInput, TransactionOutput};
717
718 #[test]
719 fn test_blvm_protocol_creation() {
720 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
721 assert_eq!(engine.get_protocol_version(), ProtocolVersion::BitcoinV1);
722 assert_eq!(engine.get_network_params().network_name, "mainnet");
723 }
724
725 #[test]
726 fn test_blvm_protocol_creation_all_variants() {
727 let mainnet = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
729 assert_eq!(mainnet.get_protocol_version(), ProtocolVersion::BitcoinV1);
730 assert_eq!(mainnet.get_network_params().network_name, "mainnet");
731 assert!(!mainnet.get_network_params().is_testnet);
732
733 let testnet = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
735 assert_eq!(testnet.get_protocol_version(), ProtocolVersion::Testnet3);
736 assert_eq!(testnet.get_network_params().network_name, "testnet");
737 assert!(testnet.get_network_params().is_testnet);
738
739 let regtest = BitcoinProtocolEngine::new(ProtocolVersion::Regtest).unwrap();
741 assert_eq!(regtest.get_protocol_version(), ProtocolVersion::Regtest);
742 assert_eq!(regtest.get_network_params().network_name, "regtest");
743 assert!(regtest.get_network_params().is_testnet);
744
745 let signet = BitcoinProtocolEngine::new(ProtocolVersion::Signet).unwrap();
747 assert_eq!(signet.get_protocol_version(), ProtocolVersion::Signet);
748 assert_eq!(signet.get_network_params().network_name, "signet");
749 assert!(signet.get_network_params().is_testnet);
750 assert_eq!(signet.get_network_params().default_port, 38333);
751 }
752
753 #[test]
754 fn test_network_parameters() {
755 let mainnet = NetworkParameters::mainnet().unwrap();
756 assert_eq!(mainnet.magic_bytes, [0xf9, 0xbe, 0xb4, 0xd9]);
757 assert_eq!(mainnet.default_port, 8333);
758 assert!(!mainnet.is_testnet);
759
760 let testnet = NetworkParameters::testnet().unwrap();
761 assert_eq!(testnet.magic_bytes, [0x0b, 0x11, 0x09, 0x07]);
762 assert_eq!(testnet.default_port, 18333);
763 assert!(testnet.is_testnet);
764
765 let regtest = NetworkParameters::regtest().unwrap();
766 assert_eq!(regtest.magic_bytes, [0xfa, 0xbf, 0xb5, 0xda]);
767 assert_eq!(regtest.default_port, 18444);
768 assert!(regtest.is_testnet);
769 }
770
771 #[test]
772 fn test_network_parameters_consistency() {
773 let mainnet = NetworkParameters::mainnet().unwrap();
774 assert_eq!(mainnet.max_target, 0x1d00ffff);
775 assert_eq!(mainnet.halving_interval, 210000);
776
777 let testnet = NetworkParameters::testnet().unwrap();
778 assert_eq!(testnet.max_target, 0x1d00ffff);
779 assert_eq!(testnet.halving_interval, 210000);
780
781 let regtest = NetworkParameters::regtest().unwrap();
782 assert_eq!(regtest.max_target, 0x207fffff); assert_eq!(regtest.halving_interval, 150); }
785
786 #[test]
787 fn test_feature_support() {
788 let mainnet = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
789 assert!(mainnet.supports_feature("segwit"));
790 assert!(mainnet.supports_feature("taproot"));
791 assert!(mainnet.supports_feature("rbf"));
792 assert!(mainnet.supports_feature("ctv"));
793 assert!(!mainnet.supports_feature("fast_mining"));
794 assert!(!mainnet.supports_feature("nonexistent"));
795
796 let testnet = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
797 assert!(testnet.supports_feature("segwit"));
798 assert!(testnet.supports_feature("taproot"));
799 assert!(testnet.supports_feature("rbf"));
800 assert!(testnet.supports_feature("ctv"));
801 assert!(!testnet.supports_feature("fast_mining"));
802
803 let regtest = BitcoinProtocolEngine::new(ProtocolVersion::Regtest).unwrap();
804 assert!(regtest.supports_feature("segwit"));
805 assert!(regtest.supports_feature("taproot"));
806 assert!(regtest.supports_feature("rbf"));
807 assert!(regtest.supports_feature("ctv"));
808 assert!(regtest.supports_feature("fast_mining"));
809
810 let signet = BitcoinProtocolEngine::new(ProtocolVersion::Signet).unwrap();
811 assert!(signet.supports_feature("segwit"));
812 assert!(signet.supports_feature("taproot"));
813 assert!(signet.supports_feature("signet"));
814 assert!(!signet.supports_feature("fast_mining"));
815 }
816
817 #[test]
818 fn test_signet_challenge_override_on_engine() {
819 let engine = BitcoinProtocolEngine::new(ProtocolVersion::Signet)
820 .unwrap()
821 .with_signet_challenge(Some(vec![0x51]));
822 assert_eq!(
823 engine
824 .get_network_params()
825 .signet_challenge
826 .as_ref()
827 .map(|b| b.as_ref()),
828 Some([0x51].as_slice())
829 );
830 let ctx = engine.connect_block_validation_context(None::<&[BlockHeader]>, 0);
831 assert_eq!(
832 ctx.signet_challenge.as_ref().map(|b| b.as_ref()),
833 Some([0x51].as_slice())
834 );
835 }
836
837 #[test]
838 fn test_block_validation_empty_utxos() {
839 use crate::validation::ProtocolValidationContext;
840 use blvm_consensus::opcodes::OP_1;
841
842 let engine = BitcoinProtocolEngine::new(ProtocolVersion::Regtest).unwrap();
843 let utxos = UtxoSet::default();
844
845 let coinbase_tx = Transaction {
846 version: 2,
847 inputs: blvm_consensus::tx_inputs![TransactionInput {
848 prevout: OutPoint {
849 hash: [0u8; 32],
850 index: 0xffffffff,
851 },
852 script_sig: vec![0x00, 0xff],
853 sequence: 0xffffffff,
854 }],
855 outputs: blvm_consensus::tx_outputs![TransactionOutput {
856 value: 5_000_000_000,
857 script_pubkey: vec![OP_1],
858 }],
859 lock_time: 0,
860 };
861
862 let merkle_root = blvm_consensus::mining::calculate_merkle_root(&[coinbase_tx.clone()])
863 .expect("merkle root");
864
865 let block = Block {
866 header: BlockHeader {
867 version: 4,
868 prev_block_hash: [0u8; 32],
869 merkle_root,
870 timestamp: 1_231_006_505,
871 bits: 0x0300ffff,
872 nonce: 0,
873 },
874 transactions: vec![coinbase_tx].into_boxed_slice(),
875 };
876
877 let witnesses: Vec<Vec<blvm_consensus::segwit::Witness>> = block
878 .transactions
879 .iter()
880 .map(|tx| tx.inputs.iter().map(|_| Vec::new()).collect())
881 .collect();
882 let mut context = ProtocolValidationContext::new(ProtocolVersion::Regtest, 0).unwrap();
883 context.network_time = block.header.timestamp;
884 context.median_time_past = block.header.timestamp - 1;
885
886 let (result, new_utxos) = engine
887 .validate_and_connect_block(&block, &witnesses, &utxos, 0, None, &context)
888 .unwrap();
889 assert_eq!(result, ValidationResult::Valid);
890 assert!(!new_utxos.is_empty());
891 }
892
893 #[test]
894 fn test_transaction_validation() {
895 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
896
897 let tx = Transaction {
899 version: 1,
900 inputs: vec![TransactionInput {
901 prevout: OutPoint {
902 hash: [0u8; 32],
903 index: 0,
904 },
905 script_sig: vec![blvm_consensus::opcodes::PUSH_65_BYTES, 0x04],
906 sequence: 0xffffffff,
907 }]
908 .into(),
909 outputs: vec![TransactionOutput {
910 value: 50_0000_0000,
911 script_pubkey: vec![
912 blvm_consensus::opcodes::OP_DUP,
913 blvm_consensus::opcodes::OP_HASH160,
914 blvm_consensus::opcodes::PUSH_20_BYTES,
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 0x00,
932 0x00,
933 0x00,
934 0x00,
935 blvm_consensus::opcodes::OP_EQUALVERIFY,
936 blvm_consensus::opcodes::OP_CHECKSIG,
937 ], }]
939 .into(),
940 lock_time: 0,
941 };
942
943 let result = engine.validate_transaction(&tx);
944 assert!(result.is_ok());
945 }
946
947 #[test]
948 fn test_cross_protocol_validation() {
949 let mainnet_engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
950 let testnet_engine = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
951
952 assert_eq!(
954 mainnet_engine.supports_feature("segwit"),
955 testnet_engine.supports_feature("segwit")
956 );
957 assert_eq!(
958 mainnet_engine.supports_feature("taproot"),
959 testnet_engine.supports_feature("taproot")
960 );
961
962 assert_ne!(
964 mainnet_engine.get_network_params().magic_bytes,
965 testnet_engine.get_network_params().magic_bytes
966 );
967 assert_ne!(
968 mainnet_engine.get_network_params().default_port,
969 testnet_engine.get_network_params().default_port
970 );
971 }
972
973 #[test]
974 fn test_protocol_version_switching() {
975 let versions = vec![
977 ProtocolVersion::BitcoinV1,
978 ProtocolVersion::Testnet3,
979 ProtocolVersion::Regtest,
980 ProtocolVersion::Signet,
981 ];
982
983 for version in versions {
984 let engine = BitcoinProtocolEngine::new(version).unwrap();
985 assert_eq!(engine.get_protocol_version(), version);
986 }
987 }
988
989 #[test]
990 fn test_network_parameters_serialization() {
991 let mainnet = NetworkParameters::mainnet().unwrap();
992 let testnet = NetworkParameters::testnet().unwrap();
993 let regtest = NetworkParameters::regtest().unwrap();
994
995 let mainnet_json = serde_json::to_string(&mainnet).unwrap();
997 let mainnet_deserialized: NetworkParameters = serde_json::from_str(&mainnet_json).unwrap();
998 assert_eq!(mainnet.magic_bytes, mainnet_deserialized.magic_bytes);
999 assert_eq!(mainnet.default_port, mainnet_deserialized.default_port);
1000 assert_eq!(mainnet.network_name, mainnet_deserialized.network_name);
1001 assert_eq!(mainnet.is_testnet, mainnet_deserialized.is_testnet);
1002
1003 let testnet_json = serde_json::to_string(&testnet).unwrap();
1004 let testnet_deserialized: NetworkParameters = serde_json::from_str(&testnet_json).unwrap();
1005 assert_eq!(testnet.magic_bytes, testnet_deserialized.magic_bytes);
1006
1007 let regtest_json = serde_json::to_string(®test).unwrap();
1008 let regtest_deserialized: NetworkParameters = serde_json::from_str(®test_json).unwrap();
1009 assert_eq!(regtest.magic_bytes, regtest_deserialized.magic_bytes);
1010 }
1011
1012 #[test]
1013 fn test_protocol_version_serialization() {
1014 let versions = vec![
1015 ProtocolVersion::BitcoinV1,
1016 ProtocolVersion::Testnet3,
1017 ProtocolVersion::Regtest,
1018 ProtocolVersion::Signet,
1019 ];
1020
1021 for version in versions {
1022 let json = serde_json::to_string(&version).unwrap();
1023 let deserialized: ProtocolVersion = serde_json::from_str(&json).unwrap();
1024 assert_eq!(version, deserialized);
1025 }
1026 }
1027
1028 #[test]
1029 fn test_network_parameters_equality() {
1030 let mainnet1 = NetworkParameters::mainnet().unwrap();
1031 let mainnet2 = NetworkParameters::mainnet().unwrap();
1032 let testnet = NetworkParameters::testnet().unwrap();
1033
1034 assert_eq!(mainnet1, mainnet2);
1035 assert_ne!(mainnet1, testnet);
1036 }
1037
1038 #[test]
1039 fn test_protocol_version_equality() {
1040 assert_eq!(ProtocolVersion::BitcoinV1, ProtocolVersion::BitcoinV1);
1041 assert_ne!(ProtocolVersion::BitcoinV1, ProtocolVersion::Testnet3);
1042 assert_ne!(ProtocolVersion::Testnet3, ProtocolVersion::Regtest);
1043 }
1044
1045 #[test]
1046 fn test_feature_activation_by_height() {
1047 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
1048
1049 assert!(!engine.is_feature_active("segwit", 481_823, 1503539000));
1051 assert!(engine.is_feature_active("segwit", 481_824, 1503539857));
1052 assert!(engine.is_feature_active("segwit", 500_000, 1504000000));
1053
1054 assert!(!engine.is_feature_active("taproot", 709_631, 1636934000));
1056 assert!(engine.is_feature_active("taproot", 709_632, 1636934400));
1057 assert!(engine.is_feature_active("taproot", 800_000, 1640000000));
1058 }
1059
1060 #[test]
1061 fn test_economic_parameters_access() {
1062 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
1063 let params = engine.get_economic_parameters();
1064
1065 assert_eq!(params.initial_subsidy, 50_0000_0000);
1066 assert_eq!(params.halving_interval, 210_000);
1067 assert_eq!(params.coinbase_maturity, 100);
1068
1069 assert_eq!(params.get_block_subsidy(0), 50_0000_0000);
1071 assert_eq!(params.get_block_subsidy(210_000), 25_0000_0000);
1072 }
1073
1074 #[test]
1075 fn test_feature_registry_access() {
1076 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
1077 let registry = engine.get_feature_registry();
1078
1079 assert!(registry.get_feature("segwit").is_some());
1080 assert!(registry.get_feature("taproot").is_some());
1081 assert!(registry.get_feature("nonexistent").is_none());
1082
1083 let features = registry.list_features();
1084 assert!(features.contains(&"segwit".to_string()));
1085 assert!(features.contains(&"taproot".to_string()));
1086 }
1087}