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 = 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", "CreateCoinbaseTransaction")]
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", "ComputeMerkleRoot")]
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", "ComputeMerkleRoot")]
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", "ComputeMerkleRoot")]
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", "ComputeMerkleRoot")]
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
545fn calculate_block_hash(header: &BlockHeader) -> Hash {
547 let mut data = Vec::new();
548
549 data.extend_from_slice(&(header.version as u32).to_le_bytes());
551
552 data.extend_from_slice(&header.prev_block_hash);
554
555 data.extend_from_slice(&header.merkle_root);
557
558 data.extend_from_slice(&(header.timestamp as u32).to_le_bytes());
560
561 data.extend_from_slice(&(header.bits as u32).to_le_bytes());
563
564 data.extend_from_slice(&(header.nonce as u32).to_le_bytes());
566
567 sha256_hash(&data)
568}
569
570#[inline(always)]
575fn sha256_hash(data: &[u8]) -> Hash {
576 use crate::crypto::OptimizedSha256;
577 OptimizedSha256::new().hash(data)
578}
579
580#[inline(always)]
582fn double_sha256_hash(data: &[u8]) -> Hash {
583 use crate::crypto::OptimizedSha256;
584 OptimizedSha256::new().hash256(data)
585}
586
587fn expand_target(bits: Natural) -> Result<u128> {
590 let exponent = (bits >> 24) as u8;
591 let mantissa = bits & 0x00ffffff;
592
593 if exponent <= 3 {
594 let shift = 8 * (3 - exponent);
595 Ok((mantissa >> shift) as u128)
596 } else {
597 let shift = 8 * (exponent - 3);
598 if shift >= 104 {
599 return Err(crate::error::ConsensusError::InvalidProofOfWork(
601 "Target too large".into(),
602 ));
603 }
604 Ok((mantissa as u128) << shift)
606 }
607}
608
609fn get_current_timestamp() -> Natural {
611 1231006505
614}
615
616#[cfg(test)]
617mod tests {
618 use super::*;
619 use crate::opcodes::*;
620
621 #[test]
622 fn test_create_new_block() {
623 let mut utxo_set = UtxoSet::default();
624 let outpoint = OutPoint {
626 hash: [1; 32],
627 index: 0,
628 };
629 let utxo = UTXO {
630 value: 10000,
631 script_pubkey: vec![].into(),
633 height: 0,
634 is_coinbase: false,
635 };
636 utxo_set.insert(outpoint, std::sync::Arc::new(utxo));
637
638 let mempool_txs = vec![create_valid_transaction()];
639 let height = 100;
640 let prev_header = create_valid_block_header();
641 let mut prev_header2 = prev_header.clone();
643 prev_header2.timestamp = prev_header.timestamp + 600; let prev_headers = vec![prev_header.clone(), prev_header2];
645 let coinbase_script = vec![OP_1];
646 let coinbase_address = vec![OP_1];
647
648 let result = create_new_block(
651 &utxo_set,
652 &mempool_txs,
653 height,
654 &prev_header,
655 &prev_headers,
656 &coinbase_script,
657 &coinbase_address,
658 );
659
660 if let Ok(block) = result {
661 assert_eq!(block.transactions.len(), 2); assert!(is_coinbase(&block.transactions[0]));
663 assert_eq!(block.header.version, 1);
664 assert_eq!(block.header.timestamp, 1231006505);
665 } else {
666 assert!(result.is_err());
669 }
670 }
671
672 #[test]
673 fn test_mine_block_success() {
674 let block = create_test_block();
675 let result = mine_block(block, 1000);
676
677 assert!(result.is_ok());
679 let (mined_block, mining_result) = result.unwrap();
680 assert!(matches!(
681 mining_result,
682 MiningResult::Success | MiningResult::Failure
683 ));
684 assert_eq!(mined_block.header.version, 1);
685 }
686
687 #[test]
688 fn test_create_block_template() {
689 let utxo_set = UtxoSet::default();
690 let mempool_txs = vec![create_valid_transaction()];
691 let height = 100;
692 let prev_header = create_valid_block_header();
693 let prev_headers = vec![prev_header.clone()];
694 let coinbase_script = vec![OP_1];
695 let coinbase_address = vec![OP_1];
696
697 let result = create_block_template(
699 &utxo_set,
700 &mempool_txs,
701 height,
702 &prev_header,
703 &prev_headers,
704 &coinbase_script,
705 &coinbase_address,
706 );
707
708 assert!(result.is_err());
710 }
711
712 #[test]
713 fn test_coinbase_transaction() {
714 let height = 100;
715 let subsidy = get_block_subsidy(height);
716 let script = vec![OP_1];
717 let address = vec![OP_1];
718
719 let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
720
721 assert!(is_coinbase(&coinbase_tx));
722 assert_eq!(coinbase_tx.outputs[0].value, subsidy);
723 assert_eq!(coinbase_tx.inputs[0].prevout.hash, [0u8; 32]);
724 assert_eq!(coinbase_tx.inputs[0].prevout.index, 0xffffffff);
725 }
726
727 #[test]
728 fn test_merkle_root_calculation() {
729 let txs = vec![create_valid_transaction(), create_valid_transaction()];
730
731 let merkle_root = calculate_merkle_root(&txs).unwrap();
732 assert_ne!(merkle_root, [0u8; 32]);
733 }
734
735 #[test]
736 fn test_merkle_root_empty() {
737 let txs = vec![];
738 let result = calculate_merkle_root(&txs);
739 assert!(result.is_err());
740 }
741
742 #[test]
747 fn test_create_block_template_comprehensive() {
748 let mut utxo_set = UtxoSet::default();
749 let outpoint = OutPoint {
751 hash: [1; 32],
752 index: 0,
753 };
754 let utxo = UTXO {
755 value: 10000,
756 script_pubkey: vec![].into(),
758 height: 0,
759 is_coinbase: false,
760 };
761 utxo_set.insert(outpoint, std::sync::Arc::new(utxo));
762
763 let mempool_txs = vec![create_valid_transaction()];
764 let height = 100;
765 let prev_header = create_valid_block_header();
766 let mut prev_header2 = prev_header.clone();
768 prev_header2.timestamp = prev_header.timestamp + 600; let prev_headers = vec![prev_header.clone(), prev_header2];
770 let coinbase_script = vec![OP_1];
771 let coinbase_address = vec![OP_2];
772
773 let result = create_block_template(
774 &utxo_set,
775 &mempool_txs,
776 height,
777 &prev_header,
778 &prev_headers,
779 &coinbase_script,
780 &coinbase_address,
781 );
782
783 if let Ok(template) = result {
786 assert_eq!(template.height, height);
787 assert!(template.target > 0);
788 assert!(is_coinbase(&template.coinbase_tx));
789 assert_eq!(template.transactions.len(), 1);
790 } else {
791 assert!(result.is_err());
793 }
794 }
795
796 #[test]
797 fn test_mine_block_attempts() {
798 let block = create_test_block();
799 let (mined_block, result) = mine_block(block, 1000).unwrap();
800
801 assert!(matches!(
803 result,
804 MiningResult::Success | MiningResult::Failure
805 ));
806 assert_eq!(mined_block.header.version, 1);
807 }
808
809 #[test]
810 fn test_mine_block_failure() {
811 let block = create_test_block();
812 let (mined_block, result) = mine_block(block, 0).unwrap();
813
814 assert_eq!(result, MiningResult::Failure);
816 assert_eq!(mined_block.header.nonce, 0);
817 }
818
819 #[test]
820 fn test_create_coinbase_transaction() {
821 let height = 100;
822 let subsidy = 5000000000;
823 let script = vec![0x51, 0x52];
824 let address = vec![0x53, 0x54];
825
826 let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
827
828 assert!(is_coinbase(&coinbase_tx));
829 assert_eq!(coinbase_tx.outputs.len(), 1);
830 assert_eq!(coinbase_tx.outputs[0].value, subsidy);
831 assert_eq!(coinbase_tx.outputs[0].script_pubkey, address);
832 assert_eq!(coinbase_tx.inputs[0].script_sig, script);
833 assert_eq!(coinbase_tx.inputs[0].prevout.hash, [0u8; 32]);
834 assert_eq!(coinbase_tx.inputs[0].prevout.index, 0xffffffff);
835 }
836
837 #[test]
838 fn test_calculate_tx_hash() {
839 let tx = create_valid_transaction();
840 let hash = calculate_tx_hash(&tx);
841
842 assert_eq!(hash.len(), 32);
844
845 let hash2 = calculate_tx_hash(&tx);
847 assert_eq!(hash, hash2);
848 }
849
850 #[test]
851 fn test_calculate_tx_hash_different_txs() {
852 let tx1 = create_valid_transaction();
853 let mut tx2 = tx1.clone();
854 tx2.version = 2; let hash1 = calculate_tx_hash(&tx1);
857 let hash2 = calculate_tx_hash(&tx2);
858
859 assert_ne!(hash1, hash2);
861 }
862
863 #[test]
864 fn test_encode_varint_small() {
865 let encoded = encode_varint(0x42);
866 assert_eq!(encoded, vec![0x42]);
867 }
868
869 #[test]
870 fn test_encode_varint_medium() {
871 let encoded = encode_varint(0x1234);
872 assert_eq!(encoded.len(), 3);
873 assert_eq!(encoded[0], 0xfd);
874 }
875
876 #[test]
877 fn test_encode_varint_large() {
878 let encoded = encode_varint(0x12345678);
879 assert_eq!(encoded.len(), 5);
880 assert_eq!(encoded[0], 0xfe);
881 }
882
883 #[test]
884 fn test_encode_varint_huge() {
885 let encoded = encode_varint(0x123456789abcdef0);
886 assert_eq!(encoded.len(), 9);
887 assert_eq!(encoded[0], 0xff);
888 }
889
890 #[test]
891 fn test_calculate_block_hash() {
892 let header = create_valid_block_header();
893 let hash = calculate_block_hash(&header);
894
895 assert_eq!(hash.len(), 32);
897
898 let hash2 = calculate_block_hash(&header);
900 assert_eq!(hash, hash2);
901 }
902
903 #[test]
904 fn test_calculate_block_hash_different_headers() {
905 let header1 = create_valid_block_header();
906 let mut header2 = header1.clone();
907 header2.version = 2; let hash1 = calculate_block_hash(&header1);
910 let hash2 = calculate_block_hash(&header2);
911
912 assert_ne!(hash1, hash2);
914 }
915
916 #[test]
917 fn test_sha256_hash() {
918 let data = b"hello world";
919 let hash = sha256_hash(data);
920
921 assert_eq!(hash.len(), 32);
923
924 let hash2 = sha256_hash(data);
926 assert_eq!(hash, hash2);
927 }
928
929 #[test]
930 fn test_sha256_hash_different_data() {
931 let data1 = b"hello";
932 let data2 = b"world";
933
934 let hash1 = sha256_hash(data1);
935 let hash2 = sha256_hash(data2);
936
937 assert_ne!(hash1, hash2);
939 }
940
941 #[test]
942 fn test_expand_target_small() {
943 let bits = 0x0300ffff; let target = expand_target(bits).unwrap();
945 assert!(target > 0);
946 }
947
948 #[test]
949 fn test_expand_target_medium() {
950 let bits = 0x0600ffff; let target = expand_target(bits).unwrap();
952 assert!(target > 0);
953 }
954
955 #[test]
956 fn test_expand_target_too_large() {
957 let bits = 0x2000ffff; let result = expand_target(bits);
959 assert!(result.is_err());
960 }
961
962 #[test]
963 fn test_get_current_timestamp() {
964 let timestamp = get_current_timestamp();
965 assert_eq!(timestamp, 1231006505);
966 }
967
968 #[test]
969 fn test_merkle_root_single_transaction() {
970 let txs = vec![create_valid_transaction()];
971 let merkle_root = calculate_merkle_root(&txs).unwrap();
972
973 assert_eq!(merkle_root.len(), 32);
975 assert_ne!(merkle_root, [0u8; 32]);
976 }
977
978 #[test]
979 fn test_merkle_root_three_transactions() {
980 let txs = vec![
981 create_valid_transaction(),
982 create_valid_transaction(),
983 create_valid_transaction(),
984 ];
985 let merkle_root = calculate_merkle_root(&txs).unwrap();
986
987 assert_eq!(merkle_root.len(), 32);
989 assert_ne!(merkle_root, [0u8; 32]);
990 }
991
992 #[test]
993 fn test_merkle_root_five_transactions() {
994 let txs = vec![
995 create_valid_transaction(),
996 create_valid_transaction(),
997 create_valid_transaction(),
998 create_valid_transaction(),
999 create_valid_transaction(),
1000 ];
1001 let merkle_root = calculate_merkle_root(&txs).unwrap();
1002
1003 assert_eq!(merkle_root.len(), 32);
1005 assert_ne!(merkle_root, [0u8; 32]);
1006 }
1007
1008 #[test]
1009 fn test_block_template_fields() {
1010 let mut utxo_set = UtxoSet::default();
1011 let outpoint = OutPoint {
1013 hash: [1; 32],
1014 index: 0,
1015 };
1016 let utxo = UTXO {
1017 value: 10000,
1018 script_pubkey: vec![].into(),
1020 height: 0,
1021 is_coinbase: false,
1022 };
1023 utxo_set.insert(outpoint, std::sync::Arc::new(utxo));
1024
1025 let mempool_txs = vec![create_valid_transaction()];
1026 let height = 100;
1027 let prev_header = create_valid_block_header();
1028 let prev_headers = vec![prev_header.clone(), prev_header.clone()];
1029 let coinbase_script = vec![OP_1];
1030 let coinbase_address = vec![OP_2];
1031
1032 let result = create_block_template(
1033 &utxo_set,
1034 &mempool_txs,
1035 height,
1036 &prev_header,
1037 &prev_headers,
1038 &coinbase_script,
1039 &coinbase_address,
1040 );
1041
1042 if let Ok(template) = result {
1045 assert_eq!(template.height, height);
1047 assert!(template.target > 0);
1048 assert!(template.timestamp > 0);
1049 assert!(is_coinbase(&template.coinbase_tx));
1050 assert_eq!(template.transactions.len(), 1);
1051 assert_eq!(template.header.version, 1);
1052 } else {
1053 assert!(result.is_err());
1055 }
1056 }
1057
1058 fn create_valid_transaction() -> Transaction {
1060 use std::cell::Cell;
1062 thread_local! {
1063 static COUNTER: Cell<u64> = Cell::new(0);
1064 }
1065 let counter = COUNTER.with(|c| {
1066 let val = c.get();
1067 c.set(val + 1);
1068 val
1069 });
1070
1071 Transaction {
1072 version: 1,
1073 inputs: vec![TransactionInput {
1074 prevout: OutPoint {
1075 hash: [1; 32].into(), index: 0,
1077 },
1078 script_sig: {
1085 let mut sig = vec![OP_1]; if counter > 0 {
1088 sig.push(PUSH_1_BYTE); sig.push((counter & 0xff) as u8); }
1091 sig
1092 },
1093 sequence: 0xffffffff,
1094 }]
1095 .into(),
1096 outputs: vec![TransactionOutput {
1097 value: 1000 + counter as i64, script_pubkey: vec![].into(),
1100 }]
1101 .into(),
1102 lock_time: 0,
1103 }
1104 }
1105
1106 fn create_valid_block_header() -> BlockHeader {
1107 BlockHeader {
1108 version: 1,
1109 prev_block_hash: [0; 32],
1110 merkle_root: [0; 32],
1111 timestamp: 1231006505,
1112 bits: 0x0600ffff, nonce: 0,
1114 }
1115 }
1116
1117 fn create_test_block() -> Block {
1118 Block {
1119 header: create_valid_block_header(),
1120 transactions: vec![create_valid_transaction()].into_boxed_slice(),
1121 }
1122 }
1123
1124 #[test]
1125 fn test_create_coinbase_transaction_zero_subsidy() {
1126 let height = 100;
1127 let subsidy = 0; let script = vec![OP_1];
1129 let address = vec![OP_1];
1130
1131 let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
1132
1133 assert!(is_coinbase(&coinbase_tx));
1134 assert_eq!(coinbase_tx.outputs[0].value, 0);
1135 }
1136
1137 #[test]
1138 fn test_create_coinbase_transaction_large_subsidy() {
1139 let height = 100;
1140 let subsidy = 2100000000000000; let script = vec![OP_1];
1142 let address = vec![OP_1];
1143
1144 let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
1145
1146 assert!(is_coinbase(&coinbase_tx));
1147 assert_eq!(coinbase_tx.outputs[0].value, subsidy);
1148 }
1149
1150 #[test]
1151 fn test_create_coinbase_transaction_empty_script() {
1152 let height = 100;
1153 let subsidy = 5000000000;
1154 let script = vec![]; let address = vec![OP_1];
1156
1157 let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
1158
1159 assert!(is_coinbase(&coinbase_tx));
1160 assert_eq!(coinbase_tx.outputs[0].value, subsidy);
1161 }
1162
1163 #[test]
1164 fn test_create_coinbase_transaction_empty_address() {
1165 let height = 100;
1166 let subsidy = 5000000000;
1167 let script = vec![OP_1];
1168 let address = vec![]; let coinbase_tx = create_coinbase_transaction(height, subsidy, &script, &address).unwrap();
1171
1172 assert!(is_coinbase(&coinbase_tx));
1173 assert_eq!(coinbase_tx.outputs[0].value, subsidy);
1174 }
1175
1176 #[test]
1177 fn test_calculate_merkle_root_single_transaction() {
1178 let txs = vec![create_valid_transaction()];
1179 let merkle_root = calculate_merkle_root(&txs).unwrap();
1180
1181 assert_eq!(merkle_root.len(), 32);
1182 assert_ne!(merkle_root, [0u8; 32]);
1183 }
1184
1185 #[test]
1186 fn test_calculate_merkle_root_three_transactions() {
1187 let txs = vec![
1188 create_valid_transaction(),
1189 create_valid_transaction(),
1190 create_valid_transaction(),
1191 ];
1192
1193 let merkle_root = calculate_merkle_root(&txs).unwrap();
1194 assert_eq!(merkle_root.len(), 32);
1195 assert_ne!(merkle_root, [0u8; 32]);
1196 }
1197
1198 #[test]
1199 fn test_calculate_merkle_root_five_transactions() {
1200 let txs = vec![
1201 create_valid_transaction(),
1202 create_valid_transaction(),
1203 create_valid_transaction(),
1204 create_valid_transaction(),
1205 create_valid_transaction(),
1206 ];
1207
1208 let merkle_root = calculate_merkle_root(&txs).unwrap();
1209 assert_eq!(merkle_root.len(), 32);
1210 assert_ne!(merkle_root, [0u8; 32]);
1211 }
1212
1213 #[test]
1214 fn test_calculate_tx_hash_different_transactions() {
1215 let tx1 = create_valid_transaction();
1216 let mut tx2 = create_valid_transaction();
1217 tx2.version = 2; let hash1 = calculate_tx_hash(&tx1);
1220 let hash2 = calculate_tx_hash(&tx2);
1221
1222 assert_ne!(hash1, hash2);
1223 }
1224
1225 #[test]
1226 fn test_sha256_hash_empty_data() {
1227 let data = vec![];
1228 let hash = sha256_hash(&data);
1229
1230 assert_eq!(hash.len(), 32);
1231 }
1232
1233 #[test]
1241 fn test_merkle_tree_uses_double_sha256_not_single() {
1242 let hash_a = [0x01u8; 32];
1244 let hash_b = [0x02u8; 32];
1245
1246 let mut combined = [0u8; 64];
1248 combined[..32].copy_from_slice(&hash_a);
1249 combined[32..].copy_from_slice(&hash_b);
1250
1251 let expected_double = double_sha256_hash(&combined);
1252 let wrong_single = sha256_hash(&combined);
1253
1254 assert_ne!(
1256 expected_double, wrong_single,
1257 "Double SHA256 and single SHA256 must produce different results"
1258 );
1259
1260 let root = calculate_merkle_root_from_tx_ids(&[hash_a, hash_b]).unwrap();
1262 assert_eq!(
1263 root, expected_double,
1264 "Merkle root must use double SHA256, not single SHA256"
1265 );
1266 assert_ne!(
1267 root, wrong_single,
1268 "Merkle root must NOT match single SHA256 result"
1269 );
1270 }
1271
1272 #[test]
1273 fn test_merkle_root_single_tx_equals_txid() {
1274 let tx = create_valid_transaction();
1276 let txid = calculate_tx_hash(&tx);
1277
1278 let root_from_txs = calculate_merkle_root(&[tx]).unwrap();
1279 let root_from_ids = calculate_merkle_root_from_tx_ids(&[txid]).unwrap();
1280
1281 assert_eq!(root_from_txs, txid, "Single tx merkle root must equal txid");
1282 assert_eq!(
1283 root_from_ids, txid,
1284 "Single txid merkle root must equal txid"
1285 );
1286 }
1287
1288 #[test]
1289 fn test_calculate_merkle_root_from_tx_ids_matches_calculate_merkle_root() {
1290 let tx1 = create_valid_transaction();
1292 let tx2 = create_valid_transaction();
1293 let tx3 = create_valid_transaction();
1294
1295 let txid1 = calculate_tx_hash(&tx1);
1296 let txid2 = calculate_tx_hash(&tx2);
1297 let txid3 = calculate_tx_hash(&tx3);
1298
1299 let root_from_txs = calculate_merkle_root(&[tx1, tx2, tx3]).unwrap();
1300 let root_from_ids = calculate_merkle_root_from_tx_ids(&[txid1, txid2, txid3]).unwrap();
1301
1302 assert_eq!(
1303 root_from_txs, root_from_ids,
1304 "calculate_merkle_root and calculate_merkle_root_from_tx_ids must produce identical results"
1305 );
1306 }
1307
1308 #[test]
1309 fn test_calculate_merkle_root_from_tx_ids_two_txs() {
1310 let tx1 = create_valid_transaction();
1311 let tx2 = create_valid_transaction();
1312
1313 let txid1 = calculate_tx_hash(&tx1);
1314 let txid2 = calculate_tx_hash(&tx2);
1315
1316 let root_from_txs = calculate_merkle_root(&[tx1, tx2]).unwrap();
1317 let root_from_ids = calculate_merkle_root_from_tx_ids(&[txid1, txid2]).unwrap();
1318
1319 assert_eq!(root_from_txs, root_from_ids);
1320 }
1321
1322 #[test]
1323 fn test_calculate_merkle_root_from_tx_ids_four_txs() {
1324 let tx1 = create_valid_transaction();
1325 let tx2 = create_valid_transaction();
1326 let tx3 = create_valid_transaction();
1327 let tx4 = create_valid_transaction();
1328
1329 let txid1 = calculate_tx_hash(&tx1);
1330 let txid2 = calculate_tx_hash(&tx2);
1331 let txid3 = calculate_tx_hash(&tx3);
1332 let txid4 = calculate_tx_hash(&tx4);
1333
1334 let root_from_txs = calculate_merkle_root(&[tx1, tx2, tx3, tx4]).unwrap();
1335 let root_from_ids =
1336 calculate_merkle_root_from_tx_ids(&[txid1, txid2, txid3, txid4]).unwrap();
1337
1338 assert_eq!(root_from_txs, root_from_ids);
1339 }
1340
1341 #[test]
1342 fn test_calculate_merkle_root_from_tx_ids_empty() {
1343 let result = calculate_merkle_root_from_tx_ids(&[]);
1344 assert!(result.is_err(), "Empty tx_ids list should fail");
1345 }
1346
1347 #[test]
1348 fn test_merkle_root_deterministic() {
1349 let tx1 = create_valid_transaction();
1351 let tx2 = create_valid_transaction();
1352
1353 let txid1 = calculate_tx_hash(&tx1);
1354 let txid2 = calculate_tx_hash(&tx2);
1355
1356 let root1 = calculate_merkle_root_from_tx_ids(&[txid1, txid2]).unwrap();
1357 let root2 = calculate_merkle_root_from_tx_ids(&[txid1, txid2]).unwrap();
1358
1359 assert_eq!(root1, root2, "Merkle root must be deterministic");
1360 }
1361
1362 #[test]
1363 fn test_merkle_root_order_matters() {
1364 let txid1 = [0x01u8; 32];
1366 let txid2 = [0x02u8; 32];
1367
1368 let root_ab = calculate_merkle_root_from_tx_ids(&[txid1, txid2]).unwrap();
1369 let root_ba = calculate_merkle_root_from_tx_ids(&[txid2, txid1]).unwrap();
1370
1371 assert_ne!(root_ab, root_ba, "Tx order must affect merkle root");
1372 }
1373
1374 #[test]
1375 fn test_double_sha256_hash_known_value() {
1376 let result = double_sha256_hash(&[]);
1380 assert_eq!(result.len(), 32);
1382 let result2 = double_sha256_hash(&[]);
1383 assert_eq!(result, result2);
1384
1385 let single = sha256_hash(&[]);
1387 assert_ne!(
1388 result, single,
1389 "double SHA256 must differ from single SHA256"
1390 );
1391 }
1392}