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