Skip to content

feat(discv5): add standalone discovery v5 module - #2

Open
lodekeeper-z wants to merge 120 commits into
discv5-basefrom
feat/discv5-carveout
Open

lodekeeper-z wants to merge 120 commits into
discv5-basefrom
feat/discv5-carveout

Conversation

@lodekeeper-z

@lodekeeper-z lodekeeper-z commented Aug 17, 2026 •

Copy link
Copy Markdown
Owner

Adds a standalone Discovery v5 implementation built on Zig 0.16 std.Io, organized around one public Runtime and one internal single-writer actor.

The actor is the authoritative owner of sessions, requests, lookups, peers, address votes, local ENR state, and protocol metrics. Every outbound datagram becomes a move-owned value in one bounded global ActorEffect FIFO. Runtime is the sole transport executor and returns exactly one sent, failed, or runtime_stopped completion to the actor, which commits or aborts the prepared protocol transition. Request records own response correlation, retry and rekey state, admission permits, lookup association, and cleanup obligations.

Transport is the sole socket owner. Internal completion is synchronous. Best-effort discovery observations use a bounded event outbox, while API requests and lookups reserve capacity in separate reliable result planes before any network work is accepted. Cancellation, timeout, shutdown, payload ownership, and stalled consumers therefore produce one authoritative terminal result without blocking the actor.

Remote state remains explicitly bounded, including sessions, challenges, response recovery, admission permits, queued requests, lookup candidates, events, votes, and retained metadata. Expected traffic receives owned packet budgets before ordinary source-IP bans, replay epochs never forget authenticated nonces under live keys, retries use fresh ciphertext, duplicate probes retransmit the exact retained WHOAREYOU challenge, and response recovery keeps stable keys until candidate-key traffic proves adoption.

Lookup traversal keeps the 16-result and 16-request limits with a bounded 32-candidate frontier. Synchronous candidate failures cannot strand a lookup, temporary local request pressure is deferred for bounded maintenance repumping, and returned candidates retain validated contact metadata locally so traversal and final results do not depend on the global contact cache. Duplicate candidates preserve the newest retained ENR and endpoint.

Returned NODES ENRs are signature-validated once at the packet boundary and reused as owned validated values for distance checks, peer learning, events, request results, and lookup candidates. Routing preserves endpoint-specific relay trust: locally configured records are immediately trusted, while network-learned ENRs become relayable only after authenticated traffic from their advertised UDP endpoint.

Stable-session expiration is maintenance-owned. Observational metrics do not mutate TTL or LRU state, unauthenticated and rejected traffic cannot refresh recency, and only accepted authenticated traffic refreshes a session. Capacity-safe insertion reuses expired storage before evicting live state.

The runtime exposes per-event-kind drops, contact retention and rejection totals, stable-session churn, and point-in-time actor workload gauges. The discovery executable supports sustained replenishing stress runs and reports reliable lookup completions independently from lossy observations.

Canonical RLP/ENR decoding rejects malformed remote input without assertions, including unsupported signed ENR fields. secp256k1 signing is deterministic RFC6979 over the supplied digest and emits canonical low-S signatures compatible with ChainSafe's Noble-based implementation. Empty request IDs remain wire-valid and multipart NODES responses remain bounded. Normal stop closes command intake, interrupts blocked transport through Runtime-owned cancellation, reaps internal work, and terminalizes every accepted command, effect, lookup, and request exactly once.

AI assistance was used for implementation, test development, profiling, and review; all changes were exercised through the repository's deterministic verification and stress workflows.

Implement ENR and RLP codecs, wire messages and packet handling, authenticated sessions, request tracking, routing, lookup orchestration, ingress rate limiting, and a std.Io runtime service.

Cover official wire vectors, malformed encodings, bounded attacker-controlled state, ownership, retries, event delivery, and service-level discovery flows.
Add a runnable std.Io.Threaded example that seeds public bootnodes, performs random or targeted recursive lookups, prints discovered ENRs, and shuts down cleanly.
Replace the split Protocol, Service, and request-index architecture with a single-writer actor and request-owned lifecycle state. Transport sends now follow prepare, send, and infallible commit transitions, while admission permits, handshake recovery, lookups, sessions, peers, and public events each have one authoritative owner.\n\nKeep all remote state bounded, retain endpoint-gated relay trust, add deterministic low-S secp256k1 signing, and preserve late-response, retry, replay, graceful-shutdown, and malformed-input behavior through focused regressions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant