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 .await
184 .map(|result| result.0)
185 }
186
187 async fn dev_inspect_transaction_block(
188 &self,
189 sender: IotaAddress,
190 transaction_kind: TransactionKind,
191 gas_price: Option<u64>,
192 ) -> IotaResult<DevInspectResults> {
193 self.fullnode
194 .dev_inspect_transaction_block(
195 sender,
196 transaction_kind,
197 gas_price,
198 None,
199 None,
200 None,
201 None,
202 None,
203 )
204 .await
205 }
206
207 async fn query_tx_events_asc(
208 &self,
209 tx_digest: &TransactionDigest,
210 limit: usize,
211 ) -> IotaResult<Vec<Event>> {
212 Ok(self
213 .validator
214 .query_events(
215 &self.kv_store,
216 EventFilter::Transaction(*tx_digest),
217 None,
218 limit,
219 false,
220 )
221 .await
222 .unwrap_or_default()
223 .into_iter()
224 .map(|iota_event| iota_event.into())
225 .collect())
226 }
227
228 async fn create_checkpoint(&mut self) -> anyhow::Result<VerifiedCheckpoint> {
229 unimplemented!("create_checkpoint not supported")
230 }
231
232 async fn advance_clock(
233 &mut self,
234 _duration: std::time::Duration,
235 ) -> anyhow::Result<TransactionEffects> {
236 unimplemented!("advance_clock not supported")
237 }
238
239 async fn advance_epoch(&mut self) -> anyhow::Result<()> {
240 self.validator.reconfigure_for_testing().await;
241 self.fullnode.reconfigure_for_testing().await;
242 Ok(())
243 }
244
245 async fn request_gas(
246 &mut self,
247 _address: IotaAddress,
248 _amount: u64,
249 ) -> anyhow::Result<TransactionEffects> {
250 unimplemented!("request_gas not supported")
251 }
252
253 async fn get_active_validator_addresses(&self) -> IotaResult<Vec<IotaAddress>> {
254 let system_state_summary = self
255 .fullnode
256 .get_system_state()
257 .map_err(|e| {
258 IotaError::IotaSystemStateRead(format!(
259 "Failed to get system state from fullnode: {}",
260 e
261 ))
262 })?
263 .into_iota_system_state_summary();
264 let active_validators = match system_state_summary {
265 IotaSystemStateSummary::V1(inner) => inner.active_validators,
266 IotaSystemStateSummary::V2(inner) => inner.active_validators,
267 _ => unimplemented!(),
268 };
269
270 Ok(active_validators
271 .iter()
272 .map(|x| x.iota_address)
273 .collect::<Vec<_>>())
274 }
275}
276
277impl ReadStore for ValidatorWithFullnode {
278 fn get_committee(
279 &self,
280 _epoch: EpochId,
281 ) -> iota_types::storage::error::Result<Option<Arc<iota_types::committee::Committee>>> {
282 todo!()
283 }
284
285 fn get_latest_epoch_id(&self) -> iota_types::storage::error::Result<EpochId> {
286 Ok(self.validator.epoch_store_for_testing().epoch())
287 }
288
289 fn get_latest_checkpoint(&self) -> iota_types::storage::error::Result<VerifiedCheckpoint> {
290 let sequence_number = self
291 .validator
292 .get_latest_checkpoint_sequence_number()
293 .unwrap();
294 self.get_checkpoint_by_sequence_number(sequence_number)
295 .map(|c| c.unwrap())
296 }
297
298 fn get_highest_verified_checkpoint(
299 &self,
300 ) -> iota_types::storage::error::Result<VerifiedCheckpoint> {
301 todo!()
302 }
303
304 fn get_highest_synced_checkpoint(
305 &self,
306 ) -> iota_types::storage::error::Result<VerifiedCheckpoint> {
307 todo!()
308 }
309
310 fn get_lowest_available_checkpoint(
311 &self,
312 ) -> iota_types::storage::error::Result<iota_types::messages_checkpoint::CheckpointSequenceNumber>
313 {
314 todo!()
315 }
316
317 fn get_checkpoint_by_digest(
318 &self,
319 _digest: &iota_types::messages_checkpoint::CheckpointDigest,
320 ) -> iota_types::storage::error::Result<Option<VerifiedCheckpoint>> {
321 todo!()
322 }
323
324 fn get_checkpoint_by_sequence_number(
325 &self,
326 sequence_number: iota_types::messages_checkpoint::CheckpointSequenceNumber,
327 ) -> iota_types::storage::error::Result<Option<VerifiedCheckpoint>> {
328 self.validator
329 .get_checkpoint_store()
330 .get_checkpoint_by_sequence_number(sequence_number)
331 .map_err(iota_types::storage::error::Error::custom)
332 }
333
334 fn get_checkpoint_contents_by_digest(
335 &self,
336 digest: &CheckpointContentsDigest,
337 ) -> iota_types::storage::error::Result<
338 Option<iota_types::messages_checkpoint::CheckpointContents>,
339 > {
340 self.validator
341 .get_checkpoint_store()
342 .get_checkpoint_contents(digest)
343 .map_err(iota_types::storage::error::Error::custom)
344 }
345
346 fn get_checkpoint_contents_by_sequence_number(
347 &self,
348 _sequence_number: iota_types::messages_checkpoint::CheckpointSequenceNumber,
349 ) -> iota_types::storage::error::Result<
350 Option<iota_types::messages_checkpoint::CheckpointContents>,
351 > {
352 todo!()
353 }
354
355 fn get_transaction(
356 &self,
357 tx_digest: &TransactionDigest,
358 ) -> iota_types::storage::error::Result<Option<Arc<iota_types::transaction::VerifiedTransaction>>>
359 {
360 self.validator
361 .get_transaction_cache_reader()
362 .get_transaction_block(tx_digest)
363 .map_err(iota_types::storage::error::Error::custom)
364 }
365
366 fn get_transaction_effects(
367 &self,
368 tx_digest: &TransactionDigest,
369 ) -> iota_types::storage::error::Result<Option<TransactionEffects>> {
370 self.validator
371 .get_transaction_cache_reader()
372 .get_executed_effects(tx_digest)
373 .map_err(iota_types::storage::error::Error::custom)
374 }
375
376 fn get_events(
377 &self,
378 event_digest: &TransactionEventsDigest,
379 ) -> iota_types::storage::error::Result<Option<TransactionEvents>> {
380 self.validator
381 .get_transaction_cache_reader()
382 .get_events(event_digest)
383 .map_err(iota_types::storage::error::Error::custom)
384 }
385
386 fn get_full_checkpoint_contents_by_sequence_number(
387 &self,
388 _sequence_number: iota_types::messages_checkpoint::CheckpointSequenceNumber,
389 ) -> iota_types::storage::error::Result<
390 Option<iota_types::messages_checkpoint::FullCheckpointContents>,
391 > {
392 todo!()
393 }
394
395 fn get_full_checkpoint_contents(
396 &self,
397 _digest: &CheckpointContentsDigest,
398 ) -> iota_types::storage::error::Result<
399 Option<iota_types::messages_checkpoint::FullCheckpointContents>,
400 > {
401 todo!()
402 }
403}
404
405impl ObjectStore for ValidatorWithFullnode {
406 fn get_object(
407 &self,
408 object_id: &ObjectID,
409 ) -> Result<Option<Object>, iota_types::storage::error::Error> {
410 self.validator.get_object_store().get_object(object_id)
411 }
412
413 fn get_object_by_key(
414 &self,
415 object_id: &ObjectID,
416 version: VersionNumber,
417 ) -> Result<Option<Object>, iota_types::storage::error::Error> {
418 self.validator
419 .get_object_store()
420 .get_object_by_key(object_id, version)
421 }
422}
423
424#[async_trait::async_trait]
425impl TransactionalAdapter for Simulacrum<StdRng, PersistedStore> {
426 async fn execute_txn(
427 &mut self,
428 transaction: Transaction,
429 ) -> anyhow::Result<(TransactionEffects, Option<ExecutionError>)> {
430 Ok(self.execute_transaction(transaction)?)
431 }
432
433 async fn read_input_objects(&self, _transaction: Transaction) -> IotaResult<InputObjects> {
434 unimplemented!("read_input_objects not supported in simulator mode")
435 }
436
437 fn prepare_txn(
438 &self,
439 _transaction: Transaction,
440 _input_objects: InputObjects,
441 ) -> anyhow::Result<(TransactionEffects, Option<ExecutionError>)> {
442 unimplemented!("prepare_txn not supported in simulator mode")
443 }
444
445 async fn dev_inspect_transaction_block(
446 &self,
447 _sender: IotaAddress,
448 _transaction_kind: TransactionKind,
449 _gas_price: Option<u64>,
450 ) -> IotaResult<DevInspectResults> {
451 unimplemented!("dev_inspect_transaction_block not supported in simulator mode")
452 }
453
454 async fn dry_run_transaction_block(
455 &self,
456 _transaction_block: TransactionData,
457 _transaction_digest: TransactionDigest,
458 ) -> IotaResult<DryRunTransactionBlockResponse> {
459 unimplemented!("dry_run_transaction_block not supported in simulator mode")
460 }
461
462 async fn query_tx_events_asc(
463 &self,
464 tx_digest: &TransactionDigest,
465 _limit: usize,
466 ) -> IotaResult<Vec<Event>> {
467 Ok(self
468 .store()
469 .get_transaction_events_by_tx_digest(tx_digest)
470 .map(|x| x.data)
471 .unwrap_or_default())
472 }
473
474 async fn create_checkpoint(&mut self) -> anyhow::Result<VerifiedCheckpoint> {
475 Ok(self.create_checkpoint())
476 }
477
478 async fn advance_clock(
479 &mut self,
480 duration: std::time::Duration,
481 ) -> anyhow::Result<TransactionEffects> {
482 Ok(self.advance_clock(duration))
483 }
484
485 async fn advance_epoch(&mut self) -> anyhow::Result<()> {
486 self.advance_epoch();
487 Ok(())
488 }
489
490 async fn request_gas(
491 &mut self,
492 address: IotaAddress,
493 amount: u64,
494 ) -> anyhow::Result<TransactionEffects> {
495 self.request_gas(address, amount)
496 }
497
498 async fn get_active_validator_addresses(&self) -> IotaResult<Vec<IotaAddress>> {
499 Ok(self.epoch_start_state().get_validator_addresses())
503 }
504}