use epoch ref to update fork choice

this dramatically speeds up startup in long periods of non-finality
This commit is contained in:
Jacek Sieka 2020-08-03 20:39:43 +02:00 committed by zah
parent a5d900d052
commit c6674de5d2
8 changed files with 53 additions and 41 deletions

View File

@ -44,18 +44,14 @@ proc init*(T: type AttestationPool, chainDag: ChainDAGRef, quarantine: Quarantin
blocks.add cur blocks.add cur
cur = cur.parent cur = cur.parent
for blck in reversed(blocks): debug "Preloading fork choice with blocks", blocks = blocks.len
chainDag.withState(chainDag.tmpState, blck.atSlot(blck.slot)):
debug "Preloading fork choice with block",
block_root = shortlog(blck.root),
parent_root = shortlog(blck.parent.root),
justified_epoch = state.current_justified_checkpoint.epoch,
finalized_epoch = state.finalized_checkpoint.epoch,
slot = blck.slot
let status = for blck in reversed(blocks):
let
epochRef = chainDag.getEpochRef(blck, blck.slot.compute_epoch_at_slot)
status =
forkChoice.process_block( forkChoice.process_block(
chainDag, state, blck, chainDag.get(blck).data.message, blck.slot) chainDag, epochRef, blck, chainDag.get(blck).data.message, blck.slot)
doAssert status.isOk(), "Error in preloading the fork choice: " & $status.error doAssert status.isOk(), "Error in preloading the fork choice: " & $status.error
@ -208,13 +204,13 @@ proc addAttestation*(pool: var AttestationPool,
pool.addResolved(blck, attestation, wallSlot) pool.addResolved(blck, attestation, wallSlot)
proc addForkChoice*(pool: var AttestationPool, proc addForkChoice*(pool: var AttestationPool,
state: BeaconState, epochRef: EpochRef,
blckRef: BlockRef, blckRef: BlockRef,
blck: BeaconBlock, blck: BeaconBlock,
wallSlot: Slot) = wallSlot: Slot) =
## Add a verified block to the fork choice context ## Add a verified block to the fork choice context
let state = pool.forkChoice.process_block( let state = pool.forkChoice.process_block(
pool.chainDag, state, blckRef, blck, wallSlot) pool.chainDag, epochRef, blckRef, blck, wallSlot)
if state.isErr: if state.isErr:
# TODO If this happens, it is effectively a bug - the BlockRef structure # TODO If this happens, it is effectively a bug - the BlockRef structure

View File

@ -344,8 +344,9 @@ proc storeBlock(
blckRef: BlockRef, signedBlock: SignedBeaconBlock, blckRef: BlockRef, signedBlock: SignedBeaconBlock,
state: HashedBeaconState): state: HashedBeaconState):
# Callback add to fork choice if valid # Callback add to fork choice if valid
let epochRef = getEpochInfo(blckRef, state.data)
node.attestationPool.addForkChoice( node.attestationPool.addForkChoice(
state.data, blckRef, signedBlock.message, epochRef, blckRef, signedBlock.message,
node.beaconClock.now().slotOrZero()) node.beaconClock.now().slotOrZero())
node.dumpBlock(signedBlock, blck) node.dumpBlock(signedBlock, blck)

View File

@ -137,8 +137,10 @@ type
runtimePreset*: RuntimePreset runtimePreset*: RuntimePreset
EpochRef* = ref object EpochRef* = ref object
shuffled_active_validator_indices*: seq[ValidatorIndex]
epoch*: Epoch epoch*: Epoch
current_justified_checkpoint*: Checkpoint
finalized_checkpoint*: Checkpoint
shuffled_active_validator_indices*: seq[ValidatorIndex]
BlockRef* = ref object BlockRef* = ref object
## Node in object graph guaranteed to lead back to tail block, and to have ## Node in object graph guaranteed to lead back to tail block, and to have

View File

@ -66,6 +66,8 @@ func init*(T: type EpochRef, state: BeaconState): T =
let epoch = state.get_current_epoch() let epoch = state.get_current_epoch()
EpochRef( EpochRef(
epoch: epoch, epoch: epoch,
current_justified_checkpoint: state.current_justified_checkpoint,
finalized_checkpoint: state.finalized_checkpoint,
shuffled_active_validator_indices: shuffled_active_validator_indices:
get_shuffled_active_validator_indices(state, epoch)) get_shuffled_active_validator_indices(state, epoch))

View File

@ -166,36 +166,36 @@ proc get_balances_for_block(self: var Checkpoints, blck: BlockSlot, dag: ChainDA
proc process_state(self: var Checkpoints, proc process_state(self: var Checkpoints,
dag: ChainDAGRef, dag: ChainDAGRef,
state: BeaconState, epochRef: EpochRef,
blck: BlockRef) = blck: BlockRef) =
trace "Processing state", trace "Processing epoch",
state_slot = state.slot, epoch = epochRef.epoch,
state_justified = state.current_justified_checkpoint.epoch, state_justified = epochRef.current_justified_checkpoint.epoch,
current_justified = self.current.justified.epoch, current_justified = self.current.justified.epoch,
state_finalized = state.finalized_checkpoint.epoch, state_finalized = epochRef.finalized_checkpoint.epoch,
current_finalized = self.current.finalized current_finalized = self.current.finalized
if (state.current_justified_checkpoint.epoch > self.current.justified.epoch) and if (epochRef.current_justified_checkpoint.epoch > self.current.justified.epoch) and
(state.finalized_checkpoint.epoch >= self.current.finalized.epoch): (epochRef.finalized_checkpoint.epoch >= self.current.finalized.epoch):
let justifiedBlck = blck.atEpochStart( let justifiedBlck = blck.atEpochStart(
state.current_justified_checkpoint.epoch) epochRef.current_justified_checkpoint.epoch)
doAssert justifiedBlck.blck.root == state.current_justified_checkpoint.root doAssert justifiedBlck.blck.root == epochRef.current_justified_checkpoint.root
let candidate = FFGCheckpoints( let candidate = FFGCheckpoints(
justified: BalanceCheckpoint( justified: BalanceCheckpoint(
blck: justifiedBlck.blck, blck: justifiedBlck.blck,
epoch: state.current_justified_checkpoint.epoch, epoch: epochRef.current_justified_checkpoint.epoch,
balances: self.get_balances_for_block(justifiedBlck, dag), balances: self.get_balances_for_block(justifiedBlck, dag),
), ),
finalized: state.finalized_checkpoint, finalized: epochRef.finalized_checkpoint,
) )
trace "Applying candidate", trace "Applying candidate",
justified_block = shortLog(candidate.justified.blck), justified_block = shortLog(candidate.justified.blck),
justified_epoch = shortLog(candidate.justified.epoch), justified_epoch = shortLog(candidate.justified.epoch),
finalized = candidate.finalized, finalized = candidate.finalized,
state_finalized = state.finalized_checkpoint.epoch state_finalized = epochRef.finalized_checkpoint.epoch
if self.current.justified.blck.isAncestorOf(justifiedBlck.blck): if self.current.justified.blck.isAncestorOf(justifiedBlck.blck):
trace "Updating current", trace "Updating current",
@ -249,11 +249,11 @@ proc process_block*(self: var ForkChoiceBackend,
proc process_block*(self: var ForkChoice, proc process_block*(self: var ForkChoice,
dag: ChainDAGRef, dag: ChainDAGRef,
state: BeaconState, epochRef: EpochRef,
blckRef: BlockRef, blckRef: BlockRef,
blck: SomeBeaconBlock, blck: SomeBeaconBlock,
wallSlot: Slot): FcResult[void] = wallSlot: Slot): FcResult[void] =
process_state(self.checkpoints, dag, state, blckRef) process_state(self.checkpoints, dag, epochRef, blckRef)
maybe_update(self.checkpoints, wallSlot) maybe_update(self.checkpoints, wallSlot)
@ -276,7 +276,7 @@ proc process_block*(self: var ForkChoice,
? process_block( ? process_block(
self.backend, blckRef.root, blck.parent_root, self.backend, blckRef.root, blck.parent_root,
state.current_justified_checkpoint.epoch, state.finalized_checkpoint.epoch epochRef.current_justified_checkpoint.epoch, epochRef.finalized_checkpoint.epoch
) )
trace "Integrating block in fork choice", trace "Integrating block in fork choice",

View File

@ -221,8 +221,9 @@ proc proposeSignedBlock*(node: BeaconNode,
blckRef: BlockRef, signedBlock: SignedBeaconBlock, blckRef: BlockRef, signedBlock: SignedBeaconBlock,
state: HashedBeaconState): state: HashedBeaconState):
# Callback add to fork choice if valid # Callback add to fork choice if valid
let epochRef = getEpochInfo(blckRef, state.data)
node.attestationPool.addForkChoice( node.attestationPool.addForkChoice(
state.data, blckRef, signedBlock.message, epochRef, blckRef, signedBlock.message,
node.beaconClock.now().slotOrZero()) node.beaconClock.now().slotOrZero())
if newBlockRef.isErr: if newBlockRef.isErr:

View File

@ -142,7 +142,8 @@ cli do(slots = SLOTS_PER_EPOCH * 6,
blckRef: BlockRef, signedBlock: SignedBeaconBlock, blckRef: BlockRef, signedBlock: SignedBeaconBlock,
state: HashedBeaconState): state: HashedBeaconState):
# Callback add to fork choice if valid # Callback add to fork choice if valid
attPool.addForkChoice(state.data, blckRef, signedBlock.message, blckRef.slot) let epochRef = getEpochInfo(blckRef, state.data)
attPool.addForkChoice(epochRef, blckRef, signedBlock.message, blckRef.slot)
blck() = added[] blck() = added[]
chainDag.updateHead(added[]) chainDag.updateHead(added[])

View File

@ -168,7 +168,8 @@ suiteReport "Attestation pool processing" & preset():
blckRef: BlockRef, signedBlock: SignedBeaconBlock, blckRef: BlockRef, signedBlock: SignedBeaconBlock,
state: HashedBeaconState): state: HashedBeaconState):
# Callback add to fork choice if valid # Callback add to fork choice if valid
pool[].addForkChoice(state.data, blckRef, signedBlock.message, blckRef.slot) let epochRef = getEpochInfo(blckRef, state.data)
pool[].addForkChoice(epochRef, blckRef, signedBlock.message, blckRef.slot)
let head = pool[].selectHead(b1Add[].slot) let head = pool[].selectHead(b1Add[].slot)
@ -181,7 +182,8 @@ suiteReport "Attestation pool processing" & preset():
blckRef: BlockRef, signedBlock: SignedBeaconBlock, blckRef: BlockRef, signedBlock: SignedBeaconBlock,
state: HashedBeaconState): state: HashedBeaconState):
# Callback add to fork choice if valid # Callback add to fork choice if valid
pool[].addForkChoice(state.data, blckRef, signedBlock.message, blckRef.slot) let epochRef = getEpochInfo(blckRef, state.data)
pool[].addForkChoice(epochRef, blckRef, signedBlock.message, blckRef.slot)
let head2 = pool[].selectHead(b2Add[].slot) let head2 = pool[].selectHead(b2Add[].slot)
@ -196,7 +198,8 @@ suiteReport "Attestation pool processing" & preset():
blckRef: BlockRef, signedBlock: SignedBeaconBlock, blckRef: BlockRef, signedBlock: SignedBeaconBlock,
state: HashedBeaconState): state: HashedBeaconState):
# Callback add to fork choice if valid # Callback add to fork choice if valid
pool[].addForkChoice(state.data, blckRef, signedBlock.message, blckRef.slot) let epochRef = getEpochInfo(blckRef, state.data)
pool[].addForkChoice(epochRef, blckRef, signedBlock.message, blckRef.slot)
let head = pool[].selectHead(b10Add[].slot) let head = pool[].selectHead(b10Add[].slot)
@ -211,7 +214,8 @@ suiteReport "Attestation pool processing" & preset():
blckRef: BlockRef, signedBlock: SignedBeaconBlock, blckRef: BlockRef, signedBlock: SignedBeaconBlock,
state: HashedBeaconState): state: HashedBeaconState):
# Callback add to fork choice if valid # Callback add to fork choice if valid
pool[].addForkChoice(state.data, blckRef, signedBlock.message, blckRef.slot) let epochRef = getEpochInfo(blckRef, state.data)
pool[].addForkChoice(epochRef, blckRef, signedBlock.message, blckRef.slot)
bc1 = get_beacon_committee( bc1 = get_beacon_committee(
state.data.data, state.data.data.slot, 1.CommitteeIndex, cache) state.data.data, state.data.data.slot, 1.CommitteeIndex, cache)
@ -253,7 +257,8 @@ suiteReport "Attestation pool processing" & preset():
blckRef: BlockRef, signedBlock: SignedBeaconBlock, blckRef: BlockRef, signedBlock: SignedBeaconBlock,
state: HashedBeaconState): state: HashedBeaconState):
# Callback add to fork choice if valid # Callback add to fork choice if valid
pool[].addForkChoice(state.data, blckRef, signedBlock.message, blckRef.slot) let epochRef = getEpochInfo(blckRef, state.data)
pool[].addForkChoice(epochRef, blckRef, signedBlock.message, blckRef.slot)
let head = pool[].selectHead(b10Add[].slot) let head = pool[].selectHead(b10Add[].slot)
@ -267,7 +272,8 @@ suiteReport "Attestation pool processing" & preset():
blckRef: BlockRef, signedBlock: SignedBeaconBlock, blckRef: BlockRef, signedBlock: SignedBeaconBlock,
state: HashedBeaconState): state: HashedBeaconState):
# Callback add to fork choice if valid # Callback add to fork choice if valid
pool[].addForkChoice(state.data, blckRef, signedBlock.message, blckRef.slot) let epochRef = getEpochInfo(blckRef, state.data)
pool[].addForkChoice(epochRef, blckRef, signedBlock.message, blckRef.slot)
doAssert: b10Add_clone.error == Duplicate doAssert: b10Add_clone.error == Duplicate
@ -281,7 +287,8 @@ suiteReport "Attestation pool processing" & preset():
blckRef: BlockRef, signedBlock: SignedBeaconBlock, blckRef: BlockRef, signedBlock: SignedBeaconBlock,
state: HashedBeaconState): state: HashedBeaconState):
# Callback add to fork choice if valid # Callback add to fork choice if valid
pool[].addForkChoice(state.data, blckRef, signedBlock.message, blckRef.slot) let epochRef = getEpochInfo(blckRef, state.data)
pool[].addForkChoice(epochRef, blckRef, signedBlock.message, blckRef.slot)
let head = pool[].selectHead(b10Add[].slot) let head = pool[].selectHead(b10Add[].slot)
@ -315,7 +322,8 @@ suiteReport "Attestation pool processing" & preset():
blckRef: BlockRef, signedBlock: SignedBeaconBlock, blckRef: BlockRef, signedBlock: SignedBeaconBlock,
state: HashedBeaconState): state: HashedBeaconState):
# Callback add to fork choice if valid # Callback add to fork choice if valid
pool[].addForkChoice(state.data, blckRef, signedBlock.message, blckRef.slot) let epochRef = getEpochInfo(blckRef, state.data)
pool[].addForkChoice(epochRef, blckRef, signedBlock.message, blckRef.slot)
let head = pool[].selectHead(blockRef[].slot) let head = pool[].selectHead(blockRef[].slot)
doassert: head == blockRef[] doassert: head == blockRef[]
@ -356,6 +364,7 @@ suiteReport "Attestation pool processing" & preset():
blckRef: BlockRef, signedBlock: SignedBeaconBlock, blckRef: BlockRef, signedBlock: SignedBeaconBlock,
state: HashedBeaconState): state: HashedBeaconState):
# Callback add to fork choice if valid # Callback add to fork choice if valid
pool[].addForkChoice(state.data, blckRef, signedBlock.message, blckRef.slot) let epochRef = getEpochInfo(blckRef, state.data)
pool[].addForkChoice(epochRef, blckRef, signedBlock.message, blckRef.slot)
doAssert: b10Add_clone.error == Duplicate doAssert: b10Add_clone.error == Duplicate