transaction_fuzzer/
transaction_data_gen.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::{
6    base_types::{IotaAddress, ObjectID, ObjectRef, SequenceNumber},
7    digests::ObjectDigest,
8    transaction::{
9        GasData, TransactionData, TransactionDataV1, TransactionExpiration, TransactionKind,
10    },
11};
12use move_core_types::account_address::AccountAddress;
13use proptest::{arbitrary::*, collection::vec, prelude::*};
14
15use crate::{
16    account_universe::{gas_budget_selection_strategy, gas_price_selection_strategy},
17    type_arg_fuzzer::{gen_type_tag, pt_for_tags},
18};
19
20const MAX_NUM_GAS_OBJS: usize = 1024_usize;
21
22pub fn gen_transaction_expiration_with_bound(
23    max_epoch: u64,
24) -> impl Strategy<Value = TransactionExpiration> {
25    prop_oneof![
26        Just(TransactionExpiration::None),
27        (0u64..=max_epoch).prop_map(TransactionExpiration::Epoch),
28    ]
29}
30
31pub fn gen_transaction_expiration() -> impl Strategy<Value = TransactionExpiration> {
32    prop_oneof![
33        Just(TransactionExpiration::None),
34        (0u64..=u64::MAX).prop_map(TransactionExpiration::Epoch),
35    ]
36}
37
38pub fn gen_object_ref() -> impl Strategy<Value = ObjectRef> {
39    (
40        any::<AccountAddress>(),
41        any::<SequenceNumber>(),
42        any::<[u8; 32]>(),
43    )
44        .prop_map(move |(addr, seq, seed)| {
45            (ObjectID::from_address(addr), seq, ObjectDigest::new(seed))
46        })
47}
48
49pub fn gen_gas_data(sender: IotaAddress) -> impl Strategy<Value = GasData> {
50    (
51        vec(gen_object_ref(), 0..MAX_NUM_GAS_OBJS),
52        gas_price_selection_strategy(),
53        gas_budget_selection_strategy(),
54    )
55        .prop_map(move |(obj_refs, price, budget)| GasData {
56            payment: obj_refs,
57            owner: sender,
58            price,
59            budget,
60        })
61}
62
63pub fn gen_transaction_kind() -> impl Strategy<Value = TransactionKind> {
64    (vec(gen_type_tag(), 0..10))
65        .prop_map(pt_for_tags)
66        .prop_map(TransactionKind::ProgrammableTransaction)
67}
68
69pub fn transaction_data_gen(sender: IotaAddress) -> impl Strategy<Value = TransactionData> {
70    TransactionDataGenBuilder::new(sender)
71        .kind(gen_transaction_kind())
72        .gas_data(gen_gas_data(sender))
73        .expiration(gen_transaction_expiration())
74        .finish()
75}
76
77pub struct TransactionDataGenBuilder<
78    K: Strategy<Value = TransactionKind>,
79    G: Strategy<Value = GasData>,
80    E: Strategy<Value = TransactionExpiration>,
81> {
82    pub kind: Option<K>,
83    pub sender: IotaAddress,
84    pub gas_data: Option<G>,
85    pub expiration: Option<E>,
86}
87
88impl<
89    K: Strategy<Value = TransactionKind>,
90    G: Strategy<Value = GasData>,
91    E: Strategy<Value = TransactionExpiration>,
92> TransactionDataGenBuilder<K, G, E>
93{
94    pub fn new(sender: IotaAddress) -> Self {
95        Self {
96            kind: None,
97            sender,
98            gas_data: None,
99            expiration: None,
100        }
101    }
102
103    pub fn kind(mut self, kind: K) -> Self {
104        self.kind = Some(kind);
105        self
106    }
107
108    pub fn gas_data(mut self, gas_data: G) -> Self {
109        self.gas_data = Some(gas_data);
110        self
111    }
112
113    pub fn expiration(mut self, expiration: E) -> Self {
114        self.expiration = Some(expiration);
115        self
116    }
117
118    pub fn finish(self) -> impl Strategy<Value = TransactionData> {
119        (
120            self.kind.expect("kind must be set"),
121            Just(self.sender),
122            self.gas_data.expect("gas_data must be set"),
123            self.expiration.expect("expiration must be set"),
124        )
125            .prop_map(|(kind, sender, gas_data, expiration)| TransactionDataV1 {
126                kind,
127                sender,
128                gas_data,
129                expiration,
130            })
131            .prop_map(TransactionData::V1)
132    }
133}