# dig-block
[](https://github.com/DIG-Network/dig-block)
[](LICENSE)
**`dig-block`** is the DIG Network L2 block format, production, and validation library. It
owns the canonical on-wire shape of every L2 block, the builder pipeline that assembles blocks
from spend bundles, and the three-tier validation pipeline (structural → execution → state)
that rejects any block that does not match consensus rules.
## Scope
This crate is **single-block scoped**: every public function operates on one block (or
one checkpoint) in isolation. External state (coin set, chain tip, wall clock, validator set)
is injected through two traits:
- `CoinLookup` — coin-set queries for Tier 3 state validation.
- `BlockSigner` — proposer signing hook for block production.
`dig-block` never reads from disk, never makes network calls, and never maintains state across
blocks. Downstream crates (`dig-coinstore`, `dig-epoch`, `dig-gossip`) supply the trait
implementations, storage, chain management, and networking.
## Install
```toml
[dependencies]
dig-block = "0.1"
```
Rust edition 2021; minimum supported Rust version **1.75**.
## Public API at a glance
| **Block types** | `L2BlockHeader`, `L2Block`, `AttestedBlock`, `Checkpoint`, `CheckpointSubmission`, `Receipt`, `ReceiptList`, `SignerBitmap`, `BlockStatus`, `CheckpointStatus` |
| **Block production** | `BlockBuilder`, `CheckpointBuilder` |
| **Validation** | `L2Block::validate_structure`, `L2Block::validate_execution`, `L2Block::validate_state`, `L2Block::validate_full` |
| **Validation output** | `ExecutionResult`, `PendingAssertion`, `AssertionKind` |
| **Integration traits** | `CoinLookup`, `BlockSigner` |
| **Hashing** | `hash_leaf`, `hash_node`, `compute_spends_root`, `compute_additions_root`, `compute_removals_root`, `compute_filter_hash`, `compute_receipts_root`, `compute_state_root_from_delta` |
| **Errors** | `BlockError`, `CheckpointError`, `BuilderError`, `SignerBitmapError`, `ReceiptError` |
| **Constants** | `EMPTY_ROOT`, `ZERO_HASH`, `MAX_BLOCK_SIZE`, `MAX_COST_PER_BLOCK`, `MAX_SLASH_PROPOSALS_PER_BLOCK`, `MAX_SLASH_PROPOSAL_PAYLOAD_BYTES`, `DFSP_ACTIVATION_HEIGHT`, `MAX_FUTURE_TIMESTAMP_SECONDS`, `HASH_LEAF_PREFIX`, `HASH_TREE_PREFIX`, `VERSION_V1`, `VERSION_V2`, `MAX_VALIDATORS` |
| **Primitives** | `Bytes32`, `Cost`, `Signature`, `PublicKey` (re-exported from `chia-protocol` / `chia-bls`) |
A convenience glob import is provided:
```rust
use dig_block::prelude::*;
```
## Quickstart — build a block
```rust,no_run
use dig_block::prelude::*;
use dig_block::traits::SignerError;
// 1. Implement BlockSigner for your key backend.
struct MySigner;
impl BlockSigner for MySigner {
fn sign_block(&self, _header_hash: &Bytes32) -> Result<Signature, SignerError> {
Ok(Signature::default())
}
}
// 2. Build an anchored builder.
let parent = Bytes32::default();
let l1_hash = Bytes32::default();
let mut builder = BlockBuilder::new(
/*height=*/ 1, /*epoch=*/ 0, parent,
/*l1_height=*/ 100, l1_hash, /*proposer_index=*/ 0,
);
// 3. (Optional) add spend bundles / slash proposals / set L1 proofs etc.
// builder.add_spend_bundle(bundle, cost, fee)?;
// 4. Finalize and sign.
let state_root = Bytes32::default();
let receipts_root = Bytes32::default();
let block = builder.build(state_root, receipts_root, &MySigner)
.expect("well-formed builder output");
```
The output is **structurally valid by construction**: `block.validate_structure()` always passes
on anything `BlockBuilder::build` produces (BLD-007).
## Quickstart — validate a block
```rust,no_run
use dig_block::prelude::*;
use chia_protocol::CoinState;
use dig_clvm::ValidationConfig;
struct MyCoinLookup;
impl CoinLookup for MyCoinLookup {
fn get_coin_state(&self, _id: &Bytes32) -> Option<CoinState> { None }
fn get_chain_height(&self) -> u64 { 0 }
fn get_chain_timestamp(&self) -> u64 { 0 }
}
fn validate(block: &L2Block, pk: &PublicKey) -> Result<Bytes32, BlockError> {
// Runs Tier 1 → Tier 2 → Tier 3 with short-circuit on failure.
// Returns the computed state root on success.
block.validate_full(
&ValidationConfig::default(),
&Bytes32::default(), // genesis challenge
&MyCoinLookup,
pk,
)
}
```
## Validation pipeline
```text
┌─────────────────────────────────────────────────────────────────────┐
│ L2Block │
│ │ │
│ ▼ │
│ Tier 1: L2Block::validate_structure() │
│ • no external state │
│ • SVL-001..006: version, DFSP roots, cost/size, timestamp, │
│ count agreement, Merkle roots, duplicates │
│ │ │
│ ▼ │
│ Tier 2: L2Block::validate_execution(config, genesis_challenge) │
│ • dig_clvm::validate_spend_bundle per SpendBundle │
│ • EXE-002..007: puzzle hash, CLVM, conditions, BLS, conservation, │
│ cost │
│ • Produces ExecutionResult → PendingAssertion vec │
│ │ │
│ ▼ │
│ Tier 3: L2Block::validate_state(exec, coins, pubkey) │
│ • CoinLookup for persistent coin state │
│ • STV-002..007: coin existence, puzzle-hash cross-check, │
│ addition uniqueness, height/time locks, proposer signature, │
│ state root recompute │
│ │ │
│ ▼ │
│ Ok(computed_state_root) / Err(BlockError) │
└─────────────────────────────────────────────────────────────────────┘
```
Each tier can also be invoked independently, e.g. for light clients that only need structural
verification, or for validators that want to cache `ExecutionResult` for replay.
## Dependencies
`dig-block` reuses the Chia Rust ecosystem and does not reimplement CLVM, BLS, or Merkle primitives:
| Core protocol types (`Bytes32`, `Coin`, `SpendBundle`, `CoinSpend`, `CoinState`) | `chia-protocol` |
| BLS12-381 signatures (`Signature`, `PublicKey`, `verify`) | `chia-bls` |
| CLVM execution + condition parsing | `dig-clvm` (wraps `chia-consensus`) |
| Merkle set roots (additions, removals) | `chia-consensus` |
| Binary Merkle trees (spends, receipts, slash proposals) | `chia-sdk-types` |
| SHA-256 | `chia-sha2` |
| CLVM tree hashing | `clvm-utils` |
| Bincode serialization | `bincode` + `serde` |
| BIP-158 compact block filter | `bitcoin::bip158` |
CLVM execution is **always** routed through `dig_clvm::validate_spend_bundle`; dig-block never
calls `chia-consensus::run_spendbundle` directly. This architectural boundary is enforced by a
grep-based lint in `tests/test_exe_003_clvm_delegation.rs`.
## Testing
74 normative requirements; one dedicated integration test file per requirement. The full suite:
```bash
cargo test --release
```
Runs ~600 tests against the public API (no unit tests reach into private modules). Property-based
coverage via `proptest` in `tests/test_ser_005_roundtrip_integrity.rs`.
## Specification
All behavior is derived from the authoritative crate specification:
[`docs/resources/SPEC.md`](docs/resources/SPEC.md).
Each requirement has a three-document trace:
- `docs/requirements/domains/{domain}/NORMATIVE.md` — authoritative MUST/SHOULD statements
- `docs/requirements/domains/{domain}/specs/{PREFIX-NNN}.md` — detailed spec + test plan
- `docs/requirements/domains/{domain}/VERIFICATION.md` / `TRACKING.yaml` — status + test refs
## License
MIT. See [`LICENSE`](LICENSE).
## Versioning
Semantic versioning. Wire-format changes to the block header bump the minor version pre-1.0 and
the major version post-1.0. Adding new protocol versions (`VERSION_V3`, etc.) follows the same
rule.