> ## Documentation Index
> Fetch the complete documentation index at: https://docs.leafage.chaintable.com/llms.txt
> Use this file to discover all available pages before exploring further.

# What is Leafage

> Leafage is an architecture for EVM state queries and block data distribution: one write node executes blocks, and any number of query nodes consume the execution results and serve RPC.

Leafage is an **architecture for EVM state queries and block data distribution**. It separates what a traditional full node couples together: sync and execution, state storage, RPC serving, and data export. **One write node** joins the P2P network and executes blocks; the **state diffs** and **block data** produced by execution are distributed through Kafka + S3 to **any number of query nodes** and to external consumers. Clients never talk to a node directly: a gateway routes each request to a suitable query node according to its **block context**.

## Execute once, consume everywhere

At its core, Leafage separates "execution" from "consuming execution results":

* **Write side**: the chain's original execution client plus the pipeline library. It is the only role that executes blocks. While executing, it exports state diffs, block headers, and transactions / traces / events to S3, and publishes block change notifications to Kafka.
* **Read side**: leafage-evm query nodes. They do not sync, do not execute blocks, and do not maintain a Merkle Patricia Trie. They apply state diffs to local state in notification order and run read-only calls with revm.

All query nodes consume the same single-partition Kafka notification stream and apply the same diffs in the same order, so there is no P2P non-determinism. Adding query capacity means starting one more query node, not syncing the whole chain again.

|                     | Traditional full node                    | Leafage                                            |
| ------------------- | ---------------------------------------- | -------------------------------------------------- |
| Block execution     | Every node executes every block          | Only the write node executes                       |
| Source of state     | Its own execution                        | State diffs exported by the write node             |
| State storage       | MPT + transactions + receipts            | Account state only (balance, nonce, code, storage) |
| Replica consistency | Depends on each node's sync progress     | Observed and confirmed by consistency-checker      |
| Data export         | `debug_traceBlock` competes with queries | Exported during execution and written to S3        |

## The five components and their roles

| Component                                                 | Side         | Role                                                                                                                         |
| --------------------------------------------------------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------- |
| [Write node](/en/components/go-ethereum-x)                | Write        | Execution client + pipeline integration; the only block executor                                                             |
| [pipeline](/en/components/pipeline)                       | Write        | Library embedded in the write node: serializes execution data, writes S3, and on the Leader publishes notifications to Kafka |
| [leafage-evm](/en/components/leafage-evm)                 | Read         | Query node: applies state diffs and serves `eth_call` and other state queries                                                |
| [consistency-checker](/en/components/consistency-checker) | Verification | Waits for replicas to converge, marks fork blocks, maintains node state, publishes confirmed block notifications             |
| [nodex-proxy](/en/components/nodex-proxy)                 | Gateway      | Discovers nodes through etcd and routes requests to State / Archive / Native nodes by block context                          |

Components never call each other directly. They cooperate through three pieces of middleware: Kafka carries notifications, S3 carries payloads, and etcd carries runtime state.

## Data flowing through the pipeline

For every block it executes, the write node produces four objects and one notification:

| Data                    | Channel              | Content                                                                         | Consumers                                 |
| ----------------------- | -------------------- | ------------------------------------------------------------------------------- | ----------------------------------------- |
| Header                  | S3 internal bucket   | Block header                                                                    | leafage-evm                               |
| StateDiff               | S3 internal bucket   | The block's state changes relative to its parent                                | leafage-evm                               |
| BlockFile               | S3 external bucket   | Transactions, call traces, event logs                                           | External consumers                        |
| BlockValidation         | S3 external bucket   | Validation summary; doubles as a by-height index and carries the `is_fork` flag | consistency-checker, leafage-evm catch-up |
| BlockChangeNotification | Kafka internal topic | New block / reorg notification carrying hashes and heights only                 | leafage-evm, consistency-checker          |

The internal bucket and internal topic serve Leafage's own query nodes. The external bucket and external topic serve external consumers such as indexers and analytics platforms. The external topic is published by consistency-checker and contains only **confirmed** blocks.

## Three kinds of query nodes

leafage-evm keeps as much history as its startup flags say, which splits it into State and Archive nodes. A Native node is a full node of the original chain, used as a fallback.

| Type         | State it keeps                                                       | Queries it suits                                                       |
| ------------ | -------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| State node   | Latest state; on disk only the latest value of each account and slot | `latest` and near-head queries, which is the vast majority of requests |
| Archive node | Full historical state at every block height                          | `eth_call` and state reads at any historical height                    |
| Native node  | Everything the original chain client can do                          | Calls that touch precompiles leafage-evm cannot execute locally        |

nodex-proxy routes between the three node pools according to the block context carried by the request, and automatically retries on an Archive or Native node when a State node returns `-39006` or `-39008`.

## Three identities of a block

The same block passes through three stages along the pipeline. Keeping them apart is what makes the component interfaces readable:

| Identity   | Decided by                                     | Meaning                                                                                                         |
| ---------- | ---------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| Published  | Write node (Leader)                            | Has entered the internal Kafka topic; query nodes start applying it                                             |
| Confirmed  | consistency-checker                            | A `ready_ratio` share of query nodes has caught up to this height; external consumers can safely query it       |
| Fork block | consistency-checker, by writing back `is_fork` | Was published but is not on the canonical chain; the S3 object stays, and notifications mark it `is_fork: true` |

## Isolation unit: chain and version

One chain is one independent deployment unit. Kafka topics, S3 keys, and etcd keys all start with `chainID`, so multiple chains can share one Kafka, S3, and etcd.

With version mode enabled, the key space gains an extra `version` segment. Two data versions of the same chain can then run side by side on the same infrastructure, and etcd's `{chainID}/version` switches between them without clients noticing.

## Glossary

| Term                              | Meaning                                                                            | Details                                                            |
| --------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| Write node                        | Execution client + pipeline; the only role that executes blocks                    | [Write nodes and query nodes](/en/concepts/nodes)                  |
| Query node / leafage-evm          | Lightweight node that consumes state diffs and serves RPC                          | [Write nodes and query nodes](/en/concepts/nodes)                  |
| State / Archive / Native node     | The three query node types, distinguished by how much state they keep              | [Write nodes and query nodes](/en/concepts/nodes)                  |
| Leader                            | The one write node instance that publishes notifications to Kafka                  | [Write nodes and query nodes](/en/concepts/nodes)                  |
| State diff (StateDiff)            | The set of account state changes produced by executing one block                   | [State and state diffs](/en/concepts/state)                        |
| Diff layer (DiffLayer)            | The in-memory form of one block's state diff inside a query node                   | [State and state diffs](/en/concepts/state)                        |
| Finalization                      | Flushing a diff layer to the database once it leaves the in-memory window          | [State and state diffs](/en/concepts/state)                        |
| Block change notification         | The new block / reorg message published by the write node                          | [Block notifications and the canonical chain](/en/concepts/blocks) |
| Canonical chain / fork block      | The chain containing the current canonical head / a block dropped by a reorg       | [Block notifications and the canonical chain](/en/concepts/blocks) |
| Confirmed block                   | A block published by consistency-checker after replicas converged                  | [Block notifications and the canonical chain](/en/concepts/blocks) |
| Block context (`blockCtx`)        | The "which block's state" a request asks for, with `Equals` / `Contains` semantics | [Block context and routing](/en/concepts/block-context)            |
| Internal bucket / external bucket | The two S3 buckets, for query nodes and external consumers respectively            | [Interface contracts](/en/architecture/interfaces#s3)              |
| Internal topic / external topic   | The two Kafka topics, carrying published and confirmed blocks respectively         | [Interface contracts](/en/architecture/interfaces#kafka)           |
| Version namespace                 | The optional `version` segment in Kafka, S3, and etcd keys                         | [Interface contracts](/en/architecture/interfaces)                 |

## Summary

* Leafage is an **architecture for EVM state queries and block data distribution**: only the write node executes blocks; every other role consumes the results.
* The write side exports four objects, **StateDiff, Header, BlockFile, BlockValidation**, plus one **block change notification**; Kafka carries notifications only, payloads go through S3.
* Query nodes come in three kinds, **State / Archive / Native**; nodex-proxy routes by **block context** and falls back automatically on error codes.
* A block has three identities, **published, confirmed, fork block**; external consumers should rely only on confirmed notifications.

Continue reading:

* [Write nodes and query nodes](/en/concepts/nodes): the boundary between the two sides, the three node types, and the node lifecycle.
* [State and state diffs](/en/concepts/state): why query nodes need no MPT, and how diff layers are organized and finalized.
* [Block notifications and the canonical chain](/en/concepts/blocks): notification format, reorgs, fork marking, and confirmation semantics.
* [Block context and routing](/en/concepts/block-context): what `Equals` / `Contains` mean and how the proxy routes.
* [Architecture overview](/en/architecture/overview): component split, runtime topology, and design trade-offs.
