1use std::{sync::Arc, time::Duration};
6
7use fastcrypto::{hash::MultisetHash, traits::KeyPair};
8use iota_protocol_config::ProtocolConfig;
9use iota_sdk_types::{
10 Address, CheckpointSummary, EndOfEpochData, GasCostSummary, Identifier, ObjectId,
11 ObjectReference, Transaction, TransactionDigest,
12 crypto::{Intent, IntentScope},
13};
14use iota_types::{
15 base_types::{AuthorityName, ExecutionDigests, random_object_ref},
16 committee::{Committee, EpochId},
17 crypto::{
18 AccountPrivateKey, AuthorityKeyPair, AuthorityPublicKeyBytes, AuthoritySignInfo,
19 AuthoritySignature, AuthorityStrongQuorumSignInfo, Signer,
20 },
21 effects::{SignedTransactionEffects, TestEffectsBuilder},
22 error::IotaError,
23 message_envelope::Envelope,
24 messages_checkpoint::{CertifiedCheckpointSummary, VerifiedCheckpoint},
25 messages_consensus::ConsensusTransactionKind,
26 signature::VerifyParams,
27 transaction::{
28 CallArg, CertifiedTransaction, SenderSignedTransactionAPI, SignedTransaction,
29 TEST_ONLY_GAS_UNIT_FOR_TRANSFER, TransactionAPI, TransactionEnvelope,
30 },
31 utils::{create_fake_transaction, to_sender_signed_transaction},
32};
33use move_core_types::account_address::AccountAddress;
34use tokio::time::timeout;
35use tracing::{info, warn};
36
37use crate::{
38 authority::{AuthorityState, ExecutionEnv},
39 global_state_hasher::GlobalStateHasher,
40};
41
42const WAIT_FOR_TX_TIMEOUT: Duration = Duration::from_secs(15);
43
44pub async fn send_and_confirm_transaction(
45 authority: &AuthorityState,
46 fullnode: Option<&AuthorityState>,
47 transaction: TransactionEnvelope,
48) -> Result<(CertifiedTransaction, SignedTransactionEffects), IotaError> {
49 let epoch_store = authority.load_epoch_store_one_call_per_task();
51 transaction.validity_check(&epoch_store.tx_validity_check_context())?;
52 let transaction = epoch_store.verify_transaction(transaction)?;
53 let response = authority
54 .handle_transaction(&epoch_store, transaction.clone())
55 .await?;
56 let vote = response.status.into_signed_for_testing();
57
58 let committee = authority.clone_committee_for_testing();
60 let certificate = CertifiedTransaction::new(transaction.into_message(), vec![vote], &committee)
61 .unwrap()
62 .try_into_verified_for_testing(
63 &committee,
64 &VerifyParams::from_protocol_config(epoch_store.protocol_config()),
65 )
66 .unwrap();
67
68 let state_acc =
76 GlobalStateHasher::new_for_tests(authority.get_global_state_hash_store().clone());
77 let mut state = state_acc.accumulate_cached_live_object_set_for_testing()?;
78 let (result, _execution_error_opt) =
79 authority.try_execute_for_test(&certificate, ExecutionEnv::new())?;
80 let state_after = state_acc.accumulate_cached_live_object_set_for_testing()?;
81 let effects_acc = state_acc.accumulate_effects(&[result.inner().data().clone()]);
82 state.union(&effects_acc);
83
84 assert_eq!(state_after.digest(), state.digest());
85
86 if let Some(fullnode) = fullnode {
87 fullnode.try_execute_for_test(&certificate, ExecutionEnv::new())?;
88 }
89 Ok((certificate.into_inner(), result.into_inner()))
90}
91
92#[cfg(test)]
93pub(crate) fn init_state_parameters_from_rng<R>(
94 rng: &mut R,
95) -> (iota_config::genesis::Genesis, AuthorityKeyPair)
96where
97 R: rand::CryptoRng,
98{
99 let dir = iota_macros::nondeterministic!(tempfile::TempDir::new().unwrap());
100 let network_config = iota_swarm_config::network_config_builder::ConfigBuilder::new(&dir)
101 .rng(rng)
102 .build();
103 let genesis = network_config.genesis;
104 let authority_key = network_config.validator_configs[0]
105 .authority_key_pair()
106 .copy();
107
108 (genesis, authority_key)
109}
110
111pub async fn wait_for_tx(digest: TransactionDigest, state: Arc<AuthorityState>) {
112 match timeout(
113 WAIT_FOR_TX_TIMEOUT,
114 state
115 .get_transaction_cache_reader()
116 .try_notify_read_executed_effects("", &[digest]),
117 )
118 .await
119 {
120 Ok(Ok(_)) => info!(?digest, "digest found"),
121 Ok(Err(e)) => panic!("failed to read effects of digest! {e}"),
122 Err(e) => {
123 warn!(?digest, "digest not found!");
124 panic!("timed out waiting for effects of digest! {e}");
125 }
126 }
127}
128
129pub async fn wait_for_all_txes(digests: Vec<TransactionDigest>, state: Arc<AuthorityState>) {
130 match timeout(
131 WAIT_FOR_TX_TIMEOUT,
132 state
133 .get_transaction_cache_reader()
134 .try_notify_read_executed_effects("", &digests),
135 )
136 .await
137 {
138 Ok(Ok(_)) => info!(?digests, "all digests found"),
139 Ok(Err(e)) => panic!("failed to read effects of digests! {e}"),
140 Err(e) => {
141 warn!(?digests, "some digests not found!");
142 panic!("timed out waiting for effects of digests! {e}");
143 }
144 }
145}
146
147pub fn create_fake_cert_and_effect_digest<'a>(
148 signers: impl Iterator<
149 Item = (
150 &'a AuthorityName,
151 &'a (dyn Signer<AuthoritySignature> + Send + Sync),
152 ),
153 >,
154 committee: &Committee,
155) -> (ExecutionDigests, CertifiedTransaction) {
156 let transaction = create_fake_transaction();
157 let cert = CertifiedTransaction::new(
158 transaction.data().clone(),
159 signers
160 .map(|(name, signer)| {
161 AuthoritySignInfo::new(
162 committee.epoch,
163 transaction.data(),
164 Intent::iota_app(IntentScope::SenderSignedTransaction),
165 *name,
166 signer,
167 )
168 })
169 .collect(),
170 committee,
171 )
172 .unwrap();
173 let effects = TestEffectsBuilder::new(transaction.data()).build();
174 (
175 ExecutionDigests::new(*transaction.digest(), effects.digest()),
176 cert,
177 )
178}
179
180pub fn make_transfer_iota_transaction(
181 gas_object: ObjectReference,
182 recipient: Address,
183 amount: Option<u64>,
184 sender: Address,
185 private_key: &AccountPrivateKey,
186 gas_price: u64,
187) -> TransactionEnvelope {
188 let tx = Transaction::new_transfer_iota(
189 recipient,
190 sender,
191 amount,
192 gas_object,
193 gas_price * TEST_ONLY_GAS_UNIT_FOR_TRANSFER,
194 gas_price,
195 );
196 to_sender_signed_transaction(tx, private_key)
197}
198
199pub fn make_pay_iota_transaction(
200 gas_object: ObjectReference,
201 coins: Vec<ObjectReference>,
202 recipients: Vec<Address>,
203 amounts: Vec<u64>,
204 sender: Address,
205 private_key: &AccountPrivateKey,
206 gas_price: u64,
207 gas_budget: u64,
208) -> TransactionEnvelope {
209 let tx = Transaction::new_pay_iota(
210 sender, coins, recipients, amounts, gas_object, gas_budget, gas_price,
211 )
212 .unwrap();
213 to_sender_signed_transaction(tx, private_key)
214}
215
216pub fn make_transfer_object_transaction(
217 object_ref: ObjectReference,
218 gas_object: ObjectReference,
219 sender: Address,
220 private_key: &AccountPrivateKey,
221 recipient: Address,
222 gas_price: u64,
223) -> TransactionEnvelope {
224 let tx = Transaction::new_transfer(
225 recipient,
226 object_ref,
227 sender,
228 gas_object,
229 gas_price * TEST_ONLY_GAS_UNIT_FOR_TRANSFER * 10,
230 gas_price,
231 );
232 to_sender_signed_transaction(tx, private_key)
233}
234
235pub fn make_transfer_object_move_transaction(
236 src: Address,
237 private_key: &AccountPrivateKey,
238 dest: Address,
239 object_ref: ObjectReference,
240 framework_obj_id: ObjectId,
241 gas_object_ref: ObjectReference,
242 gas_budget_in_units: u64,
243 gas_price: u64,
244) -> TransactionEnvelope {
245 let args = vec![
246 CallArg::ImmutableOrOwned(object_ref),
247 CallArg::pure(&AccountAddress::new(dest.into_bytes())),
248 ];
249
250 to_sender_signed_transaction(
251 Transaction::new_move_call(
252 src,
253 framework_obj_id,
254 Identifier::from_static("object_basics"),
255 Identifier::from_static("transfer"),
256 Vec::new(),
257 gas_object_ref,
258 args,
259 gas_budget_in_units * gas_price,
260 gas_price,
261 )
262 .unwrap(),
263 private_key,
264 )
265}
266
267pub fn make_dummy_tx(
269 receiver: Address,
270 sender: Address,
271 sender_sec: &AccountPrivateKey,
272) -> TransactionEnvelope {
273 TransactionEnvelope::from_data_and_signer(
274 Transaction::new_transfer(
275 receiver,
276 random_object_ref(),
277 sender,
278 random_object_ref(),
279 TEST_ONLY_GAS_UNIT_FOR_TRANSFER * 10,
280 10,
281 ),
282 vec![sender_sec],
283 )
284}
285
286pub fn make_cert_with_large_committee(
288 committee: &Committee,
289 key_pairs: &[AuthorityKeyPair],
290 transaction: &TransactionEnvelope,
291) -> CertifiedTransaction {
292 let len = committee.voting_rights.len();
294 assert_eq!(len, key_pairs.len());
295 let count = (len * 2).div_ceil(3);
296
297 let sigs: Vec<_> = key_pairs
298 .iter()
299 .take(count)
300 .map(|key_pair| {
301 SignedTransaction::new(
302 committee.epoch(),
303 transaction.clone().into_data(),
304 key_pair,
305 AuthorityPublicKeyBytes::from(key_pair.public()),
306 )
307 .auth_sig()
308 .clone()
309 })
310 .collect();
311
312 let cert = CertifiedTransaction::new(transaction.clone().into_data(), sigs, committee).unwrap();
313 cert.verify_signatures_authenticated(
314 committee,
315 &VerifyParams::from_protocol_config(&ProtocolConfig::get_for_max_version_UNSAFE()),
316 )
317 .unwrap();
318 cert
319}
320
321pub fn set_scheduler_env(use_execution_scheduler: bool) {
325 if use_execution_scheduler {
327 std::env::set_var("ENABLE_EXECUTION_SCHEDULER", "1");
328 std::env::remove_var("ENABLE_TRANSACTION_MANAGER");
329 } else {
330 std::env::set_var("ENABLE_TRANSACTION_MANAGER", "1");
331 std::env::remove_var("ENABLE_EXECUTION_SCHEDULER");
332 }
333}
334
335#[allow(deprecated)]
343pub fn consensus_transaction_feature_gate(
344 kind: &ConsensusTransactionKind,
345 config: &ProtocolConfig,
346) -> Option<bool> {
347 match kind {
348 ConsensusTransactionKind::CertifiedTransaction(_)
349 | ConsensusTransactionKind::CheckpointSignature(_)
350 | ConsensusTransactionKind::EndOfPublish(_)
351 | ConsensusTransactionKind::CapabilityNotificationV1(_)
352 | ConsensusTransactionKind::SignedCapabilityNotificationV1(_)
353 | ConsensusTransactionKind::RandomnessDkgMessage(_, _)
354 | ConsensusTransactionKind::RandomnessDkgConfirmation(_, _) => None,
355 ConsensusTransactionKind::UserTransactionV1(_)
356 | ConsensusTransactionKind::OverloadNotificationV1(_, _, _) => {
357 Some(config.enable_pcool_flow())
358 }
359 ConsensusTransactionKind::MisbehaviorReport(_) => Some(config.calculate_validator_scores()),
360 ConsensusTransactionKind::NewJWKFetchedDeprecated => Some(false),
363 ConsensusTransactionKind::TransactionDenyRuleProposal(_) => {
364 Some(config.enable_pcool_flow())
365 }
366 }
367}
368
369pub fn certified_summary(
372 epoch: EpochId,
373 sequence_number: u64,
374 end_of_epoch_data: Option<EndOfEpochData>,
375) -> CertifiedCheckpointSummary {
376 let summary = CheckpointSummary {
377 epoch,
378 sequence_number,
379 network_total_transactions: 0,
380 contents_digest: Default::default(),
381 previous_digest: None,
382 epoch_rolling_gas_cost_summary: GasCostSummary::default(),
383 end_of_epoch_data,
384 timestamp_ms: 0,
385 version_specific_data: Vec::new(),
386 checkpoint_commitments: Vec::new(),
387 };
388 let sig = AuthorityStrongQuorumSignInfo {
389 epoch,
390 signature: Default::default(),
391 signers_map: Default::default(),
392 };
393 Envelope::new_from_data_and_sig(summary, sig)
394}
395
396pub fn executed_checkpoint(epoch: EpochId, sequence_number: u64) -> VerifiedCheckpoint {
399 VerifiedCheckpoint::new_unchecked(certified_summary(epoch, sequence_number, None))
400}