fix state cache loading

* load the cache of the current state epoch instead of the target state
epoch, when applying states and slots
* load state cache for each slot/block (for longer slot jumps)
* load state cache after full updateStateData
* look up two state cache epochs, instead of the same epoch twice :)
This commit is contained in:
Jacek Sieka 2021-06-03 15:32:00 +02:00 committed by zah
parent 09a459b1d7
commit b11da2cb34
2 changed files with 27 additions and 12 deletions

View File

@ -266,16 +266,15 @@ func loadStateCache(
# functions
template load(e: Epoch) =
if epoch notin cache.shuffled_active_validator_indices:
let epochRef = dag.findEpochRef(blck, epoch)
if e notin cache.shuffled_active_validator_indices:
let epochRef = dag.findEpochRef(blck, e)
if epochRef != nil:
cache.shuffled_active_validator_indices[epochRef.epoch] =
epochRef.shuffled_active_validator_indices
if epochRef.epoch == epoch:
for i, idx in epochRef.beacon_proposers:
cache.beacon_proposer_indices[
epoch.compute_start_slot_at_epoch + i] = idx
epochRef.epoch.compute_start_slot_at_epoch + i] = idx
load(epoch)
@ -662,6 +661,8 @@ proc advanceSlots(
# target
doAssert getStateField(state, slot) <= slot
while getStateField(state, slot) < slot:
loadStateCache(dag, cache, state.blck, getStateField(state, slot).epoch)
doAssert process_slots(
state.data, getStateField(state, slot) + 1, cache, rewards,
dag.updateFlags),
@ -683,7 +684,7 @@ proc applyBlock(
doAssert (addr(statePtr.data) == addr v)
statePtr[] = dag.headState
loadStateCache(dag, cache, blck.refs, blck.data.message.slot.epoch)
loadStateCache(dag, cache, state.blck, getStateField(state, slot).epoch)
let ok = state_transition(
dag.runtimePreset, state.data, blck.data,
@ -832,11 +833,12 @@ proc updateStateData*(
dag.applyBlock(state, dag.get(ancestors[i]), {}, cache, rewards)
doAssert ok, "Blocks in database should never fail to apply.."
loadStateCache(dag, cache, bs.blck, bs.slot.epoch)
# ...and make sure to process empty slots as requested
dag.advanceSlots(state, bs.slot, save, cache, rewards)
# ...and make sure to load the state cache, if it exists
loadStateCache(dag, cache, state.blck, getStateField(state, slot).epoch)
let
assignDur = assignTick - startTick
replayDur = Moment.now() - assignTick

View File

@ -357,9 +357,6 @@ suite "chain DAG finalization tests" & preset():
assign(tmpState[], dag.headState.data)
# StateCache is designed to only hold a single linear history at a time
cache = StateCache()
for i in 0 ..< (SLOTS_PER_EPOCH * 6):
if i == 1:
# There are 2 heads now because of the fork at slot 1
@ -393,6 +390,22 @@ suite "chain DAG finalization tests" & preset():
for er in dag.epochRefs:
check: er[1] == nil or er[1].epoch >= dag.finalizedHead.slot.epoch
block:
let tmpStateData = assignClone(dag.headState)
# Check that cached data is available after updateStateData - since we
# just processed the head the relevant epochrefs should not have been
# evicted yet
cache = StateCache()
updateStateData(
dag, tmpStateData[], dag.head.atSlot(dag.head.slot), false, cache)
check:
dag.head.slot.epoch in cache.shuffled_active_validator_indices
(dag.head.slot.epoch - 1) in cache.shuffled_active_validator_indices
dag.head.slot in cache.beacon_proposer_indices
block:
# The late block is a block whose parent was finalized long ago and thus
# is no longer a viable head candidate