dig-peer-protocol
DIG Network L2 protocol types — superset of chia-protocol with extension opcodes 200–222 — plus DigLink, the websocket peer link that can actually carry them.
One dependency replaces five: chia-protocol, chia-sdk-client, chia-ssl, chia-traits, chia_streamable_macro — all re-exported verbatim.
Install
[]
= { = "0.3", = ["rustls"] }
Features
| Flag | Forwards to | Adds re-exports |
|---|---|---|
native-tls |
chia-sdk-client/native-tls |
Client, ClientState, Connector, create_native_tls_connector |
rustls |
chia-sdk-client/rustls |
Client, ClientState, Connector, create_rustls_connector |
Neither default. Without a TLS feature: DIG types and Peer still compile; Client does not.
Why this crate exists
chia_protocol::Message stores msg_type as ProtocolMessageTypes — a closed #[repr(u8)] enum covering opcodes 0–107. Message::from_bytes rejects any unknown opcode. DIG extension opcodes (200+) cannot decode through stock Message.
DigMessage has identical wire layout but stores msg_type as raw u8. Encodes/decodes any opcode (Chia or DIG) without touching upstream types. Conversions to/from Message are lossless for opcodes the Chia enum recognizes. The byte-identity is asserted exhaustively — over every opcode chia-protocol accepts — in tests/wire_compatibility.rs.
The same closed enum breaks the transport, not just the type: chia_sdk_client::Peer decodes inbound frames with Message::from_bytes, so one DIG frame ends its receive loop and drops the connection. DigLink is the replacement — a websocket link written against the wire format that frames DigMessage.
use ;
let = connect.await?;
link.send_dig.await?;
while let Some = inbound.recv.await
DIG previously carried vendored forks of chia-protocol and chia-sdk-client to get this. DigLink replaces them, so chia-protocol is an ordinary dependency again with no [patch.crates-io].
Wire format
DigMessage binary layout (same as chia_protocol::Message):
[u8 msg_type] [u8 has_id (0|1)] [u16 id (big-endian, if has_id==1)] [u32 data_len (BE)] [u8; data_len payload]
msg_type< 200 → Chia standard opcodemsg_type≥ 200 → DIG extension opcode (seeDigMessageType)
Opcode assignments
DIG band: 200..=219. Chia band: 0..=107 (+ reserves). Gap 108..=199 reserved for future Chia.
| Opcode | Variant | Payload | Gossip strategy |
|---|---|---|---|
| 200 | NewAttestation |
— | Plumtree eager push |
| 201 | NewCheckpointProposal |
— | Plumtree eager push |
| 202 | NewCheckpointSignature |
— | Plumtree eager push |
| 203 | RequestCheckpointSignatures |
— | Unicast request |
| 204 | RespondCheckpointSignatures |
— | Unicast response |
| 205 | RequestStatus |
— | Unicast request |
| 206 | RespondStatus |
— | Unicast response |
| 207 | NewCheckpointSubmission |
— | Plumtree eager push |
| 208 | ValidatorAnnounce |
— | Broadcast flood |
| 209 | RequestBlockTransactions |
— | Unicast request |
| 210 | RespondBlockTransactions |
— | Unicast response |
| 211 | ReconciliationSketch |
— | ERLAY reconciliation |
| 212 | ReconciliationResponse |
— | ERLAY reconciliation |
| 213 | StemTransaction |
— | Dandelion++ stem |
| 214 | PlumtreeLazyAnnounce |
— | Plumtree lazy |
| 215 | PlumtreePrune |
— | Plumtree control |
| 216 | PlumtreeGraft |
— | Plumtree control |
| 217 | PlumtreeRequestByHash |
— | Plumtree pull |
| 218 | RegisterPeer |
RegisterPeer struct |
Unicast → introducer |
| 219 | RegisterAck |
RegisterAck struct |
Unicast ← introducer |
Payload types for 200–217 are TBD (defined by consumer crates); the protocol crate only defines discriminants + framing.
Public interface — DIG types
DigMessage — raw-opcode wire message
Inputs/outputs
| Method | Input | Output | Failure mode |
|---|---|---|---|
new |
u8, Option<u16>, Bytes |
DigMessage |
infallible |
to_bytes |
&self |
Vec<u8> |
infallible |
from_bytes |
&[u8] |
Option<DigMessage> |
None if truncated or data_len > MAX_MESSAGE_SIZE |
from_bytes_owned |
Vec<u8> |
Option<DigMessage> |
same as from_bytes; moves payload, no copy |
from_bytes/from_bytes_owned reject any data_len prefix above MAX_MESSAGE_SIZE
(16 MiB) before slicing/allocating the payload. This bounds only the allocation these
functions perform — callers MUST still enforce their own per-frame size cap at the
transport layer before buffering an incoming frame.
DigMessageType — typed discriminants (200–219)
// Serde: serializes/deserializes as raw u8 (not variant name)
// "RegisterPeer(218)"
; // Error; Display + std::error::Error
Inputs/outputs
| Conversion | Input | Output |
|---|---|---|
as u8 |
variant | u8 in 200..=219 |
DigMessageType::try_from(u8) |
u8 |
Result<Self, UnknownDigMessageType> |
serde_json::to_string(&variant) |
variant | "218" (stringified u8) |
serde_json::from_str::<DigMessageType> |
"218" |
Ok(RegisterPeer) / Err if not 200–219 |
RegisterPeer — introducer registration request (opcode 218)
RegisterAck — introducer registration response (opcode 219)
RequestPeersIntroducer / RespondPeersIntroducer — Chia-standard (opcodes 63/64)
These use #[streamable(message)] because opcodes 63/64 exist in stock ProtocolMessageTypes. Compatible with Peer::request_infallible directly (no DigMessage wrapper needed).
Re-exports from Chia crates
From chia_protocol::* (full glob)
~100 wire types. Key items:
| Category | Types |
|---|---|
| Framing | DIG-owned DigMessage, Bytes, NodeType; ProtocolMessageTypes + ChiaProtocolMessage + TimestampedPeerInfo re-exported by name for chia paths |
| Block | FullBlock, HeaderBlock, BlockRecord, Foliage, FoliageBlockData |
| Peer discovery | RequestPeers, RespondPeers, TimestampedPeerInfo |
| Mempool/tx | NewTransaction, RequestTransaction, RespondTransaction, MempoolItemsAdded |
| State/coins | Coin, CoinState, CoinSpend, RequestCoinState, CoinStateUpdate |
| Consensus/PoS | ProofOfSpace, NewSignagePointOrEndOfSubSlot, ChallengeChainSubSlot |
| Wallet protocol | NewPeakWallet, RegisterForCoinUpdates, RegisterForPhUpdates, SendTransaction |
| Fees | FeeEstimate, FeeEstimateGroup, FeeRate, RequestFeeEstimates |
See chia-protocol docs for the full list.
From chia_sdk_client
// Always available
pub use ;
// Requires feature = "native-tls" or "rustls"
pub use ;
pub use create_native_tls_connector;
pub use create_rustls_connector;
From chia_ssl
pub use ChiaCertificate; // { cert_pem: String, key_pem: String }
From chia_traits
pub use Streamable; // trait — binary codec (to_bytes / from_bytes / hash)
From chia_streamable_macro
pub use streamable; // #[streamable] / #[streamable(message)] proc macro
Encode / decode example
use ;
// --- Encode outbound RegisterPeer ---
let rp = new;
let wire: DigMessage = rp.to_dig_message.unwrap;
assert_eq!; // 218
let bytes: = wire.to_bytes; // send over socket
// --- Decode inbound frame ---
let msg: DigMessage = from_bytes.expect;
match try_from
Error types
| Error | Source | Cause |
|---|---|---|
UnknownDigMessageType(u8) |
DigMessageType::try_from |
Wire value not in 200..=219 |
chia_traits::Error |
Streamable::to_bytes/from_bytes |
Malformed payload |
ClientError |
chia_sdk_client |
TLS, handshake, IO, protocol violations |
DigMessage::from_bytes/from_bytes_owned return Option<DigMessage> (no error type)
— None means truncated/malformed frame OR a data_len prefix above
DigMessage::MAX_MESSAGE_SIZE (16 MiB).
Invariants
DigMessage::to_bytesoutput is binary-identical toMessage::to_bytesfor opcodes present inProtocolMessageTypes.from_bytes(to_bytes(m)) == Some(m)for all validDigMessage.DigMessageType as u8∈200..=219for all variants;TryFrom<u8>is the inverse.- Payload types 200–217 are defined by downstream crates; this crate only defines discriminants + framing.
License
Apache-2.0