Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Consensus protocol upgrade activation mechanism #6429

Closed
arhag opened this issue Dec 4, 2018 · 1 comment
Closed

Consensus protocol upgrade activation mechanism #6429

arhag opened this issue Dec 4, 2018 · 1 comment
Assignees
Labels
SNAPSHOTS Requires introducing a new version for snapshots and/or ends support for old versions of snapshots

Comments

@arhag
Copy link
Contributor

arhag commented Dec 4, 2018

This issue tracks the code changes needed to facilitate consensus protocol upgrades.

Signaling consensus protocol upgrade features

Consensus protocol upgrade changes are associated with a feature (called a "consensus protocol upgrade feature") recognized by nodeos. Each feature will have an associated 256-bit digest that uniquely identifies it. There are two classes of consensus protocol upgrade features: those that require pre-activation via an intrinsic and those that do not.

A consensus protocol upgrade feature is activated by signaling its activation in the block header through a new block header extension type called the "protocol feature activation" extension. This extension type (which will be discussed in more detail below), includes the 256-bit digests of consensus protocol upgrade features to be activated at the start of that block.

There are constraints on whether a consensus protocol upgrade feature (of either class) can be activated:

  • the nodeos software must be configured to recognize and accept the feature;
  • and, any dependencies of the feature must have already been activated.

Furthermore, a consensus protocol upgrade feature of the class that requires pre-activation has further requirements:

  • activation of the feature, signaled through the block header extension, is disallowed if the same feature has not already been pre-activated via an intrinsic;
  • any block building on a block that included pre-activation of a feature must signal activation of that feature in its block header extension otherwise it is an invalid block.

Most consensus protocol upgrade features will likely be of the type that require pre-activation. Consensus protocol upgrade features that do not require pre-activation have the characteristic that any one of the active block producers can initiate the activation of the feature. The other block producers could still ignore that block if they were not ready to accept activation of the feature, but that is a subjective producer policy decision that would have to be coded into the nodeos software that the block producer was running. One type of subjective policy decision that will be formalized as part of this mechanism, however, is to optionally reject activation of features if they occur before a locally specified time known as the "earliest allowed activation time".

Having a type of consensus protocol upgrade feature that requires pre-activation allows the subjective policy decision by each producer to be replaced by an objective policy that runs on the blockchain. A system contract action with strict authorization requirements can use a special intrinsic to pre-activate the feature; and block producers can use, for example, the eosio.msig contract to satisfy the authority of that system contract action.

However, there is still an important use case for consensus protocol upgrade features that do not require pre-activation. For example, if the community needs to execute a consensus protocol upgrade to change the producer schedule in a situation in which all producers are down and for some reason will not be coming back up, it should be possible for nodes that understand that consensus protocol upgrade feature to accept a block produced by a producer outside of the current producer schedule as long as the block activates the feature and the producer is the appropriately scheduled producer for the given time slot under the new producer schedule. It would not be possible to pre-activate such a consensus protocol upgrade feature in the scenario when all producers are down since no blocks would be produced to execute the action that calls the pre-activation intrinsic.

"Protocol feature activation" block header extension type

This new mechanism also introduces a "protocol feature activation" extension type within block header extensions.

Currently, no extensions are allowed in the block header. This change would allow a single block extension as long as it follows the rules of a well-formed "protocol feature activation".

For a "protocol feature activation" extension to be well-formed it must have a uint16_t type value of 0 and its payload data must be the serialization of a vector of distinct 256-bit digests (the digests do not need to be in any particular order, but they must not repeat).

If further extension types are added in the future, the following constraints should still apply: at most one well-formed "protocol feature activation" extension is allowed in the vector of block extensions, and if a "protocol feature activation" extension is present, it should be the first item in the vector of extensions.

Note that the "activation set" will actually be stored in the block_header_state rather than in the ChainBase database. Changing the definition of block_header_state means that a new chain_snapshot_header version is necessary (e.g. version 2).

Pre-activating consensus protocol upgrade features

Some consensus protocol upgrade features will require pre-activation and some will not. Either way, it is possible to pre-activate a feature assuming the following conditions hold:

  • the nodeos software must be configured to recognize and accept the feature;
  • the associated 256-bit digest is not already in the "pre-activation sequence" (a sequence of 256-bit digests stored in the ChainBase database, likely in the global_property_object) nor in the "activation set";
  • and, the 256-bit digests of any dependencies of the feature must already exist in the union of the "activation set" and the set comprised of elements in the "pre-activation sequence".

If a feature is successfully pre-activated (this would be initiated by a special privileged intrinsic), then its associated 256-bit digest is added to the end of the "pre-activation sequence".

Activating consensus protocol upgrade features

When computing the next block_header_state, if the block header has one well-formed "protocol feature activation", the computation should start with an empty "pending activation set" and then go (in order) through the sequence of 256-bit digests deserialized from the payload data of the "protocol feature activation" extension, and for each do the following sequence of operations:

  1. If nodeos software is not configured to recognize the digest as that of a valid consensus protocol upgrade feature it accepts, then reject the block.
  2. If the pending block time is earlier than the "earliest allowed activation time" of the feature, reject the block.
  3. If the digest already exists in the "activation set" (or also in the "pending activation set" if sequence of digests has not already been vetted to not have repeats), reject the block.
  4. The 256-bit digests of any dependencies of the feature must all already exist in the union of the "activation set" and "pending activation set"; otherwise reject the block.
  5. Add the digest to the "pending activation set".

If this is computing the next block_header_state within the fork database, it should also then merge the "pending activation set" into the "activation set" of the newly created block_header_state. However, the merge should not occur if this a pending block_header_state generated within the start_block function.

At the start of a block, prior to executing the onblock transaction, if a non-empty vector of feature digests is provided to the start_block function, then the controller logic must first ensure the above 5 steps have already occurred and then it must go (in order) through the sequence of 256-bit digests in this provided vector, and for each do the following sequence of operations:

  1. If the digest is of a feature of the class that requires pre-activation, assert that the digest is in the "pre-activation sequence" (reject the block if the assertion fails).
  2. Run the trigger function (if one exists) for the feature associated with the digest. If the trigger function fails, reject the block (and make sure any state changes done in the trigger functions are reverted).
  3. Add the digest to the "activation set" of the pending block_header_state.
  4. If the digest exists in the "pre-activation sequence", remove the digest from the "pre-activation sequence" and shift any remaining items in the sequence accordingly.

Regardless of what vector was passed into the start_block function, after the above, assert that the "pre-activation sequence" is empty. If the assertion fails, any state changes that may have been done since the start of the block should be undone and the block should be rejected.

The producer plugin would need to be modified to pass a vector of feature digests consisting of at least the digests (in order) of the "pre-activation sequence", otherwise it would not be able to start a new block after pre-activation of a feature. However, the producer plugin would be free to add additional digests of consensus protocol upgrade features to the beginning of this vector in order to activate consensus protocol upgrade features that do not require pre-activation and that were not already pre-activated. The set of digests to add would be determined from RPC calls made through the producer_api_plugin.

Checking if a feature is activated

An internal function is necessary to check if a particular feature (identified by digest) is in the "activation set". This function is mostly intended to be used by the native blockchain logic to adjust behavior according to whether a particular consensus protocol upgrade feature has been activated or not. It would also be used to implement a new intrinsic which allows contracts to query whether a feature has been activated or not.

@arhag arhag added the SNAPSHOTS Requires introducing a new version for snapshots and/or ends support for old versions of snapshots label Dec 4, 2018
@arhag arhag self-assigned this Dec 4, 2018
arhag added a commit that referenced this issue Jan 30, 2019
arhag added a commit that referenced this issue Feb 16, 2019
arhag added a commit that referenced this issue Feb 20, 2019
arhag added a commit that referenced this issue Feb 23, 2019
arhag added a commit that referenced this issue Feb 25, 2019
@arhag
Copy link
Contributor Author

arhag commented Mar 26, 2019

Resolved by #6831.

@arhag arhag closed this as completed Mar 26, 2019
@wanderingbort wanderingbort mentioned this issue Apr 1, 2019
3 tasks
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
SNAPSHOTS Requires introducing a new version for snapshots and/or ends support for old versions of snapshots
Projects
None yet
Development

No branches or pull requests

1 participant