-
Notifications
You must be signed in to change notification settings - Fork 2.7k
babe: ancient epoch tree pruning #3746
Conversation
|
@rphmeier I didn't include any changes to traverse the tree according to max depth (sorting children), I think if we have fast |
Demi-Marie
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This mostly LGTM but I am not at all familiar with tree pruning.
marcio-diaz
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me, maybe add the test in your TODO or something closer.
rphmeier
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic looks good to me.
f06e872 to
421e766
Compare
|
Missing test added. |
|
|
||
| // we found the deepest ancestor of the finalized block, so we prune | ||
| // out any children that don't include the finalized block. | ||
| root.children.retain(|node| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there is only 1 child that can fulfill this precondition, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, do you think this should be more explicit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is just going to be a little more inefficient
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let children = mem::replace(&mut root.children, Vec::new());
root.children = children.into_iter().filter(|node| ...).take(1).collect()
Currently as we observe BABE epoch changes we track them in a fork tree which keeps growing indefinitely as the chain grows. Since we have finality, after a given block is finalized we know that the chain will not revert past that point and therefore we can prune the tree out of epochs that could not be live at the finalized block (i.e. epochs from other forks, and epochs on the canonical chain for which
epoch.end_slot() <= finalized_slot). The implementation is rather simple since we just usefind_node_whereto find the deepest ancestor of the finalized block that passes the given predicate, and if found we re-root the tree to it.I built polkadot with this patch using the database of one of the validators which was filled with ancient forks. The tree was pruned correctly and import time went back to normal afterwards (getting the current epoch from the tree taking ~3ms rather than a second). #3665 should also make this significantly faster.
Fixes #3651. @rphmeier suggested the following:
I suggest that we implement this by subtracting a fixed delay to the finalized slot we pass in the predicate when searching the tree, i.e.
epoch.end_slot() <= (finalized_slot - N_EPOCHS_TO_KEEP * SLOTS_PER_EPOCH). My initial implementation was keeping the path from root to the current node when traversing the tree, which was then used to traverse back arbitrarily when the correct node was found. This made the implementation much more complicated and I'd also like to avoid introducingparentpointers in the tree for the same reason.TODO: