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