A testnet network that periodically rolls back to genesis
|Authors||Mário Havel (@taxmeifyoucan), pk910 (@pk910), Rémy Roy (@remyroy)|
Table of Contents
This EIP proposes a specification for an automatically reset testnet, a novel approach to testnets which can be implemented within Ethereum clients. It enables a single testing infrastructure consisting of ephemeral networks with deterministic parameters. Each network iteration is created by a specified function which deterministically generates genesis states.
This kind of testnet can provide an alternative environment for short-term testing of applications, validators and also breaking changes in client implementations. It avoids issues of long running testnets which suffer from state bloat, lack of testnet funds or consensus issues. Periodically resetting the network back to genesis cleans the validator set and returns funds back to faucets while keeping the network reasonably small for easy bootstrapping.
The testnet is set to always reset after a predefined time period. The reset means generation of the next genesis, discarding the old one and starting a new network. This is possible by introducing functions for the genesis generation and the client reset.
To connect to the current instance of the network, the client must implement the genesis function. This function defines how the client stores information about the testnet and generates the current genesis. With each reset, the network starts from a new genesis which needs to be built based on given parameters and correspond in EL and CL clients. The main parameters iterated with each genesis are chainId, genesis timestamp and withdrawal credentatials of the first validator.
The network always starts from a genesis which is deterministically created based on the original one - this very first genesis is hardcoded and we can call it
genesis 0. Terminal time, the expiration of each genesis, is given by its
period is a constant defining the length of time a single ephemeral network runs. Therefore once the timestamp reaches the terminal time of the ephemeral network, it has to switch to a new genesis. The main changes in the genesis iteration are chainId, timestamp and the withdrawal credentials of the first validator.
Clients shall include a hardcoded
genesis 0, similarly to other networks predefined in clients. But this genesis is used directly only at the very beginning of the testnet existence, in its first iteration
0. Later on, with iteration
1 and further, the client does not initialize this genesis but uses it to derive the current one. When
i>0, given a known
period and current timestamp, client always calculates the number of lifecycle iterations from
genesis 0 and creates a new genesis with the latest parameters.
When the client starts with the option of an ephemeral testnet, it checks whether a genesis for the network is present. If it doesn’t exist or the current genesis timestamp is older than
genesis_timestamp + period, it triggers the generation of a new genesis. This new genesis, derived from
genesis 0, will be written to the database and used to run the current network.
The EL client includes the hardcoded
genesis 0 serving as a preimage for generating the current one. Iteration of variables is done as follows:
- Number of iterations:
genesis_0.timestamp) / period)
- Timestamp of current genesis:
- Current EL ChainId:
Genesis generation in the CL client includes iteration of values as in EL but also requires the updated genesis state. The state in SSZ format can be either generated by the client or downloaded from an external source. It includes validators with deposits ready to launch a merged network with the validator set created by trusted entities within the community.
MIN_GENESIS_TIME is set to the latest genesis timestamp and defines when the current period starts. It is recommended to add a small
GENESIS_DELAY, for example 15 minutes, to avoid issues while infrastructure is restarting with the new genesis.
To ensure a successful reset,
ForkDigest needs to be unique for each iteration. In order to keep the
ForkVersions of the network static for better tooling support, the withdrawal credentials of the first validator in the validator set need to be overridden by a calculated value.
The update of
genesis.validators changes the state, therefore, clients have to be able to generate or download the latest genesis state. Generating the genesis ssz is not considered a standard client feature and adding it enables to trustlessly create the latest genesis state at the price of certain complexity. An alternative solution is to obtaining it from a third party, either by downloading the ssz file from a server or using the checkpoint sync feature with an endpoint serving the genesis state. This became an accepted practice with Holešky testnet and the existing feature can be used for obtaining genesis states for automatically reset testnets. It also allows maintainers to update the genesis validator set without requiring new client releases. The full implementation of the recommended practice for obtaining the latest CL state should behave as follows:
- When the testnet flag is provided, automatically use the hardcoded checkpoint to download the latest genesis state using checkpoint sync feature
- If user provides a custom checkpoint sync flag, override the default option and use the endpoint provided by user
- Include a backup download option pointing to testnet releases which are publicly distributed and trigger this option if the checkpoint state sync fails
- If the client includes a feature for generating the genesis, use it to verify parameters in the downloaded state and issue an error if values don’t correspond
It’s important to note that
genesis_validators_root is normally predefined in the client but in this case it’s not known in advance which can potentially break certain architectures. For example light clients which are relying on hardcoded
genesis_validators_root won’t work.
The reset function defines an automatic process of throwing away the old data and starting with a new genesis. It depends on the previously defined function for genesis generation and client should implement it to be able to automatically follow the latest network iteration.
For the reset function, we can introduce the
terminal_timestamp value which marks when the network expires. It can be the same as genesis timestamp of the next iteration or can be calculated simply as
terminal_timestamp = genesis_timestamp + period.
When the network reaches a slot with a timestamp
- Client stops accepting/creating new blocks
- Shutdown client services running the network, e.g. p2p communication, beacon service, execution environment
- This feature should be implemented alongside Genesis even without further reset functions just to create a basic support which is always safe from forking
- Client calls a function which discards the current genesis, all chain or beacon data
- Clients include feature for purging the db and it might be useful here
- It’s recommended to include an additional flag, e.g.
--retain-ephemeral-data, which would first export the existing data before removing the database
- Client triggers the Genesis function (as defined above):
- Behaves like a regular client startup when genesis is not present
- New genesis is written into db and initialized
- Main network services are started again pointing to the updated genesis
- After new genesis time is reached, network starts again from the new genesis
Clients should be able to do this without manual restarting, operating the network fully independently and with minimal downtime. It’s possible that depending on the client architecture, it might not be feasible to fully implement, e.g. if the client doesn’t support a graceful shutdown. The reset feature is considered an advanced support and is mainly necessary for infrastructure providers, genesis validators, etc.
Ephemeral testnets with deterministic parameters and the same infrastructure provide a sustainable alternative to traditional testnets. At each reset, validator set is cleared, faucets are filled again and the database is kept small.
The whole state is purged which on one hand keeps the network small and easy to bootstrap but introduces problems for testing of advanced applications. Generally, using the network is recommended for short term testing, deploying
Hello World kinds of contracts that don’t need to stay forever on a long term testnet. However, there can be an offchain mechanism that automatically deploys standard contract primitives after each reset so application developers can also utilize the network more.
By defining two functions for Genesis and Reset, this EIP enables two levels of how a client implementation can support the testnet.
- Basic support requires the client to determine the current network specs and enables only connecting to the network.
- This means support of the Genesis function
- Enough to participate in the network for short term testing
- To follow the latest iteration, the user has to manually shut down the client and delete the database
- It’s still recommended to add a feature for terminating the network
- Full support enables client which can also follow the reset process and always sync the latest chain iteration
- This would require also support of the Reset feature
- Needed for running persistent infrastructure, genesis validators and bootnodes
- Might be more complex to implement due to client architure of clients
The design is also compatible with nodes managed by external tooling, i.e. even if client doesn’t implement these features, it can run on the same network as other nodes which are automatically reset by scripts. Any client supporting a custom network can be used for the testnet.
Constants and variables defining testnet properties are arbitrary but need to be crafted considering certain limitations and security properties.
Constant hardcoded in the client defining the period of time after which network resets.
It can be defined based on users’ needs but for security reasons, it also depends on the number of validators in genesis. Considering the time to activate a validator, the number of trusted validators should be high enough so the network cannot be overtaken by a malicious actor.
Genesis Validators => Epochs until < 66% majority 10k => 1289 Epochs (5,7 days) 50k => 6441 Epochs (28,6 days) 75k => 9660 Epochs (42,9 days) 100k => 12877 Epochs (57,2 days) 150k => 19323 Epochs (85,9 days) 200k => 25764 Epochs (114,5 days)
ChainId is a variable because it needs to keep changing with each new genesis to avoid replay attack. The function for the new ChainId value is a simple iteration (+1). The ChainId in
genesis 0 is hardcoded constant and network iterates it with new gensis.
It shouldn’t collide with any other existing EVM chain even after longer period of iterations.
The network itself is providing a secure environment thanks to regular resets. Even if some sort of vulnerability is exploited, it will be cleared on the next reset. This is also a reason why to keep periods relatively shorter (weeks/months opposed to months/years) with big enough genesis validator set to keep an honest majority.
Changes in clients caused by the implementation of features for resetting networks need to be reviewed with standard security procedures. Especially the mechanism for trigger reset which needs to be separated from other networks that are not configured as ephemeral.
Copyright and related rights waived via CC0.
Please cite this document as:
Mário Havel (@taxmeifyoucan), pk910 (@pk910), Rémy Roy (@remyroy), "EIP-6916: Automatically Reset Tesnet [DRAFT]," Ethereum Improvement Proposals, no. 6916, April 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-6916.