iota_replay/fuzz_mutations/
shuffle_command_inputs.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use iota_types::transaction::{Command, TransactionKind};
6use rand::seq::SliceRandom;
7use tracing::info;
8
9use crate::fuzz::TransactionKindMutator;
10
11pub struct ShuffleCommandInputs {
12    pub rng: rand::rngs::StdRng,
13    pub num_mutations_per_base_left: u64,
14}
15
16impl ShuffleCommandInputs {
17    fn shuffle_command(&mut self, command: &mut Command) {
18        match command {
19            Command::MakeMoveVec(_, ref mut args)
20            | Command::MergeCoins(_, ref mut args)
21            | Command::SplitCoins(_, ref mut args)
22            | Command::TransferObjects(ref mut args, _) => {
23                args.shuffle(&mut self.rng);
24            }
25            Command::MoveCall(ref mut pt) => pt.arguments.shuffle(&mut self.rng),
26            Command::Publish(_, _) => (),
27            Command::Upgrade(_, _, _, _) => (),
28        }
29    }
30}
31
32impl TransactionKindMutator for ShuffleCommandInputs {
33    fn mutate(&mut self, transaction_kind: &TransactionKind) -> Option<TransactionKind> {
34        if self.num_mutations_per_base_left == 0 {
35            // Nothing else to do
36            return None;
37        }
38
39        self.num_mutations_per_base_left -= 1;
40        if let TransactionKind::ProgrammableTransaction(mut p) = transaction_kind.clone() {
41            for command in &mut p.commands {
42                self.shuffle_command(command);
43            }
44            info!("Mutation: Shuffling command inputs");
45            Some(TransactionKind::ProgrammableTransaction(p))
46        } else {
47            // Other types not supported yet
48            None
49        }
50    }
51
52    fn reset(&mut self, mutations_per_base: u64) {
53        self.num_mutations_per_base_left = mutations_per_base;
54    }
55}