# SER-003: Wire-Format Interop

## Summary

The blockstore provides conversion functions between L2 blocks and the Chia wire format used for peer-to-peer gossip. `block_to_wire_bytes` serializes a block using `chia-traits::Streamable`, producing bytes compatible with the Chia network protocol. `block_from_wire_bytes` deserializes wire-format bytes back into an `L2Block`. The wire format intentionally differs from the storage format (Streamable vs bincode) to maintain network compatibility while allowing internal storage optimization.

## Specification

```rust
use chia_traits::Streamable;

/// Convert an L2Block to wire-format bytes for peer gossip.
/// Uses chia-traits Streamable encoding, which differs from the
/// bincode storage format.
pub fn block_to_wire_bytes(block: &L2Block) -> Result<Vec<u8>> {
    let mut buf = Vec::new();
    block.stream(&mut buf)
        .map_err(|e| BlockStoreError::Serialization(
            format!("wire serialization failed: {e}")
        ))?;
    Ok(buf)
}

/// Parse an L2Block from wire-format bytes received from peers.
/// Uses chia-traits Streamable decoding.
pub fn block_from_wire_bytes(bytes: &[u8]) -> Result<L2Block> {
    let mut cursor = std::io::Cursor::new(bytes);
    L2Block::parse(&mut cursor)
        .map_err(|e| BlockStoreError::Serialization(
            format!("wire deserialization failed: {e}")
        ))
}
```

## Acceptance Criteria

1. `block_to_wire_bytes` produces bytes conforming to the `chia-traits::Streamable` encoding.
2. `block_from_wire_bytes(block_to_wire_bytes(block))` returns an `L2Block` equal to the original.
3. Wire-format bytes MUST differ from bincode-serialized bytes for the same block (different encoding schemes).
4. Wire-format bytes MUST be compatible with other Chia network nodes expecting Streamable encoding.
5. Invalid wire bytes MUST produce `BlockStoreError::Serialization`.
6. The functions MUST NOT apply any compression (compression is a transport-layer concern, not a serialization concern).

## Implementation Notes

- `chia-traits::Streamable` uses a big-endian, length-prefixed encoding that differs fundamentally from bincode's little-endian, struct-layout-driven encoding.
- These functions are used for gossip message serialization/deserialization, not for storage. Storage always uses the bincode + zstd pipeline (SER-001).
- The wire format is defined externally by the Chia protocol; any changes must maintain backward compatibility with the network.
- No compression is applied at this layer; if gossip messages need compression, it is handled at the transport layer.

## Test Plan

- **Unit: round-trip** -- Convert a block to wire bytes and back, verify equality.
- **Unit: format divergence** -- Serialize the same block with both `block_to_wire_bytes` and `bincode::serialize`, verify the outputs are different.
- **Unit: Streamable compatibility** -- Verify wire bytes can be parsed by `chia-traits::Streamable::parse` directly (not just by `block_from_wire_bytes`).
- **Unit: invalid input** -- Pass random/truncated bytes to `block_from_wire_bytes`, verify `BlockStoreError::Serialization`.
- **Unit: no compression** -- Verify wire bytes have no zstd framing (not compressed).
- **Property: deterministic** -- Serializing the same block twice produces identical wire bytes.

## Expected Test Files

- `tests/ser_003_tests.rs`
