lambdaclass / lambda_ethereum_rust

Lambda Ethereum Rust Execution client
Apache License 2.0
163 stars 19 forks source link
eth ethereum rollup zk-rollup

Lambda Ethereum Rust Execution Client

Telegram Chat license

📚 References and acknowledgements

The following links, repos, companies and projects have been important in the development of this repo, we have learned a lot from them and want to thank and acknowledge them.

If we forgot to include anyone, please file an issue so we can add you. We always strive to reference the inspirations and code we use, but as an organization with multiple people, mistakes can happen, and someone might forget to include a reference.

Philosophy

Many long-established clients accumulate bloat over time. This often occurs due to the need to support legacy features for existing users or through attempts to implement overly ambitious software. The result is often complex, difficult-to-maintain, and error-prone systems.

In contrast, our philosophy is rooted in simplicity. We strive to write minimal code, prioritize clarity, and embrace simplicity in design. We believe this approach is the best way to build a client that is both fast and resilient. By adhering to these principles, we will be able to iterate fast and explore next-generation features early, either from the Ethereum roadmap or from innovations from the L2s.

Read more about our engineering philosophy here

Design Principles

L1 and L2 support

This client supports running in two different modes:

We call the first one Lambda Ethereum Rust L1 and the second one Lambda Ethereum Rust L2.

Lambda Ethereum Rust L2

Full Roadmap

The main differences between this mode and regular Ethereum Rust are:

Lambda Ethereum Rust L1

Table of Contents

Roadmap

An Ethereum execution client consists roughly of the following parts:

Because most of the milestones below do not overlap much, we are currently working on them in parallel.

Milestone 1: Read-only RPC Node Support

Implement the bare minimum required to:

In a bit more detail:

Task Description Status
Add libmdbx bindings and basic API, create tables for state (blocks, transactions, etc)
EVM wrapper for block execution
JSON RPC API server setup
RPC State-serving endpoints 🏗️ (almost done, a few endpoint are left)
Basic Engine API implementation. Set new chain head (forkchoiceUpdated) and new block (newPayload).

See detailed issues and progress for this milestone here.

Milestone 2: History & Reorgs

Implement support for block reorganizations and historical state queries. This milestone involves persisting the state trie to enable efficient access to historical states and implementing a tree structure for the blockchain to manage multiple chain branches. It also involves a real implementation of the engine_forkchoiceUpdated Engine API when we do not have to build the block ourselves (i.e. when payloadAttributes is null).

Task Description Status
Persist data on an on-disk Merkle Patricia Tree using libmdbx
Engine API forkchoiceUpdated implementation (without payloadAttributes) 🏗️
Support for RPC historical queries, i.e. queries (eth_call, eth_getBalance, etc) at any block

Detailed issues and progress here.

Milestone 3: Block building

Add the ability to build new payloads (blocks), so the consensus client can propose new blocks based on transactions received from the RPC endpoints.

Task Description Status
engine_forkchoiceUpdated implementation with a non-null payloadAttributes 🏗️
engine_getPayload endpoint implementation that builds blocks. 🏗️
Implement a mempool and the eth_sendRawTransaction endpoint where users can send transactions

Detailed issues and progress here.

Milestone 4: P2P Network

Implement the peer to peer networking stack, i.e. the DevP2P protocol. This includes discv4, RLPx and the eth capability. This will let us get and retrieve blocks and transactions from other nodes. We'll add the transactions we receive to the mempool. We'll also download blocks from other nodes when we get payloads where the parent isn't in our local chain.

Task Description Status
Implement discv4 for peer discovery
Implement the RLPx transport protocol 🏗️
Implement the eth capability 🏗️

Detailed issues and progress here.

Milestone 5: State Sync

Add support for the SNAP protocol, which lets us get a recent copy of the blockchain state instead of going through all blocks from genesis. This is used for used for snap sync. Since we don't support older versions of the spec by design, this is a prerequisite to being able to sync the node with public networks, including mainnet.

Task Description Status
Implement SNAP protocol for snap syncing

Detailed issues and progress here.

Quick Start (L1 localnet)

Demo

Prerequisites

This make target will:

  1. Build our node inside a docker image.
  2. Fetch our fork ethereum package, a private testnet on which multiple ethereum clients can interact.
  3. Start the localnet with kurtosis.

If everything went well, you should be faced with our client's logs (ctrl-c to leave)

To stop everything, simply run:

make stop-localnet

Dev Setup

Build

Rust

To build the node, you will need the rust toolchain:

  1. First, install asdf:
  2. Add the rust plugin:
    asdf plugin-add rust https://github.com/asdf-community/asdf-rust.git
  3. cd into the project and run:
    asdf install

You now should be able to build the client:

make build

Database

Currently, the database is libmdbx, it will be set up when you start the client. The location of the db's files will depend on your OS:

You can delete the db with:

cargo run --bin ethereum_rust -- removedb

Test

For testing, we're using three kinds of tests.

Ethereum Foundation Tests

These are the official execution spec tests, you can execute them with:

make test

This will download the test cases from the official execution spec tests repo and run them with our glue code under cmd/ef_tests/tests.

Crate Specific Tests

The second kind are each crate's tests, you can run them like this:

make test CRATE=<crate>

For example:

make test CRATE="ethereum_rust-blockchain"
Hive Tests

Finally, we have End-to-End tests with hive. Hive is a system which simply sends RPC commands to our node, and expects a certain response. You can read more about it here.

Prereqs

We need to have go installed for the first time we run hive, an easy way to do this is adding the asdf go plugin:

asdf plugin add golang https://github.com/asdf-community/asdf-golang.git

# If you need to se GOROOT please follow: https://github.com/asdf-community/asdf-golang?tab=readme-ov-file#goroot

And uncommenting the golang line in the asdf .tool-versions file:

rust 1.80.1
golang 1.23.2
Running Simulations

Hive tests are categorized by "simulations', and test instances can be filtered with a regex:

make run-hive-debug SIMULATION=<simulation> TEST_PATTERN=<test-regex>

This is an example of a Hive simulation called ethereum/rpc-compat, which will specificaly run chain id and transaction by hash rpc tests:

make run-hive SIMULATION=ethereum/rpc-compat TEST_PATTERN="/eth_chainId|eth_getTransactionByHash"

If you want debug output from hive, use the run-hive-debug instead:

make run-hive-debug SIMULATION=ethereum/rpc-compat TEST_PATTERN="*"

This example runs every test under rpc, with debug output

Run

Example run:

cargo run --bin ethereum_rust -- --network test_data/genesis-kurtosis.json

The network argument is mandatory, as it defines the parameters of the chain. For more information about the different cli arguments check out the next section.

CLI Commands

Ethereum Rust supports the following command line arguments:

Crates documentation

Documentation for each crate can be found on the following links (still a work in progress, we will be adding more documentation as we go).