20bdf56668
mDNS-style LAN discovery (iroh MdnsDiscovery, discovery flag, default on) feeds a presence tracker; trusted peers that appear trigger fetches of every incomplete pin, and Pin itself now fetches from present trusted peers. Serving is our own ProtocolHandler: trusted NodeIds get the full store, everyone else a filtered view limited to open_lan pins and ticket-exported hashes (plus hashseq children) that answers "not found" for the rest. Ticket export records standing serve-consent for that hash; trust changes take effect on new connections. ShapedStore implements the full iroh-blobs Store trait to charge provider reads to an upload token bucket and downloader writes to a download bucket; upload cap 0 closes incoming connections at accept. Subscribe now streams transfer_progress both ways, peer_joined, and pin_complete. Tests: forged-ticket trust gating (denied untrusted, served after trust), 256 KiB/s upload cap enforced by wall clock, event stream during a transfer, and real-mdns auto-sync between two daemons (skips where multicast is unavailable). Dependencies: n0-future, async-channel, futures-lite, bytes — all already in the tree via iroh; needed directly to name types in iroh-blobs trait signatures and channels. iroh feature discovery-local-network for MdnsDiscovery. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3.2 KiB
3.2 KiB
Milestone 4 — LAN discovery, trust, rate limiting, events
What landed
- LAN discovery via iroh's
MdnsDiscovery(the documented_irohmDNS service — identifiable on the network, not anonymous noise), enabled by thediscoveryconfig flag (default on). Sightings stream to the daemon, which tracks peer presence and reacts based on trust. - Trust gate. The provider is now our own
ProtocolHandler: connections from trusted NodeIds get the full store; everyone else gets a filtered view that answers "not found" for anything outside the openly-served set. Verified by the forged-ticket test: an untrusted peer that knows a private hash gets nothing until trusted. - Openly-served set =
open_lanpins + ticket-exported hashes, plus their HashSeq children, kept in memory and recomputed on pin changes and fetch completion. - Auto-sync. When a trusted peer appears on the LAN, every
incomplete pin is queued for download from them (
pinalso fetches immediately if a trusted peer is present — "fetch if absent" is now real). Verified end-to-end over actual mdns between two daemons in the test suite; the test skips gracefully where multicast is unavailable. - Token-bucket rate limiters wrap the store itself (
ShapedStoreimplements the full iroh-blobsStoretrait): provider data reads pay into the upload bucket, downloader batch writes pay into the download bucket. Upload cap 0 disables serving outright (connections closed at accept). Enforcement is proven by wall-clock in the test suite. - Event stream is live:
transfer_progress(both directions),peer_joined,pin_complete.
Decisions and trade-offs
- Ticket export grants standing serve-consent for that hash
(persisted in
meta.jsonasexported). Handing out a ticket is deliberate publication, and without this either every ticket import would require the exporter to pre-trust the importer, or tickets would silently stop working the moment the trust gate exists. This is the documented consent ladder: trusted peers see everything, open_lan/exported content is public, everything else is private. - Trust is evaluated at connection accept. Revoking (or granting)
trust applies to new connections; an existing connection keeps its
view until it closes. Cheap, predictable, and the window is bounded by
QUIC idle timeouts. Request-level re-checks would need a fork of
iroh-blobs' provider internals (
ResponseWriteris not constructible from outside the crate). - Gating by filtered store view (get → None) means an untrusted peer probing a private hash can't distinguish "refused" from "absent" — deliberately, that's the less chatty posture.
- "Connected" for peers means "seen via LAN discovery in the last two
minutes" — presence, not an open QUIC connection. Good enough for
peer listand the status count; honest about what it measures. fetch only from trusted peers: auto-sync only ever dials trusted peers. Ticket import dials the ticket's provider — importing the ticket is the explicit consent for that single fetch.- Download progress events report per-child offsets for collections; good enough for progress bars, not an exact byte ledger.