transaction_fuzzer/
transaction_data_gen.rs1use 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}