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