Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

web3-DHT-Beacon

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

What it is / is not

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 / L0d
Is not A beacon-chain, validator, checkpoint sync server, or public-IP discv5 replacement
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.

Problem

Native beacon DHT (discv5 ENR) binds reachability to IP (/ip4/…/tcp/… or /udp/…).

CoNET nodes that only peer through conet-l0d publish wallet locators. Classic DHT cannot introduce them to each other without leaking public IPs.

TCP vs UDP surfaces (v0.2.1)

Surface Transport Bridge config / API Default port
TCP duplex / beacon libp2p conet-l0d proxy_duplex / client_duplex logical_port, bootstrap_nodes 4210
UDP discv5 + QUIC LayerMinus Chat mailbox (not L0d udp_ports, not duplex) logical_udp_port, discovery_nodes, discv5_quic_enabled 4300

Multiaddrs (naming only — UDP bytes do not ride L0d datagram overlay):

/web3/<wallet>/tcp/4210/p2p/<peer_id>     # TCP duplex
/web3/<wallet>/udp/4300/p2p/<peer_id>     # UDP discovery locator

URI forms:

web3://<wallet>:4210#peer_id=<id>                    # bootstrap (TCP)
web3://<wallet>:4300#peer_id=<id>&transport=udp      # discovery (UDP)

Set logical_udp_port = 0 to disable the UDP surface (TCP-only hubs).

discv5/QUIC via Chat mailbox

When discv5_quic_enabled = true:

  1. Egress: intercept local Prysm UDP → encrypt to recipient user PGPPOST { "data": armor } to a healthy entry (one-shot Chat, not a long-lived duplex).
  2. Ingress: adapter / lab POST /web3/v1/dht/udp-datagram (JSON datagram or armored data) → inject to beacon_udp_inject (local Prysm discv5/QUIC listen).
  3. Announce may include user_public_key_armored so peers know the Chat encrypt target.

Lab-only: mailbox_loopback = true hairpins without SI.

Bridge model

                    ┌─────────────────────────┐
   native beacon    │  web3-beacon-dht        │
   (unchanged)      │  (extension / bridge)   │
                    │                         │
   --bootstrap-node │  wallet-keyed records   │
   ←── web3 TCP     │  TCP 4210 + UDP 4300    │
       + UDP disc   │  (never public IP ENR)  │
                    └───────────┬─────────────┘
                    ┌───────────┴─────────────┐
                    ▼                         ▼
         conet-l0d duplex (TCP)     Chat mailbox (UDP discs)
                    │                         │
                    ▼                         ▼
         remote peer TCP            remote peer discv5/QUIC
  1. Peers announce to the bridge: wallet + peer_id + TCP and/or UDP web3://… (never an IP host).
  2. Operators read /web3/v1/dht/bootstrap:
    • Default (dual): bootstrap_nodes (TCP duplex) + discovery_nodes (UDP discv5/QUIC).
    • UDP-only product (bootstrap_udp_only = true): only discovery_nodes; bootstrap_nodes and lab_prysm_bootstrap_enrs are empty. Hub .30 lab uses this mode.
  3. Actual CL traffic still runs on the native beacon; the bridge helps peers discover who to dial over web3://, and optionally carry UDP discovery bytes (HTTP peer / Chat mailbox).

Iron rule: bootstrap / peers = web3:// only

Must Must not
Every bootstrap_nodes[] / discovery_nodes[] entry is web3://… Classic discv5 enr:…
Announce stores only web3:// multiaddrs (/tcp/ and /udp/) /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
UDP-only hubs: spokes consume discovery_nodes only Product path using lab_prysm_bootstrap_enrs / --peer / classic ENR

classic_enr on announce is rejected. Stored snapshots strip any legacy ENR on load. Bootstrap never prefers ENR over web3://.

Status

Production-oriented bridge: signed announce (v1 TCP / v2 TCP+UDP), split TCP/UDP bootstrap, one-shot pull CLI. Debian/apt packaging and a tighter native-beacon bootstrap adapter are planned.

Features

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|udp}/<port>/p2p/<peer_id>IP hosts rejected
Announce EIP-191 personal_signv2 when UDP published; v1 still accepted for TCP-only
Bootstrap GET /web3/v1/dht/bootstrap — hub first, deduped; dual or bootstrap_udp_only (UDP discovery_nodes only)
Pull CLI pull-bootstrap prints TCP then UDP; udp-only hubs require non-empty discovery_nodes
Persist Optional JSON snapshot

HTTP API

Method Path Purpose
GET /eth/v1/node/identity Bridge hub identity (TCP + UDP discovery addresses)
GET /eth/v1/node/peer_count Registered record count
GET /eth/v1/node/version web3-beacon-dht/0.2.1
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 TCP + UDP locators
POST /web3/v1/dht/udp-datagram Inject discv5/QUIC datagram (requires discv5_quic_enabled)

Announce body (JSON):

{
  "wallet": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "peer_id": "16Uiu2HAmExamplePeerId",
  "logical_port": 4210,
  "logical_udp_port": 4300,
  "web3_uris": ["web3://0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:4210"],
  "web3_udp_uris": ["web3://0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:4300"],
  "user_public_key_armored": "-----BEGIN PGP PUBLIC KEY BLOCK-----\\n…",
  "seq": 1,
  "ttl_secs": 86400,
  "signature": "0x…65-byte EIP-191 personal_sign…"
}

Signed messages:

# v1 (TCP-only / legacy)
web3-beacon-dht-announce:v1:<wallet_lower>:<peer_id>:<logical_port>:<seq>

# v2 (TCP + UDP discovery surface — preferred when logical_udp_port is set)
web3-beacon-dht-announce:v2:<wallet_lower>:<peer_id>:<tcp_port>:<udp_port>:<seq>

Bootstrap response shape (dual track):

{
  "bootstrap_nodes": ["web3://0x…:4210#peer_id=…"],
  "discovery_nodes": ["web3://0x…:4300#peer_id=…&transport=udp"],
  "bootstrap_udp_only": false,
  "tcp_ports": [4210],
  "udp_ports": [4300],
  "discv5_quic_enabled": false,
  "udp_transport": "chat_mailbox",
  "count": 1,
  "discovery_count": 1
}

UDP-only product hub (bootstrap_udp_only = true in toml; e.g. deploy/30/):

{
  "bootstrap_nodes": [],
  "discovery_nodes": ["web3://0x…:4310#peer_id=…&transport=udp"],
  "bootstrap_udp_only": true,
  "lab_prysm_bootstrap_enrs": [],
  "tcp_ports": [],
  "udp_ports": [4310],
  "count": 0,
  "discovery_count": 1
}

Lab deploy notes: deploy/30/ (hub), deploy/45/ (spoke consumer), deploy/98/ (UDP announce).

Build

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.toml

Configuration

See 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
logical_udp_port = 4300
dht_server_enabled = true
discv5_quic_enabled = false
persist_path = "/var/lib/web3-beacon-dht/peers.json"
evict_interval_secs = 300
require_announce_sig = true

Keep the HTTP listen address on loopback or a private overlay. TCP peer reachability stays with native beacon + conet-l0d duplex. UDP discv5/QUIC (when enabled) uses Chat mailbox one-shot POST, not L0d udp_ports / duplex.

systemd

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-dht

Future apt-get install web3-beacon-dht packaging will use the same unit layout.

Relation to CoNET stack

Component Role
Native beacon (Prysm, …) Consensus + libp2p; unchanged
CoNET-L0D web3:// duplex for TCP (4210)
LayerMinus / CoNET-SI Chat Mailbox for UDP discv5/QUIC datagrams (4300 logical)
web3-DHT-Beacon (this repo) Extension DHT bridge — TCP bootstrap + UDP discovery naming + optional Chat UDP proxy
Classic IP DHT :4110 Still used by IP-native L1 hubs (not wallet overlay)

License

MIT — see LICENSE.

Related docs

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages