# DEP 0008: Transaction-local state

```
status: accepted
```

## Motivation

In DarkFi, spending a coin requires a Merkle inclusion proof against
the global incremental Merkle tree. When a transaction contains
multiple calls where one call's output is spent by a subsequent call,
the intermediate coin hasn't been inserted into the global tree yet.
The global tree's state at verification time depends on block ordering,
so the prover and verifier cannot agree on a root.

## Proposal

We can build a small, deterministic Merkle tree from the intermediate
output commitments produced within the transaction itself. For intra-tx
spends, the burn proof demonstrates inclusion in this local tree rather
than the global one. Since the transaction defines the order of calls
and their outputs, both prover and verifier will always construct the
same tree and arrive at the same root.

### Construction

Given a transaction with ordered calls `[C0, C1, C2]`:

* `C0` produces output commitments `[O0, O1]`
* `C1` wants to spend `O1`, so the prover builds a local tree from `{O0, O1}`
* `C1` generates a standard Merkle inclusion proof for `O1` in this
  local tree
* If `C1` also produces `O2`, and `C2` wants to spend it, a new local
  tree is built from `{O0, O1, O2}` (all outputs preceding `C2`)

The local tree root becomes the public `merkle_root` input to the burn
proof, replacing the global anchor.

The burn circuit itself remains unchanged. The Merkle path verification
logic is identical - the only difference is which root the verifier
expects.

We have to add a public `mode_flag` (0 = global, 1 = local) so the
verifier knows which root check to perform. This would be added to
the `Input` and `Output` structs in the `Money` contract and the smart
contract would then be able to select the correct code path for verification.

## Privacy

The Merkle proof hides which leaf is being proven. If the local tree
contains multiple leaves, an observer knows "this spend consumed one
of the outputs from previous calls" but not which one. If there's only
a single preceding output, the privacy set is 1 and the link is
trivially visible, but in that case the transaction structure already
reveals it.

## Nullifier Handling

Intermediate coins must still emit nullifiers. The verifier checks:

* No two nullifiers within the same transaction collide (prevents
  intra-tx double spend)
* No nullifier collides with any previously spent nullifier in the
  global state.

## Global Tree Updates

After a transaction is finalized, only the surviving output commitments
(those not consumed by an intra-tx spend) need to be inserted into the
global Merkle tree. Intermediate coins that were both created and
destroyed within the transaction can be omitted from the global tree
to save space. The nullifiers still need to be recorded to prevent
replay.

## Transaction Validity Rules

* A call at index `K` may only spend outputs from calls at indices `0..K-1`.
  Circular dependencies are impossible by construction.
* Proofs must be generated sequentially: call 0 first (to produce outputs),
  then call 1 (which may reference those outputs), and so on.
* If any call in the transaction fails verification, the entire transaction
  is rejected atomically.
