Skip to main content

transaction_fuzzer/
type_arg_fuzzer.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use iota_core::test_utils::send_and_confirm_transaction;
6use iota_sdk_types::{
7    Address, Identifier, ObjectId, ProgrammableTransaction, StructTag, Transaction,
8    TransactionEffects, TransactionKind, TypeTag,
9};
10use iota_types::{
11    effects::TransactionEffectsAPI, error::IotaError,
12    programmable_transaction_builder::ProgrammableTransactionBuilder, transaction::TransactionAPI,
13    utils::to_sender_signed_transaction,
14};
15use proptest::{arbitrary::*, prelude::*};
16
17use crate::{
18    account_universe::AccountCurrent,
19    executor::{Executor, assert_is_acceptable_result},
20};
21
22const GAS_PRICE: u64 = 1000;
23const GAS: u64 = 1_000_000 * GAS_PRICE;
24
25pub fn gen_type_tag() -> impl Strategy<Value = TypeTag> {
26    prop_oneof![
27        2 => any::<TypeTag>(),
28        1 => gen_nested_type_tag()
29    ]
30}
31
32// Generate deep nested type tags
33pub fn gen_nested_type_tag() -> impl Strategy<Value = TypeTag> {
34    let leaf = prop_oneof![
35        Just(TypeTag::Bool),
36        Just(TypeTag::U8),
37        Just(TypeTag::U16),
38        Just(TypeTag::U32),
39        Just(TypeTag::U64),
40        Just(TypeTag::U128),
41        Just(TypeTag::U256),
42        Just(TypeTag::Address),
43        Just(TypeTag::Signer),
44    ];
45    leaf.prop_recursive(8, 6, 10, |inner| {
46        prop_oneof![
47            inner.prop_map(|x| TypeTag::Vector(Box::new(x))),
48            gen_struct_tag().prop_map(|x| TypeTag::Struct(Box::new(x))),
49        ]
50    })
51}
52
53pub fn gen_struct_tag() -> impl Strategy<Value = StructTag> {
54    (
55        any::<Address>(),
56        any::<Identifier>(),
57        any::<Identifier>(),
58        any::<Vec<TypeTag>>(),
59    )
60        .prop_map(|(address, module, name, type_params)| {
61            StructTag::new(address, module, name, type_params)
62        })
63}
64
65pub fn generate_valid_type_factory_tags(
66    type_factory_addr: ObjectId,
67) -> impl Strategy<Value = TypeTag> {
68    let leaf = prop_oneof![
69        base_type_factory_tag_gen(type_factory_addr),
70        nested_type_factory_tag_gen(type_factory_addr),
71    ];
72
73    leaf.prop_recursive(8, 6, 10, move |inner| {
74        prop_oneof![inner.prop_map(|x| TypeTag::Vector(Box::new(x))),]
75    })
76}
77
78pub fn generate_valid_and_invalid_type_factory_tags(
79    type_factory_addr: ObjectId,
80) -> impl Strategy<Value = TypeTag> {
81    let leaf = prop_oneof![
82        any::<TypeTag>(),
83        base_type_factory_tag_gen(type_factory_addr),
84        nested_type_factory_tag_gen(type_factory_addr),
85    ];
86
87    leaf.prop_recursive(8, 6, 10, move |inner| {
88        prop_oneof![inner.prop_map(|x| TypeTag::Vector(Box::new(x))),]
89    })
90}
91
92pub fn base_type_factory_tag_gen(addr: ObjectId) -> impl Strategy<Value = TypeTag> {
93    "[A-Z]".prop_map(move |name| {
94        TypeTag::Struct(Box::new(StructTag::new(
95            addr,
96            Identifier::from_static("type_factory"),
97            Identifier::new(name).unwrap(),
98            vec![],
99        )))
100    })
101}
102
103pub fn nested_type_factory_tag_gen(addr: ObjectId) -> impl Strategy<Value = TypeTag> {
104    base_type_factory_tag_gen(addr).prop_recursive(20, 256, 10, move |inner| {
105        (inner, "[A-Z]").prop_map(move |(instantiation, name)| {
106            TypeTag::Struct(Box::new(StructTag::new(
107                addr,
108                Identifier::from_static("type_factory"),
109                Identifier::new(name.to_string() + &name).unwrap(),
110                vec![instantiation],
111            )))
112        })
113    })
114}
115
116pub fn type_factory_pt_for_tags(
117    package_id: ObjectId,
118    type_tags: Vec<TypeTag>,
119    len: usize,
120) -> ProgrammableTransaction {
121    let mut builder = ProgrammableTransactionBuilder::new();
122    builder
123        .move_call(
124            package_id,
125            Identifier::from_static("type_factory"),
126            Identifier::new(format!("type_tags{len}")).unwrap(),
127            type_tags,
128            vec![],
129        )
130        .unwrap();
131    builder.finish()
132}
133
134pub fn pt_for_tags(type_tags: Vec<TypeTag>) -> ProgrammableTransaction {
135    let mut builder = ProgrammableTransactionBuilder::new();
136    builder
137        .move_call(
138            ObjectId::FRAMEWORK,
139            Identifier::from_static("random_type_tag_fuzzing"),
140            Identifier::from_static("random_type_tag_fuzzing_fn"),
141            type_tags,
142            vec![],
143        )
144        .unwrap();
145    builder.finish()
146}
147
148pub fn run_pt(account: &mut AccountCurrent, exec: &mut Executor, pt: ProgrammableTransaction) {
149    let result = run_pt_effects(account, exec, pt);
150    let status = result.map(|effects| effects.status().clone());
151    assert_is_acceptable_result(&status);
152}
153
154pub fn run_pt_effects(
155    account: &mut AccountCurrent,
156    exec: &mut Executor,
157    pt: ProgrammableTransaction,
158) -> Result<TransactionEffects, IotaError> {
159    let gas_object = account.new_gas_object(exec);
160    let gas_object_ref = gas_object.object_ref();
161    let kind = TransactionKind::Programmable(pt);
162    let tx = Transaction::new(
163        kind,
164        account.initial_data.account.address,
165        gas_object_ref,
166        GAS,
167        GAS_PRICE,
168    );
169    let signed_txn = to_sender_signed_transaction(tx, &account.initial_data.account.key);
170    exec.rt
171        .block_on(send_and_confirm_transaction(&exec.state, None, signed_txn))
172        .map(|(_, effects)| effects.into_data())
173}