1use crate::economic::get_block_subsidy;
4use crate::error::Result;
5use crate::pow::{check_proof_of_work, get_next_work_required};
6use crate::transaction::check_transaction;
7use crate::types::*;
8use blvm_spec_lock::spec_locked;
9
10#[cfg(test)]
11use crate::transaction::is_coinbase;
12
13#[spec_locked("12.1", "CreateNewBlock")]
22pub fn create_new_block(
23 utxo_set: &UtxoSet,
24 mempool_txs: &[Transaction],
25 height: Natural,
26 prev_header: &BlockHeader,
27 prev_headers: &[BlockHeader],
28 coinbase_script: &ByteString,
29 coinbase_address: &ByteString,
30) -> Result<Block> {
31 let block_time = get_current_timestamp();
33 create_new_block_with_time(
34 utxo_set,
35 mempool_txs,
36 height,
37 prev_header,
38 prev_headers,
39 coinbase_script,
40 coinbase_address,
41 block_time,
42 )
43}
44
45#[allow(clippy::too_many_arguments)]
51#[spec_locked("12.1", "CreateNewBlock")]
52pub fn create_new_block_with_time(
53 utxo_set: &UtxoSet,
54 mempool_txs: &[Transaction],
55 height: Natural,
56 prev_header: &BlockHeader,
57 prev_headers: &[BlockHeader],
58 coinbase_script: &ByteString,
59 coinbase_address: &ByteString,
60 block_time: u64,
61) -> Result<Block> {
62 use crate::mempool::{accept_to_memory_pool, Mempool, MempoolResult};
63
64 let coinbase_tx = create_coinbase_transaction(
66 height,
67 get_block_subsidy(height),
68 coinbase_script,
69 coinbase_address,
70 )?;
71
72 let mut selected_txs = Vec::new();
75 let temp_mempool: Mempool = std::collections::HashSet::new(); for tx in mempool_txs {
78 if check_transaction(tx)? != ValidationResult::Valid {
80 continue;
81 }
82
83 let time_context = Some(TimeContext {
85 network_time: block_time,
86 median_time_past: block_time, });
88 match accept_to_memory_pool(tx, None, utxo_set, &temp_mempool, height, time_context)? {
89 MempoolResult::Accepted => {
90 selected_txs.push(tx.clone());
91 }
92 MempoolResult::Rejected(_reason) => {
93 #[cfg(test)]
96 eprintln!("Transaction rejected: {_reason}");
97 continue;
98 }
99 }
100 }
101
102 let mut transactions = vec![coinbase_tx];
104 transactions.extend(selected_txs);
105
106 let merkle_root = calculate_merkle_root(&transactions)?;
108
109 let next_work = get_next_work_required(prev_header, prev_headers)?;
111
112 let header = BlockHeader {
114 version: 1,
115 prev_block_hash: calculate_block_hash(prev_header),
116 merkle_root,
117 timestamp: block_time,
118 bits: next_work,
119 nonce: 0, };
121
122 Ok(Block {
123 header,
124 transactions: transactions.into_boxed_slice(),
125 })
126}
127
128#[track_caller] #[spec_locked("12.3", "MineBlock")]
136pub fn mine_block(mut block: Block, max_attempts: Natural) -> Result<(Block, MiningResult)> {
137 for nonce in 0..max_attempts {
138 block.header.nonce = nonce;
139
140 if check_proof_of_work(&block.header).unwrap_or(false) {
141 return Ok((block, MiningResult::Success));
142 }
143 }
144
145 Ok((block, MiningResult::Failure))
146}
147
148#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
156pub struct BlockTemplate {
157 pub header: BlockHeader,
158 pub coinbase_tx: Transaction,
159 pub transactions: Vec<Transaction>,
160 pub target: u128,
161 pub height: Natural,
162 pub timestamp: Natural,
163}
164
165#[spec_locked("12.4", "BlockTemplate")]
167pub fn create_block_template(
168 utxo_set: &UtxoSet,
169 mempool_txs: &[Transaction],
170 height: Natural,
171 prev_header: &BlockHeader,
172 prev_headers: &[BlockHeader],
173 coinbase_script: &ByteString,
174 coinbase_address: &ByteString,
175) -> Result<BlockTemplate> {
176 let block = create_new_block(
177 utxo_set,
178 mempool_txs,
179 height,
180 prev_header,
181 prev_headers,
182 coinbase_script,
183 coinbase_address,
184 )?;
185
186 let target_u256 = crate::pow::expand_target(block.header.bits)?;
187 let target = if target_u256.is_zero() {
188 0
189 } else if target_u256.low_u128() > 0 {
190 target_u256.low_u128()
191 } else {
192 1
193 };
194
195 let header = block.header.clone();
196
197 #[cfg(feature = "production")]
199 let coinbase_tx = {
200 use crate::optimizations::_optimized_access::get_proven_by_;
201 get_proven_by_(&block.transactions, 0)
202 .ok_or_else(|| {
203 crate::error::ConsensusError::BlockValidation("Block has no transactions".into())
204 })?
205 .clone()
206 };
207
208 #[cfg(not(feature = "production"))]
209 let coinbase_tx = block.transactions[0].clone();
210
211 Ok(BlockTemplate {
212 header: block.header,
213 coinbase_tx,
214 transactions: block.transactions[1..].to_vec(),
215 target,
216 height,
217 timestamp: header.timestamp,
218 })
219}
220
221#[derive(Debug, Clone, PartialEq, Eq)]
227pub enum MiningResult {
228 Success,
229 Failure,
230}
231
232#[spec_locked("12.2", "CreateCoinbaseTransaction")]
237fn create_coinbase_transaction(
238 height: Natural,
239 subsidy: Integer,
240 script: &ByteString,
241 address: &ByteString,
242) -> Result<Transaction> {
243 let lock_time = height.saturating_sub(13);
244 let coinbase_input = TransactionInput {
245 prevout: OutPoint {
246 hash: [0u8; 32],
247 index: 0xffffffff,
248 },
249 script_sig: script.clone(),
250 sequence: 0xfffffffe, };
252
253 let coinbase_output = TransactionOutput {
254 value: subsidy,
255 script_pubkey: address.clone(),
256 };
257
258 Ok(Transaction {
259 version: 1,
260 inputs: crate::tx_inputs![coinbase_input],
261 outputs: crate::tx_outputs![coinbase_output],
262 lock_time,
263 })
264}
265
266#[track_caller] #[cfg_attr(feature = "production", inline(always))]
269#[cfg_attr(not(feature = "production"), inline)]
270#[spec_locked("8.4.1", "ComputeMerkleRoot")]
271pub fn calculate_merkle_root(transactions: &[Transaction]) -> Result<Hash> {
272 if transactions.is_empty() {
273 return Err(crate::error::ConsensusError::InvalidProofOfWork(
274 "Cannot calculate merkle root for empty transaction list".into(),
275 ));
276 }
277
278 #[cfg(feature = "production")]
282 let mut hashes: Vec<crate::optimizations::CacheAlignedHash> = {
283 use crate::optimizations::simd_vectorization;
284
285 let serialized_txs: Vec<Vec<u8>> = {
289 #[cfg(feature = "rayon")]
290 {
291 use rayon::prelude::*;
292 transactions
293 .par_iter()
294 .map(serialize_tx_for_hash) .collect()
296 }
297 #[cfg(not(feature = "rayon"))]
298 {
299 transactions
300 .iter()
301 .map(serialize_tx_for_hash) .collect()
303 }
304 };
305
306 let tx_data_refs: Vec<&[u8]> = serialized_txs.iter().map(|v| v.as_slice()).collect();
309 simd_vectorization::batch_double_sha256_aligned(&tx_data_refs)
310 };
311
312 #[cfg(not(feature = "production"))]
313 let mut hashes: Vec<Hash> = {
314 let mut hashes = Vec::with_capacity(transactions.len());
316 for tx in transactions {
317 hashes.push(calculate_tx_hash(tx));
318 }
319 hashes
320 };
321
322 #[cfg(feature = "production")]
327 {
328 use crate::optimizations::CacheAlignedHash;
329
330 let mut mutated = false;
331
332 while hashes.len() > 1 {
333 let mut level_mutated = false;
335 let mut pos = 0;
336 while pos + 1 < hashes.len() {
337 if hashes[pos].as_bytes() == hashes[pos + 1].as_bytes() {
338 level_mutated = true;
339 }
340 pos += 2;
341 }
342 if level_mutated {
343 mutated = true;
344 }
345
346 if hashes.len() & 1 != 0 {
348 let last = hashes[hashes.len() - 1].clone();
349 hashes.push(last);
350 }
351
352 let next_level: Vec<CacheAlignedHash> = hashes
354 .chunks(2)
355 .map(|chunk| {
356 let mut combined = [0u8; 64];
357 combined[..32].copy_from_slice(chunk[0].as_bytes());
358 combined[32..].copy_from_slice(if chunk.len() == 2 {
359 chunk[1].as_bytes()
360 } else {
361 chunk[0].as_bytes()
362 });
363 CacheAlignedHash::new(double_sha256_hash(&combined))
364 })
365 .collect();
366
367 hashes = next_level;
368 }
369
370 if mutated {
371 return Err(crate::error::ConsensusError::InvalidProofOfWork(
372 "Merkle root mutation detected (CVE-2012-2459)".into(),
373 ));
374 }
375
376 Ok(*hashes[0].as_bytes())
377 }
378
379 #[cfg(not(feature = "production"))]
380 {
381 let (root, mutated) = merkle_tree_from_hashes(&mut hashes)?;
382 if mutated {
383 return Err(crate::error::ConsensusError::InvalidProofOfWork(
384 "Merkle root mutation detected (CVE-2012-2459)".into(),
385 ));
386 }
387 Ok(root)
388 }
389}
390
391#[spec_locked("8.4.1", "ComputeMerkleRoot")]
401pub fn calculate_merkle_root_from_tx_ids(tx_ids: &[Hash]) -> Result<Hash> {
402 let (root, mutated) = compute_merkle_root_and_mutated(tx_ids)?;
403 if mutated {
404 return Err(crate::error::ConsensusError::InvalidProofOfWork(
405 "Merkle root mutation detected (CVE-2012-2459)".into(),
406 ));
407 }
408 Ok(root)
409}
410
411#[spec_locked("8.4.1", "ComputeMerkleRoot")]
416pub fn compute_merkle_root_and_mutated(tx_ids: &[Hash]) -> Result<(Hash, bool)> {
417 if tx_ids.is_empty() {
418 return Err(crate::error::ConsensusError::InvalidProofOfWork(
419 "Cannot calculate merkle root for empty transaction list".into(),
420 ));
421 }
422 let mut hashes = tx_ids.to_vec();
423 merkle_tree_from_hashes(&mut hashes)
424}
425
426#[spec_locked("8.4.1", "ComputeMerkleRoot")]
431fn merkle_tree_from_hashes(hashes: &mut Vec<Hash>) -> Result<(Hash, bool)> {
432 let mut mutated = false;
433
434 while hashes.len() > 1 {
435 for pos in (0..hashes.len().saturating_sub(1)).step_by(2) {
437 if hashes[pos] == hashes[pos + 1] {
438 mutated = true;
439 }
440 }
441
442 if hashes.len() & 1 != 0 {
444 hashes.push(hashes[hashes.len() - 1]);
445 }
446
447 let mut next_level = Vec::with_capacity(hashes.len() / 2);
448
449 for chunk in hashes.chunks(2) {
451 let mut combined = [0u8; 64];
452 combined[..32].copy_from_slice(&chunk[0]);
453 combined[32..].copy_from_slice(if chunk.len() == 2 {
454 &chunk[1]
455 } else {
456 &chunk[0]
457 });
458 next_level.push(double_sha256_hash(&combined));
459 }
460
461 *hashes = next_level;
462 }
463
464 Ok((hashes[0], mutated))
465}
466
467fn serialize_tx_for_hash(tx: &Transaction) -> Vec<u8> {
472 #[cfg(feature = "production")]
474 let mut data = {
475 use crate::optimizations::prealloc_tx_buffer;
476 prealloc_tx_buffer()
477 };
478
479 #[cfg(not(feature = "production"))]
480 let mut data = Vec::new();
481
482 data.extend_from_slice(&(tx.version as u32).to_le_bytes());
484
485 data.extend_from_slice(&encode_varint(tx.inputs.len() as u64));
487
488 for input in &tx.inputs {
490 data.extend_from_slice(&input.prevout.hash);
492 data.extend_from_slice(&input.prevout.index.to_le_bytes());
494 data.extend_from_slice(&encode_varint(input.script_sig.len() as u64));
496 data.extend_from_slice(&input.script_sig);
498 data.extend_from_slice(&(input.sequence as u32).to_le_bytes());
500 }
501
502 data.extend_from_slice(&encode_varint(tx.outputs.len() as u64));
504
505 for output in &tx.outputs {
507 data.extend_from_slice(&(output.value as u64).to_le_bytes());
509 data.extend_from_slice(&encode_varint(output.script_pubkey.len() as u64));
511 data.extend_from_slice(&output.script_pubkey);
513 }
514
515 data.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
517
518 data
519}
520
521#[allow(dead_code)] fn calculate_tx_hash(tx: &Transaction) -> Hash {
527 let data = serialize_tx_for_hash(tx);
528 let hash1 = sha256_hash(&data);
530 sha256_hash(&hash1)
531}
532
533fn encode_varint(value: u64) -> Vec<u8> {
535 if value < 0xfd {
536 vec![value as u8]
537 } else if value <= 0xffff {
538 let mut result = vec![0xfd];
539 result.extend_from_slice(&(value as u16).to_le_bytes());
540 result
541 } else if value <= 0xffffffff {
542 let mut result = vec![0xfe];
543 result.extend_from_slice(&(value as u32).to_le_bytes());
544 result
545 } else {
546 let mut result = vec![0xff];
547 result.extend_from_slice(&value.to_le_bytes());
548 result
549 }
550}
551
552fn calculate_block_hash(header: &BlockHeader) -> Hash {
554 let wire = crate::serialization::block::serialize_block_header(header);
555 double_sha256_hash(&wire)
556}
557
558#[inline(always)]
563fn sha256_hash(data: &[u8]) -> Hash {
564 use crate::crypto::OptimizedSha256;
565 OptimizedSha256::new().hash(data)
566}
567
568#[inline(always)]
570fn double_sha256_hash(data: &[u8]) -> Hash {
571 use crate::crypto::OptimizedSha256;
572 OptimizedSha256::new().hash256(data)
573}
574
575fn expand_target(bits: Natural) -> Result<u128> {
578 let exponent = (bits >> 24) as u8;
579 let mantissa = bits & 0x00ffffff;
580
581 if exponent <= 3 {
582 let shift = 8 * (3 - exponent);
583 Ok((mantissa >> shift) as u128)
584 } else {
585 let shift = 8 * (exponent - 3);
586 if shift >= 104 {
587 return Err(crate::error::ConsensusError::InvalidProofOfWork(
589 "Target too large".into(),
590 ));
591 }
592 Ok((mantissa as u128) << shift)
594 }
595}
596
597fn get_current_timestamp() -> Natural {
599 1231006505
602}
603
604#[cfg(test)]
605mod tests {
606 use super::*;
607 use crate::opcodes::*;
608
609 #[test]
610 fn test_create_new_block() {
611 let mut utxo_set = UtxoSet::default();
612 let outpoint = OutPoint {
614 hash: [1; 32],
615 index: 0,
616 };
617 let utxo = UTXO {
618 value: 10000,
619 script_pubkey: vec![].into(),
621 height: 0,
622 is_coinbase: false,
623 };
624 utxo_set.insert(outpoint, std::sync::Arc::new(utxo));
625
626 let mempool_txs = vec![create_valid_transaction()];
627 let height = 100;
628 let prev_header = create_valid_block_header();
629 let mut prev_header2 = prev_header.clone();
631 prev_header2.timestamp = prev_header.timestamp + 600; let prev_headers = vec![prev_header.clone(), prev_header2];
633 let coinbase_script = vec![OP_1];
634 let coinbase_address = vec![OP_1];
635
636 let result = create_new_block(
639 &utxo_set,
640 &mempool_txs,
641 height,
642 &prev_header,
643 &prev_headers,
644 &coinbase_script,
645 &coinbase_address,
646 );
647
648 if let Ok(block) = result {
649 assert_eq!(block.transactions.len(), 2); assert!(is_coinbase(&block.transactions[0]));
651 assert_eq!(block.header.version, 1);
652 assert_eq!(block.header.timestamp, 1231006505);
653 } else {
654 assert!(result.is_err());
657 }
658 }
659
660 #[test]
661 fn test_mine_block_success() {
662 let block = create_test_block();
663 let result = mine_block(block, 1000);
664
665 assert!(result.is_ok());
667 let (mined_block, mining_result) = result.unwrap();
668 assert!(matches!(
669 mining_result,
670 MiningResult::Success | MiningResult::Failure
671 ));
672 assert_eq!(mined_block.header.version, 1);
673 }
674
675 #[test]
676 fn test_create_block_template() {
677 let utxo_set = UtxoSet::default();
678 let mempool_txs = vec![create_valid_transaction()];
679 let height = 100;
680 let prev_header = create_valid_block_header();
681 let prev_headers = vec![prev_header.clone()];
682 let coinbase_script = vec![OP_1];
683 let coinbase_address = vec![OP_1];
684
685 let result = create_block_template(
687 &utxo_set,
688 &mempool_txs,
689 height,
690 &prev_header,
691 &prev_headers,
692 &coinbase_script,
693 &coinbase_address,
694 );
695
696 assert!(result.is_err());
698 }
699
700 #[test]
701 fn test_coinbase_transaction() {
702 let height = 100;
703 let subsidy = get_block_subsidy(height);
704 let script = vec![OP_1];
705 let address = vec![OP_1];
706
707 let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
708
709 assert!(is_coinbase(&coinbase_tx));
710 assert_eq!(coinbase_tx.outputs[0].value, subsidy);
711 assert_eq!(coinbase_tx.inputs[0].prevout.hash, [0u8; 32]);
712 assert_eq!(coinbase_tx.inputs[0].prevout.index, 0xffffffff);
713 }
714
715 #[test]
716 fn test_merkle_root_calculation() {
717 let txs = vec![create_valid_transaction(), create_valid_transaction()];
718
719 let merkle_root = calculate_merkle_root(&txs).unwrap();
720 assert_ne!(merkle_root, [0u8; 32]);
721 }
722
723 #[test]
724 fn test_merkle_root_empty() {
725 let txs = vec![];
726 let result = calculate_merkle_root(&txs);
727 assert!(result.is_err());
728 }
729
730 #[test]
735 fn test_create_block_template_comprehensive() {
736 let mut utxo_set = UtxoSet::default();
737 let outpoint = OutPoint {
739 hash: [1; 32],
740 index: 0,
741 };
742 let utxo = UTXO {
743 value: 10000,
744 script_pubkey: vec![].into(),
746 height: 0,
747 is_coinbase: false,
748 };
749 utxo_set.insert(outpoint, std::sync::Arc::new(utxo));
750
751 let mempool_txs = vec![create_valid_transaction()];
752 let height = 100;
753 let prev_header = create_valid_block_header();
754 let mut prev_header2 = prev_header.clone();
756 prev_header2.timestamp = prev_header.timestamp + 600; let prev_headers = vec![prev_header.clone(), prev_header2];
758 let coinbase_script = vec![OP_1];
759 let coinbase_address = vec![OP_2];
760
761 let result = create_block_template(
762 &utxo_set,
763 &mempool_txs,
764 height,
765 &prev_header,
766 &prev_headers,
767 &coinbase_script,
768 &coinbase_address,
769 );
770
771 if let Ok(template) = result {
774 assert_eq!(template.height, height);
775 assert!(template.target > 0);
776 assert!(is_coinbase(&template.coinbase_tx));
777 assert_eq!(template.transactions.len(), 1);
778 } else {
779 assert!(result.is_err());
781 }
782 }
783
784 #[test]
785 fn test_mine_block_attempts() {
786 let block = create_test_block();
787 let (mined_block, result) = mine_block(block, 1000).unwrap();
788
789 assert!(matches!(
791 result,
792 MiningResult::Success | MiningResult::Failure
793 ));
794 assert_eq!(mined_block.header.version, 1);
795 }
796
797 #[test]
798 fn test_mine_block_failure() {
799 let block = create_test_block();
800 let (mined_block, result) = mine_block(block, 0).unwrap();
801
802 assert_eq!(result, MiningResult::Failure);
804 assert_eq!(mined_block.header.nonce, 0);
805 }
806
807 #[test]
808 fn test_create_coinbase_transaction() {
809 let height = 100;
810 let subsidy = 5000000000;
811 let script = vec![0x51, 0x52];
812 let address = vec![0x53, 0x54];
813
814 let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
815
816 assert!(is_coinbase(&coinbase_tx));
817 assert_eq!(coinbase_tx.outputs.len(), 1);
818 assert_eq!(coinbase_tx.outputs[0].value, subsidy);
819 assert_eq!(coinbase_tx.outputs[0].script_pubkey, address);
820 assert_eq!(coinbase_tx.inputs[0].script_sig, script);
821 assert_eq!(coinbase_tx.inputs[0].prevout.hash, [0u8; 32]);
822 assert_eq!(coinbase_tx.inputs[0].prevout.index, 0xffffffff);
823 }
824
825 #[test]
826 fn test_calculate_tx_hash() {
827 let tx = create_valid_transaction();
828 let hash = calculate_tx_hash(&tx);
829
830 assert_eq!(hash.len(), 32);
832
833 let hash2 = calculate_tx_hash(&tx);
835 assert_eq!(hash, hash2);
836 }
837
838 #[test]
839 fn test_calculate_tx_hash_different_txs() {
840 let tx1 = create_valid_transaction();
841 let mut tx2 = tx1.clone();
842 tx2.version = 2; let hash1 = calculate_tx_hash(&tx1);
845 let hash2 = calculate_tx_hash(&tx2);
846
847 assert_ne!(hash1, hash2);
849 }
850
851 #[test]
852 fn test_encode_varint_small() {
853 let encoded = encode_varint(0x42);
854 assert_eq!(encoded, vec![0x42]);
855 }
856
857 #[test]
858 fn test_encode_varint_medium() {
859 let encoded = encode_varint(0x1234);
860 assert_eq!(encoded.len(), 3);
861 assert_eq!(encoded[0], 0xfd);
862 }
863
864 #[test]
865 fn test_encode_varint_large() {
866 let encoded = encode_varint(0x12345678);
867 assert_eq!(encoded.len(), 5);
868 assert_eq!(encoded[0], 0xfe);
869 }
870
871 #[test]
872 fn test_encode_varint_huge() {
873 let encoded = encode_varint(0x123456789abcdef0);
874 assert_eq!(encoded.len(), 9);
875 assert_eq!(encoded[0], 0xff);
876 }
877
878 #[test]
879 fn test_calculate_block_hash() {
880 let header = create_valid_block_header();
881 let hash = calculate_block_hash(&header);
882
883 assert_eq!(hash.len(), 32);
885
886 let hash2 = calculate_block_hash(&header);
888 assert_eq!(hash, hash2);
889 }
890
891 #[test]
892 fn test_calculate_block_hash_different_headers() {
893 let header1 = create_valid_block_header();
894 let mut header2 = header1.clone();
895 header2.version = 2; let hash1 = calculate_block_hash(&header1);
898 let hash2 = calculate_block_hash(&header2);
899
900 assert_ne!(hash1, hash2);
902 }
903
904 #[test]
905 fn test_sha256_hash() {
906 let data = b"hello world";
907 let hash = sha256_hash(data);
908
909 assert_eq!(hash.len(), 32);
911
912 let hash2 = sha256_hash(data);
914 assert_eq!(hash, hash2);
915 }
916
917 #[test]
918 fn test_sha256_hash_different_data() {
919 let data1 = b"hello";
920 let data2 = b"world";
921
922 let hash1 = sha256_hash(data1);
923 let hash2 = sha256_hash(data2);
924
925 assert_ne!(hash1, hash2);
927 }
928
929 #[test]
930 fn test_expand_target_small() {
931 let bits = 0x0300ffff; let target = expand_target(bits).unwrap();
933 assert!(target > 0);
934 }
935
936 #[test]
937 fn test_expand_target_medium() {
938 let bits = 0x0600ffff; let target = expand_target(bits).unwrap();
940 assert!(target > 0);
941 }
942
943 #[test]
944 fn test_expand_target_too_large() {
945 let bits = 0x2000ffff; let result = expand_target(bits);
947 assert!(result.is_err());
948 }
949
950 #[test]
951 fn test_pow_expand_target_regtest_minimum_difficulty() {
952 let target = crate::pow::expand_target(0x207fffff).expect("regtest nBits");
953 assert!(!target.is_zero());
954 assert_eq!(target.gbt_target_hex().len(), 64);
955 }
956
957 #[test]
958 fn test_create_block_template_regtest_nbits() {
959 let utxo_set = UtxoSet::default();
960 let prev_header = BlockHeader {
961 version: 4,
962 prev_block_hash: [0u8; 32],
963 merkle_root: [0u8; 32],
964 timestamp: 1_600_000_000,
965 bits: 0x207fffff,
966 nonce: 0,
967 };
968 let prev_headers = vec![prev_header.clone(), prev_header.clone()];
969
970 let template = create_block_template(
971 &utxo_set,
972 &[],
973 1,
974 &prev_header,
975 &prev_headers,
976 &vec![],
977 &vec![0x51],
978 )
979 .expect("create_block_template must not fail on regtest nBits");
980
981 assert_eq!(template.header.bits, 0x207fffff);
982 assert!(template.target > 0);
983 }
984
985 #[test]
986 fn test_get_current_timestamp() {
987 let timestamp = get_current_timestamp();
988 assert_eq!(timestamp, 1231006505);
989 }
990
991 #[test]
992 fn test_merkle_root_single_transaction() {
993 let txs = vec![create_valid_transaction()];
994 let merkle_root = calculate_merkle_root(&txs).unwrap();
995
996 assert_eq!(merkle_root.len(), 32);
998 assert_ne!(merkle_root, [0u8; 32]);
999 }
1000
1001 #[test]
1002 fn test_merkle_root_three_transactions() {
1003 let txs = vec![
1004 create_valid_transaction(),
1005 create_valid_transaction(),
1006 create_valid_transaction(),
1007 ];
1008 let merkle_root = calculate_merkle_root(&txs).unwrap();
1009
1010 assert_eq!(merkle_root.len(), 32);
1012 assert_ne!(merkle_root, [0u8; 32]);
1013 }
1014
1015 #[test]
1016 fn test_merkle_root_five_transactions() {
1017 let txs = vec![
1018 create_valid_transaction(),
1019 create_valid_transaction(),
1020 create_valid_transaction(),
1021 create_valid_transaction(),
1022 create_valid_transaction(),
1023 ];
1024 let merkle_root = calculate_merkle_root(&txs).unwrap();
1025
1026 assert_eq!(merkle_root.len(), 32);
1028 assert_ne!(merkle_root, [0u8; 32]);
1029 }
1030
1031 #[test]
1032 fn test_block_template_fields() {
1033 let mut utxo_set = UtxoSet::default();
1034 let outpoint = OutPoint {
1036 hash: [1; 32],
1037 index: 0,
1038 };
1039 let utxo = UTXO {
1040 value: 10000,
1041 script_pubkey: vec![].into(),
1043 height: 0,
1044 is_coinbase: false,
1045 };
1046 utxo_set.insert(outpoint, std::sync::Arc::new(utxo));
1047
1048 let mempool_txs = vec![create_valid_transaction()];
1049 let height = 100;
1050 let prev_header = create_valid_block_header();
1051 let prev_headers = vec![prev_header.clone(), prev_header.clone()];
1052 let coinbase_script = vec![OP_1];
1053 let coinbase_address = vec![OP_2];
1054
1055 let result = create_block_template(
1056 &utxo_set,
1057 &mempool_txs,
1058 height,
1059 &prev_header,
1060 &prev_headers,
1061 &coinbase_script,
1062 &coinbase_address,
1063 );
1064
1065 if let Ok(template) = result {
1068 assert_eq!(template.height, height);
1070 assert!(template.target > 0);
1071 assert!(template.timestamp > 0);
1072 assert!(is_coinbase(&template.coinbase_tx));
1073 assert_eq!(template.transactions.len(), 1);
1074 assert_eq!(template.header.version, 1);
1075 } else {
1076 assert!(result.is_err());
1078 }
1079 }
1080
1081 fn create_valid_transaction() -> Transaction {
1083 use std::cell::Cell;
1085 thread_local! {
1086 static COUNTER: Cell<u64> = const { Cell::new(0) };
1087 }
1088 let counter = COUNTER.with(|c| {
1089 let val = c.get();
1090 c.set(val + 1);
1091 val
1092 });
1093
1094 Transaction {
1095 version: 1,
1096 inputs: vec![TransactionInput {
1097 prevout: OutPoint {
1098 hash: [1; 32], index: 0,
1100 },
1101 script_sig: {
1108 let mut sig = vec![OP_1]; if counter > 0 {
1111 sig.push(PUSH_1_BYTE); sig.push((counter & 0xff) as u8); }
1114 sig
1115 },
1116 sequence: 0xffffffff,
1117 }]
1118 .into(),
1119 outputs: vec![TransactionOutput {
1120 value: 1000 + counter as i64, script_pubkey: vec![],
1123 }]
1124 .into(),
1125 lock_time: 0,
1126 }
1127 }
1128
1129 fn create_valid_block_header() -> BlockHeader {
1130 BlockHeader {
1131 version: 1,
1132 prev_block_hash: [0; 32],
1133 merkle_root: [0; 32],
1134 timestamp: 1231006505,
1135 bits: 0x0600ffff, nonce: 0,
1137 }
1138 }
1139
1140 fn create_test_block() -> Block {
1141 Block {
1142 header: create_valid_block_header(),
1143 transactions: vec![create_valid_transaction()].into_boxed_slice(),
1144 }
1145 }
1146
1147 #[test]
1148 fn test_create_coinbase_transaction_zero_subsidy() {
1149 let height = 100;
1150 let subsidy = 0; let script = vec![OP_1];
1152 let address = vec![OP_1];
1153
1154 let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
1155
1156 assert!(is_coinbase(&coinbase_tx));
1157 assert_eq!(coinbase_tx.outputs[0].value, 0);
1158 }
1159
1160 #[test]
1161 fn test_create_coinbase_transaction_large_subsidy() {
1162 let height = 100;
1163 let subsidy = 2100000000000000; let script = vec![OP_1];
1165 let address = vec![OP_1];
1166
1167 let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
1168
1169 assert!(is_coinbase(&coinbase_tx));
1170 assert_eq!(coinbase_tx.outputs[0].value, subsidy);
1171 }
1172
1173 #[test]
1174 fn test_create_coinbase_transaction_empty_script() {
1175 let height = 100;
1176 let subsidy = 5000000000;
1177 let script = vec![]; let address = vec![OP_1];
1179
1180 let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
1181
1182 assert!(is_coinbase(&coinbase_tx));
1183 assert_eq!(coinbase_tx.outputs[0].value, subsidy);
1184 }
1185
1186 #[test]
1187 fn test_create_coinbase_transaction_empty_address() {
1188 let height = 100;
1189 let subsidy = 5000000000;
1190 let script = vec![OP_1];
1191 let address = vec![]; let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
1194
1195 assert!(is_coinbase(&coinbase_tx));
1196 assert_eq!(coinbase_tx.outputs[0].value, subsidy);
1197 }
1198
1199 #[test]
1200 fn test_calculate_merkle_root_single_transaction() {
1201 let txs = vec![create_valid_transaction()];
1202 let merkle_root = calculate_merkle_root(&txs).unwrap();
1203
1204 assert_eq!(merkle_root.len(), 32);
1205 assert_ne!(merkle_root, [0u8; 32]);
1206 }
1207
1208 #[test]
1209 fn test_calculate_merkle_root_three_transactions() {
1210 let txs = vec![
1211 create_valid_transaction(),
1212 create_valid_transaction(),
1213 create_valid_transaction(),
1214 ];
1215
1216 let merkle_root = calculate_merkle_root(&txs).unwrap();
1217 assert_eq!(merkle_root.len(), 32);
1218 assert_ne!(merkle_root, [0u8; 32]);
1219 }
1220
1221 #[test]
1222 fn test_calculate_merkle_root_five_transactions() {
1223 let txs = vec![
1224 create_valid_transaction(),
1225 create_valid_transaction(),
1226 create_valid_transaction(),
1227 create_valid_transaction(),
1228 create_valid_transaction(),
1229 ];
1230
1231 let merkle_root = calculate_merkle_root(&txs).unwrap();
1232 assert_eq!(merkle_root.len(), 32);
1233 assert_ne!(merkle_root, [0u8; 32]);
1234 }
1235
1236 #[test]
1237 fn test_calculate_tx_hash_different_transactions() {
1238 let tx1 = create_valid_transaction();
1239 let mut tx2 = create_valid_transaction();
1240 tx2.version = 2; let hash1 = calculate_tx_hash(&tx1);
1243 let hash2 = calculate_tx_hash(&tx2);
1244
1245 assert_ne!(hash1, hash2);
1246 }
1247
1248 #[test]
1249 fn test_sha256_hash_empty_data() {
1250 let data = vec![];
1251 let hash = sha256_hash(&data);
1252
1253 assert_eq!(hash.len(), 32);
1254 }
1255
1256 #[test]
1264 fn test_merkle_tree_uses_double_sha256_not_single() {
1265 let hash_a = [0x01u8; 32];
1267 let hash_b = [0x02u8; 32];
1268
1269 let mut combined = [0u8; 64];
1271 combined[..32].copy_from_slice(&hash_a);
1272 combined[32..].copy_from_slice(&hash_b);
1273
1274 let expected_double = double_sha256_hash(&combined);
1275 let wrong_single = sha256_hash(&combined);
1276
1277 assert_ne!(
1279 expected_double, wrong_single,
1280 "Double SHA256 and single SHA256 must produce different results"
1281 );
1282
1283 let root = calculate_merkle_root_from_tx_ids(&[hash_a, hash_b]).unwrap();
1285 assert_eq!(
1286 root, expected_double,
1287 "Merkle root must use double SHA256, not single SHA256"
1288 );
1289 assert_ne!(
1290 root, wrong_single,
1291 "Merkle root must NOT match single SHA256 result"
1292 );
1293 }
1294
1295 #[test]
1296 fn test_merkle_root_single_tx_equals_txid() {
1297 let tx = create_valid_transaction();
1299 let txid = calculate_tx_hash(&tx);
1300
1301 let root_from_txs = calculate_merkle_root(&[tx]).unwrap();
1302 let root_from_ids = calculate_merkle_root_from_tx_ids(&[txid]).unwrap();
1303
1304 assert_eq!(root_from_txs, txid, "Single tx merkle root must equal txid");
1305 assert_eq!(
1306 root_from_ids, txid,
1307 "Single txid merkle root must equal txid"
1308 );
1309 }
1310
1311 #[test]
1312 fn test_calculate_merkle_root_from_tx_ids_matches_calculate_merkle_root() {
1313 let tx1 = create_valid_transaction();
1315 let tx2 = create_valid_transaction();
1316 let tx3 = create_valid_transaction();
1317
1318 let txid1 = calculate_tx_hash(&tx1);
1319 let txid2 = calculate_tx_hash(&tx2);
1320 let txid3 = calculate_tx_hash(&tx3);
1321
1322 let root_from_txs = calculate_merkle_root(&[tx1, tx2, tx3]).unwrap();
1323 let root_from_ids = calculate_merkle_root_from_tx_ids(&[txid1, txid2, txid3]).unwrap();
1324
1325 assert_eq!(
1326 root_from_txs, root_from_ids,
1327 "calculate_merkle_root and calculate_merkle_root_from_tx_ids must produce identical results"
1328 );
1329 }
1330
1331 #[test]
1332 fn test_calculate_merkle_root_from_tx_ids_two_txs() {
1333 let tx1 = create_valid_transaction();
1334 let tx2 = create_valid_transaction();
1335
1336 let txid1 = calculate_tx_hash(&tx1);
1337 let txid2 = calculate_tx_hash(&tx2);
1338
1339 let root_from_txs = calculate_merkle_root(&[tx1, tx2]).unwrap();
1340 let root_from_ids = calculate_merkle_root_from_tx_ids(&[txid1, txid2]).unwrap();
1341
1342 assert_eq!(root_from_txs, root_from_ids);
1343 }
1344
1345 #[test]
1346 fn test_calculate_merkle_root_from_tx_ids_four_txs() {
1347 let tx1 = create_valid_transaction();
1348 let tx2 = create_valid_transaction();
1349 let tx3 = create_valid_transaction();
1350 let tx4 = create_valid_transaction();
1351
1352 let txid1 = calculate_tx_hash(&tx1);
1353 let txid2 = calculate_tx_hash(&tx2);
1354 let txid3 = calculate_tx_hash(&tx3);
1355 let txid4 = calculate_tx_hash(&tx4);
1356
1357 let root_from_txs = calculate_merkle_root(&[tx1, tx2, tx3, tx4]).unwrap();
1358 let root_from_ids =
1359 calculate_merkle_root_from_tx_ids(&[txid1, txid2, txid3, txid4]).unwrap();
1360
1361 assert_eq!(root_from_txs, root_from_ids);
1362 }
1363
1364 #[test]
1365 fn test_calculate_merkle_root_from_tx_ids_empty() {
1366 let result = calculate_merkle_root_from_tx_ids(&[]);
1367 assert!(result.is_err(), "Empty tx_ids list should fail");
1368 }
1369
1370 #[test]
1371 fn test_merkle_root_deterministic() {
1372 let tx1 = create_valid_transaction();
1374 let tx2 = create_valid_transaction();
1375
1376 let txid1 = calculate_tx_hash(&tx1);
1377 let txid2 = calculate_tx_hash(&tx2);
1378
1379 let root1 = calculate_merkle_root_from_tx_ids(&[txid1, txid2]).unwrap();
1380 let root2 = calculate_merkle_root_from_tx_ids(&[txid1, txid2]).unwrap();
1381
1382 assert_eq!(root1, root2, "Merkle root must be deterministic");
1383 }
1384
1385 #[test]
1386 fn test_merkle_root_order_matters() {
1387 let txid1 = [0x01u8; 32];
1389 let txid2 = [0x02u8; 32];
1390
1391 let root_ab = calculate_merkle_root_from_tx_ids(&[txid1, txid2]).unwrap();
1392 let root_ba = calculate_merkle_root_from_tx_ids(&[txid2, txid1]).unwrap();
1393
1394 assert_ne!(root_ab, root_ba, "Tx order must affect merkle root");
1395 }
1396
1397 #[test]
1398 fn test_double_sha256_hash_known_value() {
1399 let result = double_sha256_hash(&[]);
1403 assert_eq!(result.len(), 32);
1405 let result2 = double_sha256_hash(&[]);
1406 assert_eq!(result, result2);
1407
1408 let single = sha256_hash(&[]);
1410 assert_ne!(
1411 result, single,
1412 "double SHA256 must differ from single SHA256"
1413 );
1414 }
1415}