A from-scratch Rust implementation of Ethereum protocol primitives. The goal is to internalise every significant pattern used in Reth, Revm, Lighthouse, and Alloy by building miniature versions of them.
Rule: every function returns Result. No .unwrap() outside tests.
rust-eth-playground/
├── types/ # Newtypes, Transaction enum, errors
├── rlp-codec/ # RLP encode/decode, signing, Merkle Patricia Trie
├── networking/ # Async TCP p2p with tokio + mpsc/broadcast
└── execution/ # Provider traits, executor, validator, pipeline
The crates form a layered dependency graph: types → rlp-codec → execution, with networking depending on types and rlp-codec.
Address(20 bytes),B256(32 bytes),Bloom(256 bytes) as newtypes with manually implementedDisplay,LowerHex,UpperHex,From,AsRef,TryFrom<&[u8]>,FromStr,Hash,Default.Transactionenum withLegacy,Eip1559, andEip4844variants, plusAccessListItem.- Helper methods:
effective_gas_price,max_cost,tx_type,is_create, all using checked arithmetic. DecodeErrorandTransactionErrorbuilt withthiserror, including#[from]conversions.
RlpItemenum with hand-written encoder and decoder covering single bytes, short/long strings, and short/long lists.RlpEncodableandRlpDecodabletraits implemented foru64,u128,bool,Vec<u8>,Address,B256, andTransaction.- Roundtrip tests over deeply-nested and edge-case inputs.
- EIP-155 transaction signing (
signing.rs): keccak256 helper, EIP-155 legacy payload, EIP-2718 typed envelopes for EIP-1559 / EIP-4844, ECDSA signing viak256, sender recovery,SignedTransaction::hash()over the wire format.SigningErrorpropagates RLP and ECDSA failures via#[from]. - Merkle Patricia Trie (
trie.rs): leaf / extension / branch nodes, nibble-walking insert with path-splitting,root_hashthat inlines nodes < 32 bytes and hashes larger ones.
tokio_util::codec::{Encoder, Decoder}implementation using a 4-byte big-endian length prefix, 1-byte type tag, and RLP-encoded payload, with partial-read handling.- Message enum:
Ping,Pong,Status,Transactions,GetBlockHeaders. - Three-layer architecture: TCP listener → per-connection tasks → central manager task communicating over
mpscchannels. tokio::select!in the manager driving peer messages, a 10-second ping interval, and abroadcast-channel shutdown wired to ctrl-c.- Shared chain state behind
Arc<RwLock<...>>. JoinSet-based graceful shutdown.
- Five provider traits (
BlockProvider,HeaderProvider,StateProvider,TransactionProvider,ReceiptProvider) and aFullProvidersupertrait with a blanket impl, mirroring Reth's split. InMemoryProviderbacked byHashMaps implementing all five traits.CachedProvider<T>— generic cache wrapper exercising trait bounds, forwarding, and interior-mutability decisions.BlockExecutortrait with associated output type,ConsensusValidatortrait, and aPipelinegeneric over four trait-bounded type parameters.- Production-faithful sender handling: blocks store
Vec<SignedTransaction>; senders are recovered into aBlockWithSenders { block, senders }wrapper before execution, mirroring Reth's pattern (rather than cachingfromon the transaction the way geth does). - Receipts use the real
SignedTransaction::hash()rather than a placeholder.
cargo build --workspace
cargo test --workspace
# Run the networking demo binary
cargo run -p networking