This is an update describing a new mechanism for hard-forking protocol upgrades that will be used after Lima.
All the hard forks have been scheduled so far. Lima hard fork is going to be the last scheduled hard fork, after that, there will be just community hard forks. It means that Aeternity will provide implementation of new features (some of which will be consensus breaking) and let miners decide whether they want to upgrade to a new consensus protocol or stay with the current one.
It is done in a form of voting where key blocks produced by the miners will include a certain signal showing whether they support the new consensus protocol. If the number of key blocks that include a predefined signal within a predefined signalling interval (between two block heights), a node will upgrade to the new consensus protocol at the end of the signalling interval.
--- [ ] --- ... --- [ ] --- ... --- [ ] --- [ ] --- H1 HS HE - 1 HE
H1 is a height at which a node has protocol
HS is a signalling interval start (inclusive)
HE is a signalling interval end (exclusive)
The new consensus protocol must be strictly greater than
C1. At height
HS we assume that all the nodes willing to participate in the miner signalling are updated to the version able to signal and follow the new consensus protocol.
HE - 1 is the last signalling block and fork happens (depending on the signalling outcome) at height
HE. The hard fork happens per chain fork:
[ ] --- [ ] --- [ ] --- v5 <--- High difficulty | --- [ ] --- ... --- [ ] --- ... --- [ ] --- [ ] --- v4 <--- Low difficulty H1 HS HE - 1 HE
If there was a fork within the signalling interval, there could be multiple competing chains with different signalling outcomes at
HE. The decision whether the chain upgraded to the consensus protocol can be made after the chain reasonably settles (after
The work on miner signalled consensus started at the end of July/beginning of August. First, we had to identify where we tried to get a protocol version from block height. Since there were just scheduled hard forks, there was no doubt what protocol version was supposed to be effective at a certain height. However, this changed with community forks, now it’s not possible to determine which protocol is effective at a given height (after Lima), because it depends on the fork signalling outcome. Therefore, we had to refactor a lot of code that assumed a protocol version from height. The implementation was split into two parts: code refactoring and signalling outcome computation.
The core of this work was mostly getting rid of the calls to
aec_hard_forks:protocol_effective_at_height/1 function which returns a protocol at a given height. For example, this function had to be removed from the sync - imagine a situation where community fork may happen at height 1000 and the local node’s chain is at height 999, the sync receives a block with height 1010. The sync at this point doesn’t know what the protocol version will be at height 1010 so getting the protocol from height isn’t relevant.
The refactoring PRs: PR #2678, PR #2686, PR #2697, PR #2705, PR #2760, PR #2763, PR #2769, PR #2774, PR #2778, PR #2793, PR #2800, PR #2802, PR #2804, PR #2837, PR #2847. The result of the refactoring was that the function for getting the protocol from height can be used only when:
- a new block is being added to the chain;
- a new key block candidate is prepared.
Signalling outcome computation
At first we developed a mechanism that used asynchronous workers to compute the signalling outcome per chain fork. This implementation made it possible to change the configuration of fork signalling, restart the node and return the correct result per given configuration. Although, the rest of the developers decided it could be done another way when we don’t allow changes of the configuration for
ae_uat so the users won’t make accidental mistakes.
The second mechanism for computing of the signalling outcome uses a separate database table where it aggregates the count of the predefined signal per key block within the signalling interval.
This part also includes changes of the configuration. For
ae_uat, it’s possible to use
fork_management > fork > enabled which can be set to
false. It indicates that the node will follow the fork signalling outcome (
true) or stay with the current protocol (
false). If the configuration is missing, the default value is
true. The other environments (different form the mainnet and testnet) may use the full configuration, for example:
enabled: true signalling_start_height: 1000 signalling_end_height: 2000 # How many blocks at least must include signal to make new protocol active. signalling_block_count: 900 # The signal value (it's part of key block header - info field). info_field: 1234 # The new protocol version. version: 5
The signalling using the key block header field
info is backward compatible, as the meaning of the value of such field is not under consensus.
The activation of the new consensus protocol based on miner signalling is meant to be a temporary measure during the time interval when the new protocol may be activated on the network while the node is running. Once the network reasonably settles on whether to activate the new consensus protocol, the user is meant to enforce such decision on the eventual node restart either by configuration or by upgrading the node to a new version.