L1 overlay lab — wallet-addressed geth / Prysm
Evidence level: laboratory review (2026-08-24). This page records a
read-only evaluation of two non-production spokes that run unmodified
geth and Prysm behind conet-l0d. It is not the public
L1 join path, not a claim that production validators have moved off
public IP:port peering, and not a new SI command family.
The design under test is:
remote identity = wallet + logical port
→ web3://0x…:8400 | web3://0x…:4200
→ conet-l0d client_duplex / proxy_duplex
→ 127.0.0.1:<bound port>
→ unmodified geth / Prysm
Layer Minus carries encrypted duplex frames. geth still names an EL peer
with an enode:// public key. Prysm still names a CL peer with a libp2p
peer ID. Those application identifiers stay. The durable remote that
conet-l0d dials or accepts is a billing / channel EOA, not a public
host address.
Public operators continue to use Run an L1 node.
Verdict
| Host | Role in this lab | Wallet-addressed overlay | Unmodified clients on loopback | Notes |
|---|---|---|---|---|
Spoke .98 |
Client toward .82 and toward .45 |
Meets the lab design | Yes | Dials two wallets; geth/beacon have no public P2P sockets |
Spoke .45 |
Client + published wallet host | Meets the lab design | Yes | Outbound only to .82; inbound proxy_duplex accepts any client that targets .45 billing |
Hub .82 |
Production L1 + L0d proxy | Dual-stack | No — still public :8400 / :4200 |
Expected for a live validator host; not an L0d-only spoke |
.45 dual role is the design, not a compromise. The host is:
- a client that joins
.82's wallet-addressed network (web3://0x66dCB48f…:8400/:4200); and - a published wallet (
0xEF107528…) that any conforming client may dial. The host does not pre-list those clients and does not dial them back.
.98 is one such client. A future third client would use the same
web3://0xEF107528…:port locator. Requiring .45 to add a
client_duplex row for every inbound peer would invert that model.
Overall: both spokes peer by wallet locator; remaining operational limits are SI listen-pool capacity and the hub still advertising public L1 P2P — not a return to IP-first identity on the spokes.
Identity map (do not treat as a production roster)
| Host | Billing EOA (duplex signer / client_duplex target) |
Channel :8400 routing EOA |
Channel :4200 routing EOA |
|---|---|---|---|
.82 hub |
0x66dCB48ff905f5f5f3692f302da0A84e0265A792 |
0x66dCB48ff905f5f5f3692f302da0A84e0265A792 |
0x3048925d768694D4b95524DFB71b38e812D705Dd |
.45 spoke |
0xEF10752843cAC32C73DAb86658B8ab6E5667199B |
0xEF10752843cAC32C73DAb86658B8ab6E5667199B |
0x3F84B8f11BF7886DCf0c902A3148cc2926E185dA |
.98 spoke |
0x72c240E4e35caF9822E6B71BBB816db83E1534a5 |
0x8a2b04C82B43447b69946b31BCCEa14ed29471f4 |
0x2Ae19d1f39445fFa218F540cdD6BDCAfBD68ca7b |
This matches the documented wallet split in
conet-l0d — Wallet and key roles and
wallet-addressed peer identity:
- billing EOA signs the duplex offer / is the
web3://host inclient_duplex; - per-port routing EOA owns AddressPGP listen for that logical port
(
[[l0.channels]]); - temporary line wallets are process-memory identities for one occupied
pipe (examples on
.98:0xc8b1ae25…,0x60c12814…).
.98 is the fuller split (billing ≠ geth routing ≠ beacon routing). .45
reuses the billing wallet on :8400 and still isolates beacon on
0x3F84B8f1….
How the spokes actually connect
.98 — full wallet mesh (outbound)
l0.client_duplex at the snapshot:
web3://0x66dCB48ff905f5f5f3692f302da0A84e0265A792:8400@18400
web3://0x66dCB48ff905f5f5f3692f302da0A84e0265A792:4200@14200
web3://0xEF10752843cAC32C73DAb86658B8ab6E5667199B:8400@18401
web3://0xEF10752843cAC32C73DAb86658B8ab6E5667199B:4200@14201
The @LOCAL suffix is a Linux bind pin only. It is not part of the public
web3:// locator. geth bootnodes and Prysm --peer use those loopback
ports:
| Client | Remote | Loopback target |
|---|---|---|
| geth | hub .82 |
127.0.0.1:18400 |
| geth | spoke .45 |
127.0.0.1:18401 |
| Prysm | hub .82 |
/ip4/127.0.0.1/tcp/14200/p2p/16Uiu2HAmDJCHuVkXtkPrrL8YykQ9gFZnQkR9Q6WjZZUrmueohPfd |
| Prysm | spoke .45 |
/ip4/127.0.0.1/tcp/14201/p2p/16Uiu2HAkxjzYKtKJZc9E7pMTa3LzB9XHdHoDBaRHymQgtofmbKUA |
Observed 2026-08-24T12:25Z–12:30Z UTC:
admin_peers= 2, both127.0.0.1:18400and127.0.0.1:18401;- beacon
connected= 2; - geth/beacon established sockets were loopback only;
- L0d log:
l0_connect HTTP 200; pipe_tx installedandduplex_offer completefor ports8400and4200; - hub log allocated proxy lines with
billing_wallet=0x72c240e4…(the.98billing EOA), not a public IP.
geth flags that enforce the overlay: --nat none --netrestrict 127.0.0.0/8.
Prysm flags: --no-discovery --p2p-local-ip=127.0.0.1.
.45 — client of .82, server for any wallet client
Intended roles on one process:
| Direction | Config | Remote identity |
|---|---|---|
| Outbound client | l0.client_duplex |
Only .82 billing 0x66dCB48f… on :8400 / :4200 |
| Inbound host | [[l0.proxy_duplex]] on loopback :8400 / :4200 |
Callers target .45 billing 0xEF107528…; callers are not pre-listed |
l0.client_duplex at the snapshot:
web3://0x66dCB48ff905f5f5f3692f302da0A84e0265A792:8400@18400
web3://0x66dCB48ff905f5f5f3692f302da0A84e0265A792:4200@14200
There is no .45 → .98 client_duplex or [[peers]] row. That is
correct. .98 (or any later client) reaches .45 by dialing
web3://0xEF10752843cAC32C73DAb86658B8ab6E5667199B:8400 /
:4200. The offer is authorized as a signed mainWallet:port event, not
by a static peer roster.
Observed 2026-08-24 (rechecked after the dual-role clarification):
- geth peers: outbound
127.0.0.1:18400(client →.82) and inbound127.0.0.1:44776(accepted wallet line;.98in this lab); - beacon
connected= 2 (client →.82on14200, plus inbound on local:4200); - no geth/beacon sockets to a public hub
:8400/:4200; - L0d:
pipe_tx installed/duplex_offer completeon:8400and:4200.
Checklist against the written design
| Design rule | Source | .45 |
.98 |
|---|---|---|---|
Remote is web3://0x…:port, not IP:port |
Locator, duplex lifecycle | Pass (client → .82; host accepts by own billing) |
Pass (client → .82 and .45) |
| Client of a published wallet | client_duplex |
Pass (only .82) |
Pass (.82 + .45) |
| Published wallet any client may dial | [[l0.proxy_duplex]] |
Pass (does not roster inbound peers) | Pass (also publishes loopback origins) |
| One communication identity per logical port | [[l0.channels]] |
Pass | Pass |
| Temporary identity per accepted line | Persistent-stream bootstrap | Pass (listen-ready temp wallets) |
Pass |
| Origin service stays on loopback | Server / client profile | Pass | Pass |
| Unmodified geth / Prysm | This lab thesis | Pass | Pass |
| No public EL/CL P2P from the spoke process | Lab intent | Pass at snapshot | Pass at snapshot |
Sync status (do not confuse with overlay correctness)
Overlay success is wallet duplex + loopback peers. Tip height is a separate catch-up problem.
| Host | EL eth_blockNumber |
CL head_slot / sync_distance |
Hub tip (same window) |
|---|---|---|---|
.98 |
0x0 (importing potential segments; eth_syncing still reports start 0x0) |
1215 / 1031840, is_syncing=true |
EL 0xef37e, CL slot 1033055, is_syncing=false |
.45 |
0x0 |
23519 / 1009536, is_syncing=true, is_optimistic=true |
same |
Both spokes were behind the canonical tip. That does not undo the wallet-addressed transport. It does mean they are not yet production-quality full nodes.
Gaps that are still real
- SI listen pool. Temporary-identity pre-warm and inbound
duplex_offerfail with{"ok":false,"error":"pool_full"}when Guardianl0_listenslots are exhausted. Restarting the hub process freed slots in this lab. Capacity is an L0 operational limit, not an IP-identity fallback. Current L0d cools a failing SI host and random-picks another from the GuardianNodesInfoV6 contract pool (si_pool_from_contract); see SI entry discovery. - Hub dual-stack.
.82still listens on public:8400/:4200for the production L1 set. Itsproxy_duplexfor:4200was bound to the public address. Spokes must keep--netrestrict 127.0.0.0/8and must not add those public ports as geth bootnodes or Prysm--peer. - Host firewall is not the identity model.
.98additionally rejects egress TCP to hub/spoke:8400/:4200. That is a safety net. The contract remains the wallet locator. - AES decrypt refusals appeared on
.98during early offers (stale armor / wrong key set). Later sessions completed withpipe_txinstalled. Treat decrypt failure as fail-closed, not as a reason to open public P2P.
Do not treat “.45 has no client_duplex toward .98” as a defect.
Inbound authorization is the signed offer to .45 billing
0xEF107528…, not a reverse dial.
What this is not
- Not a replacement for the six-host public L1 roster in Run an L1 node.
- Not evidence that Beacon validators on
.45/.98are in service. Those hosts are not on the current production L1 voting set. - Not a claim that Layer Minus hides the spoke IP from the selected Guardian entry. L0d still posts to existing entry hosts over HTTP.
- Not a new SI
duplex_*command. Offer/accept remain encrypted application objects; SI only providesl0_listen/l0_connect.