Skip to content

Repository files navigation

EthCC — an Ethereum execution client in C

License: MIT OR Apache-2.0

EthCC is an Ethereum execution client written in C, in the style of Firedancer. The goal is full parity with reth: the same results, byte for byte, with less CPU and memory.

Today the execution engine implements every proof-of-stake mainnet rule set: Paris (The Merge, September 2022), Shanghai, Cancun, Prague (Pectra) and Osaka (Fusaka) with the BPO2 blob schedule. It executes real mainnet blocks from execution witnesses, reproduces reth's results byte for byte, and does so about 2× faster than reth's stateless validator on the same blocks.

Status

Component Status
EVM (all Osaka opcodes, EIP-7702), 18 precompiles, tx / block rules ✅ done
Hard forks Paris (The Merge), Shanghai, Cancun, Prague, Osaka (+ BPO1/BPO2): all of proof-of-stake mainnet ✅ done
Merkle Patricia Trie, post-state root ✅ done
Stateless execution from witnesses (poc-exec) ✅ done
Parallel pipeline (witness hashing, sender recovery, storage roots, prefetch) ✅ done
Proof-of-work hard forks (Frontier … London) planned
Storage: libmdbx with EthCC's own schema, per-block commits ✅ done (v0.2)
Initial-state import from a reth datadir (ec-import) ✅ done (v0.2)
Following the chain against its own database, checked against reth (ec-node --shadow) ✅ done (v0.2)
Engine API (engine_newPayloadV4, engine_forkchoiceUpdatedV3, JWT) with an in-memory block tree, undo records and reorgs below the persisted head (ec-node --engine) ✅ done (v0.2)
Block building (engine_getPayload), txpool planned
Staged sync, ERA import planned
P2P (discv4/v5, RLPx, eth/68–69) planned
JSON-RPC (eth_*, debug_*, trace_*, WS/IPC) planned
Txpool and payload building planned

EthCC can follow mainnet behind a consensus client through the Engine API, on its own database. It cannot replace reth yet: it bootstraps its state from a reth database, catches up missing blocks from a reth node, does not build blocks, and has no P2P or user-facing JSON-RPC.

Results

Verified on every change:

Check Result
execution-spec-tests v5.4.0, state tests: Paris / Shanghai / Cancun / Prague / Osaka 1 564 / 1 745 / 16 847 / 18 869 / 19 517 — all pass
execution-spec-tests v5.4.0, blockchain tests: Paris / Shanghai / Cancun / Prague / Osaka (+ fork transitions) 1 624 / 1 849 / 17 685 / 20 859 / 21 558 (+ 295 / 295) — all pass
execution-spec-tests v5.4.0, Engine API fixtures: Paris / Shanghai / Cancun / Prague / Osaka 1 624 / 1 849 / 17 685 / 20 878 / 21 577 — all pass
1 074 consecutive mainnet blocks vs reth (state root, every receipt, bloom, gas, requests) 1 074 identical, 0 different
Differential fuzzing vs geth (goevmlab, 1 h) 8 348 tests, 0 differences

Speed vs reth's stateless validator on the same mainnet blocks (interleaved A/B, median of 3 runs per block; ratio = reth time / EthCC time):

Mode Ratio
1 core, CPU time 1.95×
8 cores, wall clock 1.98×

Details: docs/results/2026-09-summary.md.

Node (v0.2): the full mainnet state imported from reth (421 M accounts, 1.66 B slots; 262 GB database) reproduces reth's state root, and the following live blocks executed against EthCC's own database match reth exactly — state root and every receipt. Details: docs/results/2026-09-v0.2-node.md.

Engine API (v0.2): all 21 577 EEST Osaka Engine API fixtures pass through the JSON-RPC layer against a database, 5 835 fork-switch scenarios pass, and EthCC follows mainnet live through the Engine API. Details: docs/results/2026-09-v0.2b-engine.md.

Build

Requirements: Linux x86-64 with AVX2, SHA and ADX (any recent Intel/AMD CPU), clang (GCC 15.2.0 miscompiles the vendored Firedancer code), GNU make, Python 3.

git clone https://github.com/feofilaktov/EthCC.git && cd EthCC
make                      # debug build: ASan + UBSan, library, tests, tools
make test                 # unit tests
make PROFILE=release      # -O3 -march=native

config.mk uses ~/.local/opt/LLVM-23.1.2-Linux-X64/bin/clang if present, otherwise clang from PATH; override with make CC=....

Verify

# Ethereum execution-spec-tests: fixtures_develop.tar.gz from the EEST v5.4.0 release
export EC_EEST_DIR=/path/to/fixtures
build/release/bin/statetest                  # Osaka state tests
make PROFILE=release blocktest               # Osaka + BPO transition blockchain tests

# Real mainnet blocks from your own reth node (needs the debug RPC namespace)
python3 tools/fetch/fetch.py --follow 100    # fetch each new head block with its witness
build/release/bin/poc-exec ~/Dev/Ethcc-data/mainnet
build/release/bin/poc-exec --threads 8 --bench 3 ~/Dev/Ethcc-data/mainnet

# The blockchain tests again, through an EthCC database (bulk-loaded
# pre-state, a commit per block, post-state read back from the database)
make PROFILE=release blocktest-db
# ... and through the node's block tree; the Engine API fixtures through the
# JSON-RPC layer against a database
build/release/bin/blocktest --db /dev/shm/ecbt --chain
build/release/bin/enginetest --db /dev/shm/ecet --json

# All of the above (unit tests, EEST, mainnet with 1 and 8 threads)
tools/verify.sh

# Speed vs reth's stateless validator on the same blocks
tools/bench-reth/setup.sh
python3 tools/bench/ab.py ~/Dev/Ethcc-data/mainnet 3 7

# Differential fuzzing against geth (goevmlab)
tools/fuzz/run.sh 3600 4

Run a node (shadow mode)

EthCC builds its database from a synced reth node (reth 2.x, default "storage v2" layout), then follows that node's chain, executing every block against its own database and checking every root against the block header.

make PROFILE=release
# one-time import: reth's database is opened read-only (reth keeps running);
# its state root must match, or no head is written
build/release/bin/ec-import --reth-db /path/to/reth/datadir/db --db ~/ethcc-db --rpc http://127.0.0.1:8545
# follow the chain two blocks behind reth, comparing every receipt too
build/release/bin/ec-node --shadow --db ~/ethcc-db --rpc http://127.0.0.1:8545 --threads 8 --receipts

The reth node must expose the eth and debug RPC namespaces.

Behind a consensus client (Engine API)

# EthCC's Engine API on 127.0.0.1:8552 (JWT secret file as for reth/Lighthouse);
# --backfill-rpc catches up the blocks between the database and the network
build/release/bin/ec-node --engine --db ~/ethcc-db --jwt jwt.hex --authrpc-port 8552 \
    --threads 8 --backfill-rpc http://127.0.0.1:8545

Two ways to feed it without giving up reth:

  • ec-replay reads beacon blocks from a consensus client's REST API (read-only) and sends EthCC exactly the engine_newPayloadV4 / engine_forkchoiceUpdatedV3 calls the consensus client would send (--follow keeps up with the head).
  • ec-mirror sits between the consensus client and reth: reth answers every call, and the Engine API traffic is copied to EthCC, with every status compared (DIFF lines on disagreement). Point the consensus client's --execution-endpoint at ec-mirror.
build/release/bin/ec-replay --engine http://127.0.0.1:8552 --jwt jwt.hex --beacon http://127.0.0.1:5052 --follow
build/release/bin/ec-mirror --listen 127.0.0.1:8550 --jwt jwt.hex \
    --primary http://127.0.0.1:8551 --secondary http://127.0.0.1:8552 --secondary-jwt ethcc-jwt.hex
```  The import
holds a read snapshot of reth's database for its whole duration, which makes
reth's database file grow while it runs.

## Layout

src/util arenas, thread pool, hex, big-stack threads, .ecfx fixture reader src/prim 256-bit integers, strict RLP, transactions / headers / blocks / receipts src/crypto keccak (Firedancer + s2n-bignum; 4-way AVX2 via XKCP), sha256, secp256k1 (libsecp256k1), P-256 and bn254 (Firedancer), RIPEMD-160, BLAKE2F, MODEXP src/state journaled world-state overlay over a pluggable backend src/evm computed-goto interpreter, calls / creates / EIP-7702, all Osaka precompiles src/trie Merkle Patricia Trie with lazy node resolution, parallel state root src/exec transaction and block rules, system calls, requests, witness backend src/db libmdbx database: schema, state view and backend, per-block commit, bulk loader src/import read-only reader of a reth datadir (Compact decoders) src/net HTTP/JSON-RPC client and server, JWT src/node Engine API: payloads, block tree of recent blocks, JSON-RPC methods src/app ec-node (engine / shadow), ec-import, ec-replay, ec-mirror, poc-exec tests unit tests; EEST runners (statetest, blocktest) tools reth fixture fetcher, verification, A/B benchmark, fuzzing, vendoring scripts deps vendored third-party code (each directory has SOURCE and LICENSE files) docs design, implementation plan, results


## Roadmap

1. **Tip-following node** — done (v0.2): libmdbx storage with EthCC's own
   schema, import from a reth database, Engine API behind a consensus client
   with reorgs among recent blocks, every root checked.
2. **All hard forks** from Frontier, staged sync from genesis, ERA import.
3. **P2P** (discovery, RLPx, eth wire).
4. **JSON-RPC parity** with reth (`eth_*`, `debug_*`, `trace_*`, subscriptions).
5. **Txpool and payload building**; pruning, CLI, metrics.

Progress is tracked in [issues](https://github.com/feofilaktov/EthCC/issues) and
[milestones](https://github.com/feofilaktov/EthCC/milestones).

## Contributing and security

See [CONTRIBUTING.md](CONTRIBUTING.md). Report vulnerabilities privately as
described in [SECURITY.md](SECURITY.md). Release history: [CHANGELOG.md](CHANGELOG.md).

## License

Licensed under either of

- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or <https://www.apache.org/licenses/LICENSE-2.0>)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or <https://opensource.org/licenses/MIT>)

at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in this project by you, as defined in the Apache-2.0 license,
shall be dual licensed as above, without any additional terms or conditions.

Third-party code under `deps/` keeps its own license (see each directory's
LICENSE / COPYING and SOURCE files): Firedancer, blst, c-kzg-4844 and libmdbx
are Apache-2.0; libsecp256k1 and yyjson are MIT; XKCP is CC0.

About

Ethereum execution client in C, Firedancer-style. Consensus-identical to reth, ~2x faster execution.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages