flow-go icon indicating copy to clipboard operation
flow-go copied to clipboard

[Access] Create a VersionControl module for tracking VersionBeacon events

Open peterargue opened this issue 1 year ago • 1 comments

Access nodes need to consume VersionBeacon events to identify which blocks they can safely execute scripts against.

Currently, execution nodes consume these events within their StopControl (https://github.com/onflow/flow-go/blob/538e72ed6d36c017002eb5b49c3846c35c2c0385/engine/execution/ingestion/stop/stop_control.go#L48) module, which is used to cause the EN to stop execution or crash when the target height is reached during a height coordinated upgrade (HCU). The existing implementations has a few limitations that make it unsuitable for the access node:

  1. It’s tightly coupled to the execution usecase
  2. It only supports a “stop” height
  3. It only tracks the latest beacon, and has no concept of there the nodes current version fits in the beacon list.

The Access node usecase is quite different:

  1. Given the VersionBeacon events, identify which block range is compatible with it’s current version.
  2. For each script execution request, check if the request’s block is within the range of compatible blocks.
  3. If the node is compatible with the head of the chain, watch for new VersionBeacon events and update the compatibility range when a new version is announced.

Luckily, a system that meets the Access node’s usecase is also compatible with the Execution node’s, and could provide more control around version transitions.

VersionControl Module

The goal of the VersionControl module is to discover the range of blocks that are compatible with the node’s current version. Other components in the system can then query the control module for compatibility with a specific block, or subscribe to be notified when a version change height has been reached.

For example:

  • An Access node’s script execution engine could call CompatibleAtBlock() before executing a script to determine if the node’s current version is compatible with the version required for that block. An execution node could do the same before executing a block.
  • An Access node’s stop contoller could subscribe to version update events, and crash the node when the HCU height is reached. This enables automated upgrades similar to what’s used on ENs.

Startup

The module should accept the node’s current version semver as a constructor argument. The value should never change during runtime.

On start, it should walk the VersionBeacon events backwards from the latest finalized block until it discovers the first event who’s version is less than or equal to the node’s current version, using a semver comparison.

The VersionBeacon storage object has a method

https://github.com/onflow/flow-go/blob/11a67d951f8e0155f0becb59265bd4cd3f63e522/storage/badger/version_beacon.go#L27-L29

This can be called in a loop to walk backwards through each event. The flow.SealedVersionBeaconevents return from that Highest method include the height the

service event was sealed in. This height can be used to efficiently iterate through all events in the db without iterating over individual blocks.

At the end of the search, the module should know the

  • start height: the height where the network became compatible with the node’s current version
  • end height: the height where the network became incompatible with the node’s current version.

It’s possible for there to be no events for either or both of the range’s start and end heights.

  • If there’s no start, the node is compatible with all blocks strictly less than the end height
  • If there’s no end, the node is compatible with all blocks greater than or equal to the start height
  • If there are no VersionBeacon events, then the node is compatible with any block
  • If there is a start and end, the node is compatible with blocks between in the range [start, end)

If there is no end height, the module must continue monitoring for new VersionBeacon events, and updating its state when one is discovered.

Monitoring

The module should handle block finalized events. For each block, it checks if there are any new version beacon events using the same Highest(height uint64) (*flow.SealedVersionBeacon, error) method used during initialization.

When a new event is discovered, it’s stored locally in the module’s state for use during queries.

Notifications

When the module receives a block finalized notification for the end height, it should call the callback for all consumers. These consumers can then take any actions necessary (e.g. crash the node for automated ugprades)

API

The module should be a component.Component. There are 2 exported methods:

  • BlockFinalized(h *flow.Header): This is used by the consensus follower to notify consumers of new finalized block (see interface)
  • CompatibleAtBlock(height uint64) bool: This is called by the Access node’s script execution logic to determine if a script can be executed by the node at a given block height.
  • AddVersionUpdatesConsumer(func(height uint64, semver string)): This is called by a subscriber to receive notifications when a new upgrade height is reached.

peterargue avatar Apr 25 '24 23:04 peterargue

@Guitarheroua here's the initial design for the version control module. Take a look and get familiar with the existing StopControl module to get a sense the how it will go together. let me know if you have any questions

peterargue avatar Apr 30 '24 00:04 peterargue