Skip to content

feat(DA): Minimal PeerDAS Data Availability Client - DA client side#1485

Open
KimiWu123 wants to merge 10 commits into
ReamLabs:masterfrom
KimiWu123:feat/standalone-da
Open

feat(DA): Minimal PeerDAS Data Availability Client - DA client side#1485
KimiWu123 wants to merge 10 commits into
ReamLabs:masterfrom
KimiWu123:feat/standalone-da

Conversation

@KimiWu123

@KimiWu123 KimiWu123 commented Jul 1, 2026

Copy link
Copy Markdown

What was wrong?

To address #1408, have a standalone DA client.

This is an MVP of the minimal DA client, and I want to hear your feedback regarding the architecture before jumping into the implementation details.
It's easier to review the PR commit by commit.

How was it fixed?

Summary

The core of a minimum DA node. It runs as its own process beside the beacon node and does one thing: durably store a block's data columns and verify them, over a small local HTTP/RPC surface. The beacon keeps consensus logic; the DA node keeps the data.

Command: cargo run -p ream -- -v 4 --ephemeral da_node

Design philosophy

  • Beacon owns consensus (gossip, fork choice, custody decisions); the DA node owns storage and self-contained verification. They talk over HTTP/RPC — the DA node has no P2P and no chain view.
  • The core defines the domain and depends on neither beacon nor any commitment scheme; KZG plugs in through an adapter behind a trait, so the core stays reusable by a future scheme.
  • Single-writer, load-shedding pipeline; loopback-only. One verification consumer is the sole writer, so "only verified data is stored" is structural and writes stay serialized; ingress is non-blocking and sheds load, so a slow verifier never blocks callers.

Crate layout

graph TB
    bin["bin/ream<br/>"]
    rpc["ream-rpc-da<br/>HTTP / RPC ingress"]
    node["ream-da-node<br/>(pipeline) ingest → verify → store"]
    kzg["da_adapters<br>(ream-da-verifier-kzg)<br/>KZG verifier"]
    core["ream-da<br/>core: traits + domain types"]
    ext["ream-consensus-beacon<br/>+ KZG libraries"]

    bin --> rpc
    bin --> node
    bin --> kzg
    rpc --> core
    rpc --> node
    node --> core
    kzg --> core
    kzg --> ext

    style core fill:#e8f5e9,stroke:#43a047
    style bin fill:#e3f2fd,stroke:#1e88e5
    style ext fill:#f5f5f5,stroke:#bbb
Loading

Arrows read "depends on". ream-da depends on nothing beacon- or crypto-specific; beacon types and KZG are reachable only through the adapter. The pipeline depends solely on the core's traits, so the concrete verifier is injected at bin/ream.

What's included

  • Store — columns keyed by (block root, column), with availability reporting and finality-driven pruning.
  • Pipeline — a bounded ingest queue feeding a single verify-and-store consumer, with backpressure and load-shedding.
  • KZG verification — structure, the inclusion proof against the block header, and the cell proofs; trusted setup warmed up at startup.
  • RPC surface — accept candidates and retention hints; serve availability and stored columns; a liveness probe.

Next steps

  • File store → embedded database — swap file-per-column for a transactional key-value DB (as Lighthouse stores DA data), for atomicity and cheaper range/prune.
  • SSZ wire format — replace the dev-only hex-in-JSON envelope with SSZ, dropping the ~2× hex expansion and matching how columns are encoded on the wire.
  • (TBD)Verification workers / batching — to replace current pipeline with a verification pool (and batch process) while keeping writes single-threaded. This is for performance consideration; need more investigation and data to decide.
  • Beacon integration - need to discuss with @perfogic

To-Do

KimiWu123 added 9 commits July 1, 2026 16:53
* init: da_node cli

* memory store framework

* add verification service

* chore: eliminate warnings
* complete store read/write

* optimize in-memory index

* refine the file format

* chore: define DA_VERIFICATION_QUEUE_CAPACITY
* impl. the verification of candidate columns

* spawn store put (a file write)
* impl. ingest_handle for the verification queue

* test ingest handle
* impl availability struct

* add data prune fn under store

* test: add tests for data prune

* process retention

* add a retention test
* rpc for ingest

* start da rpc in run_da_node

* support availability

* support column data query

* support retention hint

* add rpc tests

* restrict local ip only
* verifier adapter

* add tests and minor refinement

* wire up new kzg verifier

* warm up trusted setup

* set beacon network for max_blobs_per_block
* comment to explain the division of labor

* test: a mock verifier fore da_node service

* test: add a real sidecar case

* refactor: minor KzgVeririder refactor

* health check api

* support 503 error in da rpc
@KimiWu123 KimiWu123 force-pushed the feat/standalone-da branch from 87877d6 to 20eb069 Compare July 1, 2026 09:01
@perfogic

perfogic commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Thanks for putting this together and for mentioning me.
I just looked through the PR, and I think this is useful as an early DA-node scaffold for Phase 3 in this tracking issue:
#1478
I believe some of the types, storage/verifier abstractions, and RPC surface here can be reused later when we integrate this with the beacon-side DataAvailabilityChecker module, which will first decouple data availability validation from block handling.
I’ll take a closer look later this week after I finish the DataAvailabilityChecker issue, and then we can see which parts of this PR can help with the Phase 3 integration.

@KimiWu123

Copy link
Copy Markdown
Author

Hi @perfogic
Quick thought on the DataAvailabilityChecker — might be worth deciding early where the Beacon/DA line sits.

If you just stick a thin interface in front of the availability + verification bits, anything that's really DA node's job can sit behind it — mock it for now, and later we swap the mock for the actual RPC call to the DA node. That way you don't have to touch any DA logic to keep going: it runs against the mock today, and in phase 3 we just plug in the real thing instead of reworking the checker.

Basically lets us build both sides in parallel, and makes phase 3 a wiring job instead of a rewrite.

@perfogic

perfogic commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Currently, the DataAvailabilityChecker is meant to handle the existing is_data_available issue described in the tracking issue, so it is definitely not something I want to mock out.

The plan is closer to the lighthouse-style flow: separate the DA availability logic internally inside the beacon node first, so on_block can keep blocks pending when data columns are not available yet and retry them when DataColumnSidecars arrive.

Later, if we decide to integrate a standalone da-node, the backend behind the checker can be replaced with a DA-node RPC/provider interface. But the Phase 1 checker itself is still needed to fix the beacon-side pending availability flow.
You can keep working on your next steps for the DA-node side, and we can align the integration boundary later 👍. Thanks for your suggestion, btw

@KimiWu123

Copy link
Copy Markdown
Author

is_data_available seems like very DA-side work, and I’m worried we might be duplicating work. But, no worries, I'll keep working on the next steps.

@perfogic

perfogic commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Yeah, still the same as what we discussed in the common channel. Also, I just updated the Phase 3 description in the tracking issue (#1478) to add the boundary, that should answer the duplication concern.

* check availability before verify

* check slot in candidate and in block header if consistent

* add a helper function - holds in DaAvailability

* fix da path and move trusted setup to the end of run_da_node

* fix typo and format
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants