Skip to main content

Module client

Module client 

Source
Expand description

Wire message payload types for the cdn/client/v1 paid-delivery protocol.

cdn/client/v1 is the paid byte-transfer path (ADR 005 §cdn/client/v1): a payer opens a bidirectional QUIC stream, sends a StreamRequest, and the delivering node answers with a StreamResponse followed by a loop of ChunkData interleaved with cumulative payment Vouchers, terminating in ClientMessage::StreamEnd. Acceptance of a voucher is implicit — delivery simply continues; only rejection is signalled, via ClientMessage::StreamError. A delivery or payment fault is signalled by StreamError.

Like crate::message this is a leaf crate with no crypto dependency. The two signed artifacts on this protocol are produced/verified by decdn_incentive:

  • StreamResponse.slash_sig — an EIP-712 secp256k1 signature over the signed body fields {hash, ok, rate_per_mb, total_bytes, pool_id, timestamp_us} (ADR 014 §1), produced by the stream-response slash signer in decdn_incentive (analogous to its ProbeSlashData). error is unsigned.
  • Voucher.signature — an EIP-712 secp256k1 voucher signature; the wire carries {signature, amount} and the receiver reconstructs the full typed data {poolId, signer, provider, amount, bytesDelivered} from stream context (ADR 005 §Voucher wire format, decdn_incentive::Voucher).

§Signed-field freezing (ADR 013 §Signed Field Freezing)

The signed set on StreamResponseBody is the cdn/client/v1 v1 baseline. Any change to it is a Tier-3 ALPN bump. New unsigned fields go on StreamResponse as optional fields, following the total_bytes exemplar on crate::message::ProbeResponse.

§Variant order

ClientMessage, StreamError, and VoucherRejectReason all have frozen variant order — postcard encodes each variant as its declaration-order index. Reordering is a wire-breaking change; the *_discriminant_is_* / *_variant_order tests lock the assignments.

Structs§

ChunkData
Node → payer chunk of blob bytes. The payload carries at least one byte; its length is the sender’s choice, bounded above by the framing layer’s MAX_MESSAGE_SIZE; ADR 005 §cdn/client/v1 additionally requires a sender not to cross a CHUNK_BYTES payment boundary, so in practice a frame runs to at most one interval. Frames need not be uniform, and the frame before ClientMessage::StreamEnd is commonly shorter than the ones before it.
ChunkPreimage
Payer → node released hash-chain preimage, advancing the lane’s claim by one chunk with no signature (ADR 003 §Hash-chain metering (PayWord), ADR 005 §Payment quantum and credit window).
ClientBinding
Off-chain ephemeral client identity binding (ADR 003 §Off-Chain Ephemeral Binding), carried inside StreamRequestExt. The address and its attesting signature are paired so neither can appear without the other.
StreamRequest
Payer → node request opening a paid delivery (ADR 005 §cdn/client/v1).
StreamRequestExt
Optional StreamRequest extension fields (ADR 005 §Client identity binding), carried as trailing bytes after the StreamRequest message via the two-phase pattern (see encode_stream_request / parse_stream_request_ext).
StreamResponse
Node → payer response to a StreamRequest (ADR 005 §cdn/client/v1).
StreamResponseBody
Signed fields of a StreamResponse (ADR 014 §1). Layout is frozen per ADR 013 — future additions go on StreamResponse as optional unsigned fields, not here.
StreamResponseExt
Optional StreamResponse extension fields, carried as trailing bytes after the StreamResponse message via the two-phase pattern (ADR 013 §Tier 1; see encode_stream_response / parse_stream_response_ext).
Voucher
Payer → node cumulative payment voucher (ADR 005 §Voucher wire format).
WatermarkBundle
The node’s true watermark for a pool capability, echoed back on a gated StreamError::VoucherRejected so a wallet-less client can self-heal (issue #1481). amount/bytes_delivered mirror the seller-side PoolState::last_* fields as u64 cumulative totals, for the same reason as Voucher — matching the contract’s on-chain uint64 storage. last_signature is the node’s stored last-accepted client signature (r‖s‖v, exactly VOUCHER_SIG_LEN) — not a node signature over this bundle — so the client can confirm which of its own vouchers the node holds.
WireCapability
A pool owner’s spending capability, carried inside StreamRequestExt (ADR 003 §Capability delegation). signer and pool_id are not on the wire — they are derived from stream context, exactly like a Voucher’s implicit fields: signer is the request’s bound Ethereum address (ClientBinding::ethereum_address, or the registered on-chain signer when binding is absent) and pool_id is StreamRequest::pool_id.

Enums§

ClientMessage
Top-level protocol enum for cdn/client/v1. Variant order is frozen per ADR 013 — new variants MUST be appended at the end.
StreamError
A stream failure code (ADR 005 §Open-time refusal classes).
VoucherRejectReason
Why a Voucher was rejected (ADR 005 §VoucherRejected semantics).

Constants§

BINDING_SIG_LEN
Exact byte length of a BindNodeId client-binding signature (r‖s‖v, 32+32+1). The same EOA off-chain EIP-712 signing form as SLASH_SIG_LEN / VOUCHER_SIG_LEN (ADR 024 §Off-Chain Signature Verification — EOA Recovery Only); pinned by ClientBinding::validate.
CHUNK_BYTES
The payment quantum: one chunk of delivery, 1 MiB (ADR 003 §Chunk Cadence).
CHUNK_FRAME_HEADERS_MAX
Stack-buffer size for the full framing + ChunkData header: varint postcard_len + the one-byte ChunkData discriminant + varint payload_len. Sized to the unconditioned u32 varint width — 5 + 1 + 5 — for the same reason as the ChunkData header buffer; the cap keeps the bytes actually written to at most 9.
MAX_CHAIN_LENGTH
The highest chain index: the hash chain’s incremental range over its anchor (ADR 003 §Chain length and rollover).
MB_BYTES
One megabyte in bytes (ADR 003: 1 MB = 1,048,576 bytes, exactly). The unit of rate_per_mb and, by the identity below, of CHUNK_BYTES.
NO_NAMESPACE
The reserved “no namespace” StreamRequest::namespace_id value (all-zero big-endian uint256): content published without a namespace, served best-effort from cache / DHT with no authorized origins (ADR 002 §Namespace 0).
VOUCHER_SIG_LEN
Exact byte length of an EOA secp256k1 voucher signature (r‖s‖v, 32+32+1). Mirrors SLASH_SIG_LEN; both are the EOA off-chain signing form (ADR 024 §Off-Chain Signature Verification — EOA Recovery Only). Carried as a Vec<u8> on the wire (serde derives array impls only up to [T; 32]), with the length pinned by Voucher::validate.

Functions§

encode_chunk_frame
Encode one ClientMessage::ChunkData frame body directly from its payload.
encode_chunk_frame_headers
Encode the full frame headers for a ChunkData payload of payload_len bytes: the framing varint postcard_len followed by the ChunkData header (discriminant + varint payload_len). The payload itself is not included — the caller sends it as Bytes alongside this header via a vectored write.
encode_stream_request
Encode a cdn/client/v1 StreamRequest frame payload with an optional trailing StreamRequestExt (ADR 005 §Client identity binding, two-phase).
encode_stream_response
Encode a StreamResponse with its optional trailing StreamResponseExt (ADR 013 §Tier 1, two-phase). See encode_stream_request for why the two values are encoded separately.
parse_stream_request_ext
Parse the trailing StreamRequestExt bytes returned as the remainder by crate::decode_message after a ClientMessage::StreamRequest.
parse_stream_response_ext
Parse the trailing StreamResponseExt bytes returned as the remainder by crate::decode_message after a ClientMessage::StreamResponse.