1#[cfg(any(test, feature = "property-tests"))]
7use proptest::prelude::*;
8
9#[cfg(any(test, feature = "property-tests"))]
10use crate::segwit::Witness;
11use crate::types::{
12 BlockHeader, OutPoint, Transaction, TransactionInput, TransactionOutput, UtxoSet, UTXO,
13};
14
15#[cfg(any(test, feature = "property-tests"))]
16pub fn transaction_with_witness_strategy() -> impl Strategy<Value = (Transaction, Vec<Witness>)> {
19 (1..10usize).prop_flat_map(|input_count| {
20 let tx_strategy = transaction_with_input_count_strategy(input_count);
21 let witness_strategy = prop::collection::vec(
22 prop::collection::vec(prop::collection::vec(any::<u8>(), 0..64), 0..5),
23 input_count,
24 );
25 (tx_strategy, witness_strategy).prop_map(|(tx, witnesses)| (tx, witnesses))
26 })
27}
28
29#[cfg(any(test, feature = "property-tests"))]
30fn transaction_with_input_count_strategy(input_count: usize) -> impl Strategy<Value = Transaction> {
31 prop::collection::vec(any::<u8>(), 0..10).prop_map(move |output_data| {
32 let inputs: Vec<TransactionInput> = (0..input_count)
33 .map(|i| TransactionInput {
34 prevout: OutPoint {
35 hash: [0; 32],
36 index: i as u32,
37 },
38 script_sig: vec![0x51], sequence: 0xffffffff,
40 })
41 .collect();
42 let outputs: Vec<TransactionOutput> = output_data
43 .iter()
44 .map(|_| TransactionOutput {
45 value: 1000,
46 script_pubkey: vec![0x51],
47 })
48 .collect();
49 Transaction {
50 version: 1,
51 inputs: inputs.into(),
52 outputs: outputs.into(),
53 lock_time: 0,
54 }
55 })
56}
57
58#[cfg(any(test, feature = "property-tests"))]
59pub fn transaction_strategy() -> impl Strategy<Value = Transaction> {
61 (1..10usize, 0..10usize).prop_map(|(input_count, output_count)| {
63 let inputs: Vec<TransactionInput> = (0..input_count)
64 .map(|i| TransactionInput {
65 prevout: OutPoint {
66 hash: [0; 32],
67 index: i as u32,
68 },
69 script_sig: vec![0x51],
70 sequence: 0xffffffff,
71 })
72 .collect();
73 let outputs: Vec<TransactionOutput> = (0..output_count)
74 .map(|_| TransactionOutput {
75 value: 1000,
76 script_pubkey: vec![0x51],
77 })
78 .collect();
79 Transaction {
80 version: 1,
81 inputs: inputs.into(),
82 outputs: outputs.into(),
83 lock_time: 0,
84 }
85 })
86}
87
88pub fn create_test_header(timestamp: u64, prev_hash: [u8; 32]) -> BlockHeader {
91 BlockHeader {
92 version: 1,
93 prev_block_hash: prev_hash,
94 merkle_root: [0; 32],
95 timestamp,
96 bits: 0x1d00ffff,
97 nonce: 0,
98 }
99}
100
101pub fn create_coinbase_tx(value: i64) -> Transaction {
104 Transaction {
105 version: 1,
106 inputs: vec![TransactionInput {
107 prevout: OutPoint {
108 hash: [0; 32],
109 index: 0xffffffff,
110 },
111 script_sig: vec![0x03, 0x01, 0x00, 0x00], sequence: 0xffffffff,
113 }]
114 .into(),
115 outputs: vec![TransactionOutput {
116 value,
117 script_pubkey: vec![0x51],
118 }]
119 .into(),
120 lock_time: 0,
121 }
122}
123
124pub fn create_test_utxo_set_two_outputs() -> UtxoSet {
127 let mut utxo_set = UtxoSet::default();
128 utxo_set.insert(
129 OutPoint {
130 hash: [1; 32],
131 index: 0,
132 },
133 std::sync::Arc::new(UTXO {
134 value: 100_000_000, script_pubkey: vec![0x51].into(),
136 height: 100,
137 is_coinbase: false,
138 }),
139 );
140 utxo_set.insert(
141 OutPoint {
142 hash: [2; 32],
143 index: 0,
144 },
145 std::sync::Arc::new(UTXO {
146 value: 50_000_000, script_pubkey: vec![0x52].into(),
148 height: 101,
149 is_coinbase: false,
150 }),
151 );
152 utxo_set
153}
154
155#[cfg(all(test, feature = "property-tests"))]
156#[test]
157fn test_transaction_with_witness_strategy_satisfies_constraint() {
158 use proptest::test_runner::Config;
159 proptest!(Config::with_cases(50), |((tx, w) in transaction_with_witness_strategy())| {
160 prop_assert_eq!(w.len(), tx.inputs.len());
161 });
162}