Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unify engines #3405

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Unify engines #3405

wants to merge 1 commit into from

Conversation

yacovm
Copy link
Contributor

@yacovm yacovm commented Sep 19, 2024

Why this should be merged

The lifecycle of an avalanchego node can be separated to three main stages:

Stage I - If supported by the VM, then a state sync occurs. Otherwise, this stage is skipped.
In the X-chain, this stage is entirely substituted by a custom bootstrapping phase that replicates and executes the X-chain DAG.

Stage II - A stage called bootstrapping, which entails replicating the blocks from other avalanchego nodes, and executing them.

Stage III - The final form of an avalanchego node, in which it runs the snowman consensus protocol.

The phases are implemented by components called "engines":

  • avalanche bootstrapping
  • snowman
  • state syncer
  • snowman bootstrapper

And the handler in snow/networking/handler/ is responsible to route messages from the network into the correct engine.
Engines all implement the same common.Engine interface, but the interface consists of the union of all operations across all engines.

Indeed, it is often the case that a message of type m dispatched by engine e, cannot be processed by a different engine e'.
For instance, a Chits message cannot be processed by any engine other than consensus, and a message about a query of state summary is only relevant to the state sync engine.

To that end, each engine simply implements a no-op dispatcher for messages it does not care about.

The biggest problem with the existing aforementioned structure, is that the lifecycle of the engines imposes a strict one way movement across the various stages,
and there is no single component which consolidates the transition among the stages. The movement between the various stages takes place by a callback given to each
engine at every stage but the final one (Stage I and Stage II).

The structure therefore makes it difficult to introduce movement from snowman consensus back to bootstrapping / state sync, or to have better control over the message dispatch.

This commit unifies all engines into a single one under snow/engine/unified

As a result, the implementation of the handler in snow/networking/handler/handler.go is now simpler,
as it only interacts with the unified engine, and it never needs to query the snow.EngineState.

The state transition between the various stages is now taken care of by the unified engine, and since the code to dispatch messages to the right engine
is now all in the unified engine, it's not only more testable but it lets us move among the stages in the same place where we consider the stage we're in to dispatch
the message to the correct engine.

How this works

Just a refactoring: I shrinked the interfaces of the engines to what is absolutely required and now only the unified engine implements the common.Engine. Removed un-necessary code from the handler package and moved the logic into the unified engine.

How this was tested

CI.

@yacovm yacovm marked this pull request as draft September 19, 2024 21:26
@yacovm yacovm self-assigned this Sep 23, 2024
@yacovm yacovm force-pushed the unifiedEngine branch 19 times, most recently from 788480d to 9d6c351 Compare October 13, 2024 20:55
@yacovm yacovm force-pushed the unifiedEngine branch 4 times, most recently from 92df2c8 to fd73ebb Compare October 15, 2024 22:06
@yacovm yacovm marked this pull request as ready for review October 16, 2024 12:02
@yacovm yacovm requested a review from marun as a code owner October 16, 2024 12:02
The lifecycle of an avalanchego node can be separated to three main stages:

Stage I - If supported by the VM, then a state sync occurs. Otherwise, this stage is skipped.
In the X-chain, this stage is entirely substituted by a custom bootstrapping phase that replicates and executes the X-chain DAG.

Stage II - A stage called bootstrapping, which entails replicating the blocks from other avalanchego nodes, and executing them.

Stage III - The final form of an avalanchego node, in which it runs the snowman consensus protocol.

The phases are implemented by components called "engines":

- avalanche bootstrapping
- snowman
- state syncer
- snowman bootstrapper

And the handler in snow/networking/handler/ is responsible to route messages from the network into the correct engine.
Engines all implement the same common.Engine interface, but the interface consists of the union of all operations across all engines.

Indeed, it is often the case that a message of type `m` dispatched by engine `e`, cannot be processed by a different engine `e'.
For instance, a Chits message cannot be processed by any engine other than consensus, and a message about a query of state summary is only relevant to the state sync engine.

To that end, each engine simply implements a no-op dispatcher for messages it does not care about.

The biggest problem with the existing aforementioned structure, is that the lifecycle of the engines imposes a strict one way movement across the various stages,
and there is no single component which consolidates the transition among the stages. The movement between the various stages takes place by a callback given to each
engine at every stage but the final one (Stage I and Stage II).

The structure therefore makes it difficult to introduce movement from snowman consensus back to bootstrapping / state sync, or to have better control over the message dispatch.

This commit unifies all engines into a single one under snow/engine/unified

As a result, the implementation of the handler in snow/networking/handler/handler.go is now simpler,
as it only interacts with the unified engine, and it never needs to query the snow.EngineState.

The state transition between the various stages is now taken care of by the unified engine, and since the code to dispatch messages to the right engine
is now all in the unified engine, it's not only more testable but it lets us move among the stages in the same place where we consider the stage we're in to dispatch
the message to the correct engine.

Signed-off-by: Yacov Manevich <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant