1use std::sync::Arc;
7
8use fastcrypto::{hash::MultisetHash, traits::KeyPair};
9use iota_config::{genesis::Genesis, node::ExpensiveSafetyCheckConfig};
10use iota_sdk_types::{
11 Address, ObjectId, ObjectReference, Owner, RandomnessRound, Transaction, TransactionEffects,
12 Version, VersionAssignment,
13};
14use iota_types::{
15 crypto::{AccountPrivateKey, AuthorityKeyPair},
16 effects::SignedTransactionEffects,
17 error::{ExecutionError, IotaError},
18 executable_transaction::VerifiedExecutableTransaction,
19 messages_consensus::ConsensusTransaction,
20 object::Object,
21 signature::VerifyParams,
22 transaction::{
23 CertifiedTransaction, SenderSignedTransactionAPI, TEST_ONLY_GAS_UNIT_FOR_TRANSFER,
24 TransactionAPI, TransactionEnvelope, TransactionKey, VerifiedCertificate,
25 VerifiedSignedTransaction, VerifiedTransaction,
26 },
27 utils::to_sender_signed_transaction,
28};
29
30use super::{
31 authority_per_epoch_store::AuthorityPerEpochStore,
32 epoch_start_configuration::EpochStartConfigTrait,
33 shared_object_version_manager::{AssignedTxAndVersions, AssignedVersions, Schedulable},
34 test_authority_builder::TestAuthorityBuilder,
35};
36use crate::{
37 authority::{AuthorityState, ExecutionEnv},
38 checkpoints::CheckpointServiceNoop,
39 consensus_handler::SequencedConsensusTransaction,
40 execution_scheduler::{
41 ExecutionSchedulerAPI, transaction_manager::SchedulableAttestedTransaction,
42 },
43 global_state_hasher::GlobalStateHasher,
44};
45
46pub async fn send_and_confirm_transaction(
47 authority: &AuthorityState,
48 transaction: TransactionEnvelope,
49) -> Result<(CertifiedTransaction, SignedTransactionEffects), IotaError> {
50 send_and_confirm_transaction_(
51 authority,
52 None, transaction,
54 false, )
56 .await
57}
58pub async fn send_and_confirm_transaction_(
59 authority: &AuthorityState,
60 fullnode: Option<&AuthorityState>,
61 transaction: TransactionEnvelope,
62 with_shared: bool, ) -> Result<(CertifiedTransaction, SignedTransactionEffects), IotaError> {
64 let (txn, effects, _execution_error_opt) = send_and_confirm_transaction_with_execution_error(
65 authority,
66 fullnode,
67 transaction,
68 with_shared,
69 true,
70 )
71 .await?;
72 Ok((txn, effects))
73}
74
75pub async fn certify_transaction(
76 authority: &AuthorityState,
77 transaction: TransactionEnvelope,
78) -> Result<VerifiedCertificate, IotaError> {
79 let epoch_store = authority.load_epoch_store_one_call_per_task();
81 transaction.validity_check(&epoch_store.tx_validity_check_context())?;
83 let transaction = epoch_store.verify_transaction(transaction).unwrap();
84
85 let response = authority
86 .handle_transaction(&epoch_store, transaction.clone())
87 .await?;
88 let vote = response.status.into_signed_for_testing();
89 epoch_store.assign_to_a_new_commit_for_testing(&[transaction.key()]);
91
92 let committee = authority.clone_committee_for_testing();
94 let certificate = CertifiedTransaction::new(transaction.into_message(), vec![vote], &committee)
95 .unwrap()
96 .try_into_verified_for_testing(
97 &committee,
98 &VerifyParams::from_protocol_config(epoch_store.protocol_config()),
99 )
100 .unwrap();
101 Ok(certificate)
102}
103
104pub async fn execute_certificate_with_execution_error(
105 authority: &AuthorityState,
106 fullnode: Option<&AuthorityState>,
107 certificate: VerifiedCertificate,
108 with_shared: bool, fake_consensus: bool,
110) -> Result<
111 (
112 CertifiedTransaction,
113 SignedTransactionEffects,
114 Option<ExecutionError>,
115 ),
116 IotaError,
117> {
118 let state_acc =
123 GlobalStateHasher::new_for_tests(authority.get_global_state_hash_store().clone());
124 let mut state = state_acc.accumulate_cached_live_object_set_for_testing()?;
125
126 let assigned_versions = if with_shared {
127 if fake_consensus {
128 send_consensus(authority, &certificate).await
129 } else {
130 let assigned_versions = authority
132 .epoch_store_for_testing()
133 .assign_shared_object_versions_for_tests(
134 authority.get_object_cache_reader().as_ref(),
135 &[VerifiedExecutableTransaction::new_from_certificate(
136 certificate.clone(),
137 )],
138 )?;
139 assigned_versions
140 .into_map()
141 .get(&certificate.key())
142 .cloned()
143 .unwrap()
144 }
145 } else {
146 vec![]
147 };
148
149 let (result, execution_error_opt) = authority.try_execute_for_test(
154 &certificate,
155 ExecutionEnv::new().with_assigned_versions(assigned_versions.clone()),
156 )?;
157 let state_after = state_acc.accumulate_cached_live_object_set_for_testing()?;
158 let effects_acc = state_acc.accumulate_effects(&[result.inner().data().clone()]);
159 state.union(&effects_acc);
160
161 assert_eq!(state_after.digest(), state.digest());
162
163 if let Some(fullnode) = fullnode {
164 fullnode.try_execute_for_test(
165 &certificate,
166 ExecutionEnv::new().with_assigned_versions(assigned_versions),
167 )?;
168 }
169 Ok((
170 certificate.into_inner(),
171 result.into_inner(),
172 execution_error_opt,
173 ))
174}
175
176pub async fn send_and_confirm_transaction_with_execution_error(
177 authority: &AuthorityState,
178 fullnode: Option<&AuthorityState>,
179 transaction: TransactionEnvelope,
180 with_shared: bool, fake_consensus: bool, ) -> Result<
183 (
184 CertifiedTransaction,
185 SignedTransactionEffects,
186 Option<ExecutionError>,
187 ),
188 IotaError,
189> {
190 let certificate = certify_transaction(authority, transaction).await?;
191 execute_certificate_with_execution_error(
192 authority,
193 fullnode,
194 certificate,
195 with_shared,
196 fake_consensus,
197 )
198 .await
199}
200
201pub async fn init_state_validator_with_fullnode() -> (Arc<AuthorityState>, Arc<AuthorityState>) {
202 use iota_types::crypto::get_authority_key_pair;
203
204 let validator = TestAuthorityBuilder::new().build().await;
205 let fullnode_key_pair = get_authority_key_pair().1;
206 let fullnode = TestAuthorityBuilder::new()
207 .with_keypair(&fullnode_key_pair)
208 .build()
209 .await;
210 (validator, fullnode)
211}
212
213pub async fn init_state_with_committee(
214 genesis: &Genesis,
215 authority_key: &AuthorityKeyPair,
216) -> Arc<AuthorityState> {
217 TestAuthorityBuilder::new()
218 .with_genesis_and_keypair(genesis, authority_key)
219 .build()
220 .await
221}
222
223pub async fn init_state_with_ids<I: IntoIterator<Item = (Address, ObjectId)>>(
224 objects: I,
225) -> Arc<AuthorityState> {
226 let state = TestAuthorityBuilder::new().build().await;
227 for (address, object_id) in objects {
228 let obj = Object::with_id_owner_for_testing(object_id, address);
229 state.insert_genesis_object(obj);
231 }
232 state
233}
234
235pub async fn init_state_with_ids_and_versions<
236 I: IntoIterator<Item = (Address, ObjectId, Version)>,
237>(
238 objects: I,
239) -> Arc<AuthorityState> {
240 let state = TestAuthorityBuilder::new().build().await;
241 for (address, object_id, version) in objects {
242 let obj =
243 Object::with_id_owner_version_for_testing(object_id, version, Owner::Address(address));
244 state.insert_genesis_object(obj);
245 }
246 state
247}
248
249pub async fn init_state_with_objects<I: IntoIterator<Item = Object>>(
250 objects: I,
251) -> Arc<AuthorityState> {
252 let dir = tempfile::TempDir::new().unwrap();
253 let network_config =
254 iota_swarm_config::network_config_builder::ConfigBuilder::new(&dir).build();
255 let genesis = network_config.genesis;
256 let keypair = network_config.validator_configs[0]
257 .authority_key_pair()
258 .copy();
259 init_state_with_objects_and_committee(objects, &genesis, &keypair).await
260}
261
262pub async fn init_state_with_objects_and_committee<I: IntoIterator<Item = Object>>(
263 objects: I,
264 genesis: &Genesis,
265 authority_key: &AuthorityKeyPair,
266) -> Arc<AuthorityState> {
267 let state = init_state_with_committee(genesis, authority_key).await;
268 for o in objects {
269 state.insert_genesis_object(o);
270 }
271 state
272}
273
274pub async fn init_state_with_object_id(address: Address, object: ObjectId) -> Arc<AuthorityState> {
275 init_state_with_ids(std::iter::once((address, object))).await
276}
277
278pub async fn init_state_with_ids_and_expensive_checks<
279 I: IntoIterator<Item = (Address, ObjectId)>,
280>(
281 objects: I,
282 config: ExpensiveSafetyCheckConfig,
283) -> Arc<AuthorityState> {
284 let state = TestAuthorityBuilder::new()
285 .with_expensive_safety_checks(config)
286 .build()
287 .await;
288 for (address, object_id) in objects {
289 let obj = Object::with_id_owner_for_testing(object_id, address);
290 state.insert_genesis_object(obj);
292 }
293 state
294}
295
296pub fn init_transfer_transaction(
297 authority_state: &AuthorityState,
298 sender: Address,
299 secret: &AccountPrivateKey,
300 recipient: Address,
301 object_ref: ObjectReference,
302 gas_object_ref: ObjectReference,
303 gas_budget: u64,
304 gas_price: u64,
305) -> VerifiedTransaction {
306 let tx = Transaction::new_transfer(
307 recipient,
308 object_ref,
309 sender,
310 gas_object_ref,
311 gas_budget,
312 gas_price,
313 );
314 let tx = to_sender_signed_transaction(tx, secret);
315 authority_state
316 .epoch_store_for_testing()
317 .verify_transaction(tx)
318 .unwrap()
319}
320
321pub fn init_certified_transfer_transaction(
322 sender: Address,
323 secret: &AccountPrivateKey,
324 recipient: Address,
325 object_ref: ObjectReference,
326 gas_object_ref: ObjectReference,
327 authority_state: &AuthorityState,
328) -> VerifiedCertificate {
329 let rgp = authority_state.reference_gas_price_for_testing().unwrap();
330 let transfer_transaction = init_transfer_transaction(
331 authority_state,
332 sender,
333 secret,
334 recipient,
335 object_ref,
336 gas_object_ref,
337 rgp * TEST_ONLY_GAS_UNIT_FOR_TRANSFER,
338 rgp,
339 );
340 init_certified_transaction(transfer_transaction.into(), authority_state)
341}
342
343pub fn init_certified_transaction(
347 transaction: TransactionEnvelope,
348 authority_state: &AuthorityState,
349) -> VerifiedCertificate {
350 let epoch_store = authority_state.epoch_store_for_testing();
351 let transaction = epoch_store.verify_transaction(transaction).unwrap();
352 epoch_store.assign_to_a_new_commit_for_testing(&[transaction.key()]);
353
354 let vote = VerifiedSignedTransaction::new(
355 0,
356 transaction.clone(),
357 authority_state.name,
358 &*authority_state.secret,
359 );
360 CertifiedTransaction::new(
361 transaction.into_message(),
362 vec![vote.auth_sig().clone()],
363 epoch_store.committee(),
364 )
365 .unwrap()
366 .try_into_verified_for_testing(
367 epoch_store.committee(),
368 &VerifyParams::from_protocol_config(epoch_store.protocol_config()),
369 )
370 .unwrap()
371}
372
373pub async fn certify_shared_obj_transaction_no_execution(
374 authority: &AuthorityState,
375 transaction: TransactionEnvelope,
376) -> Result<(VerifiedCertificate, AssignedVersions), IotaError> {
377 let epoch_store = authority.load_epoch_store_one_call_per_task();
378 let transaction = epoch_store.verify_transaction(transaction).unwrap();
379 let response = authority
380 .handle_transaction(&epoch_store, transaction.clone())
381 .await?;
382 let vote = response.status.into_signed_for_testing();
383
384 let committee = authority.clone_committee_for_testing();
386 let certificate =
387 CertifiedTransaction::new(transaction.into_message(), vec![vote.clone()], &committee)
388 .unwrap()
389 .try_into_verified_for_testing(
390 &committee,
391 &VerifyParams::from_protocol_config(epoch_store.protocol_config()),
392 )
393 .unwrap();
394
395 let assigned_versions = send_consensus_no_execution(authority, &certificate).await;
396
397 Ok((certificate, assigned_versions))
398}
399
400pub async fn enqueue_all_and_execute_all(
401 authority: &AuthorityState,
402 certificates: Vec<(VerifiedCertificate, ExecutionEnv)>,
403) -> Result<Vec<TransactionEffects>, IotaError> {
404 authority.execution_scheduler().enqueue(
405 certificates
406 .iter()
407 .map(|(cert, env)| {
408 (
409 VerifiedExecutableTransaction::new_from_certificate(cert.clone()).into(),
410 env.clone(),
411 )
412 })
413 .collect(),
414 &authority.epoch_store_for_testing(),
415 );
416 let mut output = Vec::new();
417 for (cert, _) in certificates {
418 let effects = authority.notify_read_effects("", &cert).await?;
419 output.push(effects);
420 }
421 Ok(output)
422}
423
424pub async fn execute_sequenced_certificate_to_effects(
425 authority: &AuthorityState,
426 certificate: VerifiedCertificate,
427 assigned_versions: AssignedVersions,
428) -> Result<(TransactionEffects, Option<ExecutionError>), IotaError> {
429 let env = ExecutionEnv::new().with_assigned_versions(assigned_versions);
430 authority
431 .epoch_store_for_testing()
432 .assign_to_a_new_commit_for_testing(&[certificate.key()]);
433 authority.execution_scheduler().enqueue(
434 vec![(
435 VerifiedExecutableTransaction::new_from_certificate(certificate.clone()).into(),
436 env.clone(),
437 )],
438 &authority.epoch_store_for_testing(),
439 );
440
441 let (result, execution_error_opt) = authority.try_execute_for_test(&certificate, env)?;
442 let effects = result.inner().data().clone();
443 Ok((effects, execution_error_opt))
444}
445
446pub async fn send_consensus(
447 authority: &AuthorityState,
448 cert: &VerifiedCertificate,
449) -> AssignedVersions {
450 let transaction = SequencedConsensusTransaction::new_test(
451 ConsensusTransaction::new_certificate_message(&authority.name, cert.clone().into_inner()),
452 );
453
454 let (_, assigned_versions) = authority
455 .epoch_store_for_testing()
456 .process_consensus_transactions_for_tests(
457 vec![transaction],
458 &Arc::new(CheckpointServiceNoop {}),
459 authority.get_object_cache_reader().as_ref(),
460 &authority.metrics,
461 true,
462 authority,
463 )
464 .await
465 .unwrap();
466
467 let assigned_versions = assigned_versions
468 .into_map()
469 .remove(&cert.key())
470 .unwrap_or_default();
471
472 let certs = vec![(
473 VerifiedExecutableTransaction::new_from_certificate(cert.clone()),
474 ExecutionEnv::new().with_assigned_versions(assigned_versions.clone()),
475 )];
476
477 let epoch_store = authority.epoch_store_for_testing();
478 epoch_store.assign_to_a_new_commit_for_testing(&[cert.key()]);
479 authority
480 .execution_scheduler()
481 .enqueue_transactions(certs, &epoch_store);
482
483 assigned_versions
484}
485
486pub async fn send_consensus_no_execution(
488 authority: &AuthorityState,
489 cert: &VerifiedCertificate,
490) -> AssignedVersions {
491 let transaction = SequencedConsensusTransaction::new_test(
492 ConsensusTransaction::new_certificate_message(&authority.name, cert.clone().into_inner()),
493 );
494
495 let (_, assigned_versions) = authority
499 .epoch_store_for_testing()
500 .process_consensus_transactions_for_tests(
501 vec![transaction],
502 &Arc::new(CheckpointServiceNoop {}),
503 authority.get_object_cache_reader().as_ref(),
504 &authority.metrics,
505 true,
506 authority,
507 )
508 .await
509 .unwrap();
510 assert_eq!(assigned_versions.0.len(), 1);
511 assigned_versions
512 .into_map()
513 .remove(&cert.key())
514 .expect("the commit must have assigned versions for this certificate")
515}
516
517pub async fn send_batch_consensus_no_execution(
518 authority: &AuthorityState,
519 certificates: &[VerifiedCertificate],
520 skip_consensus_commit_prologue_in_test: bool,
521) -> (Vec<Schedulable>, AssignedTxAndVersions) {
522 let transactions = certificates
523 .iter()
524 .map(|cert| {
525 SequencedConsensusTransaction::new_test(ConsensusTransaction::new_certificate_message(
526 &authority.name,
527 cert.clone().into_inner(),
528 ))
529 })
530 .collect();
531
532 let (scheduled, assigned_versions) = authority
536 .epoch_store_for_testing()
537 .process_consensus_transactions_for_tests(
538 transactions,
539 &Arc::new(CheckpointServiceNoop {}),
540 authority.get_object_cache_reader().as_ref(),
541 &authority.metrics,
542 skip_consensus_commit_prologue_in_test,
543 authority,
544 )
545 .await
546 .unwrap();
547 (drop_attestations(scheduled), assigned_versions)
548}
549
550pub fn drop_attestations(scheduled: Vec<SchedulableAttestedTransaction>) -> Vec<Schedulable> {
553 scheduled
554 .into_iter()
555 .map(|scheduled| match scheduled {
556 Schedulable::Transaction(attested) => Schedulable::Transaction(attested.into_parts().0),
557 Schedulable::RandomnessStateUpdate(epoch, round) => {
558 Schedulable::RandomnessStateUpdate(epoch, round)
559 }
560 })
561 .collect()
562}
563
564pub fn resolve_randomness_round(
567 state: &AuthorityState,
568 epoch_store: &AuthorityPerEpochStore,
569 round: u64,
570) -> VerifiedExecutableTransaction {
571 let transaction = make_randomness_state_update(epoch_store, round);
572 state.get_cache_commit().persist_transaction(&transaction);
573 epoch_store
574 .insert_tx_key(
575 TransactionKey::RandomnessRound(epoch_store.epoch(), RandomnessRound::new(round)),
576 *transaction.digest(),
577 )
578 .unwrap();
579 transaction
580}
581
582pub fn randomness_assigned_versions(
583 epoch_store: &AuthorityPerEpochStore,
584) -> Vec<VersionAssignment> {
585 vec![VersionAssignment::new(
586 ObjectId::RANDOMNESS_STATE,
587 epoch_store
588 .epoch_start_config()
589 .randomness_obj_initial_shared_version(),
590 )]
591}
592
593pub fn make_randomness_state_update(
596 epoch_store: &AuthorityPerEpochStore,
597 round: u64,
598) -> VerifiedExecutableTransaction {
599 VerifiedExecutableTransaction::new_system(
600 VerifiedTransaction::new_randomness_state_update(
601 epoch_store.epoch(),
602 RandomnessRound::new(round),
603 vec![round as u8],
604 epoch_store
605 .epoch_start_config()
606 .randomness_obj_initial_shared_version(),
607 ),
608 epoch_store.epoch(),
609 )
610}