mirror of
https://github.com/sigp/lighthouse.git
synced 2026-07-05 13:54:36 +00:00
Fix syncing bugs by recursively attempting to process parents in the … (#429)
* Fix syncing bugs by recursively attempting to process parents in the import queue, change BlockRootsIterator * Swap from crossbeam channel to tokio mpsc * Recursion fix * Remove exess block processing * Fix network lag, correct attestation topic * Correct network poll logic * Overhaul of SimpleSync and modify BlockRootsIterator to return start_slot * Fix bug in tests relating to StateRootsIterator * Remove old, commented-out heartbeat code. * Tidy docs on import queue enum * Change source logging msg in simple sync * Rename function parameter in simple sync * Use `BestBlockRootsIterator` in `reduced_tree` * Update comments for `BestBlockRootsIterator` * Fix duplicate dep in cargo.toml
This commit is contained in:
@@ -41,31 +41,23 @@ impl<T: BeaconChainTypes> ImportQueue<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Completes all possible partials into `BeaconBlock` and returns them, sorted by increasing
|
||||
/// slot number. Does not delete the partials from the queue, this must be done manually.
|
||||
///
|
||||
/// Returns `(queue_index, block, sender)`:
|
||||
///
|
||||
/// - `block_root`: may be used to remove the entry if it is successfully processed.
|
||||
/// - `block`: the completed block.
|
||||
/// - `sender`: the `PeerId` the provided the `BeaconBlockBody` which completed the partial.
|
||||
pub fn complete_blocks(&self) -> Vec<(Hash256, BeaconBlock, PeerId)> {
|
||||
let mut complete: Vec<(Hash256, BeaconBlock, PeerId)> = self
|
||||
.partials
|
||||
.iter()
|
||||
.filter_map(|(_, partial)| partial.clone().complete())
|
||||
.collect();
|
||||
|
||||
// Sort the completable partials to be in ascending slot order.
|
||||
complete.sort_unstable_by(|a, b| a.1.slot.partial_cmp(&b.1.slot).unwrap());
|
||||
|
||||
complete
|
||||
}
|
||||
|
||||
/// Returns true of the if the `BlockRoot` is found in the `import_queue`.
|
||||
pub fn contains_block_root(&self, block_root: Hash256) -> bool {
|
||||
self.partials.contains_key(&block_root)
|
||||
}
|
||||
|
||||
/// Attempts to complete the `BlockRoot` if it is found in the `import_queue`.
|
||||
///
|
||||
/// Returns an Enum with a `PartialBeaconBlockCompletion`.
|
||||
/// Does not remove the `block_root` from the `import_queue`.
|
||||
pub fn attempt_complete_block(&self, block_root: Hash256) -> PartialBeaconBlockCompletion {
|
||||
if let Some(partial) = self.partials.get(&block_root) {
|
||||
partial.attempt_complete()
|
||||
} else {
|
||||
PartialBeaconBlockCompletion::MissingRoot
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes the first `PartialBeaconBlock` with a matching `block_root`, returning the partial
|
||||
/// if it exists.
|
||||
pub fn remove(&mut self, block_root: Hash256) -> Option<PartialBeaconBlock> {
|
||||
@@ -102,6 +94,8 @@ impl<T: BeaconChainTypes> ImportQueue<T> {
|
||||
block_roots: &[BlockRootSlot],
|
||||
sender: PeerId,
|
||||
) -> Vec<BlockRootSlot> {
|
||||
// TODO: This will currently not return a `BlockRootSlot` if this root exists but there is no header.
|
||||
// It would be more robust if it did.
|
||||
let new_block_root_slots: Vec<BlockRootSlot> = block_roots
|
||||
.iter()
|
||||
// Ignore any roots already stored in the queue.
|
||||
@@ -135,12 +129,8 @@ impl<T: BeaconChainTypes> ImportQueue<T> {
|
||||
/// the queue and it's block root is included in the output.
|
||||
///
|
||||
/// If a `header` is already in the queue, but not yet processed by the chain the block root is
|
||||
/// included in the output and the `inserted` time for the partial record is set to
|
||||
/// not included in the output and the `inserted` time for the partial record is set to
|
||||
/// `Instant::now()`. Updating the `inserted` time stops the partial from becoming stale.
|
||||
///
|
||||
/// Presently the queue enforces that a `BeaconBlockHeader` _must_ be received before its
|
||||
/// `BeaconBlockBody`. This is not a natural requirement and we could enhance the queue to lift
|
||||
/// this restraint.
|
||||
pub fn enqueue_headers(
|
||||
&mut self,
|
||||
headers: Vec<BeaconBlockHeader>,
|
||||
@@ -152,8 +142,10 @@ impl<T: BeaconChainTypes> ImportQueue<T> {
|
||||
let block_root = Hash256::from_slice(&header.canonical_root()[..]);
|
||||
|
||||
if self.chain_has_not_seen_block(&block_root) {
|
||||
self.insert_header(block_root, header, sender.clone());
|
||||
required_bodies.push(block_root);
|
||||
if !self.insert_header(block_root, header, sender.clone()) {
|
||||
// If a body is empty
|
||||
required_bodies.push(block_root);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,10 +155,17 @@ impl<T: BeaconChainTypes> ImportQueue<T> {
|
||||
/// If there is a matching `header` for this `body`, adds it to the queue.
|
||||
///
|
||||
/// If there is no `header` for the `body`, the body is simply discarded.
|
||||
pub fn enqueue_bodies(&mut self, bodies: Vec<BeaconBlockBody>, sender: PeerId) {
|
||||
pub fn enqueue_bodies(
|
||||
&mut self,
|
||||
bodies: Vec<BeaconBlockBody>,
|
||||
sender: PeerId,
|
||||
) -> Option<Hash256> {
|
||||
let mut last_block_hash = None;
|
||||
for body in bodies {
|
||||
self.insert_body(body, sender.clone());
|
||||
last_block_hash = self.insert_body(body, sender.clone());
|
||||
}
|
||||
|
||||
last_block_hash
|
||||
}
|
||||
|
||||
pub fn enqueue_full_blocks(&mut self, blocks: Vec<BeaconBlock>, sender: PeerId) {
|
||||
@@ -179,12 +178,22 @@ impl<T: BeaconChainTypes> ImportQueue<T> {
|
||||
///
|
||||
/// If the header already exists, the `inserted` time is set to `now` and not other
|
||||
/// modifications are made.
|
||||
fn insert_header(&mut self, block_root: Hash256, header: BeaconBlockHeader, sender: PeerId) {
|
||||
/// Returns true is `body` exists.
|
||||
fn insert_header(
|
||||
&mut self,
|
||||
block_root: Hash256,
|
||||
header: BeaconBlockHeader,
|
||||
sender: PeerId,
|
||||
) -> bool {
|
||||
let mut exists = false;
|
||||
self.partials
|
||||
.entry(block_root)
|
||||
.and_modify(|partial| {
|
||||
partial.header = Some(header.clone());
|
||||
partial.inserted = Instant::now();
|
||||
if partial.body.is_some() {
|
||||
exists = true;
|
||||
}
|
||||
})
|
||||
.or_insert_with(|| PartialBeaconBlock {
|
||||
slot: header.slot,
|
||||
@@ -194,28 +203,30 @@ impl<T: BeaconChainTypes> ImportQueue<T> {
|
||||
inserted: Instant::now(),
|
||||
sender,
|
||||
});
|
||||
exists
|
||||
}
|
||||
|
||||
/// Updates an existing partial with the `body`.
|
||||
///
|
||||
/// If there is no header for the `body`, the body is simply discarded.
|
||||
///
|
||||
/// If the body already existed, the `inserted` time is set to `now`.
|
||||
fn insert_body(&mut self, body: BeaconBlockBody, sender: PeerId) {
|
||||
///
|
||||
/// Returns the block hash of the inserted body
|
||||
fn insert_body(&mut self, body: BeaconBlockBody, sender: PeerId) -> Option<Hash256> {
|
||||
let body_root = Hash256::from_slice(&body.tree_hash_root()[..]);
|
||||
let mut last_root = None;
|
||||
|
||||
self.partials.iter_mut().for_each(|(_, mut p)| {
|
||||
self.partials.iter_mut().for_each(|(root, mut p)| {
|
||||
if let Some(header) = &mut p.header {
|
||||
if body_root == header.block_body_root {
|
||||
p.inserted = Instant::now();
|
||||
|
||||
if p.body.is_none() {
|
||||
p.body = Some(body.clone());
|
||||
p.sender = sender.clone();
|
||||
}
|
||||
p.body = Some(body.clone());
|
||||
p.sender = sender.clone();
|
||||
last_root = Some(*root);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
last_root
|
||||
}
|
||||
|
||||
/// Updates an existing `partial` with the completed block, or adds a new (complete) partial.
|
||||
@@ -257,13 +268,33 @@ pub struct PartialBeaconBlock {
|
||||
}
|
||||
|
||||
impl PartialBeaconBlock {
|
||||
/// Consumes `self` and returns a full built `BeaconBlock`, it's root and the `sender`
|
||||
/// `PeerId`, if enough information exists to complete the block. Otherwise, returns `None`.
|
||||
pub fn complete(self) -> Option<(Hash256, BeaconBlock, PeerId)> {
|
||||
Some((
|
||||
self.block_root,
|
||||
self.header?.into_block(self.body?),
|
||||
self.sender,
|
||||
))
|
||||
/// Attempts to build a block.
|
||||
///
|
||||
/// Does not comsume the `PartialBeaconBlock`.
|
||||
pub fn attempt_complete(&self) -> PartialBeaconBlockCompletion {
|
||||
if self.header.is_none() {
|
||||
PartialBeaconBlockCompletion::MissingHeader(self.slot)
|
||||
} else if self.body.is_none() {
|
||||
PartialBeaconBlockCompletion::MissingBody
|
||||
} else {
|
||||
PartialBeaconBlockCompletion::Complete(
|
||||
self.header
|
||||
.clone()
|
||||
.unwrap()
|
||||
.into_block(self.body.clone().unwrap()),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The result of trying to convert a `BeaconBlock` into a `PartialBeaconBlock`.
|
||||
pub enum PartialBeaconBlockCompletion {
|
||||
/// The partial contains a valid BeaconBlock.
|
||||
Complete(BeaconBlock),
|
||||
/// The partial does not exist.
|
||||
MissingRoot,
|
||||
/// The partial contains a `BeaconBlockRoot` but no `BeaconBlockHeader`.
|
||||
MissingHeader(Slot),
|
||||
/// The partial contains a `BeaconBlockRoot` and `BeaconBlockHeader` but no `BeaconBlockBody`.
|
||||
MissingBody,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user