Skip to content

o1-labs/mina-light-node

Repository files navigation

mina-light-node

A trustless Mina light node — it joins the p2p network and verifies the chain from its recursive SNARK proof. Unlike a typical light client (an RPC consumer), this is a real light node: it participates in the network.

   Mina p2p network ──▶ mina-relay ──(candidate tip)──▶ mina-verify ──▶ verified tip
   (untrusted)          (this repo)                     (separate repo)   + Merkle-proof reads
  • Safety ("never accept a false state") comes from mina-verify — one recursive proof validates the whole chain (stronger than Bitcoin SPV: no header download).
  • Liveness / censorship-resistance ("you see the real, current chain") comes from mina-relay — decentralized p2p access across many peers, not a trusted RPC. It bootstraps from the seeds, then discovers the wider network via Kademlia (Mina's /coda/kad/1.0.0), reaching ~20+ peers instead of ~2 (eclipse resistance).

Crates

Crate What
mina-relay The p2p network layer: connect to gossip, receive blocks, tap the mempool, broadcast txs, track peers. Proof-systems-agnostic (libp2p + message types only; no verification). Reusable on its own.
mina-light-node The product binary: wires mina-relay + mina-verify into one runnable trustless light node.

The verifier lives in its own repo, MinaProtocol/mina-verify, because it's consumed independently (MCP server via wasm, mobile app, the trustless indexer's trust gate). This repo composes it; it does not own it.

Status

Scaffold. mina-relay carries the working gossip/RPC/broadcast primitives (moved from mina-verify-capture). The mina-light-node binary currently follows the gossip network and surfaces candidate tips; the verifier trust-gate, account reads, mempool tap, broadcast API, and liveness cross-check are TODOs (see src/main.rs).

Binaries

Binary What
mina-light-node Headless node: verify-before-ingest, surfaces the verified tip on stdout / LIGHT_NODE_TIP_FILE.
mina-light-node-server The node + a trustless HTTP API (reads / submit / mempool) — what a Rosetta adapter or a client-side integrity monitor consumes.

Build / run

cargo build
# headless node
MINA_NETWORK=devnet cargo run -p mina-light-node
# node + trustless HTTP API on :8645
MINA_NETWORK=devnet cargo run -p mina-light-node --bin mina-light-node-server

HTTP API (mina-light-node-server, env LIGHT_NODE_HTTP_ADDR, default 127.0.0.1:8645)

curl :8645/health                  # liveness + verify counters + sync freshness
curl :8645/status                  # chain health: height, epoch, global_slot, min_window_density, reorgs, forks
curl :8645/metrics                 # Prometheus exposition (scrape for the integrity monitor)
curl :8645/tip                     # {height, state_hash, staking_epoch_ledger_hash}
curl ':8645/account?index=0'       # trustless balance/nonce by leaf index (instant)
curl ':8645/account?pubkey=B62…'   # by public key (resolved from the swept index map)
curl :8645/mempool                 # best-effort pending tx ids
curl -XPOST :8645/submit -d '{"tx_hex":"…"}'   # broadcast a signed user command

Every /account answer is Merkle-proved against the verified tip's staking-epoch-ledger root (what peers serve over sync-ledger), so a lying peer is rejected.

Client-side integrity monitor

/status + /metrics make the node a trustless system-integrity monitor: it independently proves the real chain and exposes the signals to alert on. The tip is fork-choice-tracked (ChainMonitor), so reorgs/forks are counted, not just height. Example Prometheus alerts: mina_light_node_seconds_since_last_verified high (chain stalled / node eclipsed), mina_light_node_reorgs_total rising (deep reorgs), mina_light_node_min_window_density low (chain-quality / censorship), mina_light_node_rejected_total > 0 (a peer served bad proofs). Cross-check your Rosetta/RPC tip against /tip (and balances against /account) to catch a stale or lying provider. If the verifier can't be built the process exits non-zero (it never runs "healthy" while verifying nothing).

Reactive verification. A peer that relays invalid-proof blocks is disconnected and blocklisted after a few strikes (mina_light_node_banned_total); the node never adopts an unverified tip regardless. With Kademlia discovery keeping mina_light_node_peers high (~20+), banning a bad peer is safe — there are plenty of honest ones to fall back on. Alert on mina_light_node_peers low (eclipse risk) and mina_light_node_banned_total rising.

Baked pubkey → index map

By-public-key needs a pubkey → leaf-index map (the sync-ledger RPC indexes by leaf, not key). It's an untrusted hint — every read still re-proves Merkle inclusion — so it ships in the image. Generate it with mapgen and point the server at it via LIGHT_NODE_INDEX_MAP:

MINA_NETWORK=devnet cargo run -p mina-light-node --bin mina-light-node-mapgen devnet.bin
LIGHT_NODE_INDEX_MAP=devnet.bin MINA_NETWORK=devnet cargo run -p mina-light-node --bin mina-light-node-server

The release pipeline runs mapgen per network, bakes the map into the image and attaches it to the GitHub Release. Without a baked map the server falls back to sweeping the epoch ledger at cold start (minutes on a large ledger). The map is generated by an RPC sweep, not the S3 RocksDB tarball — see docs/ (the tarball stores the leaf index in Mina's internal RocksDB Location encoding, which the sweep sidesteps).

Roadmap (see the trustless-light-stack arch doc)

  • Wire the trust gate: verify each gossiped block's proof before ingest (verify_tip + ChainMonitor); validated on live devnet.
  • Account reads: GET /account?pubkey=&index= Merkle-proves balance/nonce against the verified staking-epoch-ledger root; validated on devnet (account 0 + by-pubkey).
  • Mempool tap: tx-pool gossip → bounded, TTL'd view (mempool::MempoolView), keyed by the canonical Mina tx hash; GET /mempool.
  • Broadcast: POST /submit publishes a signed tx to the tx-pool gossip topic.
  • Liveness cross-check (expose side): GET /tip is the proof-verified tip a consumer compares against a less-trusted source to flag divergence.
  • HTTP/RPC surface + deploy glue (mina-light-node-server, see deploy/).
  • Baked pubkey→index map built by mapgen at release time, baked into the image + attached to the release (removes the cold-start sweep); env LIGHT_NODE_INDEX_MAP.
  • Generate the map from the S3 RocksDB epoch-ledger tarball (vs the current RPC sweep).
  • Optional GraphQL facade for existing Mina clients.

About

A trustless Mina light node - A trustless, SPV-class light node for Mina, powered by recursive zk-SNARKs.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors