EIP-6916 Auto-resetting testnet (Automatically Reset Testnet)
Final · Networking & nodes · EIP status Final · created 2023-04-10
A standard for testnets that automatically return to their initial state (genesis) after a set period. It lets clients compute a new genesis themselves and restart the network.
Why it is needed
Running a testnet for a long time causes problems to accumulate. Transaction history and state data keep growing, making it heavy to bring up a new node, and the faucet that hands out test coins runs out of funds. Even if the validator set grows bloated or a consensus problem arises, there is no way to roll back. This EIP standardizes periodically resetting the network to genesis. At each reset the validator set is emptied, funds return to the faucet, and the database stays small. Because each network's genesis is computed by a set rule, short-lived networks that come and go can be run repeatedly on a single test infrastructure. It can be used for short-term testing of applications and validators, and also as an environment for testing breaking changes in clients.
What changes
Today
- Old testnets accumulate state, making node sync and operation heavy
- Faucet funds run dry, making test coins hard to obtain
- Even if the validator set grows bloated or a consensus problem arises, there is no means of resetting
- Starting a new network requires manual work every time
After EIP-6916
- After a set period, the network automatically restarts from a new genesis
- At each reset the validator set is emptied and faucet funds are refilled
- The database stays small, so nodes are easy to bring up fresh
- Because genesis is computed by rule, clients find the latest network on their own
Who is affected
- App developers: You get an environment suited to short-term testing. However, contracts and state deployed before a reset are all lost, so it is not suited to long-term testing.
- Client teams: Clients must implement genesis generation (supported by default) and the auto-reset feature (full support). Depending on client architecture, an internal reset implementation can be difficult.
- Validator and infrastructure operators: Running always-on infrastructure such as bootnodes or genesis validators requires full support. If a client does not support reset, an external script can reproduce the same behavior.
- Light client: A design that assumes genesis_validators_root is fixed in advance does not work on this network.
In depth
Genesis iteration formula for execution clients
Only the initial genesis, genesis 0, is hardcoded in the client, and every later genesis is computed deterministically from it. The iteration count is i = int((current_slot_timestamp - genesis_0.genesis_time) / period). The current genesis time is current_genesis.genesis_time = period * i + genesis_0.genesis_time, and the current chain ID is chainId = genesis_0.chainId + i. Genesis 0 is used as is only in the first iteration, where i is 0. From i>0 it serves as the preimage from which the latest genesis is built. On startup, the client triggers generation of a new genesis if there is no stored genesis or if the current slot timestamp is later than current_genesis.genesis_time + period.
Consensus client: how to change the ForkDigest
The consensus layer (CL) also needs a configuration containing the iteration value, like the chain ID, plus an updated genesis state (SSZ). It is recommended to set MIN_GENESIS_TIME to the latest genesis time and to use a small GENESIS_DELAY of about 15 minutes to avoid problems during infrastructure restarts. For a reset to succeed, the ForkDigest must differ on every iteration, but ForkVersions are kept fixed for tooling compatibility. Instead, the first validator's withdrawal credentials are overwritten with genesis.validators[0].withdrawal_credentials = 0x0100000000000000000000000000000000000000000000000000000000000000 + i, and genesis.genesis_validators_root is recomputed as hash_tree_root(genesis.validators). Because the state changes this way, the ForkDigest of each iteration naturally differs.
Three ways to obtain the genesis state
Having the client generate the genesis SSZ itself lets it build the latest state without trust, but the implementation is complex. Reusing checkpoint sync is the recommended approach. When the testnet flag is on, the client automatically downloads the latest genesis state from a hardcoded checkpoint endpoint. If the user supplies a separate checkpoint flag, that endpoint takes priority. If checkpoint sync fails or is not supported, a fallback path downloads from a publicly hosted SSZ file URL. If the client has a generation feature, it verifies the values and checksum of the downloaded state and raises an error on mismatch. This approach is already used on the Holešky testnet and lets maintainers update the genesis validator set without a new client release.
Reset procedure
terminal_timestamp = current_genesis.genesis_time + period sets the network's expiry time. When the slot at that time is reached, the client stops producing and accepting blocks and shuts down p2p, beacon services and the execution environment. This halt feature is worth implementing even without the rest of the reset, because it alone can prevent fork incidents. The client then deletes the current genesis and all chain and beacon data (existing DB cleanup tools can be reused, and a flag such as --retain-ephemeral-data can support exporting data before deletion), calls the genesis function again to write the new genesis to the DB, and restarts the services. A full implementation must perform this process by itself, with minimal downtime and no manual restart. Clients that do not support graceful shutdown can reproduce the same behavior with external scripts and system tools instead of an internal reset.
Basic support and full support
This EIP splits client support into two levels. Basic support implements only the genesis function, enough to compute the current network specification and connect. It is sufficient for short-term testing, but to follow the next iteration users must stop the client and wipe the database themselves. Full support also implements the reset feature so the client automatically follows the latest chain iteration, which is needed for always-on infrastructure, genesis validators and bootnode operation. The design is also compatible with nodes managed by external tooling, so any client that supports custom networks can join the same network by resetting through scripts.
Relationship between reset period and validator count
period is a constant hardcoded in the client. It can be chosen to fit user needs, but for security it is tied to the number of genesis validators. Because validator activation takes time, the number of trusted validators must be large enough that a reset comes before a malicious actor can gain a majority of less than 66% of the network. According to the source, with 10,000 genesis validators the network is safe for up to 1289 epochs (5.7 days), with 50,000 for 6441 epochs (28.6 days), with 100,000 for 12877 epochs (57.2 days), and with 200,000 for 25764 epochs (114.5 days). The chain ID increases by 1 on every iteration to avoid replay attacks, so low chain ID values should be avoided so that it does not collide with other public EVM chains even after many iterations.
Limitations and caveats
Because the entire state is wiped on reset, this is not suited to testing long-lived, advanced applications. However, anyone can set up an off-chain mechanism that automatically deploys standard contracts after a reset. The fact that genesis_validators_root is not known in advance can also break some architectures, notably light clients that rely on hardcoding this value. On the security side, even if a vulnerability is exploited it disappears at the next reset, so it is recommended to keep the period short, on the order of weeks to months. The mechanism that triggers a reset must be strictly separated from any other network that is not configured as an ephemeral network. This EIP is a Standard whose status is finalized as Final.