When a parent block is rejected, also reject its children (#2479)
This commit is contained in:
parent
e49f96caf7
commit
6676eb96b3
|
|
@ -22,8 +22,8 @@ use zebra_chain::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
request::HashOrHeight, BoxError, CommitBlockError, Config, FinalizedBlock, PreparedBlock,
|
request::HashOrHeight, BoxError, CloneError, CommitBlockError, Config, FinalizedBlock,
|
||||||
Request, Response, ValidateContextError,
|
PreparedBlock, Request, Response, ValidateContextError,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(any(test, feature = "proptest-impl"))]
|
#[cfg(any(test, feature = "proptest-impl"))]
|
||||||
|
|
@ -201,20 +201,38 @@ impl StateService {
|
||||||
/// Attempt to validate and commit all queued blocks whose parents have
|
/// Attempt to validate and commit all queued blocks whose parents have
|
||||||
/// recently arrived starting from `new_parent`, in breadth-first ordering.
|
/// recently arrived starting from `new_parent`, in breadth-first ordering.
|
||||||
fn process_queued(&mut self, new_parent: block::Hash) {
|
fn process_queued(&mut self, new_parent: block::Hash) {
|
||||||
let mut new_parents = vec![new_parent];
|
let mut new_parents: Vec<(block::Hash, Result<(), CloneError>)> =
|
||||||
|
vec![(new_parent, Ok(()))];
|
||||||
|
|
||||||
while let Some(parent_hash) = new_parents.pop() {
|
while let Some((parent_hash, parent_result)) = new_parents.pop() {
|
||||||
let queued_children = self.queued_blocks.dequeue_children(parent_hash);
|
let queued_children = self.queued_blocks.dequeue_children(parent_hash);
|
||||||
|
|
||||||
for (child, rsp_tx) in queued_children {
|
for (child, rsp_tx) in queued_children {
|
||||||
let child_hash = child.hash;
|
let child_hash = child.hash;
|
||||||
tracing::trace!(?child_hash, "validating queued child");
|
let result;
|
||||||
let result = self
|
|
||||||
.validate_and_commit(child)
|
// If the block is invalid, reject any descendant blocks.
|
||||||
.map(|()| child_hash)
|
//
|
||||||
.map_err(BoxError::from);
|
// At this point, we know that the block and all its descendants
|
||||||
let _ = rsp_tx.send(result);
|
// are invalid, because we checked all the consensus rules before
|
||||||
new_parents.push(child_hash);
|
// committing the block to the non-finalized state.
|
||||||
|
// (These checks also bind the transaction data to the block
|
||||||
|
// header, using the transaction merkle tree and authorizing data
|
||||||
|
// commitment.)
|
||||||
|
if let Err(ref parent_error) = parent_result {
|
||||||
|
tracing::trace!(
|
||||||
|
?child_hash,
|
||||||
|
?parent_error,
|
||||||
|
"rejecting queued child due to parent error"
|
||||||
|
);
|
||||||
|
result = Err(parent_error.clone());
|
||||||
|
} else {
|
||||||
|
tracing::trace!(?child_hash, "validating queued child");
|
||||||
|
result = self.validate_and_commit(child).map_err(CloneError::from);
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = rsp_tx.send(result.clone().map(|()| child_hash).map_err(BoxError::from));
|
||||||
|
new_parents.push((child_hash, result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue