Skip to content

Commit 35d64c7

Browse files
committed
Add set_all_blocks_to_optimistic
1 parent aaf6235 commit 35d64c7

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed

consensus/proto_array/src/proto_array_fork_choice.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,77 @@ impl ProtoArrayForkChoice {
290290
.map_err(|e| format!("find_head failed: {:?}", e))
291291
}
292292

293+
/// For all nodes, regardless of their relationship to the finalized block, set their execution
294+
/// status to be optimistic.
295+
///
296+
/// In practice this means forgetting any `VALID` or `INVALID` statuses.
297+
pub fn set_all_blocks_to_optimistic(&mut self) -> Result<(), String> {
298+
// Iterate backwards through all nodes in the `proto_array`. Whilst it's not strictly
299+
// required to do this process in reverse, it seems natural when we consider how LMD votes
300+
// are counted.
301+
//
302+
// This function will touch all blocks, even those that do not descend from the finalized
303+
// block. Since this function is expected to run at start-up during very rare
304+
// circumstances we prefer simplicity over efficiency.
305+
for node_index in (0..self.proto_array.nodes.len()).rev() {
306+
let node = self
307+
.proto_array
308+
.nodes
309+
.get_mut(node_index)
310+
.ok_or("unreachable index out of bounds in proto_array nodes")?;
311+
312+
match node.execution_status {
313+
ExecutionStatus::Invalid(block_hash) => {
314+
node.execution_status = ExecutionStatus::Optimistic(block_hash);
315+
316+
// Restore the weight of the node, it would have been set to `0` in
317+
// `apply_score_changes` when it was invalidated.
318+
let restored_weight = self
319+
.votes
320+
.0
321+
.iter()
322+
.enumerate()
323+
.filter_map(|(validator_index, vote)| {
324+
if vote.current_root == node.root {
325+
Some(validator_index)
326+
} else {
327+
None
328+
}
329+
})
330+
// This `filter_map` asserts that any voting validator that does not have a
331+
// balance should be ignored. This is consistent with `compute_deltas`.
332+
.filter_map(|validator_index| self.balances.get(validator_index))
333+
.sum();
334+
335+
// Add the restored weight to the node and all ancestors.
336+
if restored_weight > 0 {
337+
let mut node_or_ancestor = node;
338+
while let Some(parent_index) = node_or_ancestor.parent {
339+
node_or_ancestor
340+
.weight
341+
.checked_add(restored_weight)
342+
.ok_or("Overflow when adding weight to ancestor")?;
343+
node_or_ancestor = self
344+
.proto_array
345+
.nodes
346+
.get_mut(parent_index)
347+
.ok_or(format!("Missing parent index: {}", parent_index))?;
348+
}
349+
}
350+
}
351+
// There are no balance changes required if the node was either valid or
352+
// optimistic.
353+
ExecutionStatus::Valid(block_hash) | ExecutionStatus::Optimistic(block_hash) => {
354+
node.execution_status = ExecutionStatus::Optimistic(block_hash)
355+
}
356+
// An irrelevant node cannot become optimistic, this is a no-op.
357+
ExecutionStatus::Irrelevant(_) => (),
358+
}
359+
}
360+
361+
Ok(())
362+
}
363+
293364
pub fn maybe_prune(&mut self, finalized_root: Hash256) -> Result<(), String> {
294365
self.proto_array
295366
.maybe_prune(finalized_root)

0 commit comments

Comments
 (0)