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