# PAR-001: CLVM Execution via clvmr with ChiaDialect

> **Authoritative requirement:** [PAR-001](../NORMATIVE.md#PAR-001)
> **Verification:** [VERIFICATION.md](../VERIFICATION.md)
> **Tracking:** [TRACKING.yaml](../TRACKING.yaml)
> **Spec reference:** [SPEC.md](../../../../resources/SPEC.md) — Section 7

---

## Summary

All CLVM program execution within `dig-clvm` must use the `clvmr` crate with `ChiaDialect`, the same Rust CLVM runtime used by Chia L1 full nodes. On L1, CLVM execution is delegated to the Rust implementation via `chia_rs` at [`multiprocess_validation.py:62`](https://github.com/Chia-Network/chia-blockchain/blob/main/chia/consensus/multiprocess_validation.py#L62), where `_run_block()` calls into `run_block_generator` or `run_block_generator2` -- both of which ultimately invoke `clvmr::run_program()` with `ChiaDialect`. The `dig-clvm` crate must use the exact same execution path.

The crate must not contain a custom CLVM interpreter, bytecode evaluator, or any alternative execution engine. The `ChiaDialect` encodes Chia-specific operator behavior, soft-fork flags, and cost calculations that are not trivially reproducible. A custom interpreter would inevitably diverge from L1 behavior, creating consensus incompatibility. This is the most fundamental parity requirement: identical CLVM execution produces identical conditions, which produces identical state transitions.

The `clvmr` dependency is used both directly (for low-level execution via `run_program()`) and indirectly through `chia-consensus` (which wraps `clvmr` in higher-level functions like `run_spendbundle()`). Both paths use `ChiaDialect`. The `dig-clvm` crate delegates to `chia-consensus` for production validation (see [PAR-002](PAR-002.md)) and re-exports `clvmr` types like `Allocator`, `NodePtr`, and `Cost` for callers who need low-level access.

---

## Specification

### Required Execution Path

All CLVM execution must flow through one of:

```rust
// Path 1: Via chia-consensus (production validation)
use chia_consensus::spendbundle_conditions::run_spendbundle;

run_spendbundle(
    allocator,     // clvmr::Allocator
    bundle,        // &SpendBundle
    max_cost,      // clvmr::Cost
    height,        // u32
    constants,     // &ConsensusConstants
    flags,         // u32 (ChiaDialect flags)
)?;

// Path 2: Via chia-sdk-types (convenience)
use chia_sdk_types::run_puzzle;

run_puzzle(
    allocator,     // &mut clvmr::Allocator
    puzzle,        // NodePtr
    solution,      // NodePtr
)?;
// Internally: run_program(allocator, &ChiaDialect::new(0), puzzle, solution, 11_000_000_000)

// Path 3: Via clvmr directly (low-level, if needed)
use clvmr::{run_program, ChiaDialect, Allocator};

let dialect = ChiaDialect::new(flags);
let (cost, result) = run_program(
    allocator,
    &dialect,
    program,
    environment,
    max_cost,
)?;
```

### Prohibited Patterns

```rust
// PROHIBITED: Custom CLVM interpreter
fn eval_clvm(program: &[u8], env: &[u8]) -> Vec<u8> { /* custom eval loop */ }

// PROHIBITED: Alternative dialect
struct DigDialect;
impl Dialect for DigDialect { /* custom operator handling */ }

// PROHIBITED: Bypassing clvmr for execution
fn run_program_custom(bytecode: &[u8]) -> Result<Vec<u8>> { /* hand-rolled */ }
```

### ChiaDialect Flags

The `ChiaDialect::new(flags)` constructor accepts a `u32` flags value that controls soft-fork behavior. Valid flag combinations are:

| Flag | Value | Purpose | L1 Ref |
|------|-------|---------|--------|
| `0` | `0x00` | Default (all features enabled post-hard-fork) | Default for DIG L2 |
| `MEMPOOL_MODE` | `0x01` | Stricter validation for mempool admission | [`mempool.py:13`](https://github.com/Chia-Network/chia-blockchain/blob/main/chia/full_node/mempool.py#L13) |
| `NO_UNKNOWN_OPS` | `0x02` | Reject unknown CLVM operators | Part of `MEMPOOL_MODE` |
| `LIMIT_HEAP` | `0x04` | Enforce heap size limits | Part of `MEMPOOL_MODE` |

DIG L2 sets `hard_fork_height = 0`, meaning all post-hard-fork features are enabled from block 0. The flags value for block validation should be obtained via `get_flags_for_height_and_constants()` from `chia-consensus`.

### Re-exports

The following `clvmr` types must be re-exported from `dig-clvm`:

```rust
pub use clvmr::{Allocator, NodePtr, Cost};
```

---

## Acceptance Criteria

- [ ] All CLVM execution in `dig-clvm` flows through `clvmr::run_program()` or a `chia-consensus` function that delegates to it
- [ ] `grep -r "impl Dialect" src/` returns zero matches (no custom dialect)
- [ ] `grep -r "fn eval" src/ | grep -i clvm` returns zero matches (no custom evaluator)
- [ ] `ChiaDialect` is the only dialect instantiated anywhere in the crate
- [ ] `clvmr` v0.14 appears in `Cargo.toml` dependencies
- [ ] `Allocator`, `NodePtr`, and `Cost` are re-exported from the crate root

---

## Implementation Notes

- The `clvmr` version (v0.14) must match the version depended on by `chia-consensus` v0.26. Version mismatch causes type incompatibility.
- `ChiaDialect::new(0)` is the standard configuration for DIG L2 since `hard_fork_height = 0`. The `flags` parameter only matters when `MEMPOOL_MODE` is needed (see [PAR-011](PAR-011.md)).
- The `Allocator` is a bump allocator that manages CLVM S-expression nodes. It must be created fresh for each validation call (or reused carefully with `reset()`).
- `run_program()` returns `(Cost, NodePtr)` where `Cost` is the CLVM execution cost and `NodePtr` points to the result tree in the allocator.

---

## Verification

### Test Plan

1. **Code review -- no custom interpreter**:
   - Run `grep -rn "fn eval\|fn interpret\|fn execute_clvm\|impl Dialect" src/`.
   - Assert zero matches for custom CLVM execution logic.
   - Verify all execution paths lead to `clvmr::run_program()`.

2. **Code review -- ChiaDialect only**:
   - Run `grep -rn "Dialect" src/`.
   - Verify every match references `ChiaDialect` from `clvmr`.

3. **Execution parity test**:
   - Compile and run a known CLVM program (e.g., `(+ 2 5)` -> `7`) via `dig-clvm`.
   - Compare the result and cost to executing the same program directly via `clvmr::run_program()`.
   - Assert identical results.

4. **Complex program test**:
   - Execute a standard Chia puzzle (e.g., `p2_delegated_puzzle_or_hidden_puzzle`) with a known solution.
   - Verify the conditions output matches the expected L1 output.

5. **Dependency audit**:
   - Run `cargo tree -p dig-clvm | grep clvmr`.
   - Verify exactly one version of `clvmr` in the dependency tree.

6. **Re-export test**:
   - In an integration test, use `dig_clvm::Allocator`, `dig_clvm::NodePtr`, `dig_clvm::Cost`.
   - Assert they compile and function correctly.

### Expected Test Files

- `tests/parity_tests.rs` -- PAR-001 CLVM execution parity tests
- Code review checklist (manual)

---

## Source Citations

- Chia L1 CLVM execution: [`multiprocess_validation.py:62`](https://github.com/Chia-Network/chia-blockchain/blob/main/chia/consensus/multiprocess_validation.py#L62)
- `clvmr` crate: [`clvmr` v0.14](https://crates.io/crates/clvmr)
- `ChiaDialect` and flags: [`mempool.py:13-14`](https://github.com/Chia-Network/chia-blockchain/blob/main/chia/full_node/mempool.py#L13)
- dig-clvm architecture: [SPEC.md Section 2.1](../../../../resources/SPEC.md)

---

## References

- [PAR-002](PAR-002.md) -- Condition parsing via `chia-consensus` (uses `clvmr` internally)
- [PAR-006](PAR-006.md) -- Per-condition costs (cost model built into `ChiaDialect`)
- [PAR-011](PAR-011.md) -- Mempool flags (`MEMPOOL_MODE` flag passed to `ChiaDialect`)
