#[non_exhaustive]pub struct RangeFrame {Show 13 fields
pub offset: u64,
pub length: u64,
pub bytes: String,
pub complete: bool,
pub total_length: Option<u64>,
pub chunk_lens: Option<Vec<u64>>,
pub chunk_index: Option<u64>,
pub inclusion_proof: Option<String>,
pub root: Option<HexId>,
pub range_proof: Option<Vec<String>>,
pub first_chunk_index: Option<u64>,
pub chunk_count: Option<u64>,
pub chunk_lens_offset: Option<u64>,
}Expand description
One range frame of a resource: a byte window, plus the per-resource verification metadata that makes the window independently checkable.
The metadata splits in two by whether it scales with the resource, and the split decides which frames carry it:
- The identity set —
root,total_length,chunk_count, pluschunk_indexwhen the window begins on a chunk boundary — rides EVERY frame. It is fixed-size, so carrying it everywhere costs a bounded number of bytes, and it is what lets a client fetching in parallel from many holders reject a wrong-generation or wrong-layout source the moment a frame arrives, rather than after paying for the whole resource in bandwidth. - The resource-scaling set —
chunk_lensandinclusion_proof— rides the first frame, or a paged prologue, once per range stream. Repeating it per frame would cost proportionally to the resource against a frame budget with no slack; a layout too large to state on one frame is paged instead, each page stamped with thechunk_lens_offsetit begins at.
The window is exactly the span the caller requested — never widened.
§Construction
This type is #[non_exhaustive]:
build it with data and the with_* setters rather than a struct
literal. That is deliberate — the wire form grows as the protocol does, and
routing construction through named setters means a future additive field is a
PATCH release for every consumer instead of another semver cascade. It also
makes the two frame shapes different call chains rather than one call with a
pile of Nones, so a continuation frame cannot accidentally claim a layout it
is not stating.
§Cross-repo contract
The wire form is byte-identical to dig_nat::mux::RangeFrame, the
streaming implementation of this frame (SYSTEM.md → “Canonical DIG-node RPC
interface”). Field names, encodings, and the population rule above are pinned
against dig-nat’s actual output in tests/nat_wire_mirror.rs; a change to any
of them lands in both crates in the same unit of work or not at all.
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.offset: u64The window start offset (echoed).
length: u64This window’s byte length.
bytes: StringThis window’s ciphertext, base64.
complete: boolWhether this frame ends the resource.
total_length: Option<u64>The full resource ciphertext length. Part of the fixed-size identity set, so it rides EVERY frame.
chunk_lens: Option<Vec<u64>>Per-chunk ciphertext lengths of the full resource, in order — the layout a
reader needs before it can decrypt (per-chunk AEAD needs the WHOLE array,
and a reader rejects an array whose sum differs from
total_length).
Resource-scaling, so it rides the first frame or a paged prologue, once
per range stream — never repeated on continuation frames. When paged, this
is one page of the array and
chunk_lens_offset states the entry it begins
at.
chunk_index: Option<u64>This frame’s first chunk index — the pre-existing alias of
first_chunk_index, carrying the same value, and
the name dig-nat emits.
Part of the identity set: it rides every frame whose window begins on a
chunk boundary, and is OMITTED (rather than guessed) on a mid-chunk window.
Being fixed-size, it is settable on its own — see
with_chunk_index — precisely so a continuation
frame can state it without dragging along the once-per-stream
inclusion_proof.
inclusion_proof: Option<String>Whole-resource merkle proof against root, base64, relayed
verbatim.
Resource-scaling, so it rides the first frame or the paged prologue, once per range stream. A holder MUST NOT repeat it per frame: it is bounded at 4,096 base64 bytes, which against the frame budget leaves no slack for the payload the frame exists to carry.
root: Option<HexId>The chain-anchored root (64-hex) this frame’s resource verified against. Part of the fixed-size identity set, so it rides EVERY frame.
NOT A TRUST ANCHOR BY ITSELF. The client resolves the resource’s root from the URN (chain-anchored) and PINS it before fetching; a peer-declared value never replaces that pinned root. What this field provides is a generation-CONSISTENCY check: a frame declaring a root other than the pinned one is REJECTED and attributed to the offending peer (NC-9 fail-closed). So a declared root can only ever cause rejection — it can never move the pinned root, and never makes an unverified frame acceptable.
range_proof: Option<Vec<String>>RESERVED — not currently derivable; a server MUST NOT emit it.
Per-chunk merkle inclusion proofs for the chunks a frame covers. No such
proof exists in the current store format: the generation root’s merkle
leaves are per-RESOURCE (a leaf is the SHA-256 of a resource’s WHOLE
ciphertext), so a single chunk has no leaf to prove. A client MUST NOT
require this field, and per-range verification instead uses the
whole-resource inclusion_proof together with the
per-frame root/chunk_lens metadata.
Making it derivable requires a per-resource chunk-level commitment in the
store format first (tracked as dig_ecosystem#1601). The field is kept in
the wire type, unused, so populating it later is additive (§5.1); each entry
would be an opaque base64 proof blob, since this pure level-00 wire type
MUST NOT depend on the merkle primitive.
first_chunk_index: Option<u64>The chunk index of the first chunk in this frame (0-based, into the
resource’s chunk sequence described by chunk_lens).
Present only when the frame’s window begins EXACTLY on a chunk boundary; a mid-chunk window omits it rather than assert an index the caller’s own alignment check would contradict. The served window is exactly the requested span — a server MUST NOT widen a range to a chunk boundary — so a frame is chunk-aligned only when the caller asked for an aligned span.
chunk_count: Option<u64>The resource’s TOTAL chunk count — how many entries the fully reassembled
chunk_lens array has.
Fixed-size, so it belongs to the identity set and rides EVERY frame.
Together with root and
total_length it is what lets a reader detect a
wrong-generation or wrong-layout holder on the first frame it receives. It is
also how a reader sizes the array it is paging in, and therefore how it knows
a paged prologue is complete: the prologue ends when the reader holds
chunk_count entries, which no single page can tell it.
chunk_lens_offset: Option<u64>The index into the resource’s chunk_lens array at which
THIS frame’s page begins — how a paged prologue is located and
reassembled.
A resource whose layout exceeds the per-frame entry cap cannot state it on
one frame, so the sender pages it: successive frames each carry up to that
many entries, stamped with the offset they start at. A reader places each page
at its offset and holds the whole array once it has
chunk_count entries.
Absent means “this frame’s chunk_lens, if any, begins at entry 0” — the
single-frame layout, which is the shape every pre-0.6.0 producer emits. So an
older frame decodes with exactly its original meaning (§5.1).
Implementations§
Source§impl RangeFrame
impl RangeFrame
Sourcepub fn data(offset: u64, length: u64, bytes: impl Into<String>) -> Self
pub fn data(offset: u64, length: u64, bytes: impl Into<String>) -> Self
A data frame: length bytes of base64 ciphertext at offset, carrying
no metadata — the bare shape every continuation frame starts from.
length is stated rather than derived because bytes is
already base64 on this type, and recovering the raw window length from it
would need a base64 codec this pure level-00 wire crate deliberately does not
depend on. A serve path passes the length it served.
Sourcepub fn with_complete(self, complete: bool) -> Self
pub fn with_complete(self, complete: bool) -> Self
Mark this as the final frame of the range.
Sourcepub fn with_identity(
self,
root: impl Into<HexId>,
total_length: u64,
chunk_count: u64,
) -> Self
pub fn with_identity( self, root: impl Into<HexId>, total_length: u64, chunk_count: u64, ) -> Self
The fixed-size identity set every frame of a range carries: the
generation root (64-hex) the range is served from, the resource’s
ciphertext total_length, and its chunk_count.
These three are what let a reader reject a wrong-generation or wrong-layout holder the moment a frame arrives — which the resource-scaling metadata never could, since it arrives once. Call this on every frame.
Sourcepub fn with_chunk_index(self, chunk_index: u64) -> Self
pub fn with_chunk_index(self, chunk_index: u64) -> Self
State chunk_index — the chunk this frame’s window
begins on — for a chunk-aligned window.
Separate from with_inclusion_proof on purpose:
the index is fixed-size identity metadata that rides every aligned frame,
while the proof is once-per-stream, so binding them together would force a
producer to either repeat a proof it MUST NOT repeat or bypass this API. Omit
the call entirely for a mid-chunk window.
Sourcepub fn with_first_chunk_index(self, first_chunk_index: u64) -> Self
pub fn with_first_chunk_index(self, first_chunk_index: u64) -> Self
Additionally state first_chunk_index, this
crate’s v0.4.0 alias of chunk_index.
Both names carry the same value. dig-nat emits only chunk_index, so
with_chunk_index alone is the interoperable
choice; a producer serving readers that expect the newer name states both.
Sourcepub fn with_chunk_lens_page(
self,
chunk_lens_offset: u64,
chunk_lens: Vec<u64>,
) -> Self
pub fn with_chunk_lens_page( self, chunk_lens_offset: u64, chunk_lens: Vec<u64>, ) -> Self
One page of the resource’s chunk_lens array, beginning at entry
chunk_lens_offset.
Call it once with offset 0 for a layout that fits a single frame, or once
per page of a paged prologue. A page is only ever useful as part of a
complete set: chunk_lens is a decrypt input, and a reader needs all
chunk_count entries before it can decrypt anything.
Sourcepub fn with_inclusion_proof(self, inclusion_proof: impl Into<String>) -> Self
pub fn with_inclusion_proof(self, inclusion_proof: impl Into<String>) -> Self
The whole-resource merkle inclusion proof against
root (base64, relayed verbatim).
Resource-scaling: state it on the first frame or the prologue, once per range stream, never per frame.
Sourcepub fn with_range_proof(self, range_proof: Vec<String>) -> Self
pub fn with_range_proof(self, range_proof: Vec<String>) -> Self
State the RESERVED range_proof field.
A server MUST NOT emit it — no per-chunk proof is derivable from the current
store format (see the field’s own documentation). The setter exists so the
shape stays constructible for the conformance vectors that pin it, and so no
field of this #[non_exhaustive] type is unreachable; it is not a serve-path
call.
Trait Implementations§
Source§impl Clone for RangeFrame
impl Clone for RangeFrame
Source§fn clone(&self) -> RangeFrame
fn clone(&self) -> RangeFrame
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more