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