An Ethereum indexing node you run inside your own infra. Backfill from public datasets, follow the head over Ethereum P2P, and deterministically reduce blocks into only the state, outputs, and durable streams you choose to retain. Point viem or any JSON-RPC client at it, or stream changes over the SDK.
$ leani subscribe blocks --once# On first use, review and accept the checkpoint.# --once may print an early peer preview.# Print only blocks Ethereum has finalized:$ leani subscribe blocks --finality finalized --once
Build the current alpha from source, then follow checkpoint setup on first use.Install Leani →
1M blocks → 9.5 MBexternalized policy, real Mainnet run
0 API keyspublic Xatu datasets + Ethereum P2P
7 processorsbuilt in, or your own native Rust
MIT-licensedRust library + standalone node
# Why we built it
We run blobs.money, a live dashboard for Ethereum blob economics. It needs block headers, every type-3 transaction, and receipts. Nothing else.
Getting that meant paying for metered RPC: millions ofeth_getBlockByNumber and eth_getBlockReceiptscalls to backfill history that public datasets already serve, then a WebSocket to follow the head. The alternative — running our own full node — meant terabyte-class NVMe and days of sync, keeping the whole chain on disk to reduce a sliver of it to application-shaped data.
So we built the node we wanted. It can use fast, trusted Xatu datasets for aggregation or commitment-checked EraE material for an independent audit path. It follows the head over Ethereum P2P, anchors finality from consensus, records provenance, and discards raw input when policy allows.
Then we generalized it: any data you can derive from blocks, transactions, receipts, and logs — events, balances, pool prices — with the same discipline. The same normalized input and deterministic processor contract applies whichever capable source supplies the block.
Your app doesn't need the whole chain. It needs its own data.
# Two lanes in. One processor contract.
Historical backfill and live head-following normalize into the same block envelope. Each source declares its capabilities and trust model; raw input can disappear after commit or remain under an explicit retention policy.
HISTORICAL LANEBackfill the past.Xatu · EraE · retained raw
LIVE LANEFollow the head.Ethereum P2P · CL finality
ONE SHARED CONTRACTOne input. Your processors.
YOUR APPLICATIONKeep what matters.State + durable delivery
HISTORY
LIVE HEAD
leani_
ERC-20reduce()
Poolsreduce()
Eventsreduce()
Yoursreduce()
ERC-20map()
Poolsmap()
Eventsmap()
Yoursmap()
02
Validation
01
Block envelope
COMMITTED STATE
raw bytesoptional after commit
Shared inputIndependent processors
INSIDE THE PIPELINEHover a layer or select a stage to explore
Parallel map
Your processors shape each block.
Each small module is a processor with its own map and reduce. Deterministic map work can run concurrently, turning the requested block material into a compact, versioned delta.
Built-in or your own Rust. Each processor owns both steps.
Xatu is trusted; EraE commitments are checked. Live P2P provenance and CL finality stay explicit. Raw bytes are optional after commit.
The durable boundary
# Backfill meets live without a gap
History and head following run as independent lanes, then meet at an exact parent-hash boundary. Downstream delivery uses the same committed change protocol for both.
01
Resume from coverage
Committed intervals—not downloaded files—decide the first missing block after a restart.
02
Commit the branch
Apply, undo, and finality events are published only after processor state commits.
03
Commit, then ACK
Named consumers atomically save application data and their cursor before acknowledging.
04
Prune by policy
Required consumers fence pruning; lag and byte budgets create explicit backpressure.
Transport is at-least-once. Exactly-once application behavior comes from committing the destination mutation and cursor in one transaction, then acknowledging.
P2P history fallback can fill the entire eligible gap by default; settinghistory_fallback_blocks opts into a bounded suffix.Coverage details →
# Processors do the work
A processor is a deterministic map/reduce over blocks, transactions, receipts, and logs. Configure a built-in—or register trusted native Rust code in a custom binary. These are complete processor sections, not legacy shorthand.
One atomic block bundle—economics plus every blob transaction. Node commits are atomic; consumers receive at-least-once and commit their cursor before ACK.see it live →docs →
Event-derived watchlist balances with declared coverage. Exact for conventional Transfer semantics when indexing begins before the relevant initial mint; rebasing, reflection, and non-standard tokens need a different model.docs →
Declarative static-ABI decoding—no EVM or contract code, just logs. Dynamic values, tuples, arrays, and anonymous events are rejected by doctor. Illustrative response; hashes, cursors, and values vary by run.docs →
Latest exact reserves or sqrtPriceX96 per configured pool—never floating point, no EVM execution. Use uniswap-observations when you need immutable history.docs →
Ordered aggregate with constant-sized state for top-level A-to-B transactions. Internal calls and traces are intentionally outside this processor. Illustrative response; hashes, cursors, and values vary by run.docs →
Native Rust processors register state transforms and typed read extensions through the public factory API — same durability, streams, coverage, and query controls as built-ins.build your own →docs →
# Storage is a policy, not a promise
State, query output, delivery, artifacts, checkpoints, undo, and raw history have independent lifecycle controls and hard budgets. Keep a current value, a rolling window, a reusable history, or only an acknowledged external copy.
Profile
Retained by leani
Bound
Best fit
Measured example
externalized
State, coverage, and delivery only until the required consumer ACKs
Byte/age budgets with pause-on-limit backpressure
PostgreSQL, ClickHouse, object storage, or another application-owned sink
Every materialized processor entity and required indexes
Grows with output cardinality and indexed history
Reusable local historical query surfaces
1M dev-native blobs blocks: 1.58 GiB compacted DB
Measured figures are workload-specific evidence, not host-size or cost guarantees. The real-source runs used gzip HTTP delivery, immediate acknowledgement, four source workers, and did not include an application database.
The 1.58 GiB full-output figure retained 2.55 million entities and 550,000 index rows. Externalized, latest, or windowed policy is the intended choice when that reusable query surface is unnecessary.
Trusted Xatu input and commitment-checked EraE input have different trust and performance profiles; retention policy does not change source trust.
Existing Ethereum clients can use the block, transaction, receipt, log, chain-metadata, and subscription methods leani advertises. Availability still depends on configured sources, retained material, and hash locators.
Number and range lookups can use capable historical sources. Hash-only history is recent-only unless a locator or retained index is enabled. Raw RPC history is post-Merge exact; pre-Merge ommer-aware responses are deferred.
refused, explicitly
eth_call
eth_getBalance · eth_getCode · eth_getStorageAt
eth_estimateGas
debug/trace methods
No EVM, no state trie—so these fail explicitly instead of returning something almost right. Keep an execution provider for stateful methods and as an independent fallback while evaluating the public preview.
# The operational contract is part of the product
coverage-owned backfill
Coverage lives in SQLite. Restart at the first uncovered block—not at the last file or HTTP response.
reorg protocol
Apply, undo, and finalized changes make branch replacement explicit instead of silently rewriting downstream state.
durable consumers
Named consumers, leases, acknowledgements, lag telemetry, pruning fences, and commit-then-ACK helpers.
query then follow
Hold a stable multi-page snapshot and receive the exact boundary cursor needed to continue on the stream.
source provenance
Every change identifies its live, recovery, backfill, or recompute origin and publication revision.
capability routing
Trusted Xatu, commitment-checked EraE, retained raw segments, and P2P are selected only when they satisfy the request.
recovery built in
Checksummed portable savepoints, recovery checkpoints, retained artifacts, export, and replay are explicit APIs.
ops built in
Prometheus metrics, health and readiness, hard resource budgets, and a dependency-free network dashboard.
Ethereum Mainnet · no API key
# Follow Ethereum blocks
Install the alpha from source, then read block summaries directly from Ethereum's network with one command. On first use, Leani asks you to approve a checkpoint, a trusted starting point for checking the chain. Prepare a reusable node when you want queries and SDK subscriptions.
1 · inspect a first block
shell
leani subscribe blocks --once
2 · prepare a reusable node
shell
mkdir leani-blocks && cd leani-blocksleani init blocksleani serve# In another terminal in this directory:# leani subscribe blocks --format json
Your first result may be a preview while Leani checks the block's place in Ethereum's chain. Rows marked included are on the followed chain and can still be reorged. Add --finality finalized to print only blocks Ethereum consensus has finalized. See the full quickstart, thenindex a bounded historical range.