← back to projects

Mini ETH Node

May 2026 – Presentactive
RustEthereumRLPECDSAMerkle Patricia TrieTCPAsyncExecution

// the problem

A full Ethereum client has many moving pieces: primitive types, RLP, hashing, signatures, state roots, block validation, transaction execution, receipts, networking, peer management, and chain-head updates. Reading production clients is valuable, but the size of those systems makes it difficult to isolate the core execution-node flow. Mini ETH Node narrows the scope to signed value-transfer blocks so the essential mechanics are visible end to end.

// the design decision

The node accepts signed value-transfer blocks over an async TCP protocol. It validates parent/head relationships, recovers transaction senders, executes transactions against in-memory state, computes receipts and gas accounting, commits blocks, updates the shared chain head, and exposes account-state and chain-head queries. A deterministic test client reconstructs genesis keys, queries node state before building each block, signs transactions, sends blocks one at a time, and resumes from the node's current head across runs.

// key implementation detail

Workspace boundaries: core/types: Ethereum-style addresses, hashes, headers, blocks, accounts, transactions, genesis config, and chain head. core/rlp-codec: RLP encoding/decoding, Keccak/RLP header hashing, ECDSA signing and sender recovery, Merkle Patricia Trie state-root calculation. core/execution: Provider traits, in-memory provider, executor, validator, value-transfer pipeline, receipts, gas accounting, nonce and balance checks, journal rollback. core/networking: TCP protocol, framed codec, connection tasks, peer manager, handshake, ping/pong, block forwarding, account-state query, and chain-head query. processor: Pending queue, out-of-order buffering, parent/head validation, execution, block commitment, stale-block rejection, and metrics. node: Runtime wiring for listener, networking manager, processor adapter, shared chain head, tracing, graceful shutdown, and deterministic test client.

// what i learned

Separating protocol routing from authoritative state makes the system much easier to reason about: networking never imports processor types, and the processor remains the source of truth for account state and chain-head updates. The block builder is deliberately state-light; it signs blocks from snapshots returned by the node instead of predicting execution locally. That constraint keeps test behavior deterministic while matching the way real clients should treat canonical state.