1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//! The deCDN wire protocol: the ALPN identifiers, the message types each ALPN
//! carries, and the framing that puts them on a QUIC stream.
//!
//! deCDN speaks three ALPNs ([ADR 005]):
//!
//! | ALPN | Constant | Messages | Purpose |
//! |---|---|---|---|
//! | `cdn/probe/v1` | [`ALPN_PROBE`] | [`ProbeMessage`] | Latency and availability probing |
//! | `cdn/client/v1` | [`ALPN_CLIENT`] | [`ClientMessage`] | All paid delivery, client to node and node to node |
//! | `cdn/dht/v1` | [`ALPN_DHT`] | [`DhtMessage`] | Content discovery over a Kademlia DHT ([ADR 022]) |
//!
//! # Modules
//!
//! | Module | Contents |
//! |---|---|
//! | [`framing`] | The length-prefixed frame, [`encode_message`] / [`decode_message`], and the async [`read_frame`] / [`write_frame`] |
//! | [`message`] | `cdn/probe/v1`: [`ProbeRequest`], [`ProbeResponse`] |
//! | [`client`] | `cdn/client/v1`: [`StreamRequest`], [`StreamResponse`], [`ChunkData`], the wire [`Voucher`], [`StreamError`] |
//! | [`dht`] | `cdn/dht/v1`: store and find requests, provider records, closer-node lists |
//! | [`coverage`] | The block coverage bitmap a partial holder advertises |
//! | [`identity`] | The 32-byte [`NodeId`] and [`ContentHash`] newtypes |
//! | [`region`] | ISO 3166-1 alpha-2 [`Region`] codes |
//!
//! # Frames and extensions
//!
//! Every message is a postcard encoding behind a varint length prefix, capped at
//! [`MAX_MESSAGE_SIZE`] ([ADR 013 § Wire Framing]). A signed message has a frozen
//! base: the fields its signature covers. Unsigned fields travel as trailing
//! bytes after the base. [`decode_message`] returns them as a remainder, and the
//! `parse_*_ext` functions read them ([ADR 013 § Three Tiers of Evolution]).
//!
//! ```
//! use decdn_protocol::{ProbeMessage, ProbeRequest, decode_message, encode_message};
//!
//! let request = ProbeMessage::Request(ProbeRequest {
//! hash: [7; 32],
//! timestamp_us: 1_700_000_000_000_000,
//! });
//! let frame = encode_message(&request)?;
//! let (decoded, remainder) = decode_message::<ProbeMessage>(&frame)?;
//! assert_eq!(decoded, request);
//! assert!(remainder.is_empty());
//! # Ok::<(), decdn_protocol::FrameError>(())
//! ```
//!
//! This crate holds no cryptography. The signatures carried in these messages
//! are made and checked by [`decdn-incentive`]. It has few dependencies, so
//! code that only speaks the protocol links no blob store, Ethereum client, or
//! cloud SDK.
//!
//! [ADR 005]: https://github.com/decdn/decdn/blob/main/adr/005-protocol.md
//! [ADR 022]: https://github.com/decdn/decdn/blob/main/adr/022-content-discovery.md
//! [ADR 013 § Wire Framing]: https://github.com/decdn/decdn/blob/main/adr/013-schema-evolution.md#wire-framing
//! [ADR 013 § Three Tiers of Evolution]: https://github.com/decdn/decdn/blob/main/adr/013-schema-evolution.md#three-tiers-of-evolution
//! [`decdn-incentive`]: https://docs.rs/decdn-incentive
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
/// ALPN protocol identifier for latency and availability probing.
pub const ALPN_PROBE: & = b"cdn/probe/v1";
/// ALPN protocol identifier for paid blob delivery (client-to-node and node-to-node).
pub const ALPN_CLIENT: & = b"cdn/client/v1";
/// ALPN protocol identifier for Kademlia-based content discovery (ADR 022).
pub const ALPN_DHT: & = b"cdn/dht/v1";
/// Connection rejected by the per-source or global rate limiter (ADR 013 §0x10).
///
/// Unlike `0x01`–`0x03`, this code is delivered via `CONNECTION_CLOSE` rather
/// than `RESET_STREAM` because the rejection happens before any application
/// stream is opened. The close-frame reason bytes carry a short layer label
/// (e.g. `global-full`, `per-source`) so the peer can pick an appropriate
/// backoff. Peers that receive this code SHOULD back off before
/// reconnecting; they MUST NOT treat it as a protocol error (the server is
/// functioning normally — the client is overloading it). The requester side
/// (`decdn-client`) types this code as `UpstreamRateLimited` so the pull
/// orchestrator suppresses the peer briefly instead of scoring it unreachable.
pub const APP_ERR_RATE_LIMITED: u32 = 0x10;