UMNode — Unus Mundus Node¶
Status — pre-alpha. UMNode joins an Ethereum network, follows the chain head, and persists a peer inventory; two workers fill a compact on-disk block store (realtime from the head, backfill through history), a block-hash / transaction-hash index is built alongside, and a JSON-RPC server serves block and transaction reads plus debug/ops methods. An execution subsystem (on by default) builds state from genesis and serves
eth_call, the state getters, thecallTracertrace methods, and — deriving receipts instead of downloading them —eth_getTransactionReceipt,eth_getBlockReceiptsandeth_getLogs. This documentation is kept up to date as the project progresses.
UMNode is an ultra-lightweight imitation of a blockchain client, built for one job: serving RPC. It speaks a chain's peer-to-peer wire protocol directly to pull blocks, headers and receipts, stores them locally in a compact segmented store, and serves them over JSON-RPC — without running consensus. State is built by a trie-free embedded EVM that re-executes the stored chain — nothing is trusted that the node didn't derive itself.
It is currently EVM-only: Ethereum (eth/68, eth/69 and eth/70) and
BNB Smart Chain (bsc's eth/68 and eth/70 flavours, with the Parlia
execution rules). More network families will follow as the core stabilises.
Why UMNode exists¶
A full node carries the entire weight of consensus to answer an RPC query.
UMNode takes the opposite bet: most RPC traffic is reads of historical
blocks, transactions and receipts — data that can be fetched directly over the
wire protocol and stored compactly. For the state-dependent rest (eth_call,
balances, traces), UMNode re-executes the chain through an embedded EVM into a
compact flat state store — no Merkle trie, no consensus — so it
aims to stay small, cheap to run, and fast to stand up.
The trade-off: state-dependent calls answer only once the backfill has reached
genesis and execution has caught up — until then they return an explicit
state not ready error (never an approximation). Operators who only need
block/transaction serving can skip state entirely with --execute=false.
What it does today¶
- Joins the network — discovery (v4/v5), dials out only, never accepts inbound connections.
- Handshakes at the eth layer — validates network id and EIP-2124 fork id so it only keeps genuinely compatible peers.
- Tracks the chain head — polls a peer on an interval and follows the head.
- Persists a peer inventory — remembers known-good peers across restarts so it can re-dial them.
- Opens a segmented block store — a compact, immutable, compressed on-disk format, created and validated at startup.
- Fills it from the network — a realtime worker follows the head; a backfill worker fills the rest of history (forward from genesis by default, so an indexer can consume blocks in order).
- Fetches from existing nodes too —
--rpc-peerspoints it at the JSON-RPC of synced (or partially synced) nodes, used ahead of the p2p peers and validated like them; a node can run from them alone. - Indexes by hash — an optional block-hash / transaction-hash index backs by-hash lookups, built as blocks confirm.
- Keeps as much history as you ask — an archive by default;
--block-history Nprunes the block store to the most recentNblocks, dropping whole sealed segments and capping state and receipts history with it;--extra-archive-blocks A:B,…keeps block ranges outside that window, with their state history and receipts when the archive has them. - Backs its segments up, and starts from them —
--backupcopies every sealed segment (blocks, state history, receipts) and the state snapshots to S3 / R2 / a directory as it seals, and pruning waits for it: no segment goes before it is backed up. The segment archive is also where a node starts: backfill attaches verified block segments from it (the public archive by default) instead of fetching block by block, and--syncmode snap(the default) restores the newest state snapshot and executes on from its head, downloading only the blocks the node keeps. - Serves JSON-RPC — block and transaction reads (
eth_getBlockByNumber,eth_getBlockByHash,eth_getTransactionByHash), receipts and logs (eth_getTransactionReceipt,eth_getBlockReceipts,eth_getLogs), the state methods, plus debug / ops methods (debug_status,debug_getBlockArtifact,debug_indexStatus, …).
Where to start¶
- Quickstart — run UMNode in minutes with Go or Docker.
- Configuration — the per-network YAML file and how settings are resolved.
- CLI flags — every flag, its default and meaning.
- Architecture — the theory: how UMNode fills and serves its store.
- Block store — the segmented, immutable, compressed store in depth.
- JSON-RPC API — every method, its parameters and result shape.
- Hash indexing — by-hash lookups, and the index's size and upkeep.
- Networking & peers — discovery, handshake and the peer inventory.
- Segment archive — backing sealed segments up to S3, and attaching them from an archive.
License & source¶
Source lives at github.com/ofzhur/umnode.