# ASPRegistry contract

> The ASPRegistry stores the append-only history of [ASP](/concepts/asp-attestation)-attested roots. Spending circuits prove their note's label is in an ASP root, and [`PoolVault`](/protocol/contracts/pool-vault)`.transact` requires that root to equal the current `latestASPRoot()`. The history is kept for auditing, but only the latest root is accepted for spends.

The ASPRegistry stores the append-only history of [ASP](/concepts/asp-attestation)-attested roots. Spending circuits prove their note's label is in an ASP root, and [`PoolVault`](/protocol/contracts/pool-vault)`.transact` requires that root to equal the current `latestASPRoot()`. The history is kept for auditing, but only the latest root is accepted for spends.

## State

`associationSets(uint256 _index) → AssociationSetData` Indexed accessor over the append-only history. Each entry is `{ uint256 root; bytes ipfsCID }`.
`latestASPRoot() → uint256` The most-recent root in the history. Reverts with `ASPRegistry_EmptyAssociationSet` if no root has been published yet.
`latestIPFSCID() → bytes` IPFS CID published alongside the latest root.

Note: there is no `isRootKnown` or `currentRoot` view on this contract. To check a specific root, compare against `latestASPRoot()` or walk `associationSets(i)` backwards.

## Only the latest root spends

Unlike the [PoolVault](/protocol/contracts/pool-vault)'s sixteen-root buffer and the [Keystore](/protocol/contracts/keystore)'s twenty-minute liveness window, the ASP root is checked by strict equality with `latestASPRoot()`. Publishing a new root immediately invalidates every transact proof built against the previous one (`PoolVault_InvalidASPRoot`), so clients should fetch the root as late as possible before proving and be ready to rebuild. A frequently posting or adversarially timed postman can delay withdrawals; it cannot freeze funds, because [ragequit](/operations/ragequit) does not check this root at all.

## Main functions

`updateASPRoot(uint256 _aspRoot, bytes _ipfsCID)` Append a new ASP root and the IPFS CID of the snapshot it was derived from. `POSTMAN_ROLE`\-gated.
`registerLabel(bytes _ciphertext)` Permissionless. Emits a `LabelRegistered` event with the encrypted label, for ASP indexers to pick up. The [Entrypoint](/protocol/contracts/entrypoint) calls it at deposit time only when the caller supplies a non-empty `aspCiphertext`. Callers may also invoke it directly.

## Roles

`POSTMAN_ROLE` Allowed to call `updateASPRoot`. Typically granted to the ASP service's signing accounts.

## Trust model

The contract trusts holders of [`POSTMAN_ROLE`](/protocol/contracts/access-control) to only publish roots derived from legitimate ASP attestation. A malicious postman could approve labels that shouldn't be approved, because the contract has no way to verify policy.

The mitigation is operational: `POSTMAN_ROLE` is granted carefully. Recovery from a bad update isn't automatic and would require either tolerating the bad approvals or a coordinated upgrade.

Source: `v2-monorepo/packages/contracts/src/contracts/ASPRegistry.sol`
