set `safe_block_hash` to fork choice justified (#4010)

Implements the fork choice safe block spec, where `safe_block_hash` in
`forkChoiceUpdated` is set to justified (used to be `ZERO_HASH`).
https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.3/fork_choice/safe-block.md#get_safe_execution_payload_hash
This commit is contained in:
Etan Kissling 2022-08-26 01:34:02 +02:00 committed by GitHub
parent ebfb624557
commit 64972e3c8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 131 additions and 88 deletions

View File

@ -733,26 +733,55 @@ func getAggregatedAttestation*(pool: var AttestationPool,
res res
type BeaconHead* = object
blck*: BlockRef
safeExecutionPayloadHash*, finalizedExecutionPayloadHash*: Eth2Digest
proc getBeaconHead*(
pool: var AttestationPool, headBlock: BlockRef): BeaconHead =
let
finalizedExecutionPayloadHash =
pool.dag.loadExecutionBlockRoot(pool.dag.finalizedHead.blck)
# https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.3/fork_choice/safe-block.md#get_safe_execution_payload_hash
safeBlockRoot = pool.forkChoice.get_safe_beacon_block_root()
safeBlock = pool.dag.getBlockRef(safeBlockRoot)
safeExecutionPayloadHash =
if safeBlock.isErr:
# Safe block is currently the justified block determined by fork choice.
# If finality already advanced beyond the current justified checkpoint,
# e.g., because we have selected a head that did not yet realize the cp,
# the justified block may end up not having a `BlockRef` anymore.
# Because we know that a different fork already finalized a later point,
# let's just report the finalized execution payload hash instead.
finalizedExecutionPayloadHash
else:
pool.dag.loadExecutionBlockRoot(safeBlock.get)
BeaconHead(
blck: headBlock,
safeExecutionPayloadHash: safeExecutionPayloadHash,
finalizedExecutionPayloadHash: finalizedExecutionPayloadHash)
proc selectOptimisticHead*( proc selectOptimisticHead*(
pool: var AttestationPool, wallTime: BeaconTime): Opt[BlockRef] = pool: var AttestationPool, wallTime: BeaconTime): Opt[BeaconHead] =
## Trigger fork choice and returns the new head block. ## Trigger fork choice and returns the new head block.
## Can return `nil`
# TODO rename this to get_optimistic_head # TODO rename this to get_optimistic_head
let newHead = pool.forkChoice.get_head(pool.dag, wallTime) let newHeadRoot = pool.forkChoice.get_head(pool.dag, wallTime)
if newHeadRoot.isErr:
error "Couldn't select head", err = newHeadRoot.error
return err()
if newHead.isErr: let headBlock = pool.dag.getBlockRef(newHeadRoot.get()).valueOr:
error "Couldn't select head", err = newHead.error # This should normally not happen, but if the chain dag and fork choice
err() # get out of sync, we'll need to try to download the selected head - in
else: # the meantime, return nil to indicate that no new head was chosen
let ret = pool.dag.getBlockRef(newHead.get()) warn "Fork choice selected unknown head, trying to sync",
if ret.isErr(): root = newHeadRoot.get()
# This should normally not happen, but if the chain dag and fork choice pool.quarantine[].addMissing(newHeadRoot.get())
# get out of sync, we'll need to try to download the selected head - in return err()
# the meantime, return nil to indicate that no new head was chosen
warn "Fork choice selected unknown head, trying to sync", root = newHead.get()
pool.quarantine[].addMissing(newHead.get())
ret ok pool.getBeaconHead(headBlock)
proc prune*(pool: var AttestationPool) = proc prune*(pool: var AttestationPool) =
if (let v = pool.forkChoice.prune(); v.isErr): if (let v = pool.forkChoice.prune(); v.isErr):

View File

@ -118,7 +118,8 @@ from web3/engine_api_types import
func `$`(h: BlockHash): string = $h.asEth2Digest func `$`(h: BlockHash): string = $h.asEth2Digest
proc runForkchoiceUpdated*( proc runForkchoiceUpdated*(
eth1Monitor: Eth1Monitor, headBlockRoot, finalizedBlockRoot: Eth2Digest): eth1Monitor: Eth1Monitor,
headBlockRoot, safeBlockRoot, finalizedBlockRoot: Eth2Digest):
Future[PayloadExecutionStatus] {.async.} = Future[PayloadExecutionStatus] {.async.} =
# Allow finalizedBlockRoot to be 0 to avoid sync deadlocks. # Allow finalizedBlockRoot to be 0 to avoid sync deadlocks.
# #
@ -138,15 +139,15 @@ proc runForkchoiceUpdated*(
let fcuR = awaitWithTimeout( let fcuR = awaitWithTimeout(
forkchoiceUpdated( forkchoiceUpdated(
eth1Monitor, headBlockRoot, finalizedBlockRoot), eth1Monitor, headBlockRoot, safeBlockRoot, finalizedBlockRoot),
FORKCHOICEUPDATED_TIMEOUT): FORKCHOICEUPDATED_TIMEOUT):
debug "runForkchoiceUpdated: forkchoiceUpdated timed out" debug "runForkchoiceUpdated: forkchoiceUpdated timed out"
ForkchoiceUpdatedResponse( ForkchoiceUpdatedResponse(
payloadStatus: PayloadStatusV1(status: PayloadExecutionStatus.syncing)) payloadStatus: PayloadStatusV1(
status: PayloadExecutionStatus.syncing))
debug "runForkchoiceUpdated: ran forkchoiceUpdated", debug "runForkchoiceUpdated: ran forkchoiceUpdated",
headBlockRoot, headBlockRoot, safeBlockRoot, finalizedBlockRoot,
finalizedBlockRoot,
payloadStatus = $fcuR.payloadStatus.status, payloadStatus = $fcuR.payloadStatus.status,
latestValidHash = $fcuR.payloadStatus.latestValidHash, latestValidHash = $fcuR.payloadStatus.latestValidHash,
validationError = $fcuR.payloadStatus.validationError validationError = $fcuR.payloadStatus.validationError
@ -157,31 +158,32 @@ proc runForkchoiceUpdated*(
err = err.msg err = err.msg
return PayloadExecutionStatus.syncing return PayloadExecutionStatus.syncing
proc updateExecutionClientHead(self: ref ConsensusManager, newHead: BlockRef) proc updateExecutionClientHead(self: ref ConsensusManager, newHead: BeaconHead)
{.async.} = {.async.} =
if self.eth1Monitor.isNil: if self.eth1Monitor.isNil:
return return
let executionHeadRoot = self.dag.loadExecutionBlockRoot(newHead) let headExecutionPayloadHash = self.dag.loadExecutionBlockRoot(newHead.blck)
if executionHeadRoot.isZero: if headExecutionPayloadHash.isZero:
# Blocks without execution payloads can't be optimistic. # Blocks without execution payloads can't be optimistic.
self.dag.markBlockVerified(self.quarantine[], newHead.root) self.dag.markBlockVerified(self.quarantine[], newHead.blck.root)
return return
# Can't use dag.head here because it hasn't been updated yet # Can't use dag.head here because it hasn't been updated yet
let payloadExecutionStatus = await self.eth1Monitor.runForkchoiceUpdated( let payloadExecutionStatus = await self.eth1Monitor.runForkchoiceUpdated(
executionHeadRoot, headExecutionPayloadHash,
self.dag.loadExecutionBlockRoot(self.dag.finalizedHead.blck)) newHead.safeExecutionPayloadHash,
newHead.finalizedExecutionPayloadHash)
case payloadExecutionStatus case payloadExecutionStatus
of PayloadExecutionStatus.valid: of PayloadExecutionStatus.valid:
self.dag.markBlockVerified(self.quarantine[], newHead.root) self.dag.markBlockVerified(self.quarantine[], newHead.blck.root)
of PayloadExecutionStatus.invalid, PayloadExecutionStatus.invalid_block_hash: of PayloadExecutionStatus.invalid, PayloadExecutionStatus.invalid_block_hash:
self.dag.markBlockInvalid(newHead.root) self.dag.markBlockInvalid(newHead.blck.root)
self.quarantine[].addUnviable(newHead.root) self.quarantine[].addUnviable(newHead.blck.root)
of PayloadExecutionStatus.accepted, PayloadExecutionStatus.syncing: of PayloadExecutionStatus.accepted, PayloadExecutionStatus.syncing:
self.dag.optimisticRoots.incl newHead.root self.dag.optimisticRoots.incl newHead.blck.root
proc updateHead*(self: var ConsensusManager, newHead: BlockRef) = proc updateHead*(self: var ConsensusManager, newHead: BlockRef) =
## Trigger fork choice and update the DAG with the new head block ## Trigger fork choice and update the DAG with the new head block
@ -206,11 +208,11 @@ proc updateHead*(self: var ConsensusManager, wallSlot: Slot) =
head = shortLog(self.dag.head), wallSlot head = shortLog(self.dag.head), wallSlot
return return
if self.dag.loadExecutionBlockRoot(newHead).isZero: if self.dag.loadExecutionBlockRoot(newHead.blck).isZero:
# Blocks without execution payloads can't be optimistic. # Blocks without execution payloads can't be optimistic.
self.dag.markBlockVerified(self.quarantine[], newHead.root) self.dag.markBlockVerified(self.quarantine[], newHead.blck.root)
self.updateHead(newHead) self.updateHead(newHead.blck)
proc checkNextProposer(dag: ChainDAGRef, slot: Slot): proc checkNextProposer(dag: ChainDAGRef, slot: Slot):
Opt[(ValidatorIndex, ValidatorPubKey)] = Opt[(ValidatorIndex, ValidatorPubKey)] =
@ -247,9 +249,8 @@ proc runProposalForkchoiceUpdated*(self: ref ConsensusManager) {.async.} =
get_randao_mix(state.data, get_current_epoch(state.data)).data get_randao_mix(state.data, get_current_epoch(state.data)).data
feeRecipient = self.getFeeRecipient( feeRecipient = self.getFeeRecipient(
nextProposer, validatorIndex, nextSlot.epoch) nextProposer, validatorIndex, nextSlot.epoch)
headBlockRoot = self.dag.loadExecutionBlockRoot(self.dag.head) beaconHead = self.attestationPool[].getBeaconHead(self.dag.head)
finalizedBlockRoot = headBlockRoot = self.dag.loadExecutionBlockRoot(beaconHead.blck)
self.dag.loadExecutionBlockRoot(self.dag.finalizedHead.blck)
if headBlockRoot.isZero: if headBlockRoot.isZero:
return return
@ -257,8 +258,11 @@ proc runProposalForkchoiceUpdated*(self: ref ConsensusManager) {.async.} =
try: try:
let fcResult = awaitWithTimeout( let fcResult = awaitWithTimeout(
forkchoiceUpdated( forkchoiceUpdated(
self.eth1Monitor, headBlockRoot, finalizedBlockRoot, timestamp, self.eth1Monitor,
randomData, feeRecipient), headBlockRoot,
beaconHead.safeExecutionPayloadHash,
beaconHead.finalizedExecutionPayloadHash,
timestamp, randomData, feeRecipient),
FORKCHOICEUPDATED_TIMEOUT): FORKCHOICEUPDATED_TIMEOUT):
debug "runProposalForkchoiceUpdated: forkchoiceUpdated timed out" debug "runProposalForkchoiceUpdated: forkchoiceUpdated timed out"
ForkchoiceUpdatedResponse( ForkchoiceUpdatedResponse(
@ -271,13 +275,14 @@ proc runProposalForkchoiceUpdated*(self: ref ConsensusManager) {.async.} =
self.forkchoiceUpdatedInfo = Opt.some ForkchoiceUpdatedInformation( self.forkchoiceUpdatedInfo = Opt.some ForkchoiceUpdatedInformation(
payloadId: bellatrix.PayloadID(fcResult.payloadId.get), payloadId: bellatrix.PayloadID(fcResult.payloadId.get),
headBlockRoot: headBlockRoot, headBlockRoot: headBlockRoot,
finalizedBlockRoot: finalizedBlockRoot, safeBlockRoot: beaconHead.safeExecutionPayloadHash,
finalizedBlockRoot: beaconHead.finalizedExecutionPayloadHash,
timestamp: timestamp, timestamp: timestamp,
feeRecipient: feeRecipient) feeRecipient: feeRecipient)
except CatchableError as err: except CatchableError as err:
error "Engine API fork-choice update failed", err = err.msg error "Engine API fork-choice update failed", err = err.msg
proc updateHeadWithExecution*(self: ref ConsensusManager, newHead: BlockRef) proc updateHeadWithExecution*(self: ref ConsensusManager, newHead: BeaconHead)
{.async.} = {.async.} =
## Trigger fork choice and update the DAG with the new head block ## Trigger fork choice and update the DAG with the new head block
## This does not automatically prune the DAG after finalization ## This does not automatically prune the DAG after finalization
@ -290,7 +295,7 @@ proc updateHeadWithExecution*(self: ref ConsensusManager, newHead: BlockRef)
# Store the new head in the chain DAG - this may cause epochs to be # Store the new head in the chain DAG - this may cause epochs to be
# justified and finalized # justified and finalized
self.dag.updateHead(newHead, self.quarantine[]) self.dag.updateHead(newHead.blck, self.quarantine[])
# TODO after things stabilize with this, check for upcoming proposal and # TODO after things stabilize with this, check for upcoming proposal and
# don't bother sending first fcU, but initially, keep both in place # don't bother sending first fcU, but initially, keep both in place

View File

@ -496,7 +496,7 @@ proc newPayload*(p: Eth1Monitor, payload: engine_api.ExecutionPayloadV1):
p.dataProvider.web3.provider.engine_newPayloadV1(payload) p.dataProvider.web3.provider.engine_newPayloadV1(payload)
proc forkchoiceUpdated*(p: Eth1Monitor, proc forkchoiceUpdated*(p: Eth1Monitor,
headBlock, finalizedBlock: Eth2Digest): headBlock, safeBlock, finalizedBlock: Eth2Digest):
Future[engine_api.ForkchoiceUpdatedResponse] = Future[engine_api.ForkchoiceUpdatedResponse] =
# Eth1 monitor can recycle connections without (external) warning; at least, # Eth1 monitor can recycle connections without (external) warning; at least,
# don't crash. # don't crash.
@ -510,17 +510,12 @@ proc forkchoiceUpdated*(p: Eth1Monitor,
p.dataProvider.web3.provider.engine_forkchoiceUpdatedV1( p.dataProvider.web3.provider.engine_forkchoiceUpdatedV1(
ForkchoiceStateV1( ForkchoiceStateV1(
headBlockHash: headBlock.asBlockHash, headBlockHash: headBlock.asBlockHash,
safeBlockHash: safeBlock.asBlockHash,
# https://hackmd.io/@n0ble/kintsugi-spec#Engine-API
# "CL client software MUST use headBlockHash value as a stub for the
# safeBlockHash parameter"
safeBlockHash: headBlock.asBlockHash,
finalizedBlockHash: finalizedBlock.asBlockHash), finalizedBlockHash: finalizedBlock.asBlockHash),
none(engine_api.PayloadAttributesV1)) none(engine_api.PayloadAttributesV1))
proc forkchoiceUpdated*(p: Eth1Monitor, proc forkchoiceUpdated*(p: Eth1Monitor,
headBlock, finalizedBlock: Eth2Digest, headBlock, safeBlock, finalizedBlock: Eth2Digest,
timestamp: uint64, timestamp: uint64,
randomData: array[32, byte], randomData: array[32, byte],
suggestedFeeRecipient: Eth1Address): suggestedFeeRecipient: Eth1Address):
@ -537,12 +532,7 @@ proc forkchoiceUpdated*(p: Eth1Monitor,
p.dataProvider.web3.provider.engine_forkchoiceUpdatedV1( p.dataProvider.web3.provider.engine_forkchoiceUpdatedV1(
ForkchoiceStateV1( ForkchoiceStateV1(
headBlockHash: headBlock.asBlockHash, headBlockHash: headBlock.asBlockHash,
safeBlockHash: safeBlock.asBlockHash,
# https://hackmd.io/@n0ble/kintsugi-spec#Engine-API
# "CL client software MUST use headBlockHash value as a stub for the
# safeBlockHash parameter"
safeBlockHash: headBlock.asBlockHash,
finalizedBlockHash: finalizedBlock.asBlockHash), finalizedBlockHash: finalizedBlock.asBlockHash),
some(engine_api.PayloadAttributesV1( some(engine_api.PayloadAttributesV1(
timestamp: Quantity timestamp, timestamp: Quantity timestamp,

View File

@ -413,6 +413,11 @@ proc get_head*(self: var ForkChoice,
self.checkpoints.justified.balances, self.checkpoints.justified.balances,
self.checkpoints.proposer_boost_root) self.checkpoints.proposer_boost_root)
# https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.3/fork_choice/safe-block.md#get_safe_beacon_block_root
func get_safe_beacon_block_root*(self: var ForkChoice): Eth2Digest =
# Use most recent justified block as a stopgap
self.checkpoints.justified.checkpoint.root
func prune*( func prune*(
self: var ForkChoiceBackend, finalized_root: Eth2Digest self: var ForkChoiceBackend, finalized_root: Eth2Digest
): FcResult[void] = ): FcResult[void] =

View File

@ -173,20 +173,20 @@ from ../eth1/eth1_monitor import
Eth1Monitor, asEngineExecutionPayload, ensureDataProvider, newPayload Eth1Monitor, asEngineExecutionPayload, ensureDataProvider, newPayload
proc expectValidForkchoiceUpdated( proc expectValidForkchoiceUpdated(
eth1Monitor: Eth1Monitor, headBlockRoot, finalizedBlockRoot: Eth2Digest): eth1Monitor: Eth1Monitor,
Future[void] {.async.} = headBlockRoot, safeBlockRoot, finalizedBlockRoot: Eth2Digest
): Future[void] {.async.} =
let payloadExecutionStatus = let payloadExecutionStatus =
await eth1Monitor.runForkchoiceUpdated(headBlockRoot, finalizedBlockRoot) await eth1Monitor.runForkchoiceUpdated(
headBlockRoot, safeBlockRoot, finalizedBlockRoot)
if payloadExecutionStatus != PayloadExecutionStatus.valid: if payloadExecutionStatus != PayloadExecutionStatus.valid:
# Only called when expecting this to be valid because `newPayload` or some # Only called when expecting this to be valid because `newPayload` or some
# previous `forkchoiceUpdated` had already marked it as valid. # previous `forkchoiceUpdated` had already marked it as valid.
warn "expectValidForkchoiceUpdate: forkChoiceUpdated not `VALID`", warn "expectValidForkchoiceUpdate: forkChoiceUpdated not `VALID`",
payloadExecutionStatus, payloadExecutionStatus, headBlockRoot, safeBlockRoot, finalizedBlockRoot
headBlockRoot,
finalizedBlockRoot
from ../consensus_object_pools/attestation_pool import from ../consensus_object_pools/attestation_pool import
addForkChoice, selectOptimisticHead addForkChoice, selectOptimisticHead, BeaconHead
from ../consensus_object_pools/blockchain_dag import from ../consensus_object_pools/blockchain_dag import
is_optimistic, loadExecutionBlockRoot, markBlockVerified is_optimistic, loadExecutionBlockRoot, markBlockVerified
from ../consensus_object_pools/block_dag import shortLog from ../consensus_object_pools/block_dag import shortLog
@ -294,20 +294,20 @@ proc storeBlock*(
wallSlot.start_beacon_time) wallSlot.start_beacon_time)
if newHead.isOk: if newHead.isOk:
let executionHeadRoot = let headExecutionPayloadHash =
self.consensusManager.dag.loadExecutionBlockRoot(newHead.get) self.consensusManager.dag.loadExecutionBlockRoot(newHead.get.blck)
if executionHeadRoot.isZero: if headExecutionPayloadHash.isZero:
# Blocks without execution payloads can't be optimistic. # Blocks without execution payloads can't be optimistic.
self.consensusManager[].updateHead(newHead.get) self.consensusManager[].updateHead(newHead.get.blck)
elif not self.consensusManager.dag.is_optimistic newHead.get.root: elif not self.consensusManager.dag.is_optimistic newHead.get.blck.root:
# Not `NOT_VALID`; either `VALID` or `INVALIDATED`, but latter wouldn't # Not `NOT_VALID`; either `VALID` or `INVALIDATED`, but latter wouldn't
# be selected as head, so `VALID`. `forkchoiceUpdated` necessary for EL # be selected as head, so `VALID`. `forkchoiceUpdated` necessary for EL
# client only. # client only.
self.consensusManager[].updateHead(newHead.get) self.consensusManager[].updateHead(newHead.get.blck)
asyncSpawn self.consensusManager.eth1Monitor.expectValidForkchoiceUpdated( asyncSpawn self.consensusManager.eth1Monitor.expectValidForkchoiceUpdated(
executionHeadRoot, headExecutionPayloadHash,
self.consensusManager.dag.loadExecutionBlockRoot( newHead.get.safeExecutionPayloadHash,
self.consensusManager.dag.finalizedHead.blck)) newHead.get.finalizedExecutionPayloadHash)
# TODO remove redundant fcU in case of proposal # TODO remove redundant fcU in case of proposal
asyncSpawn self.consensusManager.runProposalForkchoiceUpdated() asyncSpawn self.consensusManager.runProposalForkchoiceUpdated()

View File

@ -90,6 +90,7 @@ programMain:
# engine_forkchoiceUpdatedV1 # engine_forkchoiceUpdatedV1
discard await eth1Monitor.runForkchoiceUpdated( discard await eth1Monitor.runForkchoiceUpdated(
headBlockRoot = payload.block_hash, headBlockRoot = payload.block_hash,
safeBlockRoot = payload.block_hash, # stub value
finalizedBlockRoot = ZERO_HASH) finalizedBlockRoot = ZERO_HASH)
else: discard else: discard
return return

View File

@ -313,6 +313,7 @@ from web3/engine_api import ForkchoiceUpdatedResponse
# TODO: This copies the entire BeaconState on each call # TODO: This copies the entire BeaconState on each call
proc forkchoice_updated(state: bellatrix.BeaconState, proc forkchoice_updated(state: bellatrix.BeaconState,
head_block_hash: Eth2Digest, head_block_hash: Eth2Digest,
safe_block_hash: Eth2Digest,
finalized_block_hash: Eth2Digest, finalized_block_hash: Eth2Digest,
fee_recipient: ethtypes.Address, fee_recipient: ethtypes.Address,
execution_engine: Eth1Monitor): execution_engine: Eth1Monitor):
@ -328,8 +329,8 @@ proc forkchoice_updated(state: bellatrix.BeaconState,
try: try:
awaitWithTimeout( awaitWithTimeout(
execution_engine.forkchoiceUpdated( execution_engine.forkchoiceUpdated(
head_block_hash, finalized_block_hash, timestamp, random.data, head_block_hash, safe_block_hash, finalized_block_hash,
fee_recipient), timestamp, random.data, fee_recipient),
FORKCHOICEUPDATED_TIMEOUT): FORKCHOICEUPDATED_TIMEOUT):
error "Engine API fork-choice update timed out" error "Engine API fork-choice update timed out"
default(ForkchoiceUpdatedResponse) default(ForkchoiceUpdatedResponse)
@ -398,14 +399,15 @@ proc getExecutionPayload(
node.eth1Monitor.terminalBlockHash.get.asEth2Digest node.eth1Monitor.terminalBlockHash.get.asEth2Digest
else: else:
default(Eth2Digest) default(Eth2Digest)
executionBlockRoot = node.dag.loadExecutionBlockRoot(node.dag.head) beaconHead = node.attestationPool[].getBeaconHead(node.dag.head)
executionBlockRoot = node.dag.loadExecutionBlockRoot(beaconHead.blck)
latestHead = latestHead =
if not executionBlockRoot.isZero: if not executionBlockRoot.isZero:
executionBlockRoot executionBlockRoot
else: else:
terminalBlockHash terminalBlockHash
latestFinalized = latestSafe = beaconHead.safeExecutionPayloadHash
node.dag.loadExecutionBlockRoot(node.dag.finalizedHead.blck) latestFinalized = beaconHead.finalizedExecutionPayloadHash
feeRecipient = node.getFeeRecipient(pubkey, validator_index, epoch) feeRecipient = node.getFeeRecipient(pubkey, validator_index, epoch)
lastFcU = node.consensusManager.forkchoiceUpdatedInfo lastFcU = node.consensusManager.forkchoiceUpdatedInfo
timestamp = compute_timestamp_at_slot( timestamp = compute_timestamp_at_slot(
@ -414,14 +416,14 @@ proc getExecutionPayload(
payload_id = payload_id =
if lastFcU.isSome and if lastFcU.isSome and
lastFcU.get.headBlockRoot == latestHead and lastFcU.get.headBlockRoot == latestHead and
lastFcU.get.safeBlockRoot == latestSafe and
lastFcU.get.finalizedBlockRoot == latestFinalized and lastFcU.get.finalizedBlockRoot == latestFinalized and
lastFcU.get.timestamp == timestamp and lastFcU.get.timestamp == timestamp and
lastFcU.get.feeRecipient == feeRecipient: lastFcU.get.feeRecipient == feeRecipient:
some bellatrix.PayloadID(lastFcU.get.payloadId) some bellatrix.PayloadID(lastFcU.get.payloadId)
else: else:
debug "getExecutionPayload: didn't find payloadId, re-querying", debug "getExecutionPayload: didn't find payloadId, re-querying",
latestHead, latestHead, latestSafe, latestFinalized,
latestFinalized,
timestamp, timestamp,
feeRecipient, feeRecipient,
cachedHeadBlockRoot = lastFcU.get.headBlockRoot, cachedHeadBlockRoot = lastFcU.get.headBlockRoot,
@ -430,7 +432,8 @@ proc getExecutionPayload(
cachedFeeRecipient = lastFcU.get.feeRecipient cachedFeeRecipient = lastFcU.get.feeRecipient
(await forkchoice_updated( (await forkchoice_updated(
proposalState.bellatrixData.data, latestHead, latestFinalized, proposalState.bellatrixData.data,
latestHead, latestSafe, latestFinalized,
feeRecipient, node.consensusManager.eth1Monitor)) feeRecipient, node.consensusManager.eth1Monitor))
payload = try: payload = try:
awaitWithTimeout( awaitWithTimeout(

View File

@ -416,7 +416,8 @@ suite "Attestation pool processing" & preset():
epochRef, blckRef, unrealized, signedBlock.message, epochRef, blckRef, unrealized, signedBlock.message,
blckRef.slot.start_beacon_time) blckRef.slot.start_beacon_time)
let head = pool[].selectOptimisticHead(b1Add[].slot.start_beacon_time).get() let head =
pool[].selectOptimisticHead(b1Add[].slot.start_beacon_time).get().blck
check: check:
head == b1Add[] head == b1Add[]
@ -430,7 +431,8 @@ suite "Attestation pool processing" & preset():
epochRef, blckRef, unrealized, signedBlock.message, epochRef, blckRef, unrealized, signedBlock.message,
blckRef.slot.start_beacon_time) blckRef.slot.start_beacon_time)
let head2 = pool[].selectOptimisticHead(b2Add[].slot.start_beacon_time).get() let head2 =
pool[].selectOptimisticHead(b2Add[].slot.start_beacon_time).get().blck
check: check:
head2 == b2Add[] head2 == b2Add[]
@ -447,7 +449,8 @@ suite "Attestation pool processing" & preset():
epochRef, blckRef, unrealized, signedBlock.message, epochRef, blckRef, unrealized, signedBlock.message,
blckRef.slot.start_beacon_time) blckRef.slot.start_beacon_time)
let head = pool[].selectOptimisticHead(b10Add[].slot.start_beacon_time).get() let head =
pool[].selectOptimisticHead(b10Add[].slot.start_beacon_time).get().blck
check: check:
head == b10Add[] head == b10Add[]
@ -475,7 +478,8 @@ suite "Attestation pool processing" & preset():
attestation0, @[bc1[0]], attestation0.loadSig, attestation0, @[bc1[0]], attestation0.loadSig,
attestation0.data.slot.start_beacon_time) attestation0.data.slot.start_beacon_time)
let head2 = pool[].selectOptimisticHead(b10Add[].slot.start_beacon_time).get() let head2 =
pool[].selectOptimisticHead(b10Add[].slot.start_beacon_time).get().blck
check: check:
# Single vote for b10 and no votes for b11 # Single vote for b10 and no votes for b11
@ -488,7 +492,8 @@ suite "Attestation pool processing" & preset():
attestation1, @[bc1[1]], attestation1.loadSig, attestation1, @[bc1[1]], attestation1.loadSig,
attestation1.data.slot.start_beacon_time) attestation1.data.slot.start_beacon_time)
let head3 = pool[].selectOptimisticHead(b10Add[].slot.start_beacon_time).get() let head3 =
pool[].selectOptimisticHead(b10Add[].slot.start_beacon_time).get().blck
let bigger = if b11.root.data < b10.root.data: b10Add else: b11Add let bigger = if b11.root.data < b10.root.data: b10Add else: b11Add
check: check:
@ -499,7 +504,8 @@ suite "Attestation pool processing" & preset():
attestation2, @[bc1[2]], attestation2.loadSig, attestation2, @[bc1[2]], attestation2.loadSig,
attestation2.data.slot.start_beacon_time) attestation2.data.slot.start_beacon_time)
let head4 = pool[].selectOptimisticHead(b11Add[].slot.start_beacon_time).get() let head4 =
pool[].selectOptimisticHead(b11Add[].slot.start_beacon_time).get().blck
check: check:
# Two votes for b11 # Two votes for b11
@ -517,7 +523,8 @@ suite "Attestation pool processing" & preset():
epochRef, blckRef, unrealized, signedBlock.message, epochRef, blckRef, unrealized, signedBlock.message,
blckRef.slot.start_beacon_time) blckRef.slot.start_beacon_time)
let head = pool[].selectOptimisticHead(b10Add[].slot.start_beacon_time).get() let head =
pool[].selectOptimisticHead(b10Add[].slot.start_beacon_time).get().blck
check: check:
head == b10Add[] head == b10Add[]
@ -550,7 +557,8 @@ suite "Attestation pool processing" & preset():
epochRef, blckRef, unrealized, signedBlock.message, epochRef, blckRef, unrealized, signedBlock.message,
blckRef.slot.start_beacon_time) blckRef.slot.start_beacon_time)
let head = pool[].selectOptimisticHead(b10Add[].slot.start_beacon_time).get() let head =
pool[].selectOptimisticHead(b10Add[].slot.start_beacon_time).get().blck
doAssert: head == b10Add[] doAssert: head == b10Add[]
@ -577,7 +585,9 @@ suite "Attestation pool processing" & preset():
epochRef, blckRef, unrealized, signedBlock.message, epochRef, blckRef, unrealized, signedBlock.message,
blckRef.slot.start_beacon_time) blckRef.slot.start_beacon_time)
let head = pool[].selectOptimisticHead(blockRef[].slot.start_beacon_time).get() let head =
pool[].selectOptimisticHead(
blockRef[].slot.start_beacon_time).get().blck
doAssert: head == blockRef[] doAssert: head == blockRef[]
dag.updateHead(head, quarantine[]) dag.updateHead(head, quarantine[])
pruneAtFinalization(dag, pool[]) pruneAtFinalization(dag, pool[])