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: [0x0a, 0x03, 0xcf, 0x40],
685 default_port: 38333,
686 genesis_block: genesis::signet_genesis(),
687 max_target: 0x1e0377ae,
688 halving_interval: blvm_consensus::economic::subsidy_halving_interval(
689 blvm_consensus::types::Network::Signet,
690 ),
691 network_name: "signet".to_string(),
692 is_testnet: true,
693 signet_challenge: None,
694 })
695 }
696
697 pub fn testnet4() -> Result<Self> {
699 Ok(NetworkParameters {
700 magic_bytes: [0x1c, 0x16, 0x3f, 0x28],
701 default_port: 48333,
702 genesis_block: genesis::testnet4_genesis(),
703 max_target: 0x1d00ffff,
704 halving_interval: blvm_consensus::economic::subsidy_halving_interval(
705 blvm_consensus::types::Network::Testnet4,
706 ),
707 network_name: "testnet4".to_string(),
708 is_testnet: true,
709 signet_challenge: None,
710 })
711 }
712}
713
714#[cfg(test)]
715mod tests {
716 use super::*;
717 use blvm_consensus::types::{BlockHeader, OutPoint, TransactionInput, TransactionOutput};
718
719 fn mine_regtest(mut header: BlockHeader) -> BlockHeader {
722 header.bits = 0x207fffff;
723 while !blvm_consensus::pow::check_proof_of_work(&header).unwrap() {
724 header.nonce += 1;
725 }
726 header
727 }
728
729 #[test]
730 fn test_blvm_protocol_creation() {
731 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
732 assert_eq!(engine.get_protocol_version(), ProtocolVersion::BitcoinV1);
733 assert_eq!(engine.get_network_params().network_name, "mainnet");
734 }
735
736 #[test]
737 fn test_blvm_protocol_creation_all_variants() {
738 let mainnet = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
740 assert_eq!(mainnet.get_protocol_version(), ProtocolVersion::BitcoinV1);
741 assert_eq!(mainnet.get_network_params().network_name, "mainnet");
742 assert!(!mainnet.get_network_params().is_testnet);
743
744 let testnet = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
746 assert_eq!(testnet.get_protocol_version(), ProtocolVersion::Testnet3);
747 assert_eq!(testnet.get_network_params().network_name, "testnet");
748 assert!(testnet.get_network_params().is_testnet);
749
750 let regtest = BitcoinProtocolEngine::new(ProtocolVersion::Regtest).unwrap();
752 assert_eq!(regtest.get_protocol_version(), ProtocolVersion::Regtest);
753 assert_eq!(regtest.get_network_params().network_name, "regtest");
754 assert!(regtest.get_network_params().is_testnet);
755
756 let signet = BitcoinProtocolEngine::new(ProtocolVersion::Signet).unwrap();
758 assert_eq!(signet.get_protocol_version(), ProtocolVersion::Signet);
759 assert_eq!(signet.get_network_params().network_name, "signet");
760 assert!(signet.get_network_params().is_testnet);
761 assert_eq!(signet.get_network_params().default_port, 38333);
762 }
763
764 #[test]
765 fn test_network_parameters() {
766 let mainnet = NetworkParameters::mainnet().unwrap();
767 assert_eq!(mainnet.magic_bytes, [0xf9, 0xbe, 0xb4, 0xd9]);
768 assert_eq!(mainnet.default_port, 8333);
769 assert!(!mainnet.is_testnet);
770
771 let testnet = NetworkParameters::testnet().unwrap();
772 assert_eq!(testnet.magic_bytes, [0x0b, 0x11, 0x09, 0x07]);
773 assert_eq!(testnet.default_port, 18333);
774 assert!(testnet.is_testnet);
775
776 let regtest = NetworkParameters::regtest().unwrap();
777 assert_eq!(regtest.magic_bytes, [0xfa, 0xbf, 0xb5, 0xda]);
778 assert_eq!(regtest.default_port, 18444);
779 assert!(regtest.is_testnet);
780 }
781
782 #[test]
783 fn test_signet_magic_matches_bitcoin_core_default_signet() {
784 use sha2::{Digest, Sha256};
785 let challenge = hex::decode(
787 "512103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae",
788 )
789 .unwrap();
790 let mut ser = vec![challenge.len() as u8];
792 ser.extend_from_slice(&challenge);
793 let digest = Sha256::digest(Sha256::digest(&ser));
794 let expected = [0x0a, 0x03, 0xcf, 0x40];
795 assert_eq!(&digest[..4], &expected);
796
797 let params = NetworkParameters::signet().unwrap();
798 assert_eq!(params.magic_bytes, expected);
799 let constants = crate::network_params::NetworkConstants::signet().unwrap();
800 assert_eq!(constants.magic_bytes, expected);
801 let engine = BitcoinProtocolEngine::new(ProtocolVersion::Signet).unwrap();
802 assert_eq!(engine.get_network_params().magic_bytes, expected);
803 }
804
805 #[test]
806 fn test_network_parameters_consistency() {
807 let mainnet = NetworkParameters::mainnet().unwrap();
808 assert_eq!(mainnet.max_target, 0x1d00ffff);
809 assert_eq!(mainnet.halving_interval, 210000);
810
811 let testnet = NetworkParameters::testnet().unwrap();
812 assert_eq!(testnet.max_target, 0x1d00ffff);
813 assert_eq!(testnet.halving_interval, 210000);
814
815 let regtest = NetworkParameters::regtest().unwrap();
816 assert_eq!(regtest.max_target, 0x207fffff); assert_eq!(regtest.halving_interval, 150); }
819
820 #[test]
821 fn test_feature_support() {
822 let mainnet = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
823 assert!(mainnet.supports_feature("segwit"));
824 assert!(mainnet.supports_feature("taproot"));
825 assert!(mainnet.supports_feature("rbf"));
826 assert!(mainnet.supports_feature("ctv"));
827 assert!(!mainnet.supports_feature("fast_mining"));
828 assert!(!mainnet.supports_feature("nonexistent"));
829
830 let testnet = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
831 assert!(testnet.supports_feature("segwit"));
832 assert!(testnet.supports_feature("taproot"));
833 assert!(testnet.supports_feature("rbf"));
834 assert!(testnet.supports_feature("ctv"));
835 assert!(!testnet.supports_feature("fast_mining"));
836
837 let regtest = BitcoinProtocolEngine::new(ProtocolVersion::Regtest).unwrap();
838 assert!(regtest.supports_feature("segwit"));
839 assert!(regtest.supports_feature("taproot"));
840 assert!(regtest.supports_feature("rbf"));
841 assert!(regtest.supports_feature("ctv"));
842 assert!(regtest.supports_feature("fast_mining"));
843
844 let signet = BitcoinProtocolEngine::new(ProtocolVersion::Signet).unwrap();
845 assert!(signet.supports_feature("segwit"));
846 assert!(signet.supports_feature("taproot"));
847 assert!(signet.supports_feature("signet"));
848 assert!(!signet.supports_feature("fast_mining"));
849 }
850
851 #[test]
852 fn test_signet_challenge_override_on_engine() {
853 let engine = BitcoinProtocolEngine::new(ProtocolVersion::Signet)
854 .unwrap()
855 .with_signet_challenge(Some(vec![0x51]));
856 assert_eq!(
857 engine
858 .get_network_params()
859 .signet_challenge
860 .as_ref()
861 .map(|b| b.as_ref()),
862 Some([0x51].as_slice())
863 );
864 let ctx = engine.connect_block_validation_context(None::<&[BlockHeader]>, 0);
865 assert_eq!(
866 ctx.signet_challenge.as_ref().map(|b| b.as_ref()),
867 Some([0x51].as_slice())
868 );
869 }
870
871 #[test]
872 fn test_block_validation_empty_utxos() {
873 use crate::validation::ProtocolValidationContext;
874 use blvm_consensus::opcodes::OP_1;
875
876 let engine = BitcoinProtocolEngine::new(ProtocolVersion::Regtest).unwrap();
877 let utxos = UtxoSet::default();
878
879 let coinbase_tx = Transaction {
880 version: 2,
881 inputs: blvm_consensus::tx_inputs![TransactionInput {
882 prevout: OutPoint {
883 hash: [0u8; 32],
884 index: 0xffffffff,
885 },
886 script_sig: vec![0x00, 0xff],
887 sequence: 0xffffffff,
888 }],
889 outputs: blvm_consensus::tx_outputs![TransactionOutput {
890 value: 5_000_000_000,
891 script_pubkey: vec![OP_1],
892 }],
893 lock_time: 0,
894 };
895
896 let merkle_root = blvm_consensus::mining::calculate_merkle_root(&[coinbase_tx.clone()])
897 .expect("merkle root");
898
899 let block = Block {
900 header: mine_regtest(BlockHeader {
901 version: 4,
902 prev_block_hash: [0u8; 32],
903 merkle_root,
904 timestamp: 1_231_006_505,
905 bits: 0x207fffff,
906 nonce: 0,
907 }),
908 transactions: vec![coinbase_tx].into_boxed_slice(),
909 };
910
911 let witnesses: Vec<Vec<blvm_consensus::segwit::Witness>> = block
912 .transactions
913 .iter()
914 .map(|tx| tx.inputs.iter().map(|_| Vec::new()).collect())
915 .collect();
916 let mut context = ProtocolValidationContext::new(ProtocolVersion::Regtest, 0).unwrap();
917 context.network_time = block.header.timestamp;
918 context.median_time_past = block.header.timestamp - 1;
919
920 let (result, new_utxos) = engine
921 .validate_and_connect_block(&block, &witnesses, &utxos, 0, None, &context)
922 .unwrap();
923 assert_eq!(result, ValidationResult::Valid);
924 assert!(!new_utxos.is_empty());
925 }
926
927 #[test]
928 fn test_transaction_validation() {
929 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
930
931 let tx = Transaction {
933 version: 1,
934 inputs: vec![TransactionInput {
935 prevout: OutPoint {
936 hash: [0u8; 32],
937 index: 0,
938 },
939 script_sig: vec![blvm_consensus::opcodes::PUSH_65_BYTES, 0x04],
940 sequence: 0xffffffff,
941 }]
942 .into(),
943 outputs: vec![TransactionOutput {
944 value: 50_0000_0000,
945 script_pubkey: vec![
946 blvm_consensus::opcodes::OP_DUP,
947 blvm_consensus::opcodes::OP_HASH160,
948 blvm_consensus::opcodes::PUSH_20_BYTES,
949 0x00,
950 0x00,
951 0x00,
952 0x00,
953 0x00,
954 0x00,
955 0x00,
956 0x00,
957 0x00,
958 0x00,
959 0x00,
960 0x00,
961 0x00,
962 0x00,
963 0x00,
964 0x00,
965 0x00,
966 0x00,
967 0x00,
968 0x00,
969 blvm_consensus::opcodes::OP_EQUALVERIFY,
970 blvm_consensus::opcodes::OP_CHECKSIG,
971 ], }]
973 .into(),
974 lock_time: 0,
975 };
976
977 let result = engine.validate_transaction(&tx);
978 assert!(result.is_ok());
979 }
980
981 #[test]
982 fn test_cross_protocol_validation() {
983 let mainnet_engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
984 let testnet_engine = BitcoinProtocolEngine::new(ProtocolVersion::Testnet3).unwrap();
985
986 assert_eq!(
988 mainnet_engine.supports_feature("segwit"),
989 testnet_engine.supports_feature("segwit")
990 );
991 assert_eq!(
992 mainnet_engine.supports_feature("taproot"),
993 testnet_engine.supports_feature("taproot")
994 );
995
996 assert_ne!(
998 mainnet_engine.get_network_params().magic_bytes,
999 testnet_engine.get_network_params().magic_bytes
1000 );
1001 assert_ne!(
1002 mainnet_engine.get_network_params().default_port,
1003 testnet_engine.get_network_params().default_port
1004 );
1005 }
1006
1007 #[test]
1008 fn test_protocol_version_switching() {
1009 let versions = vec![
1011 ProtocolVersion::BitcoinV1,
1012 ProtocolVersion::Testnet3,
1013 ProtocolVersion::Regtest,
1014 ProtocolVersion::Signet,
1015 ];
1016
1017 for version in versions {
1018 let engine = BitcoinProtocolEngine::new(version).unwrap();
1019 assert_eq!(engine.get_protocol_version(), version);
1020 }
1021 }
1022
1023 #[test]
1024 fn test_network_parameters_serialization() {
1025 let mainnet = NetworkParameters::mainnet().unwrap();
1026 let testnet = NetworkParameters::testnet().unwrap();
1027 let regtest = NetworkParameters::regtest().unwrap();
1028
1029 let mainnet_json = serde_json::to_string(&mainnet).unwrap();
1031 let mainnet_deserialized: NetworkParameters = serde_json::from_str(&mainnet_json).unwrap();
1032 assert_eq!(mainnet.magic_bytes, mainnet_deserialized.magic_bytes);
1033 assert_eq!(mainnet.default_port, mainnet_deserialized.default_port);
1034 assert_eq!(mainnet.network_name, mainnet_deserialized.network_name);
1035 assert_eq!(mainnet.is_testnet, mainnet_deserialized.is_testnet);
1036
1037 let testnet_json = serde_json::to_string(&testnet).unwrap();
1038 let testnet_deserialized: NetworkParameters = serde_json::from_str(&testnet_json).unwrap();
1039 assert_eq!(testnet.magic_bytes, testnet_deserialized.magic_bytes);
1040
1041 let regtest_json = serde_json::to_string(®test).unwrap();
1042 let regtest_deserialized: NetworkParameters = serde_json::from_str(®test_json).unwrap();
1043 assert_eq!(regtest.magic_bytes, regtest_deserialized.magic_bytes);
1044 }
1045
1046 #[test]
1047 fn test_protocol_version_serialization() {
1048 let versions = vec![
1049 ProtocolVersion::BitcoinV1,
1050 ProtocolVersion::Testnet3,
1051 ProtocolVersion::Regtest,
1052 ProtocolVersion::Signet,
1053 ];
1054
1055 for version in versions {
1056 let json = serde_json::to_string(&version).unwrap();
1057 let deserialized: ProtocolVersion = serde_json::from_str(&json).unwrap();
1058 assert_eq!(version, deserialized);
1059 }
1060 }
1061
1062 #[test]
1063 fn test_network_parameters_equality() {
1064 let mainnet1 = NetworkParameters::mainnet().unwrap();
1065 let mainnet2 = NetworkParameters::mainnet().unwrap();
1066 let testnet = NetworkParameters::testnet().unwrap();
1067
1068 assert_eq!(mainnet1, mainnet2);
1069 assert_ne!(mainnet1, testnet);
1070 }
1071
1072 #[test]
1073 fn test_protocol_version_equality() {
1074 assert_eq!(ProtocolVersion::BitcoinV1, ProtocolVersion::BitcoinV1);
1075 assert_ne!(ProtocolVersion::BitcoinV1, ProtocolVersion::Testnet3);
1076 assert_ne!(ProtocolVersion::Testnet3, ProtocolVersion::Regtest);
1077 }
1078
1079 #[test]
1080 fn test_feature_activation_by_height() {
1081 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
1082
1083 assert!(!engine.is_feature_active("segwit", 481_823, 1503539000));
1085 assert!(engine.is_feature_active("segwit", 481_824, 1503539857));
1086 assert!(engine.is_feature_active("segwit", 500_000, 1504000000));
1087
1088 assert!(!engine.is_feature_active("taproot", 709_631, 1636934000));
1090 assert!(engine.is_feature_active("taproot", 709_632, 1636934400));
1091 assert!(engine.is_feature_active("taproot", 800_000, 1640000000));
1092 }
1093
1094 #[test]
1095 fn test_economic_parameters_access() {
1096 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
1097 let params = engine.get_economic_parameters();
1098
1099 assert_eq!(params.initial_subsidy, 50_0000_0000);
1100 assert_eq!(params.halving_interval, 210_000);
1101 assert_eq!(params.coinbase_maturity, 100);
1102
1103 assert_eq!(params.get_block_subsidy(0), 50_0000_0000);
1105 assert_eq!(params.get_block_subsidy(210_000), 25_0000_0000);
1106 }
1107
1108 #[test]
1109 fn test_feature_registry_access() {
1110 let engine = BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap();
1111 let registry = engine.get_feature_registry();
1112
1113 assert!(registry.get_feature("segwit").is_some());
1114 assert!(registry.get_feature("taproot").is_some());
1115 assert!(registry.get_feature("nonexistent").is_none());
1116
1117 let features = registry.list_features();
1118 assert!(features.contains(&"segwit".to_string()));
1119 assert!(features.contains(&"taproot".to_string()));
1120 }
1121}