Files
varde/docs/milestone-3.md
T
bl 61171a5ea8 Milestone 3: iroh endpoint, tickets, pin-triggered fetch
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>
2026-07-14 21:18:25 +02:00

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, mode 0600, 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 need wan_upload on both ends — documented behavior, not a bug.
  • Downloader, not the rpc client. The Blobs rpc client (add_from_path/download) would pull in the whole quic-rpc feature surface; the underlying Downloader gives queueing, retries and resume with no extra dependencies. One found-the-hard-way detail: the downloader dials by NodeId only, so the ticket's NodeAddr must be registered with the endpoint (add_node_addr) before queueing, or every dial fails with "no addressing information".
  • Pin-before-fetch. TicketImport records 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. TicketImport replies immediately with the pinned hash; completion is observable via Status {hash} polling or the pin_complete event on a subscribed connection.
  • A bare Pin still 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).