# VAL-009: Condition Validation Delegated to chia-consensus

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

---

## Summary

Chia CLVM programs produce a list of "conditions" as their output. These conditions are instructions to the consensus layer: create new coins, assert announcements, require time locks, assert identity, send/receive messages, and more. Validating these conditions is one of the most complex parts of the consensus engine, involving announcement matching, concurrent spend assertions, identity checks, relative and absolute time/height locks, and ephemeral assertions.

`dig-clvm` MUST delegate all condition validation to `chia-consensus` and MUST NOT reimplement any of it. This is a core architectural principle (SPEC Section 9.2): the condition validation logic in `chia-consensus` is the same Rust code used by Chia L1 full nodes, and reimplementing it would be error-prone, drift from L1 behavior, and duplicate thousands of lines of battle-tested consensus code.

On Chia L1, condition validation is handled by `chia_rs` (the Rust crate) called from Python. The condition opcodes are defined at [`condition_opcodes.py:7-73`](https://github.com/Chia-Network/chia-blockchain/blob/main/chia/types/condition_opcodes.py#L7), covering over 30 opcodes including the newer `SEND_MESSAGE(66)` and `RECEIVE_MESSAGE(67)` from Chia 2.3+. The `run_spendbundle()` function processes all conditions internally, including announcement matching (`CREATE_COIN_ANNOUNCEMENT`/`ASSERT_COIN_ANNOUNCEMENT`, `CREATE_PUZZLE_ANNOUNCEMENT`/`ASSERT_PUZZLE_ANNOUNCEMENT`), time locks (`ASSERT_SECONDS_ABSOLUTE`, `ASSERT_SECONDS_RELATIVE`, `ASSERT_HEIGHT_ABSOLUTE`, `ASSERT_HEIGHT_RELATIVE`), and identity assertions (`ASSERT_MY_COIN_ID`, `ASSERT_MY_PARENT_ID`, `ASSERT_MY_PUZZLEHASH`, `ASSERT_MY_AMOUNT`).

---

## Specification

### Conditions Handled by chia-consensus

The following condition categories MUST be validated by `chia-consensus` through the `run_spendbundle()` delegation, not by `dig-clvm` code:

#### 1. Announcement Matching

- `CREATE_COIN_ANNOUNCEMENT` / `ASSERT_COIN_ANNOUNCEMENT`
- `CREATE_PUZZLE_ANNOUNCEMENT` / `ASSERT_PUZZLE_ANNOUNCEMENT`

Announcements created by one spend can be asserted by another spend in the same bundle. `run_spendbundle()` collects all created announcements and validates that every assertion has a matching creation.

#### 2. Concurrent Spend Assertions

- `ASSERT_CONCURRENT_SPEND`
- `ASSERT_CONCURRENT_PUZZLE`

Asserts that another specific coin (by ID or puzzle hash) is being spent in the same bundle.

#### 3. Identity Assertions

- `ASSERT_MY_COIN_ID`
- `ASSERT_MY_PARENT_ID`
- `ASSERT_MY_PUZZLEHASH`
- `ASSERT_MY_AMOUNT`

Asserts properties of the coin being spent. Validated against the coin's actual fields.

#### 4. Time and Height Locks

- `ASSERT_SECONDS_ABSOLUTE` / `ASSERT_SECONDS_RELATIVE`
- `ASSERT_HEIGHT_ABSOLUTE` / `ASSERT_HEIGHT_RELATIVE`
- `ASSERT_BEFORE_SECONDS_ABSOLUTE` / `ASSERT_BEFORE_SECONDS_RELATIVE`
- `ASSERT_BEFORE_HEIGHT_ABSOLUTE` / `ASSERT_BEFORE_HEIGHT_RELATIVE`

Time locks are validated against `context.height` and `context.timestamp` as passed through to `run_spendbundle()`. The L1 implementation is at [`check_time_locks.py:15`](https://github.com/Chia-Network/chia-blockchain/blob/main/chia/consensus/check_time_locks.py#L15).

#### 5. Ephemeral Assertions

- `ASSERT_EPHEMERAL`

Asserts that the coin being spent is ephemeral (created and spent in the same block). Handled by `chia-consensus` condition processing.

#### 6. Message Conditions (Chia 2.3+)

- `SEND_MESSAGE(66)` / `RECEIVE_MESSAGE(67)`

Cross-layer messaging conditions added in Chia 2.3. Defined at [`condition_opcodes.py:37`](https://github.com/Chia-Network/chia-blockchain/blob/main/chia/types/condition_opcodes.py#L37).

### What dig-clvm MUST NOT Implement

- MUST NOT implement announcement hash computation or matching.
- MUST NOT implement time/height lock validation.
- MUST NOT implement identity assertion checks.
- MUST NOT implement concurrent spend/puzzle assertion checks.
- MUST NOT implement message condition validation.
- MUST NOT implement any condition opcode parsing or interpretation.

All of the above is handled by `run_spendbundle()` as part of the VAL-002 delegation.

---

## Acceptance Criteria

- [ ] No announcement matching logic exists in `dig-clvm` source code.
- [ ] No time/height lock validation logic exists in `dig-clvm` source code.
- [ ] No identity assertion logic exists in `dig-clvm` source code.
- [ ] No condition opcode parsing or interpretation exists in `dig-clvm` source code.
- [ ] Announcement mismatches produce errors through the `run_spendbundle()` path (mapped to `ValidationError::Clvm`).
- [ ] Time lock violations produce errors through the `run_spendbundle()` path.
- [ ] A bundle with `ASSERT_COIN_ANNOUNCEMENT` matching a `CREATE_COIN_ANNOUNCEMENT` in the same bundle succeeds.
- [ ] A bundle with `ASSERT_COIN_ANNOUNCEMENT` with no matching creation fails.

---

## Implementation Notes

- **Primary file:** No implementation file for this requirement. This is a "MUST NOT" requirement enforced by code review.
- **How it works:** By delegating to `run_spendbundle()` (VAL-002), all condition validation is inherited from `chia-consensus`. The conditions are returned in the `SpendBundleConditions` output for inspection, but `dig-clvm` does not need to interpret them for validation purposes.
- **`OwnedSpendBundleConditions`:** After `run_spendbundle()` completes, the conditions are available for callers to inspect via `SpendResult.conditions`. This allows callers to examine announcements, time locks, etc., but `dig-clvm` itself does not act on them beyond what `run_spendbundle()` already validated.
- **Height and timestamp:** These are passed to `run_spendbundle()` through the `ValidationContext` so that `chia-consensus` can evaluate time/height lock conditions correctly.
- **Edge case:** `run_spendbundle()` does not check time locks post-execution on its own for all cases. On L1, [`check_time_locks()`](https://github.com/Chia-Network/chia-blockchain/blob/main/chia/consensus/check_time_locks.py#L15) is called separately for some time lock conditions. If `chia-consensus` does not fully validate time locks during `run_spendbundle()`, `dig-clvm` may need to call `check_time_locks()` separately. This should be verified during implementation.

---

## Verification

### Test Plan

| Test | Type | Description | Expected Result |
|------|------|-------------|-----------------|
| Code review: no conditions | Code review | Search `dig-clvm` for announcement hash, time lock, or identity assertion logic | None found |
| Announcement match success | Simulator test | Bundle with CREATE_COIN_ANNOUNCEMENT + ASSERT_COIN_ANNOUNCEMENT | Succeeds |
| Announcement match failure | Simulator test | Bundle with ASSERT_COIN_ANNOUNCEMENT but no matching creation | Fails with CLVM error |
| Time lock respected | Simulator test | Bundle with ASSERT_HEIGHT_ABSOLUTE > current height | Fails |
| Time lock passed | Simulator test | Bundle with ASSERT_HEIGHT_ABSOLUTE <= current height | Succeeds |
| Identity assertion | Simulator test | Bundle with ASSERT_MY_COIN_ID matching the actual coin ID | Succeeds |
| Identity mismatch | Simulator test | Bundle with ASSERT_MY_COIN_ID with wrong value | Fails |
| Concurrent spend | Simulator test | Two spends in bundle, one asserts the other via ASSERT_CONCURRENT_SPEND | Succeeds |

---

## Source Citations

- **SPEC.md Section 6.1** (lines 658-664): Step 4 condition validation, all handled by `chia-consensus`.
- **SPEC.md Section 9.2** (lines 939-947): Design decision: "Why `chia-consensus` for Validation Instead of Hand-Rolled."
- **SPEC.md Section 2.5** (lines 95-113): `chia-consensus` crate inventory showing condition processing APIs.
- **L1 reference — condition opcodes:** [`condition_opcodes.py:7-73`](https://github.com/Chia-Network/chia-blockchain/blob/main/chia/types/condition_opcodes.py#L7)
- **L1 reference — check_time_locks:** [`check_time_locks.py:15`](https://github.com/Chia-Network/chia-blockchain/blob/main/chia/consensus/check_time_locks.py#L15)
- **L1 reference — SEND_MESSAGE/RECEIVE_MESSAGE:** [`condition_opcodes.py:37`](https://github.com/Chia-Network/chia-blockchain/blob/main/chia/types/condition_opcodes.py#L37)

---

## References

- [VAL-002](VAL-002.md) — Delegates to run_spendbundle (which performs all condition validation)
- [VAL-010](VAL-010.md) — Ephemeral coin support (ephemeral assertion conditions)
- [VAL-012](VAL-012.md) — BLS signature verification (AGG_SIG conditions are also handled by chia-consensus)
- [VAL-013](VAL-013.md) — MEMPOOL_MODE (affects condition strictness)
- [VAL-014](VAL-014.md) — SpendResult output (conditions are available for inspection)
