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 <yacov.manevich@avalabs.org>