grace_active_until on the previous Registry account. Snapshots are never deleted.
Why versions matter
An attestation’s payload records theregistryVersion it was signed under, and verification uses exactly that snapshot’s keys and redundancy buffer, even if newer versions exist. So:
- A signature is checked against the node set that was active when it was signed.
- A round signed under an older version keeps verifying after the node set changes, as long as its timestamp is inside that version’s window.
Version lifetime
On EVM and Starknet, each version activates at the block timestamp of the transaction that published it; version
0, the empty constructor snapshot, activates at 0. Version v accepts payloads whose timestamp / 1000 lies in [activatesAt(v), activatesAt(v + 1) + 60]. A payload before activation fails with R_NOT_YET_ACTIVE. The latest version has no upper bound. See EVM result codes.
Because the EVM and Starknet check uses the payload timestamp, a round stamped inside the window keeps verifying later, while a retired node set cannot sign for new timestamps.
EVM and Starknet storage
Both registries cap the node set at 256 nodes (MAX_NODES = 256), matching the 256-bit signers bitmap, and use 0-based node indices: bit i is node index i of that version. Version 0 is the empty set.
- EVM. Each snapshot’s public keys, in index order, are one SSTORE2 blob. The contract keeps one packed entry per version (blob pointer, node count, redundancy buffer, activation time, latest flag) and one chained registry root per version.
- Starknet. Keys live in per-
(version, index)maps under one felt key (slot = version · 2^32 + index), plus one entry per version with node count, redundancy buffer, activation time and latest flag. Storage index0of each version holds the running plain-sum aggregate key; public indexisits at storage indexi + 1.
Changes
On Starknet the stored aggregate is updated by adding or subtracting the changed key. A node address is in one of three states: never registered, active or retired. A retired address cannot be registered again.
Solana storage
RegistryState(["molpha_registry"]) points at the current version.- Each version is its own
Registryaccount (["molpha_registry", version_u32_le]) with the orderedNodeaddresses (at most 256), node count, redundancy buffer (1 to 8),active_fromandgrace_active_until. - Signing keys live in per-operator
Nodeaccounts (["molpha_node", node_owner]), not in the snapshot. Bitirefers toregistry.nodes[i]. - Version
0is the empty genesis snapshot.
register_node, deactivate_node, reinstate_node, update_registry_policy and slash_offence each publish the next version. Removal is swap-remove, so positions change between versions. See Solana program.