Protocol v2: trusted-peer push, truthful partials, split downloads

Three capabilities the iroh-blobs 0.103 line makes possible:

- Push (new API surface, protocol v2): `Push { hash, node_id }` hands
  fully-present content to a trusted peer, unprompted. Consent is
  mutual — the sender pushes only to peers it trusts, and the receiver
  (which now accepts connections unconditionally and gates per request)
  admits pushes only from peers *it* trusts, deferring with RateLimited
  while metered. An accepted push is pinned by the receiver (default
  policy, format inferred from the request ranges) once its transfer
  completes, and surfaces as a PushReceived event. Because QUIC writes
  are fire-and-forget, the sender confirms delivery by observing the
  receiver's bitfields (root + last hashseq child) before replying —
  Pushed { bytes } means verified received, not merely sent. New
  varde-ctl `push` command.

- Truthful partial presence: Status/List report bytes actually present
  and verified for partial blobs, from the store's bitfields via
  observe, instead of the old "0 until complete".

- Split downloads: multi-provider fetches stripe one request across
  providers (SplitStrategy::Split) instead of trying them serially.

Trusted peers may observe bitfields even when serving is disabled or
metered — bitfields are metadata, and push confirmation rides on them.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-16 14:52:27 +02:00
parent ad69f7d884
commit 4033c0ffab
9 changed files with 474 additions and 33 deletions
+12
View File
@@ -73,6 +73,14 @@ enum Command {
/// Peer trust operations
#[command(subcommand)]
Peer(PeerCommand),
/// Push fully-present content to a trusted peer
Push {
/// BLAKE3 hash (hex)
hash: String,
/// The receiving peer's iroh NodeId (z-base-32); must be trusted
/// on both sides
node_id: String,
},
/// Drop all unpinned blobs
Gc,
/// Stream daemon events to stdout (one JSON object per line)
@@ -180,6 +188,7 @@ fn to_request(command: Command) -> Result<Request> {
Command::Peer(PeerCommand::Trust { node_id }) => Request::PeerTrust { node_id },
Command::Peer(PeerCommand::Untrust { node_id }) => Request::PeerUntrust { node_id },
Command::Peer(PeerCommand::List) => Request::PeerList {},
Command::Push { hash, node_id } => Request::Push { hash, node_id },
Command::Gc => Request::Gc {},
Command::Subscribe => Request::Subscribe {},
})
@@ -291,5 +300,8 @@ fn print_human(data: Option<&ResponseData>) {
ResponseData::GcDone { blobs_removed } => {
println!("gc: removed {blobs_removed} blobs");
}
ResponseData::Pushed { hash, bytes } => {
println!("pushed {hash} ({bytes} bytes)");
}
}
}