Replies: 4 comments 9 replies
-
How do we want to resolve the auditors concerns about checkpoint vs full verification syncing? It might help to change the state request names (and related functions, variables, comments) to something like:
Anyone have better names? Which names do you prefer? Is there anything else we could do to make this code clearer? |
Beta Was this translation helpful? Give feedback.
-
Here is some of the confusion in this auditor note that we should resolve in our documentation:
This is the core of the confusion:
All valid finalized blocks are saved to disk, that's what finalization means in Zebra. Saving to disk is not under user control, and it's not a choice the application makes Non-finalized blocks are saved to disk if they are part of the best chain, and beyond the rollback limit. If they are not part of the best chain and beyond the rollback limit, they are dropped.
To do contextual validation, the state service will:
Breadth-first order is not guaranteed, because a lower height block from another fork can arrive at any time. Forks are allowed from the finalized tip, and any non-finalized block.
The 28 most recent ancestor blocks must have been validated and committed by the state, regardless of whether they are finalized or non-finalized.
This is incorrect, due to the confusion above. Verification OrderThe Zebra implementation chooses to verify blocks using checkpoints or semantic/contextual verification, based on their heights and its checkpoints. Checkpoint verification happens in strict height order, in both Semantic verification happens in parallel in the Guaranteed Chain ContextSo blocks are not validated by the state until all their ancestors have been validated. If a contextually verified block's ancestors aren't validated, it will wait in the queue and timeout, or be rejected with an error when it is received by the block write task. So No Cross-Module DependenciesIn most cases, the syncer or gossip downloaders will reject blocks that are too far in front of the tip. This prevents CPU and memory denial of service. But peers can't make Zebra panic by submitting blocks out of order, even if they convince these services to submit those blocks by the state. If that happens, the state will timeout or reject the block. |
Beta Was this translation helpful? Give feedback.
-
@arya2 @upbqdn and @oxarbitrage any thoughts on this discussion? :) |
Beta Was this translation helpful? Give feedback.
-
The audit is over and all fixes have been implemented |
Beta Was this translation helpful? Give feedback.
-
This note is mainly a discussion around
zebra-state
’s handling of finalized block state. The Zebrad application’sstart
command spawns the Syncer service which will continuously request chain tips and blocks from the peers until it downloads and verifies enough history of the chain to be able to validate blocks. It obtains some prospective tips and iteratively tries to extend them and download the missing blocks. In the snippet below, the Syncer’sdownload_and_verify()
function rejects blocks that are more thanMAX_BLOCK_REORG_HEIGHT
(99) blocks from the tip height:zebra/zebrad/src/components/sync/downloads.rs
Lines 364 to 377 in 5a88fe7
Then the Syncer uses a clone of the
ChainVerifier
to verify the newly downloaded block, which for blocks below the latest configured checkpoint height will use theCheckpointVerifier
instead of full block verification. TheCheckpointVerifier
will not process blocks beyond the target checkpoint until it receives all the required blocks that it needs in order to be able to verify the blocks that chain back to the previous checkpoint. In the snippet below, theCheckpointVerifier
uses the state service to contextually verify the block and commit it to the finalized state:zebra/zebra-consensus/src/checkpoint.rs
Lines 980 to 1002 in 5a88fe7
Note that a checkpointed/finalized block can be a settled network upgrade or a block beyond the rollback/reorg limit. The state service processes the finalized block and queues it to be committed to state (finalized blocks can be optionally saved to disk.). The state service will not commit any non-finalized blocks until the finalized blocks’ queue is fully drained and committed:
zebra/zebra-state/src/service.rs
Lines 639 to 662 in 5a88fe7
Once the finalized block writer is finished, the state service will validate and commit the non-finalized queued blocks whose parents have recently arrived in breadth-first ordering (lowest to highest heights). Thus, when
validate_and_commit_non_finalized()
calls thecheck::initial_contextual_validity()
for the first time there are some finalized blocks in the state to be used to validate the block’s difficulty threshold and timestamp. Theassert_eq!()
check below expects at least 28 blocks in the relevant chain:zebra/zebra-state/src/service/check.rs
Lines 85 to 97 in 5a88fe7
For the first non-finalized block to be validated there must be at least 28 blocks in the finalized state. If an honest node fails to obtain enough finalized blocks from its peers during syncing, an attacker could send it a non-finalized block to verify, which will fail this assertion and crash the Zebra node.
A relevant issue (“On startup, check that the finalized state blocks match the checkpoint
hashes”) was fixed by the maintainers after the audit branch was cut. It ensures that, on startup, the Zebrad node would not indefinitely follow a forked chain that does not include the socially accepted checkpoints.
Beta Was this translation helpful? Give feedback.
All reactions