zebra_chain/work/difficulty/
arbitrary.rs

1use super::*;
2
3use proptest::{collection::vec, prelude::*};
4
5impl Arbitrary for CompactDifficulty {
6    type Parameters = ();
7
8    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
9        (vec(any::<u8>(), 32))
10            .prop_filter_map("zero CompactDifficulty values are invalid", |v| {
11                let mut bytes = [0; 32];
12                bytes.copy_from_slice(v.as_slice());
13                if bytes == [0; 32] {
14                    return None;
15                }
16                // In the Zcash protocol, a CompactDifficulty is generated using the difficulty
17                // adjustment functions. Instead of using those functions, we make a random
18                // ExpandedDifficulty, then convert it to a CompactDifficulty.
19                Some(ExpandedDifficulty::from_hash(&block::Hash(bytes)).to_compact())
20            })
21            .boxed()
22    }
23
24    type Strategy = BoxedStrategy<Self>;
25}
26
27impl Arbitrary for ExpandedDifficulty {
28    type Parameters = ();
29
30    fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
31        any::<CompactDifficulty>()
32            .prop_map(|d| {
33                // In the Zcash protocol, an ExpandedDifficulty is converted from a CompactDifficulty,
34                // or generated using the difficulty adjustment functions. We use the conversion in
35                // our proptest strategy.
36                d.to_expanded()
37                    .expect("arbitrary CompactDifficulty is valid")
38            })
39            .boxed()
40    }
41
42    type Strategy = BoxedStrategy<Self>;
43}
44
45impl Arbitrary for Work {
46    type Parameters = ();
47
48    fn arbitrary_with(_args: ()) -> Self::Strategy {
49        // In the Zcash protocol, a Work is converted from an ExpandedDifficulty.
50        // But some randomised difficulties are impractically large, and will
51        // never appear in any real-world block. So we just use a random Work value.
52        (1..u128::MAX).prop_map(Work).boxed()
53    }
54
55    type Strategy = BoxedStrategy<Self>;
56}
57
58impl Arbitrary for PartialCumulativeWork {
59    type Parameters = ();
60
61    fn arbitrary_with(_args: ()) -> Self::Strategy {
62        // In Zebra's implementation, a PartialCumulativeWork is the sum of 0..100 Work values.
63        // But our Work values are randomised, rather than being derived from real-world
64        // difficulties. So we don't need to sum multiple Work values here.
65        (any::<Work>())
66            .prop_map(PartialCumulativeWork::from)
67            .boxed()
68    }
69
70    type Strategy = BoxedStrategy<Self>;
71}