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")]
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")]
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")]
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")]
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 = expand_target(block.header.bits)?;
187
188 let header = block.header.clone();
189
190 #[cfg(feature = "production")]
192 let coinbase_tx = {
193 use crate::optimizations::_optimized_access::get_proven_by_;
194 get_proven_by_(&block.transactions, 0)
195 .ok_or_else(|| {
196 crate::error::ConsensusError::BlockValidation("Block has no transactions".into())
197 })?
198 .clone()
199 };
200
201 #[cfg(not(feature = "production"))]
202 let coinbase_tx = block.transactions[0].clone();
203
204 Ok(BlockTemplate {
205 header: block.header,
206 coinbase_tx,
207 transactions: block.transactions[1..].to_vec(),
208 target,
209 height,
210 timestamp: header.timestamp,
211 })
212}
213
214#[derive(Debug, Clone, PartialEq, Eq)]
220pub enum MiningResult {
221 Success,
222 Failure,
223}
224
225#[spec_locked("12.2")]
230fn create_coinbase_transaction(
231 height: Natural,
232 subsidy: Integer,
233 script: &ByteString,
234 address: &ByteString,
235) -> Result<Transaction> {
236 let lock_time = height.saturating_sub(13);
237 let coinbase_input = TransactionInput {
238 prevout: OutPoint {
239 hash: [0u8; 32],
240 index: 0xffffffff,
241 },
242 script_sig: script.clone(),
243 sequence: 0xfffffffe, };
245
246 let coinbase_output = TransactionOutput {
247 value: subsidy,
248 script_pubkey: address.clone(),
249 };
250
251 Ok(Transaction {
252 version: 1,
253 inputs: crate::tx_inputs![coinbase_input],
254 outputs: crate::tx_outputs![coinbase_output],
255 lock_time,
256 })
257}
258
259#[track_caller] #[cfg_attr(feature = "production", inline(always))]
262#[cfg_attr(not(feature = "production"), inline)]
263#[spec_locked("8.4.1")]
264pub fn calculate_merkle_root(transactions: &[Transaction]) -> Result<Hash> {
265 if transactions.is_empty() {
266 return Err(crate::error::ConsensusError::InvalidProofOfWork(
267 "Cannot calculate merkle root for empty transaction list".into(),
268 ));
269 }
270
271 #[cfg(feature = "production")]
275 let mut hashes: Vec<crate::optimizations::CacheAlignedHash> = {
276 use crate::optimizations::simd_vectorization;
277
278 let serialized_txs: Vec<Vec<u8>> = {
282 #[cfg(feature = "rayon")]
283 {
284 use rayon::prelude::*;
285 transactions
286 .par_iter()
287 .map(serialize_tx_for_hash) .collect()
289 }
290 #[cfg(not(feature = "rayon"))]
291 {
292 transactions
293 .iter()
294 .map(serialize_tx_for_hash) .collect()
296 }
297 };
298
299 let tx_data_refs: Vec<&[u8]> = serialized_txs.iter().map(|v| v.as_slice()).collect();
302 simd_vectorization::batch_double_sha256_aligned(&tx_data_refs)
303 };
304
305 #[cfg(not(feature = "production"))]
306 let mut hashes: Vec<Hash> = {
307 let mut hashes = Vec::with_capacity(transactions.len());
309 for tx in transactions {
310 hashes.push(calculate_tx_hash(tx));
311 }
312 hashes
313 };
314
315 #[cfg(feature = "production")]
320 {
321 use crate::optimizations::CacheAlignedHash;
322
323 let mut mutated = false;
324
325 while hashes.len() > 1 {
326 let mut level_mutated = false;
328 let mut pos = 0;
329 while pos + 1 < hashes.len() {
330 if hashes[pos].as_bytes() == hashes[pos + 1].as_bytes() {
331 level_mutated = true;
332 }
333 pos += 2;
334 }
335 if level_mutated {
336 mutated = true;
337 }
338
339 if hashes.len() & 1 != 0 {
341 let last = hashes[hashes.len() - 1].clone();
342 hashes.push(last);
343 }
344
345 let next_level: Vec<CacheAlignedHash> = hashes
347 .chunks(2)
348 .map(|chunk| {
349 let mut combined = [0u8; 64];
350 combined[..32].copy_from_slice(chunk[0].as_bytes());
351 combined[32..].copy_from_slice(if chunk.len() == 2 {
352 chunk[1].as_bytes()
353 } else {
354 chunk[0].as_bytes()
355 });
356 CacheAlignedHash::new(double_sha256_hash(&combined))
357 })
358 .collect();
359
360 hashes = next_level;
361 }
362
363 if mutated {
364 return Err(crate::error::ConsensusError::InvalidProofOfWork(
365 "Merkle root mutation detected (CVE-2012-2459)".into(),
366 ));
367 }
368
369 Ok(*hashes[0].as_bytes())
370 }
371
372 #[cfg(not(feature = "production"))]
373 {
374 let (root, mutated) = merkle_tree_from_hashes(&mut hashes)?;
375 if mutated {
376 return Err(crate::error::ConsensusError::InvalidProofOfWork(
377 "Merkle root mutation detected (CVE-2012-2459)".into(),
378 ));
379 }
380 Ok(root)
381 }
382}
383
384#[spec_locked("8.4.1")]
394pub fn calculate_merkle_root_from_tx_ids(tx_ids: &[Hash]) -> Result<Hash> {
395 let (root, mutated) = compute_merkle_root_and_mutated(tx_ids)?;
396 if mutated {
397 return Err(crate::error::ConsensusError::InvalidProofOfWork(
398 "Merkle root mutation detected (CVE-2012-2459)".into(),
399 ));
400 }
401 Ok(root)
402}
403
404#[spec_locked("8.4.1")]
409pub fn compute_merkle_root_and_mutated(tx_ids: &[Hash]) -> Result<(Hash, bool)> {
410 if tx_ids.is_empty() {
411 return Err(crate::error::ConsensusError::InvalidProofOfWork(
412 "Cannot calculate merkle root for empty transaction list".into(),
413 ));
414 }
415 let mut hashes = tx_ids.to_vec();
416 merkle_tree_from_hashes(&mut hashes)
417}
418
419#[spec_locked("8.4.1")]
424fn merkle_tree_from_hashes(hashes: &mut Vec<Hash>) -> Result<(Hash, bool)> {
425 let mut mutated = false;
426
427 while hashes.len() > 1 {
428 for pos in (0..hashes.len().saturating_sub(1)).step_by(2) {
430 if hashes[pos] == hashes[pos + 1] {
431 mutated = true;
432 }
433 }
434
435 if hashes.len() & 1 != 0 {
437 hashes.push(hashes[hashes.len() - 1]);
438 }
439
440 let mut next_level = Vec::with_capacity(hashes.len() / 2);
441
442 for chunk in hashes.chunks(2) {
444 let mut combined = [0u8; 64];
445 combined[..32].copy_from_slice(&chunk[0]);
446 combined[32..].copy_from_slice(if chunk.len() == 2 {
447 &chunk[1]
448 } else {
449 &chunk[0]
450 });
451 next_level.push(double_sha256_hash(&combined));
452 }
453
454 *hashes = next_level;
455 }
456
457 Ok((hashes[0], mutated))
458}
459
460fn serialize_tx_for_hash(tx: &Transaction) -> Vec<u8> {
465 #[cfg(feature = "production")]
467 let mut data = {
468 use crate::optimizations::prealloc_tx_buffer;
469 prealloc_tx_buffer()
470 };
471
472 #[cfg(not(feature = "production"))]
473 let mut data = Vec::new();
474
475 data.extend_from_slice(&(tx.version as u32).to_le_bytes());
477
478 data.extend_from_slice(&encode_varint(tx.inputs.len() as u64));
480
481 for input in &tx.inputs {
483 data.extend_from_slice(&input.prevout.hash);
485 data.extend_from_slice(&input.prevout.index.to_le_bytes());
487 data.extend_from_slice(&encode_varint(input.script_sig.len() as u64));
489 data.extend_from_slice(&input.script_sig);
491 data.extend_from_slice(&(input.sequence as u32).to_le_bytes());
493 }
494
495 data.extend_from_slice(&encode_varint(tx.outputs.len() as u64));
497
498 for output in &tx.outputs {
500 data.extend_from_slice(&(output.value as u64).to_le_bytes());
502 data.extend_from_slice(&encode_varint(output.script_pubkey.len() as u64));
504 data.extend_from_slice(&output.script_pubkey);
506 }
507
508 data.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
510
511 data
512}
513
514#[allow(dead_code)] fn calculate_tx_hash(tx: &Transaction) -> Hash {
520 let data = serialize_tx_for_hash(tx);
521 let hash1 = sha256_hash(&data);
523 sha256_hash(&hash1)
524}
525
526fn encode_varint(value: u64) -> Vec<u8> {
528 if value < 0xfd {
529 vec![value as u8]
530 } else if value <= 0xffff {
531 let mut result = vec![0xfd];
532 result.extend_from_slice(&(value as u16).to_le_bytes());
533 result
534 } else if value <= 0xffffffff {
535 let mut result = vec![0xfe];
536 result.extend_from_slice(&(value as u32).to_le_bytes());
537 result
538 } else {
539 let mut result = vec![0xff];
540 result.extend_from_slice(&value.to_le_bytes());
541 result
542 }
543}
544
545#[spec_locked("7.2")]
548fn calculate_block_hash(header: &BlockHeader) -> Hash {
549 let mut data = Vec::new();
550
551 data.extend_from_slice(&(header.version as u32).to_le_bytes());
553
554 data.extend_from_slice(&header.prev_block_hash);
556
557 data.extend_from_slice(&header.merkle_root);
559
560 data.extend_from_slice(&(header.timestamp as u32).to_le_bytes());
562
563 data.extend_from_slice(&(header.bits as u32).to_le_bytes());
565
566 data.extend_from_slice(&(header.nonce as u32).to_le_bytes());
568
569 sha256_hash(&data)
570}
571
572#[inline(always)]
577fn sha256_hash(data: &[u8]) -> Hash {
578 use crate::crypto::OptimizedSha256;
579 OptimizedSha256::new().hash(data)
580}
581
582#[inline(always)]
584fn double_sha256_hash(data: &[u8]) -> Hash {
585 use crate::crypto::OptimizedSha256;
586 OptimizedSha256::new().hash256(data)
587}
588
589#[spec_locked("7.1")]
592fn expand_target(bits: Natural) -> Result<u128> {
593 let exponent = (bits >> 24) as u8;
594 let mantissa = bits & 0x00ffffff;
595
596 if exponent <= 3 {
597 let shift = 8 * (3 - exponent);
598 Ok((mantissa >> shift) as u128)
599 } else {
600 let shift = 8 * (exponent - 3);
601 if shift >= 104 {
602 return Err(crate::error::ConsensusError::InvalidProofOfWork(
604 "Target too large".into(),
605 ));
606 }
607 Ok((mantissa as u128) << shift)
609 }
610}
611
612fn get_current_timestamp() -> Natural {
614 1231006505
617}
618
619#[cfg(test)]
620mod tests {
621 use super::*;
622 use crate::opcodes::*;
623
624 #[test]
625 fn test_create_new_block() {
626 let mut utxo_set = UtxoSet::default();
627 let outpoint = OutPoint {
629 hash: [1; 32],
630 index: 0,
631 };
632 let utxo = UTXO {
633 value: 10000,
634 script_pubkey: vec![].into(),
636 height: 0,
637 is_coinbase: false,
638 };
639 utxo_set.insert(outpoint, std::sync::Arc::new(utxo));
640
641 let mempool_txs = vec![create_valid_transaction()];
642 let height = 100;
643 let prev_header = create_valid_block_header();
644 let mut prev_header2 = prev_header.clone();
646 prev_header2.timestamp = prev_header.timestamp + 600; let prev_headers = vec![prev_header.clone(), prev_header2];
648 let coinbase_script = vec![OP_1];
649 let coinbase_address = vec![OP_1];
650
651 let result = create_new_block(
654 &utxo_set,
655 &mempool_txs,
656 height,
657 &prev_header,
658 &prev_headers,
659 &coinbase_script,
660 &coinbase_address,
661 );
662
663 if let Ok(block) = result {
664 assert_eq!(block.transactions.len(), 2); assert!(is_coinbase(&block.transactions[0]));
666 assert_eq!(block.header.version, 1);
667 assert_eq!(block.header.timestamp, 1231006505);
668 } else {
669 assert!(result.is_err());
672 }
673 }
674
675 #[test]
676 fn test_mine_block_success() {
677 let block = create_test_block();
678 let result = mine_block(block, 1000);
679
680 assert!(result.is_ok());
682 let (mined_block, mining_result) = result.unwrap();
683 assert!(matches!(
684 mining_result,
685 MiningResult::Success | MiningResult::Failure
686 ));
687 assert_eq!(mined_block.header.version, 1);
688 }
689
690 #[test]
691 fn test_create_block_template() {
692 let utxo_set = UtxoSet::default();
693 let mempool_txs = vec![create_valid_transaction()];
694 let height = 100;
695 let prev_header = create_valid_block_header();
696 let prev_headers = vec![prev_header.clone()];
697 let coinbase_script = vec![OP_1];
698 let coinbase_address = vec![OP_1];
699
700 let result = create_block_template(
702 &utxo_set,
703 &mempool_txs,
704 height,
705 &prev_header,
706 &prev_headers,
707 &coinbase_script,
708 &coinbase_address,
709 );
710
711 assert!(result.is_err());
713 }
714
715 #[test]
716 fn test_coinbase_transaction() {
717 let height = 100;
718 let subsidy = get_block_subsidy(height);
719 let script = vec![OP_1];
720 let address = vec![OP_1];
721
722 let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
723
724 assert!(is_coinbase(&coinbase_tx));
725 assert_eq!(coinbase_tx.outputs[0].value, subsidy);
726 assert_eq!(coinbase_tx.inputs[0].prevout.hash, [0u8; 32]);
727 assert_eq!(coinbase_tx.inputs[0].prevout.index, 0xffffffff);
728 }
729
730 #[test]
731 fn test_merkle_root_calculation() {
732 let txs = vec![create_valid_transaction(), create_valid_transaction()];
733
734 let merkle_root = calculate_merkle_root(&txs).unwrap();
735 assert_ne!(merkle_root, [0u8; 32]);
736 }
737
738 #[test]
739 fn test_merkle_root_empty() {
740 let txs = vec![];
741 let result = calculate_merkle_root(&txs);
742 assert!(result.is_err());
743 }
744
745 #[test]
750 fn test_create_block_template_comprehensive() {
751 let mut utxo_set = UtxoSet::default();
752 let outpoint = OutPoint {
754 hash: [1; 32],
755 index: 0,
756 };
757 let utxo = UTXO {
758 value: 10000,
759 script_pubkey: vec![].into(),
761 height: 0,
762 is_coinbase: false,
763 };
764 utxo_set.insert(outpoint, std::sync::Arc::new(utxo));
765
766 let mempool_txs = vec![create_valid_transaction()];
767 let height = 100;
768 let prev_header = create_valid_block_header();
769 let mut prev_header2 = prev_header.clone();
771 prev_header2.timestamp = prev_header.timestamp + 600; let prev_headers = vec![prev_header.clone(), prev_header2];
773 let coinbase_script = vec![OP_1];
774 let coinbase_address = vec![OP_2];
775
776 let result = create_block_template(
777 &utxo_set,
778 &mempool_txs,
779 height,
780 &prev_header,
781 &prev_headers,
782 &coinbase_script,
783 &coinbase_address,
784 );
785
786 if let Ok(template) = result {
789 assert_eq!(template.height, height);
790 assert!(template.target > 0);
791 assert!(is_coinbase(&template.coinbase_tx));
792 assert_eq!(template.transactions.len(), 1);
793 } else {
794 assert!(result.is_err());
796 }
797 }
798
799 #[test]
800 fn test_mine_block_attempts() {
801 let block = create_test_block();
802 let (mined_block, result) = mine_block(block, 1000).unwrap();
803
804 assert!(matches!(
806 result,
807 MiningResult::Success | MiningResult::Failure
808 ));
809 assert_eq!(mined_block.header.version, 1);
810 }
811
812 #[test]
813 fn test_mine_block_failure() {
814 let block = create_test_block();
815 let (mined_block, result) = mine_block(block, 0).unwrap();
816
817 assert_eq!(result, MiningResult::Failure);
819 assert_eq!(mined_block.header.nonce, 0);
820 }
821
822 #[test]
823 fn test_create_coinbase_transaction() {
824 let height = 100;
825 let subsidy = 5000000000;
826 let script = vec![0x51, 0x52];
827 let address = vec![0x53, 0x54];
828
829 let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
830
831 assert!(is_coinbase(&coinbase_tx));
832 assert_eq!(coinbase_tx.outputs.len(), 1);
833 assert_eq!(coinbase_tx.outputs[0].value, subsidy);
834 assert_eq!(coinbase_tx.outputs[0].script_pubkey, address);
835 assert_eq!(coinbase_tx.inputs[0].script_sig, script);
836 assert_eq!(coinbase_tx.inputs[0].prevout.hash, [0u8; 32]);
837 assert_eq!(coinbase_tx.inputs[0].prevout.index, 0xffffffff);
838 }
839
840 #[test]
841 fn test_calculate_tx_hash() {
842 let tx = create_valid_transaction();
843 let hash = calculate_tx_hash(&tx);
844
845 assert_eq!(hash.len(), 32);
847
848 let hash2 = calculate_tx_hash(&tx);
850 assert_eq!(hash, hash2);
851 }
852
853 #[test]
854 fn test_calculate_tx_hash_different_txs() {
855 let tx1 = create_valid_transaction();
856 let mut tx2 = tx1.clone();
857 tx2.version = 2; let hash1 = calculate_tx_hash(&tx1);
860 let hash2 = calculate_tx_hash(&tx2);
861
862 assert_ne!(hash1, hash2);
864 }
865
866 #[test]
867 fn test_encode_varint_small() {
868 let encoded = encode_varint(0x42);
869 assert_eq!(encoded, vec![0x42]);
870 }
871
872 #[test]
873 fn test_encode_varint_medium() {
874 let encoded = encode_varint(0x1234);
875 assert_eq!(encoded.len(), 3);
876 assert_eq!(encoded[0], 0xfd);
877 }
878
879 #[test]
880 fn test_encode_varint_large() {
881 let encoded = encode_varint(0x12345678);
882 assert_eq!(encoded.len(), 5);
883 assert_eq!(encoded[0], 0xfe);
884 }
885
886 #[test]
887 fn test_encode_varint_huge() {
888 let encoded = encode_varint(0x123456789abcdef0);
889 assert_eq!(encoded.len(), 9);
890 assert_eq!(encoded[0], 0xff);
891 }
892
893 #[test]
894 fn test_calculate_block_hash() {
895 let header = create_valid_block_header();
896 let hash = calculate_block_hash(&header);
897
898 assert_eq!(hash.len(), 32);
900
901 let hash2 = calculate_block_hash(&header);
903 assert_eq!(hash, hash2);
904 }
905
906 #[test]
907 fn test_calculate_block_hash_different_headers() {
908 let header1 = create_valid_block_header();
909 let mut header2 = header1.clone();
910 header2.version = 2; let hash1 = calculate_block_hash(&header1);
913 let hash2 = calculate_block_hash(&header2);
914
915 assert_ne!(hash1, hash2);
917 }
918
919 #[test]
920 fn test_sha256_hash() {
921 let data = b"hello world";
922 let hash = sha256_hash(data);
923
924 assert_eq!(hash.len(), 32);
926
927 let hash2 = sha256_hash(data);
929 assert_eq!(hash, hash2);
930 }
931
932 #[test]
933 fn test_sha256_hash_different_data() {
934 let data1 = b"hello";
935 let data2 = b"world";
936
937 let hash1 = sha256_hash(data1);
938 let hash2 = sha256_hash(data2);
939
940 assert_ne!(hash1, hash2);
942 }
943
944 #[test]
945 fn test_expand_target_small() {
946 let bits = 0x0300ffff; let target = expand_target(bits).unwrap();
948 assert!(target > 0);
949 }
950
951 #[test]
952 fn test_expand_target_medium() {
953 let bits = 0x0600ffff; let target = expand_target(bits).unwrap();
955 assert!(target > 0);
956 }
957
958 #[test]
959 fn test_expand_target_too_large() {
960 let bits = 0x2000ffff; let result = expand_target(bits);
962 assert!(result.is_err());
963 }
964
965 #[test]
966 fn test_get_current_timestamp() {
967 let timestamp = get_current_timestamp();
968 assert_eq!(timestamp, 1231006505);
969 }
970
971 #[test]
972 fn test_merkle_root_single_transaction() {
973 let txs = vec![create_valid_transaction()];
974 let merkle_root = calculate_merkle_root(&txs).unwrap();
975
976 assert_eq!(merkle_root.len(), 32);
978 assert_ne!(merkle_root, [0u8; 32]);
979 }
980
981 #[test]
982 fn test_merkle_root_three_transactions() {
983 let txs = vec![
984 create_valid_transaction(),
985 create_valid_transaction(),
986 create_valid_transaction(),
987 ];
988 let merkle_root = calculate_merkle_root(&txs).unwrap();
989
990 assert_eq!(merkle_root.len(), 32);
992 assert_ne!(merkle_root, [0u8; 32]);
993 }
994
995 #[test]
996 fn test_merkle_root_five_transactions() {
997 let txs = vec![
998 create_valid_transaction(),
999 create_valid_transaction(),
1000 create_valid_transaction(),
1001 create_valid_transaction(),
1002 create_valid_transaction(),
1003 ];
1004 let merkle_root = calculate_merkle_root(&txs).unwrap();
1005
1006 assert_eq!(merkle_root.len(), 32);
1008 assert_ne!(merkle_root, [0u8; 32]);
1009 }
1010
1011 #[test]
1012 fn test_block_template_fields() {
1013 let mut utxo_set = UtxoSet::default();
1014 let outpoint = OutPoint {
1016 hash: [1; 32],
1017 index: 0,
1018 };
1019 let utxo = UTXO {
1020 value: 10000,
1021 script_pubkey: vec![].into(),
1023 height: 0,
1024 is_coinbase: false,
1025 };
1026 utxo_set.insert(outpoint, std::sync::Arc::new(utxo));
1027
1028 let mempool_txs = vec![create_valid_transaction()];
1029 let height = 100;
1030 let prev_header = create_valid_block_header();
1031 let prev_headers = vec![prev_header.clone(), prev_header.clone()];
1032 let coinbase_script = vec![OP_1];
1033 let coinbase_address = vec![OP_2];
1034
1035 let result = create_block_template(
1036 &utxo_set,
1037 &mempool_txs,
1038 height,
1039 &prev_header,
1040 &prev_headers,
1041 &coinbase_script,
1042 &coinbase_address,
1043 );
1044
1045 if let Ok(template) = result {
1048 assert_eq!(template.height, height);
1050 assert!(template.target > 0);
1051 assert!(template.timestamp > 0);
1052 assert!(is_coinbase(&template.coinbase_tx));
1053 assert_eq!(template.transactions.len(), 1);
1054 assert_eq!(template.header.version, 1);
1055 } else {
1056 assert!(result.is_err());
1058 }
1059 }
1060
1061 fn create_valid_transaction() -> Transaction {
1063 use std::cell::Cell;
1065 thread_local! {
1066 static COUNTER: Cell<u64> = Cell::new(0);
1067 }
1068 let counter = COUNTER.with(|c| {
1069 let val = c.get();
1070 c.set(val + 1);
1071 val
1072 });
1073
1074 Transaction {
1075 version: 1,
1076 inputs: vec![TransactionInput {
1077 prevout: OutPoint {
1078 hash: [1; 32].into(), index: 0,
1080 },
1081 script_sig: {
1088 let mut sig = vec![OP_1]; if counter > 0 {
1091 sig.push(PUSH_1_BYTE); sig.push((counter & 0xff) as u8); }
1094 sig
1095 },
1096 sequence: 0xffffffff,
1097 }]
1098 .into(),
1099 outputs: vec![TransactionOutput {
1100 value: 1000 + counter as i64, script_pubkey: vec![].into(),
1103 }]
1104 .into(),
1105 lock_time: 0,
1106 }
1107 }
1108
1109 fn create_valid_block_header() -> BlockHeader {
1110 BlockHeader {
1111 version: 1,
1112 prev_block_hash: [0; 32],
1113 merkle_root: [0; 32],
1114 timestamp: 1231006505,
1115 bits: 0x0600ffff, nonce: 0,
1117 }
1118 }
1119
1120 fn create_test_block() -> Block {
1121 Block {
1122 header: create_valid_block_header(),
1123 transactions: vec![create_valid_transaction()].into_boxed_slice(),
1124 }
1125 }
1126
1127 #[test]
1128 fn test_create_coinbase_transaction_zero_subsidy() {
1129 let height = 100;
1130 let subsidy = 0; let script = vec![OP_1];
1132 let address = vec![OP_1];
1133
1134 let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
1135
1136 assert!(is_coinbase(&coinbase_tx));
1137 assert_eq!(coinbase_tx.outputs[0].value, 0);
1138 }
1139
1140 #[test]
1141 fn test_create_coinbase_transaction_large_subsidy() {
1142 let height = 100;
1143 let subsidy = 2100000000000000; let script = vec![OP_1];
1145 let address = vec![OP_1];
1146
1147 let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
1148
1149 assert!(is_coinbase(&coinbase_tx));
1150 assert_eq!(coinbase_tx.outputs[0].value, subsidy);
1151 }
1152
1153 #[test]
1154 fn test_create_coinbase_transaction_empty_script() {
1155 let height = 100;
1156 let subsidy = 5000000000;
1157 let script = vec![]; let address = vec![OP_1];
1159
1160 let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
1161
1162 assert!(is_coinbase(&coinbase_tx));
1163 assert_eq!(coinbase_tx.outputs[0].value, subsidy);
1164 }
1165
1166 #[test]
1167 fn test_create_coinbase_transaction_empty_address() {
1168 let height = 100;
1169 let subsidy = 5000000000;
1170 let script = vec![OP_1];
1171 let address = vec![]; let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
1174
1175 assert!(is_coinbase(&coinbase_tx));
1176 assert_eq!(coinbase_tx.outputs[0].value, subsidy);
1177 }
1178
1179 #[test]
1180 fn test_calculate_merkle_root_single_transaction() {
1181 let txs = vec![create_valid_transaction()];
1182 let merkle_root = calculate_merkle_root(&txs).unwrap();
1183
1184 assert_eq!(merkle_root.len(), 32);
1185 assert_ne!(merkle_root, [0u8; 32]);
1186 }
1187
1188 #[test]
1189 fn test_calculate_merkle_root_three_transactions() {
1190 let txs = vec![
1191 create_valid_transaction(),
1192 create_valid_transaction(),
1193 create_valid_transaction(),
1194 ];
1195
1196 let merkle_root = calculate_merkle_root(&txs).unwrap();
1197 assert_eq!(merkle_root.len(), 32);
1198 assert_ne!(merkle_root, [0u8; 32]);
1199 }
1200
1201 #[test]
1202 fn test_calculate_merkle_root_five_transactions() {
1203 let txs = vec![
1204 create_valid_transaction(),
1205 create_valid_transaction(),
1206 create_valid_transaction(),
1207 create_valid_transaction(),
1208 create_valid_transaction(),
1209 ];
1210
1211 let merkle_root = calculate_merkle_root(&txs).unwrap();
1212 assert_eq!(merkle_root.len(), 32);
1213 assert_ne!(merkle_root, [0u8; 32]);
1214 }
1215
1216 #[test]
1217 fn test_calculate_tx_hash_different_transactions() {
1218 let tx1 = create_valid_transaction();
1219 let mut tx2 = create_valid_transaction();
1220 tx2.version = 2; let hash1 = calculate_tx_hash(&tx1);
1223 let hash2 = calculate_tx_hash(&tx2);
1224
1225 assert_ne!(hash1, hash2);
1226 }
1227
1228 #[test]
1229 fn test_sha256_hash_empty_data() {
1230 let data = vec![];
1231 let hash = sha256_hash(&data);
1232
1233 assert_eq!(hash.len(), 32);
1234 }
1235
1236 #[test]
1244 fn test_merkle_tree_uses_double_sha256_not_single() {
1245 let hash_a = [0x01u8; 32];
1247 let hash_b = [0x02u8; 32];
1248
1249 let mut combined = [0u8; 64];
1251 combined[..32].copy_from_slice(&hash_a);
1252 combined[32..].copy_from_slice(&hash_b);
1253
1254 let expected_double = double_sha256_hash(&combined);
1255 let wrong_single = sha256_hash(&combined);
1256
1257 assert_ne!(
1259 expected_double, wrong_single,
1260 "Double SHA256 and single SHA256 must produce different results"
1261 );
1262
1263 let root = calculate_merkle_root_from_tx_ids(&[hash_a, hash_b]).unwrap();
1265 assert_eq!(
1266 root, expected_double,
1267 "Merkle root must use double SHA256, not single SHA256"
1268 );
1269 assert_ne!(
1270 root, wrong_single,
1271 "Merkle root must NOT match single SHA256 result"
1272 );
1273 }
1274
1275 #[test]
1276 fn test_merkle_root_single_tx_equals_txid() {
1277 let tx = create_valid_transaction();
1279 let txid = calculate_tx_hash(&tx);
1280
1281 let root_from_txs = calculate_merkle_root(&[tx]).unwrap();
1282 let root_from_ids = calculate_merkle_root_from_tx_ids(&[txid]).unwrap();
1283
1284 assert_eq!(root_from_txs, txid, "Single tx merkle root must equal txid");
1285 assert_eq!(
1286 root_from_ids, txid,
1287 "Single txid merkle root must equal txid"
1288 );
1289 }
1290
1291 #[test]
1292 fn test_calculate_merkle_root_from_tx_ids_matches_calculate_merkle_root() {
1293 let tx1 = create_valid_transaction();
1295 let tx2 = create_valid_transaction();
1296 let tx3 = create_valid_transaction();
1297
1298 let txid1 = calculate_tx_hash(&tx1);
1299 let txid2 = calculate_tx_hash(&tx2);
1300 let txid3 = calculate_tx_hash(&tx3);
1301
1302 let root_from_txs = calculate_merkle_root(&[tx1, tx2, tx3]).unwrap();
1303 let root_from_ids = calculate_merkle_root_from_tx_ids(&[txid1, txid2, txid3]).unwrap();
1304
1305 assert_eq!(
1306 root_from_txs, root_from_ids,
1307 "calculate_merkle_root and calculate_merkle_root_from_tx_ids must produce identical results"
1308 );
1309 }
1310
1311 #[test]
1312 fn test_calculate_merkle_root_from_tx_ids_two_txs() {
1313 let tx1 = create_valid_transaction();
1314 let tx2 = create_valid_transaction();
1315
1316 let txid1 = calculate_tx_hash(&tx1);
1317 let txid2 = calculate_tx_hash(&tx2);
1318
1319 let root_from_txs = calculate_merkle_root(&[tx1, tx2]).unwrap();
1320 let root_from_ids = calculate_merkle_root_from_tx_ids(&[txid1, txid2]).unwrap();
1321
1322 assert_eq!(root_from_txs, root_from_ids);
1323 }
1324
1325 #[test]
1326 fn test_calculate_merkle_root_from_tx_ids_four_txs() {
1327 let tx1 = create_valid_transaction();
1328 let tx2 = create_valid_transaction();
1329 let tx3 = create_valid_transaction();
1330 let tx4 = create_valid_transaction();
1331
1332 let txid1 = calculate_tx_hash(&tx1);
1333 let txid2 = calculate_tx_hash(&tx2);
1334 let txid3 = calculate_tx_hash(&tx3);
1335 let txid4 = calculate_tx_hash(&tx4);
1336
1337 let root_from_txs = calculate_merkle_root(&[tx1, tx2, tx3, tx4]).unwrap();
1338 let root_from_ids =
1339 calculate_merkle_root_from_tx_ids(&[txid1, txid2, txid3, txid4]).unwrap();
1340
1341 assert_eq!(root_from_txs, root_from_ids);
1342 }
1343
1344 #[test]
1345 fn test_calculate_merkle_root_from_tx_ids_empty() {
1346 let result = calculate_merkle_root_from_tx_ids(&[]);
1347 assert!(result.is_err(), "Empty tx_ids list should fail");
1348 }
1349
1350 #[test]
1351 fn test_merkle_root_deterministic() {
1352 let tx1 = create_valid_transaction();
1354 let tx2 = create_valid_transaction();
1355
1356 let txid1 = calculate_tx_hash(&tx1);
1357 let txid2 = calculate_tx_hash(&tx2);
1358
1359 let root1 = calculate_merkle_root_from_tx_ids(&[txid1, txid2]).unwrap();
1360 let root2 = calculate_merkle_root_from_tx_ids(&[txid1, txid2]).unwrap();
1361
1362 assert_eq!(root1, root2, "Merkle root must be deterministic");
1363 }
1364
1365 #[test]
1366 fn test_merkle_root_order_matters() {
1367 let txid1 = [0x01u8; 32];
1369 let txid2 = [0x02u8; 32];
1370
1371 let root_ab = calculate_merkle_root_from_tx_ids(&[txid1, txid2]).unwrap();
1372 let root_ba = calculate_merkle_root_from_tx_ids(&[txid2, txid1]).unwrap();
1373
1374 assert_ne!(root_ab, root_ba, "Tx order must affect merkle root");
1375 }
1376
1377 #[test]
1378 fn test_double_sha256_hash_known_value() {
1379 let result = double_sha256_hash(&[]);
1383 assert_eq!(result.len(), 32);
1385 let result2 = double_sha256_hash(&[]);
1386 assert_eq!(result, result2);
1387
1388 let single = sha256_hash(&[]);
1390 assert_ne!(
1391 result, single,
1392 "double SHA256 must differ from single SHA256"
1393 );
1394 }
1395}