# VAL-015: No Full UTXO Set in Memory

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

---

## Summary

`dig-clvm` operates as a pure computation crate with a hard boundary: it never touches persistent storage, never loads the full UTXO set, and never manages a coin database. The `coin_records` field in `ValidationContext` is a `HashMap<Bytes32, CoinRecord>` that contains only the coins relevant to the current validation operation — typically the coins being spent in the current bundle. The caller is entirely responsible for loading the appropriate coin records from whatever storage backend they use and providing them to the validator.

This design principle ensures that `dig-clvm` remains a focused, composable library that performs validation logic without imposing storage requirements on its consumers. Different applications may use different storage backends — an in-memory store for testing, a SQLite database for a full node, or a remote RPC for a light client. By accepting only the minimal set of relevant coins, `dig-clvm` is agnostic to all of these choices and imposes no dependency on any storage layer.

The boundary is strict and deliberate: no filesystem access, no database connections, no network calls, no global state. Every piece of data needed for validation is passed in through function parameters. This makes the crate deterministic, testable in isolation, and safe to use in any execution context (sync, async, WASM, embedded, etc.).

---

## Specification

### coin_records Field

```rust
use std::collections::HashMap;
use chia_protocol::Bytes32;

/// Minimal coin record for validation purposes.
/// Contains only the fields needed by the validator.
#[derive(Debug, Clone)]
pub struct CoinRecord {
    /// The coin itself (parent_coin_info, puzzle_hash, amount).
    pub coin: Coin,

    /// Whether this coin has already been spent.
    pub spent: bool,

    /// Block height at which this coin was confirmed (created).
    pub confirmed_block_index: u32,

    /// Timestamp of the block in which this coin was confirmed.
    pub timestamp: u64,
}

pub struct ValidationContext {
    /// Only the coins relevant to this validation operation.
    /// Keyed by coin_id (Bytes32).
    /// The caller loads these from their storage backend.
    pub coin_records: HashMap<Bytes32, CoinRecord>,

    /// Coins created by earlier bundles in the same block.
    pub ephemeral_coins: HashSet<Bytes32>,

    /// Block height for timelock validation.
    pub height: u32,

    /// Block timestamp for timelock validation.
    pub timestamp: u64,

    /// Network constants (genesis challenge, cost limits, etc.).
    pub constants: NetworkConstants,
}
```

### What the Caller Provides

For a single spend bundle with N coin spends, the caller provides exactly N entries in `coin_records`:

```rust
// Caller's responsibility: load only what's needed
let mut coin_records = HashMap::new();

for coin_spend in &spend_bundle.coin_spends {
    let coin_id = coin_spend.coin.coin_id();
    // Load from caller's storage backend (DB, cache, RPC, etc.)
    if let Some(record) = my_storage.get_coin_record(&coin_id) {
        coin_records.insert(coin_id, record);
    }
    // If not found, the validator will return CoinNotFound
}

let context = ValidationContext {
    coin_records,
    ephemeral_coins: HashSet::new(),
    height: current_height,
    timestamp: current_timestamp,
    constants: DIG_MAINNET,
};
```

### What dig-clvm Does NOT Do

```rust
// dig-clvm NEVER does any of the following:

// No filesystem access
// std::fs::read(...)          // NEVER
// std::fs::write(...)         // NEVER

// No database access
// sqlite::Connection::open()  // NEVER
// rusqlite, sled, rocksdb     // NEVER in dependencies

// No network access
// reqwest::get(...)           // NEVER
// TcpStream::connect(...)     // NEVER

// No global mutable state
// static mut UTXO_SET: ...    // NEVER
// lazy_static! { ... }        // NEVER for mutable state
```

### Pure Computation Boundary

The validation functions are pure in the functional programming sense (with the exception of the mutable `BlsCache` optimization):

```rust
/// Pure function: output depends only on inputs.
/// No side effects except optional BlsCache mutation.
pub fn validate_spend_bundle(
    spend_bundle: &SpendBundle,        // Input: the transaction
    context: &ValidationContext,        // Input: relevant state
    config: &ValidationConfig,          // Input: validation flags
    cache: Option<&mut BlsCache>,       // Optimization: BLS cache
) -> Result<SpendResult, ValidationError> {
    // All data comes from parameters.
    // No global state, no I/O, no storage access.
    // ...
}
```

### Memory Characteristics

The `coin_records` HashMap is small by design:

| Scenario | Typical Size |
|----------|-------------|
| Single spend bundle | 1-10 entries |
| Block validation (sequential) | 1-10 entries per bundle call |
| Block validation (batch) | 100-1000 entries for entire block |
| Stress test | Still bounded by max block size |

This contrasts with a full UTXO set which could contain millions of entries and require gigabytes of storage.

---

## Acceptance Criteria

- [ ] `coin_records` in `ValidationContext` is a `HashMap<Bytes32, CoinRecord>` containing only relevant coins, not the full UTXO set.
- [ ] `dig-clvm` has no dependencies on storage libraries (no SQLite, RocksDB, sled, filesystem, or network crates).
- [ ] All data required for validation is passed through function parameters.
- [ ] The crate compiles and functions correctly without any storage backend available.
- [ ] No global mutable state exists in the crate (except thread-local or cache optimizations).

---

## Implementation Notes

- **Primary file:** `src/consensus/context.rs` (ValidationContext definition), `src/lib.rs` (crate-level dependency audit).
- **Cargo.toml audit:** The `[dependencies]` section should not contain any storage or I/O crates. Only `chia-consensus`, `chia-protocol`, `chia-bls`, `chia-sdk-types`, `clvmr`, and standard library types.
- **No async:** The crate does not use `tokio`, `async-std`, or any async runtime. All functions are synchronous. This reinforces the pure computation boundary — async is typically needed for I/O, which this crate does not perform.
- **WASM compatibility:** Because the crate has no I/O dependencies, it should be compilable to `wasm32-unknown-unknown` target with minimal effort. This is a bonus, not a requirement, but the no-I/O constraint enables it.
- **Testing implications:** Tests can create `ValidationContext` with in-memory `HashMap` entries. No test fixtures, database setup, or mocking frameworks are needed.
- **Ephemeral coins supplement:** The `ephemeral_coins` set (VAL-010) supplements `coin_records` for intra-block spending. It is also caller-provided, not internally maintained.
- **CoinRecord is minimal:** The `CoinRecord` type used by `dig-clvm` need only contain the fields the validator actually reads: `coin`, `spent`, `confirmed_block_index`, `timestamp`. It does not need to match L1's full `CoinRecord` schema.

---

## Verification

### Test Plan

| Test | Type | Description | Expected Result |
|------|------|-------------|-----------------|
| Validation with HashMap | Unit test | Provide coin_records as HashMap, validate bundle | Succeeds using only provided records |
| Missing coin record | Unit test | Omit a required coin from coin_records | Err(CoinNotFound) |
| Empty coin_records | Unit test | Empty HashMap, bundle spends coins | Err(CoinNotFound) for first coin |
| No storage deps | Build test | Compile crate, audit dependency tree | No SQLite, RocksDB, sled, filesystem crates |
| Deterministic output | Unit test | Same inputs produce same SpendResult | Byte-identical results |
| No global state | Code review | Audit for static mut, lazy_static with mutation | None found |
| WASM target | Build test | `cargo build --target wasm32-unknown-unknown` | Compiles (stretch goal) |

---

## Source Citations

- **SPEC.md Section 5.1**: "coin_records is HashMap with only relevant coins. Crate never touches storage. Hard boundary: pure computation."
- **SPEC.md Section 3.1**: ValidationContext definition — "Caller provides coin records, ephemeral set, height, timestamp, constants."
- **SPEC.md Section 1.1**: Design philosophy — "Pure computation library, no I/O, no storage."

---

## References

- [VAL-004](VAL-004.md) — Coin existence check (reads from coin_records)
- [VAL-005](VAL-005.md) — Already-spent check (reads spent field from coin_records)
- [VAL-010](VAL-010.md) — Ephemeral coins (supplements coin_records for intra-block coins)
- [CON-007](../../constants/specs/CON-007.md) — Minimal dependencies (same philosophy for constants crate)
