1use std::num::NonZeroUsize;
14use std::path::PathBuf;
15use std::sync::Arc;
16
17use anyhow::{Context, Result, anyhow, ensure};
18use fastcrypto::traits::Signer;
19use rand::rngs::OsRng;
20use sui_config::verifier_signing_config::VerifierSigningConfig;
21use sui_config::{genesis, transaction_deny_config::TransactionDenyConfig};
22use sui_framework_snapshot::load_bytecode_snapshot;
23use sui_protocol_config::ProtocolVersion;
24use sui_storage::blob::{Blob, BlobEncoding};
25use sui_swarm_config::genesis_config::AccountConfig;
26use sui_swarm_config::network_config::NetworkConfig;
27use sui_swarm_config::network_config_builder::ConfigBuilder;
28use sui_types::base_types::{AuthorityName, ObjectID, ObjectRef, SequenceNumber, VersionNumber};
29use sui_types::crypto::{AccountKeyPair, AuthoritySignature, get_account_key_pair};
30use sui_types::digests::{ChainIdentifier, ConsensusCommitDigest};
31use sui_types::effects::TransactionEffectsAPI;
32use sui_types::messages_consensus::ConsensusDeterminedVersionAssignments;
33use sui_types::object::{Object, Owner};
34use sui_types::storage::ObjectKey;
35use sui_types::storage::{ObjectStore, ReadStore, RpcStateReader};
36use sui_types::sui_system_state::epoch_start_sui_system_state::EpochStartSystemState;
37use sui_types::transaction::EndOfEpochTransactionKind;
38use sui_types::{
39 base_types::{EpochId, SuiAddress},
40 committee::Committee,
41 effects::TransactionEffects,
42 error::ExecutionError,
43 gas_coin::MIST_PER_SUI,
44 inner_temporary_store::InnerTemporaryStore,
45 messages_checkpoint::{EndOfEpochData, VerifiedCheckpoint},
46 signature::VerifyParams,
47 transaction::{Transaction, VerifiedTransaction},
48};
49
50use self::epoch_state::EpochState;
51pub use self::store::SimulatorStore;
52pub use self::store::in_mem_store::InMemoryStore;
53use self::store::in_mem_store::KeyStore;
54use sui_core::mock_checkpoint_builder::{MockCheckpointBuilder, ValidatorKeypairProvider};
55use sui_types::messages_checkpoint::{CheckpointContents, CheckpointSequenceNumber};
56use sui_types::{
57 gas_coin::GasCoin,
58 programmable_transaction_builder::ProgrammableTransactionBuilder,
59 transaction::{GasData, TransactionData, TransactionKind},
60};
61
62#[derive(Debug, Clone, Default)]
66pub struct AdvanceEpochConfig {
67 pub create_random_state: bool,
70 pub create_authenticator_state: bool,
72 pub create_authenticator_state_expire: bool,
74 pub create_deny_list_state: bool,
76 pub create_bridge_state: bool,
78 pub create_bridge_committee: bool,
80 pub system_packages_snapshot: Option<u64>,
85}
86
87mod epoch_state;
88pub mod store;
89
90pub struct Simulacrum<R = OsRng, Store: SimulatorStore = InMemoryStore> {
100 rng: R,
101 keystore: KeyStore,
102 #[allow(unused)]
103 genesis: genesis::Genesis,
104 store: Store,
105 checkpoint_builder: MockCheckpointBuilder,
106
107 epoch_state: EpochState,
109
110 deny_config: TransactionDenyConfig,
112 data_ingestion_path: Option<PathBuf>,
113 verifier_signing_config: VerifierSigningConfig,
114}
115
116impl Simulacrum {
117 #[allow(clippy::new_without_default)]
119 pub fn new() -> Self {
120 Self::new_with_rng(OsRng)
121 }
122}
123
124impl<R> Simulacrum<R>
125where
126 R: rand::RngCore + rand::CryptoRng,
127{
128 pub fn new_with_rng(mut rng: R) -> Self {
143 let config = ConfigBuilder::new_with_temp_dir()
144 .rng(&mut rng)
145 .with_chain_start_timestamp_ms(1)
146 .deterministic_committee_size(NonZeroUsize::new(1).unwrap())
147 .build();
148 Self::new_with_network_config_in_mem(&config, rng)
149 }
150
151 pub fn new_with_protocol_version(mut rng: R, protocol_version: ProtocolVersion) -> Self {
153 let config = ConfigBuilder::new_with_temp_dir()
154 .rng(&mut rng)
155 .with_chain_start_timestamp_ms(1)
156 .deterministic_committee_size(NonZeroUsize::new(1).unwrap())
157 .with_protocol_version(protocol_version)
158 .build();
159 Self::new_with_network_config_in_mem(&config, rng)
160 }
161
162 pub fn new_with_protocol_version_and_accounts(
163 mut rng: R,
164 chain_start_timestamp_ms: u64,
165 protocol_version: ProtocolVersion,
166 account_configs: Vec<AccountConfig>,
167 ) -> Self {
168 let config = ConfigBuilder::new_with_temp_dir()
169 .rng(&mut rng)
170 .with_chain_start_timestamp_ms(chain_start_timestamp_ms)
171 .deterministic_committee_size(NonZeroUsize::new(1).unwrap())
172 .with_protocol_version(protocol_version)
173 .with_accounts(account_configs)
174 .build();
175 Self::new_with_network_config_in_mem(&config, rng)
176 }
177
178 fn new_with_network_config_in_mem(config: &NetworkConfig, rng: R) -> Self {
179 let store = InMemoryStore::new(&config.genesis);
180 Self::new_with_network_config_store(config, rng, store)
181 }
182}
183
184impl<R, S: store::SimulatorStore> Simulacrum<R, S> {
185 pub fn new_with_network_config_store(config: &NetworkConfig, rng: R, store: S) -> Self {
186 let keystore = KeyStore::from_network_config(config);
187 let checkpoint_builder = MockCheckpointBuilder::new(config.genesis.checkpoint());
188
189 let genesis = &config.genesis;
190 let epoch_state = EpochState::new(genesis.sui_system_object());
191
192 Self {
193 rng,
194 keystore,
195 genesis: genesis.clone(),
196 store,
197 checkpoint_builder,
198 epoch_state,
199 deny_config: TransactionDenyConfig::default(),
200 verifier_signing_config: VerifierSigningConfig::default(),
201 data_ingestion_path: None,
202 }
203 }
204
205 pub fn execute_transaction(
217 &mut self,
218 transaction: Transaction,
219 ) -> anyhow::Result<(TransactionEffects, Option<ExecutionError>)> {
220 let transaction = transaction
221 .try_into_verified_for_testing(self.epoch_state.epoch(), &VerifyParams::default())?;
222 self.execute_transaction_impl(transaction)
223 }
224
225 fn execute_transaction_impl(
226 &mut self,
227 transaction: VerifiedTransaction,
228 ) -> anyhow::Result<(TransactionEffects, Option<ExecutionError>)> {
229 let (inner_temporary_store, _, effects, execution_error_opt) =
230 self.epoch_state.execute_transaction(
231 &self.store,
232 &self.deny_config,
233 &self.verifier_signing_config,
234 &transaction,
235 )?;
236
237 let InnerTemporaryStore {
238 written, events, ..
239 } = inner_temporary_store;
240
241 self.store.insert_executed_transaction(
242 transaction.clone(),
243 effects.clone(),
244 events,
245 written,
246 );
247
248 self.checkpoint_builder
250 .push_transaction(transaction, effects.clone());
251 Ok((effects, execution_error_opt.err()))
252 }
253
254 fn execute_system_transaction(
255 &mut self,
256 transaction: Transaction,
257 ) -> anyhow::Result<(TransactionEffects, Option<ExecutionError>)> {
258 let transaction = VerifiedTransaction::new_unchecked(transaction);
259 self.execute_transaction_impl(transaction)
260 }
261
262 pub fn create_checkpoint(&mut self) -> VerifiedCheckpoint {
265 if self.epoch_state.protocol_config().enable_accumulators() {
266 let (settlement_txns, checkpoint_height) = self
267 .checkpoint_builder
268 .get_settlement_txns(self.epoch_state.protocol_config());
269
270 let mut settlement_effects = Vec::with_capacity(settlement_txns.len());
272 for txn in settlement_txns {
273 let (effects, _) = self
274 .execute_system_transaction(txn)
275 .expect("settlement txn cannot fail");
276 effects.status().unwrap();
277 settlement_effects.push(effects);
278 }
279
280 let barrier_tx = self
282 .checkpoint_builder
283 .get_barrier_tx(checkpoint_height, &settlement_effects);
284 self.execute_system_transaction(barrier_tx)
285 .expect("barrier txn cannot fail")
286 .0
287 .status()
288 .unwrap();
289 }
290
291 let committee = CommitteeWithKeys::new(&self.keystore, self.epoch_state.committee());
292 let (checkpoint, contents, _) = self
293 .checkpoint_builder
294 .build(&committee, self.store.get_clock().timestamp_ms());
295 self.store.insert_checkpoint(checkpoint.clone());
296 self.store.insert_checkpoint_contents(contents.clone());
297 self.process_data_ingestion(checkpoint.clone(), contents)
298 .unwrap();
299 checkpoint
300 }
301
302 pub fn advance_clock(&mut self, duration: std::time::Duration) -> TransactionEffects {
307 let epoch = self.epoch_state.epoch();
308 let round = self.epoch_state.next_consensus_round();
309 let timestamp_ms = self.store.get_clock().timestamp_ms() + duration.as_millis() as u64;
310
311 let consensus_commit_prologue_transaction =
312 VerifiedTransaction::new_consensus_commit_prologue_v3(
313 epoch,
314 round,
315 timestamp_ms,
316 ConsensusCommitDigest::default(),
317 ConsensusDeterminedVersionAssignments::empty_for_testing(),
318 );
319
320 self.execute_transaction(consensus_commit_prologue_transaction.into())
321 .expect("advancing the clock cannot fail")
322 .0
323 }
324
325 pub fn advance_epoch(&mut self, config: AdvanceEpochConfig) {
336 let next_epoch = self.epoch_state.epoch() + 1;
337 let next_epoch_protocol_version = self.epoch_state.protocol_version();
338 let gas_cost_summary = self.checkpoint_builder.epoch_rolling_gas_cost_summary();
339 let epoch_start_timestamp_ms = self.store.get_clock().timestamp_ms();
340
341 let next_epoch_system_package_bytes = if let Some(snapshot_version) =
342 config.system_packages_snapshot
343 {
344 let packages = match load_bytecode_snapshot(snapshot_version) {
345 Ok(snapshot_packages) => snapshot_packages,
346 Err(e) => {
347 panic!("Failed to load bytecode snapshot for version {snapshot_version}: {e}");
348 }
349 };
350
351 packages
352 .into_iter()
353 .map(|pkg| (SequenceNumber::from(1u64), pkg.bytes, pkg.dependencies))
354 .collect()
355 } else {
356 vec![]
357 };
358
359 let mut kinds = vec![];
360
361 if config.create_random_state {
362 kinds.push(EndOfEpochTransactionKind::new_randomness_state_create());
363 }
364
365 if config.create_authenticator_state {
366 kinds.push(EndOfEpochTransactionKind::new_authenticator_state_create());
367 }
368
369 if config.create_authenticator_state_expire {
370 let current_epoch = self.epoch_state.epoch();
371 kinds.push(EndOfEpochTransactionKind::new_authenticator_state_expire(
372 current_epoch,
373 SequenceNumber::from(1),
374 ));
375 }
376
377 if config.create_deny_list_state {
378 kinds.push(EndOfEpochTransactionKind::new_deny_list_state_create());
379 }
380
381 if config.create_bridge_state {
382 let chain_id = ChainIdentifier::default();
384 kinds.push(EndOfEpochTransactionKind::new_bridge_create(chain_id));
385 }
386
387 if config.create_bridge_committee {
388 let bridge_version = SequenceNumber::from(1);
390 kinds.push(EndOfEpochTransactionKind::init_bridge_committee(
391 bridge_version,
392 ));
393 }
394
395 kinds.push(EndOfEpochTransactionKind::new_change_epoch(
396 next_epoch,
397 next_epoch_protocol_version,
398 gas_cost_summary.storage_cost,
399 gas_cost_summary.computation_cost,
400 gas_cost_summary.storage_rebate,
401 gas_cost_summary.non_refundable_storage_fee,
402 epoch_start_timestamp_ms,
403 next_epoch_system_package_bytes,
404 ));
405
406 let tx = VerifiedTransaction::new_end_of_epoch_transaction(kinds);
407 self.execute_transaction(tx.into())
408 .expect("advancing the epoch cannot fail");
409
410 let new_epoch_state = EpochState::new_with_protocol_config(
411 self.store.get_system_state(),
412 self.epoch_state.protocol_config().clone(),
413 );
414 let end_of_epoch_data = EndOfEpochData {
415 next_epoch_committee: new_epoch_state.committee().voting_rights.clone(),
416 next_epoch_protocol_version,
417 epoch_commitments: vec![],
418 };
419 let committee = CommitteeWithKeys::new(&self.keystore, self.epoch_state.committee());
420 let (checkpoint, contents, _) = self.checkpoint_builder.build_end_of_epoch(
421 &committee,
422 self.store.get_clock().timestamp_ms(),
423 next_epoch,
424 end_of_epoch_data,
425 );
426
427 self.store.insert_checkpoint(checkpoint.clone());
428 self.store.insert_checkpoint_contents(contents.clone());
429 self.process_data_ingestion(checkpoint, contents).unwrap();
430 self.epoch_state = new_epoch_state;
431 }
432
433 pub fn store(&self) -> &dyn SimulatorStore {
434 &self.store
435 }
436
437 pub fn keystore(&self) -> &KeyStore {
438 &self.keystore
439 }
440
441 pub fn epoch_start_state(&self) -> &EpochStartSystemState {
442 self.epoch_state.epoch_start_state()
443 }
444
445 pub fn rng(&mut self) -> &mut R {
451 &mut self.rng
452 }
453
454 pub fn reference_gas_price(&self) -> u64 {
456 self.epoch_state.reference_gas_price()
457 }
458
459 pub fn funded_account(
477 &mut self,
478 amount: u64,
479 ) -> Result<(SuiAddress, AccountKeyPair, ObjectRef)> {
480 let (address, key) = get_account_key_pair();
481 let fx = self.request_gas(address, amount)?;
482 ensure!(fx.status().is_ok(), "Failed to request gas for account");
483
484 let gas = fx
485 .created()
486 .into_iter()
487 .find_map(|(oref, owner)| {
488 matches!(owner, Owner::AddressOwner(owner) if owner == address).then_some(oref)
489 })
490 .context("Could not find created object")?;
491
492 Ok((address, key, gas))
493 }
494
495 pub fn request_gas(&mut self, address: SuiAddress, amount: u64) -> Result<TransactionEffects> {
512 let (sender, key) = self.keystore().accounts().next().unwrap();
515 let object = self
516 .store()
517 .owned_objects(*sender)
518 .find(|object| {
519 object.is_gas_coin() && object.get_coin_value_unsafe() > amount + MIST_PER_SUI
520 })
521 .ok_or_else(|| {
522 anyhow!("unable to find a coin with enough to satisfy request for {amount} Mist")
523 })?;
524
525 let gas_data = sui_types::transaction::GasData {
526 payment: vec![object.compute_object_reference()],
527 owner: *sender,
528 price: self.reference_gas_price(),
529 budget: MIST_PER_SUI,
530 };
531
532 let pt = {
533 let mut builder =
534 sui_types::programmable_transaction_builder::ProgrammableTransactionBuilder::new();
535 builder.transfer_sui(address, Some(amount));
536 builder.finish()
537 };
538
539 let kind = sui_types::transaction::TransactionKind::ProgrammableTransaction(pt);
540 let tx_data =
541 sui_types::transaction::TransactionData::new_with_gas_data(kind, *sender, gas_data);
542 let tx = Transaction::from_data_and_signer(tx_data, vec![key]);
543
544 self.execute_transaction(tx).map(|x| x.0)
545 }
546
547 pub fn set_data_ingestion_path(&mut self, data_ingestion_path: PathBuf) {
548 self.data_ingestion_path = Some(data_ingestion_path);
549 let checkpoint = self.store.get_checkpoint_by_sequence_number(0).unwrap();
550 let contents = self
551 .store
552 .get_checkpoint_contents(&checkpoint.content_digest);
553 self.process_data_ingestion(checkpoint, contents.unwrap())
554 .unwrap();
555 }
556
557 pub fn override_next_checkpoint_number(&mut self, number: CheckpointSequenceNumber) {
558 let committee = CommitteeWithKeys::new(&self.keystore, self.epoch_state.committee());
559 self.checkpoint_builder
560 .override_next_checkpoint_number(number, &committee);
561 }
562
563 fn process_data_ingestion(
564 &self,
565 checkpoint: VerifiedCheckpoint,
566 checkpoint_contents: CheckpointContents,
567 ) -> anyhow::Result<()> {
568 if let Some(path) = &self.data_ingestion_path {
569 let file_name = format!("{}.chk", checkpoint.sequence_number);
570 let checkpoint_data: sui_types::full_checkpoint_content::CheckpointData = self
571 .get_checkpoint_data(checkpoint, checkpoint_contents)?
572 .into();
573 std::fs::create_dir_all(path)?;
574 let blob = Blob::encode(&checkpoint_data, BlobEncoding::Bcs)?;
575 std::fs::write(path.join(file_name), blob.to_bytes())?;
576 }
577 Ok(())
578 }
579}
580
581pub struct CommitteeWithKeys<'a> {
582 keystore: &'a KeyStore,
583 committee: &'a Committee,
584}
585
586impl<'a> CommitteeWithKeys<'a> {
587 fn new(keystore: &'a KeyStore, committee: &'a Committee) -> Self {
588 Self {
589 keystore,
590 committee,
591 }
592 }
593
594 pub fn keystore(&self) -> &KeyStore {
595 self.keystore
596 }
597}
598
599impl ValidatorKeypairProvider for CommitteeWithKeys<'_> {
600 fn get_validator_key(&self, name: &AuthorityName) -> &dyn Signer<AuthoritySignature> {
601 self.keystore.validator(name).unwrap()
602 }
603
604 fn get_committee(&self) -> &Committee {
605 self.committee
606 }
607}
608
609impl<T, V: store::SimulatorStore> ObjectStore for Simulacrum<T, V> {
610 fn get_object(&self, object_id: &ObjectID) -> Option<Object> {
611 store::SimulatorStore::get_object(&self.store, object_id)
612 }
613
614 fn get_object_by_key(&self, object_id: &ObjectID, version: VersionNumber) -> Option<Object> {
615 self.store.get_object_by_key(object_id, version)
616 }
617}
618
619impl<T, V: store::SimulatorStore> ReadStore for Simulacrum<T, V> {
620 fn get_committee(
621 &self,
622 _epoch: sui_types::committee::EpochId,
623 ) -> Option<std::sync::Arc<Committee>> {
624 todo!()
625 }
626
627 fn get_latest_checkpoint(&self) -> sui_types::storage::error::Result<VerifiedCheckpoint> {
628 Ok(self.store().get_highest_checkpint().unwrap())
629 }
630
631 fn get_latest_epoch_id(&self) -> sui_types::storage::error::Result<EpochId> {
632 Ok(self.epoch_state.epoch())
633 }
634
635 fn get_highest_verified_checkpoint(
636 &self,
637 ) -> sui_types::storage::error::Result<VerifiedCheckpoint> {
638 todo!()
639 }
640
641 fn get_highest_synced_checkpoint(
642 &self,
643 ) -> sui_types::storage::error::Result<VerifiedCheckpoint> {
644 todo!()
645 }
646
647 fn get_lowest_available_checkpoint(
648 &self,
649 ) -> sui_types::storage::error::Result<sui_types::messages_checkpoint::CheckpointSequenceNumber>
650 {
651 Ok(0)
654 }
655
656 fn get_checkpoint_by_digest(
657 &self,
658 digest: &sui_types::messages_checkpoint::CheckpointDigest,
659 ) -> Option<VerifiedCheckpoint> {
660 self.store().get_checkpoint_by_digest(digest)
661 }
662
663 fn get_checkpoint_by_sequence_number(
664 &self,
665 sequence_number: sui_types::messages_checkpoint::CheckpointSequenceNumber,
666 ) -> Option<VerifiedCheckpoint> {
667 self.store()
668 .get_checkpoint_by_sequence_number(sequence_number)
669 }
670
671 fn get_checkpoint_contents_by_digest(
672 &self,
673 digest: &sui_types::messages_checkpoint::CheckpointContentsDigest,
674 ) -> Option<sui_types::messages_checkpoint::CheckpointContents> {
675 self.store().get_checkpoint_contents(digest)
676 }
677
678 fn get_checkpoint_contents_by_sequence_number(
679 &self,
680 _sequence_number: sui_types::messages_checkpoint::CheckpointSequenceNumber,
681 ) -> Option<sui_types::messages_checkpoint::CheckpointContents> {
682 todo!()
683 }
684
685 fn get_transaction(
686 &self,
687 tx_digest: &sui_types::digests::TransactionDigest,
688 ) -> Option<Arc<VerifiedTransaction>> {
689 self.store().get_transaction(tx_digest).map(Arc::new)
690 }
691
692 fn get_transaction_effects(
693 &self,
694 tx_digest: &sui_types::digests::TransactionDigest,
695 ) -> Option<TransactionEffects> {
696 self.store().get_transaction_effects(tx_digest)
697 }
698
699 fn get_events(
700 &self,
701 event_digest: &sui_types::digests::TransactionDigest,
702 ) -> Option<sui_types::effects::TransactionEvents> {
703 self.store().get_transaction_events(event_digest)
704 }
705
706 fn get_full_checkpoint_contents(
707 &self,
708 _sequence_number: Option<sui_types::messages_checkpoint::CheckpointSequenceNumber>,
709 _digest: &sui_types::messages_checkpoint::CheckpointContentsDigest,
710 ) -> Option<sui_types::messages_checkpoint::VersionedFullCheckpointContents> {
711 todo!()
712 }
713
714 fn get_unchanged_loaded_runtime_objects(
715 &self,
716 _digest: &sui_types::digests::TransactionDigest,
717 ) -> Option<Vec<ObjectKey>> {
718 None
719 }
720
721 fn get_transaction_checkpoint(
722 &self,
723 _digest: &sui_types::digests::TransactionDigest,
724 ) -> Option<CheckpointSequenceNumber> {
725 None
726 }
727}
728
729impl<T: Send + Sync, V: store::SimulatorStore + Send + Sync> RpcStateReader for Simulacrum<T, V> {
730 fn get_lowest_available_checkpoint_objects(
731 &self,
732 ) -> sui_types::storage::error::Result<CheckpointSequenceNumber> {
733 Ok(0)
734 }
735
736 fn get_chain_identifier(
737 &self,
738 ) -> sui_types::storage::error::Result<sui_types::digests::ChainIdentifier> {
739 Ok(self
740 .store()
741 .get_checkpoint_by_sequence_number(0)
742 .unwrap()
743 .digest()
744 .to_owned()
745 .into())
746 }
747
748 fn indexes(&self) -> Option<&dyn sui_types::storage::RpcIndexes> {
749 None
750 }
751
752 fn get_struct_layout(
753 &self,
754 _: &move_core_types::language_storage::StructTag,
755 ) -> sui_types::storage::error::Result<Option<move_core_types::annotated_value::MoveTypeLayout>>
756 {
757 Ok(None)
758 }
759}
760
761impl Simulacrum {
762 pub fn transfer_txn(&mut self, recipient: SuiAddress) -> (Transaction, u64) {
767 let (sender, key) = self.keystore().accounts().next().unwrap();
768 let sender = *sender;
769
770 let object = self
771 .store()
772 .owned_objects(sender)
773 .find(|object| object.is_gas_coin())
774 .unwrap();
775 let gas_coin = GasCoin::try_from(&object).unwrap();
776 let transfer_amount = gas_coin.value() / 2;
777
778 let pt = {
779 let mut builder = ProgrammableTransactionBuilder::new();
780 builder.transfer_sui(recipient, Some(transfer_amount));
781 builder.finish()
782 };
783
784 let kind = TransactionKind::ProgrammableTransaction(pt);
785 let gas_data = GasData {
786 payment: vec![object.compute_object_reference()],
787 owner: sender,
788 price: self.reference_gas_price(),
789 budget: 1_000_000_000,
790 };
791 let tx_data = TransactionData::new_with_gas_data(kind, sender, gas_data);
792 let tx = Transaction::from_data_and_signer(tx_data, vec![key]);
793 (tx, transfer_amount)
794 }
795}
796
797#[cfg(test)]
798mod tests {
799 use std::time::Duration;
800
801 use rand::{SeedableRng, rngs::StdRng};
802 use sui_types::{
803 base_types::SuiAddress, effects::TransactionEffectsAPI, gas_coin::GasCoin,
804 transaction::TransactionDataAPI,
805 };
806
807 use super::*;
808
809 #[test]
810 fn deterministic_genesis() {
811 let rng = StdRng::from_seed([9; 32]);
812 let chain1 = Simulacrum::new_with_rng(rng);
813 let genesis_checkpoint_digest1 = *chain1
814 .store()
815 .get_checkpoint_by_sequence_number(0)
816 .unwrap()
817 .digest();
818
819 let rng = StdRng::from_seed([9; 32]);
820 let chain2 = Simulacrum::new_with_rng(rng);
821 let genesis_checkpoint_digest2 = *chain2
822 .store()
823 .get_checkpoint_by_sequence_number(0)
824 .unwrap()
825 .digest();
826
827 assert_eq!(genesis_checkpoint_digest1, genesis_checkpoint_digest2);
828
829 let rng = StdRng::from_seed([0; 32]);
831 let chain3 = Simulacrum::new_with_rng(rng);
832
833 assert_ne!(
834 chain1.store().get_committee_by_epoch(0),
835 chain3.store().get_committee_by_epoch(0),
836 );
837 }
838
839 #[test]
840 fn simple() {
841 let steps = 10;
842 let mut chain = Simulacrum::new();
843
844 let clock = chain.store().get_clock();
845 let start_time_ms = clock.timestamp_ms();
846 println!("clock: {:#?}", clock);
847 for _ in 0..steps {
848 chain.advance_clock(Duration::from_millis(1));
849 chain.create_checkpoint();
850 let clock = chain.store().get_clock();
851 println!("clock: {:#?}", clock);
852 }
853 let end_time_ms = chain.store().get_clock().timestamp_ms();
854 assert_eq!(end_time_ms - start_time_ms, steps);
855 dbg!(chain.store().get_highest_checkpint());
856 }
857
858 #[test]
859 fn simple_epoch() {
860 let steps = 10;
861 let mut chain = Simulacrum::new();
862
863 let start_epoch = chain.store.get_highest_checkpint().unwrap().epoch;
864 for i in 0..steps {
865 chain.advance_epoch(AdvanceEpochConfig::default());
866 chain.advance_clock(Duration::from_millis(1));
867 chain.create_checkpoint();
868 println!("{i}");
869 }
870 let end_epoch = chain.store.get_highest_checkpint().unwrap().epoch;
871 assert_eq!(end_epoch - start_epoch, steps);
872 dbg!(chain.store().get_highest_checkpint());
873 }
874
875 #[test]
876 fn transfer() {
877 let mut sim = Simulacrum::new();
878 let recipient = SuiAddress::random_for_testing_only();
879 let (tx, transfer_amount) = sim.transfer_txn(recipient);
880
881 let gas_id = tx.data().transaction_data().gas_data().payment[0].0;
882 let effects = sim.execute_transaction(tx).unwrap().0;
883 let gas_summary = effects.gas_cost_summary();
884 let gas_paid = gas_summary.net_gas_usage();
885
886 assert_eq!(
887 (transfer_amount as i64 - gas_paid) as u64,
888 store::SimulatorStore::get_object(sim.store(), &gas_id)
889 .and_then(|object| GasCoin::try_from(&object).ok())
890 .unwrap()
891 .value()
892 );
893
894 assert_eq!(
895 transfer_amount,
896 sim.store()
897 .owned_objects(recipient)
898 .next()
899 .and_then(|object| GasCoin::try_from(&object).ok())
900 .unwrap()
901 .value()
902 );
903
904 let checkpoint = sim.create_checkpoint();
905
906 assert_eq!(&checkpoint.epoch_rolling_gas_cost_summary, gas_summary);
907 if sim.epoch_state.protocol_config().enable_accumulators() {
908 assert_eq!(checkpoint.network_total_transactions, 3); } else {
910 assert_eq!(checkpoint.network_total_transactions, 2); };
912 }
913}