Skip to content

Epic: RPC — ETH Compliance, Performance & Correctness Testing #7

@tac0turtle

Description

@tac0turtle

Goal

Make Evolve's JSON-RPC layer fully Ethereum-compliant, high-performance, and rigorously tested. The end state: MetaMask and all standard Ethereum wallets/tooling (ethers.js, viem, wagmi, Foundry, Hardhat) work out of the box with zero quirks, and the RPC is never the bottleneck for transaction submission or query throughput.

Current State

  • Implemented methods: eth_chainId, eth_blockNumber, eth_getBalance, eth_getTransactionCount, eth_getBlockByNumber/Hash, eth_getTransactionByHash, eth_getTransactionReceipt, eth_call, eth_estimateGas, eth_gasPrice, eth_sendRawTransaction, eth_getLogs, eth_syncing, eth_protocolVersion, eth_getCode, eth_getStorageAt, eth_feeHistory, eth_maxPriorityFeePerGas, eth_getBlockTransactionCountByNumber/Hash, web3_clientVersion, web3_sha3, net_version, net_listening, net_peerCount
  • Subscriptions: newHeads, logs, newPendingTransactions, syncing via WebSocket
  • Observability: Prometheus metrics endpoint, health endpoint
  • Missing methods: Several methods required by wallets (see below)
  • No compliance test suite: No automated verification against the ETH JSON-RPC spec
  • No load testing: No benchmarks for RPC throughput or latency
  • Stub implementations: fee_history returns zero fees, net_peerCount returns 0

Scope

1. ETH JSON-RPC Compliance — Missing Methods

Methods required by MetaMask and common tooling that are not yet implemented:

  • eth_accounts — Returns list of addresses owned by client (return empty for non-custodial)
  • eth_sign / eth_signTransaction — Return proper "not supported" errors (MetaMask expects these to exist)
  • eth_getTransactionByBlockHashAndIndex — Required by block explorers
  • eth_getTransactionByBlockNumberAndIndex — Required by block explorers
  • eth_getBlockReceipts — Batch receipt fetching (used by indexers)
  • eth_getUncleCountByBlockHash / eth_getUncleCountByBlockNumber — Return 0 (no uncles, but wallets call these)
  • eth_getUncleByBlockHashAndIndex / eth_getUncleByBlockNumberAndIndex — Return null
  • eth_newFilter / eth_newBlockFilter / eth_newPendingTransactionFilter / eth_getFilterChanges / eth_getFilterLogs / eth_uninstallFilter — HTTP polling filter API (MetaMask uses these when WebSocket is unavailable)
  • eth_createAccessList — Used by wallets for EIP-2930 tx optimization
  • eth_getProof — Merkle proof for account/storage (used by bridges and light clients)
  • debug_traceTransaction / debug_traceBlockByNumber — Optional but needed for debugging tooling (Tenderly, Foundry)

2. ETH Compliance Correctness Testing

  • Ethereum JSON-RPC spec conformance suite: Automated tests that verify every implemented method returns spec-compliant responses (correct field names, correct hex encoding, correct types)
  • MetaMask connection test: Automated end-to-end test that simulates the MetaMask handshake sequence:
    1. eth_chainId
    2. net_version
    3. eth_blockNumber
    4. eth_getBalance
    5. eth_gasPrice / eth_maxPriorityFeePerGas / eth_feeHistory
    6. eth_getTransactionCount (nonce)
    7. eth_estimateGas
    8. eth_sendRawTransaction
    9. eth_getTransactionReceipt (polling)
  • ethers.js / viem integration tests: Send real transactions using ethers.js and viem clients against a running node, verify end-to-end correctness
  • Foundry compatibility test: forge script and cast against a running Evolve node
  • Block/receipt/log field correctness: Verify all RPC response fields match Ethereum expectations:
    • Block: baseFeePerGas present, mixHash/nonce correct defaults, size non-zero
    • Receipt: status, cumulativeGasUsed, effectiveGasPrice, type field present
    • Transaction: v/r/s fields correct, type field present, accessList when applicable
    • Logs: logIndex, transactionIndex, blockNumber all populated
  • Error code compliance: Verify JSON-RPC error codes match the spec (-32700 parse error, -32600 invalid request, -32601 method not found, -32602 invalid params, -32603 internal error, -32000 execution reverted with revert data)
  • Edge case testing: earliest/latest/pending/safe/finalized block tags, zero address, empty data, max u256 values, nonexistent blocks/txs return null not error

3. Performance Testing & Optimization

  • Load testing harness: Build or integrate a load testing tool (e.g., custom Rust tool, vegeta, k6) that hammers the RPC with realistic workloads
  • Throughput benchmarks:
    • eth_sendRawTransaction submissions/sec (target: RPC should not be the bottleneck — must exceed block gas consumption rate)
    • eth_getBalance / eth_getTransactionCount queries/sec (read-heavy wallet workload)
    • eth_getBlockByNumber with full transactions (large response serialization)
    • eth_getLogs with broad filters (index query performance)
    • eth_call execution (dry-run throughput)
  • Latency benchmarks: p50/p95/p99 latency for each method category (read, write, subscription)
  • Concurrent connection limits: Test with 100, 1000, 10000 concurrent WebSocket connections
  • WebSocket subscription throughput: Measure event delivery latency for newHeads and logs under load
  • Serialization performance: Profile JSON serialization/deserialization — consider simd-json if it's a bottleneck
  • Connection pooling: Verify jsonrpsee handles connection reuse efficiently
  • Batch request support: Verify JSON-RPC batch requests work and benchmark batch vs. individual call performance
  • CI performance regression tests: Track key latency/throughput metrics across commits

4. Fee/Gas Correctness

The current fee_history and gas-related methods return hardcoded zeros. This breaks wallet UX.

  • eth_feeHistory: Return actual base fee history from indexed blocks (wallets use this to suggest gas prices)
  • eth_gasPrice: Return a meaningful gas price (even if fixed/low, MetaMask uses this to populate the tx form)
  • eth_maxPriorityFeePerGas: Return a sensible default (wallets add this to base fee)
  • eth_estimateGas: Verify accuracy — should return gas that is sufficient but not wildly over-estimated
  • EIP-1559 fee fields: Ensure block responses include correct baseFeePerGas and receipts include effectiveGasPrice

5. Subscription Correctness

  • newHeads delivers all blocks: No gaps under high block production
  • logs filtering: Verify address and topic filters match Ethereum semantics exactly (OR within position, AND across positions)
  • Subscription backpressure: Test behavior when subscriber can't keep up (current: lagged messages dropped with warning — verify this is acceptable)
  • Reconnection handling: Test that clients can reconnect and resubscribe without losing data
  • newPendingTransactions: Verify hash is emitted when tx enters mempool, not on execution

6. RPC Server Hardening

  • Request size limits: Cap incoming request body size to prevent OOM
  • Rate limiting: Per-IP or per-connection rate limiting for public deployments
  • Timeout configuration: Request execution timeouts to prevent slow queries from blocking the server
  • CORS configuration: Configurable CORS headers (MetaMask needs this for browser dApps)
  • Batch request limits: Cap the number of requests in a JSON-RPC batch
  • eth_getLogs result limits: Cap the number of logs returned per query to prevent memory exhaustion
  • Connection limits: Max concurrent HTTP and WebSocket connections

Success Criteria

  1. MetaMask connects, displays balance, sends a transaction, and shows the receipt — zero errors, zero workarounds.
  2. ethers.js, viem, and Foundry (cast, forge script) work against Evolve without custom provider configuration.
  3. Automated compliance test suite passes on every PR, covering all implemented methods against the ETH JSON-RPC spec.
  4. eth_sendRawTransaction throughput exceeds 10,000 submissions/sec (RPC layer only, excluding STF execution).
  5. p99 latency for read methods (eth_getBalance, eth_blockNumber) under load is <10ms.
  6. All fee/gas methods return meaningful values that wallets can use without user confusion.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions