Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/prompts/ai-review.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
You are a senior code reviewer for ethlambda, a minimalist Lean Ethereum consensus client written in Rust.
You are a senior code reviewer for ethlambda, a minimalist Beacon Chain and Lean Chain client written in Rust.

Review this PR focusing on:
- Code correctness and potential bugs
Expand Down
5 changes: 3 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# ethlambda Development Guide

Development reference for ethlambda - minimalist Lean Ethereum consensus client.
Not to be confused with Ethereum consensus clients AKA Beacon Chain clients AKA Eth2 clients.
Development reference for ethlambda - minimalist Beacon Chain and Lean Chain client.
The two are different protocols sharing one binary: `ethlambda beacon` follows the
Ethereum Beacon Chain (AKA Eth2), and `ethlambda node` runs Lean consensus.

## Quick Reference

Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Contributing to ethlambda

Thanks for your interest in contributing to ethlambda — a minimalist Lean Consensus client for Ethereum, written in Rust.
Thanks for your interest in contributing to ethlambda — a minimalist Beacon Chain and Lean Chain client for Ethereum, written in Rust.

Before diving in, we recommend reading [our introductory blog post](https://blog.lambdaclass.com/introducing-ethlambda-a-lean-consensus-client-for-ethereums-next-era/) to understand the project's goals and philosophy.

Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ FROM ubuntu AS runtime
WORKDIR /app

LABEL org.opencontainers.image.source=https://github.com/lambdaclass/ethlambda
LABEL org.opencontainers.image.description="A minimalist and fast Lean Consensus client written in Rust by LambdaClass"
LABEL org.opencontainers.image.description="A minimalist and fast Beacon Chain and Lean Chain client written in Rust by LambdaClass"
LABEL org.opencontainers.image.licenses="MIT"

ARG GIT_COMMIT=unknown
Expand Down
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

# ethlambda

Minimalist, fast and modular implementation of the Lean Ethereum client written in Rust.
Minimalist, fast and modular implementation of a Beacon Chain and Lean Chain client written in Rust.

🌐 Visit our website at [**ethlambda.xyz**](https://ethlambda.xyz) to learn more about the project.

Expand Down Expand Up @@ -184,8 +184,8 @@ cargo build --release

#### `ethlambda node` — the Lean consensus chain

This is what the rest of this README is about, and it is the default: a bare
flag list with no sub-command still runs the node, so existing scripts and
The [devnet section](#running-in-a-devnet) below runs this sub-command, and it
is the default: a bare flag list with no sub-command still runs the node, so existing scripts and
Docker entrypoints keep working unchanged.

It needs a genesis config, a validator registry, a bootnode list and this
Expand Down Expand Up @@ -316,7 +316,11 @@ Full documentation is available in the [`docs/`](./docs) directory. Please refer

## Current status

The client implements the core features of a Lean Ethereum consensus client:
ethlambda is a Beacon Chain and Lean Chain client. On the Beacon Chain
(`ethlambda beacon`), it follows a network from a checkpoint-synced anchor and serves
the standard Beacon API; see the [Beacon Chain follower](#beacon-chain-follower)
quickstart. On the Lean Chain (`ethlambda node`), it implements the core features of a
Lean consensus client:

- **Networking** — libp2p peer connections, STATUS message handling, gossipsub for blocks and attestations
- **State management** — genesis state generation, state transition function, block processing
Expand Down
2 changes: 1 addition & 1 deletion book.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ authors = ["lambdaclass"]
language = "en"
src = "docs"
title = "ethlambda"
description = "Minimalist, fast and modular implementation of the Lean Ethereum client written in Rust"
description = "Minimalist, fast and modular implementation of a Beacon Chain and Lean Chain client written in Rust"

[rust]
edition = "2024"
Expand Down
17 changes: 9 additions & 8 deletions docs/3sf_mini.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# 3SF-mini: Justification & Finalization

ethlambda uses **3SF-mini** (Three-Stage Finality, minimal version) for justification
and finalization. Unlike the Ethereum Beacon Chain's epoch-based Casper FFG, 3SF-mini
operates at the **slot level**: any slot can be justified, not just epoch boundaries.
ethlambda's Lean Chain (`ethlambda node`) uses **3SF-mini** (Three-Stage Finality,
minimal version) for justification and finalization. Unlike the Ethereum Beacon Chain's
epoch-based Casper FFG, which `ethlambda beacon` follows, 3SF-mini operates at the
**slot level**: any slot can be justified, not just epoch boundaries.

## Quick Example: Three Slots to Finality

Expand Down Expand Up @@ -78,7 +79,7 @@ A checkpoint becomes **justified** when at least two-thirds of validators attest

The threshold is computed as: `3 × vote_count >= 2 × validator_count`

> **In ethlambda:** Justification and finalization are processed inside
> **In ethlambda's Lean Chain:** Justification and finalization are processed inside
> `process_attestations()` in `crates/blockchain/state_transition/src/lib.rs`,
> called from `process_block()`. The supermajority check is
> `3 * vote_count >= 2 * validator_count`.
Expand All @@ -98,7 +99,7 @@ finalized slot. This is the novel part of 3SF-mini.

A slot is **justifiable** if `delta = slot - finalized_slot` matches any rule:

> **In ethlambda:** The function `slot_is_justifiable_after(slot, finalized_slot)` in
> **In ethlambda's Lean Chain:** The function `slot_is_justifiable_after(slot, finalized_slot)` in
> `crates/blockchain/state_transition/src/lib.rs` implements this check. It uses
> `isqrt()` for perfect square detection and the identity `4n(n+1) + 1 = (2n+1)²`
> for pronic number detection.
Expand Down Expand Up @@ -155,7 +156,7 @@ whose target is the **next justifiable slot**. In other words, there must be **n
justifiable slots between source and target**: the two must be consecutive entries in
the justifiability schedule.

> **In ethlambda:** The `try_finalize()` function iterates over slots between
> **In ethlambda's Lean Chain:** The `try_finalize()` function iterates over slots between
> source and target and calls `slot_is_justifiable_after` on each. If any slot
> is justifiable, finalization fails (source and target aren't consecutive).
> The check uses `original_finalized_slot` (the finalized slot at the start of
Expand Down Expand Up @@ -304,7 +305,7 @@ When finalization advances, the following cleanup occurs:
- Gossip signatures and aggregation proofs for finalized blocks are cleaned up
- Future fork choice runs start from the finalized slot's successor

> **In ethlambda:** The `justified_slots` bitlist uses relative indexing (index 0 =
> **In ethlambda's Lean Chain:** The `justified_slots` bitlist uses relative indexing (index 0 =
> `finalized_slot + 1`). When finalization advances, `shift_window()` in
> `crates/blockchain/state_transition/src/justified_slots_ops.rs` drops the
> now-finalized prefix. The attestation target is also walked back to the nearest
Expand Down Expand Up @@ -342,7 +343,7 @@ behind the head. The attestation **target** is derived by walking back from the
toward the safe target (max 3 steps), then to the nearest justifiable slot. See
[Safe Target Selection](lmd_ghost.md#safe-target-selection) for details.

> **In ethlambda:** `get_attestation_target()` in `crates/blockchain/src/store.rs`
> **In ethlambda's Lean Chain:** `get_attestation_target()` in `crates/blockchain/src/store.rs`
> implements this walk-back. `JUSTIFICATION_LOOKBACK_SLOTS = 3` provides a liveness
> guarantee: even if the safe target is stuck, the target eventually advances once
> the head moves far enough ahead.
Expand Down
6 changes: 6 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ genservers: each owns its state, and the only way in is a message.
Everything else hangs off those two: an aggregation worker on a blocking thread, the libp2p
swarm loop on its own task, and the axum servers that expose the node to the outside world.

This page describes the Lean Chain node, `ethlambda node`. `ethlambda beacon` runs the
same two actors over its own `Store`, but its chain actor (`BlockChain::spawn_beacon`) has
no validator keys, no aggregator role and no duties for the sync gate to hold back: it
imports blocks and runs the Beacon Chain's fork choice. [The mainnet wire](./beacon_wire.md)
and [Beacon Chain state transition](./beacon_stf.md) cover that side.

> Note: for what a genserver is, read [this blogpost on the `spawned` crate](https://blog.lambdaclass.com/introducing-spawned-erlang-style-actors-for-rust/).

```text
Expand Down
12 changes: 6 additions & 6 deletions docs/benchmarking.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Benchmarking

`ethlambda benchmark` measures two things the node does in production, each
against a reproducible offline workload, with no devnet running:
`ethlambda benchmark` measures two things the node does in production, one per
chain, each against a reproducible offline workload, with no devnet running:

- **`synthetic`**: block building, the way the node performs it when it
proposes, on a synthetic in-memory chain built for the run.
- **`import`**: block import, replaying a corpus of real blocks through the
node's own import path. See [Import workload](#import-workload) below.
- **`synthetic`**: Lean Chain block building, the way `ethlambda node` performs
it when it proposes, on a synthetic in-memory chain built for the run.
- **`import`**: Beacon Chain block import, replaying a corpus of real blocks
through `ethlambda beacon`'s own import path. See [Import workload](#import-workload) below.

Both are otherwise only observable through the Prometheus histograms a live
node exports. Those are noisy, depend on whatever the network happened to be
Expand Down
4 changes: 3 additions & 1 deletion docs/fork_choice_visualization.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ A browser-based real-time visualization of the LMD GHOST fork choice tree, serve
| `GET /lean/v0/fork_choice/ui` | Interactive D3.js visualization page |
| `GET /lean/v0/fork_choice` | JSON snapshot of the fork choice tree |

Both endpoints are served on the API port (`--api-port`, default `5052`).
Both endpoints are served on the API port (`--api-port`, default `5052`), by `ethlambda node`
only: they show the Lean Chain's fork choice tree, and on `ethlambda beacon` every `/lean/v0`
path returns 404.

## Quick Start

Expand Down
2 changes: 1 addition & 1 deletion docs/infographics/3sf-mini-infographic.html
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,7 @@ <h2>Justification &amp; Finalization</h2>

<!-- ═══════ FOOTER ═══════ -->
<div class="footer">
<p>ethlambda &mdash; A minimalist Lean Ethereum consensus client</p>
<p>ethlambda &mdash; A minimalist Beacon Chain and Lean Chain client</p>
<p style="margin-top:0.25rem"><a href="https://github.com/lambdaclass/ethlambda">github.com/lambdaclass/ethlambda</a></p>
</div>

Expand Down
2 changes: 1 addition & 1 deletion docs/infographics/ethlambda_architecture.html
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@
</div>
<div>
<h1>ethlambda</h1>
<div class="subtitle">Minimalist Lean Ethereum Consensus Client in Rust</div>
<div class="subtitle">Minimalist Beacon Chain and Lean Chain Client in Rust</div>
</div>
<div class="badge">
<span class="lang-badge lb-rust">Rust</span>
Expand Down
16 changes: 10 additions & 6 deletions docs/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,31 @@

# Introduction

**ethlambda** is a minimalist, fast and modular implementation of the Lean Ethereum
consensus client, written in Rust.
**ethlambda** is a minimalist, fast and modular implementation of a Beacon Chain and
Lean Chain client, written in Rust.

This book collects the design notes and operator-facing references for ethlambda.
It is split into four parts:
It is split into five parts:

- **Design** describes the shape of a running node: the
[architecture](./architecture.md) of its actors, workers and shared storage,
and how they are wired together at startup.
- **Consensus** explains how the chain advances: the
- **Consensus** explains how the Lean Chain advances: the
[slot and interval structure](./slots_and_intervals.md) that schedules every
validator duty, the [3SF-mini](./3sf_mini.md) justification and finalization
rules, and the [LMD-GHOST](./lmd_ghost.md) fork choice algorithm. These
documents are implementation-agnostic; ethlambda-specific behaviour is called
out in blockquotes.
- **Beacon Chain** covers the Ethereum Beacon Chain side: its
[state transition](./beacon_stf.md), the [mainnet wire](./beacon_wire.md),
and the [execution layer pairing](./beacon_engine.md).
- **Operations** documents observable surfaces of a running node:
[Prometheus metrics](./metrics.md), [checkpoint sync](./checkpoint_sync.md),
and the [fork choice visualization](./fork_choice_visualization.md) served
by the API.
- **Development** collects notes for contributors, starting with the
[spec deviations](./spec_deviations.md) where ethlambda departs from leanSpec.
[spec deviations](./spec_deviations.md) where ethlambda departs from leanSpec (Lean
Chain) or consensus-specs (Beacon Chain).

For build and contribution instructions, see the
[`README`](https://github.com/lambdaclass/ethlambda/blob/main/README.md) and
Expand All @@ -48,7 +52,7 @@ into the rendered output:

## Related projects

ethlambda is one of several Lean Ethereum consensus clients under active development.
On the Lean Chain, ethlambda is one of several clients under active development.
For comparison and cross-client testing:

- [zeam](https://github.com/blockblaz/zeam) (Zig)
Expand Down
34 changes: 19 additions & 15 deletions docs/lmd_ghost.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ fork choice algorithm works. LMD-GHOST is the fork choice rule used by Ethereum'
and its derivatives. Each validator's **latest attestation** is their single active vote, and the
algorithm follows the heaviest branch at every fork.

This document is implementation-agnostic, with ethlambda-specific details called out in
blockquotes marked **"In ethlambda"**.
This document is implementation-agnostic, with details of ethlambda's Lean Chain
(`ethlambda node`) called out in blockquotes marked **"In ethlambda's Lean Chain"**.
ethlambda's Beacon Chain follower (`ethlambda beacon`) runs the consensus-specs fork
choice instead; see [its section of the Beacon Chain state transition](./beacon_stf.md#fork-choice).

> Much of the conceptual framing in this document is inspired by Ben Edgington's
> [Eth2 Book](https://eth2book.info/), particularly the
Expand Down Expand Up @@ -176,7 +178,7 @@ the chain.
| Attestations | Latest message per validator: validator_index → attestation |
| Min score | Minimum weight for a branch to be considered (0 = follow any branch; higher = conservative) |

> **In ethlambda:** The function is `compute_lmd_ghost_head()` in
> **In ethlambda's Lean Chain:** The function is `compute_lmd_ghost_head()` in
> `crates/blockchain/fork_choice/src/lib.rs`. The block tree comes from
> the `LiveChain` storage index, and `min_score` is 0 for head selection
> or ⌈2V/3⌉ for safe target computation.
Expand Down Expand Up @@ -207,7 +209,7 @@ effective balance is added instead.
└ start_root (not weighted, used as the descent origin)
```

> **In ethlambda:** All validators have equal weight (+1 per vote). The Ethereum
> **In ethlambda's Lean Chain:** All validators have equal weight (+1 per vote). The Ethereum
> Beacon Chain instead weights votes by effective balance (up to 2048 ETH).

Then, **greedily descend.** Starting from the start root, at each node pick the child
Expand Down Expand Up @@ -399,7 +401,7 @@ finality gadget (e.g., Casper FFG in the Ethereum Beacon Chain, or [3SF-mini](3s
└────────────────────────────────────────────────────┘
```

> **In ethlambda:** The finality gadget is [3SF-mini](3sf_mini.md), which operates at
> **In ethlambda's Lean Chain:** The finality gadget is [3SF-mini](3sf_mini.md), which operates at
> the slot level rather than epoch boundaries.

The two layers interact: LMD-GHOST runs its greedy descent **starting from the latest
Expand All @@ -422,7 +424,7 @@ tree.** Without finality, fork choice would need to consider every block since g
and the tree would grow without bound. With finality, all blocks at or before the finalized
checkpoint can be discarded from the fork choice's working set.

> **In ethlambda:** The `LiveChain` index (the in-memory block tree used by fork choice)
> **In ethlambda's Lean Chain:** The `LiveChain` index (the in-memory block tree used by fork choice)
> is pruned every time finalization advances, keeping it bounded to only the non-finalized
> portion of the chain.

Expand Down Expand Up @@ -455,7 +457,7 @@ designated moments. This ensures all validators operate on a consistent view.
fixed points
```

> **In ethlambda:** The two stages are called "new" and "known" attestations, held in
> **In ethlambda's Lean Chain:** The two stages are called "new" and "known" attestations, held in
> the in-memory `new_payloads` and `known_payloads` buffers of the `Store` respectively.
> Promotion happens at tick intervals 0 (if proposing) and 4 (end of slot).

Expand Down Expand Up @@ -576,7 +578,7 @@ Reorgs are normal during transient network conditions but should be rare in stab
operation. They cannot cross a finalization boundary: once a block is finalized, it is
permanently part of the canonical chain.

> **In ethlambda:** Reorgs are detected by checking whether the old and new heads
> **In ethlambda's Lean Chain:** Reorgs are detected by checking whether the old and new heads
> share a common prefix, and tracked via Prometheus metrics
> (`lean_fork_choice_reorgs_total`).

Expand Down Expand Up @@ -684,10 +686,12 @@ at specific intervals:

### Differences from the Ethereum Beacon Chain

ethlambda is a lean consensus client with several simplifications compared to the
Ethereum Beacon Chain:
Lean consensus simplifies several parts of the Ethereum Beacon Chain's fork choice. This
section describes ethlambda's Lean Chain (`ethlambda node`); its Beacon Chain follower
(`ethlambda beacon`) runs the Beacon Chain's own fork choice, proposer boost and
equivocation discounting included.

| Aspect | ethlambda | Ethereum Beacon Chain |
| Aspect | Lean Chain | Ethereum Beacon Chain |
|--------|-----------|----------------------|
| **Vote weight** | Equal: 1 vote per validator | Proportional to effective balance (up to 32 ETH) |
| **Proposer boost** | None | Yes: newly proposed blocks get temporary bonus weight |
Expand All @@ -697,18 +701,18 @@ Ethereum Beacon Chain:
| **Slot duration** | 4 seconds (configurable) | 12 seconds |

**No proposer boost.** The Beacon Chain adds a "proposer boost", a temporary weight bonus
given to newly proposed blocks to prevent balancing attacks. ethlambda does not implement
this. Instead, proposer fairness is handled through the two-stage attestation pipeline
given to newly proposed blocks to prevent balancing attacks. The Lean Chain has no such
boost. Instead, proposer fairness is handled through the two-stage attestation pipeline
(the proposer's own attestation enters as "new", not "known").

**No balance weighting.** In the Beacon Chain, a validator with 32 ETH of effective balance
has more fork choice weight than one with 16 ETH. In ethlambda, every validator has exactly
has more fork choice weight than one with 16 ETH. On the Lean Chain, every validator has exactly
equal weight (1 vote = 1 unit of weight), simplifying the algorithm and analysis.

**No equivocation discounting.** The Beacon Chain's fork choice detects validators who
equivocate (attest to conflicting blocks in the same slot) and excludes their weight. This
addresses the "nothing at stake" problem where validators can costlessly vote for multiple
forks. ethlambda does not implement this in its fork choice.
forks. The Lean Chain's fork choice does not do this.

### Key Files

Expand Down
Loading
Loading