Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load block roots from fork choice where possible when serving BlocksByRange requests #7058

Open
wants to merge 2 commits into
base: holesky-rescue
Choose a base branch
from

Conversation

jimmygchen
Copy link
Member

Issue Addressed

Partially #7053.

Proposed Changes

Load block roots from fork choice where possible to avoid loading state from disk when serving block by range requests.

…te from disk when serving block by range requests.
@jimmygchen jimmygchen force-pushed the avoid-load-state-blocks-range-req branch from d961ca9 to 2cb71e2 Compare February 28, 2025 06:38
@jimmygchen jimmygchen added the ready-for-review The code is ready for review label Feb 28, 2025
@@ -681,64 +681,24 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
"start_slot" => req.start_slot(),
);

let forwards_block_root_iter = match self
let block_roots_timer = std::time::Instant::now();
let (block_roots, block_roots_source) = if let Some(block_roots) = self
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than attempting to access fork choice and seeing if it works, I think we should check if the start slot is newer than finalization (start_slot >= finalized_slot), and use fork choice in that case. Fork choice has to have every chain newer than finalization.

This will be more efficient, as it fixes the issue with skipped slots. If a peer requests a range of unfinalized slots that is empty, we can just return nothing. Currently, we will try fork choice, get None, and then try get_block_roots_from_store and get the block roots from the skipped slots. This is not actually helpful, as later in the function we'll drop the blocks that are out of range anyway:

// Due to skip slots, blocks could be out of the range, we ensure they
// are in the range before sending
if block.slot() >= *req.start_slot()
&& block.slot() < req.start_slot() + req.count()
{
blocks_sent += 1;
self.send_network_message(NetworkMessage::SendResponse {
peer_id,
request_id,
response: Response::BlocksByRange(Some(block.clone())),
id: (connection_id, substream_id),
});
}

In other words, the new fork choice impl allows us to avoid looking up blocks from skipped slots and then discarding them.

Something that this code change is not currently handling is requests that span across the finalized slot. If start_slot < finalized_slot and end_slot > finalized_slot, then the current impl will return partial data (all the blocks newer than finalization). Instead of this, short-term I think it would be better to fallback on the old disk-based iterator, which is accomplished by the same code change I suggested above: only use fork choice if the start slot is newer than finalization.

Longer term, we should use some kind of hybrid iterator so we can easily span the finalized slot without any mucking around. For now I think we don't need to worry about this though, because these requests should be infrequent.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation. I've applied the change to check for finalization in bd093d9

count: u64,
) -> Option<Vec<Hash256>> {
let head_block_root = self.canonical_head.cached_head().head_block_root();
let fork_choice_read_lock = self.canonical_head.fork_choice_read_lock();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically we should probably avoid locking fork choice from an async task, but atm I think we have bigger fish to fry. It's nowhere near as bad as doing 10s of state loads 😱

…nalized_slot`), and use fork choice in that case.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ready-for-review The code is ready for review v7.0.0-beta.2
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants