# VAL-013: MEMPOOL_MODE Stricter Rules

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

---

## Summary

`MEMPOOL_MODE` is a validation flag that activates stricter CLVM execution rules when validating spend bundles destined for the mempool. In mempool mode, the CLVM virtual machine uses a `MempoolVisitor` that rejects unknown opcodes and enforces tighter cost accounting compared to the permissive rules used for block validation. This ensures that transactions in the mempool are conservatively valid and less likely to cause issues when included in a block.

The distinction between mempool and block validation modes mirrors Chia L1's approach, where the mempool applies forward-compatible rules that reject potentially problematic transactions before they consume block space. Unknown opcodes that might be valid in future soft forks are rejected in the mempool because their semantics are not yet defined, even though block validation would accept them as no-ops. This protects node operators from relaying transactions they cannot fully validate.

On Chia L1, `MEMPOOL_MODE` is set in [`mempool.py:13`](https://github.com/Chia-Network/chia-blockchain/blob/main/chia/full_node/mempool.py#L13) during mempool transaction validation. When this flag is present in `config.flags`, `chia-consensus` switches from the default `BlockVisitor` to `MempoolVisitor`, which has additional opcode validation and stricter cost limits. The flag is passed through `dig-clvm`'s `ValidationConfig.flags` field, and the crate forwards it to `chia-consensus` without modification.

---

## Specification

### MEMPOOL_MODE Flag

```rust
/// When set, use MempoolVisitor for stricter CLVM execution.
/// Rejects unknown opcodes and enforces tighter cost accounting.
pub const MEMPOOL_MODE: u32 = 0x0001;
```

### Flag Passing

The `MEMPOOL_MODE` flag is set in the `ValidationConfig.flags` field:

```rust
pub struct ValidationConfig {
    /// Bitfield of validation flags.
    /// Supported flags:
    ///   - MEMPOOL_MODE (0x0001): stricter CLVM rules
    ///   - DONT_VALIDATE_SIGNATURE (0x0004): skip BLS verification
    pub flags: u32,
}

// Mempool validation example:
let config = ValidationConfig {
    flags: MEMPOOL_MODE,  // strict mode for mempool
};

let result = validate_spend_bundle(&bundle, &context, &config, Some(&mut cache))?;
```

### MempoolVisitor Behavior

When `MEMPOOL_MODE` is active, the CLVM execution engine (via `chia-consensus`) applies these additional restrictions:

```rust
// chia-consensus internally selects the visitor based on flags:
//
// if flags & MEMPOOL_MODE != 0 {
//     run_program_with_visitor::<MempoolVisitor>(...)
// } else {
//     run_program_with_visitor::<BlockVisitor>(...)
// }
```

**Restrictions in MEMPOOL_MODE:**

1. **Unknown opcodes rejected:** Any CLVM opcode not in the recognized set causes an immediate error. In block mode, unknown opcodes are treated as no-ops with a fixed cost.

2. **Stricter cost accounting:** Some operations have higher cost multipliers in mempool mode to prevent cost manipulation attacks.

3. **Future soft-fork conditions rejected:** Condition opcodes that are reserved for future use but not yet active are rejected in mempool mode.

### Flag Combinations

Flags are combinable via bitwise OR:

```rust
// Mempool mode with signature verification:
let flags = MEMPOOL_MODE;

// Mempool mode without signature verification:
let flags = MEMPOOL_MODE | DONT_VALIDATE_SIGNATURE;

// Block mode (no special flags):
let flags = 0u32;

// Block mode without signature verification:
let flags = DONT_VALIDATE_SIGNATURE;
```

### Error Behavior

When `MEMPOOL_MODE` causes a rejection, the error originates from `chia-consensus` and is wrapped by `dig-clvm`:

```rust
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ValidationError {
    // ... other variants ...

    /// CLVM execution failed. Inner error from chia-consensus.
    /// In MEMPOOL_MODE, this can be triggered by unknown opcodes
    /// or stricter cost rules that would pass in block mode.
    ClvmError(String),
}
```

### When to Use Each Mode

| Scenario | Flags | Rationale |
|----------|-------|-----------|
| Mempool admission | `MEMPOOL_MODE` | Reject uncertain transactions |
| Block validation | `0` | Accept all consensus-valid transactions |
| Testing (fast) | `DONT_VALIDATE_SIGNATURE` | Skip expensive BLS during tests |
| Mempool pre-check | `MEMPOOL_MODE \| DONT_VALIDATE_SIGNATURE` | Quick mempool filter without BLS |

---

## Acceptance Criteria

- [ ] When `MEMPOOL_MODE` flag is set in `config.flags`, CLVM execution uses the `MempoolVisitor` (stricter rules).
- [ ] When `MEMPOOL_MODE` is not set, CLVM execution uses the default `BlockVisitor` (permissive rules).
- [ ] Unknown CLVM opcodes cause validation failure in `MEMPOOL_MODE` but succeed (as no-ops) without it.
- [ ] `MEMPOOL_MODE` can be combined with `DONT_VALIDATE_SIGNATURE` via bitwise OR.
- [ ] The flag value `0x0001` matches the Chia L1 definition for `MEMPOOL_MODE`.

---

## Implementation Notes

- **Primary file:** `src/consensus/validate.rs` (flag forwarding to chia-consensus), `src/consensus/config.rs` (flag constants).
- **Transparent forwarding:** `dig-clvm` does not implement the `MempoolVisitor` or `BlockVisitor` logic. The flag is passed directly to `chia-consensus`'s `run_program` or equivalent function, which handles visitor selection internally.
- **No flag validation:** `dig-clvm` does not validate that `config.flags` contains only known flags. Unknown flag bits are passed through to `chia-consensus`, which may ignore them.
- **Default is block mode:** A `ValidationConfig` with `flags: 0` uses block validation rules (the most permissive consensus-valid mode).
- **Mempool is a superset:** Any transaction that passes mempool validation will also pass block validation. The reverse is not necessarily true. This means `MEMPOOL_MODE` is strictly more restrictive.
- **Testing consideration:** Tests that validate known-good bundles should work identically with or without `MEMPOOL_MODE`, since well-formed transactions use only recognized opcodes.

---

## Verification

### Test Plan

| Test | Type | Description | Expected Result |
|------|------|-------------|-----------------|
| Mempool rejects unknown opcode | Simulator test | Bundle with unknown CLVM opcode, MEMPOOL_MODE set | Err(ClvmError) |
| Block accepts unknown opcode | Simulator test | Same bundle without MEMPOOL_MODE | Validation passes (unknown opcode = no-op) |
| Standard bundle passes both | Simulator test | Normal bundle with standard opcodes | Passes in both MEMPOOL_MODE and block mode |
| Combined flags | Unit test | MEMPOOL_MODE \| DONT_VALIDATE_SIGNATURE | Both effects apply: strict CLVM + no BLS |
| Flag constant value | Unit test | Assert MEMPOOL_MODE == 0x0001 | Matches L1 definition |
| Default config is block mode | Unit test | ValidationConfig { flags: 0 } | Block-mode validation (permissive) |

---

## Source Citations

- **SPEC.md Section 5.1**: "MEMPOOL_MODE flag -> MempoolVisitor -> reject unknown opcodes, stricter cost."
- **SPEC.md Section 5.1**: `ValidationConfig.flags` field — "Bitfield controlling validation behavior."
- **L1 reference — mempool.py:13:** [`mempool.py`](https://github.com/Chia-Network/chia-blockchain/blob/main/chia/full_node/mempool.py#L13) — MEMPOOL_MODE flag usage in mempool validation.
- **L1 reference — chia-consensus:** `MempoolVisitor` vs `BlockVisitor` implementation for opcode strictness.

---

## References

- [VAL-007](VAL-007.md) — Cost enforcement (interacts with MEMPOOL_MODE cost rules)
- [VAL-009](VAL-009.md) — Condition validation (MempoolVisitor rejects unknown conditions)
- [VAL-012](VAL-012.md) — BLS signature verification (DONT_VALIDATE_SIGNATURE flag)
- [PAR-011](../../parity/specs/PAR-011.md) — Mempool flag parity with L1
