iota_replay/
fuzz_mutations.rs1use iota_types::transaction::TransactionKind;
6use rand::{SeedableRng, seq::SliceRandom};
7
8use crate::fuzz::TransactionKindMutator;
9
10pub mod drop_random_command_suffix;
11pub mod drop_random_commands;
12pub mod shuffle_command_inputs;
13pub mod shuffle_commands;
14pub mod shuffle_transaction_inputs;
15pub mod shuffle_types;
16
17const NUM_TRIES: u64 = 5;
20
21pub struct RandomMutator {
27 pub rng: rand::rngs::StdRng,
28 pub mutators: Vec<Box<dyn TransactionKindMutator + Send + Sync>>,
29 pub num_tries: u64,
30}
31
32pub struct ChainedMutator {
33 pub mutators: Vec<Box<dyn TransactionKindMutator>>,
34}
35
36impl RandomMutator {
37 pub fn new() -> Self {
38 Self {
39 rng: rand::rngs::StdRng::from_seed([0u8; 32]),
40 mutators: vec![],
41 num_tries: NUM_TRIES,
42 }
43 }
44
45 pub fn add_mutator(&mut self, mutator: Box<dyn TransactionKindMutator + Send + Sync>) {
46 self.mutators.push(mutator);
47 }
48
49 pub fn select_mutator(&mut self) -> Option<&mut Box<dyn TransactionKindMutator + Send + Sync>> {
50 self.mutators.choose_mut(&mut self.rng)
51 }
52}
53
54impl Default for RandomMutator {
55 fn default() -> Self {
56 Self::new()
57 }
58}
59
60impl TransactionKindMutator for RandomMutator {
61 fn mutate(&mut self, transaction_kind: &TransactionKind) -> Option<TransactionKind> {
62 for _ in 0..self.num_tries {
63 if let Some(mutator) = self.select_mutator() {
64 return mutator.mutate(transaction_kind);
65 }
66 }
67 None
68 }
69
70 fn reset(&mut self, mutations_per_base: u64) {
71 for mutator in self.mutators.iter_mut() {
72 mutator.reset(mutations_per_base);
73 }
74 }
75}
76
77impl ChainedMutator {
78 pub fn new() -> Self {
79 Self { mutators: vec![] }
80 }
81
82 pub fn add_mutator(&mut self, mutator: Box<dyn TransactionKindMutator>) {
83 self.mutators.push(mutator);
84 }
85}
86
87impl Default for ChainedMutator {
88 fn default() -> Self {
89 Self::new()
90 }
91}
92
93impl TransactionKindMutator for ChainedMutator {
94 fn mutate(&mut self, transaction_kind: &TransactionKind) -> Option<TransactionKind> {
95 let mut mutated = transaction_kind.clone();
96 let mut num_mutations = 0;
97
98 for mutator in self.mutators.iter_mut() {
99 if let Some(new_mutated) = mutator.mutate(&mutated) {
100 num_mutations += 1;
101 mutated = new_mutated;
102 }
103 }
104
105 if num_mutations == 0 {
106 None
107 } else {
108 Some(mutated)
109 }
110 }
111
112 fn reset(&mut self, mutations_per_base: u64) {
113 for mutator in self.mutators.iter_mut() {
114 mutator.reset(mutations_per_base);
115 }
116 }
117}
118
119pub fn base_fuzzers(num_mutations: u64) -> RandomMutator {
120 let mut mutator = RandomMutator::new();
121 mutator.add_mutator(Box::new(shuffle_commands::ShuffleCommands {
122 rng: rand::rngs::StdRng::from_seed([0u8; 32]),
123 num_mutations_per_base_left: num_mutations,
124 }));
125 mutator.add_mutator(Box::new(shuffle_types::ShuffleTypes {
126 rng: rand::rngs::StdRng::from_seed([0u8; 32]),
127 num_mutations_per_base_left: num_mutations,
128 }));
129 mutator.add_mutator(Box::new(shuffle_command_inputs::ShuffleCommandInputs {
130 rng: rand::rngs::StdRng::from_seed([0u8; 32]),
131 num_mutations_per_base_left: num_mutations,
132 }));
133 mutator.add_mutator(Box::new(
134 shuffle_transaction_inputs::ShuffleTransactionInputs {
135 rng: rand::rngs::StdRng::from_seed([0u8; 32]),
136 num_mutations_per_base_left: num_mutations,
137 },
138 ));
139 mutator.add_mutator(Box::new(drop_random_commands::DropRandomCommands {
140 rng: rand::rngs::StdRng::from_seed([0u8; 32]),
141 num_mutations_per_base_left: num_mutations,
142 }));
143 mutator.add_mutator(Box::new(drop_random_command_suffix::DropCommandSuffix {
144 rng: rand::rngs::StdRng::from_seed([0u8; 32]),
145 num_mutations_per_base_left: num_mutations,
146 }));
147 mutator
148}