Skip to main content

dig_blockstore/
wire.rs

1//! Chia **Streamable** wire helpers for gossip / full-node interop ([`SER-003`](../docs/requirements/domains/serialization/specs/SER-003.md)).
2//!
3//! ## Usage
4//!
5//! - **Encode:** [`block_to_wire_bytes`] → append to P2P frames or log captures.
6//! - **Decode:** [`block_from_wire_bytes`] after stripping transport framing (length prefix, etc.).
7//!
8//! ## Rationale
9//!
10//! - **Differs from storage:** [`crate::store::BlockStore`] persists bodies via bincode + zstd ([`SER-001`](../docs/requirements/domains/serialization/specs/SER-001.md)).
11//!   [`dig_block::L2Block`] also implements [`serde::Serialize`] for bincode; wire bytes use [`chia_traits::Streamable`]
12//!   (length-prefixed lists, big-endian integers) so tooling matches **chia-protocol** / Chia nodes ([`SER-003`] NORMATIVE).
13//! - **No compression:** SER-003 §6 — zstd belongs to transport; this layer is pure structure bytes (see tests for no `ZSTD_MAGIC` prefix).
14//!
15//! ## Upstream types
16//!
17//! - [`dig_block::L2Block`] implements [`Streamable`] in **dig-block** (manual `impl`, field order matches structs) so
18//!   encoding stays on the type-owning crate; this module is a thin [`BlockStoreError`] adapter for dig-blockstore callers.
19
20use chia_traits::Streamable;
21use dig_block::L2Block;
22
23use crate::error::BlockStoreError;
24
25/// Serialize a block for Chia-style wire/gossip ([`SER-003`](../docs/requirements/domains/serialization/specs/SER-003.md)).
26///
27/// **Pipeline:** [`L2Block::stream`] from [`Streamable`] (same as other chia-protocol messages).
28///
29/// **Errors:** [`BlockStoreError::Serialization`] wraps [`chia_traits::chia_error::Error`] from the encoder.
30pub fn block_to_wire_bytes(block: &L2Block) -> Result<Vec<u8>, BlockStoreError> {
31    let mut buf = Vec::new();
32    block
33        .stream(&mut buf)
34        .map_err(|e| BlockStoreError::Serialization(format!("wire serialization failed: {e}")))?;
35    Ok(buf)
36}
37
38/// Deserialize wire bytes from a peer into [`L2Block`] ([`SER-003`](../docs/requirements/domains/serialization/specs/SER-003.md)).
39///
40/// **Pipeline:** [`Streamable::from_bytes`] — rejects trailing garbage.
41///
42/// **Important:** Uses explicit UFCS (`<L2Block as Streamable>::from_bytes`) because
43/// `dig_block::L2Block` has an **inherent** `from_bytes` method that uses a different
44/// deserialization path (BlockError-based). The Streamable trait method is the correct
45/// one for wire-format compatibility with the Chia protocol.
46///
47/// **Errors:** Malformed frames map to [`BlockStoreError::Serialization`] (never [`BlockStoreError::Compression`]).
48pub fn block_from_wire_bytes(bytes: &[u8]) -> Result<L2Block, BlockStoreError> {
49    <L2Block as Streamable>::from_bytes(bytes)
50        .map_err(|e| BlockStoreError::Serialization(format!("wire deserialization failed: {e}")))
51}