The Merkle tree & nullifiers
Two on-chain structures do all the bookkeeping: a Merkle tree that proves a note exists, and a nullifier registry that stops it from being spent twice.
The Merkle tree — "my note is real"
Every note commitment is appended as a leaf to one giant tree (depth 32 — room for billions of notes). The tree hashes pairs of nodes upward until a single root summarizes the whole set. To prove your note exists, you reveal the chain of sibling hashes from your leaf to the root — the inclusion path — without revealing which leaf you are.
Because the root changes with every deposit, PolyShield accepts a rolling window of the last 1024 roots. A proof you started building a few blocks ago still verifies against the root that was current when you fetched your path — so you're never racing the chain.
Nullifiers — "and I haven't spent it"
Proving a note exists isn't enough — you could try to spend the same note repeatedly. Each spend publishes the note's nullifier, which the Vault records in a registry. Spend the same note again and its nullifier is already present, so the transaction reverts. The nullifier is checked before any state change (checks-effects-interactions), closing double-spend.
This is why spending always mints a fresh note: you can't edit a note in place, because the old one is permanently nullified. The leftover balance flows into a new note with a new nonce, a new commitment, and — importantly — a new, unlinkable nullifier for next time.