61171a5ea8
The daemon binds an iroh endpoint (ed25519 identity at secret.key, 0600), serves its store via Blobs/Router on the standard ALPN, and fetches with the iroh-blobs Downloader rather than the rpc client to keep quic-rpc out of the tree. Relay is disabled unless wan_upload is set: LAN-only, zero WAN upload by default. TicketImport pins first (the pin is the GC root protecting in-flight data), registers the ticket's NodeAddr with the endpoint (the downloader dials by NodeId alone), then fetches in the background; completion emits pin_complete. Tests: two-daemon localhost transfers (blob + directory collection, byte-identical), and kill -9 mid-transfer followed by restart on the same store resuming to completion. Dependencies: iroh 0.35 (endpoint/router, pairs with iroh-blobs 0.35), rand 0.8 (secret key generation, same version iroh uses). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2.8 KiB
2.8 KiB
Milestone 3 — Transfer
The daemon now has an iroh endpoint: it serves its store over
iroh_blobs::ALPN via the standard Blobs/Router stack, and fetches
pinned content with the iroh-blobs Downloader. TicketExport /
TicketImport complete the v1 out-of-band sharing loop; the pin created
by an import triggers the fetch from the ticket-embedded provider.
Decisions
- Endpoint identity is an ed25519 key at
<store_dir>/secret.key(hex, mode0600, created on first start). Node ids surface in the API as opaque strings in iroh's canonical encoding. - Relay disabled unless
wan_upload = true. The default posture is LAN-only with zero WAN upload; with the relay off the endpoint is only reachable over direct paths and never moves bytes through third-party infrastructure. Tickets between machines that can't reach each other directly needwan_uploadon both ends — documented behavior, not a bug. - Downloader, not the rpc client. The
Blobsrpc client (add_from_path/download) would pull in the whole quic-rpc feature surface; the underlyingDownloadergives queueing, retries and resume with no extra dependencies. One found-the-hard-way detail: the downloader dials by NodeId only, so the ticket'sNodeAddrmust be registered with the endpoint (add_node_addr) before queueing, or every dial fails with "no addressing information". - Pin-before-fetch.
TicketImportrecords the pin (and the format from the ticket) before the fetch starts: the pin is the GC root that protects in-flight data, and the standing intent survives an unreachable provider or a crash. Re-issuing the import after a crash resumes from iroh-blobs' on-disk partial state. - Fetches are background tasks.
TicketImportreplies immediately with the pinned hash; completion is observable viaStatus {hash}polling or thepin_completeevent on a subscribed connection. - A bare
Pinstill fetches nothing — there are no known providers until LAN discovery lands in milestone 4. The pin is recorded and the spec's "fetch if absent" activates when provider sources exist. - No serving gate yet: this milestone serves any peer that presents the hash (tickets are unguessable capability tokens; BLAKE3 hashes of private content should be treated as secrets). The trust allowlist gate is milestone 4's first change.
Tests
Two-daemon localhost integration: single blob and directory collection transfer, byte-identical after materialize on the fetcher. Crash test: SIGKILL the fetcher ~150 ms into a 64 MB transfer, restart on the same store, re-import the ticket, content completes and matches (proves clean restart with partial on-disk state; on a fast machine the kill may land after completion, which still exercises restart-with-state).