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

51 lines
2.8 KiB
Markdown

# 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).