Optimise state_root_at_slot for finalized slot (#8353)

This is an optimisation targeted at Fulu networks in non-finality.

While debugging on Holesky, we found that `state_root_at_slot` was being called from `prepare_beacon_proposer` a lot, for the finalized state:

2c9b670f5d/beacon_node/http_api/src/lib.rs (L3860-L3861)

This was causing `prepare_beacon_proposer` calls to take upwards of 5 seconds, sometimes 10 seconds, because it would trigger _multiple_ beacon state loads in order to iterate back to the finalized slot. Ideally, loading the finalized state should be quick because we keep it cached in the state cache (technically we keep the split state, but they usually coincide). Instead we are computing the finalized state root separately (slow), and then loading the state from the cache (fast).

Although it would be possible to make the API faster by removing the `state_root_at_slot` call, I believe it's simpler to change `state_root_at_slot` itself and remove the footgun. Devs rightly expect operations involving the finalized state to be fast.


Co-Authored-By: Michael Sproul <michael@sigmaprime.io>
This commit is contained in:
Michael Sproul
2025-11-05 13:08:46 +11:00
committed by GitHub
parent 0507eca7b4
commit a7e89a8761
2 changed files with 10 additions and 0 deletions

View File

@@ -883,6 +883,12 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
return Ok(None);
}
// Fast-path for the split slot (which usually corresponds to the finalized slot).
let split = self.store.get_split_info();
if request_slot == split.slot {
return Ok(Some(split.state_root));
}
// Try an optimized path of reading the root directly from the head state.
let fast_lookup: Option<Hash256> = self.with_head(|head| {
if head.beacon_block.slot() <= request_slot {