-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
1 changed file
with
140 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
--- | ||
eip: 6916 | ||
title: Automatically Reset Tesnet | ||
description: A testnet network that periodically rolls back to genesis | ||
author: Mário Havel (@taxmeifyoucan), pk910 (@pk910), Rémy Roy (@remyroy) | ||
discussions-to: https://ethereum-magicians.org/t/automatically-reset-testnet/15825 | ||
status: Draft | ||
type: Standards Track | ||
category: Core | ||
created: 2023-04-10 | ||
--- | ||
|
||
## Abstract | ||
|
||
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. | ||
|
||
## Motivation | ||
|
||
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. | ||
|
||
## Specification | ||
|
||
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. | ||
|
||
### Genesis | ||
|
||
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 `MIN_GENESIS_TIME` and `period` where `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. | ||
|
||
#### Execution client | ||
|
||
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: | ||
* `i` = `int((latest_timestamp` - `genesis_0.timestamp) / period)` | ||
* Timestamp of current genesis: | ||
* `genesis_timestamp` = `period` * `i` + `genesis_0.timestamp` | ||
* Current EL ChainId: | ||
* `chainId` = `genesis_0.chainId` + `i` | ||
|
||
#### Consensus client | ||
|
||
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. | ||
* `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 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. | ||
|
||
### Reset | ||
|
||
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 `>= terminal_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. | ||
|
||
## Rationale | ||
|
||
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. | ||
|
||
### Network parameters | ||
|
||
Constants and variables defining testnet properties are arbitrary but need to be crafted considering certain limitations and security properties. | ||
|
||
#### Reset Period | ||
|
||
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 | ||
|
||
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. | ||
|
||
## Security Considerations | ||
|
||
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 | ||
|
||
Copyright and related rights waived via [CC0](../LICENSE.md). |