Uh oh!
There was an error while loading. Please reload this page.
feat(dig-node): peer provider-snapshot mTLS RPC + concrete NeighbourhoodProbe - #157
Merged
Merged
Conversation
…oodProbe (#1989) Add the anti-Sybil identity-binding layer of the DHT-sampling flywheel (epic #1934 child 4a): the dig.getProviderSnapshot peer RPC and the concrete DhtNeighbourhoodProbe that consumes it. Server: dig.getProviderSnapshot answers this node's LOCAL DHT provider store, reusing the RLY-009 DhtRecordsAnswer wire shape verbatim (counts only, never provider identities). max_keys is clamped to a frame-safe 512-key cap. Added to the peer-reachable allowlist as a dig-node-local method (the shared dig-rpc-protocol allowlist is a pinned dep we cannot extend; promoting it is a cross-repo follow-up), answered at the NodeResponder like dig.getPeers. Client + probe: DhtNeighbourhoodProbe routes toward a keyspace point with find_node, fetches each peer's snapshot over mTLS, and builds one PeerObservation per responding peer. THE load-bearing rule: PeerObservation.peer_id is set from SHA-256(verified mTLS server-cert SPKI DER) of the session, NEVER Contact.peer_id or any payload field. Per-peer holdings and per-round observation volume are capped before reconcile so a lying peer cannot OOM the reconciler. An unreachable/silent/erroring peer yields nothing, never an error. Tests cover the anti-Sybil identity binding (a peer claiming a different id in its Contact is attributed to its real SPKI), the volume caps, the bounded counts-only server, the silent-peer contract, the wire-shape parse, and a real-wire two-node round-trip proving peer_id == the responding server's SPKI. Scope: RPC (server+client) + concrete probe + caps only. The prefetch loop (selection, fetch, cache writes) is child 4b. Version: dig-node-core 0.31.0 -> 0.32.0 (MINOR, new capability); workspace 0.80.0 -> 0.81.0. Co-Authored-By: Claude <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
MichaelTaylor3d added a commit
that referenced
this pull request
Aug 3, 2026
Rebased onto #157; main took 0.81.0/0.32.0 while this was in review. Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of DIG-Network/dig_ecosystem#1989 — child 4/7 of epic #1934, PR 4a of 2 (4b = the governed prefetch loop, a separate later PR). SECURITY-CRITICAL: the anti-Sybil identity-binding layer.
What changed
Provides the concrete
NeighbourhoodProbe(child 2 left it a mocked trait seam) + the node↔node RPC it needs to obtain other peers' provider snapshots.dig.getProviderSnapshotpeer RPC — answers with the node's LOCALDhtService::provider_snapshot(max_keys), reusing the RLY-009DhtRecordsAnswerwire shape verbatim (counts-only, no provider identities).max_keysclamped toMAX_PROVIDER_SNAPSHOT_KEYS = 512(bounded by the 64 KiBread_framedframe ceiling). Answered at theNodeResponderlevel (it needsself.dht, which the FFI-safehandle_rpclacks), async-awaited (noblock_in_place— that's only needed for RLY-009's sync callback and would panic under the current-thread test runtime).DhtNeighbourhoodProbe::observe_near(point)—find_node(point)→ for eachContact, mTLS-dial + call the RPC → onePeerObservationper responding peer.dig-rpc-protocolis a crates.io 0.6 pin (can't extend), so this is a dig-node-local method — an explicit, documented exception inis_peer_reachable_methodwith a regression test asserting it's the ONE deliberate local addition (the sharedpeer_reachable_names()set is unchanged).Security properties (the point)
PeerObservation.peer_idis set ONLY from the verified session SPKI (PeerConnection.peer_id = SHA-256(SPKI DER), checked by dig-tls) — NEVERContact.peer_id, NEVER any payload field (the answer is deliberately identity-free). Proven by a unit test (Contact claims0xAA…, session verifies0xBB…→ observation attributed to0xBB…) + a real-wire two-node test assertingpeer_id == the responding server's SPKI. This is what makes child 2's quorum "one peer = one vote" hold.reconcile():MAX_HOLDINGS_PER_PEER = 512,MAX_OBS_PER_ROUND = 4096— truncated so a lying peer can't OOM the reconciler.How verified
cargo fmt --all -- --check→ 0;cargo clippy -p dig-node-core --all-targets --all-features -- -D warnings→ 0;cargo build -p dig-node-core→ 0.neighbourhood_probemodule: 11/11 pass (server clamp + empty-DHT, parse good/malformed, identity binding, silent peer, per-peer cap at/over bound, round cap, malformed-key drop, the two-node real-wire test); peer allowlist tests 4/4. The 7 broaderpeer::testsfailures are the known sandbox socket-bind limit (pass on real runners), none touch this code. Coverage deferred to CI's ≥80% gate (local llvm-cov >2min timeout).Version
dig-node-core0.31.0 → 0.32.0; root[workspace.package].version0.80.0 → 0.81.0;Cargo.lockupdated.SPEC.md(+ dig-node-core SPEC) document the method + bounds + the verified-identity contract.Follow-ups (orchestrator-owned / cross-repo)
dig.getProviderSnapshotas a node↔node peer RPC reusing RLY-009'sDhtRecordsAnswershape (I'll add it).dig-rpc-protocolallowlist so the local exception can be removed.Generated by Claude Code