This EIP proposes a specification for an automatically reset testnet, a novel approach to testnets that 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.
A testnet which automatically resets 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 the 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 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 the addition of the start time of that genesis MIN_GENESIS_TIME
and the testnet lifetime period
, where period
is a constant defining the length of time a single ephemeral network runs. Therefore, once the current slot timestamp reaches the terminal time of the ephemeral network, it has to switch to a new genesis. The main changes in each new genesis iteration are chainId, genesis time and the withdrawal credentials of the first validator.
Clients shall include a hardcoded genesis 0
, much like other networks predefined in clients. However, this genesis shall be used directly, only at the very beginning of the testnet's existence, in its first iteration where i
equals 0
. Later on, with iteration i
equal to 1
and above, the client does not initialize this genesis but uses it to derive the current one. When i>0
, given a known period
and current slot timestamp, the 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 slot timestamp is older than current_genesis.genesis_time + 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:
i
= int((current_slot_timestamp
- genesis_0.genesis_time) / period)
current_genesis.genesis_time
= period
* i
+ genesis_0.genesis_time
chainId
= genesis_0.chainId
+ i
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 time 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.
genesis.validators[0].withdrawal_credentials
= 0x0100000000000000000000000000000000000000000000000000000000000000
+ i
genesis.genesis_validators_root
= hash_tree_root(genesis.validators)
The update of genesis.validators[0]
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 obtain 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:
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 which the client must implement in order to be able to automatically follow the latest network iteration.
For the reset function, we can introduce the terminal_timestamp
value which defines the network expiry time of an iteration. It can be the same as the genesis time of the next iteration (without the genesis delay) or can be calculated simply as terminal_timestamp = current_genesis.genesis_time + period
.
When the network reaches a slot with a timestamp >= terminal_timestamp
:
--retain-ephemeral-data
, which would first export the existing data in a standard format before removing the databaseFor a full reset implementation, clients should be able to perform the above actions without requiring manual restart, operating the network fully independently and with minimal downtime.
Note that depending on the client architecture, it may not be feasible to fully implement such an internal reset mechanism, e.g. if the client doesn't support a graceful shutdown. The reset feature is considered an advanced level of support and is mainly needed by infrastructure providers and genesis validators. The assumption is that even if the client doesn't implement reset, advanced users can achieve similar behavior with external scripts handling the client by system tools.
Ephemeral testnets with deterministic parameters provide a sustainable alternative to traditional testnets, with the same infrastructure. At each reset, the validator set is cleared, faucets are filled again and the database is kept small.
Upon reset the whole state is purged, which, on the one hand keeps the network small and easy to bootstrap but introduces problems for testing longer term / advanced applications. However, basic contract infrastructure can be automatically deployed after each reset by any user. 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 mechanisms for Genesis and Reset, this EIP enables two levels of how a client implementation can support the testnet;
The design is also compatible with nodes managed by external tooling, i.e. even if the 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 set out below.
The period
is a constant, hardcoded in the client defining the period of time after which the 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 incrementation (+1). The ChainId in genesis 0
is a hardcoded constant. This constant is used by the client with each new genesis to derive a new ChainId for that network iteration.
New ChainIds shouldn't collide with any other existing public EVM chain even after many iterations. Consequently, low ChainId values are discouraged.
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 to keep periods relatively short (weeks/months opposed to months/years) with a 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 together with standard security procedures. Especially the mechanism for triggering reset which must be separated from other networks that are not configured as ephemeral.
Copyright and related rights waived via CC0.