use proptest::prelude::*;
use blvm_consensus::types::*;
use blvm_consensus::{check_transaction, connect_block, UtxoSet};
impl Arbitrary for Transaction {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
(
any::<u64>(), prop::collection::vec(
(
any::<[u8; 32]>(), any::<u64>(), prop::collection::vec(any::<u8>(), 0..100), any::<u64>(), ),
0..10 ),
prop::collection::vec(
(
any::<i64>(), prop::collection::vec(any::<u8>(), 0..100), ),
0..10 ),
any::<u64>(), )
.prop_map(|(version, inputs, outputs, lock_time)| Transaction {
version,
inputs: inputs.into_iter().map(|(hash, index, script_sig, sequence)| {
TransactionInput {
prevout: OutPoint { hash, index },
script_sig,
sequence,
}
}).collect(),
outputs: outputs.into_iter().map(|(value, script_pubkey)| {
TransactionOutput {
value,
script_pubkey,
}
}).collect(),
lock_time,
})
.boxed()
}
}
impl Arbitrary for BlockHeader {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
(
any::<i32>(), any::<[u8; 32]>(), any::<[u8; 32]>(), any::<u64>(), any::<u64>(), any::<u64>(), )
.prop_map(|(version, prev_block_hash, merkle_root, timestamp, bits, nonce)| {
BlockHeader {
version,
prev_block_hash,
merkle_root,
timestamp,
bits,
nonce,
}
})
.boxed()
}
}
impl Arbitrary for Block {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
(
any::<BlockHeader>(),
prop::collection::vec(any::<Transaction>(), 0..100), )
.prop_map(|(header, transactions)| Block {
header,
transactions: transactions.into(),
})
.boxed()
}
}
impl Arbitrary for OutPoint {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
(
any::<[u8; 32]>(), any::<u64>(), )
.prop_map(|(hash, index)| OutPoint { hash, index })
.boxed()
}
}
impl Arbitrary for UTXO {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
(
any::<i64>(), prop::collection::vec(any::<u8>(), 0..100), any::<u64>(), )
.prop_map(|(value, script_pubkey, height)| UTXO {
value,
script_pubkey,
height,
})
.boxed()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_transaction_arbitrary() {
proptest!(|(tx: Transaction)| {
let _result = check_transaction(&tx);
});
}
#[test]
fn test_block_header_arbitrary() {
proptest!(|(header: BlockHeader)| {
assert!(header.version >= -1 && header.version <= 2);
});
}
#[test]
fn test_block_arbitrary() {
proptest!(|(block: Block)| {
let utxo_set = UtxoSet::default();
let witnesses: Vec<segwit::Witness> = block.transactions.iter().map(|_| Vec::new()).collect();
let ctx = block::BlockValidationContext::for_network(crate::types::Network::Mainnet);
let _result = connect_block(&block, &witnesses, utxo_set, 0, &ctx);
});
}
}