Skip to content

Commit

Permalink
Add fast-lookups
Browse files Browse the repository at this point in the history
  • Loading branch information
paulhauner committed May 31, 2021
1 parent 2786a46 commit 6c73e22
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 11 deletions.
49 changes: 40 additions & 9 deletions beacon_node/beacon_chain/src/beacon_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -554,10 +554,34 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
return Ok(Some(self.genesis_block_root));
}

let start_slot = target_slot.saturating_sub(1_u64);
let prev_slot = target_slot.saturating_sub(1_u64);
let mut prev_root_opt = None;

process_results(self.forwards_iter_block_roots(start_slot)?, |iter| {
// Try an optimized path of reading the root directly from the head state.
let fast_lookup: Option<Option<Hash256>> = self.with_head(|head| {
let state = &head.beacon_state;

// It's always a skip slot if the target slot is higher than the head.
if target_slot > state.slot {
return Ok(Some(None));
}

// If the previous and target roots are available in the state, read them and return
// Some/None depending on if there is a skip slot.
if let Ok(prev_root) = state.get_block_root(prev_slot) {
if let Ok(curr_root) = state.get_block_root(target_slot) {
return Ok(Some((prev_root != curr_root).then(|| *curr_root)));
}
}

// Fast lookup is not possible.
Ok::<_, Error>(None)
})?;
if let Some(root_opt) = fast_lookup {
return Ok(root_opt);
}

process_results(self.forwards_iter_block_roots(prev_slot)?, |iter| {
for (curr_root, curr_slot) in iter {
if let Some(prev_root) = prev_root_opt {
if curr_slot == target_slot {
Expand Down Expand Up @@ -588,14 +612,21 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
return Ok(Some(self.genesis_block_root));
}

// If the head is equal to or less than the target slot, simply return the head block root.
let head_root_opt = self.with_head(|head| {
Ok::<_, Error>(
(head.beacon_block.slot() <= target_slot).then(|| head.beacon_block_root),
)
// Try an optimized path of reading the root directly from the head state.
let fast_lookup = self.with_head(|head| {
if head.beacon_block.slot() <= target_slot {
// Return the head root if all slots between the target and the head are skipped.
Ok(Some(head.beacon_block_root))
} else if let Ok(root) = head.beacon_state.get_block_root(target_slot) {
// Return the root if it's easily accessible from the head state.
Ok(Some(*root))
} else {
// Fast lookup is not possible.
Ok::<_, Error>(None)
}
})?;
if let Some(head_root) = head_root_opt {
return Ok(Some(head_root));
if let Some(root) = fast_lookup {
return Ok(Some(root));
}

process_results(self.forwards_iter_block_roots(target_slot)?, |mut iter| {
Expand Down
6 changes: 4 additions & 2 deletions beacon_node/beacon_chain/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -615,8 +615,10 @@ fn produces_and_processes_with_genesis_skip_slots() {
fn block_roots_skip_slot_behaviour() {
let harness = get_harness(VALIDATOR_COUNT);

let chain_length = 16;
let skipped_slots = [1, 6, 7, 10, 16];
// Test should be longer than the block roots to ensure a DB lookup is triggered.
let chain_length = harness.chain.head().unwrap().beacon_state.block_roots.len() as u64 * 3;

let skipped_slots = [1, 6, 7, 10, chain_length];

// Build a chain with some skip slots.
for i in 1..=chain_length {
Expand Down

0 comments on commit 6c73e22

Please sign in to comment.