# VAL-001: Entry Point Signature

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

---

## Summary

`validate_spend_bundle()` is the primary public entry point of the `dig-clvm` crate. It is the function that DIG validators, mempools, and block builders call to validate a spend bundle against L2 consensus rules and obtain the resulting coin state changes (additions, removals, fee).

This function mirrors the role played by several cooperating functions on Chia L1. On L1, mempool admission flows through [`pre_validate_spendbundle()`](https://github.com/Chia-Network/chia-blockchain/blob/main/chia/full_node/mempool_manager.py#L428) which calls [`validate_clvm_and_signature()`](https://github.com/Chia-Network/chia-blockchain/blob/main/chia/full_node/mempool_manager.py#L445), while block validation flows through [`validate_block_body()`](https://github.com/Chia-Network/chia-blockchain/blob/main/chia/consensus/block_body_validation.py#L191). `dig-clvm` consolidates these into a single well-typed Rust function that accepts a `SpendBundle`, the chain context needed to validate it, configurable cost/flag parameters, and an optional BLS signature cache for cross-call optimization.

The function signature is carefully designed so that the caller controls all inputs (coin records, chain height, constants) and the crate never reaches out to storage, networking, or any external state. This keeps the crate a pure computation library, consistent with the separation of concerns established on Chia L1 where execution is separated from state commitment.

---

## Specification

### Function Signature

```rust
pub fn validate_spend_bundle(
    bundle: &SpendBundle,
    context: &ValidationContext,
    config: &ValidationConfig,
    bls_cache: Option<&mut BlsCache>,
) -> Result<SpendResult, ValidationError>;
```

### Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `bundle` | `&SpendBundle` | The spend bundle to validate. Contains `coin_spends: Vec<CoinSpend>` and `aggregated_signature: Signature`. Imported from `chia-protocol`. |
| `context` | `&ValidationContext` | L2 chain state: current height, timestamp, network constants (from `dig-constants`), coin records for the coins being spent, and ephemeral coin IDs from earlier bundles in the same block. |
| `config` | `&ValidationConfig` | Validation parameters: `max_cost_per_spend` (default 11B), `max_cost_per_block` (default 550B), and `flags` (`0`, `MEMPOOL_MODE`, `DONT_VALIDATE_SIGNATURE`, or combinations). |
| `bls_cache` | `Option<&mut BlsCache>` | Optional BLS signature cache. When provided, verified pairings are stored and reused across calls. Pass the same cache from mempool validation through block validation to avoid re-verifying signatures. Pass `None` to verify from scratch every time. |

### Return Type

- **`Ok(SpendResult)`** on successful validation. Contains `additions`, `removals`, `fee`, and `conditions`.
- **`Err(ValidationError)`** on any validation failure. The error variant indicates the specific failure (see `ValidationError` enum in SPEC Section 5.1).

### Error Cases

| Error Variant | When Returned |
|---------------|---------------|
| `ValidationError::DoubleSpend(Bytes32)` | Same coin appears twice in the bundle |
| `ValidationError::CoinNotFound(Bytes32)` | Coin not in `coin_records` and not in `ephemeral_coins` |
| `ValidationError::AlreadySpent(Bytes32)` | Coin is marked as spent in `coin_records` |
| `ValidationError::PuzzleHashMismatch(Bytes32)` | `tree_hash(puzzle_reveal) != coin.puzzle_hash` |
| `ValidationError::Clvm(ValidationErr)` | CLVM execution or condition parsing failure |
| `ValidationError::CostExceeded { limit, consumed }` | Total cost exceeds `config.max_cost_per_block` |
| `ValidationError::SignatureFailed` | BLS aggregate signature does not verify |
| `ValidationError::ConservationViolation { input, output }` | `sum(removals) < sum(additions) + fee` |
| `ValidationError::Driver(DriverError)` | Upstream driver error |

---

## Acceptance Criteria

- [ ] The function `validate_spend_bundle` is publicly exported from the crate and has the exact signature specified above.
- [ ] The function accepts `&SpendBundle` (from `chia-protocol`), `&ValidationContext`, `&ValidationConfig`, and `Option<&mut BlsCache>`.
- [ ] The return type is `Result<SpendResult, ValidationError>`.
- [ ] The function compiles and is callable from external crates that depend on `dig-clvm`.
- [ ] Passing `None` for `bls_cache` performs full BLS verification without caching.
- [ ] Passing `Some(&mut cache)` for `bls_cache` stores and reuses verified pairings.
- [ ] All `ValidationError` variants listed in the spec are present and reachable through this function.

---

## Implementation Notes

- **Primary file:** `src/consensus/validate.rs`
- **Public export:** `src/lib.rs` must re-export `validate_spend_bundle`.
- **Dependencies:** This requirement depends on every other VAL requirement (VAL-002 through VAL-015) since this function orchestrates the full validation pipeline.
- **The `SpendBundle` type** comes from `chia-protocol`, not a custom type. It is the canonical wire type used by Chia full nodes.
- **The `BlsCache` type** comes from `chia-bls`. It is the same cache used by Chia L1 for mempool-to-block signature reuse.
- **Edge cases:**
  - An empty `SpendBundle` (zero coin spends) should be handled gracefully. The spec does not mandate rejection of empty bundles, but the conservation check would pass trivially (0 >= 0 + 0).
  - The `bls_cache` is `&mut` because verification may update it. Ensure the borrow checker is satisfied when `None` is passed.

---

## Verification

### Test Plan

| Test | Type | Description | Expected Result |
|------|------|-------------|-----------------|
| Signature compiles | Unit test | Call `validate_spend_bundle` with valid types, confirm compilation | Compiles without error |
| Valid spend returns Ok | Simulator test | Build a standard spend bundle with proper signature, pass to function | Returns `Ok(SpendResult)` |
| bls_cache=None works | Simulator test | Call with `None` for bls_cache on a valid bundle | Returns `Ok(SpendResult)` |
| bls_cache=Some works | Simulator test | Call with `Some(&mut cache)`, verify cache is populated after call | Returns `Ok(SpendResult)`, cache grows |
| Error variants reachable | Simulator tests | Trigger each `ValidationError` variant through this entry point | Each variant returned at least once |
| Re-export accessible | Integration test | Import `validate_spend_bundle` from `dig_clvm::` directly | Import resolves |

---

## Source Citations

- **SPEC.md Section 5.1** (lines 374-563): Full `validate_spend_bundle()` signature and supporting types.
- **SPEC.md Section 6.1** (lines 611-679): Internal validation flow (Path A) showing step-by-step orchestration.
- **L1 reference — `pre_validate_spendbundle()`:** [`mempool_manager.py:428`](https://github.com/Chia-Network/chia-blockchain/blob/main/chia/full_node/mempool_manager.py#L428)
- **L1 reference — `validate_clvm_and_signature()`:** [`mempool_manager.py:445`](https://github.com/Chia-Network/chia-blockchain/blob/main/chia/full_node/mempool_manager.py#L445)
- **L1 reference — `validate_block_body()`:** [`block_body_validation.py:191`](https://github.com/Chia-Network/chia-blockchain/blob/main/chia/consensus/block_body_validation.py#L191)

---

## References

- [VAL-002](VAL-002.md) — Delegates to `chia-consensus::run_spendbundle()`
- [VAL-003](VAL-003.md) — Duplicate spend rejection (structural check)
- [VAL-004](VAL-004.md) — Missing coin rejection (structural check)
- [VAL-005](VAL-005.md) — Already-spent coin rejection (structural check)
- [VAL-006](VAL-006.md) — Puzzle hash mismatch rejection (structural check)
- [VAL-007](VAL-007.md) — Cost limit enforcement
- [VAL-011](VAL-011.md) — Conservation check
- [VAL-012](VAL-012.md) — BLS signature verification
- [VAL-014](VAL-014.md) — SpendResult output structure
