Skip to content

chore(testing): add Anvil-based EVM integration harness - #231

Open
Markodiba wants to merge 1 commit into
Octo-Protocol-org:mainfrom
Markodiba:chore/anvil-integration-harness
Open

chore(testing): add Anvil-based EVM integration harness#231
Markodiba wants to merge 1 commit into
Octo-Protocol-org:mainfrom
Markodiba:chore/anvil-integration-harness

Conversation

@Markodiba

@Markodiba Markodiba commented Aug 25, 2026

Copy link
Copy Markdown

Summary

Implements issue #219 (doc Issue #7 in docs/ethereum-expansion-issues.md): a local Anvil
(Foundry) devnet harness for EVM integration tests, giving EVM work the same local-devnet story
Stellar already has via StellarNetwork::Standalone
(crates/wallet-core/src/signer.rs).

  • New octo-evm-test-support crate (crates/evm-test-support):
    • AnvilInstance: spawns anvil --port 0 per test (random free port, own process), parses the
      real bound port from its startup banner, confirms readiness by polling eth_chainId, and
      kills the process in Drop — including on panic, since Drop runs during unwind.
    • MockErc20: deploys a constructor-configurable-decimals ERC-20
      (contracts/MockERC20.sol, precompiled bytecode checked in as contracts/MockERC20.bin so
      only anvil, not solc, needs to be on PATH), with mint/transfer/balance_of helpers
      that produce real Transfer logs.
    • Reorg controls: snapshot() / revert_to(id) (anvil_snapshot/anvil_revert), mine(n)
      (evm_mine), set_base_fee(wei) (anvil_setNextBlockBaseFeePerGas) — the primitive feat(ingest): Confirmation depth and reorg handling for EVM deposits #222
      (reorg handling) depends on, since a reorg can't be induced on demand on a public testnet.
    • gate() mirrors the OCTO_LIVE_TESTS pattern in
      crates/api/tests/horizon_live_tests.rs: tests skip
      cleanly (not fail) unless OCTO_EVM_TESTS=1 and anvil is on PATH, so just test stays
      green with no Foundry installed.
  • just test-evm recipe; CI installs Foundry (foundry-rs/foundry-toolchain@v1) and runs it.
  • CONTRIBUTING.md: documents the optional Foundry install.

Scope note: the issue says "Depends on #218" (octo-evm-rpc, the resilient typed JSON-RPC
client) and suggests crates/evm-rpc/tests/common/anvil.rs, but neither crates/evm-core (#217)
nor crates/evm-rpc (#218) exist in this repo yet. The issue itself anticipates this and offers a
fallback — "or a small test-support crate if #221/#224 also need it" — which is what this PR does:
a standalone crate with its own minimal JSON-RPC client (src/rpc.rs, just enough to drive Anvil,
including the HTTP-200-with-error-member check #218 will also need) and no dependency on
unbuilt crates. Transactions go through plain eth_sendTransaction against Anvil's pre-unlocked
default accounts (derived from Anvil's own default deterministic mnemonic — no --mnemonic flag
needed), so no client-side secp256k1 signing dependency was pulled in; that's #217/#218's job, not
this harness's.

Test plan

  • cargo build --workspace and cargo test --workspace — new crate's tests skip cleanly with
    no OCTO_EVM_TESTS/no Foundry, rest of the workspace unaffected.
  • just test-evm (Foundry installed locally) — all pass:
    • anvil_boots_and_mining_advances_the_chain — boots Anvil, mine(3), asserts
      eth_blockNumber advances by exactly 3.
    • snapshot_and_revert_undoes_a_mined_transfer — deploys MockErc20, mines a Transfer,
      snapshots, mines more, reverts, asserts the transfer's receipt is gone — the reorg proof feat(ingest): Confirmation depth and reorg handling for EVM deposits #222
      needs.
    • mock_erc20_supports_usdc_dai_and_zero_decimal_configs — exercises 6/18/0 decimals end to end.
    • drop_kills_the_anvil_process_even_when_the_test_panics (#[cfg(unix)]) — panics inside
      catch_unwind with the instance moved in, then confirms via kill -0 that the process is
      dead.
    • suite_skips_cleanly_when_the_env_var_is_unset plus deterministic unit tests of the skip
      predicate in src/lib.rs (no PATH/env mutation, so no flakiness under parallel tests).
  • Verified no orphan anvil processes after a full test run (pgrep anvil).
  • cargo fmt --all -- --check, cargo clippy -p octo-evm-test-support --all-targets -- -D warnings.
  • Selector-encoding unit tests cross-checked against cast keccak (Foundry) for the standard
    ERC-20 signatures.

closes #219

Gives EVM work the local-devnet story Stellar already has via
StellarNetwork::Standalone, with per-test isolated instances on random
ports and deterministic funded accounts.

Exposes anvil_snapshot/anvil_revert so reorg handling (Octo-Protocol-org#222) is testable
at all -- a reorg cannot be induced on a public testnet on demand.

Skips cleanly when Foundry is absent so `just test` stays green.

The upstream evm-rpc client (Octo-Protocol-org#218) doesn't exist yet, so this lands as a
standalone octo-evm-test-support crate per the issue's own fallback
("or a small test-support crate if Octo-Protocol-org#221/Octo-Protocol-org#224 also need it") rather than
under crates/evm-rpc/tests/common.

Refs Octo-Protocol-org#219

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

chore(testing): Anvil-based EVM integration test harness

1 participant