kaysentinel / docs /differential_testing.md
Sahek's picture
Reorganize into docs/scripts/tests folders
a385722 verified
|
Raw
History Blame Contribute Delete
3 kB
# Differential Testing Engine
To guarantee convergence between Ο†_geth(E_Geth) and Ο†_reth(E_Reth), this differential testing engine generates deterministic execution paths that maximize EVM edge-case entropy, runs them through both client boundary implementations, and checks bitwise identity over the resulting SSZ-serialized Ξ”_canonical byte streams.
## 1. Test Harness Format
Test vectors are defined as JSON (`KaysentinelTestCase`): a pre-state configuration, a transaction to execute, and the expected SSR root. See `tests/transient_storage_case.json` for a worked example.
## 2. Edge-Case Matrix
### Test Vector 1 β€” Transient Storage `TraceMid` Clean-Up (EIP-1153)
**Objective:** verify the extractor pulls transient storage values *before* VM teardown purges them, while ignoring keys written inside sub-calls that reverted.
**Execution path:**
1. `Tx.to` calls Contract A.
2. A executes `TSTORE(slot=0x01, value=0xAA)`.
3. A `DELEGATECALL`s into Contract B.
4. B executes `TSTORE(slot=0x01, value=0xBB)` and `TSTORE(slot=0x02, value=0xCC)`.
5. B hits `REVERT`, rolling back its stack frame.
**Assertion:** the final `TransientMutation` list for Contract A in Ξ”_canonical must contain exactly one entry β€” `[slot=0x01, value=0xAA]`. B's writes must be fully discarded, proving extraction happens at the TraceMid β†’ Post boundary and doesn't pick up stale tree artifacts.
### Test Vector 2 β€” Post-Cancun `SELFDESTRUCT` Lifecycles (EIP-6780)
**Objective:** validate lifecycle statuses assigned by Geth's `core/state/journal.go` and Reth's `BundleState` align with Cancun semantics.
**Execution path:**
1. `Tx.to` deploys Contract C via `CREATE2`.
2. C calls a function executing `SELFDESTRUCT` targeting an external escrow vault, same transaction.
3. Contract D (100+ blocks old) is also forced to `SELFDESTRUCT` in the same block.
**Assertion:** C's account entry must show `lifecycle_status = 2` (`SELFDESTRUCT_PENDING`) with balance wiped. D's account entry must stay `lifecycle_status = 0` (`LIVE`), code intact, only the balance mutation recorded.
### Test Vector 3 β€” High-Entropy Multi-Account Modification (Sorting Validation)
**Objective:** stress-test map iteration ordering differences between Go's randomized map traversal and Rust's `BTreeMap`.
**Execution path:**
1. A proxy batching contract runs 20 sub-calls touching randomly generated addresses (A1...A20) via `BALANCE` modifications and storage initialization.
2. Addresses are touched out of sequential order at runtime (e.g. A15 β†’ A3 β†’ A19).
**Assertion:** Geth and Reth extractors must produce byte-identical SSZ output, proving `account_mutations` is sorted ascending lexicographically by address and `storage_diffs` by slot before serialization.
## 3. Verification Script
See `scripts/verify_ssr.py`. It takes the SSZ byte outputs from both runtimes, checks length equality, computes SHA-256 digests, and β€” on mismatch β€” walks the byte streams to report the first differing offset.