원클릭으로
evolve-simulator
// Use the Evolve deterministic simulator for testing with controlled time, storage, and randomness. Use when creating simulations, seed-based testing, fault injection, stress testing, or deterministic test reproduction.
// Use the Evolve deterministic simulator for testing with controlled time, storage, and randomness. Use when creating simulations, seed-based testing, fault injection, stress testing, or deterministic test reproduction.
| name | evolve-simulator |
| description | Use the Evolve deterministic simulator for testing with controlled time, storage, and randomness. Use when creating simulations, seed-based testing, fault injection, stress testing, or deterministic test reproduction. |
The evolve_simulator crate provides a deterministic simulation engine for testing Evolve SDK applications with controlled time, storage, and randomness.
use evolve_simulator::{Simulator, SimConfig, SimulatorBuilder};
// Create a simulator with default config
let mut sim = Simulator::new(12345, SimConfig::default());
// Run simulation for 100 blocks
sim.run_blocks(100).unwrap();
// Get performance report
let report = sim.generate_report();
println!("{}", report.to_string_pretty());
// Print reproduction command
println!("Reproduce with seed: {}", sim.seed());
use evolve_simulator::{SimConfig, StorageConfig, TimeConfig, MetricsConfig};
let config = SimConfig {
time: TimeConfig {
ticks_per_block: 10,
tick_ms: 100, // 100ms per tick
initial_timestamp_ms: 0,
},
storage: StorageConfig {
read_fault_prob: 0.01, // 1% read failures
write_fault_prob: 0.01, // 1% write failures
log_operations: true, // Log all operations
},
metrics: MetricsConfig::default(),
max_blocks: 1000,
max_txs_per_block: 100,
stop_on_error: false,
};
let (sim, seed) = SimulatorBuilder::new()
.seed(42) // Optional: use specific seed
.max_blocks(500)
.stop_on_error()
.storage_config(StorageConfig::with_faults(0.01, 0.01))
.with_state(b"key".to_vec(), b"value".to_vec()) // Initial state
.build_with_seed();
println!("Running with seed: {seed}");
// Advance by ticks
sim.tick();
sim.advance_ticks(100);
// Advance by blocks
sim.advance_block();
sim.set_block_height(50);
// Query time
let height = sim.time().block_height();
let timestamp = sim.time().now_ms();
use evolve_server_core::StateChange;
// Apply state changes
let changes = vec![
StateChange::Set { key: b"key1".to_vec(), value: b"value1".to_vec() },
StateChange::Delete { key: b"key2".to_vec() },
];
sim.apply_state_changes(changes).unwrap();
// Read storage
let value = sim.storage().get(b"key1").unwrap();
// Create checkpoint
let snapshot = sim.snapshot();
// Do some work...
sim.run_blocks(10).unwrap();
// Restore to checkpoint
sim.restore(snapshot);
let report = sim.generate_report();
println!("Total blocks: {}", report.total_blocks);
println!("Total txs: {}", report.total_txs);
println!("Success rate: {:.2}%", report.success_rate * 100.0);
println!("Avg gas/tx: {:.2}", report.avg_gas_per_tx);
println!("P99 block time: {:.2}ms", report.p99_block_time_ms);
println!("Time acceleration: {:.1}x", report.time_acceleration);
// Use pre-configured stress test settings
let config = SimConfig::stress_test();
let mut sim = Simulator::new(seed, config);
sim.run_until(|s| s.metrics().total_errors > 0).unwrap();
if let Some(reason) = sim.abort_reason() {
println!("Simulation aborted: {reason}");
}
When a test fails, capture the seed for exact reproduction:
#[test]
fn property_test() {
let (mut sim, seed) = Simulator::with_random_seed(SimConfig::default());
// ... run test ...
if test_failed {
eprintln!("FAILURE! Reproduce with seed: {seed}");
panic!("Test failed");
}
}
Bridge simulator storage to STF's ReadonlyKV interface:
use evolve_simulator::SimStorageAdapter;
let adapter = SimStorageAdapter::new(sim.storage());
let (result, state) = stf.apply_block(&adapter, &codes, &block);
// Apply changes back to simulator
sim.apply_state_changes(state.into_changes()?)?;
// Normal operation (default)
let config = SimConfig::default();
// Stress testing with fault injection
let config = SimConfig::stress_test();
// - read_fault_prob: 0.05
// - write_fault_prob: 0.05
// - stop_on_error: false
// Replay mode (deterministic, no faults)
let config = SimConfig::replay();
// - read_fault_prob: 0.0
// - write_fault_prob: 0.0
let stats = sim.storage().stats();
println!("Reads: {}", stats.reads);
println!("Writes: {}", stats.writes);
println!("Read faults: {}", stats.read_faults);
println!("Write faults: {}", stats.write_faults);
println!("Bytes read: {}", stats.bytes_read);
println!("Bytes written: {}", stats.bytes_written);
The recommended way to use the simulator is through SimTestApp:
use testapp::SimTestApp;
use evolve_simulator::SimConfig;
let mut app = SimTestApp::with_config(SimConfig::default(), 42);
// Access simulator directly when needed
let height = app.simulator().time().block_height();
let random = app.simulator_mut().rng().gen_range(0..100);
// Run blocks with generated transactions
let results = app.run_blocks_with(100, |height, sim| {
vec![generate_tx(height, sim)]
});
crates/testing/simulator/src/lib.rs - Main Simulator structcrates/testing/simulator/src/seed.rs - Deterministic RNGcrates/testing/simulator/src/time.rs - Simulated timecrates/testing/simulator/src/storage.rs - Storage with fault injectioncrates/testing/simulator/src/metrics.rs - Performance trackingUse the Evolve execution debugger for trace recording, replay, and time-travel debugging. Use when debugging failing tests, recording execution traces, stepping through state changes, or analyzing execution flow.
Write modules for the Evolve SDK using AccountCode trait and account_impl macro. Use when creating modules, writing account code, using AccountState, storage prefixes, or developing new blockchain modules.
Create custom Evolve blockchain nodes by composing storage, STF, mempool, RPC, and gRPC components. Use when the user wants to create a new node binary, build a custom chain, compose node components, or asks about evd/testapp architecture.
Write property-based tests for Evolve SDK using proptest. Use when writing property tests, invariant testing, fuzz testing, test generators, or finding edge cases.
Overview of Evolve SDK testing infrastructure including TestApp, SimTestApp, MockEnv, and transaction generators. Use when writing tests, setting up test harnesses, using test infrastructure, or choosing between testing approaches.
Analyze State Transition Function implementations for correctness, threading issues, non-determinism, and simplification opportunities. Use when analyzing STF code, checking threading model, finding non-determinism sources, or reviewing execution layer.