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: 210000,
636 network_name: "mainnet".to_string(),
637 is_testnet: false,
638 signet_challenge: None,
639 })
640 }
641
642 pub fn testnet() -> Result<Self> {
644 Ok(NetworkParameters {
645 magic_bytes: [0x0b, 0x11, 0x09, 0x07], default_port: 18333,
647 genesis_block: genesis::testnet_genesis(),
648 max_target: 0x1d00ffff,
649 halving_interval: 210000,
650 network_name: "testnet".to_string(),
651 is_testnet: true,
652 signet_challenge: None,
653 })
654 }
655
656 pub fn regtest() -> Result<Self> {
658 Ok(NetworkParameters {
659 magic_bytes: [0xfa, 0xbf, 0xb5, 0xda], default_port: 18444,
661 genesis_block: genesis::regtest_genesis(),
662 max_target: 0x207fffff, halving_interval: 150, network_name: "regtest".to_string(),
665 is_testnet: true,
666 signet_challenge: None,
667 })
668 }
669
670 pub fn signet() -> Result<Self> {
672 Ok(NetworkParameters {
673 magic_bytes: [0x0f, 0x1b, 0xf2, 0xe1],
674 default_port: 38333,
675 genesis_block: genesis::signet_genesis(),
676 max_target: 0x1e0377ae,
677 halving_interval: 210_000,
678 network_name: "signet".to_string(),
679 is_testnet: true,
680 signet_challenge: None,
681 })
682 }
683
684 pub fn testnet4() -> Result<Self> {
686 Ok(NetworkParameters {
687 magic_bytes: [0x1c, 0x16, 0x3f, 0x28],
688 default_port: 48333,
689 genesis_block: genesis::testnet4_genesis(),
690 max_target: 0x1d00ffff,
691 halving_interval: 210_000,
692 network_name: "testnet4".to_string(),
693 is_testnet: true,
694 signet_challenge: None,
695 })
696 }
697}
698
699#[cfg(test)]
700mod tests {
701 use super::*;
702 use blvm_consensus::types::{BlockHeader, OutPoint, TransactionInput, TransactionOutput};
703
704 #[test]
705 fn test_blvm_protocol_creation() {
706 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
707 assert_eq!(engine.get_protocol_version(), ProtocolVersion::BitcoinV1);
708 assert_eq!(engine.get_network_params().network_name, "mainnet");
709 }
710
711 #[test]
712 fn test_blvm_protocol_creation_all_variants() {
713 let mainnet = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
715 assert_eq!(mainnet.get_protocol_version(), ProtocolVersion::BitcoinV1);
716 assert_eq!(mainnet.get_network_params().network_name, "mainnet");
717 assert!(!mainnet.get_network_params().is_testnet);
718
719 let testnet = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
721 assert_eq!(testnet.get_protocol_version(), ProtocolVersion::Testnet3);
722 assert_eq!(testnet.get_network_params().network_name, "testnet");
723 assert!(testnet.get_network_params().is_testnet);
724
725 let regtest = BitcoinProtocolEngine::new(ProtocolVersion::Regtest).unwrap();
727 assert_eq!(regtest.get_protocol_version(), ProtocolVersion::Regtest);
728 assert_eq!(regtest.get_network_params().network_name, "regtest");
729 assert!(regtest.get_network_params().is_testnet);
730
731 let signet = BitcoinProtocolEngine::new(ProtocolVersion::Signet).unwrap();
733 assert_eq!(signet.get_protocol_version(), ProtocolVersion::Signet);
734 assert_eq!(signet.get_network_params().network_name, "signet");
735 assert!(signet.get_network_params().is_testnet);
736 assert_eq!(signet.get_network_params().default_port, 38333);
737 }
738
739 #[test]
740 fn test_network_parameters() {
741 let mainnet = NetworkParameters::mainnet().unwrap();
742 assert_eq!(mainnet.magic_bytes, [0xf9, 0xbe, 0xb4, 0xd9]);
743 assert_eq!(mainnet.default_port, 8333);
744 assert!(!mainnet.is_testnet);
745
746 let testnet = NetworkParameters::testnet().unwrap();
747 assert_eq!(testnet.magic_bytes, [0x0b, 0x11, 0x09, 0x07]);
748 assert_eq!(testnet.default_port, 18333);
749 assert!(testnet.is_testnet);
750
751 let regtest = NetworkParameters::regtest().unwrap();
752 assert_eq!(regtest.magic_bytes, [0xfa, 0xbf, 0xb5, 0xda]);
753 assert_eq!(regtest.default_port, 18444);
754 assert!(regtest.is_testnet);
755 }
756
757 #[test]
758 fn test_network_parameters_consistency() {
759 let mainnet = NetworkParameters::mainnet().unwrap();
760 assert_eq!(mainnet.max_target, 0x1d00ffff);
761 assert_eq!(mainnet.halving_interval, 210000);
762
763 let testnet = NetworkParameters::testnet().unwrap();
764 assert_eq!(testnet.max_target, 0x1d00ffff);
765 assert_eq!(testnet.halving_interval, 210000);
766
767 let regtest = NetworkParameters::regtest().unwrap();
768 assert_eq!(regtest.max_target, 0x207fffff); assert_eq!(regtest.halving_interval, 150); }
771
772 #[test]
773 fn test_feature_support() {
774 let mainnet = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
775 assert!(mainnet.supports_feature("segwit"));
776 assert!(mainnet.supports_feature("taproot"));
777 assert!(mainnet.supports_feature("rbf"));
778 assert!(mainnet.supports_feature("ctv"));
779 assert!(!mainnet.supports_feature("fast_mining"));
780 assert!(!mainnet.supports_feature("nonexistent"));
781
782 let testnet = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
783 assert!(testnet.supports_feature("segwit"));
784 assert!(testnet.supports_feature("taproot"));
785 assert!(testnet.supports_feature("rbf"));
786 assert!(testnet.supports_feature("ctv"));
787 assert!(!testnet.supports_feature("fast_mining"));
788
789 let regtest = BitcoinProtocolEngine::new(ProtocolVersion::Regtest).unwrap();
790 assert!(regtest.supports_feature("segwit"));
791 assert!(regtest.supports_feature("taproot"));
792 assert!(regtest.supports_feature("rbf"));
793 assert!(regtest.supports_feature("ctv"));
794 assert!(regtest.supports_feature("fast_mining"));
795
796 let signet = BitcoinProtocolEngine::new(ProtocolVersion::Signet).unwrap();
797 assert!(signet.supports_feature("segwit"));
798 assert!(signet.supports_feature("taproot"));
799 assert!(signet.supports_feature("signet"));
800 assert!(!signet.supports_feature("fast_mining"));
801 }
802
803 #[test]
804 fn test_signet_challenge_override_on_engine() {
805 let engine = BitcoinProtocolEngine::new(ProtocolVersion::Signet)
806 .unwrap()
807 .with_signet_challenge(Some(vec![0x51]));
808 assert_eq!(
809 engine
810 .get_network_params()
811 .signet_challenge
812 .as_ref()
813 .map(|b| b.as_ref()),
814 Some([0x51].as_slice())
815 );
816 let ctx = engine.connect_block_validation_context(None::<&[BlockHeader]>, 0);
817 assert_eq!(
818 ctx.signet_challenge.as_ref().map(|b| b.as_ref()),
819 Some([0x51].as_slice())
820 );
821 }
822
823 #[test]
824 fn test_block_validation_empty_utxos() {
825 use crate::validation::ProtocolValidationContext;
826 use blvm_consensus::opcodes::OP_1;
827
828 let engine = BitcoinProtocolEngine::new(ProtocolVersion::Regtest).unwrap();
829 let utxos = UtxoSet::default();
830
831 let coinbase_tx = Transaction {
832 version: 2,
833 inputs: blvm_consensus::tx_inputs![TransactionInput {
834 prevout: OutPoint {
835 hash: [0u8; 32],
836 index: 0xffffffff,
837 },
838 script_sig: vec![0x00, 0xff],
839 sequence: 0xffffffff,
840 }],
841 outputs: blvm_consensus::tx_outputs![TransactionOutput {
842 value: 5_000_000_000,
843 script_pubkey: vec![OP_1],
844 }],
845 lock_time: 0,
846 };
847
848 let merkle_root = blvm_consensus::mining::calculate_merkle_root(&[coinbase_tx.clone()])
849 .expect("merkle root");
850
851 let block = Block {
852 header: BlockHeader {
853 version: 4,
854 prev_block_hash: [0u8; 32],
855 merkle_root,
856 timestamp: 1_231_006_505,
857 bits: 0x0300ffff,
858 nonce: 0,
859 },
860 transactions: vec![coinbase_tx].into_boxed_slice(),
861 };
862
863 let witnesses: Vec<Vec<blvm_consensus::segwit::Witness>> = block
864 .transactions
865 .iter()
866 .map(|tx| tx.inputs.iter().map(|_| Vec::new()).collect())
867 .collect();
868 let mut context = ProtocolValidationContext::new(ProtocolVersion::Regtest, 0).unwrap();
869 context.network_time = block.header.timestamp;
870 context.median_time_past = block.header.timestamp - 1;
871
872 let (result, new_utxos) = engine
873 .validate_and_connect_block(&block, &witnesses, &utxos, 0, None, &context)
874 .unwrap();
875 assert_eq!(result, ValidationResult::Valid);
876 assert!(!new_utxos.is_empty());
877 }
878
879 #[test]
880 fn test_transaction_validation() {
881 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
882
883 let tx = Transaction {
885 version: 1,
886 inputs: vec![TransactionInput {
887 prevout: OutPoint {
888 hash: [0u8; 32],
889 index: 0,
890 },
891 script_sig: vec![blvm_consensus::opcodes::PUSH_65_BYTES, 0x04],
892 sequence: 0xffffffff,
893 }]
894 .into(),
895 outputs: vec![TransactionOutput {
896 value: 50_0000_0000,
897 script_pubkey: vec![
898 blvm_consensus::opcodes::OP_DUP,
899 blvm_consensus::opcodes::OP_HASH160,
900 blvm_consensus::opcodes::PUSH_20_BYTES,
901 0x00,
902 0x00,
903 0x00,
904 0x00,
905 0x00,
906 0x00,
907 0x00,
908 0x00,
909 0x00,
910 0x00,
911 0x00,
912 0x00,
913 0x00,
914 0x00,
915 0x00,
916 0x00,
917 0x00,
918 0x00,
919 0x00,
920 0x00,
921 blvm_consensus::opcodes::OP_EQUALVERIFY,
922 blvm_consensus::opcodes::OP_CHECKSIG,
923 ], }]
925 .into(),
926 lock_time: 0,
927 };
928
929 let result = engine.validate_transaction(&tx);
930 assert!(result.is_ok());
931 }
932
933 #[test]
934 fn test_cross_protocol_validation() {
935 let mainnet_engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
936 let testnet_engine = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
937
938 assert_eq!(
940 mainnet_engine.supports_feature("segwit"),
941 testnet_engine.supports_feature("segwit")
942 );
943 assert_eq!(
944 mainnet_engine.supports_feature("taproot"),
945 testnet_engine.supports_feature("taproot")
946 );
947
948 assert_ne!(
950 mainnet_engine.get_network_params().magic_bytes,
951 testnet_engine.get_network_params().magic_bytes
952 );
953 assert_ne!(
954 mainnet_engine.get_network_params().default_port,
955 testnet_engine.get_network_params().default_port
956 );
957 }
958
959 #[test]
960 fn test_protocol_version_switching() {
961 let versions = vec![
963 ProtocolVersion::BitcoinV1,
964 ProtocolVersion::Testnet3,
965 ProtocolVersion::Regtest,
966 ProtocolVersion::Signet,
967 ];
968
969 for version in versions {
970 let engine = BitcoinProtocolEngine::new(version).unwrap();
971 assert_eq!(engine.get_protocol_version(), version);
972 }
973 }
974
975 #[test]
976 fn test_network_parameters_serialization() {
977 let mainnet = NetworkParameters::mainnet().unwrap();
978 let testnet = NetworkParameters::testnet().unwrap();
979 let regtest = NetworkParameters::regtest().unwrap();
980
981 let mainnet_json = serde_json::to_string(&mainnet).unwrap();
983 let mainnet_deserialized: NetworkParameters = serde_json::from_str(&mainnet_json).unwrap();
984 assert_eq!(mainnet.magic_bytes, mainnet_deserialized.magic_bytes);
985 assert_eq!(mainnet.default_port, mainnet_deserialized.default_port);
986 assert_eq!(mainnet.network_name, mainnet_deserialized.network_name);
987 assert_eq!(mainnet.is_testnet, mainnet_deserialized.is_testnet);
988
989 let testnet_json = serde_json::to_string(&testnet).unwrap();
990 let testnet_deserialized: NetworkParameters = serde_json::from_str(&testnet_json).unwrap();
991 assert_eq!(testnet.magic_bytes, testnet_deserialized.magic_bytes);
992
993 let regtest_json = serde_json::to_string(®test).unwrap();
994 let regtest_deserialized: NetworkParameters = serde_json::from_str(®test_json).unwrap();
995 assert_eq!(regtest.magic_bytes, regtest_deserialized.magic_bytes);
996 }
997
998 #[test]
999 fn test_protocol_version_serialization() {
1000 let versions = vec![
1001 ProtocolVersion::BitcoinV1,
1002 ProtocolVersion::Testnet3,
1003 ProtocolVersion::Regtest,
1004 ProtocolVersion::Signet,
1005 ];
1006
1007 for version in versions {
1008 let json = serde_json::to_string(&version).unwrap();
1009 let deserialized: ProtocolVersion = serde_json::from_str(&json).unwrap();
1010 assert_eq!(version, deserialized);
1011 }
1012 }
1013
1014 #[test]
1015 fn test_network_parameters_equality() {
1016 let mainnet1 = NetworkParameters::mainnet().unwrap();
1017 let mainnet2 = NetworkParameters::mainnet().unwrap();
1018 let testnet = NetworkParameters::testnet().unwrap();
1019
1020 assert_eq!(mainnet1, mainnet2);
1021 assert_ne!(mainnet1, testnet);
1022 }
1023
1024 #[test]
1025 fn test_protocol_version_equality() {
1026 assert_eq!(ProtocolVersion::BitcoinV1, ProtocolVersion::BitcoinV1);
1027 assert_ne!(ProtocolVersion::BitcoinV1, ProtocolVersion::Testnet3);
1028 assert_ne!(ProtocolVersion::Testnet3, ProtocolVersion::Regtest);
1029 }
1030
1031 #[test]
1032 fn test_feature_activation_by_height() {
1033 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
1034
1035 assert!(!engine.is_feature_active("segwit", 481_823, 1503539000));
1037 assert!(engine.is_feature_active("segwit", 481_824, 1503539857));
1038 assert!(engine.is_feature_active("segwit", 500_000, 1504000000));
1039
1040 assert!(!engine.is_feature_active("taproot", 709_631, 1636934000));
1042 assert!(engine.is_feature_active("taproot", 709_632, 1636934400));
1043 assert!(engine.is_feature_active("taproot", 800_000, 1640000000));
1044 }
1045
1046 #[test]
1047 fn test_economic_parameters_access() {
1048 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
1049 let params = engine.get_economic_parameters();
1050
1051 assert_eq!(params.initial_subsidy, 50_0000_0000);
1052 assert_eq!(params.halving_interval, 210_000);
1053 assert_eq!(params.coinbase_maturity, 100);
1054
1055 assert_eq!(params.get_block_subsidy(0), 50_0000_0000);
1057 assert_eq!(params.get_block_subsidy(210_000), 25_0000_0000);
1058 }
1059
1060 #[test]
1061 fn test_feature_registry_access() {
1062 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
1063 let registry = engine.get_feature_registry();
1064
1065 assert!(registry.get_feature("segwit").is_some());
1066 assert!(registry.get_feature("taproot").is_some());
1067 assert!(registry.get_feature("nonexistent").is_none());
1068
1069 let features = registry.list_features();
1070 assert!(features.contains(&"segwit".to_string()));
1071 assert!(features.contains(&"taproot".to_string()));
1072 }
1073}