Restrict fork choice getters to finalized blocks (#1475)

## Issue Addressed

- Resolves #1451

## Proposed Changes

- Restricts the `contains_block` and `contains_block` so they only indicate a block is present if it descends from the finalized root. This helps to ensure that fork choice never points to a block that has been pruned from the database.
- Resolves #1451
- Before importing a block, double-check that its parent is known and a descendant of the finalized root.
- Split a big, monolithic block verification test into smaller tests. 

## Additional Notes

I suspect there would be a craftier way to do the `is_descendant_of_finalized` check, but we're a bit tight on time now and we can optimize later if it starts showing in benches.

## TODO

- [x] Tests
This commit is contained in:
Paul Hauner
2020-08-14 06:36:38 +00:00
parent b0a3731fff
commit 619ad106cf
5 changed files with 352 additions and 120 deletions

View File

@@ -738,14 +738,25 @@ where
Ok(())
}
/// Returns `true` if the block is known.
/// Returns `true` if the block is known **and** a descendant of the finalized root.
pub fn contains_block(&self, block_root: &Hash256) -> bool {
self.proto_array.contains_block(block_root)
self.proto_array.contains_block(block_root) && self.is_descendant_of_finalized(*block_root)
}
/// Returns a `ProtoBlock` if the block is known.
/// Returns a `ProtoBlock` if the block is known **and** a descendant of the finalized root.
pub fn get_block(&self, block_root: &Hash256) -> Option<ProtoBlock> {
self.proto_array.get_block(block_root)
self.proto_array.get_block(block_root).filter(|block| {
// If available, use the parent_root to perform the lookup since it will involve one
// less lookup. This involves making the assumption that the finalized block will
// always have `block.parent_root` of `None`.
self.is_descendant_of_finalized(block.parent_root.unwrap_or(block.root))
})
}
/// Return `true` if `block_root` is equal to the finalized root, or a known descendant of it.
pub fn is_descendant_of_finalized(&self, block_root: Hash256) -> bool {
self.proto_array
.is_descendant(self.fc_store.finalized_checkpoint().root, block_root)
}
/// Returns the latest message for a given validator, if any.