1use std::{sync::Arc, time::Duration};
6
7use fastcrypto::{hash::MultisetHash, traits::KeyPair};
8use iota_sdk_types::crypto::{Intent, IntentScope};
9use iota_types::{
10 base_types::{
11 AuthorityName, ExecutionDigests, Identifier, IotaAddress, ObjectID, ObjectRef,
12 TransactionDigest, random_object_ref,
13 },
14 committee::Committee,
15 crypto::{
16 AccountKeyPair, AuthorityKeyPair, AuthorityPublicKeyBytes, AuthoritySignInfo,
17 AuthoritySignature, Signer,
18 },
19 effects::{SignedTransactionEffects, TestEffectsBuilder},
20 error::IotaError,
21 message_envelope::Message,
22 transaction::{
23 CallArg, CertifiedTransaction, ObjectArg, SignedTransaction,
24 TEST_ONLY_GAS_UNIT_FOR_TRANSFER, Transaction, TransactionData,
25 },
26 utils::{create_fake_transaction, to_sender_signed_transaction},
27};
28use move_core_types::account_address::AccountAddress;
29use tokio::time::timeout;
30use tracing::{info, warn};
31
32use crate::{authority::AuthorityState, global_state_hasher::GlobalStateHasher};
33
34const WAIT_FOR_TX_TIMEOUT: Duration = Duration::from_secs(15);
35
36pub async fn send_and_confirm_transaction(
37 authority: &AuthorityState,
38 fullnode: Option<&AuthorityState>,
39 transaction: Transaction,
40) -> Result<(CertifiedTransaction, SignedTransactionEffects), IotaError> {
41 let epoch_store = authority.load_epoch_store_one_call_per_task();
43 transaction.validity_check(epoch_store.protocol_config(), epoch_store.epoch())?;
44 let transaction = epoch_store.verify_transaction(transaction)?;
45 let response = authority
46 .handle_transaction(&epoch_store, transaction.clone())
47 .await?;
48 let vote = response.status.into_signed_for_testing();
49
50 let committee = authority.clone_committee_for_testing();
52 let certificate = CertifiedTransaction::new(transaction.into_message(), vec![vote], &committee)
53 .unwrap()
54 .try_into_verified_for_testing(&committee, &Default::default())
55 .unwrap();
56
57 let state_acc =
65 GlobalStateHasher::new_for_tests(authority.get_global_state_hash_store().clone());
66 let mut state = state_acc.accumulate_cached_live_object_set_for_testing();
67 let (result, _execution_error_opt) = authority.try_execute_for_test(&certificate)?;
68 let state_after = state_acc.accumulate_cached_live_object_set_for_testing();
69 let effects_acc = state_acc.accumulate_effects(&[result.inner().data().clone()]);
70 state.union(&effects_acc);
71
72 assert_eq!(state_after.digest(), state.digest());
73
74 if let Some(fullnode) = fullnode {
75 fullnode.try_execute_for_test(&certificate)?;
76 }
77 Ok((certificate.into_inner(), result.into_inner()))
78}
79
80#[cfg(test)]
81pub(crate) fn init_state_parameters_from_rng<R>(
82 rng: &mut R,
83) -> (iota_config::genesis::Genesis, AuthorityKeyPair)
84where
85 R: rand::CryptoRng + rand::RngCore,
86{
87 let dir = iota_macros::nondeterministic!(tempfile::TempDir::new().unwrap());
88 let network_config = iota_swarm_config::network_config_builder::ConfigBuilder::new(&dir)
89 .rng(rng)
90 .build();
91 let genesis = network_config.genesis;
92 let authority_key = network_config.validator_configs[0]
93 .authority_key_pair()
94 .copy();
95
96 (genesis, authority_key)
97}
98
99pub async fn wait_for_tx(digest: TransactionDigest, state: Arc<AuthorityState>) {
100 match timeout(
101 WAIT_FOR_TX_TIMEOUT,
102 state
103 .get_transaction_cache_reader()
104 .try_notify_read_executed_effects(&[digest]),
105 )
106 .await
107 {
108 Ok(_) => info!(?digest, "digest found"),
109 Err(e) => {
110 warn!(?digest, "digest not found!");
111 panic!("timed out waiting for effects of digest! {e}");
112 }
113 }
114}
115
116pub async fn wait_for_all_txes(digests: Vec<TransactionDigest>, state: Arc<AuthorityState>) {
117 match timeout(
118 WAIT_FOR_TX_TIMEOUT,
119 state
120 .get_transaction_cache_reader()
121 .try_notify_read_executed_effects(&digests),
122 )
123 .await
124 {
125 Ok(_) => info!(?digests, "all digests found"),
126 Err(e) => {
127 warn!(?digests, "some digests not found!");
128 panic!("timed out waiting for effects of digests! {e}");
129 }
130 }
131}
132
133pub fn create_fake_cert_and_effect_digest<'a>(
134 signers: impl Iterator<
135 Item = (
136 &'a AuthorityName,
137 &'a (dyn Signer<AuthoritySignature> + Send + Sync),
138 ),
139 >,
140 committee: &Committee,
141) -> (ExecutionDigests, CertifiedTransaction) {
142 let transaction = create_fake_transaction();
143 let cert = CertifiedTransaction::new(
144 transaction.data().clone(),
145 signers
146 .map(|(name, signer)| {
147 AuthoritySignInfo::new(
148 committee.epoch,
149 transaction.data(),
150 Intent::iota_app(IntentScope::SenderSignedTransaction),
151 *name,
152 signer,
153 )
154 })
155 .collect(),
156 committee,
157 )
158 .unwrap();
159 let effects = TestEffectsBuilder::new(transaction.data()).build();
160 (
161 ExecutionDigests::new(*transaction.digest(), effects.digest()),
162 cert,
163 )
164}
165
166pub fn make_transfer_iota_transaction(
167 gas_object: ObjectRef,
168 recipient: IotaAddress,
169 amount: Option<u64>,
170 sender: IotaAddress,
171 keypair: &AccountKeyPair,
172 gas_price: u64,
173) -> Transaction {
174 let data = TransactionData::new_transfer_iota(
175 recipient,
176 sender,
177 amount,
178 gas_object,
179 gas_price * TEST_ONLY_GAS_UNIT_FOR_TRANSFER,
180 gas_price,
181 );
182 to_sender_signed_transaction(data, keypair)
183}
184
185pub fn make_pay_iota_transaction(
186 gas_object: ObjectRef,
187 coins: Vec<ObjectRef>,
188 recipients: Vec<IotaAddress>,
189 amounts: Vec<u64>,
190 sender: IotaAddress,
191 keypair: &AccountKeyPair,
192 gas_price: u64,
193 gas_budget: u64,
194) -> Transaction {
195 let data = TransactionData::new_pay_iota(
196 sender, coins, recipients, amounts, gas_object, gas_budget, gas_price,
197 )
198 .unwrap();
199 to_sender_signed_transaction(data, keypair)
200}
201
202pub fn make_transfer_object_transaction(
203 object_ref: ObjectRef,
204 gas_object: ObjectRef,
205 sender: IotaAddress,
206 keypair: &AccountKeyPair,
207 recipient: IotaAddress,
208 gas_price: u64,
209) -> Transaction {
210 let data = TransactionData::new_transfer(
211 recipient,
212 object_ref,
213 sender,
214 gas_object,
215 gas_price * TEST_ONLY_GAS_UNIT_FOR_TRANSFER * 10,
216 gas_price,
217 );
218 to_sender_signed_transaction(data, keypair)
219}
220
221pub fn make_transfer_object_move_transaction(
222 src: IotaAddress,
223 keypair: &AccountKeyPair,
224 dest: IotaAddress,
225 object_ref: ObjectRef,
226 framework_obj_id: ObjectID,
227 gas_object_ref: ObjectRef,
228 gas_budget_in_units: u64,
229 gas_price: u64,
230) -> Transaction {
231 let args = vec![
232 CallArg::Object(ObjectArg::ImmOrOwnedObject(object_ref)),
233 CallArg::Pure(bcs::to_bytes(&AccountAddress::new(dest.into_bytes())).unwrap()),
234 ];
235
236 to_sender_signed_transaction(
237 TransactionData::new_move_call(
238 src,
239 framework_obj_id,
240 Identifier::from_static("object_basics"),
241 Identifier::from_static("transfer"),
242 Vec::new(),
243 gas_object_ref,
244 args,
245 gas_budget_in_units * gas_price,
246 gas_price,
247 )
248 .unwrap(),
249 keypair,
250 )
251}
252
253pub fn make_dummy_tx(
255 receiver: IotaAddress,
256 sender: IotaAddress,
257 sender_sec: &AccountKeyPair,
258) -> Transaction {
259 Transaction::from_data_and_signer(
260 TransactionData::new_transfer(
261 receiver,
262 random_object_ref(),
263 sender,
264 random_object_ref(),
265 TEST_ONLY_GAS_UNIT_FOR_TRANSFER * 10,
266 10,
267 ),
268 vec![sender_sec],
269 )
270}
271
272pub fn make_cert_with_large_committee(
274 committee: &Committee,
275 key_pairs: &[AuthorityKeyPair],
276 transaction: &Transaction,
277) -> CertifiedTransaction {
278 let len = committee.voting_rights.len();
280 assert_eq!(len, key_pairs.len());
281 let count = (len * 2).div_ceil(3);
282
283 let sigs: Vec<_> = key_pairs
284 .iter()
285 .take(count)
286 .map(|key_pair| {
287 SignedTransaction::new(
288 committee.epoch(),
289 transaction.clone().into_data(),
290 key_pair,
291 AuthorityPublicKeyBytes::from(key_pair.public()),
292 )
293 .auth_sig()
294 .clone()
295 })
296 .collect();
297
298 let cert = CertifiedTransaction::new(transaction.clone().into_data(), sigs, committee).unwrap();
299 cert.verify_signatures_authenticated(committee, &Default::default())
300 .unwrap();
301 cert
302}