snarkVM
snarkVM copied to clipboard
[Feature] Add API to pre-process blocks
Motivation
The goal of this PR is to help with some of the block sync improvements and also remove code from snarkOS that duplicates functionality from snarkVM. The snarkOS PR is not ready yet, but this change is already ready to be merged and does not break any existing functionality or APIs.
More concretely, the PR adds an API to only check a block's subDAG, not its content. This is needed, because during sync we can apply a block to the ledger only once a subsequent block contains enough votes. This prevents us from fully verifying the block because those in-depth checks require an updated state root in the ledger. We also don't need to verify the block content to know if it is valid, because at sync we can determine the validity of a block from the DAG, i.e., when there are sufficient votes.
As of now, there is around 100 lines of code in snarkos-node-bft that I hope we can remove after this change is made.
This will prevent future bugs where the DAG checks in VM and OS might not match.
The API allows checking a block's DAG against a chain of pending blocks. This is needed, because there can be a series of blocks that do not contain sufficient votes. While this does not happen much in practice, it is possible to have a sequence of dozens of pending blocks.
This new API also lay the groundwork for light clients, which would only verify the DAG and track validator stake.
API Design
One design decision is to introduce a new type PendingBlock, which represents a block that has its DAG checked but none of its contents (transactions, state, etc.).
The idea is to use the type system to force proper API usage. Either, you call Ledger::check_next_block like before, or you first call Ledger::check_block_subdag and then Ledger::check_block_content.
In the latter case, Ledger::check_block_subdag will return a PendingBlock and Ledger::check_block_content expects a PendingBlock as its input.
I similarly would like Ledger::check_next_block to return something like a VerifiedBlock and have Ledger::advance_to_next_block only accept such a VerifiedBlock, but did not want to break any existing API.
Testing
A large chunk of this PR is adding tests for the pending block logic. It also these as integration tests as the tests only touch the public API and ledger/src/tests.ts is already over 3600LOC. It might be good to move more of the tests to integration in the future.
For this new feature, there is only one test. It builds a DAG with a series of blocks that did not receive sufficient votes and check that preprocessing a chain of pending blocks works as expected.