Extension DHT bridge for a native beacon node—not a beacon itself.
This project does not sync slots, attest, gossip blocks, or run consensus. It only bridges discovery so nodes that reach each other over web3:// / CoNET-L0D can still find and dial peers the way a normal beacon DHT would, without advertising public IP multiaddrs.
Repository: github.com/CoNET-project/web3-DHT-Beacon
| Is | An extension DHT beside the native Prysm (or other) beacon |
| Is | A bridge: web3:// wallet locators ↔ bootstrap / peer records the operator (or adapter) feeds into the native beacon |
| Is not | A beacon-chain, validator, checkpoint sync server, or discv5 replacement for the whole network |
| Does not | Implement beacon P2P gossip, fork choice, or execution engine APIs |
Native beacon keeps all consensus and libp2p duties. web3-beacon-dht only solves discovery naming when peers are wallet-addressed.
Native beacon DHT (discv5 ENR) binds reachability to IP (/ip4/…/tcp/…).
CoNET nodes that only peer through conet-l0d duplex publish:
web3://<wallet|tag>:<logical-port>
Those peers have no useful public IP in the ENR. Classic DHT cannot introduce them to each other.
┌─────────────────────────┐
native beacon │ web3-beacon-dht │
(unchanged) │ (extension / bridge) │
│ │
--bootstrap-node │ wallet-keyed records │
←── ENR or │ web3://0x…:4210 │
web3 locator │ ↔ optional classic ENR │
└───────────┬─────────────┘
│ resolve via
▼
conet-l0d duplex
│
▼
remote peer TCP
(native beacon :4200/:4210)
- Peers announce to the bridge: wallet +
peer_id+web3://…(never an IP host). - Operators (or a small adapter) read
/web3/v1/dht/bootstrapand pass locators into the native beacon bootstrap path / L0d client endpoints. - Actual CL traffic still runs on the native beacon; the bridge only helps peers discover who to dial over
web3://.
| Must | Must not |
|---|---|
Every bootstrap_nodes[] entry is web3://… (optionally #peer_id=…) |
Classic discv5 enr:… |
Announce stores only web3:// multiaddrs |
/ip4/… / /dns4/… public multiaddrs |
| Hub + peer locators hide public IPs from learners | Returning a hub/public ENR that teaches spoke nodes a dialable public address |
classic_enr on announce is rejected. Stored snapshots strip any legacy ENR on load. primary_bootstrap_arg never prefers ENR over web3://.
Production-oriented bridge: signed announce, deduped bootstrap, one-shot pull CLI. Debian/apt packaging and a tighter native-beacon bootstrap adapter are planned.
| Area | Behavior |
|---|---|
| Role | Extension DHT bridge only |
| Identity | Peers keyed by wallet (0x + 40 hex) or exact tag — real EOA, not hash labels |
| Addresses | /web3/<host>/tcp/<port>/p2p/<peer_id> — IP hosts rejected |
| Announce | EIP-191 personal_sign over web3-beacon-dht-announce:v1:… (require_announce_sig, default true) |
| Bootstrap | GET /web3/v1/dht/bootstrap — hub first, deduped, web3:// only (never classic ENR / /ip4) |
| Pull | CLI pull-bootstrap = co-located single-shot (same class as CoNET Chat one-shot; do not use L0d duplex) |
| Persist | Optional JSON snapshot |
| Method | Path | Purpose |
|---|---|---|
GET |
/eth/v1/node/identity |
Bridge hub identity for tooling (not a live beacon ENR) |
GET |
/eth/v1/node/peer_count |
Registered record count |
GET |
/eth/v1/node/version |
web3-beacon-dht/0.1.0 |
POST |
/web3/v1/dht/announce |
Publish / refresh (signature required when enforced) |
GET |
/web3/v1/dht/peers |
List or lookup by ?wallet= |
GET |
/web3/v1/dht/bootstrap |
One-shot bootstrap locators |
Announce body (JSON):
{
"wallet": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"peer_id": "16Uiu2HAmExamplePeerId",
"logical_port": 4210,
"web3_uris": ["web3://0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:4210"],
"seq": 1,
"ttl_secs": 86400,
"signature": "0x…65-byte EIP-191 personal_sign…"
}Signed message:
web3-beacon-dht-announce:v1:<wallet_lower>:<peer_id>:<logical_port>:<seq>
rustup show # toolchain pinned in rust-toolchain.toml (1.87.0)
cargo build --release
./target/release/web3-beacon-dht check-config --config config/web3-beacon-dht.example.toml
./target/release/web3-beacon-dht resolve 'web3://0x4E72cC4EfC8c87d3297d07b7D8f225E355F6Ee47:4210'
./target/release/web3-beacon-dht pull-bootstrap --url http://127.0.0.1:4120
./target/release/web3-beacon-dht start --config config/web3-beacon-dht.example.tomlSee config/web3-beacon-dht.example.toml and production deploy/30/web3-beacon-dht.toml.
wallet = "0x4E72cC4EfC8c87d3297d07b7D8f225E355F6Ee47"
peer_id = "16Uiu2HAmReplaceWithStableHubPeerId"
listen = "127.0.0.1:4120"
logical_port = 4210
persist_path = "/var/lib/web3-beacon-dht/peers.json"
evict_interval_secs = 300
require_announce_sig = trueKeep the HTTP listen address on loopback or a private overlay. Peer TCP reachability stays with native beacon + conet-l0d, not with this process. Only-read bootstrap → Chat/HTTP single-shot; duplex only for continuous peer traffic.
Example unit: systemd/web3-beacon-dht.service.
sudo install -m 0755 target/release/web3-beacon-dht /usr/bin/web3-beacon-dht
sudo install -m 0644 config/web3-beacon-dht.example.toml /etc/web3-beacon-dht.toml
sudo install -m 0644 systemd/web3-beacon-dht.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now web3-beacon-dhtFuture apt-get install web3-beacon-dht packaging will use the same unit layout.
| Component | Role |
|---|---|
| Native beacon (Prysm, …) | Consensus + libp2p; unchanged |
| CoNET-L0D | web3:// duplex transport |
| web3-DHT-Beacon (this repo) | Extension DHT bridge (discovery naming only) |
Classic IP DHT :4110 |
Still used by IP-native L1 hubs |
MIT — see LICENSE.