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::new(vec![], None));
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, false).await
134}
135
136pub async fn submit_and_execute_with_options(
140 authority: &AuthorityState,
141 fullnode: Option<&AuthorityState>,
142 transaction: Transaction,
143 with_shared: bool,
144) -> Result<(VerifiedExecutableTransaction, SignedTransactionEffects), SuiError> {
145 let (exec, effects, _) =
146 submit_and_execute_with_error(authority, fullnode, transaction, with_shared).await?;
147 Ok((exec, effects))
148}
149
150pub async fn submit_and_execute_with_error(
152 authority: &AuthorityState,
153 fullnode: Option<&AuthorityState>,
154 transaction: Transaction,
155 with_shared: bool,
156) -> Result<
157 (
158 VerifiedExecutableTransaction,
159 SignedTransactionEffects,
160 Option<ExecutionError>,
161 ),
162 SuiError,
163> {
164 let epoch_store = authority.load_epoch_store_one_call_per_task();
165
166 let verified_tx = vote_transaction(authority, transaction)?;
168
169 let executable =
171 VerifiedExecutableTransaction::new_from_consensus(verified_tx, epoch_store.epoch());
172
173 let assigned_versions = if with_shared {
175 let versions = authority
176 .epoch_store_for_testing()
177 .assign_shared_object_versions_for_tests(
178 authority.get_object_cache_reader().as_ref(),
179 std::slice::from_ref(&executable.clone()),
180 )?;
181 versions
182 .into_map()
183 .get(&executable.key())
184 .cloned()
185 .unwrap_or_else(|| AssignedVersions::new(vec![], None))
186 } else {
187 AssignedVersions::new(vec![], None)
188 };
189
190 let state_acc =
192 GlobalStateHasher::new_for_tests(authority.get_global_state_hash_store().clone());
193 let include_wrapped_tombstone = !authority
194 .epoch_store_for_testing()
195 .protocol_config()
196 .simplified_unwrap_then_delete();
197 let mut state =
198 state_acc.accumulate_cached_live_object_set_for_testing(include_wrapped_tombstone);
199
200 let env = ExecutionEnv::new().with_assigned_versions(assigned_versions.clone());
202 let (result, mut execution_error_opt) = authority
203 .try_execute_executable_for_test(&executable, env.clone())
204 .await;
205
206 let state_after =
208 state_acc.accumulate_cached_live_object_set_for_testing(include_wrapped_tombstone);
209 let effects_acc = state_acc.accumulate_effects(
210 &[result.inner().data().clone()],
211 epoch_store.protocol_config(),
212 );
213 state.union(&effects_acc);
214 assert_eq!(state_after.digest(), state.digest());
215
216 if let Some(fullnode) = fullnode {
218 let (_, fullnode_execution_error_opt) = fullnode
219 .try_execute_executable_for_test(&executable, env)
220 .await;
221 execution_error_opt = fullnode_execution_error_opt;
222 }
223
224 Ok((executable, result.into_inner(), execution_error_opt))
225}
226
227pub async fn enqueue_and_execute_all(
229 authority: &AuthorityState,
230 executables: Vec<(VerifiedExecutableTransaction, ExecutionEnv)>,
231) -> Result<Vec<TransactionEffects>, SuiError> {
232 authority.execution_scheduler.enqueue(
233 executables
234 .iter()
235 .map(|(exec, env)| (exec.clone().into(), env.clone()))
236 .collect(),
237 &authority.epoch_store_for_testing(),
238 );
239 let mut output = Vec::new();
240 for (exec, _) in executables {
241 let effects = authority
242 .notify_read_effects_for_testing("", *exec.digest())
243 .await;
244 output.push(effects);
245 }
246 Ok(output)
247}
248
249pub async fn submit_and_schedule(
252 authority: &AuthorityState,
253 transaction: Transaction,
254) -> Result<AssignedVersions, SuiError> {
255 let (executable, versions) = submit_to_consensus(authority, transaction).await?;
256
257 let env = ExecutionEnv::new().with_assigned_versions(versions.clone());
258 authority.execution_scheduler().enqueue_transactions(
259 vec![(executable, env)],
260 &authority.epoch_store_for_testing(),
261 );
262
263 Ok(versions)
264}
265
266pub async fn init_state_validator_with_fullnode() -> (Arc<AuthorityState>, Arc<AuthorityState>) {
267 use sui_types::crypto::get_authority_key_pair;
268
269 let validator = TestAuthorityBuilder::new().build().await;
270 let fullnode_key_pair = get_authority_key_pair().1;
271 let fullnode = TestAuthorityBuilder::new()
272 .with_keypair(&fullnode_key_pair)
273 .build()
274 .await;
275 (validator, fullnode)
276}
277
278pub async fn init_state_with_committee(
279 genesis: &Genesis,
280 authority_key: &AuthorityKeyPair,
281) -> Arc<AuthorityState> {
282 TestAuthorityBuilder::new()
283 .with_genesis_and_keypair(genesis, authority_key)
284 .build()
285 .await
286}
287
288pub async fn init_state_with_ids<I: IntoIterator<Item = (SuiAddress, ObjectID)>>(
289 objects: I,
290) -> Arc<AuthorityState> {
291 let state = TestAuthorityBuilder::new().build().await;
292 for (address, object_id) in objects {
293 let obj = Object::with_id_owner_for_testing(object_id, address);
294 state.insert_genesis_object(obj).await;
295 }
296 state
297}
298
299pub async fn init_state_with_ids_and_versions<
300 I: IntoIterator<Item = (SuiAddress, ObjectID, SequenceNumber)>,
301>(
302 objects: I,
303) -> Arc<AuthorityState> {
304 let state = TestAuthorityBuilder::new().build().await;
305 for (address, object_id, version) in objects {
306 let obj = Object::with_id_owner_version_for_testing(
307 object_id,
308 version,
309 Owner::AddressOwner(address),
310 );
311 state.insert_genesis_object(obj).await;
312 }
313 state
314}
315
316pub async fn init_state_with_objects<I: IntoIterator<Item = Object>>(
317 objects: I,
318) -> Arc<AuthorityState> {
319 let dir = tempfile::TempDir::new().unwrap();
320 let network_config = sui_swarm_config::network_config_builder::ConfigBuilder::new(&dir).build();
321 let genesis = network_config.genesis;
322 let keypair = network_config.validator_configs[0]
323 .protocol_key_pair()
324 .copy();
325 init_state_with_objects_and_committee(objects, &genesis, &keypair).await
326}
327
328pub async fn init_state_with_objects_and_committee<I: IntoIterator<Item = Object>>(
329 objects: I,
330 genesis: &Genesis,
331 authority_key: &AuthorityKeyPair,
332) -> Arc<AuthorityState> {
333 let state = init_state_with_committee(genesis, authority_key).await;
334 for o in objects {
335 state.insert_genesis_object(o).await;
336 }
337 state
338}
339
340pub async fn init_state_with_object_id(
341 address: SuiAddress,
342 object: ObjectID,
343) -> Arc<AuthorityState> {
344 init_state_with_ids(std::iter::once((address, object))).await
345}
346
347pub async fn init_state_with_ids_and_expensive_checks<
348 I: IntoIterator<Item = (SuiAddress, ObjectID)>,
349>(
350 objects: I,
351 config: ExpensiveSafetyCheckConfig,
352) -> Arc<AuthorityState> {
353 let state = TestAuthorityBuilder::new()
354 .with_expensive_safety_checks(config)
355 .build()
356 .await;
357 for (address, object_id) in objects {
358 let obj = Object::with_id_owner_for_testing(object_id, address);
359 state.insert_genesis_object(obj).await;
360 }
361 state
362}
363
364pub fn init_transfer_transaction(
365 authority_state: &AuthorityState,
366 sender: SuiAddress,
367 secret: &AccountKeyPair,
368 recipient: SuiAddress,
369 object_ref: ObjectRef,
370 gas_object_ref: ObjectRef,
371 gas_budget: u64,
372 gas_price: u64,
373) -> VerifiedTransaction {
374 let data = TransactionData::new_transfer(
375 recipient,
376 FullObjectRef::from_fastpath_ref(object_ref),
377 sender,
378 gas_object_ref,
379 gas_budget,
380 gas_price,
381 );
382 let tx = to_sender_signed_transaction(data, secret);
383 authority_state
384 .epoch_store_for_testing()
385 .verify_transaction_require_no_aliases(tx)
386 .unwrap()
387 .into_tx()
388}
389
390#[cfg(test)]
391pub async fn submit_batch_to_consensus<C>(
392 authority: &AuthorityState,
393 transactions: &[Transaction],
394 consensus_handler: &mut crate::consensus_handler::ConsensusHandler<C>,
395 captured_transactions: &crate::consensus_test_utils::CapturedTransactions,
396) -> (Vec<Schedulable>, HashMap<TransactionKey, AssignedVersions>)
397where
398 C: crate::checkpoints::CheckpointServiceNotify + Send + Sync + 'static,
399{
400 use crate::consensus_test_utils::TestConsensusCommit;
401 use sui_types::messages_consensus::ConsensusTransaction;
402 use sui_types::transaction::PlainTransactionWithClaims;
403
404 let consensus_transactions: Vec<ConsensusTransaction> = transactions
405 .iter()
406 .map(|tx| {
407 ConsensusTransaction::new_user_transaction_v2_message(
408 &authority.name,
409 PlainTransactionWithClaims::no_aliases(tx.clone()),
410 )
411 })
412 .collect();
413
414 let epoch_store = authority.epoch_store_for_testing();
415 let round = epoch_store.get_highest_pending_checkpoint_height() + 1;
416 let timestamp_ms = epoch_store.epoch_start_state().epoch_start_timestamp_ms();
417 let sub_dag_index = 0;
418
419 let commit =
420 TestConsensusCommit::new(consensus_transactions, round, timestamp_ms, sub_dag_index);
421
422 consensus_handler
423 .handle_consensus_commit_for_test(commit)
424 .await;
425
426 tokio::time::sleep(std::time::Duration::from_millis(100)).await;
427
428 let (scheduled_txns, assigned_tx_and_versions) = {
429 let mut captured = captured_transactions.lock();
430 assert!(
431 !captured.is_empty(),
432 "Expected transactions to be scheduled"
433 );
434 let (paired, _) = captured.remove(0);
435 let (schedulables, versions): (Vec<_>, Vec<_>) = paired.into_iter().unzip();
436 let assigned_versions = schedulables
437 .iter()
438 .map(|s| s.key())
439 .zip_debug_eq(versions)
440 .collect();
441 (schedulables, assigned_versions)
442 };
443
444 (scheduled_txns, assigned_tx_and_versions)
445}
446
447pub async fn assign_versions_and_schedule(
448 authority: &AuthorityState,
449 executable: &VerifiedExecutableTransaction,
450) -> AssignedVersions {
451 let assigned_versions = authority
452 .epoch_store_for_testing()
453 .assign_shared_object_versions_for_tests(
454 authority.get_object_cache_reader().as_ref(),
455 std::slice::from_ref(&executable.clone()),
456 )
457 .unwrap();
458
459 let versions = assigned_versions
460 .into_map()
461 .get(&executable.key())
462 .cloned()
463 .unwrap_or_else(|| AssignedVersions::new(vec![], None));
464
465 let env = ExecutionEnv::new().with_assigned_versions(versions.clone());
466 authority.execution_scheduler().enqueue_transactions(
467 vec![(executable.clone(), env)],
468 &authority.epoch_store_for_testing(),
469 );
470
471 versions
472}
473
474pub async fn assign_shared_object_versions(
477 authority: &AuthorityState,
478 executable: &VerifiedExecutableTransaction,
479) -> AssignedVersions {
480 let assigned_versions = authority
481 .epoch_store_for_testing()
482 .assign_shared_object_versions_for_tests(
483 authority.get_object_cache_reader().as_ref(),
484 std::slice::from_ref(&executable.clone()),
485 )
486 .unwrap();
487
488 assigned_versions
489 .into_map()
490 .get(&executable.key())
491 .cloned()
492 .unwrap_or_else(|| AssignedVersions::new(vec![], None))
493}