Quickstart¶
Get UMNode joining Ethereum mainnet in a couple of minutes. Pick Go if you have a toolchain, or Docker if you'd rather not.
Requirements¶
- Go 1.25+ (the module requires go 1.25.0) — only for source builds.
- Docker 24+ — alternative to a local Go toolchain.
- Outbound network access on TCP/UDP 30303 (the default Ethereum p2p port) for dialing peers and UDP discovery. No inbound port is needed — UMNode only ever dials out and never accepts incoming connections.
Run with Go¶
git clone [email protected]:ofzhur/umnode.git
cd umnode
make build # produces bin/umnode
./bin/umnode # joins Ethereum mainnet with the bundled config
Without the Makefile:
By default UMNode reads cfg/ethereum.yaml from the current working directory
and joins mainnet. It dials out only and binds UDP discovery on
0.0.0.0:30303. The bundled mainnet config keeps up to 20 peers with discovery
v4 + v5 enabled.
Override any setting with a flag:
See CLI flags for the full list and Configuration for the per-network YAML.
Already running a synced node?
Point UMNode at its JSON-RPC and it fetches block data from there first, falling back to p2p peers for whatever that node lacks — a partially synced node contributes what it has:
See RPC peers.
Run with Docker¶
The image is a distroless static build (~15 MB) with cfg/ethereum.yaml baked
in for an out-of-the-box mainnet run.
make docker # builds ofzhur/umnode:<git-describe> and :latest
make docker-run # runs it with cfg/ and data/ mounted
make docker-run is equivalent to:
No published ports are needed: UMNode dials out and runs discovery outbound, but accepts nothing inbound.
- Mount
cfg/only if you want to override the bundled config. - The
data/mount preserves the discovery node database (and, once it fills, the block store) between runs, so UMNode doesn't have to rediscover peers on every start.
To pass flags, append them after the image name:
Testnets¶
The bundled config also describes Sepolia, Hoodi and Ephemery.
Pick one with --network and give it its own data directories — every store is
bound to the chain it was created for:
./bin/umnode --network sepolia \
--block-db data/sepolia/chain --state-db data/sepolia/state \
--node-db data/sepolia/p2p/enode --inventory-db data/sepolia/p2p/inventory
Ephemery resets every 28 days; after a reset run make ephemery-genesis to
fetch the new iteration's genesis and start from empty directories. See
Bundled networks.
What you should see¶
On a healthy start UMNode logs that it has loaded the network config, opened its
stores, and begun discovery. As peers complete the eth handshake you'll see
Peer ready lines (alongside geth's periodic Looking for peers count), and as
the head advances the realtime worker logs each block it imports.
Inventory persistence enabled path=data/p2p/inventory compactionEvery=1h0m0s
Block store ready path=data/chain segmentSize=50000 codec=s2 pendingBackend=pebble sealConfirmations=256 ...
Looking for peers peercount=3 tried=8 static=0
Peer ready peer=a1b2c3d4e5f6a7b8 version=70
Imported block number=25,232,371 hash=0xbde1…51bfe txs=290
Two workers fill the store
The realtime worker writes upcoming blocks (header, body, receipts) into the store as the head advances, while the backfill worker fills history downward toward genesis. So the store grows forward from the head and backward to block 0 at the same time.
Where the state comes from
With execution on (the default), an empty node first asks its
segment archive — the public one unless --archive-source
names another — for a state snapshot: --syncmode snap, the default,
restores the newest one and executes on from its head, downloading only
the blocks the node keeps (--block-history). When the archive publishes
none — the public archive carries no snapshots — the node says so and
builds the state from genesis instead (--syncmode full), which needs
every block. See Sync modes.
Next steps¶
- Configuration — tune peers, discovery and the block store per network.
- Architecture — understand how UMNode is meant to fill and serve its store.
- Block store — the segment format, and why a couple of settings are locked at database creation.