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}
275
276impl ProtocolVersion {
277 pub fn consensus_network(self) -> types::Network {
279 match self {
280 ProtocolVersion::BitcoinV1 => types::Network::Mainnet,
281 ProtocolVersion::Testnet3 => types::Network::Testnet,
282 ProtocolVersion::Regtest => types::Network::Regtest,
283 ProtocolVersion::Signet => types::Network::Signet,
284 }
285 }
286}
287
288#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
290pub struct NetworkParameters {
291 pub magic_bytes: [u8; 4],
293 pub default_port: u16,
295 pub genesis_block: Block,
297 pub max_target: u32,
299 pub halving_interval: u64,
301 pub network_name: String,
303 pub is_testnet: bool,
305 #[serde(default, skip_serializing_if = "Option::is_none")]
307 pub signet_challenge: Option<ByteString>,
308}
309
310impl BitcoinProtocolEngine {
311 pub fn new(version: ProtocolVersion) -> Result<Self> {
313 Self::with_config(version, ProtocolConfig::default())
314 }
315
316 pub fn with_config(version: ProtocolVersion, config: ProtocolConfig) -> Result<Self> {
318 let consensus = ConsensusProof::new();
319 let network_params = NetworkParameters::for_version(version)?;
320
321 Ok(BitcoinProtocolEngine {
322 consensus,
323 protocol_version: version,
324 network_params,
325 config,
326 })
327 }
328
329 pub fn get_config(&self) -> &ProtocolConfig {
331 &self.config
332 }
333
334 pub fn get_config_mut(&mut self) -> &mut ProtocolConfig {
336 &mut self.config
337 }
338
339 pub fn get_protocol_version(&self) -> ProtocolVersion {
341 self.protocol_version
342 }
343
344 pub fn get_network_params(&self) -> &NetworkParameters {
346 &self.network_params
347 }
348
349 pub fn with_signet_challenge(mut self, script: Option<Vec<u8>>) -> Self {
351 self.network_params.signet_challenge = script;
352 self
353 }
354
355 pub fn connect_block_validation_context<H: AsRef<BlockHeader>>(
357 &self,
358 recent_headers: Option<&[H]>,
359 network_time: u64,
360 ) -> block::BlockValidationContext {
361 let mut ctx = block::block_validation_context_for_connect_ibd(
362 recent_headers,
363 network_time,
364 self.protocol_version.consensus_network(),
365 );
366 ctx.signet_challenge = self.network_params.signet_challenge.clone();
367 ctx
368 }
369
370 #[deprecated(
382 since = "0.1.0",
383 note = "Use validate_and_connect_block with explicit witnesses and a ProtocolValidationContext"
384 )]
385 pub fn validate_block(
386 &self,
387 block: &Block,
388 utxos: &UtxoSet,
389 height: u64,
390 ) -> Result<ValidationResult> {
391 let network = self.protocol_version.consensus_network();
392 let witnesses: Vec<Vec<blvm_consensus::segwit::Witness>> = block
396 .transactions
397 .iter()
398 .map(|tx| tx.inputs.iter().map(|_| Vec::new()).collect())
399 .collect();
400 let now_secs = std::time::SystemTime::now()
403 .duration_since(std::time::UNIX_EPOCH)
404 .unwrap_or_default()
405 .as_secs();
406 let time_ctx = blvm_consensus::types::TimeContext {
407 network_time: now_secs,
408 median_time_past: now_secs,
411 };
412 let (result, _) = self
413 .consensus
414 .validate_block_with_time_context(
415 block,
416 &witnesses,
417 utxos.clone(),
418 height,
419 Some(time_ctx),
420 network,
421 )
422 .map_err(ProtocolError::from)?;
423 Ok(result)
424 }
425
426 pub fn validate_transaction(&self, tx: &Transaction) -> Result<ValidationResult> {
428 self.consensus
429 .validate_transaction(tx)
430 .map_err(ProtocolError::from)
431 }
432
433 pub fn validate_and_connect_block(
491 &self,
492 block: &Block,
493 witnesses: &[Vec<segwit::Witness>], utxos: &UtxoSet,
497 height: u64,
498 recent_headers: Option<&[BlockHeader]>,
499 context: &validation::ProtocolValidationContext,
500 ) -> Result<(ValidationResult, UtxoSet)> {
501 let protocol_result = self
503 .validate_block_with_protocol_and_witnesses(block, witnesses, utxos, height, context)?;
504 if !matches!(protocol_result, ValidationResult::Valid) {
505 return Ok((protocol_result, utxos.clone()));
506 }
507
508 let network_time = if context.network_time > 0 {
510 context.network_time
511 } else {
512 crate::time::current_timestamp()
513 };
514 let mut consensus_ctx = if context.median_time_past > 0 {
515 block::BlockValidationContext::from_time_context_and_network(
516 Some(blvm_consensus::types::TimeContext {
517 network_time,
518 median_time_past: context.median_time_past,
519 }),
520 self.protocol_version.consensus_network(),
521 None,
522 )
523 } else {
524 self.connect_block_validation_context(recent_headers, network_time)
525 };
526 consensus_ctx.signet_challenge = self.network_params.signet_challenge.clone();
527 let (result, new_utxo_set, _undo_log) = blvm_consensus::block::connect_block(
528 block,
529 witnesses,
530 utxos.clone(),
531 height,
532 &consensus_ctx,
533 )?;
534
535 Ok((result, new_utxo_set))
536 }
537
538 pub fn supports_feature(&self, feature: &str) -> bool {
540 match self.protocol_version {
541 ProtocolVersion::BitcoinV1 => {
542 matches!(feature, "segwit" | "taproot" | "rbf" | "ctv")
543 }
544 ProtocolVersion::Testnet3 => {
545 matches!(feature, "segwit" | "taproot" | "rbf" | "ctv")
546 }
547 ProtocolVersion::Regtest => {
548 matches!(
549 feature,
550 "segwit" | "taproot" | "rbf" | "ctv" | "fast_mining"
551 )
552 }
553 ProtocolVersion::Signet => {
554 matches!(feature, "segwit" | "taproot" | "rbf" | "ctv" | "signet")
555 }
556 }
557 }
558
559 pub fn is_feature_active(&self, feature: &str, height: u64, timestamp: u64) -> bool {
561 let registry = features::FeatureRegistry::for_protocol(self.protocol_version);
562 registry.is_feature_active(feature, height, timestamp)
563 }
564
565 pub fn get_economic_parameters(&self) -> economic::EconomicParameters {
567 economic::EconomicParameters::for_protocol(self.protocol_version)
568 }
569
570 pub fn get_feature_registry(&self) -> features::FeatureRegistry {
572 features::FeatureRegistry::for_protocol(self.protocol_version)
573 }
574
575 pub fn feature_context(&self, height: u64, timestamp: u64) -> features::FeatureContext {
578 let registry = features::FeatureRegistry::for_protocol(self.protocol_version);
579 registry.create_context(height, timestamp)
580 }
581}
582
583impl NetworkParameters {
584 pub fn for_version(version: ProtocolVersion) -> Result<Self> {
586 match version {
587 ProtocolVersion::BitcoinV1 => Self::mainnet(),
588 ProtocolVersion::Testnet3 => Self::testnet(),
589 ProtocolVersion::Regtest => Self::regtest(),
590 ProtocolVersion::Signet => Self::signet(),
591 }
592 }
593
594 pub fn mainnet() -> Result<Self> {
596 Ok(NetworkParameters {
597 magic_bytes: [0xf9, 0xbe, 0xb4, 0xd9], default_port: 8333,
599 genesis_block: genesis::mainnet_genesis(),
600 max_target: 0x1d00ffff,
601 halving_interval: 210000,
602 network_name: "mainnet".to_string(),
603 is_testnet: false,
604 signet_challenge: None,
605 })
606 }
607
608 pub fn testnet() -> Result<Self> {
610 Ok(NetworkParameters {
611 magic_bytes: [0x0b, 0x11, 0x09, 0x07], default_port: 18333,
613 genesis_block: genesis::testnet_genesis(),
614 max_target: 0x1d00ffff,
615 halving_interval: 210000,
616 network_name: "testnet".to_string(),
617 is_testnet: true,
618 signet_challenge: None,
619 })
620 }
621
622 pub fn regtest() -> Result<Self> {
624 Ok(NetworkParameters {
625 magic_bytes: [0xfa, 0xbf, 0xb5, 0xda], default_port: 18444,
627 genesis_block: genesis::regtest_genesis(),
628 max_target: 0x207fffff, halving_interval: 150, network_name: "regtest".to_string(),
631 is_testnet: true,
632 signet_challenge: None,
633 })
634 }
635
636 pub fn signet() -> Result<Self> {
638 Ok(NetworkParameters {
639 magic_bytes: [0x0f, 0x1b, 0xf2, 0xe1],
640 default_port: 38333,
641 genesis_block: genesis::signet_genesis(),
642 max_target: 0x1e0377ae,
643 halving_interval: 210_000,
644 network_name: "signet".to_string(),
645 is_testnet: true,
646 signet_challenge: None,
647 })
648 }
649}
650
651#[cfg(test)]
652mod tests {
653 use super::*;
654 use blvm_consensus::types::{BlockHeader, OutPoint, TransactionInput, TransactionOutput};
655
656 #[test]
657 fn test_blvm_protocol_creation() {
658 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
659 assert_eq!(engine.get_protocol_version(), ProtocolVersion::BitcoinV1);
660 assert_eq!(engine.get_network_params().network_name, "mainnet");
661 }
662
663 #[test]
664 fn test_blvm_protocol_creation_all_variants() {
665 let mainnet = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
667 assert_eq!(mainnet.get_protocol_version(), ProtocolVersion::BitcoinV1);
668 assert_eq!(mainnet.get_network_params().network_name, "mainnet");
669 assert!(!mainnet.get_network_params().is_testnet);
670
671 let testnet = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
673 assert_eq!(testnet.get_protocol_version(), ProtocolVersion::Testnet3);
674 assert_eq!(testnet.get_network_params().network_name, "testnet");
675 assert!(testnet.get_network_params().is_testnet);
676
677 let regtest = BitcoinProtocolEngine::new(ProtocolVersion::Regtest).unwrap();
679 assert_eq!(regtest.get_protocol_version(), ProtocolVersion::Regtest);
680 assert_eq!(regtest.get_network_params().network_name, "regtest");
681 assert!(regtest.get_network_params().is_testnet);
682
683 let signet = BitcoinProtocolEngine::new(ProtocolVersion::Signet).unwrap();
685 assert_eq!(signet.get_protocol_version(), ProtocolVersion::Signet);
686 assert_eq!(signet.get_network_params().network_name, "signet");
687 assert!(signet.get_network_params().is_testnet);
688 assert_eq!(signet.get_network_params().default_port, 38333);
689 }
690
691 #[test]
692 fn test_network_parameters() {
693 let mainnet = NetworkParameters::mainnet().unwrap();
694 assert_eq!(mainnet.magic_bytes, [0xf9, 0xbe, 0xb4, 0xd9]);
695 assert_eq!(mainnet.default_port, 8333);
696 assert!(!mainnet.is_testnet);
697
698 let testnet = NetworkParameters::testnet().unwrap();
699 assert_eq!(testnet.magic_bytes, [0x0b, 0x11, 0x09, 0x07]);
700 assert_eq!(testnet.default_port, 18333);
701 assert!(testnet.is_testnet);
702
703 let regtest = NetworkParameters::regtest().unwrap();
704 assert_eq!(regtest.magic_bytes, [0xfa, 0xbf, 0xb5, 0xda]);
705 assert_eq!(regtest.default_port, 18444);
706 assert!(regtest.is_testnet);
707 }
708
709 #[test]
710 fn test_network_parameters_consistency() {
711 let mainnet = NetworkParameters::mainnet().unwrap();
712 assert_eq!(mainnet.max_target, 0x1d00ffff);
713 assert_eq!(mainnet.halving_interval, 210000);
714
715 let testnet = NetworkParameters::testnet().unwrap();
716 assert_eq!(testnet.max_target, 0x1d00ffff);
717 assert_eq!(testnet.halving_interval, 210000);
718
719 let regtest = NetworkParameters::regtest().unwrap();
720 assert_eq!(regtest.max_target, 0x207fffff); assert_eq!(regtest.halving_interval, 150); }
723
724 #[test]
725 fn test_feature_support() {
726 let mainnet = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
727 assert!(mainnet.supports_feature("segwit"));
728 assert!(mainnet.supports_feature("taproot"));
729 assert!(mainnet.supports_feature("rbf"));
730 assert!(mainnet.supports_feature("ctv"));
731 assert!(!mainnet.supports_feature("fast_mining"));
732 assert!(!mainnet.supports_feature("nonexistent"));
733
734 let testnet = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
735 assert!(testnet.supports_feature("segwit"));
736 assert!(testnet.supports_feature("taproot"));
737 assert!(testnet.supports_feature("rbf"));
738 assert!(testnet.supports_feature("ctv"));
739 assert!(!testnet.supports_feature("fast_mining"));
740
741 let regtest = BitcoinProtocolEngine::new(ProtocolVersion::Regtest).unwrap();
742 assert!(regtest.supports_feature("segwit"));
743 assert!(regtest.supports_feature("taproot"));
744 assert!(regtest.supports_feature("rbf"));
745 assert!(regtest.supports_feature("ctv"));
746 assert!(regtest.supports_feature("fast_mining"));
747
748 let signet = BitcoinProtocolEngine::new(ProtocolVersion::Signet).unwrap();
749 assert!(signet.supports_feature("segwit"));
750 assert!(signet.supports_feature("taproot"));
751 assert!(signet.supports_feature("signet"));
752 assert!(!signet.supports_feature("fast_mining"));
753 }
754
755 #[test]
756 fn test_signet_challenge_override_on_engine() {
757 let engine = BitcoinProtocolEngine::new(ProtocolVersion::Signet)
758 .unwrap()
759 .with_signet_challenge(Some(vec![0x51]));
760 assert_eq!(
761 engine
762 .get_network_params()
763 .signet_challenge
764 .as_ref()
765 .map(|b| b.as_ref()),
766 Some([0x51].as_slice())
767 );
768 let ctx = engine.connect_block_validation_context(None::<&[BlockHeader]>, 0);
769 assert_eq!(
770 ctx.signet_challenge.as_ref().map(|b| b.as_ref()),
771 Some([0x51].as_slice())
772 );
773 }
774
775 #[test]
776 fn test_block_validation_empty_utxos() {
777 use crate::validation::ProtocolValidationContext;
778 use blvm_consensus::opcodes::OP_1;
779
780 let engine = BitcoinProtocolEngine::new(ProtocolVersion::Regtest).unwrap();
781 let utxos = UtxoSet::default();
782
783 let coinbase_tx = Transaction {
784 version: 2,
785 inputs: blvm_consensus::tx_inputs![TransactionInput {
786 prevout: OutPoint {
787 hash: [0u8; 32],
788 index: 0xffffffff,
789 },
790 script_sig: vec![0x01, 0x00],
791 sequence: 0xffffffff,
792 }],
793 outputs: blvm_consensus::tx_outputs![TransactionOutput {
794 value: 5_000_000_000,
795 script_pubkey: vec![OP_1],
796 }],
797 lock_time: 0,
798 };
799
800 let merkle_root = blvm_consensus::mining::calculate_merkle_root(&[coinbase_tx.clone()])
801 .expect("merkle root");
802
803 let block = Block {
804 header: BlockHeader {
805 version: 4,
806 prev_block_hash: [0u8; 32],
807 merkle_root,
808 timestamp: 1_231_006_505,
809 bits: 0x0300ffff,
810 nonce: 0,
811 },
812 transactions: vec![coinbase_tx].into_boxed_slice(),
813 };
814
815 let witnesses: Vec<Vec<blvm_consensus::segwit::Witness>> = block
816 .transactions
817 .iter()
818 .map(|tx| tx.inputs.iter().map(|_| Vec::new()).collect())
819 .collect();
820 let mut context = ProtocolValidationContext::new(ProtocolVersion::Regtest, 0).unwrap();
821 context.network_time = block.header.timestamp;
822 context.median_time_past = block.header.timestamp;
823
824 let (result, new_utxos) = engine
825 .validate_and_connect_block(&block, &witnesses, &utxos, 0, None, &context)
826 .unwrap();
827 assert_eq!(result, ValidationResult::Valid);
828 assert!(!new_utxos.is_empty());
829 }
830
831 #[test]
832 fn test_transaction_validation() {
833 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
834
835 let tx = Transaction {
837 version: 1,
838 inputs: vec![TransactionInput {
839 prevout: OutPoint {
840 hash: [0u8; 32],
841 index: 0,
842 },
843 script_sig: vec![blvm_consensus::opcodes::PUSH_65_BYTES, 0x04],
844 sequence: 0xffffffff,
845 }]
846 .into(),
847 outputs: vec![TransactionOutput {
848 value: 50_0000_0000,
849 script_pubkey: vec![
850 blvm_consensus::opcodes::OP_DUP,
851 blvm_consensus::opcodes::OP_HASH160,
852 blvm_consensus::opcodes::PUSH_20_BYTES,
853 0x00,
854 0x00,
855 0x00,
856 0x00,
857 0x00,
858 0x00,
859 0x00,
860 0x00,
861 0x00,
862 0x00,
863 0x00,
864 0x00,
865 0x00,
866 0x00,
867 0x00,
868 0x00,
869 0x00,
870 0x00,
871 0x00,
872 0x00,
873 blvm_consensus::opcodes::OP_EQUALVERIFY,
874 blvm_consensus::opcodes::OP_CHECKSIG,
875 ], }]
877 .into(),
878 lock_time: 0,
879 };
880
881 let result = engine.validate_transaction(&tx);
882 assert!(result.is_ok());
883 }
884
885 #[test]
886 fn test_cross_protocol_validation() {
887 let mainnet_engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
888 let testnet_engine = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
889
890 assert_eq!(
892 mainnet_engine.supports_feature("segwit"),
893 testnet_engine.supports_feature("segwit")
894 );
895 assert_eq!(
896 mainnet_engine.supports_feature("taproot"),
897 testnet_engine.supports_feature("taproot")
898 );
899
900 assert_ne!(
902 mainnet_engine.get_network_params().magic_bytes,
903 testnet_engine.get_network_params().magic_bytes
904 );
905 assert_ne!(
906 mainnet_engine.get_network_params().default_port,
907 testnet_engine.get_network_params().default_port
908 );
909 }
910
911 #[test]
912 fn test_protocol_version_switching() {
913 let versions = vec![
915 ProtocolVersion::BitcoinV1,
916 ProtocolVersion::Testnet3,
917 ProtocolVersion::Regtest,
918 ProtocolVersion::Signet,
919 ];
920
921 for version in versions {
922 let engine = BitcoinProtocolEngine::new(version).unwrap();
923 assert_eq!(engine.get_protocol_version(), version);
924 }
925 }
926
927 #[test]
928 fn test_network_parameters_serialization() {
929 let mainnet = NetworkParameters::mainnet().unwrap();
930 let testnet = NetworkParameters::testnet().unwrap();
931 let regtest = NetworkParameters::regtest().unwrap();
932
933 let mainnet_json = serde_json::to_string(&mainnet).unwrap();
935 let mainnet_deserialized: NetworkParameters = serde_json::from_str(&mainnet_json).unwrap();
936 assert_eq!(mainnet.magic_bytes, mainnet_deserialized.magic_bytes);
937 assert_eq!(mainnet.default_port, mainnet_deserialized.default_port);
938 assert_eq!(mainnet.network_name, mainnet_deserialized.network_name);
939 assert_eq!(mainnet.is_testnet, mainnet_deserialized.is_testnet);
940
941 let testnet_json = serde_json::to_string(&testnet).unwrap();
942 let testnet_deserialized: NetworkParameters = serde_json::from_str(&testnet_json).unwrap();
943 assert_eq!(testnet.magic_bytes, testnet_deserialized.magic_bytes);
944
945 let regtest_json = serde_json::to_string(®test).unwrap();
946 let regtest_deserialized: NetworkParameters = serde_json::from_str(®test_json).unwrap();
947 assert_eq!(regtest.magic_bytes, regtest_deserialized.magic_bytes);
948 }
949
950 #[test]
951 fn test_protocol_version_serialization() {
952 let versions = vec![
953 ProtocolVersion::BitcoinV1,
954 ProtocolVersion::Testnet3,
955 ProtocolVersion::Regtest,
956 ProtocolVersion::Signet,
957 ];
958
959 for version in versions {
960 let json = serde_json::to_string(&version).unwrap();
961 let deserialized: ProtocolVersion = serde_json::from_str(&json).unwrap();
962 assert_eq!(version, deserialized);
963 }
964 }
965
966 #[test]
967 fn test_network_parameters_equality() {
968 let mainnet1 = NetworkParameters::mainnet().unwrap();
969 let mainnet2 = NetworkParameters::mainnet().unwrap();
970 let testnet = NetworkParameters::testnet().unwrap();
971
972 assert_eq!(mainnet1, mainnet2);
973 assert_ne!(mainnet1, testnet);
974 }
975
976 #[test]
977 fn test_protocol_version_equality() {
978 assert_eq!(ProtocolVersion::BitcoinV1, ProtocolVersion::BitcoinV1);
979 assert_ne!(ProtocolVersion::BitcoinV1, ProtocolVersion::Testnet3);
980 assert_ne!(ProtocolVersion::Testnet3, ProtocolVersion::Regtest);
981 }
982
983 #[test]
984 fn test_feature_activation_by_height() {
985 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
986
987 assert!(!engine.is_feature_active("segwit", 481_823, 1503539000));
989 assert!(engine.is_feature_active("segwit", 481_824, 1503539857));
990 assert!(engine.is_feature_active("segwit", 500_000, 1504000000));
991
992 assert!(!engine.is_feature_active("taproot", 709_631, 1636934000));
994 assert!(engine.is_feature_active("taproot", 709_632, 1636934400));
995 assert!(engine.is_feature_active("taproot", 800_000, 1640000000));
996 }
997
998 #[test]
999 fn test_economic_parameters_access() {
1000 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
1001 let params = engine.get_economic_parameters();
1002
1003 assert_eq!(params.initial_subsidy, 50_0000_0000);
1004 assert_eq!(params.halving_interval, 210_000);
1005 assert_eq!(params.coinbase_maturity, 100);
1006
1007 assert_eq!(params.get_block_subsidy(0), 50_0000_0000);
1009 assert_eq!(params.get_block_subsidy(210_000), 25_0000_0000);
1010 }
1011
1012 #[test]
1013 fn test_feature_registry_access() {
1014 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
1015 let registry = engine.get_feature_registry();
1016
1017 assert!(registry.get_feature("segwit").is_some());
1018 assert!(registry.get_feature("taproot").is_some());
1019 assert!(registry.get_feature("nonexistent").is_none());
1020
1021 let features = registry.list_features();
1022 assert!(features.contains(&"segwit".to_string()));
1023 assert!(features.contains(&"taproot".to_string()));
1024 }
1025}