1use 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
32pub 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}