1pub mod args;
9pub mod offchain_state;
10pub mod programmable_transaction_test_parser;
11mod simulator_persisted_store;
12pub mod test_adapter;
13
14use std::{path::Path, sync::Arc};
15
16use iota_core::authority::{
17 AuthorityState, authority_per_epoch_store::CertLockGuard,
18 authority_test_utils::send_and_confirm_transaction_with_execution_error,
19};
20use iota_json_rpc::authority_state::StateRead;
21use iota_json_rpc_types::{DevInspectResults, DryRunTransactionBlockResponse, EventFilter};
22use iota_storage::key_value_store::TransactionKeyValueStore;
23use iota_types::{
24 base_types::{IotaAddress, ObjectID, VersionNumber},
25 committee::EpochId,
26 digests::{TransactionDigest, TransactionEventsDigest},
27 effects::{TransactionEffects, TransactionEvents},
28 error::{ExecutionError, IotaError, IotaResult},
29 event::Event,
30 executable_transaction::{ExecutableTransaction, VerifiedExecutableTransaction},
31 iota_system_state::{
32 IotaSystemStateTrait, epoch_start_iota_system_state::EpochStartSystemStateTrait,
33 iota_system_state_summary::IotaSystemStateSummary,
34 },
35 messages_checkpoint::{CheckpointContentsDigest, VerifiedCheckpoint},
36 object::Object,
37 storage::{ObjectStore, ReadStore},
38 transaction::{
39 InputObjects, Transaction, TransactionData, TransactionDataAPI, TransactionKind,
40 },
41};
42pub use move_transactional_test_runner::framework::{
43 create_adapter, run_tasks_with_adapter, run_test_impl,
44};
45use rand::rngs::StdRng;
46use simulacrum::{Simulacrum, SimulatorStore};
47use simulator_persisted_store::PersistedStore;
48use test_adapter::{IotaTestAdapter, PRE_COMPILED};
49
50#[cfg_attr(not(msim), tokio::main)]
51#[cfg_attr(msim, msim::main)]
52pub async fn run_test(path: &Path) -> Result<(), Box<dyn std::error::Error>> {
53 let (_guard, _filter_handle) = telemetry_subscribers::TelemetryConfig::new()
54 .with_env()
55 .init();
56 run_test_impl::<IotaTestAdapter>(path, Some(std::sync::Arc::new(PRE_COMPILED.clone()))).await?;
57 Ok(())
58}
59
60pub struct ValidatorWithFullnode {
61 pub validator: Arc<AuthorityState>,
62 pub fullnode: Arc<AuthorityState>,
63 pub kv_store: Arc<TransactionKeyValueStore>,
64}
65
66#[async_trait::async_trait]
68pub trait TransactionalAdapter: Send + Sync + ReadStore {
69 async fn execute_txn(
70 &mut self,
71 transaction: Transaction,
72 ) -> anyhow::Result<(TransactionEffects, Option<ExecutionError>)>;
73
74 async fn read_input_objects(&self, transaction: Transaction) -> IotaResult<InputObjects>;
75
76 fn prepare_txn(
77 &self,
78 transaction: Transaction,
79 input_objects: InputObjects,
80 ) -> anyhow::Result<(TransactionEffects, Option<ExecutionError>)>;
81
82 async fn create_checkpoint(&mut self) -> anyhow::Result<VerifiedCheckpoint>;
83
84 async fn advance_clock(
85 &mut self,
86 duration: std::time::Duration,
87 ) -> anyhow::Result<TransactionEffects>;
88
89 async fn advance_epoch(&mut self) -> anyhow::Result<()>;
90
91 async fn request_gas(
92 &mut self,
93 address: IotaAddress,
94 amount: u64,
95 ) -> anyhow::Result<TransactionEffects>;
96
97 async fn dry_run_transaction_block(
98 &self,
99 transaction_block: TransactionData,
100 transaction_digest: TransactionDigest,
101 ) -> IotaResult<DryRunTransactionBlockResponse>;
102
103 async fn dev_inspect_transaction_block(
104 &self,
105 sender: IotaAddress,
106 transaction_kind: TransactionKind,
107 gas_price: Option<u64>,
108 ) -> IotaResult<DevInspectResults>;
109
110 async fn query_tx_events_asc(
111 &self,
112 tx_digest: &TransactionDigest,
113 limit: usize,
114 ) -> IotaResult<Vec<Event>>;
115
116 async fn get_active_validator_addresses(&self) -> IotaResult<Vec<IotaAddress>>;
117}
118
119#[async_trait::async_trait]
120impl TransactionalAdapter for ValidatorWithFullnode {
121 async fn execute_txn(
122 &mut self,
123 transaction: Transaction,
124 ) -> anyhow::Result<(TransactionEffects, Option<ExecutionError>)> {
125 let with_shared = transaction
126 .data()
127 .intent_message()
128 .value
129 .contains_shared_object();
130 let (_, effects, execution_error) = send_and_confirm_transaction_with_execution_error(
131 &self.validator,
132 Some(&self.fullnode),
133 transaction,
134 with_shared,
135 false,
136 )
137 .await?;
138 Ok((effects.into_data(), execution_error))
139 }
140
141 async fn read_input_objects(&self, transaction: Transaction) -> IotaResult<InputObjects> {
142 let tx = VerifiedExecutableTransaction::new_unchecked(
143 ExecutableTransaction::new_from_data_and_sig(
144 transaction.data().clone(),
145 iota_types::executable_transaction::CertificateProof::Checkpoint(0, 0),
146 ),
147 );
148
149 let epoch_store = self.validator.load_epoch_store_one_call_per_task().clone();
150 self.validator.read_objects_for_execution(
151 &CertLockGuard::guard_for_tests(),
152 &tx,
153 &epoch_store,
154 )
155 }
156
157 fn prepare_txn(
158 &self,
159 transaction: Transaction,
160 input_objects: InputObjects,
161 ) -> anyhow::Result<(TransactionEffects, Option<ExecutionError>)> {
162 let tx = VerifiedExecutableTransaction::new_unchecked(
163 ExecutableTransaction::new_from_data_and_sig(
164 transaction.data().clone(),
165 iota_types::executable_transaction::CertificateProof::Checkpoint(0, 0),
166 ),
167 );
168
169 let epoch_store = self.validator.load_epoch_store_one_call_per_task().clone();
170 let (_, effects, error) =
171 self.validator
172 .prepare_certificate_for_benchmark(&tx, input_objects, &epoch_store)?;
173 Ok((effects, error))
174 }
175
176 async fn dry_run_transaction_block(
177 &self,
178 transaction_block: TransactionData,
179 transaction_digest: TransactionDigest,
180 ) -> IotaResult<DryRunTransactionBlockResponse> {
181 self.fullnode
182 .dry_exec_transaction(transaction_block, transaction_digest)
183 .map(|result| result.0)
184 }
185
186 async fn dev_inspect_transaction_block(
187 &self,
188 sender: IotaAddress,
189 transaction_kind: TransactionKind,
190 gas_price: Option<u64>,
191 ) -> IotaResult<DevInspectResults> {
192 self.fullnode
193 .dev_inspect_transaction_block(
194 sender,
195 transaction_kind,
196 gas_price,
197 None,
198 None,
199 None,
200 None,
201 None,
202 )
203 .await
204 }
205
206 async fn query_tx_events_asc(
207 &self,
208 tx_digest: &TransactionDigest,
209 limit: usize,
210 ) -> IotaResult<Vec<Event>> {
211 Ok(self
212 .validator
213 .query_events(
214 &self.kv_store,
215 EventFilter::Transaction(*tx_digest),
216 None,
217 limit,
218 false,
219 )
220 .await
221 .unwrap_or_default()
222 .into_iter()
223 .map(|iota_event| iota_event.into())
224 .collect())
225 }
226
227 async fn create_checkpoint(&mut self) -> anyhow::Result<VerifiedCheckpoint> {
228 unimplemented!("create_checkpoint not supported")
229 }
230
231 async fn advance_clock(
232 &mut self,
233 _duration: std::time::Duration,
234 ) -> anyhow::Result<TransactionEffects> {
235 unimplemented!("advance_clock not supported")
236 }
237
238 async fn advance_epoch(&mut self) -> anyhow::Result<()> {
239 self.validator.reconfigure_for_testing().await;
240 self.fullnode.reconfigure_for_testing().await;
241 Ok(())
242 }
243
244 async fn request_gas(
245 &mut self,
246 _address: IotaAddress,
247 _amount: u64,
248 ) -> anyhow::Result<TransactionEffects> {
249 unimplemented!("request_gas not supported")
250 }
251
252 async fn get_active_validator_addresses(&self) -> IotaResult<Vec<IotaAddress>> {
253 let system_state_summary = self
254 .fullnode
255 .get_system_state()
256 .map_err(|e| {
257 IotaError::IotaSystemStateRead(format!(
258 "Failed to get system state from fullnode: {e}"
259 ))
260 })?
261 .into_iota_system_state_summary();
262 let active_validators = match system_state_summary {
263 IotaSystemStateSummary::V1(inner) => inner.active_validators,
264 IotaSystemStateSummary::V2(inner) => inner.active_validators,
265 _ => unimplemented!(),
266 };
267
268 Ok(active_validators
269 .iter()
270 .map(|x| x.iota_address)
271 .collect::<Vec<_>>())
272 }
273}
274
275impl ReadStore for ValidatorWithFullnode {
276 fn try_get_committee(
277 &self,
278 _epoch: EpochId,
279 ) -> iota_types::storage::error::Result<Option<Arc<iota_types::committee::Committee>>> {
280 todo!()
281 }
282
283 fn try_get_latest_epoch_id(&self) -> iota_types::storage::error::Result<EpochId> {
284 Ok(self.validator.epoch_store_for_testing().epoch())
285 }
286
287 fn try_get_latest_checkpoint(&self) -> iota_types::storage::error::Result<VerifiedCheckpoint> {
288 let sequence_number = self
289 .validator
290 .get_latest_checkpoint_sequence_number()
291 .unwrap();
292 self.try_get_checkpoint_by_sequence_number(sequence_number)
293 .map(|c| c.unwrap())
294 }
295
296 fn try_get_highest_verified_checkpoint(
297 &self,
298 ) -> iota_types::storage::error::Result<VerifiedCheckpoint> {
299 todo!()
300 }
301
302 fn try_get_highest_synced_checkpoint(
303 &self,
304 ) -> iota_types::storage::error::Result<VerifiedCheckpoint> {
305 todo!()
306 }
307
308 fn try_get_lowest_available_checkpoint(
309 &self,
310 ) -> iota_types::storage::error::Result<iota_types::messages_checkpoint::CheckpointSequenceNumber>
311 {
312 todo!()
313 }
314
315 fn try_get_checkpoint_by_digest(
316 &self,
317 _digest: &iota_types::messages_checkpoint::CheckpointDigest,
318 ) -> iota_types::storage::error::Result<Option<VerifiedCheckpoint>> {
319 todo!()
320 }
321
322 fn try_get_checkpoint_by_sequence_number(
323 &self,
324 sequence_number: iota_types::messages_checkpoint::CheckpointSequenceNumber,
325 ) -> iota_types::storage::error::Result<Option<VerifiedCheckpoint>> {
326 self.validator
327 .get_checkpoint_store()
328 .get_checkpoint_by_sequence_number(sequence_number)
329 .map_err(iota_types::storage::error::Error::custom)
330 }
331
332 fn try_get_checkpoint_contents_by_digest(
333 &self,
334 digest: &CheckpointContentsDigest,
335 ) -> iota_types::storage::error::Result<
336 Option<iota_types::messages_checkpoint::CheckpointContents>,
337 > {
338 self.validator
339 .get_checkpoint_store()
340 .get_checkpoint_contents(digest)
341 .map_err(iota_types::storage::error::Error::custom)
342 }
343
344 fn try_get_checkpoint_contents_by_sequence_number(
345 &self,
346 _sequence_number: iota_types::messages_checkpoint::CheckpointSequenceNumber,
347 ) -> iota_types::storage::error::Result<
348 Option<iota_types::messages_checkpoint::CheckpointContents>,
349 > {
350 todo!()
351 }
352
353 fn try_get_transaction(
354 &self,
355 tx_digest: &TransactionDigest,
356 ) -> iota_types::storage::error::Result<Option<Arc<iota_types::transaction::VerifiedTransaction>>>
357 {
358 self.validator
359 .get_transaction_cache_reader()
360 .try_get_transaction_block(tx_digest)
361 .map_err(iota_types::storage::error::Error::custom)
362 }
363
364 fn try_get_transaction_effects(
365 &self,
366 tx_digest: &TransactionDigest,
367 ) -> iota_types::storage::error::Result<Option<TransactionEffects>> {
368 self.validator
369 .get_transaction_cache_reader()
370 .try_get_executed_effects(tx_digest)
371 .map_err(iota_types::storage::error::Error::custom)
372 }
373
374 fn try_get_events(
375 &self,
376 event_digest: &TransactionEventsDigest,
377 ) -> iota_types::storage::error::Result<Option<TransactionEvents>> {
378 self.validator
379 .get_transaction_cache_reader()
380 .try_get_events(event_digest)
381 .map_err(iota_types::storage::error::Error::custom)
382 }
383
384 fn try_get_full_checkpoint_contents_by_sequence_number(
385 &self,
386 _sequence_number: iota_types::messages_checkpoint::CheckpointSequenceNumber,
387 ) -> iota_types::storage::error::Result<
388 Option<iota_types::messages_checkpoint::FullCheckpointContents>,
389 > {
390 todo!()
391 }
392
393 fn try_get_full_checkpoint_contents(
394 &self,
395 _digest: &CheckpointContentsDigest,
396 ) -> iota_types::storage::error::Result<
397 Option<iota_types::messages_checkpoint::FullCheckpointContents>,
398 > {
399 todo!()
400 }
401}
402
403impl ObjectStore for ValidatorWithFullnode {
404 fn try_get_object(
405 &self,
406 object_id: &ObjectID,
407 ) -> Result<Option<Object>, iota_types::storage::error::Error> {
408 self.validator.get_object_store().try_get_object(object_id)
409 }
410
411 fn try_get_object_by_key(
412 &self,
413 object_id: &ObjectID,
414 version: VersionNumber,
415 ) -> Result<Option<Object>, iota_types::storage::error::Error> {
416 self.validator
417 .get_object_store()
418 .try_get_object_by_key(object_id, version)
419 }
420}
421
422#[async_trait::async_trait]
423impl TransactionalAdapter for Simulacrum<StdRng, PersistedStore> {
424 async fn execute_txn(
425 &mut self,
426 transaction: Transaction,
427 ) -> anyhow::Result<(TransactionEffects, Option<ExecutionError>)> {
428 Ok(self.execute_transaction(transaction)?)
429 }
430
431 async fn read_input_objects(&self, _transaction: Transaction) -> IotaResult<InputObjects> {
432 unimplemented!("read_input_objects not supported in simulator mode")
433 }
434
435 fn prepare_txn(
436 &self,
437 _transaction: Transaction,
438 _input_objects: InputObjects,
439 ) -> anyhow::Result<(TransactionEffects, Option<ExecutionError>)> {
440 unimplemented!("prepare_txn not supported in simulator mode")
441 }
442
443 async fn dev_inspect_transaction_block(
444 &self,
445 _sender: IotaAddress,
446 _transaction_kind: TransactionKind,
447 _gas_price: Option<u64>,
448 ) -> IotaResult<DevInspectResults> {
449 unimplemented!("dev_inspect_transaction_block not supported in simulator mode")
450 }
451
452 async fn dry_run_transaction_block(
453 &self,
454 _transaction_block: TransactionData,
455 _transaction_digest: TransactionDigest,
456 ) -> IotaResult<DryRunTransactionBlockResponse> {
457 unimplemented!("dry_run_transaction_block not supported in simulator mode")
458 }
459
460 async fn query_tx_events_asc(
461 &self,
462 tx_digest: &TransactionDigest,
463 _limit: usize,
464 ) -> IotaResult<Vec<Event>> {
465 Ok(self
466 .store()
467 .get_transaction_events_by_tx_digest(tx_digest)
468 .map(|x| x.data)
469 .unwrap_or_default())
470 }
471
472 async fn create_checkpoint(&mut self) -> anyhow::Result<VerifiedCheckpoint> {
473 Ok(self.create_checkpoint())
474 }
475
476 async fn advance_clock(
477 &mut self,
478 duration: std::time::Duration,
479 ) -> anyhow::Result<TransactionEffects> {
480 Ok(self.advance_clock(duration))
481 }
482
483 async fn advance_epoch(&mut self) -> anyhow::Result<()> {
484 self.advance_epoch();
485 Ok(())
486 }
487
488 async fn request_gas(
489 &mut self,
490 address: IotaAddress,
491 amount: u64,
492 ) -> anyhow::Result<TransactionEffects> {
493 self.request_gas(address, amount)
494 }
495
496 async fn get_active_validator_addresses(&self) -> IotaResult<Vec<IotaAddress>> {
497 Ok(self.epoch_start_state().get_validator_addresses())
501 }
502}