#[cfg(any(test, feature = "property-tests"))]
use proptest::prelude::*;
#[cfg(any(test, feature = "property-tests"))]
use crate::segwit::Witness;
use crate::types::{
BlockHeader, OutPoint, Transaction, TransactionInput, TransactionOutput, UtxoSet, UTXO,
};
#[cfg(any(test, feature = "property-tests"))]
pub fn transaction_with_witness_strategy() -> impl Strategy<Value = (Transaction, Vec<Witness>)> {
(1..10usize).prop_flat_map(|input_count| {
let tx_strategy = transaction_with_input_count_strategy(input_count);
let witness_strategy = prop::collection::vec(
prop::collection::vec(prop::collection::vec(any::<u8>(), 0..64), 0..5),
input_count,
);
(tx_strategy, witness_strategy).prop_map(|(tx, witnesses)| (tx, witnesses))
})
}
#[cfg(any(test, feature = "property-tests"))]
fn transaction_with_input_count_strategy(input_count: usize) -> impl Strategy<Value = Transaction> {
prop::collection::vec(any::<u8>(), 0..10).prop_map(move |output_data| {
let inputs: Vec<TransactionInput> = (0..input_count)
.map(|i| TransactionInput {
prevout: OutPoint {
hash: [0; 32],
index: i as u32,
},
script_sig: vec![0x51], sequence: 0xffffffff,
})
.collect();
let outputs: Vec<TransactionOutput> = output_data
.iter()
.map(|_| TransactionOutput {
value: 1000,
script_pubkey: vec![0x51],
})
.collect();
Transaction {
version: 1,
inputs: inputs.into(),
outputs: outputs.into(),
lock_time: 0,
}
})
}
#[cfg(any(test, feature = "property-tests"))]
pub fn transaction_strategy() -> impl Strategy<Value = Transaction> {
(1..10usize, 0..10usize).prop_map(|(input_count, output_count)| {
let inputs: Vec<TransactionInput> = (0..input_count)
.map(|i| TransactionInput {
prevout: OutPoint {
hash: [0; 32],
index: i as u32,
},
script_sig: vec![0x51],
sequence: 0xffffffff,
})
.collect();
let outputs: Vec<TransactionOutput> = (0..output_count)
.map(|_| TransactionOutput {
value: 1000,
script_pubkey: vec![0x51],
})
.collect();
Transaction {
version: 1,
inputs: inputs.into(),
outputs: outputs.into(),
lock_time: 0,
}
})
}
pub fn create_test_header(timestamp: u64, prev_hash: [u8; 32]) -> BlockHeader {
BlockHeader {
version: 1,
prev_block_hash: prev_hash,
merkle_root: [0; 32],
timestamp,
bits: 0x1d00ffff,
nonce: 0,
}
}
pub fn create_coinbase_tx(value: i64) -> Transaction {
Transaction {
version: 1,
inputs: vec![TransactionInput {
prevout: OutPoint {
hash: [0; 32],
index: 0xffffffff,
},
script_sig: vec![0x03, 0x01, 0x00, 0x00], sequence: 0xffffffff,
}]
.into(),
outputs: vec![TransactionOutput {
value,
script_pubkey: vec![0x51],
}]
.into(),
lock_time: 0,
}
}
pub fn create_test_utxo_set_two_outputs() -> UtxoSet {
let mut utxo_set = UtxoSet::default();
utxo_set.insert(
OutPoint {
hash: [1; 32],
index: 0,
},
std::sync::Arc::new(UTXO {
value: 100_000_000, script_pubkey: vec![0x51].into(),
height: 100,
is_coinbase: false,
}),
);
utxo_set.insert(
OutPoint {
hash: [2; 32],
index: 0,
},
std::sync::Arc::new(UTXO {
value: 50_000_000, script_pubkey: vec![0x52].into(),
height: 101,
is_coinbase: false,
}),
);
utxo_set
}
#[cfg(all(test, feature = "property-tests"))]
#[test]
fn test_transaction_with_witness_strategy_satisfies_constraint() {
use proptest::test_runner::Config;
proptest!(Config::with_cases(50), |((tx, w) in transaction_with_witness_strategy())| {
prop_assert_eq!(w.len(), tx.inputs.len());
});
}