1use fastcrypto::hash::MultisetHash;
6use fastcrypto::traits::KeyPair;
7use sui_types::base_types::FullObjectRef;
8use sui_types::crypto::{AccountKeyPair, AuthorityKeyPair};
9use sui_types::utils::to_sender_signed_transaction;
10
11use super::shared_object_version_manager::AssignedVersions;
12use super::test_authority_builder::TestAuthorityBuilder;
13use super::*;
14
15#[cfg(test)]
16use super::shared_object_version_manager::Schedulable;
17#[cfg(test)]
18use mysten_common::ZipDebugEqIteratorExt;
19#[cfg(test)]
20use std::collections::HashMap;
21#[cfg(test)]
22use sui_types::transaction::TransactionKey;
23
24pub fn vote_transaction(
41 authority: &AuthorityState,
42 transaction: Transaction,
43) -> Result<VerifiedTransaction, SuiError> {
44 let epoch_store = authority.load_epoch_store_one_call_per_task();
45 transaction.validity_check(&epoch_store.tx_validity_check_context())?;
46 let verified_tx = epoch_store
47 .verify_transaction_require_no_aliases(transaction)?
48 .into_tx();
49
50 authority.handle_vote_transaction(&epoch_store, verified_tx.clone())?;
52
53 Ok(verified_tx)
54}
55
56pub fn create_executable_transaction(
60 authority: &AuthorityState,
61 transaction: Transaction,
62) -> Result<VerifiedExecutableTransaction, SuiError> {
63 let epoch_store = authority.load_epoch_store_one_call_per_task();
64 let verified_tx = vote_transaction(authority, transaction)?;
65 Ok(VerifiedExecutableTransaction::new_from_consensus(
66 verified_tx,
67 epoch_store.epoch(),
68 ))
69}
70
71pub async fn submit_to_consensus(
78 authority: &AuthorityState,
79 transaction: Transaction,
80) -> Result<(VerifiedExecutableTransaction, AssignedVersions), SuiError> {
81 let epoch_store = authority.load_epoch_store_one_call_per_task();
82
83 let verified_tx = vote_transaction(authority, transaction)?;
85
86 let executable =
88 VerifiedExecutableTransaction::new_from_consensus(verified_tx, epoch_store.epoch());
89
90 let assigned_versions = authority
92 .epoch_store_for_testing()
93 .assign_shared_object_versions_for_tests(
94 authority.get_object_cache_reader().as_ref(),
95 std::slice::from_ref(&executable.clone()),
96 )?;
97
98 let versions = assigned_versions
99 .into_map()
100 .get(&executable.key())
101 .cloned()
102 .unwrap_or_else(AssignedVersions::empty);
103
104 Ok((executable, versions))
105}
106
107pub async fn execute_from_consensus(
109 authority: &AuthorityState,
110 executable: VerifiedExecutableTransaction,
111 assigned_versions: AssignedVersions,
112) -> (TransactionEffects, Option<ExecutionError>) {
113 let env = ExecutionEnv::new().with_assigned_versions(assigned_versions);
114 authority.execution_scheduler.enqueue(
115 vec![(executable.clone().into(), env.clone())],
116 &authority.epoch_store_for_testing(),
117 );
118
119 let (result, execution_error_opt) = authority
120 .try_execute_executable_for_test(&executable, env)
121 .await;
122 let effects = result.inner().data().clone();
123 (effects, execution_error_opt)
124}
125
126pub async fn submit_and_execute(
130 authority: &AuthorityState,
131 transaction: Transaction,
132) -> Result<(VerifiedExecutableTransaction, SignedTransactionEffects), SuiError> {
133 submit_and_execute_with_options(authority, None, transaction).await
134}
135
136pub async fn submit_and_execute_with_options(
139 authority: &AuthorityState,
140 fullnode: Option<&AuthorityState>,
141 transaction: Transaction,
142) -> Result<(VerifiedExecutableTransaction, SignedTransactionEffects), SuiError> {
143 let (exec, effects, _) =
144 submit_and_execute_with_error(authority, fullnode, transaction).await?;
145 Ok((exec, effects))
146}
147
148pub async fn submit_and_execute_with_error(
150 authority: &AuthorityState,
151 fullnode: Option<&AuthorityState>,
152 transaction: Transaction,
153) -> Result<
154 (
155 VerifiedExecutableTransaction,
156 SignedTransactionEffects,
157 Option<ExecutionError>,
158 ),
159 SuiError,
160> {
161 let epoch_store = authority.load_epoch_store_one_call_per_task();
162
163 let verified_tx = vote_transaction(authority, transaction)?;
165
166 let executable =
168 VerifiedExecutableTransaction::new_from_consensus(verified_tx, epoch_store.epoch());
169
170 let versions = authority
174 .epoch_store_for_testing()
175 .assign_shared_object_versions_for_tests(
176 authority.get_object_cache_reader().as_ref(),
177 std::slice::from_ref(&executable.clone()),
178 )?;
179 let assigned_versions = versions
180 .into_map()
181 .get(&executable.key())
182 .cloned()
183 .unwrap_or_else(AssignedVersions::empty);
184
185 let state_acc =
187 GlobalStateHasher::new_for_tests(authority.get_global_state_hash_store().clone());
188 let include_wrapped_tombstone = !authority
189 .epoch_store_for_testing()
190 .protocol_config()
191 .simplified_unwrap_then_delete();
192 let mut state =
193 state_acc.accumulate_cached_live_object_set_for_testing(include_wrapped_tombstone);
194
195 let env = ExecutionEnv::new().with_assigned_versions(assigned_versions.clone());
197 let (result, mut execution_error_opt) = authority
198 .try_execute_executable_for_test(&executable, env.clone())
199 .await;
200
201 let state_after =
203 state_acc.accumulate_cached_live_object_set_for_testing(include_wrapped_tombstone);
204 let effects_acc = state_acc.accumulate_effects(
205 &[result.inner().data().clone()],
206 epoch_store.protocol_config(),
207 );
208 state.union(&effects_acc);
209 assert_eq!(state_after.digest(), state.digest());
210
211 if let Some(fullnode) = fullnode {
213 let (_, fullnode_execution_error_opt) = fullnode
214 .try_execute_executable_for_test(&executable, env)
215 .await;
216 execution_error_opt = fullnode_execution_error_opt;
217 }
218
219 Ok((executable, result.into_inner(), execution_error_opt))
220}
221
222pub async fn enqueue_and_execute_all(
224 authority: &AuthorityState,
225 executables: Vec<(VerifiedExecutableTransaction, ExecutionEnv)>,
226) -> Result<Vec<TransactionEffects>, SuiError> {
227 authority.execution_scheduler.enqueue(
228 executables
229 .iter()
230 .map(|(exec, env)| (exec.clone().into(), env.clone()))
231 .collect(),
232 &authority.epoch_store_for_testing(),
233 );
234 let mut output = Vec::new();
235 for (exec, _) in executables {
236 let effects = authority
237 .notify_read_effects_for_testing("", *exec.digest())
238 .await;
239 output.push(effects);
240 }
241 Ok(output)
242}
243
244pub async fn submit_and_schedule(
247 authority: &AuthorityState,
248 transaction: Transaction,
249) -> Result<AssignedVersions, SuiError> {
250 let (executable, versions) = submit_to_consensus(authority, transaction).await?;
251
252 let env = ExecutionEnv::new().with_assigned_versions(versions.clone());
253 authority.execution_scheduler().enqueue_transactions(
254 vec![(executable, env)],
255 &authority.epoch_store_for_testing(),
256 );
257
258 Ok(versions)
259}
260
261pub async fn init_state_validator_with_fullnode() -> (Arc<AuthorityState>, Arc<AuthorityState>) {
262 use sui_types::crypto::get_authority_key_pair;
263
264 let validator = TestAuthorityBuilder::new().build().await;
265 let fullnode_key_pair = get_authority_key_pair().1;
266 let fullnode = TestAuthorityBuilder::new()
267 .with_keypair(&fullnode_key_pair)
268 .build()
269 .await;
270 (validator, fullnode)
271}
272
273pub async fn init_state_with_committee(
274 genesis: &Genesis,
275 authority_key: &AuthorityKeyPair,
276) -> Arc<AuthorityState> {
277 TestAuthorityBuilder::new()
278 .with_genesis_and_keypair(genesis, authority_key)
279 .build()
280 .await
281}
282
283pub async fn init_state_with_ids<I: IntoIterator<Item = (SuiAddress, ObjectID)>>(
284 objects: I,
285) -> Arc<AuthorityState> {
286 let state = TestAuthorityBuilder::new().build().await;
287 for (address, object_id) in objects {
288 let obj = Object::with_id_owner_for_testing(object_id, address);
289 state.insert_genesis_object(obj);
290 }
291 state
292}
293
294pub async fn init_state_with_ids_and_versions<
295 I: IntoIterator<Item = (SuiAddress, ObjectID, SequenceNumber)>,
296>(
297 objects: I,
298) -> Arc<AuthorityState> {
299 let state = TestAuthorityBuilder::new().build().await;
300 for (address, object_id, version) in objects {
301 let obj = Object::with_id_owner_version_for_testing(
302 object_id,
303 version,
304 Owner::AddressOwner(address),
305 );
306 state.insert_genesis_object(obj);
307 }
308 state
309}
310
311pub async fn init_state_with_objects<I: IntoIterator<Item = Object>>(
312 objects: I,
313) -> Arc<AuthorityState> {
314 let dir = tempfile::TempDir::new().unwrap();
315 let network_config = sui_swarm_config::network_config_builder::ConfigBuilder::new(&dir).build();
316 let genesis = network_config.genesis;
317 let keypair = network_config.validator_configs[0]
318 .protocol_key_pair()
319 .copy();
320 init_state_with_objects_and_committee(objects, &genesis, &keypair).await
321}
322
323pub async fn init_state_with_objects_and_committee<I: IntoIterator<Item = Object>>(
324 objects: I,
325 genesis: &Genesis,
326 authority_key: &AuthorityKeyPair,
327) -> Arc<AuthorityState> {
328 let state = init_state_with_committee(genesis, authority_key).await;
329 for o in objects {
330 state.insert_genesis_object(o);
331 }
332 state
333}
334
335pub async fn init_state_with_object_id(
336 address: SuiAddress,
337 object: ObjectID,
338) -> Arc<AuthorityState> {
339 init_state_with_ids(std::iter::once((address, object))).await
340}
341
342pub async fn init_state_with_ids_and_expensive_checks<
343 I: IntoIterator<Item = (SuiAddress, ObjectID)>,
344>(
345 objects: I,
346 config: ExpensiveSafetyCheckConfig,
347) -> Arc<AuthorityState> {
348 let state = TestAuthorityBuilder::new()
349 .with_expensive_safety_checks(config)
350 .build()
351 .await;
352 for (address, object_id) in objects {
353 let obj = Object::with_id_owner_for_testing(object_id, address);
354 state.insert_genesis_object(obj);
355 }
356 state
357}
358
359pub fn init_transfer_transaction(
360 authority_state: &AuthorityState,
361 sender: SuiAddress,
362 secret: &AccountKeyPair,
363 recipient: SuiAddress,
364 object_ref: ObjectRef,
365 gas_object_ref: ObjectRef,
366 gas_budget: u64,
367 gas_price: u64,
368) -> VerifiedTransaction {
369 let data = TransactionData::new_transfer(
370 recipient,
371 FullObjectRef::from_fastpath_ref(object_ref),
372 sender,
373 gas_object_ref,
374 gas_budget,
375 gas_price,
376 );
377 let tx = to_sender_signed_transaction(data, secret);
378 authority_state
379 .epoch_store_for_testing()
380 .verify_transaction_require_no_aliases(tx)
381 .unwrap()
382 .into_tx()
383}
384
385#[cfg(test)]
386pub async fn submit_batch_to_consensus<C>(
387 authority: &AuthorityState,
388 transactions: &[Transaction],
389 consensus_handler: &mut crate::consensus_handler::ConsensusHandler<C>,
390 captured_transactions: &crate::consensus_test_utils::CapturedTransactions,
391) -> (Vec<Schedulable>, HashMap<TransactionKey, AssignedVersions>)
392where
393 C: crate::checkpoints::CheckpointServiceNotify + Send + Sync + 'static,
394{
395 use crate::consensus_test_utils::TestConsensusCommit;
396 use sui_types::messages_consensus::ConsensusTransaction;
397 use sui_types::transaction::PlainTransactionWithClaims;
398
399 let consensus_transactions: Vec<ConsensusTransaction> = transactions
400 .iter()
401 .map(|tx| {
402 ConsensusTransaction::new_user_transaction_v2_message(
403 &authority.name,
404 PlainTransactionWithClaims::no_aliases(tx.clone()),
405 )
406 })
407 .collect();
408
409 let epoch_store = authority.epoch_store_for_testing();
410 let round = epoch_store.get_highest_pending_checkpoint_height() + 1;
411 let timestamp_ms = epoch_store.epoch_start_state().epoch_start_timestamp_ms();
412 let sub_dag_index = 0;
413
414 let commit =
415 TestConsensusCommit::new(consensus_transactions, round, timestamp_ms, sub_dag_index);
416
417 consensus_handler
418 .handle_consensus_commit_for_test(commit)
419 .await;
420
421 tokio::time::sleep(std::time::Duration::from_millis(100)).await;
422
423 let (scheduled_txns, assigned_tx_and_versions) = {
424 let mut captured = captured_transactions.lock();
425 assert!(
426 !captured.is_empty(),
427 "Expected transactions to be scheduled"
428 );
429 let (paired, _) = captured.remove(0);
430 let (schedulables, versions): (Vec<_>, Vec<_>) = paired.into_iter().unzip();
431 let assigned_versions = schedulables
432 .iter()
433 .map(|s| s.key())
434 .zip_debug_eq(versions)
435 .collect();
436 (schedulables, assigned_versions)
437 };
438
439 (scheduled_txns, assigned_tx_and_versions)
440}
441
442pub async fn assign_versions_and_schedule(
443 authority: &AuthorityState,
444 executable: &VerifiedExecutableTransaction,
445) -> AssignedVersions {
446 let assigned_versions = authority
447 .epoch_store_for_testing()
448 .assign_shared_object_versions_for_tests(
449 authority.get_object_cache_reader().as_ref(),
450 std::slice::from_ref(&executable.clone()),
451 )
452 .unwrap();
453
454 let versions = assigned_versions
455 .into_map()
456 .get(&executable.key())
457 .cloned()
458 .unwrap_or_else(AssignedVersions::empty);
459
460 let env = ExecutionEnv::new().with_assigned_versions(versions.clone());
461 authority.execution_scheduler().enqueue_transactions(
462 vec![(executable.clone(), env)],
463 &authority.epoch_store_for_testing(),
464 );
465
466 versions
467}
468
469pub async fn assign_shared_object_versions(
472 authority: &AuthorityState,
473 executable: &VerifiedExecutableTransaction,
474) -> AssignedVersions {
475 let assigned_versions = authority
476 .epoch_store_for_testing()
477 .assign_shared_object_versions_for_tests(
478 authority.get_object_cache_reader().as_ref(),
479 std::slice::from_ref(&executable.clone()),
480 )
481 .unwrap();
482
483 assigned_versions
484 .into_map()
485 .get(&executable.key())
486 .cloned()
487 .unwrap_or_else(AssignedVersions::empty)
488}