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::TxLockGuard,
18 authority_test_utils::send_and_confirm_transaction_with_execution_error,
19 shared_object_version_manager::AssignedVersions,
20};
21use iota_json_rpc::authority_state::StateRead;
22use iota_sdk_types::{
23 Address, CheckpointContents, CheckpointContentsDigest, CheckpointDigest, Event, ObjectId,
24 Transaction, TransactionDigest, TransactionEffects, TransactionEvents,
25};
26use iota_storage::key_value_store::TransactionKeyValueStore;
27use iota_types::{
28 base_types::VersionNumber,
29 committee::EpochId,
30 error::{ExecutionError, IotaError, IotaResult},
31 executable_transaction::{ExecutableTransaction, VerifiedExecutableTransaction},
32 iota_system_state::{
33 IotaSystemStateTrait, epoch_start_iota_system_state::EpochStartSystemStateTrait,
34 iota_system_state_summary::IotaSystemStateSummary,
35 },
36 messages_checkpoint::VerifiedCheckpoint,
37 object::Object,
38 storage::{ObjectStore, ReadStore},
39 transaction::{InputObjects, SenderSignedTransactionAPI, TransactionEnvelope},
40 transaction_executor::{SimulateTransactionResult, VmChecks},
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: TransactionEnvelope,
72 ) -> anyhow::Result<(TransactionEffects, Option<ExecutionError>)>;
73
74 async fn read_input_objects(
75 &self,
76 transaction: TransactionEnvelope,
77 assigned_versions: AssignedVersions,
78 ) -> IotaResult<InputObjects>;
79
80 fn prepare_txn(
81 &self,
82 transaction: TransactionEnvelope,
83 input_objects: InputObjects,
84 ) -> anyhow::Result<(TransactionEffects, Option<ExecutionError>)>;
85
86 async fn create_checkpoint(&mut self) -> anyhow::Result<VerifiedCheckpoint>;
87
88 async fn advance_clock(
89 &mut self,
90 duration: std::time::Duration,
91 ) -> anyhow::Result<TransactionEffects>;
92
93 async fn advance_epoch(
96 &mut self,
97 create_deny_rules_object: bool,
98 ) -> anyhow::Result<Option<TransactionEffects>>;
99
100 async fn request_gas(
101 &mut self,
102 address: Address,
103 amount: u64,
104 ) -> anyhow::Result<TransactionEffects>;
105
106 async fn simulate_transaction(
107 &self,
108 transaction: Transaction,
109 checks: VmChecks,
110 ) -> IotaResult<SimulateTransactionResult>;
111
112 async fn query_tx_events_asc(
113 &self,
114 tx_digest: &TransactionDigest,
115 limit: usize,
116 ) -> IotaResult<Vec<Event>>;
117
118 async fn get_active_validator_addresses(&self) -> IotaResult<Vec<Address>>;
119}
120
121#[async_trait::async_trait]
122impl TransactionalAdapter for ValidatorWithFullnode {
123 async fn execute_txn(
124 &mut self,
125 transaction: TransactionEnvelope,
126 ) -> anyhow::Result<(TransactionEffects, Option<ExecutionError>)> {
127 let with_shared = transaction.contains_shared_object();
128 let (_, effects, execution_error) = send_and_confirm_transaction_with_execution_error(
129 &self.validator,
130 Some(&self.fullnode),
131 transaction,
132 with_shared,
133 false,
134 )
135 .await?;
136 Ok((effects.into_data(), execution_error))
137 }
138
139 async fn read_input_objects(
140 &self,
141 transaction: TransactionEnvelope,
142 assigned_versions: AssignedVersions,
143 ) -> IotaResult<InputObjects> {
144 let tx = VerifiedExecutableTransaction::new_unchecked(
145 ExecutableTransaction::new_from_data_and_sig(
146 transaction.data().clone(),
147 iota_types::executable_transaction::CertificateProof::Checkpoint(0, 0),
148 ),
149 );
150
151 let epoch_store = self.validator.load_epoch_store_one_call_per_task().clone();
152 self.validator
153 .read_objects_for_execution(
154 &TxLockGuard::guard_for_tests(),
155 &tx,
156 assigned_versions,
157 &epoch_store,
158 )
159 .map(|(tx_input_objects, _)| tx_input_objects)
160 }
161
162 fn prepare_txn(
163 &self,
164 transaction: TransactionEnvelope,
165 input_objects: InputObjects,
166 ) -> anyhow::Result<(TransactionEffects, Option<ExecutionError>)> {
167 let tx = VerifiedExecutableTransaction::new_unchecked(
168 ExecutableTransaction::new_from_data_and_sig(
169 transaction.data().clone(),
170 iota_types::executable_transaction::CertificateProof::Checkpoint(0, 0),
171 ),
172 );
173
174 let epoch_store = self.validator.load_epoch_store_one_call_per_task().clone();
175 let (_, effects, error) =
176 self.validator
177 .prepare_transaction_for_benchmark(&tx, input_objects, &epoch_store)?;
178 Ok((effects, error))
179 }
180
181 async fn simulate_transaction(
182 &self,
183 transaction: Transaction,
184 checks: VmChecks,
185 ) -> IotaResult<SimulateTransactionResult> {
186 self.fullnode.simulate_transaction(transaction, checks)
187 }
188
189 async fn query_tx_events_asc(
190 &self,
191 tx_digest: &TransactionDigest,
192 limit: usize,
193 ) -> IotaResult<Vec<Event>> {
194 let events = self
198 .try_get_events(tx_digest)?
199 .map_or_else(Vec::new, |e| e.0);
200 Ok(events.into_iter().take(limit).collect())
201 }
202
203 async fn create_checkpoint(&mut self) -> anyhow::Result<VerifiedCheckpoint> {
204 unimplemented!("create_checkpoint not supported")
205 }
206
207 async fn advance_clock(
208 &mut self,
209 _duration: std::time::Duration,
210 ) -> anyhow::Result<TransactionEffects> {
211 unimplemented!("advance_clock not supported")
212 }
213
214 async fn advance_epoch(
215 &mut self,
216 create_deny_rules_object: bool,
217 ) -> anyhow::Result<Option<TransactionEffects>> {
218 anyhow::ensure!(
219 !create_deny_rules_object,
220 "--create-deny-rules-object is only supported in simulator mode"
221 );
222 self.validator.reconfigure_for_testing().await;
223 self.fullnode.reconfigure_for_testing().await;
224 Ok(None)
225 }
226
227 async fn request_gas(
228 &mut self,
229 _address: Address,
230 _amount: u64,
231 ) -> anyhow::Result<TransactionEffects> {
232 unimplemented!("request_gas not supported")
233 }
234
235 async fn get_active_validator_addresses(&self) -> IotaResult<Vec<Address>> {
236 let system_state_summary = self
237 .fullnode
238 .get_system_state()
239 .map_err(|e| {
240 IotaError::IotaSystemStateRead(format!(
241 "Failed to get system state from fullnode: {e}"
242 ))
243 })?
244 .into_iota_system_state_summary();
245 let active_validators = match system_state_summary {
246 IotaSystemStateSummary::V1(inner) => inner.active_validators,
247 IotaSystemStateSummary::V2(inner) => inner.active_validators,
248 _ => unimplemented!(
249 "a new IotaSystemStateSummary enum variant was added and needs to be handled"
250 ),
251 };
252
253 Ok(active_validators
254 .iter()
255 .map(|x| x.iota_address)
256 .collect::<Vec<_>>())
257 }
258}
259
260impl ReadStore for ValidatorWithFullnode {
261 fn try_get_committee(
262 &self,
263 _epoch: EpochId,
264 ) -> iota_types::storage::error::Result<Option<Arc<iota_types::committee::Committee>>> {
265 todo!()
266 }
267
268 fn try_get_latest_epoch_id(&self) -> iota_types::storage::error::Result<EpochId> {
269 Ok(self.validator.epoch_store_for_testing().epoch())
270 }
271
272 fn try_get_latest_checkpoint(&self) -> iota_types::storage::error::Result<VerifiedCheckpoint> {
273 let sequence_number = self
274 .validator
275 .get_latest_checkpoint_sequence_number()
276 .unwrap();
277 self.try_get_checkpoint_by_sequence_number(sequence_number)
278 .map(|c| c.unwrap())
279 }
280
281 fn try_get_highest_verified_checkpoint(
282 &self,
283 ) -> iota_types::storage::error::Result<VerifiedCheckpoint> {
284 todo!()
285 }
286
287 fn try_get_highest_synced_checkpoint(
288 &self,
289 ) -> iota_types::storage::error::Result<VerifiedCheckpoint> {
290 todo!()
291 }
292
293 fn try_get_lowest_available_checkpoint(
294 &self,
295 ) -> iota_types::storage::error::Result<iota_types::messages_checkpoint::CheckpointSequenceNumber>
296 {
297 todo!()
298 }
299
300 fn try_get_checkpoint_by_digest(
301 &self,
302 _digest: &CheckpointDigest,
303 ) -> iota_types::storage::error::Result<Option<VerifiedCheckpoint>> {
304 todo!()
305 }
306
307 fn try_get_checkpoint_by_sequence_number(
308 &self,
309 sequence_number: iota_types::messages_checkpoint::CheckpointSequenceNumber,
310 ) -> iota_types::storage::error::Result<Option<VerifiedCheckpoint>> {
311 self.validator
312 .get_checkpoint_store()
313 .get_checkpoint_by_sequence_number(sequence_number)
314 .map_err(iota_types::storage::error::Error::custom)
315 }
316
317 fn try_get_checkpoint_contents_by_digest(
318 &self,
319 digest: &CheckpointContentsDigest,
320 ) -> iota_types::storage::error::Result<Option<CheckpointContents>> {
321 self.validator
322 .get_checkpoint_store()
323 .get_checkpoint_contents(digest)
324 .map_err(iota_types::storage::error::Error::custom)
325 }
326
327 fn try_get_checkpoint_contents_by_sequence_number(
328 &self,
329 _sequence_number: iota_types::messages_checkpoint::CheckpointSequenceNumber,
330 ) -> iota_types::storage::error::Result<Option<CheckpointContents>> {
331 todo!()
332 }
333
334 fn try_get_transaction(
335 &self,
336 tx_digest: &TransactionDigest,
337 ) -> iota_types::storage::error::Result<Option<Arc<iota_types::transaction::VerifiedTransaction>>>
338 {
339 self.validator
340 .get_transaction_cache_reader()
341 .try_get_transaction_block(tx_digest)
342 .map_err(iota_types::storage::error::Error::custom)
343 }
344
345 fn try_get_transaction_effects(
346 &self,
347 tx_digest: &TransactionDigest,
348 ) -> iota_types::storage::error::Result<Option<TransactionEffects>> {
349 self.validator
350 .get_transaction_cache_reader()
351 .try_get_executed_effects(tx_digest)
352 .map_err(iota_types::storage::error::Error::custom)
353 }
354
355 fn try_get_events(
356 &self,
357 digest: &TransactionDigest,
358 ) -> iota_types::storage::error::Result<Option<TransactionEvents>> {
359 self.validator
360 .get_transaction_cache_reader()
361 .try_get_events(digest)
362 .map_err(iota_types::storage::error::Error::custom)
363 }
364
365 fn try_get_full_checkpoint_contents_by_sequence_number(
366 &self,
367 _sequence_number: iota_types::messages_checkpoint::CheckpointSequenceNumber,
368 ) -> iota_types::storage::error::Result<
369 Option<iota_types::messages_checkpoint::FullCheckpointContents>,
370 > {
371 todo!()
372 }
373
374 fn try_get_full_checkpoint_contents(
375 &self,
376 _digest: &CheckpointContentsDigest,
377 ) -> iota_types::storage::error::Result<
378 Option<iota_types::messages_checkpoint::FullCheckpointContents>,
379 > {
380 todo!()
381 }
382}
383
384impl ObjectStore for ValidatorWithFullnode {
385 fn try_get_object(
386 &self,
387 object_id: &ObjectId,
388 ) -> Result<Option<Object>, iota_types::storage::error::Error> {
389 self.validator.get_object_store().try_get_object(object_id)
390 }
391
392 fn try_get_object_by_key(
393 &self,
394 object_id: &ObjectId,
395 version: VersionNumber,
396 ) -> Result<Option<Object>, iota_types::storage::error::Error> {
397 self.validator
398 .get_object_store()
399 .try_get_object_by_key(object_id, version)
400 }
401}
402
403#[async_trait::async_trait]
404impl TransactionalAdapter for Simulacrum<StdRng, PersistedStore> {
405 async fn execute_txn(
406 &mut self,
407 transaction: TransactionEnvelope,
408 ) -> anyhow::Result<(TransactionEffects, Option<ExecutionError>)> {
409 Ok(self.execute_transaction(transaction)?)
410 }
411
412 async fn read_input_objects(
413 &self,
414 _transaction: TransactionEnvelope,
415 _assigned_versions: AssignedVersions,
416 ) -> IotaResult<InputObjects> {
417 unimplemented!("read_input_objects not supported in simulator mode")
418 }
419
420 fn prepare_txn(
421 &self,
422 _transaction: TransactionEnvelope,
423 _input_objects: InputObjects,
424 ) -> anyhow::Result<(TransactionEffects, Option<ExecutionError>)> {
425 unimplemented!("prepare_txn not supported in simulator mode")
426 }
427
428 async fn simulate_transaction(
429 &self,
430 transaction: Transaction,
431 checks: VmChecks,
432 ) -> IotaResult<SimulateTransactionResult> {
433 Simulacrum::simulate_transaction(self, transaction, checks)
434 }
435
436 async fn query_tx_events_asc(
437 &self,
438 tx_digest: &TransactionDigest,
439 _limit: usize,
440 ) -> IotaResult<Vec<Event>> {
441 match self.try_get_events(tx_digest)? {
442 Some(events) => Ok(events.0),
443 None => Ok(Vec::new()),
444 }
445 }
446
447 async fn create_checkpoint(&mut self) -> anyhow::Result<VerifiedCheckpoint> {
448 Ok(Simulacrum::create_checkpoint(self))
449 }
450
451 async fn advance_clock(
452 &mut self,
453 duration: std::time::Duration,
454 ) -> anyhow::Result<TransactionEffects> {
455 Ok(Simulacrum::advance_clock(self, duration))
456 }
457
458 async fn advance_epoch(
459 &mut self,
460 create_deny_rules_object: bool,
461 ) -> anyhow::Result<Option<TransactionEffects>> {
462 Ok(Some(Simulacrum::advance_epoch(
463 self,
464 create_deny_rules_object,
465 )))
466 }
467
468 async fn request_gas(
469 &mut self,
470 address: Address,
471 amount: u64,
472 ) -> anyhow::Result<TransactionEffects> {
473 Simulacrum::request_gas(self, address, amount)
474 }
475
476 async fn get_active_validator_addresses(&self) -> IotaResult<Vec<Address>> {
477 Ok(self.epoch_start_state().get_validator_addresses())
481 }
482}