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}