transaction_fuzzer/
type_arg_fuzzer.rs

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