-
Notifications
You must be signed in to change notification settings - Fork 4
Description
Supporting Non-Validator Nodes
This medium-level design document outlines the objectives, background, and key considerations for supporting non-validator nodes. It also proposes a clear implementation approach to achieve the desired functionality and outcomes.
What is a non-validator?
A non-validator is a node that does not participate in consensus but still receives consensus messages in order to track the current state of the network.
Examples include:
-
API nodes, which serve information about confirmed transactions and blocks.
-
Full nodes, which maintain the blockchain state at specific heights but do not vote in consensus.
Although these nodes do not contribute to consensus, they must remain fully synchronized with finalized blocks and validator set changes.
Goal
Simplex currently supports validators through the Epoch implementation and will soon support a multi-epoch configuration.
However, running an instance of Epoch requires participating in consensus, which non-validator nodes are not required to do. At a high level, non-validator nodes should: Sync and replicate only finalized blocks and their corresponding finalization messages. Non-validator nodes must also synchronize finalizations spanning multiple epochs (i.e., blocks signed by different validator sets).
Per the reconfiguration spec, the epoch number of a block is equal to the block sequence of the sealing block from the previous epoch.
Given a block, the sealing block that sealed the previous epoch can be located by checking the epoch number of the block.
A sealing block of an epoch encodes the validator set of the next epoch.
Bootstrapping
At startup:
-
The non-validator is configured with a set of bootstrapping NodeIDs.
-
It queries these nodes for their latest sealing block by fetching the latest block and determining the sealing block's sequence.
-
Once it receives at least
f + 1identical sealing blocks, it can safely treat that sealing block as correct.
Recursively Fetching Sealing Blocks
This provides a backward pointer mechanism:
- The sealing block of an epoch contains the sequence number of the previous sealing block.
- Using this pointer, we can recursively fetch prior sealing blocks
- This continues until we reach the ever first Simplex block, which its predecessor is either a genesis block or the last Snowman block.
At this stage, the node reconstructs the full chain of sealing blocks across epochs in memory(sealing block hashes or full block).
Fetching Blocks Within Epochs
Once sealing blocks are obtained, blocks within each epoch can be fetched and indexed in parallel. However, verification and execution must be done in sequence order. We can bound the number of concurrent tasks(tasks fetching blocks for epochs) to avoid memory pressure. When we index a block, we should check if its the next to verify. The epoch block processing task will be marked as complete once all sequences within it have been indexed(re-send requests if necessary).
Summary of steps
- Startup
- Broadcast our latest known epoch and block.
- If behind, peers respond with their latest block.
- Obtain the sealing block's sequence from the latest block.
- Fetch the sealing block
- Sealing Block Verification
- After receiving
f + 1identical sealing blocks, treat it as valid. - Recursively fetch prior sealing blocks until reaching the first ever Simplex block. Then, fetch the previous block which is either:
- Genesis.
- The last snowman block.
- After receiving
- Block Replication
- Spawn bounded concurrent workers to replicate blocks per epoch.
- Index blocks immediately upon receipt.
- Verify only when the block is the next expected sequence.
- Complete an epoch once all sequences are indexed.
- **Normal Processing & Future Handling **
- Once sufficiently caught up, process blocks and finalizations normally.
- If a higher epoch is observed, repeat the sealing block synchronization process.