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 Network::Mainnet,
43 None,
44 )
45}
46
47#[allow(clippy::too_many_arguments)]
53#[spec_locked("12.1", "CreateNewBlock")]
54pub fn create_new_block_with_time(
55 utxo_set: &UtxoSet,
56 mempool_txs: &[Transaction],
57 height: Natural,
58 prev_header: &BlockHeader,
59 prev_headers: &[BlockHeader],
60 coinbase_script: &ByteString,
61 coinbase_address: &ByteString,
62 block_time: u64,
63 network: Network,
64 mempool_witnesses: Option<&[Option<Vec<crate::segwit::Witness>>]>,
65) -> Result<Block> {
66 use crate::bip113::get_median_time_past;
67 use crate::mempool::{Mempool, MempoolResult, accept_to_memory_pool};
68
69 let coinbase_tx = create_coinbase_transaction(
71 height,
72 get_block_subsidy(height),
73 coinbase_script,
74 coinbase_address,
75 )?;
76
77 let mut selected_txs = Vec::new();
80 let temp_mempool = Mempool::new(); for (idx, tx) in mempool_txs.iter().enumerate() {
83 if check_transaction(tx)? != ValidationResult::Valid {
85 continue;
86 }
87
88 let median_time_past = get_median_time_past(prev_headers);
89 let time_context = Some(TimeContext {
90 network_time: block_time,
91 median_time_past,
92 });
93 let tx_witnesses = mempool_witnesses
94 .and_then(|all| all.get(idx))
95 .and_then(|w| w.as_deref());
96 match accept_to_memory_pool(
97 tx,
98 tx_witnesses,
99 utxo_set,
100 &temp_mempool,
101 height,
102 time_context,
103 network,
104 )? {
105 MempoolResult::Accepted => {
106 selected_txs.push(tx.clone());
107 }
108 MempoolResult::Rejected(_reason) => {
109 #[cfg(test)]
112 eprintln!("Transaction rejected: {_reason}");
113 continue;
114 }
115 }
116 }
117
118 let mut transactions = vec![coinbase_tx];
120 transactions.extend(selected_txs);
121
122 let merkle_root = calculate_merkle_root(&transactions)?;
124
125 let next_work = get_next_work_required(prev_header, prev_headers)?;
127
128 let header = BlockHeader {
130 version: 1,
131 prev_block_hash: calculate_block_hash(prev_header),
132 merkle_root,
133 timestamp: block_time,
134 bits: next_work,
135 nonce: 0, };
137
138 Ok(Block {
139 header,
140 transactions: transactions.into_boxed_slice(),
141 })
142}
143
144#[track_caller] #[spec_locked("12.3", "MineBlock")]
152pub fn mine_block(mut block: Block, max_attempts: Natural) -> Result<(Block, MiningResult)> {
153 for nonce in 0..max_attempts {
154 block.header.nonce = nonce;
155
156 if check_proof_of_work(&block.header).unwrap_or(false) {
157 return Ok((block, MiningResult::Success));
158 }
159 }
160
161 Ok((block, MiningResult::Failure))
162}
163
164#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
172pub struct BlockTemplate {
173 pub header: BlockHeader,
174 pub coinbase_tx: Transaction,
175 pub transactions: Vec<Transaction>,
176 pub target: u128,
177 pub height: Natural,
178 pub timestamp: Natural,
179}
180
181#[spec_locked("12.4", "BlockTemplate")]
183pub fn create_block_template(
184 utxo_set: &UtxoSet,
185 mempool_txs: &[Transaction],
186 height: Natural,
187 prev_header: &BlockHeader,
188 prev_headers: &[BlockHeader],
189 coinbase_script: &ByteString,
190 coinbase_address: &ByteString,
191 network: Network,
192 mempool_witnesses: Option<&[Option<Vec<crate::segwit::Witness>>]>,
193) -> Result<BlockTemplate> {
194 let block_time = get_current_timestamp();
195 let block = create_new_block_with_time(
196 utxo_set,
197 mempool_txs,
198 height,
199 prev_header,
200 prev_headers,
201 coinbase_script,
202 coinbase_address,
203 block_time,
204 network,
205 mempool_witnesses,
206 )?;
207
208 let target_u256 = crate::pow::expand_target(block.header.bits)?;
209 let target = if target_u256.is_zero() {
210 0
211 } else if target_u256.low_u128() > 0 {
212 target_u256.low_u128()
213 } else {
214 1
215 };
216
217 let header = block.header.clone();
218
219 #[cfg(feature = "production")]
221 let coinbase_tx = {
222 use crate::optimizations::_optimized_access::get_proven_by_;
223 get_proven_by_(&block.transactions, 0)
224 .ok_or_else(|| {
225 crate::error::ConsensusError::BlockValidation("Block has no transactions".into())
226 })?
227 .clone()
228 };
229
230 #[cfg(not(feature = "production"))]
231 let coinbase_tx = block.transactions[0].clone();
232
233 Ok(BlockTemplate {
234 header: block.header,
235 coinbase_tx,
236 transactions: block.transactions[1..].to_vec(),
237 target,
238 height,
239 timestamp: header.timestamp,
240 })
241}
242
243#[derive(Debug, Clone, PartialEq, Eq)]
249pub enum MiningResult {
250 Success,
251 Failure,
252}
253
254#[spec_locked("12.2", "CreateCoinbaseTransaction")]
259fn create_coinbase_transaction(
260 height: Natural,
261 subsidy: Integer,
262 script: &ByteString,
263 address: &ByteString,
264) -> Result<Transaction> {
265 let lock_time = height.saturating_sub(13);
266 let coinbase_input = TransactionInput {
267 prevout: OutPoint {
268 hash: [0u8; 32],
269 index: 0xffffffff,
270 },
271 script_sig: script.clone(),
272 sequence: 0xfffffffe, };
274
275 let coinbase_output = TransactionOutput {
276 value: subsidy,
277 script_pubkey: address.clone(),
278 };
279
280 Ok(Transaction {
281 version: 1,
282 inputs: crate::tx_inputs![coinbase_input],
283 outputs: crate::tx_outputs![coinbase_output],
284 lock_time,
285 })
286}
287
288#[track_caller] #[cfg_attr(feature = "production", inline(always))]
291#[cfg_attr(not(feature = "production"), inline)]
292#[spec_locked("8.4.1", "ComputeMerkleRoot")]
293pub fn calculate_merkle_root(transactions: &[Transaction]) -> Result<Hash> {
294 if transactions.is_empty() {
295 return Err(crate::error::ConsensusError::InvalidProofOfWork(
296 "Cannot calculate merkle root for empty transaction list".into(),
297 ));
298 }
299
300 #[cfg(feature = "production")]
304 let mut hashes: Vec<crate::optimizations::CacheAlignedHash> = {
305 use crate::optimizations::simd_vectorization;
306
307 let serialized_txs: Vec<Vec<u8>> = {
311 #[cfg(feature = "rayon")]
312 {
313 use rayon::prelude::*;
314 transactions
315 .par_iter()
316 .map(serialize_tx_for_hash) .collect()
318 }
319 #[cfg(not(feature = "rayon"))]
320 {
321 transactions
322 .iter()
323 .map(serialize_tx_for_hash) .collect()
325 }
326 };
327
328 let tx_data_refs: Vec<&[u8]> = serialized_txs.iter().map(|v| v.as_slice()).collect();
331 simd_vectorization::batch_double_sha256_aligned(&tx_data_refs)
332 };
333
334 #[cfg(not(feature = "production"))]
335 let mut hashes: Vec<Hash> = {
336 let mut hashes = Vec::with_capacity(transactions.len());
338 for tx in transactions {
339 hashes.push(calculate_tx_hash(tx));
340 }
341 hashes
342 };
343
344 #[cfg(feature = "production")]
349 {
350 use crate::optimizations::CacheAlignedHash;
351
352 let mut mutated = false;
353
354 while hashes.len() > 1 {
355 let mut level_mutated = false;
357 let mut pos = 0;
358 while pos + 1 < hashes.len() {
359 if hashes[pos].as_bytes() == hashes[pos + 1].as_bytes() {
360 level_mutated = true;
361 }
362 pos += 2;
363 }
364 if level_mutated {
365 mutated = true;
366 }
367
368 if hashes.len() & 1 != 0 {
370 let last = hashes[hashes.len() - 1].clone();
371 hashes.push(last);
372 }
373
374 let next_level: Vec<CacheAlignedHash> = hashes
376 .chunks(2)
377 .map(|chunk| {
378 let mut combined = [0u8; 64];
379 combined[..32].copy_from_slice(chunk[0].as_bytes());
380 combined[32..].copy_from_slice(if chunk.len() == 2 {
381 chunk[1].as_bytes()
382 } else {
383 chunk[0].as_bytes()
384 });
385 CacheAlignedHash::new(double_sha256_hash(&combined))
386 })
387 .collect();
388
389 hashes = next_level;
390 }
391
392 if mutated {
393 return Err(crate::error::ConsensusError::InvalidProofOfWork(
394 "Merkle root mutation detected (CVE-2012-2459)".into(),
395 ));
396 }
397
398 Ok(*hashes[0].as_bytes())
399 }
400
401 #[cfg(not(feature = "production"))]
402 {
403 let (root, mutated) = merkle_tree_from_hashes(&mut hashes)?;
404 if mutated {
405 return Err(crate::error::ConsensusError::InvalidProofOfWork(
406 "Merkle root mutation detected (CVE-2012-2459)".into(),
407 ));
408 }
409 Ok(root)
410 }
411}
412
413#[spec_locked("8.4.1", "ComputeMerkleRoot")]
423pub fn calculate_merkle_root_from_tx_ids(tx_ids: &[Hash]) -> Result<Hash> {
424 let (root, mutated) = compute_merkle_root_and_mutated(tx_ids)?;
425 if mutated {
426 return Err(crate::error::ConsensusError::InvalidProofOfWork(
427 "Merkle root mutation detected (CVE-2012-2459)".into(),
428 ));
429 }
430 Ok(root)
431}
432
433#[spec_locked("8.4.1", "ComputeMerkleRoot")]
438pub fn compute_merkle_root_and_mutated(tx_ids: &[Hash]) -> Result<(Hash, bool)> {
439 if tx_ids.is_empty() {
440 return Err(crate::error::ConsensusError::InvalidProofOfWork(
441 "Cannot calculate merkle root for empty transaction list".into(),
442 ));
443 }
444 let mut hashes = tx_ids.to_vec();
445 merkle_tree_from_hashes(&mut hashes)
446}
447
448#[spec_locked("8.4.1", "ComputeMerkleRoot")]
453fn merkle_tree_from_hashes(hashes: &mut Vec<Hash>) -> Result<(Hash, bool)> {
454 let mut mutated = false;
455
456 while hashes.len() > 1 {
457 for pos in (0..hashes.len().saturating_sub(1)).step_by(2) {
459 if hashes[pos] == hashes[pos + 1] {
460 mutated = true;
461 }
462 }
463
464 if hashes.len() & 1 != 0 {
466 hashes.push(hashes[hashes.len() - 1]);
467 }
468
469 let mut next_level = Vec::with_capacity(hashes.len() / 2);
470
471 for chunk in hashes.chunks(2) {
473 let mut combined = [0u8; 64];
474 combined[..32].copy_from_slice(&chunk[0]);
475 combined[32..].copy_from_slice(if chunk.len() == 2 {
476 &chunk[1]
477 } else {
478 &chunk[0]
479 });
480 next_level.push(double_sha256_hash(&combined));
481 }
482
483 *hashes = next_level;
484 }
485
486 Ok((hashes[0], mutated))
487}
488
489fn serialize_tx_for_hash(tx: &Transaction) -> Vec<u8> {
494 #[cfg(feature = "production")]
496 let mut data = {
497 use crate::optimizations::prealloc_tx_buffer;
498 prealloc_tx_buffer()
499 };
500
501 #[cfg(not(feature = "production"))]
502 let mut data = Vec::new();
503
504 data.extend_from_slice(&(tx.version as u32).to_le_bytes());
506
507 data.extend_from_slice(&encode_varint(tx.inputs.len() as u64));
509
510 for input in &tx.inputs {
512 data.extend_from_slice(&input.prevout.hash);
514 data.extend_from_slice(&input.prevout.index.to_le_bytes());
516 data.extend_from_slice(&encode_varint(input.script_sig.len() as u64));
518 data.extend_from_slice(&input.script_sig);
520 data.extend_from_slice(&(input.sequence as u32).to_le_bytes());
522 }
523
524 data.extend_from_slice(&encode_varint(tx.outputs.len() as u64));
526
527 for output in &tx.outputs {
529 data.extend_from_slice(&(output.value as u64).to_le_bytes());
531 data.extend_from_slice(&encode_varint(output.script_pubkey.len() as u64));
533 data.extend_from_slice(&output.script_pubkey);
535 }
536
537 data.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
539
540 data
541}
542
543#[allow(dead_code)] fn calculate_tx_hash(tx: &Transaction) -> Hash {
549 let data = serialize_tx_for_hash(tx);
550 let hash1 = sha256_hash(&data);
552 sha256_hash(&hash1)
553}
554
555fn encode_varint(value: u64) -> Vec<u8> {
557 if value < 0xfd {
558 vec![value as u8]
559 } else if value <= 0xffff {
560 let mut result = vec![0xfd];
561 result.extend_from_slice(&(value as u16).to_le_bytes());
562 result
563 } else if value <= 0xffffffff {
564 let mut result = vec![0xfe];
565 result.extend_from_slice(&(value as u32).to_le_bytes());
566 result
567 } else {
568 let mut result = vec![0xff];
569 result.extend_from_slice(&value.to_le_bytes());
570 result
571 }
572}
573
574fn calculate_block_hash(header: &BlockHeader) -> Hash {
576 let wire = crate::serialization::block::serialize_block_header(header);
577 double_sha256_hash(&wire)
578}
579
580#[inline(always)]
585fn sha256_hash(data: &[u8]) -> Hash {
586 use crate::crypto::OptimizedSha256;
587 OptimizedSha256::new().hash(data)
588}
589
590#[inline(always)]
592fn double_sha256_hash(data: &[u8]) -> Hash {
593 use crate::crypto::OptimizedSha256;
594 OptimizedSha256::new().hash256(data)
595}
596
597fn get_current_timestamp() -> Natural {
599 std::time::SystemTime::now()
600 .duration_since(std::time::UNIX_EPOCH)
601 .unwrap_or(std::time::Duration::ZERO)
602 .as_secs()
603}
604
605#[cfg(test)]
606mod tests {
607 use super::*;
608 use crate::opcodes::*;
609
610 #[test]
611 fn test_create_new_block() {
612 let mut utxo_set = UtxoSet::default();
613 let outpoint = OutPoint {
615 hash: [1; 32],
616 index: 0,
617 };
618 let utxo = UTXO {
619 value: 10000,
620 script_pubkey: vec![].into(),
622 height: 0,
623 is_coinbase: false,
624 };
625 utxo_set.insert(outpoint, std::sync::Arc::new(utxo));
626
627 let mempool_txs = vec![create_valid_transaction()];
628 let height = 100;
629 let prev_header = create_valid_block_header();
630 let mut prev_header2 = prev_header.clone();
632 prev_header2.timestamp = prev_header.timestamp + 600; let prev_headers = vec![prev_header.clone(), prev_header2];
634 let coinbase_script = vec![OP_1];
635 let coinbase_address = vec![OP_1];
636
637 let block_time = 1_700_000_000u64;
640 let result = create_new_block_with_time(
641 &utxo_set,
642 &mempool_txs,
643 height,
644 &prev_header,
645 &prev_headers,
646 &coinbase_script,
647 &coinbase_address,
648 block_time,
649 Network::Mainnet,
650 None,
651 );
652
653 if let Ok(block) = result {
654 assert_eq!(block.transactions.len(), 2); assert!(is_coinbase(&block.transactions[0]));
656 assert_eq!(block.header.version, 1);
657 assert_eq!(block.header.timestamp, block_time);
658 } else {
659 assert!(result.is_err());
662 }
663 }
664
665 #[test]
666 fn test_mine_block_success() {
667 let block = create_test_block();
668 let result = mine_block(block, 1000);
669
670 assert!(result.is_ok());
672 let (mined_block, mining_result) = result.unwrap();
673 assert!(matches!(
674 mining_result,
675 MiningResult::Success | MiningResult::Failure
676 ));
677 assert_eq!(mined_block.header.version, 1);
678 }
679
680 #[test]
681 fn test_create_block_template() {
682 let utxo_set = UtxoSet::default();
683 let mempool_txs = vec![create_valid_transaction()];
684 let height = 100;
685 let prev_header = create_valid_block_header();
686 let prev_headers = vec![prev_header.clone()];
687 let coinbase_script = vec![OP_1];
688 let coinbase_address = vec![OP_1];
689
690 let result = create_block_template(
692 &utxo_set,
693 &mempool_txs,
694 height,
695 &prev_header,
696 &prev_headers,
697 &coinbase_script,
698 &coinbase_address,
699 Network::Mainnet,
700 None,
701 );
702
703 assert!(result.is_err());
705 }
706
707 #[test]
708 fn test_coinbase_transaction() {
709 let height = 100;
710 let subsidy = get_block_subsidy(height);
711 let script = vec![OP_1];
712 let address = vec![OP_1];
713
714 let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
715
716 assert!(is_coinbase(&coinbase_tx));
717 assert_eq!(coinbase_tx.outputs[0].value, subsidy);
718 assert_eq!(coinbase_tx.inputs[0].prevout.hash, [0u8; 32]);
719 assert_eq!(coinbase_tx.inputs[0].prevout.index, 0xffffffff);
720 }
721
722 #[test]
723 fn test_merkle_root_calculation() {
724 let txs = vec![create_valid_transaction(), create_valid_transaction()];
725
726 let merkle_root = calculate_merkle_root(&txs).unwrap();
727 assert_ne!(merkle_root, [0u8; 32]);
728 }
729
730 #[test]
731 fn test_merkle_root_empty() {
732 let txs = vec![];
733 let result = calculate_merkle_root(&txs);
734 assert!(result.is_err());
735 }
736
737 #[test]
742 fn test_create_block_template_comprehensive() {
743 let mut utxo_set = UtxoSet::default();
744 let outpoint = OutPoint {
746 hash: [1; 32],
747 index: 0,
748 };
749 let utxo = UTXO {
750 value: 10000,
751 script_pubkey: vec![].into(),
753 height: 0,
754 is_coinbase: false,
755 };
756 utxo_set.insert(outpoint, std::sync::Arc::new(utxo));
757
758 let mempool_txs = vec![create_valid_transaction()];
759 let height = 100;
760 let prev_header = create_valid_block_header();
761 let mut prev_header2 = prev_header.clone();
763 prev_header2.timestamp = prev_header.timestamp + 600; let prev_headers = vec![prev_header.clone(), prev_header2];
765 let coinbase_script = vec![OP_1];
766 let coinbase_address = vec![OP_2];
767
768 let result = create_block_template(
769 &utxo_set,
770 &mempool_txs,
771 height,
772 &prev_header,
773 &prev_headers,
774 &coinbase_script,
775 &coinbase_address,
776 Network::Mainnet,
777 None,
778 );
779
780 if let Ok(template) = result {
783 assert_eq!(template.height, height);
784 assert!(template.target > 0);
785 assert!(is_coinbase(&template.coinbase_tx));
786 assert_eq!(template.transactions.len(), 1);
787 } else {
788 assert!(result.is_err());
790 }
791 }
792
793 #[test]
794 fn test_mine_block_attempts() {
795 let block = create_test_block();
796 let (mined_block, result) = mine_block(block, 1000).unwrap();
797
798 assert!(matches!(
800 result,
801 MiningResult::Success | MiningResult::Failure
802 ));
803 assert_eq!(mined_block.header.version, 1);
804 }
805
806 #[test]
807 fn test_mine_block_failure() {
808 let block = create_test_block();
809 let (mined_block, result) = mine_block(block, 0).unwrap();
810
811 assert_eq!(result, MiningResult::Failure);
813 assert_eq!(mined_block.header.nonce, 0);
814 }
815
816 #[test]
817 fn test_create_coinbase_transaction() {
818 let height = 100;
819 let subsidy = 5000000000;
820 let script = vec![0x51, 0x52];
821 let address = vec![0x53, 0x54];
822
823 let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
824
825 assert!(is_coinbase(&coinbase_tx));
826 assert_eq!(coinbase_tx.outputs.len(), 1);
827 assert_eq!(coinbase_tx.outputs[0].value, subsidy);
828 assert_eq!(coinbase_tx.outputs[0].script_pubkey, address);
829 assert_eq!(coinbase_tx.inputs[0].script_sig, script);
830 assert_eq!(coinbase_tx.inputs[0].prevout.hash, [0u8; 32]);
831 assert_eq!(coinbase_tx.inputs[0].prevout.index, 0xffffffff);
832 }
833
834 #[test]
835 fn test_calculate_tx_hash() {
836 let tx = create_valid_transaction();
837 let hash = calculate_tx_hash(&tx);
838
839 assert_eq!(hash.len(), 32);
841
842 let hash2 = calculate_tx_hash(&tx);
844 assert_eq!(hash, hash2);
845 }
846
847 #[test]
848 fn test_calculate_tx_hash_different_txs() {
849 let tx1 = create_valid_transaction();
850 let mut tx2 = tx1.clone();
851 tx2.version = 2; let hash1 = calculate_tx_hash(&tx1);
854 let hash2 = calculate_tx_hash(&tx2);
855
856 assert_ne!(hash1, hash2);
858 }
859
860 #[test]
861 fn test_encode_varint_small() {
862 let encoded = encode_varint(0x42);
863 assert_eq!(encoded, vec![0x42]);
864 }
865
866 #[test]
867 fn test_encode_varint_medium() {
868 let encoded = encode_varint(0x1234);
869 assert_eq!(encoded.len(), 3);
870 assert_eq!(encoded[0], 0xfd);
871 }
872
873 #[test]
874 fn test_encode_varint_large() {
875 let encoded = encode_varint(0x12345678);
876 assert_eq!(encoded.len(), 5);
877 assert_eq!(encoded[0], 0xfe);
878 }
879
880 #[test]
881 fn test_encode_varint_huge() {
882 let encoded = encode_varint(0x123456789abcdef0);
883 assert_eq!(encoded.len(), 9);
884 assert_eq!(encoded[0], 0xff);
885 }
886
887 #[test]
888 fn test_calculate_block_hash() {
889 let header = create_valid_block_header();
890 let hash = calculate_block_hash(&header);
891
892 assert_eq!(hash.len(), 32);
894
895 let hash2 = calculate_block_hash(&header);
897 assert_eq!(hash, hash2);
898 }
899
900 #[test]
901 fn test_calculate_block_hash_different_headers() {
902 let header1 = create_valid_block_header();
903 let mut header2 = header1.clone();
904 header2.version = 2; let hash1 = calculate_block_hash(&header1);
907 let hash2 = calculate_block_hash(&header2);
908
909 assert_ne!(hash1, hash2);
911 }
912
913 #[test]
914 fn test_sha256_hash() {
915 let data = b"hello world";
916 let hash = sha256_hash(data);
917
918 assert_eq!(hash.len(), 32);
920
921 let hash2 = sha256_hash(data);
923 assert_eq!(hash, hash2);
924 }
925
926 #[test]
927 fn test_sha256_hash_different_data() {
928 let data1 = b"hello";
929 let data2 = b"world";
930
931 let hash1 = sha256_hash(data1);
932 let hash2 = sha256_hash(data2);
933
934 assert_ne!(hash1, hash2);
936 }
937
938 #[test]
939 fn test_pow_expand_target_regtest_minimum_difficulty() {
940 let target = crate::pow::expand_target(0x207fffff).expect("regtest nBits");
941 assert!(!target.is_zero());
942 assert_eq!(target.gbt_target_hex().len(), 64);
943 }
944
945 #[test]
946 fn test_create_block_template_regtest_nbits() {
947 let utxo_set = UtxoSet::default();
948 let prev_header = BlockHeader {
949 version: 4,
950 prev_block_hash: [0u8; 32],
951 merkle_root: [0u8; 32],
952 timestamp: 1_600_000_000,
953 bits: 0x207fffff,
954 nonce: 0,
955 };
956 let prev_headers = vec![prev_header.clone(), prev_header.clone()];
957
958 let template = create_block_template(
959 &utxo_set,
960 &[],
961 1,
962 &prev_header,
963 &prev_headers,
964 &vec![],
965 &vec![0x51],
966 Network::Regtest,
967 None,
968 )
969 .expect("create_block_template must not fail on regtest nBits");
970
971 assert_eq!(template.header.bits, 0x207fffff);
972 assert!(template.target > 0);
973 }
974
975 #[test]
976 fn test_get_current_timestamp() {
977 let timestamp = get_current_timestamp();
978 assert!(timestamp > 1_231_006_505);
980 assert!(timestamp < 4_000_000_000);
981 }
982
983 #[test]
984 fn test_merkle_root_single_transaction() {
985 let txs = vec![create_valid_transaction()];
986 let merkle_root = calculate_merkle_root(&txs).unwrap();
987
988 assert_eq!(merkle_root.len(), 32);
990 assert_ne!(merkle_root, [0u8; 32]);
991 }
992
993 #[test]
994 fn test_merkle_root_three_transactions() {
995 let txs = vec![
996 create_valid_transaction(),
997 create_valid_transaction(),
998 create_valid_transaction(),
999 ];
1000 let merkle_root = calculate_merkle_root(&txs).unwrap();
1001
1002 assert_eq!(merkle_root.len(), 32);
1004 assert_ne!(merkle_root, [0u8; 32]);
1005 }
1006
1007 #[test]
1008 fn test_merkle_root_five_transactions() {
1009 let txs = vec![
1010 create_valid_transaction(),
1011 create_valid_transaction(),
1012 create_valid_transaction(),
1013 create_valid_transaction(),
1014 create_valid_transaction(),
1015 ];
1016 let merkle_root = calculate_merkle_root(&txs).unwrap();
1017
1018 assert_eq!(merkle_root.len(), 32);
1020 assert_ne!(merkle_root, [0u8; 32]);
1021 }
1022
1023 #[test]
1024 fn test_block_template_fields() {
1025 let mut utxo_set = UtxoSet::default();
1026 let outpoint = OutPoint {
1028 hash: [1; 32],
1029 index: 0,
1030 };
1031 let utxo = UTXO {
1032 value: 10000,
1033 script_pubkey: vec![].into(),
1035 height: 0,
1036 is_coinbase: false,
1037 };
1038 utxo_set.insert(outpoint, std::sync::Arc::new(utxo));
1039
1040 let mempool_txs = vec![create_valid_transaction()];
1041 let height = 100;
1042 let prev_header = create_valid_block_header();
1043 let prev_headers = vec![prev_header.clone(), prev_header.clone()];
1044 let coinbase_script = vec![OP_1];
1045 let coinbase_address = vec![OP_2];
1046
1047 let result = create_block_template(
1048 &utxo_set,
1049 &mempool_txs,
1050 height,
1051 &prev_header,
1052 &prev_headers,
1053 &coinbase_script,
1054 &coinbase_address,
1055 Network::Mainnet,
1056 None,
1057 );
1058
1059 if let Ok(template) = result {
1062 assert_eq!(template.height, height);
1064 assert!(template.target > 0);
1065 assert!(template.timestamp > 0);
1066 assert!(is_coinbase(&template.coinbase_tx));
1067 assert_eq!(template.transactions.len(), 1);
1068 assert_eq!(template.header.version, 1);
1069 } else {
1070 assert!(result.is_err());
1072 }
1073 }
1074
1075 fn create_valid_transaction() -> Transaction {
1077 use std::cell::Cell;
1079 thread_local! {
1080 static COUNTER: Cell<u64> = const { Cell::new(0) };
1081 }
1082 let counter = COUNTER.with(|c| {
1083 let val = c.get();
1084 c.set(val + 1);
1085 val
1086 });
1087
1088 Transaction {
1089 version: 1,
1090 inputs: vec![TransactionInput {
1091 prevout: OutPoint {
1092 hash: [1; 32], index: 0,
1094 },
1095 script_sig: {
1102 let mut sig = vec![OP_1]; if counter > 0 {
1105 sig.push(PUSH_1_BYTE); sig.push((counter & 0xff) as u8); }
1108 sig
1109 },
1110 sequence: 0xffffffff,
1111 }]
1112 .into(),
1113 outputs: vec![TransactionOutput {
1114 value: 1000 + counter as i64, script_pubkey: vec![],
1117 }]
1118 .into(),
1119 lock_time: 0,
1120 }
1121 }
1122
1123 fn create_valid_block_header() -> BlockHeader {
1124 BlockHeader {
1125 version: 1,
1126 prev_block_hash: [0; 32],
1127 merkle_root: [0; 32],
1128 timestamp: 1231006505,
1129 bits: 0x0600ffff, nonce: 0,
1131 }
1132 }
1133
1134 fn create_test_block() -> Block {
1135 Block {
1136 header: create_valid_block_header(),
1137 transactions: vec![create_valid_transaction()].into_boxed_slice(),
1138 }
1139 }
1140
1141 #[test]
1142 fn test_create_coinbase_transaction_zero_subsidy() {
1143 let height = 100;
1144 let subsidy = 0; let script = vec![OP_1];
1146 let address = vec![OP_1];
1147
1148 let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
1149
1150 assert!(is_coinbase(&coinbase_tx));
1151 assert_eq!(coinbase_tx.outputs[0].value, 0);
1152 }
1153
1154 #[test]
1155 fn test_create_coinbase_transaction_large_subsidy() {
1156 let height = 100;
1157 let subsidy = 2100000000000000; let script = vec![OP_1];
1159 let address = vec![OP_1];
1160
1161 let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
1162
1163 assert!(is_coinbase(&coinbase_tx));
1164 assert_eq!(coinbase_tx.outputs[0].value, subsidy);
1165 }
1166
1167 #[test]
1168 fn test_create_coinbase_transaction_empty_script() {
1169 let height = 100;
1170 let subsidy = 5000000000;
1171 let script = vec![]; let address = vec![OP_1];
1173
1174 let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
1175
1176 assert!(is_coinbase(&coinbase_tx));
1177 assert_eq!(coinbase_tx.outputs[0].value, subsidy);
1178 }
1179
1180 #[test]
1181 fn test_create_coinbase_transaction_empty_address() {
1182 let height = 100;
1183 let subsidy = 5000000000;
1184 let script = vec![OP_1];
1185 let address = vec![]; let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
1188
1189 assert!(is_coinbase(&coinbase_tx));
1190 assert_eq!(coinbase_tx.outputs[0].value, subsidy);
1191 }
1192
1193 #[test]
1194 fn test_calculate_merkle_root_single_transaction() {
1195 let txs = vec![create_valid_transaction()];
1196 let merkle_root = calculate_merkle_root(&txs).unwrap();
1197
1198 assert_eq!(merkle_root.len(), 32);
1199 assert_ne!(merkle_root, [0u8; 32]);
1200 }
1201
1202 #[test]
1203 fn test_calculate_merkle_root_three_transactions() {
1204 let txs = vec![
1205 create_valid_transaction(),
1206 create_valid_transaction(),
1207 create_valid_transaction(),
1208 ];
1209
1210 let merkle_root = calculate_merkle_root(&txs).unwrap();
1211 assert_eq!(merkle_root.len(), 32);
1212 assert_ne!(merkle_root, [0u8; 32]);
1213 }
1214
1215 #[test]
1216 fn test_calculate_merkle_root_five_transactions() {
1217 let txs = vec![
1218 create_valid_transaction(),
1219 create_valid_transaction(),
1220 create_valid_transaction(),
1221 create_valid_transaction(),
1222 create_valid_transaction(),
1223 ];
1224
1225 let merkle_root = calculate_merkle_root(&txs).unwrap();
1226 assert_eq!(merkle_root.len(), 32);
1227 assert_ne!(merkle_root, [0u8; 32]);
1228 }
1229
1230 #[test]
1231 fn test_calculate_tx_hash_different_transactions() {
1232 let tx1 = create_valid_transaction();
1233 let mut tx2 = create_valid_transaction();
1234 tx2.version = 2; let hash1 = calculate_tx_hash(&tx1);
1237 let hash2 = calculate_tx_hash(&tx2);
1238
1239 assert_ne!(hash1, hash2);
1240 }
1241
1242 #[test]
1243 fn test_sha256_hash_empty_data() {
1244 let data = vec![];
1245 let hash = sha256_hash(&data);
1246
1247 assert_eq!(hash.len(), 32);
1248 }
1249
1250 #[test]
1258 fn test_merkle_tree_uses_double_sha256_not_single() {
1259 let hash_a = [0x01u8; 32];
1261 let hash_b = [0x02u8; 32];
1262
1263 let mut combined = [0u8; 64];
1265 combined[..32].copy_from_slice(&hash_a);
1266 combined[32..].copy_from_slice(&hash_b);
1267
1268 let expected_double = double_sha256_hash(&combined);
1269 let wrong_single = sha256_hash(&combined);
1270
1271 assert_ne!(
1273 expected_double, wrong_single,
1274 "Double SHA256 and single SHA256 must produce different results"
1275 );
1276
1277 let root = calculate_merkle_root_from_tx_ids(&[hash_a, hash_b]).unwrap();
1279 assert_eq!(
1280 root, expected_double,
1281 "Merkle root must use double SHA256, not single SHA256"
1282 );
1283 assert_ne!(
1284 root, wrong_single,
1285 "Merkle root must NOT match single SHA256 result"
1286 );
1287 }
1288
1289 #[test]
1290 fn test_merkle_root_single_tx_equals_txid() {
1291 let tx = create_valid_transaction();
1293 let txid = calculate_tx_hash(&tx);
1294
1295 let root_from_txs = calculate_merkle_root(&[tx]).unwrap();
1296 let root_from_ids = calculate_merkle_root_from_tx_ids(&[txid]).unwrap();
1297
1298 assert_eq!(root_from_txs, txid, "Single tx merkle root must equal txid");
1299 assert_eq!(
1300 root_from_ids, txid,
1301 "Single txid merkle root must equal txid"
1302 );
1303 }
1304
1305 #[test]
1306 fn test_calculate_merkle_root_from_tx_ids_matches_calculate_merkle_root() {
1307 let tx1 = create_valid_transaction();
1309 let tx2 = create_valid_transaction();
1310 let tx3 = create_valid_transaction();
1311
1312 let txid1 = calculate_tx_hash(&tx1);
1313 let txid2 = calculate_tx_hash(&tx2);
1314 let txid3 = calculate_tx_hash(&tx3);
1315
1316 let root_from_txs = calculate_merkle_root(&[tx1, tx2, tx3]).unwrap();
1317 let root_from_ids = calculate_merkle_root_from_tx_ids(&[txid1, txid2, txid3]).unwrap();
1318
1319 assert_eq!(
1320 root_from_txs, root_from_ids,
1321 "calculate_merkle_root and calculate_merkle_root_from_tx_ids must produce identical results"
1322 );
1323 }
1324
1325 #[test]
1326 fn test_calculate_merkle_root_from_tx_ids_two_txs() {
1327 let tx1 = create_valid_transaction();
1328 let tx2 = create_valid_transaction();
1329
1330 let txid1 = calculate_tx_hash(&tx1);
1331 let txid2 = calculate_tx_hash(&tx2);
1332
1333 let root_from_txs = calculate_merkle_root(&[tx1, tx2]).unwrap();
1334 let root_from_ids = calculate_merkle_root_from_tx_ids(&[txid1, txid2]).unwrap();
1335
1336 assert_eq!(root_from_txs, root_from_ids);
1337 }
1338
1339 #[test]
1340 fn test_calculate_merkle_root_from_tx_ids_four_txs() {
1341 let tx1 = create_valid_transaction();
1342 let tx2 = create_valid_transaction();
1343 let tx3 = create_valid_transaction();
1344 let tx4 = create_valid_transaction();
1345
1346 let txid1 = calculate_tx_hash(&tx1);
1347 let txid2 = calculate_tx_hash(&tx2);
1348 let txid3 = calculate_tx_hash(&tx3);
1349 let txid4 = calculate_tx_hash(&tx4);
1350
1351 let root_from_txs = calculate_merkle_root(&[tx1, tx2, tx3, tx4]).unwrap();
1352 let root_from_ids =
1353 calculate_merkle_root_from_tx_ids(&[txid1, txid2, txid3, txid4]).unwrap();
1354
1355 assert_eq!(root_from_txs, root_from_ids);
1356 }
1357
1358 #[test]
1359 fn test_calculate_merkle_root_from_tx_ids_empty() {
1360 let result = calculate_merkle_root_from_tx_ids(&[]);
1361 assert!(result.is_err(), "Empty tx_ids list should fail");
1362 }
1363
1364 #[test]
1365 fn test_merkle_root_deterministic() {
1366 let tx1 = create_valid_transaction();
1368 let tx2 = create_valid_transaction();
1369
1370 let txid1 = calculate_tx_hash(&tx1);
1371 let txid2 = calculate_tx_hash(&tx2);
1372
1373 let root1 = calculate_merkle_root_from_tx_ids(&[txid1, txid2]).unwrap();
1374 let root2 = calculate_merkle_root_from_tx_ids(&[txid1, txid2]).unwrap();
1375
1376 assert_eq!(root1, root2, "Merkle root must be deterministic");
1377 }
1378
1379 #[test]
1380 fn test_merkle_root_order_matters() {
1381 let txid1 = [0x01u8; 32];
1383 let txid2 = [0x02u8; 32];
1384
1385 let root_ab = calculate_merkle_root_from_tx_ids(&[txid1, txid2]).unwrap();
1386 let root_ba = calculate_merkle_root_from_tx_ids(&[txid2, txid1]).unwrap();
1387
1388 assert_ne!(root_ab, root_ba, "Tx order must affect merkle root");
1389 }
1390
1391 #[test]
1392 fn test_double_sha256_hash_known_value() {
1393 let result = double_sha256_hash(&[]);
1397 assert_eq!(result.len(), 32);
1399 let result2 = double_sha256_hash(&[]);
1400 assert_eq!(result, result2);
1401
1402 let single = sha256_hash(&[]);
1404 assert_ne!(
1405 result, single,
1406 "double SHA256 must differ from single SHA256"
1407 );
1408 }
1409}