forked from sigp/lighthouse
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fuzz.rs
121 lines (110 loc) · 3.22 KB
/
fuzz.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#![cfg(all(test, not(debug_assertions)))]
use crate::PeerId;
use libp2p::core::identity::{secp256k1::PublicKey as Libp2pSecpPublicKey, PublicKey};
use libsecp256k1::{PublicKey as SecpPublicKey, SecretKey};
use lru_cache::LRUTimeCache;
use proptest::prelude::*;
use proptest::sample::Index;
use std::time::Duration;
type Cache = LRUTimeCache<PeerId>;
const SHORT_TTL: Duration = Duration::from_millis(5);
const LONG_TTL: Duration = Duration::from_secs(1_000_000_000);
fn arb_secret_key() -> impl Strategy<Value = SecretKey> {
proptest::array::uniform32(any::<u8>()).prop_map(|mut bytes| loop {
if let Ok(key) = SecretKey::parse(&bytes) {
return key;
}
bytes[31] += 1;
})
}
fn arb_public_key() -> impl Strategy<Value = PublicKey> {
arb_secret_key().prop_map(|sk| {
let spk = SecpPublicKey::from_secret_key(&sk);
let bytes = spk.serialize_compressed();
PublicKey::Secp256k1(Libp2pSecpPublicKey::decode(&bytes).unwrap())
})
}
fn arb_peer_id() -> impl Strategy<Value = PeerId> {
arb_public_key().prop_map(|pk| PeerId::from_public_key(&pk))
}
fn arb_index() -> impl Strategy<Value = Index> {
any::<proptest::sample::Index>()
}
#[derive(Debug, Clone)]
enum Op {
RawInsert(Index),
RawRemove(Index),
RemoveExpired,
Insert(Index),
Update,
Wait(Duration),
Shrink,
}
fn arb_op() -> impl Strategy<Value = Op> {
prop_oneof![
arb_index().prop_map(Op::RawInsert),
arb_index().prop_map(Op::RawRemove),
Just(Op::RemoveExpired),
arb_index().prop_map(Op::Insert),
Just(Op::Update),
arb_index().prop_map(|idx| {
let millis = idx.index(SHORT_TTL.as_millis() as usize);
Op::Wait(Duration::from_millis(millis as u64))
}),
Just(Op::Shrink),
]
}
fn apply_op(cache: &mut Cache, peer_ids: &[PeerId], op: Op) {
let n = peer_ids.len();
let get_peer_id = |idx: Index| {
let i = idx.index(n);
peer_ids[i].clone()
};
match op {
Op::RawInsert(i) => {
cache.raw_insert(get_peer_id(i));
}
Op::RawRemove(i) => {
cache.raw_remove(&get_peer_id(i));
}
Op::RemoveExpired => {
cache.remove_expired();
}
Op::Insert(i) => {
cache.insert(get_peer_id(i));
}
Op::Update => {
cache.update();
}
Op::Wait(time) => {
// This is a bit yuck for a proptest.
std::thread::sleep(time);
}
Op::Shrink => {
cache.shrink_to_fit();
}
}
}
proptest! {
#[test]
fn proptest_insert_peer_ids(
peer_ids in proptest::collection::vec(arb_peer_id(), 1..200),
) {
let mut cache = Cache::new(LONG_TTL);
for peer_id in peer_ids {
cache.insert(peer_id);
}
cache.check_invariant();
}
#[test]
fn proptest_random_ops(
peer_ids in proptest::collection::vec(arb_peer_id(), 50..100),
ops in proptest::collection::vec(arb_op(), 1..2048)
) {
let mut cache = Cache::new(SHORT_TTL);
for op in ops {
apply_op(&mut cache, &peer_ids, op);
cache.check_invariant();
}
}
}