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