1use crate::error::Result;
11use crate::opcodes::*;
12use crate::types::*;
13use crate::types::{ByteString, Hash, Natural};
14use crate::witness;
15use bitcoin_hashes::{sha256d, Hash as BitcoinHash, HashEngine};
16use blvm_spec_lock::spec_locked;
17
18pub use crate::witness::Witness;
22
23#[spec_locked("11.1.1")]
26pub fn calculate_transaction_weight(
27 tx: &Transaction,
28 witness: Option<&Witness>,
29) -> Result<Natural> {
30 let base_size = calculate_base_size(tx);
32
33 let total_size = calculate_total_size(tx, witness);
35
36 Ok(witness::calculate_transaction_weight_segwit(
38 base_size, total_size,
39 ))
40}
41
42#[spec_locked("11.1.1")]
48fn calculate_base_size(tx: &Transaction) -> Natural {
49 const VERSION_AND_LOCKTIME: usize = 4 + 4;
50 const PER_INPUT: usize = 32 + 4 + 1 + 4;
51 const PER_OUTPUT: usize = 8 + 1;
52 let n_in = tx.inputs.len();
53 let n_out = tx.outputs.len();
54 let inputs_part = n_in.saturating_mul(PER_INPUT);
55 let outputs_part = n_out.saturating_mul(PER_OUTPUT);
56 (VERSION_AND_LOCKTIME + inputs_part + outputs_part) as Natural
57}
58
59#[spec_locked("11.1.1")]
61fn calculate_total_size(tx: &Transaction, witness: Option<&Witness>) -> Natural {
62 let base_size = calculate_base_size(tx);
63
64 if let Some(witness_data) = witness {
65 let witness_size: Natural = witness_data.iter().map(|w| w.len() as Natural).sum();
66 base_size + witness_size
67 } else {
68 base_size
69 }
70}
71
72#[spec_locked("11.1.4")]
75pub fn compute_witness_merkle_root(block: &Block, witnesses: &[Witness]) -> Result<Hash> {
76 if block.transactions.is_empty() {
77 return Err(crate::error::ConsensusError::ConsensusRuleViolation(
78 "Cannot compute witness merkle root for empty block".into(),
79 ));
80 }
81
82 let mut witness_hashes = Vec::new();
84 for (i, witness) in witnesses.iter().enumerate() {
85 if i == 0 {
86 witness_hashes.push([0u8; 32]);
88 } else {
89 let witness_hash = hash_witness(witness);
90 witness_hashes.push(witness_hash);
91 }
92 }
93
94 compute_merkle_root(&witness_hashes)
96}
97
98fn sha256d_bytes(data: &[u8]) -> Hash {
100 let result = sha256d::Hash::hash(data);
101 let mut hash = [0u8; 32];
102 hash.copy_from_slice(&result[..]);
103 hash
104}
105
106#[spec_locked("11.1")]
109fn hash_witness(witness: &Witness) -> Hash {
110 let mut hasher = sha256d::Hash::engine();
111 for element in witness {
112 hasher.input(element);
113 }
114 let result = sha256d::Hash::from_engine(hasher);
115 let mut hash = [0u8; 32];
116 hash.copy_from_slice(&result);
117 hash
118}
119
120#[spec_locked("11.1.4")]
124fn hash_witness_from_nested(tx_witnesses: &[Witness]) -> Hash {
125 let mut hasher = sha256d::Hash::engine();
126 for witness_stack in tx_witnesses {
127 for element in witness_stack {
128 hasher.input(element);
129 }
130 }
131 let result = sha256d::Hash::from_engine(hasher);
132 let mut hash = [0u8; 32];
133 hash.copy_from_slice(&result);
134 hash
135}
136
137#[spec_locked("11.1.4")]
152pub fn compute_witness_merkle_root_from_nested(
153 block: &Block,
154 witnesses: &[Vec<Witness>],
155) -> Result<Hash> {
156 if block.transactions.is_empty() {
157 return Err(crate::error::ConsensusError::ConsensusRuleViolation(
158 "Cannot compute witness merkle root from empty block".into(),
159 ));
160 }
161 let mut witness_hashes = Vec::with_capacity(block.transactions.len());
162 for (i, (tx, tx_witnesses)) in block.transactions.iter().zip(witnesses.iter()).enumerate() {
163 if i == 0 {
164 witness_hashes.push([0u8; 32]);
166 } else {
167 let has_witness = tx_witnesses.iter().any(|w| !w.is_empty());
169 let hash = if has_witness {
170 let serialized =
172 crate::serialization::transaction::serialize_transaction_with_witness(
173 tx,
174 tx_witnesses,
175 );
176 sha256d_bytes(&serialized)
177 } else {
178 let serialized = crate::serialization::transaction::serialize_transaction(tx);
180 sha256d_bytes(&serialized)
181 };
182 witness_hashes.push(hash);
183 }
184 }
185 let root = compute_merkle_root(&witness_hashes);
186 #[cfg(feature = "profile")]
187 if std::env::var("BLVM_WITNESS_DEBUG").is_ok() {
188 if let Ok(r) = &root {
189 eprintln!(
190 "BLVM_WITNESS_DEBUG: {} txs, root={}",
191 witness_hashes.len(),
192 hex::encode(r)
193 );
194 }
195 }
196 root
197}
198
199fn compute_merkle_root(hashes: &[Hash]) -> Result<Hash> {
202 crate::mining::calculate_merkle_root_from_tx_ids(hashes)
203}
204
205#[spec_locked("11.1.5")]
216pub fn validate_witness_commitment(
217 coinbase_tx: &Transaction,
218 witness_merkle_root: &Hash,
219 coinbase_witnesses: &[Witness],
220) -> Result<bool> {
221 let reserved_nonce: [u8; 32] = coinbase_witnesses
224 .first()
225 .and_then(|w| w.first())
226 .and_then(|item| item.as_slice().try_into().ok())
227 .unwrap_or([0u8; 32]);
228
229 let mut preimage = [0u8; 64];
231 preimage[..32].copy_from_slice(witness_merkle_root);
232 preimage[32..].copy_from_slice(&reserved_nonce);
233 let expected_commitment = sha256d_bytes(&preimage);
234
235 let mut last_commitment: Option<Hash> = None;
240 for output in &coinbase_tx.outputs {
241 if let Some(commitment) = extract_witness_commitment(&output.script_pubkey) {
242 last_commitment = Some(commitment);
243 }
244 }
245
246 match last_commitment {
247 Some(commitment) => {
248 let ok = commitment == expected_commitment;
249 #[cfg(feature = "profile")]
250 if !ok && std::env::var("BLVM_WITNESS_COMMIT_DEBUG").is_ok() {
251 eprintln!(
252 "BLVM_WITNESS_COMMIT_DEBUG: root={} nonce={} expected={} got={}",
253 hex::encode(witness_merkle_root),
254 hex::encode(reserved_nonce),
255 hex::encode(expected_commitment),
256 hex::encode(commitment),
257 );
258 }
259 Ok(ok)
260 }
261 None => Ok(true),
263 }
264}
265
266#[spec_locked("11.1.5")]
275pub(crate) fn extract_witness_commitment(script: &ByteString) -> Option<Hash> {
276 const MAGIC: [u8; 4] = [0xaa, 0x21, 0xa9, 0xed];
277 if script.len() >= 38 && script[0] == OP_RETURN && script[1] == 0x24 && script[2..6] == MAGIC {
278 let mut commitment = [0u8; 32];
279 commitment.copy_from_slice(&script[6..38]);
280 return Some(commitment);
281 }
282 None
283}
284
285#[spec_locked("11.1.6")]
287pub fn is_segwit_transaction(tx: &Transaction) -> bool {
288 use crate::witness::{
289 extract_witness_program, extract_witness_version, validate_witness_program_length,
290 };
291
292 tx.outputs.iter().any(|output| {
293 let script = &output.script_pubkey;
294 if let Some(version) = extract_witness_version(script) {
295 if let Some(program) = extract_witness_program(script, version) {
296 return validate_witness_program_length(&program, version);
297 }
298 }
299 false
300 })
301}
302
303#[spec_locked("11.1.1")]
305pub fn calculate_block_weight(block: &Block, witnesses: &[Witness]) -> Result<Natural> {
306 let mut total_weight = 0;
307
308 for (i, tx) in block.transactions.iter().enumerate() {
309 let witness = if i < witnesses.len() {
310 Some(&witnesses[i])
311 } else {
312 None
313 };
314
315 total_weight += calculate_transaction_weight(tx, witness)?;
316 }
317
318 Ok(total_weight)
319}
320
321#[spec_locked("11.1.1")]
326#[inline]
327pub fn calculate_block_weight_from_nested(
328 block: &Block,
329 witnesses: &[Vec<Witness>],
330) -> Result<Natural> {
331 let mut total_weight = 0;
332 for (i, tx) in block.transactions.iter().enumerate() {
333 let witness_size: Natural = if i < witnesses.len() {
334 witnesses[i]
335 .iter()
336 .flat_map(|w| w.iter())
337 .map(|e| e.len() as Natural)
338 .sum()
339 } else {
340 0
341 };
342 let base_size =
343 (4 + tx.inputs.len() * (32 + 4 + 1 + 4) + tx.outputs.len() * (8 + 1) + 4) as Natural;
344 total_weight +=
345 witness::calculate_transaction_weight_segwit(base_size, base_size + witness_size);
346 }
347 Ok(total_weight)
348}
349
350#[spec_locked("11.1.7")]
352pub fn validate_segwit_block(
353 block: &Block,
354 witnesses: &[Witness],
355 max_block_weight: Natural,
356) -> Result<bool> {
357 for (i, _tx) in block.transactions.iter().enumerate() {
359 if i < witnesses.len() && !witness::validate_segwit_witness_structure(&witnesses[i])? {
360 return Ok(false);
361 }
362 }
363
364 let block_weight = calculate_block_weight(block, witnesses)?;
366 if block_weight > max_block_weight {
367 return Ok(false);
368 }
369
370 if !block.transactions.is_empty() && !witnesses.is_empty() {
372 let witness_root = compute_witness_merkle_root(block, witnesses)?;
373 if !validate_witness_commitment(
375 &block.transactions[0],
376 &witness_root,
377 std::slice::from_ref(&witnesses[0]),
378 )? {
379 return Ok(false);
380 }
381 }
382
383 Ok(true)
384}
385
386#[cfg(test)]
387mod tests {
388 use super::*;
389 use crate::test_utils::create_test_header;
390
391 #[test]
392 fn test_calculate_transaction_weight() {
393 let tx = create_test_transaction();
394 let witness = vec![vec![OP_1], vec![OP_2]]; let weight = calculate_transaction_weight(&tx, Some(&witness)).unwrap();
397 assert!(weight > 0);
398 }
399
400 #[test]
401 fn test_calculate_transaction_weight_no_witness() {
402 let tx = create_test_transaction();
403
404 let weight = calculate_transaction_weight(&tx, None).unwrap();
405 assert!(weight > 0);
406 }
407
408 #[test]
409 fn test_compute_witness_merkle_root() {
410 let block = create_test_block();
411 let witnesses = vec![
412 vec![], vec![vec![OP_1]], ];
415
416 let root = compute_witness_merkle_root(&block, &witnesses).unwrap();
417 assert_eq!(root.len(), 32);
418 }
419
420 #[test]
421 fn test_compute_witness_merkle_root_empty_block() {
422 let block = Block {
423 header: create_test_header(1231006505, [0u8; 32]),
424 transactions: vec![].into_boxed_slice(),
425 };
426 let witnesses = vec![];
427
428 let result = compute_witness_merkle_root(&block, &witnesses);
429 assert!(result.is_err());
430 }
431
432 #[test]
433 fn test_validate_witness_commitment() {
434 let mut coinbase_tx = create_test_transaction();
435 let witness_root = [1u8; 32];
436 let nonce = [0u8; 32]; coinbase_tx.outputs[0].script_pubkey =
440 create_witness_commitment_script(&witness_root, &nonce);
441
442 let is_valid = validate_witness_commitment(&coinbase_tx, &witness_root, &[]).unwrap();
444 assert!(is_valid);
445 }
446
447 #[test]
448 fn test_is_segwit_transaction() {
449 let mut tx = create_test_transaction();
454 let p2wpkh_hash = [0x51; 20]; let mut script_pubkey = vec![OP_0, PUSH_20_BYTES]; script_pubkey.extend_from_slice(&p2wpkh_hash);
458 tx.outputs[0].script_pubkey = script_pubkey.into();
459
460 assert!(is_segwit_transaction(&tx));
461 }
462
463 #[test]
464 fn test_calculate_block_weight() {
465 let block = create_test_block();
466 let witnesses = vec![
467 vec![], vec![vec![OP_1]], ];
470
471 let weight = calculate_block_weight(&block, &witnesses).unwrap();
472 assert!(weight > 0);
473 }
474
475 #[test]
476 fn test_validate_segwit_block() {
477 let block = create_test_block();
478 let witnesses = vec![
479 vec![], vec![vec![OP_1]], ];
482
483 let is_valid = validate_segwit_block(&block, &witnesses, 4_000_000).unwrap();
484 assert!(is_valid);
485 }
486
487 #[test]
488 fn test_validate_segwit_block_exceeds_weight() {
489 let block = create_test_block();
490 let witnesses = vec![
491 vec![], vec![vec![OP_1]], ];
494
495 let is_valid = validate_segwit_block(&block, &witnesses, 1).unwrap(); assert!(!is_valid);
497 }
498
499 #[test]
500 fn test_validate_segwit_block_invalid_commitment() {
501 let mut block = create_test_block();
502 let witnesses = vec![
503 vec![], vec![vec![OP_1]], ];
506
507 let wrong_root = [2u8; 32];
509 block.transactions[0].outputs[0].script_pubkey =
510 create_witness_commitment_script(&wrong_root, &[0u8; 32]);
511
512 let is_valid = validate_segwit_block(&block, &witnesses, 4_000_000).unwrap();
513 assert!(!is_valid);
514 }
515
516 #[test]
517 fn test_validate_witness_commitment_no_commitment() {
518 let coinbase_tx = create_test_transaction();
519 let witness_root = [1u8; 32];
520
521 let is_valid = validate_witness_commitment(&coinbase_tx, &witness_root, &[]).unwrap();
523 assert!(is_valid); }
525
526 #[test]
527 fn test_validate_witness_commitment_invalid_commitment() {
528 let mut coinbase_tx = create_test_transaction();
529 let witness_root = [1u8; 32];
530 let invalid_root = [2u8; 32]; coinbase_tx.outputs[0].script_pubkey =
534 create_witness_commitment_script(&invalid_root, &[0u8; 32]);
535
536 let is_valid = validate_witness_commitment(&coinbase_tx, &witness_root, &[]).unwrap();
537 assert!(!is_valid);
538 }
539
540 #[test]
541 fn test_extract_witness_commitment_valid() {
542 let witness_root = [1u8; 32];
543 let nonce = [0u8; 32];
544 let script = create_witness_commitment_script(&witness_root, &nonce);
545
546 let mut preimage = [0u8; 64];
548 preimage[..32].copy_from_slice(&witness_root);
549 preimage[32..].copy_from_slice(&nonce);
550 let expected = sha256d_bytes(&preimage);
551
552 let extracted = extract_witness_commitment(&script).unwrap();
553 assert_eq!(extracted, expected);
554 }
555
556 #[test]
557 fn test_extract_witness_commitment_invalid_script() {
558 let script = vec![OP_1]; let extracted = extract_witness_commitment(&script);
561 assert!(extracted.is_none());
562 }
563
564 #[test]
565 fn test_extract_witness_commitment_wrong_opcode() {
566 let mut script = vec![0x52, PUSH_36_BYTES]; script.extend_from_slice(&[1u8; 32]);
568
569 let extracted = extract_witness_commitment(&script);
570 assert!(extracted.is_none());
571 }
572
573 #[test]
574 fn test_extract_witness_commitment_wrong_length() {
575 let mut script = vec![OP_RETURN, 0x25]; script.extend_from_slice(&[1u8; 32]);
577
578 let extracted = extract_witness_commitment(&script);
579 assert!(extracted.is_none());
580 }
581
582 #[test]
583 fn test_hash_witness() {
584 let witness = vec![vec![OP_1], vec![OP_2]];
585 let hash = hash_witness(&witness);
586
587 assert_eq!(hash.len(), 32);
588
589 let witness2 = vec![vec![OP_3], vec![OP_4]];
591 let hash2 = hash_witness(&witness2);
592 assert_ne!(hash, hash2);
593 }
594
595 #[test]
596 fn test_hash_witness_empty() {
597 let witness = vec![];
598 let hash = hash_witness(&witness);
599
600 assert_eq!(hash.len(), 32);
601 }
602
603 #[test]
604 fn test_compute_merkle_root_single_hash() {
605 let hashes = vec![[1u8; 32]];
606 let root = compute_merkle_root(&hashes).unwrap();
607
608 assert_eq!(root, [1u8; 32]);
609 }
610
611 #[test]
612 fn test_compute_merkle_root_empty() {
613 let hashes = vec![];
614 let result = compute_merkle_root(&hashes);
615
616 assert!(result.is_err());
617 }
618
619 #[test]
620 fn test_is_segwit_transaction_false() {
621 let tx = create_test_transaction();
622 assert!(!is_segwit_transaction(&tx));
625 }
626
627 #[test]
628 fn test_calculate_base_size() {
629 let tx = create_test_transaction();
630 let base_size = calculate_base_size(&tx);
631
632 assert!(base_size > 0);
633 }
634
635 #[test]
636 fn test_calculate_total_size_with_witness() {
637 let tx = create_test_transaction();
638 let witness = vec![vec![OP_1], vec![OP_2]];
639
640 let total_size = calculate_total_size(&tx, Some(&witness));
641 let base_size = calculate_base_size(&tx);
642
643 assert!(total_size > base_size);
644 }
645
646 #[test]
647 fn test_calculate_total_size_without_witness() {
648 let tx = create_test_transaction();
649
650 let total_size = calculate_total_size(&tx, None);
651 let base_size = calculate_base_size(&tx);
652
653 assert_eq!(total_size, base_size);
654 }
655
656 fn create_test_transaction() -> Transaction {
658 Transaction {
659 version: 1,
660 inputs: vec![TransactionInput {
661 prevout: OutPoint {
662 hash: [0; 32].into(),
663 index: 0,
664 },
665 script_sig: vec![OP_1],
666 sequence: 0xffffffff,
667 }]
668 .into(),
669 outputs: vec![TransactionOutput {
670 value: 1000,
671 script_pubkey: vec![OP_1].into(),
672 }]
673 .into(),
674 lock_time: 0,
675 }
676 }
677
678 fn create_test_block() -> Block {
679 Block {
680 header: create_test_header(1231006505, [0u8; 32]),
681 transactions: vec![
682 create_test_transaction(), create_test_transaction(), ]
685 .into_boxed_slice(),
686 }
687 }
688
689 fn create_witness_commitment_script(witness_root: &Hash, nonce: &[u8; 32]) -> ByteString {
690 let mut preimage = [0u8; 64];
692 preimage[..32].copy_from_slice(witness_root);
693 preimage[32..].copy_from_slice(nonce);
694 let commitment = sha256d_bytes(&preimage);
695 let mut script = vec![OP_RETURN, PUSH_36_BYTES]; script.extend_from_slice(&[0xaa, 0x21, 0xa9, 0xed]); script.extend_from_slice(&commitment);
698 script.into()
699 }
700}
701
702#[cfg(test)]
703mod property_tests {
704 use super::*;
705 use proptest::prelude::*;
706
707 proptest! {
712 #[test]
713 fn prop_transaction_weight_non_negative(
714 tx in create_transaction_strategy(),
715 witness in prop::option::of(create_witness_strategy())
716 ) {
717 let _weight = calculate_transaction_weight(&tx, witness.as_ref()).unwrap();
718 }
720 }
721
722 proptest! {
728 #[test]
729 fn prop_transaction_weight_formula(
730 tx in create_transaction_strategy(),
731 witness in prop::option::of(create_witness_strategy())
732 ) {
733 let weight = calculate_transaction_weight(&tx, witness.as_ref()).unwrap();
734 let base_size = calculate_base_size(&tx);
735 let total_size = calculate_total_size(&tx, witness.as_ref());
736 let expected_weight = 3 * base_size + total_size;
737
738 assert_eq!(weight, expected_weight);
739 }
740 }
741
742 proptest! {
748 #[test]
749 fn prop_block_weight_validation_limit(
750 block in create_block_strategy(),
751 witnesses in create_witnesses_strategy(),
752 max_weight in 1..10_000_000u64
753 ) {
754 match (calculate_block_weight(&block, &witnesses), validate_segwit_block(&block, &witnesses, max_weight as Natural)) {
756 (Ok(actual_weight), Ok(is_valid)) => {
757 if actual_weight > max_weight as Natural {
759 prop_assert!(!is_valid, "Block exceeding weight limit must be invalid");
760 }
761 },
762 (Err(_), _) | (_, Err(_)) => {
763 }
765 }
766 }
767 }
768
769 proptest! {
775 #[test]
776 fn prop_witness_commitment_deterministic(
777 coinbase_tx in create_transaction_strategy(),
778 witness_root in create_hash_strategy()
779 ) {
780 let result1 = validate_witness_commitment(&coinbase_tx, &witness_root, &[]).unwrap();
781 let result2 = validate_witness_commitment(&coinbase_tx, &witness_root, &[]).unwrap();
782
783 assert_eq!(result1, result2);
784 }
785 }
786
787 proptest! {
793 #[test]
794 fn prop_witness_merkle_root_deterministic(
795 block in create_block_strategy(),
796 witnesses in create_witnesses_strategy()
797 ) {
798 if !block.transactions.is_empty() {
799 let result1 = compute_witness_merkle_root(&block, &witnesses);
800 let result2 = compute_witness_merkle_root(&block, &witnesses);
801
802 assert_eq!(result1.is_ok(), result2.is_ok());
803 if result1.is_ok() && result2.is_ok() {
804 assert_eq!(result1.unwrap(), result2.unwrap());
805 }
806 }
807 }
808 }
809
810 proptest! {
815 #[test]
816 fn prop_segwit_transaction_detection(
817 tx in create_transaction_strategy()
818 ) {
819 let is_segwit = is_segwit_transaction(&tx);
820 let _ = is_segwit;
822 }
823 }
824
825 proptest! {
830 #[test]
831 fn prop_witness_hashing_deterministic(
832 witness in create_witness_strategy()
833 ) {
834 let hash1 = hash_witness(&witness);
835 let hash2 = hash_witness(&witness);
836
837 assert_eq!(hash1, hash2);
838 assert_eq!(hash1.len(), 32);
839 }
840 }
841
842 proptest! {
847 #[test]
848 fn prop_merkle_root_single_hash(
849 hash in create_hash_strategy()
850 ) {
851 let hashes = vec![hash];
852 let root = compute_merkle_root(&hashes).unwrap();
853
854 assert_eq!(root, hash);
855 }
856 }
857
858 #[test]
863 fn prop_merkle_root_empty_input() {
864 let hashes: Vec<Hash> = vec![];
865 let result = compute_merkle_root(&hashes);
866
867 assert!(result.is_err());
868 }
869
870 proptest! {
875 #[test]
876 fn prop_witness_commitment_extraction_deterministic(
877 script in prop::collection::vec(any::<u8>(), 0..100)
878 ) {
879 let result1 = extract_witness_commitment(&script);
880 let result2 = extract_witness_commitment(&script);
881
882 assert_eq!(result1.is_some(), result2.is_some());
883 if result1.is_some() && result2.is_some() {
884 assert_eq!(result1.unwrap(), result2.unwrap());
885 }
886 }
887 }
888
889 proptest! {
894 #[test]
895 fn prop_base_size_monotonic(
896 tx1 in create_transaction_strategy(),
897 tx2 in create_transaction_strategy()
898 ) {
899 let base_size1 = calculate_base_size(&tx1);
900 let base_size2 = calculate_base_size(&tx2);
901
902 assert!(base_size1 > 0);
904 assert!(base_size2 > 0);
905 }
906 }
907
908 proptest! {
913 #[test]
914 fn prop_total_size_with_witness_greater_than_base(
915 tx in create_transaction_strategy(),
916 witness in create_witness_strategy()
917 ) {
918 let base_size = calculate_base_size(&tx);
919 let total_size = calculate_total_size(&tx, Some(&witness));
920
921 assert!(total_size >= base_size);
922 }
923 }
924
925 fn create_transaction_strategy() -> impl Strategy<Value = Transaction> {
927 (
928 prop::collection::vec(any::<u8>(), 0..10), prop::collection::vec(any::<u8>(), 0..10), )
931 .prop_map(|(input_data, output_data)| {
932 let mut inputs = Vec::new();
933 for (i, _) in input_data.iter().enumerate() {
934 inputs.push(TransactionInput {
935 prevout: OutPoint {
936 hash: [0; 32],
937 index: i as u32,
938 },
939 script_sig: vec![OP_1],
940 sequence: 0xffffffff,
941 });
942 }
943
944 let mut outputs = Vec::new();
945 for _ in output_data {
946 outputs.push(TransactionOutput {
947 value: 1000,
948 script_pubkey: vec![OP_1],
949 });
950 }
951
952 Transaction {
953 version: 1,
954 inputs: inputs.into(),
955 outputs: outputs.into(),
956 lock_time: 0,
957 }
958 })
959 }
960
961 fn create_block_strategy() -> impl Strategy<Value = Block> {
962 prop::collection::vec(create_transaction_strategy(), 1..5).prop_map(|transactions| Block {
963 header: BlockHeader {
964 version: 1,
965 prev_block_hash: [0; 32],
966 merkle_root: [0; 32],
967 timestamp: 1231006505,
968 bits: 0x1d00ffff,
969 nonce: 0,
970 },
971 transactions: transactions.into_boxed_slice(),
972 })
973 }
974
975 fn create_witness_strategy() -> impl Strategy<Value = Witness> {
976 prop::collection::vec(prop::collection::vec(any::<u8>(), 0..10), 0..5)
977 }
978
979 fn create_witnesses_strategy() -> impl Strategy<Value = Vec<Witness>> {
980 prop::collection::vec(create_witness_strategy(), 0..5)
981 }
982
983 fn create_hash_strategy() -> impl Strategy<Value = Hash> {
984 prop::collection::vec(any::<u8>(), 32..=32).prop_map(|bytes| {
985 let mut hash = [0u8; 32];
986 hash.copy_from_slice(&bytes);
987 hash
988 })
989 }
990}