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", "CalculateTransactionWeight")]
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
42fn calculate_base_size(tx: &Transaction) -> Natural {
48 const VERSION_AND_LOCKTIME: usize = 4 + 4;
49 const PER_INPUT: usize = 32 + 4 + 1 + 4;
50 const PER_OUTPUT: usize = 8 + 1;
51 let n_in = tx.inputs.len();
52 let n_out = tx.outputs.len();
53 let inputs_part = n_in.saturating_mul(PER_INPUT);
54 let outputs_part = n_out.saturating_mul(PER_OUTPUT);
55 (VERSION_AND_LOCKTIME + inputs_part + outputs_part) as Natural
56}
57
58fn calculate_total_size(tx: &Transaction, witness: Option<&Witness>) -> Natural {
60 let base_size = calculate_base_size(tx);
61
62 if let Some(witness_data) = witness {
63 let witness_size: Natural = witness_data.iter().map(|w| w.len() as Natural).sum();
64 base_size + witness_size
65 } else {
66 base_size
67 }
68}
69
70#[spec_locked("11.1.4", "ComputeWitnessMerkleRoot")]
73pub fn compute_witness_merkle_root(block: &Block, witnesses: &[Witness]) -> Result<Hash> {
74 if block.transactions.is_empty() {
75 return Err(crate::error::ConsensusError::ConsensusRuleViolation(
76 "Cannot compute witness merkle root for empty block".into(),
77 ));
78 }
79
80 let mut witness_hashes = Vec::new();
82 for (i, witness) in witnesses.iter().enumerate() {
83 if i == 0 {
84 witness_hashes.push([0u8; 32]);
86 } else {
87 let witness_hash = hash_witness(witness);
88 witness_hashes.push(witness_hash);
89 }
90 }
91
92 compute_merkle_root(&witness_hashes)
94}
95
96fn sha256d_bytes(data: &[u8]) -> Hash {
98 let result = sha256d::Hash::hash(data);
99 let mut hash = [0u8; 32];
100 hash.copy_from_slice(&result[..]);
101 hash
102}
103
104#[spec_locked("11.1", "HashWitness")]
107fn hash_witness(witness: &Witness) -> Hash {
108 let mut hasher = sha256d::Hash::engine();
109 for element in witness {
110 hasher.input(element);
111 }
112 let result = sha256d::Hash::from_engine(hasher);
113 let mut hash = [0u8; 32];
114 hash.copy_from_slice(&result);
115 hash
116}
117
118fn hash_witness_from_nested(tx_witnesses: &[Witness]) -> Hash {
122 let mut hasher = sha256d::Hash::engine();
123 for witness_stack in tx_witnesses {
124 for element in witness_stack {
125 hasher.input(element);
126 }
127 }
128 let result = sha256d::Hash::from_engine(hasher);
129 let mut hash = [0u8; 32];
130 hash.copy_from_slice(&result);
131 hash
132}
133
134#[spec_locked("11.1.4", "ComputeWitnessMerkleRoot")]
149pub fn compute_witness_merkle_root_from_nested(
150 block: &Block,
151 witnesses: &[Vec<Witness>],
152) -> Result<Hash> {
153 if block.transactions.is_empty() {
154 return Err(crate::error::ConsensusError::ConsensusRuleViolation(
155 "Cannot compute witness merkle root from empty block".into(),
156 ));
157 }
158 let mut witness_hashes = Vec::with_capacity(block.transactions.len());
159 for (i, (tx, tx_witnesses)) in block.transactions.iter().zip(witnesses.iter()).enumerate() {
160 if i == 0 {
161 witness_hashes.push([0u8; 32]);
163 } else {
164 let has_witness = tx_witnesses.iter().any(|w| !w.is_empty());
166 let hash = if has_witness {
167 let serialized =
169 crate::serialization::transaction::serialize_transaction_with_witness(
170 tx,
171 tx_witnesses,
172 );
173 sha256d_bytes(&serialized)
174 } else {
175 let serialized = crate::serialization::transaction::serialize_transaction(tx);
177 sha256d_bytes(&serialized)
178 };
179 witness_hashes.push(hash);
180 }
181 }
182 let root = compute_merkle_root(&witness_hashes);
183 #[cfg(feature = "profile")]
184 if std::env::var("BLVM_WITNESS_DEBUG").is_ok() {
185 if let Ok(r) = &root {
186 eprintln!(
187 "BLVM_WITNESS_DEBUG: {} txs, root={}",
188 witness_hashes.len(),
189 hex::encode(r)
190 );
191 }
192 }
193 root
194}
195
196fn compute_merkle_root(hashes: &[Hash]) -> Result<Hash> {
199 crate::mining::calculate_merkle_root_from_tx_ids(hashes)
200}
201
202#[spec_locked("11.1.5", "ValidateWitnessCommitment")]
213pub fn validate_witness_commitment(
214 coinbase_tx: &Transaction,
215 witness_merkle_root: &Hash,
216 coinbase_witnesses: &[Witness],
217) -> Result<bool> {
218 let reserved_nonce: [u8; 32] = coinbase_witnesses
221 .first()
222 .and_then(|w| w.first())
223 .and_then(|item| item.as_slice().try_into().ok())
224 .unwrap_or([0u8; 32]);
225
226 let mut preimage = [0u8; 64];
228 preimage[..32].copy_from_slice(witness_merkle_root);
229 preimage[32..].copy_from_slice(&reserved_nonce);
230 let expected_commitment = sha256d_bytes(&preimage);
231
232 let mut last_commitment: Option<Hash> = None;
237 for output in &coinbase_tx.outputs {
238 if let Some(commitment) = extract_witness_commitment(&output.script_pubkey) {
239 last_commitment = Some(commitment);
240 }
241 }
242
243 match last_commitment {
244 Some(commitment) => {
245 let ok = commitment == expected_commitment;
246 #[cfg(feature = "profile")]
247 if !ok && std::env::var("BLVM_WITNESS_COMMIT_DEBUG").is_ok() {
248 eprintln!(
249 "BLVM_WITNESS_COMMIT_DEBUG: root={} nonce={} expected={} got={}",
250 hex::encode(witness_merkle_root),
251 hex::encode(reserved_nonce),
252 hex::encode(expected_commitment),
253 hex::encode(commitment),
254 );
255 }
256 Ok(ok)
257 }
258 None => Ok(true),
260 }
261}
262
263pub(crate) fn extract_witness_commitment(script: &ByteString) -> Option<Hash> {
272 const MAGIC: [u8; 4] = [0xaa, 0x21, 0xa9, 0xed];
273 if script.len() >= 38 && script[0] == OP_RETURN && script[1] == 0x24 && script[2..6] == MAGIC {
274 let mut commitment = [0u8; 32];
275 commitment.copy_from_slice(&script[6..38]);
276 return Some(commitment);
277 }
278 None
279}
280
281#[spec_locked("11.1.6", "IsSegWitTransaction")]
283pub fn is_segwit_transaction(tx: &Transaction) -> bool {
284 use crate::witness::{
285 extract_witness_program, extract_witness_version, validate_witness_program_length,
286 };
287
288 tx.outputs.iter().any(|output| {
289 let script = &output.script_pubkey;
290 if let Some(version) = extract_witness_version(script) {
291 if let Some(program) = extract_witness_program(script, version) {
292 return validate_witness_program_length(&program, version);
293 }
294 }
295 false
296 })
297}
298
299#[spec_locked("11.1.1", "CalculateBlockWeight")]
301pub fn calculate_block_weight(block: &Block, witnesses: &[Witness]) -> Result<Natural> {
302 let mut total_weight = 0;
303
304 for (i, tx) in block.transactions.iter().enumerate() {
305 let witness = if i < witnesses.len() {
306 Some(&witnesses[i])
307 } else {
308 None
309 };
310
311 total_weight += calculate_transaction_weight(tx, witness)?;
312 }
313
314 Ok(total_weight)
315}
316
317#[spec_locked("11.1.1", "CalculateBlockWeight")]
322#[inline]
323pub fn calculate_block_weight_from_nested(
324 block: &Block,
325 witnesses: &[Vec<Witness>],
326) -> Result<Natural> {
327 let mut total_weight = 0;
328 for (i, tx) in block.transactions.iter().enumerate() {
329 let witness_size: Natural = if i < witnesses.len() {
330 witnesses[i]
331 .iter()
332 .flat_map(|w| w.iter())
333 .map(|e| e.len() as Natural)
334 .sum()
335 } else {
336 0
337 };
338 let base_size =
339 (4 + tx.inputs.len() * (32 + 4 + 1 + 4) + tx.outputs.len() * (8 + 1) + 4) as Natural;
340 total_weight +=
341 witness::calculate_transaction_weight_segwit(base_size, base_size + witness_size);
342 }
343 Ok(total_weight)
344}
345
346#[spec_locked("11.1.7", "ValidateSegWitBlock")]
348pub fn validate_segwit_block(
349 block: &Block,
350 witnesses: &[Witness],
351 max_block_weight: Natural,
352) -> Result<bool> {
353 for (i, _tx) in block.transactions.iter().enumerate() {
355 if i < witnesses.len() && !witness::validate_segwit_witness_structure(&witnesses[i])? {
356 return Ok(false);
357 }
358 }
359
360 let block_weight = calculate_block_weight(block, witnesses)?;
362 if block_weight > max_block_weight {
363 return Ok(false);
364 }
365
366 if !block.transactions.is_empty() && !witnesses.is_empty() {
368 let witness_root = compute_witness_merkle_root(block, witnesses)?;
369 if !validate_witness_commitment(
371 &block.transactions[0],
372 &witness_root,
373 std::slice::from_ref(&witnesses[0]),
374 )? {
375 return Ok(false);
376 }
377 }
378
379 Ok(true)
380}
381
382#[cfg(test)]
383mod tests {
384 use super::*;
385 use crate::test_utils::create_test_header;
386
387 #[test]
388 fn test_calculate_transaction_weight() {
389 let tx = create_test_transaction();
390 let witness = vec![vec![OP_1], vec![OP_2]]; let weight = calculate_transaction_weight(&tx, Some(&witness)).unwrap();
393 assert!(weight > 0);
394 }
395
396 #[test]
397 fn test_calculate_transaction_weight_no_witness() {
398 let tx = create_test_transaction();
399
400 let weight = calculate_transaction_weight(&tx, None).unwrap();
401 assert!(weight > 0);
402 }
403
404 #[test]
405 fn test_compute_witness_merkle_root() {
406 let block = create_test_block();
407 let witnesses = vec![
408 vec![], vec![vec![OP_1]], ];
411
412 let root = compute_witness_merkle_root(&block, &witnesses).unwrap();
413 assert_eq!(root.len(), 32);
414 }
415
416 #[test]
417 fn test_compute_witness_merkle_root_empty_block() {
418 let block = Block {
419 header: create_test_header(1231006505, [0u8; 32]),
420 transactions: vec![].into_boxed_slice(),
421 };
422 let witnesses = vec![];
423
424 let result = compute_witness_merkle_root(&block, &witnesses);
425 assert!(result.is_err());
426 }
427
428 #[test]
429 fn test_validate_witness_commitment() {
430 let mut coinbase_tx = create_test_transaction();
431 let witness_root = [1u8; 32];
432 let nonce = [0u8; 32]; coinbase_tx.outputs[0].script_pubkey =
436 create_witness_commitment_script(&witness_root, &nonce);
437
438 let is_valid = validate_witness_commitment(&coinbase_tx, &witness_root, &[]).unwrap();
440 assert!(is_valid);
441 }
442
443 #[test]
444 fn test_is_segwit_transaction() {
445 let mut tx = create_test_transaction();
450 let p2wpkh_hash = [0x51; 20]; let mut script_pubkey = vec![OP_0, PUSH_20_BYTES]; script_pubkey.extend_from_slice(&p2wpkh_hash);
454 tx.outputs[0].script_pubkey = script_pubkey.into();
455
456 assert!(is_segwit_transaction(&tx));
457 }
458
459 #[test]
460 fn test_calculate_block_weight() {
461 let block = create_test_block();
462 let witnesses = vec![
463 vec![], vec![vec![OP_1]], ];
466
467 let weight = calculate_block_weight(&block, &witnesses).unwrap();
468 assert!(weight > 0);
469 }
470
471 #[test]
472 fn test_validate_segwit_block() {
473 let block = create_test_block();
474 let witnesses = vec![
475 vec![], vec![vec![OP_1]], ];
478
479 let is_valid = validate_segwit_block(&block, &witnesses, 4_000_000).unwrap();
480 assert!(is_valid);
481 }
482
483 #[test]
484 fn test_validate_segwit_block_exceeds_weight() {
485 let block = create_test_block();
486 let witnesses = vec![
487 vec![], vec![vec![OP_1]], ];
490
491 let is_valid = validate_segwit_block(&block, &witnesses, 1).unwrap(); assert!(!is_valid);
493 }
494
495 #[test]
496 fn test_validate_segwit_block_invalid_commitment() {
497 let mut block = create_test_block();
498 let witnesses = vec![
499 vec![], vec![vec![OP_1]], ];
502
503 let wrong_root = [2u8; 32];
505 block.transactions[0].outputs[0].script_pubkey =
506 create_witness_commitment_script(&wrong_root, &[0u8; 32]);
507
508 let is_valid = validate_segwit_block(&block, &witnesses, 4_000_000).unwrap();
509 assert!(!is_valid);
510 }
511
512 #[test]
513 fn test_validate_witness_commitment_no_commitment() {
514 let coinbase_tx = create_test_transaction();
515 let witness_root = [1u8; 32];
516
517 let is_valid = validate_witness_commitment(&coinbase_tx, &witness_root, &[]).unwrap();
519 assert!(is_valid); }
521
522 #[test]
523 fn test_validate_witness_commitment_invalid_commitment() {
524 let mut coinbase_tx = create_test_transaction();
525 let witness_root = [1u8; 32];
526 let invalid_root = [2u8; 32]; coinbase_tx.outputs[0].script_pubkey =
530 create_witness_commitment_script(&invalid_root, &[0u8; 32]);
531
532 let is_valid = validate_witness_commitment(&coinbase_tx, &witness_root, &[]).unwrap();
533 assert!(!is_valid);
534 }
535
536 #[test]
537 fn test_extract_witness_commitment_valid() {
538 let witness_root = [1u8; 32];
539 let nonce = [0u8; 32];
540 let script = create_witness_commitment_script(&witness_root, &nonce);
541
542 let mut preimage = [0u8; 64];
544 preimage[..32].copy_from_slice(&witness_root);
545 preimage[32..].copy_from_slice(&nonce);
546 let expected = sha256d_bytes(&preimage);
547
548 let extracted = extract_witness_commitment(&script).unwrap();
549 assert_eq!(extracted, expected);
550 }
551
552 #[test]
553 fn test_extract_witness_commitment_invalid_script() {
554 let script = vec![OP_1]; let extracted = extract_witness_commitment(&script);
557 assert!(extracted.is_none());
558 }
559
560 #[test]
561 fn test_extract_witness_commitment_wrong_opcode() {
562 let mut script = vec![0x52, PUSH_36_BYTES]; script.extend_from_slice(&[1u8; 32]);
564
565 let extracted = extract_witness_commitment(&script);
566 assert!(extracted.is_none());
567 }
568
569 #[test]
570 fn test_extract_witness_commitment_wrong_length() {
571 let mut script = vec![OP_RETURN, 0x25]; script.extend_from_slice(&[1u8; 32]);
573
574 let extracted = extract_witness_commitment(&script);
575 assert!(extracted.is_none());
576 }
577
578 #[test]
579 fn test_hash_witness() {
580 let witness = vec![vec![OP_1], vec![OP_2]];
581 let hash = hash_witness(&witness);
582
583 assert_eq!(hash.len(), 32);
584
585 let witness2 = vec![vec![OP_3], vec![OP_4]];
587 let hash2 = hash_witness(&witness2);
588 assert_ne!(hash, hash2);
589 }
590
591 #[test]
592 fn test_hash_witness_empty() {
593 let witness = vec![];
594 let hash = hash_witness(&witness);
595
596 assert_eq!(hash.len(), 32);
597 }
598
599 #[test]
600 fn test_compute_merkle_root_single_hash() {
601 let hashes = vec![[1u8; 32]];
602 let root = compute_merkle_root(&hashes).unwrap();
603
604 assert_eq!(root, [1u8; 32]);
605 }
606
607 #[test]
608 fn test_compute_merkle_root_empty() {
609 let hashes = vec![];
610 let result = compute_merkle_root(&hashes);
611
612 assert!(result.is_err());
613 }
614
615 #[test]
616 fn test_is_segwit_transaction_false() {
617 let tx = create_test_transaction();
618 assert!(!is_segwit_transaction(&tx));
621 }
622
623 #[test]
624 fn test_calculate_base_size() {
625 let tx = create_test_transaction();
626 let base_size = calculate_base_size(&tx);
627
628 assert!(base_size > 0);
629 }
630
631 #[test]
632 fn test_calculate_total_size_with_witness() {
633 let tx = create_test_transaction();
634 let witness = vec![vec![OP_1], vec![OP_2]];
635
636 let total_size = calculate_total_size(&tx, Some(&witness));
637 let base_size = calculate_base_size(&tx);
638
639 assert!(total_size > base_size);
640 }
641
642 #[test]
643 fn test_calculate_total_size_without_witness() {
644 let tx = create_test_transaction();
645
646 let total_size = calculate_total_size(&tx, None);
647 let base_size = calculate_base_size(&tx);
648
649 assert_eq!(total_size, base_size);
650 }
651
652 fn create_test_transaction() -> Transaction {
654 Transaction {
655 version: 1,
656 inputs: vec![TransactionInput {
657 prevout: OutPoint {
658 hash: [0; 32].into(),
659 index: 0,
660 },
661 script_sig: vec![OP_1],
662 sequence: 0xffffffff,
663 }]
664 .into(),
665 outputs: vec![TransactionOutput {
666 value: 1000,
667 script_pubkey: vec![OP_1].into(),
668 }]
669 .into(),
670 lock_time: 0,
671 }
672 }
673
674 fn create_test_block() -> Block {
675 Block {
676 header: create_test_header(1231006505, [0u8; 32]),
677 transactions: vec![
678 create_test_transaction(), create_test_transaction(), ]
681 .into_boxed_slice(),
682 }
683 }
684
685 fn create_witness_commitment_script(witness_root: &Hash, nonce: &[u8; 32]) -> ByteString {
686 let mut preimage = [0u8; 64];
688 preimage[..32].copy_from_slice(witness_root);
689 preimage[32..].copy_from_slice(nonce);
690 let commitment = sha256d_bytes(&preimage);
691 let mut script = vec![OP_RETURN, PUSH_36_BYTES]; script.extend_from_slice(&[0xaa, 0x21, 0xa9, 0xed]); script.extend_from_slice(&commitment);
694 script.into()
695 }
696}
697
698#[cfg(test)]
699mod property_tests {
700 use super::*;
701 use proptest::prelude::*;
702
703 proptest! {
708 #[test]
709 fn prop_transaction_weight_non_negative(
710 tx in create_transaction_strategy(),
711 witness in prop::option::of(create_witness_strategy())
712 ) {
713 let _weight = calculate_transaction_weight(&tx, witness.as_ref()).unwrap();
714 }
716 }
717
718 proptest! {
724 #[test]
725 fn prop_transaction_weight_formula(
726 tx in create_transaction_strategy(),
727 witness in prop::option::of(create_witness_strategy())
728 ) {
729 let weight = calculate_transaction_weight(&tx, witness.as_ref()).unwrap();
730 let base_size = calculate_base_size(&tx);
731 let total_size = calculate_total_size(&tx, witness.as_ref());
732 let expected_weight = 3 * base_size + total_size;
733
734 assert_eq!(weight, expected_weight);
735 }
736 }
737
738 proptest! {
744 #[test]
745 fn prop_block_weight_validation_limit(
746 block in create_block_strategy(),
747 witnesses in create_witnesses_strategy(),
748 max_weight in 1..10_000_000u64
749 ) {
750 match (calculate_block_weight(&block, &witnesses), validate_segwit_block(&block, &witnesses, max_weight as Natural)) {
752 (Ok(actual_weight), Ok(is_valid)) => {
753 if actual_weight > max_weight as Natural {
755 prop_assert!(!is_valid, "Block exceeding weight limit must be invalid");
756 }
757 },
758 (Err(_), _) | (_, Err(_)) => {
759 }
761 }
762 }
763 }
764
765 proptest! {
771 #[test]
772 fn prop_witness_commitment_deterministic(
773 coinbase_tx in create_transaction_strategy(),
774 witness_root in create_hash_strategy()
775 ) {
776 let result1 = validate_witness_commitment(&coinbase_tx, &witness_root, &[]).unwrap();
777 let result2 = validate_witness_commitment(&coinbase_tx, &witness_root, &[]).unwrap();
778
779 assert_eq!(result1, result2);
780 }
781 }
782
783 proptest! {
789 #[test]
790 fn prop_witness_merkle_root_deterministic(
791 block in create_block_strategy(),
792 witnesses in create_witnesses_strategy()
793 ) {
794 if !block.transactions.is_empty() {
795 let result1 = compute_witness_merkle_root(&block, &witnesses);
796 let result2 = compute_witness_merkle_root(&block, &witnesses);
797
798 assert_eq!(result1.is_ok(), result2.is_ok());
799 if result1.is_ok() && result2.is_ok() {
800 assert_eq!(result1.unwrap(), result2.unwrap());
801 }
802 }
803 }
804 }
805
806 proptest! {
811 #[test]
812 fn prop_segwit_transaction_detection(
813 tx in create_transaction_strategy()
814 ) {
815 let is_segwit = is_segwit_transaction(&tx);
816 let _ = is_segwit;
818 }
819 }
820
821 proptest! {
826 #[test]
827 fn prop_witness_hashing_deterministic(
828 witness in create_witness_strategy()
829 ) {
830 let hash1 = hash_witness(&witness);
831 let hash2 = hash_witness(&witness);
832
833 assert_eq!(hash1, hash2);
834 assert_eq!(hash1.len(), 32);
835 }
836 }
837
838 proptest! {
843 #[test]
844 fn prop_merkle_root_single_hash(
845 hash in create_hash_strategy()
846 ) {
847 let hashes = vec![hash];
848 let root = compute_merkle_root(&hashes).unwrap();
849
850 assert_eq!(root, hash);
851 }
852 }
853
854 #[test]
859 fn prop_merkle_root_empty_input() {
860 let hashes: Vec<Hash> = vec![];
861 let result = compute_merkle_root(&hashes);
862
863 assert!(result.is_err());
864 }
865
866 proptest! {
871 #[test]
872 fn prop_witness_commitment_extraction_deterministic(
873 script in prop::collection::vec(any::<u8>(), 0..100)
874 ) {
875 let result1 = extract_witness_commitment(&script);
876 let result2 = extract_witness_commitment(&script);
877
878 assert_eq!(result1.is_some(), result2.is_some());
879 if result1.is_some() && result2.is_some() {
880 assert_eq!(result1.unwrap(), result2.unwrap());
881 }
882 }
883 }
884
885 proptest! {
890 #[test]
891 fn prop_base_size_monotonic(
892 tx1 in create_transaction_strategy(),
893 tx2 in create_transaction_strategy()
894 ) {
895 let base_size1 = calculate_base_size(&tx1);
896 let base_size2 = calculate_base_size(&tx2);
897
898 assert!(base_size1 > 0);
900 assert!(base_size2 > 0);
901 }
902 }
903
904 proptest! {
909 #[test]
910 fn prop_total_size_with_witness_greater_than_base(
911 tx in create_transaction_strategy(),
912 witness in create_witness_strategy()
913 ) {
914 let base_size = calculate_base_size(&tx);
915 let total_size = calculate_total_size(&tx, Some(&witness));
916
917 assert!(total_size >= base_size);
918 }
919 }
920
921 fn create_transaction_strategy() -> impl Strategy<Value = Transaction> {
923 (
924 prop::collection::vec(any::<u8>(), 0..10), prop::collection::vec(any::<u8>(), 0..10), )
927 .prop_map(|(input_data, output_data)| {
928 let mut inputs = Vec::new();
929 for (i, _) in input_data.iter().enumerate() {
930 inputs.push(TransactionInput {
931 prevout: OutPoint {
932 hash: [0; 32],
933 index: i as u32,
934 },
935 script_sig: vec![OP_1],
936 sequence: 0xffffffff,
937 });
938 }
939
940 let mut outputs = Vec::new();
941 for _ in output_data {
942 outputs.push(TransactionOutput {
943 value: 1000,
944 script_pubkey: vec![OP_1],
945 });
946 }
947
948 Transaction {
949 version: 1,
950 inputs: inputs.into(),
951 outputs: outputs.into(),
952 lock_time: 0,
953 }
954 })
955 }
956
957 fn create_block_strategy() -> impl Strategy<Value = Block> {
958 prop::collection::vec(create_transaction_strategy(), 1..5).prop_map(|transactions| Block {
959 header: BlockHeader {
960 version: 1,
961 prev_block_hash: [0; 32],
962 merkle_root: [0; 32],
963 timestamp: 1231006505,
964 bits: 0x1d00ffff,
965 nonce: 0,
966 },
967 transactions: transactions.into_boxed_slice(),
968 })
969 }
970
971 fn create_witness_strategy() -> impl Strategy<Value = Witness> {
972 prop::collection::vec(prop::collection::vec(any::<u8>(), 0..10), 0..5)
973 }
974
975 fn create_witnesses_strategy() -> impl Strategy<Value = Vec<Witness>> {
976 prop::collection::vec(create_witness_strategy(), 0..5)
977 }
978
979 fn create_hash_strategy() -> impl Strategy<Value = Hash> {
980 prop::collection::vec(any::<u8>(), 32..=32).prop_map(|bytes| {
981 let mut hash = [0u8; 32];
982 hash.copy_from_slice(&bytes);
983 hash
984 })
985 }
986}