# SNP-003: SnapshotManifest Struct

## Summary

`SnapshotManifest` is the metadata header for snapshot files. It contains the schema version, block range, block count, start/end hashes, total size, compression flag, and a SHA-256 checksum of the snapshot data. The struct derives `Serialize` and `Deserialize` for bincode encoding and is written as the first bytes of every snapshot file.

## Specification

```rust
use serde::{Serialize, Deserialize};

/// Metadata header for snapshot files.
/// Written as the first bytes of the snapshot stream (bincode-encoded).
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SnapshotManifest {
    /// Schema version for forward compatibility.
    /// Current version is 1.
    pub version: u32,

    /// First block height included in the snapshot.
    pub start_height: u64,

    /// Last block height included in the snapshot (inclusive).
    pub end_height: u64,

    /// Total number of blocks in the snapshot.
    /// Must equal end_height - start_height + 1.
    pub block_count: u64,

    /// State root hash at end_height.
    /// Allows importers to verify state consistency after ingestion.
    pub state_root: Bytes32,

    /// SHA-256 checksum of all block data in the snapshot.
    /// Computed over all bytes after the manifest and before the
    /// trailing checksum in the snapshot stream.
    pub checksum: Bytes32,
}
```

## Acceptance Criteria

1. `SnapshotManifest` MUST contain all six fields: `version`, `start_height`, `end_height`, `block_count`, `state_root`, `checksum`.
2. `version` MUST be `u32`.
3. `start_height` and `end_height` MUST be `u64`.
4. `block_count` MUST be `u64`.
5. `state_root` MUST be `Bytes32`.
6. `checksum` MUST be `Bytes32`.
7. The struct MUST derive `Serialize` and `Deserialize` (serde).
8. `bincode::deserialize(bincode::serialize(manifest))` MUST produce an equal `SnapshotManifest`.
9. `block_count` MUST equal `end_height - start_height + 1` for valid snapshots.

## Implementation Notes

- The `version` field enables future schema evolution. Importers should reject unknown versions rather than attempting best-effort parsing.
- `Bytes32` is the same 32-byte fixed-size hash type used throughout the codebase (from `dig-block`).
- The `checksum` field in the manifest is a convenience for callers; the authoritative checksum is the trailing 32 bytes of the snapshot stream. During export, the manifest is written with a placeholder checksum before the actual checksum is known.
- Deriving `PartialEq` and `Eq` enables straightforward comparison in tests.
- Consider also deriving `Clone` and `Debug` for ergonomic usage.

## Test Plan

- **Unit: bincode round-trip** -- Construct a `SnapshotManifest` with known values, serialize with bincode, deserialize, verify equality.
- **Unit: all fields preserved** -- Set each field to a distinct non-default value, round-trip, verify each field individually.
- **Unit: default/zero values** -- Construct with all-zero fields, round-trip, verify all fields are zero.
- **Unit: block_count consistency** -- Verify `block_count == end_height - start_height + 1` for test manifests.
- **Unit: Serialize/Deserialize traits** -- Verify the struct implements both traits (compile-time check via trait bound function).
- **Unit: serialized size** -- Serialize a manifest, verify the size is reasonable (4 + 8 + 8 + 8 + 32 + 32 = 92 bytes plus bincode overhead).

## Expected Test Files

- `tests/snp_003_tests.rs`
