-
Notifications
You must be signed in to change notification settings - Fork 258
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
allow execution clients several seconds to construct blocks #4012
Changes from all commits
e7f6aac
223f949
f8b4984
bea11e8
38609e0
00ba2b2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,7 +16,20 @@ import | |
../consensus_object_pools/[blockchain_dag, block_quarantine, attestation_pool], | ||
../eth1/eth1_monitor | ||
|
||
from ../spec/eth2_apis/dynamic_fee_recipients import | ||
DynamicFeeRecipientsStore, getDynamicFeeRecipient | ||
from ../validators/keystore_management import | ||
KeymanagerHost, getSuggestedFeeRecipient | ||
|
||
type | ||
ForkChoiceUpdatedInformation* = object | ||
payloadId*: PayloadID | ||
headBlockRoot*: Eth2Digest | ||
safeBlockRoot*: Eth2Digest | ||
finalizedBlockRoot*: Eth2Digest | ||
timestamp*: uint64 | ||
feeRecipient*: Eth1Address | ||
|
||
ConsensusManager* = object | ||
expectedSlot: Slot | ||
expectedBlockReceived: Future[bool] | ||
|
@@ -34,20 +47,37 @@ type | |
# ---------------------------------------------------------------- | ||
eth1Monitor*: Eth1Monitor | ||
|
||
# Allow determination of preferred fee recipient during proposals | ||
# ---------------------------------------------------------------- | ||
dynamicFeeRecipientsStore: ref DynamicFeeRecipientsStore | ||
keymanagerHost: ref KeymanagerHost | ||
defaultFeeRecipient: Eth1Address | ||
|
||
# Tracking last proposal forkchoiceUpdated payload information | ||
# ---------------------------------------------------------------- | ||
forkchoiceUpdatedInfo*: Opt[ForkchoiceUpdatedInformation] | ||
|
||
# Initialization | ||
# ------------------------------------------------------------------------------ | ||
|
||
func new*(T: type ConsensusManager, | ||
dag: ChainDAGRef, | ||
attestationPool: ref AttestationPool, | ||
quarantine: ref Quarantine, | ||
eth1Monitor: Eth1Monitor | ||
eth1Monitor: Eth1Monitor, | ||
dynamicFeeRecipientsStore: ref DynamicFeeRecipientsStore, | ||
keymanagerHost: ref KeymanagerHost, | ||
defaultFeeRecipient: Eth1Address | ||
): ref ConsensusManager = | ||
(ref ConsensusManager)( | ||
dag: dag, | ||
attestationPool: attestationPool, | ||
quarantine: quarantine, | ||
eth1Monitor: eth1Monitor | ||
eth1Monitor: eth1Monitor, | ||
dynamicFeeRecipientsStore: dynamicFeeRecipientsStore, | ||
keymanagerHost: keymanagerHost, | ||
forkchoiceUpdatedInfo: Opt.none ForkchoiceUpdatedInformation, | ||
defaultFeeRecipient: defaultFeeRecipient | ||
) | ||
|
||
# Consensus Management | ||
|
@@ -182,6 +212,71 @@ proc updateHead*(self: var ConsensusManager, wallSlot: Slot) = | |
|
||
self.updateHead(newHead) | ||
|
||
proc checkNextProposer(dag: ChainDAGRef, slot: Slot): | ||
Opt[(ValidatorIndex, ValidatorPubKey)] = | ||
let proposer = dag.getProposer(dag.head, slot + 1) | ||
if proposer.isNone(): | ||
return Opt.none((ValidatorIndex, ValidatorPubKey)) | ||
Opt.some((proposer.get, dag.validatorKey(proposer.get).get().toPubKey)) | ||
|
||
proc getFeeRecipient*( | ||
self: ref ConsensusManager, pubkey: ValidatorPubKey, validatorIdx: ValidatorIndex, | ||
epoch: Epoch): Eth1Address = | ||
self.dynamicFeeRecipientsStore[].getDynamicFeeRecipient(validatorIdx, epoch).valueOr: | ||
if self.keymanagerHost != nil: | ||
self.keymanagerHost[].getSuggestedFeeRecipient(pubkey).valueOr: | ||
self.defaultFeeRecipient | ||
else: | ||
self.defaultFeeRecipient | ||
|
||
from ../spec/datatypes/bellatrix import PayloadID | ||
|
||
proc runProposalForkchoiceUpdated*(self: ref ConsensusManager) {.async.} = | ||
withState(self.dag.headState): | ||
let | ||
nextSlot = state.data.slot + 1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Edge cases:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wastes a bit of time on the EL locally, nothing else. |
||
(validatorIndex, nextProposer) = | ||
self.dag.checkNextProposer(nextSlot).valueOr: | ||
return | ||
|
||
# Approximately lines up with validator_duties version. Used optimistcally/ | ||
# opportunistically, so mismatches are fine if not too frequent. | ||
let | ||
timestamp = compute_timestamp_at_slot(state.data, nextSlot) | ||
randomData = | ||
get_randao_mix(state.data, get_current_epoch(state.data)).data | ||
feeRecipient = self.getFeeRecipient( | ||
nextProposer, validatorIndex, nextSlot.epoch) | ||
headBlockRoot = self.dag.loadExecutionBlockRoot(self.dag.head) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As this is called from an async context, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
finalizedBlockRoot = | ||
self.dag.loadExecutionBlockRoot(self.dag.finalizedHead.blck) | ||
|
||
if headBlockRoot.isZero: | ||
return | ||
|
||
try: | ||
let fcResult = awaitWithTimeout( | ||
forkchoiceUpdated( | ||
self.eth1Monitor, headBlockRoot, finalizedBlockRoot, timestamp, | ||
randomData, feeRecipient), | ||
FORKCHOICEUPDATED_TIMEOUT): | ||
debug "runProposalForkchoiceUpdated: forkchoiceUpdated timed out" | ||
ForkchoiceUpdatedResponse( | ||
payloadStatus: PayloadStatusV1(status: PayloadExecutionStatus.syncing)) | ||
|
||
if fcResult.payloadStatus.status != PayloadExecutionStatus.valid or | ||
fcResult.payloadId.isNone: | ||
return | ||
|
||
self.forkchoiceUpdatedInfo = Opt.some ForkchoiceUpdatedInformation( | ||
payloadId: bellatrix.PayloadID(fcResult.payloadId.get), | ||
headBlockRoot: headBlockRoot, | ||
finalizedBlockRoot: finalizedBlockRoot, | ||
timestamp: timestamp, | ||
feeRecipient: feeRecipient) | ||
except CatchableError as err: | ||
error "Engine API fork-choice update failed", err = err.msg | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure if ideal. Those are maybe best when it's verifying something truly Nimbus-internal, but this isn't. There are exogenous factors involved here, and |
||
|
||
proc updateHeadWithExecution*(self: ref ConsensusManager, newHead: BlockRef) | ||
{.async.} = | ||
## Trigger fork choice and update the DAG with the new head block | ||
|
@@ -197,6 +292,10 @@ proc updateHeadWithExecution*(self: ref ConsensusManager, newHead: BlockRef) | |
# justified and finalized | ||
self.dag.updateHead(newHead, self.quarantine[]) | ||
|
||
# TODO after things stabilize with this, check for upcoming proposal and | ||
# don't bother sending first fcU, but initially, keep both in place | ||
asyncSpawn self.runProposalForkchoiceUpdated() | ||
Comment on lines
+295
to
+297
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is yet another There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It has to wait until There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. f8b4984 runs it when |
||
|
||
self[].checkExpectedBlock() | ||
except CatchableError as exc: | ||
debug "updateHeadWithExecution error", | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm,
dag.getProposer
already validates thatdag.validatorKey
will returnsome
result.