DIG Network L2 protocol types — superset of chia-protocol with extension opcodes 200–219.
One dependency replaces five: chia-protocol, chia-sdk-client, chia-ssl, chia-traits, chia_streamable_macro — all re-exported verbatim.
[dependencies]
dig-protocol = { version = "0.1", features = ["rustls"] }| 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.
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.
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)
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.
pub struct DigMessage {
pub msg_type: u8, // 0..=255, any opcode
pub id: Option<u16>, // correlation id for req/resp
pub data: Bytes, // serialized payload
}
impl DigMessage {
pub fn new(msg_type: u8, id: Option<u16>, data: Bytes) -> Self;
// Wire codec (same layout as chia_protocol::Message)
pub fn to_bytes(&self) -> Vec<u8>;
pub fn from_bytes(bytes: &[u8]) -> Option<Self>; // None on short/malformed buffer
// Interop with stock Chia Message
pub fn from_chia_message(msg: &Message) -> Self; // lossless
pub fn try_into_chia_message(&self) -> Option<Message>; // None if opcode ∉ ProtocolMessageTypes
// Opcode-range predicates
pub fn is_dig_extension(&self) -> bool; // msg_type >= 200
pub fn is_chia_standard(&self) -> bool; // msg_type < 200
}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 |
from_chia_message |
&Message |
DigMessage |
infallible |
try_into_chia_message |
&self |
Option<Message> |
None if opcode not in Chia enum |
#[repr(u8)]
pub enum DigMessageType {
NewAttestation = 200,
NewCheckpointProposal = 201,
NewCheckpointSignature = 202,
RequestCheckpointSignatures = 203,
RespondCheckpointSignatures = 204,
RequestStatus = 205,
RespondStatus = 206,
NewCheckpointSubmission = 207,
ValidatorAnnounce = 208,
RequestBlockTransactions = 209,
RespondBlockTransactions = 210,
ReconciliationSketch = 211,
ReconciliationResponse = 212,
StemTransaction = 213,
PlumtreeLazyAnnounce = 214,
PlumtreePrune = 215,
PlumtreeGraft = 216,
PlumtreeRequestByHash = 217,
RegisterPeer = 218,
RegisterAck = 219,
}
impl DigMessageType {
pub const MAX_ASSIGNED: u8 = 219;
pub const ALL: [Self; 20]; // declaration order
// TryFrom<u8> — Err(UnknownDigMessageType) when value ∉ 200..=219
}
// Serde: serializes/deserializes as raw u8 (not variant name)
impl Serialize for DigMessageType { ... }
impl<'de> Deserialize<'de> for DigMessageType { ... }
impl Display for DigMessageType { ... } // "RegisterPeer(218)"
pub struct UnknownDigMessageType(pub u8); // Error; Display + std::error::ErrorInputs/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 |
#[streamable]
pub struct RegisterPeer {
pub ip: String, // externally reachable IP or hostname
pub port: u16, // P2P listening port
pub node_type: NodeType, // e.g. NodeType::FullNode
}
impl RegisterPeer {
pub fn new(ip: String, port: u16, node_type: NodeType) -> Self;
// Streamable trait — binary codec for payload body (not full wire message)
fn to_bytes(&self) -> Result<Vec<u8>, chia_traits::Error>;
fn from_bytes(bytes: &[u8]) -> Result<Self, chia_traits::Error>;
// DigMessage wrappers (prepend opcode 218 + framing)
pub fn to_dig_message(&self, id: Option<u16>) -> Result<DigMessage, chia_traits::Error>;
pub fn from_dig_message(msg: &DigMessage) -> Option<Result<Self, chia_traits::Error>>;
// from_dig_message returns None when msg.msg_type != 218
}#[streamable]
pub struct RegisterAck {
pub success: bool, // false == policy rejection (valid wire outcome)
}
impl RegisterAck {
pub fn new(success: bool) -> Self;
// Streamable: to_bytes / from_bytes
pub fn to_dig_message(&self, id: Option<u16>) -> Result<DigMessage, chia_traits::Error>;
pub fn from_dig_message(msg: &DigMessage) -> Option<Result<Self, chia_traits::Error>>;
// from_dig_message returns None when msg.msg_type != 219
}#[streamable(message)]
pub struct RequestPeersIntroducer {}
#[streamable(message)]
pub struct RespondPeersIntroducer {
pub peer_list: Vec<TimestampedPeerInfo>,
}These use #[streamable(message)] because opcodes 63/64 exist in stock ProtocolMessageTypes. Compatible with Peer::request_infallible directly (no DigMessage wrapper needed).
~100 wire types. Key items:
| Category | Types |
|---|---|
| Framing | Message, Handshake, ProtocolMessageTypes, NodeType, Bytes, BytesImpl |
| 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.
// Always available
pub use chia_sdk_client::{
ClientError, // enum — TLS, handshake, io errors
Network, // mainnet/testnet selection
Peer, // single-peer connection handle (send/request/receive)
PeerOptions, // builder config
RateLimit, // per-opcode rate limit entry
RateLimiter,
RateLimits,
V2_RATE_LIMITS, // static — V2 protocol defaults
load_ssl_cert, // load ChiaCertificate from disk
};
// Requires feature = "native-tls" or "rustls"
pub use chia_sdk_client::{Client, ClientState, Connector};
#[cfg(feature = "native-tls")]
pub use chia_sdk_client::create_native_tls_connector;
#[cfg(feature = "rustls")]
pub use chia_sdk_client::create_rustls_connector;pub use chia_ssl::ChiaCertificate; // { cert_pem: String, key_pem: String }pub use chia_traits::Streamable; // trait — binary codec (to_bytes / from_bytes / hash)pub use chia_streamable_macro::streamable; // #[streamable] / #[streamable(message)] proc macrouse dig_protocol::{DigMessage, DigMessageType, NodeType, RegisterPeer, RegisterAck};
// --- Encode outbound RegisterPeer ---
let rp = RegisterPeer::new("1.2.3.4".into(), 9444, NodeType::FullNode);
let wire: DigMessage = rp.to_dig_message(Some(1)).unwrap();
assert_eq!(wire.msg_type, DigMessageType::RegisterPeer as u8); // 218
let bytes: Vec<u8> = wire.to_bytes(); // send over socket
// --- Decode inbound frame ---
let msg: DigMessage = DigMessage::from_bytes(&bytes).expect("valid frame");
match DigMessageType::try_from(msg.msg_type) {
Ok(DigMessageType::RegisterPeer) => {
let decoded = RegisterPeer::from_dig_message(&msg).unwrap().unwrap();
println!("peer {}:{}", decoded.ip, decoded.port);
}
Ok(DigMessageType::RegisterAck) => {
let ack = RegisterAck::from_dig_message(&msg).unwrap().unwrap();
println!("ack success={}", ack.success);
}
Ok(other) => { /* dispatch other DIG opcode */ }
Err(_) => {
// Not a DIG opcode — try as Chia Message
if let Some(chia_msg) = msg.try_into_chia_message() {
// dispatch Chia handler
}
}
}| 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 returns Option<DigMessage> (no error type) — None means truncated/malformed frame.
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.
Apache-2.0