VC: Obtain randao signature before slot proposal. (#5490)
* Randao calculation caching for VC implementation. * Add time monitoring for randao signatures process. * Add delay calculation. * Address review comments. * Address review comments.
This commit is contained in:
parent
29fe958908
commit
8cec3af61c
|
@ -32,6 +32,9 @@ type
|
|||
blockRoot*: Eth2Digest
|
||||
data*: ForkedBlindedBeaconBlock
|
||||
|
||||
proc proposeBlock(vc: ValidatorClientRef, slot: Slot,
|
||||
proposerKey: ValidatorPubKey) {.async.}
|
||||
|
||||
proc produceBlock(
|
||||
vc: ValidatorClientRef,
|
||||
currentSlot, slot: Slot,
|
||||
|
@ -86,7 +89,6 @@ proc produceBlock(
|
|||
data: ForkedBeaconBlock.init(blck),
|
||||
blobsOpt: Opt.some(blobs)))
|
||||
|
||||
|
||||
proc produceBlindedBlock(
|
||||
vc: ValidatorClientRef,
|
||||
currentSlot, slot: Slot,
|
||||
|
@ -125,6 +127,58 @@ proc lazyWait[T](fut: Future[T]) {.async.} =
|
|||
except CatchableError:
|
||||
discard
|
||||
|
||||
proc prepareRandao(vc: ValidatorClientRef, slot: Slot,
|
||||
proposerKey: ValidatorPubKey) {.async.} =
|
||||
if slot == GENESIS_SLOT:
|
||||
return
|
||||
|
||||
let
|
||||
destSlot = slot - 1'u64
|
||||
destOffset = TimeDiff(nanoseconds: NANOSECONDS_PER_SLOT.int64 div 2)
|
||||
deadline = destSlot.start_beacon_time() + destOffset
|
||||
epoch = slot.epoch()
|
||||
# We going to wait to T - (T / 4 * 2), where T is proposer's
|
||||
# duty slot.
|
||||
currentSlot = (await vc.checkedWaitForSlot(destSlot, destOffset,
|
||||
false)).valueOr:
|
||||
debug "Unable to perform RANDAO signature preparation because of " &
|
||||
"system time failure"
|
||||
return
|
||||
validator =
|
||||
vc.getValidatorForDuties(proposerKey, slot, true).valueOr: return
|
||||
|
||||
if currentSlot <= destSlot:
|
||||
# We do not need result, because we want it to be cached.
|
||||
let
|
||||
start = Moment.now()
|
||||
genesisRoot = vc.beaconGenesis.genesis_validators_root
|
||||
fork = vc.forkAtEpoch(epoch)
|
||||
rsig = await validator.getEpochSignature(fork, genesisRoot, epoch)
|
||||
timeElapsed = Moment.now() - start
|
||||
if rsig.isErr():
|
||||
debug "Unable to prepare RANDAO signature", epoch = epoch,
|
||||
validator = shortLog(validator), elapsed_time = timeElapsed,
|
||||
current_slot = currentSlot, destination_slot = destSlot,
|
||||
delay = vc.getDelay(deadline)
|
||||
else:
|
||||
debug "RANDAO signature has been prepared", epoch = epoch,
|
||||
validator = shortLog(validator), elapsed_time = timeElapsed,
|
||||
current_slot = currentSlot, destination_slot = destSlot,
|
||||
delay = vc.getDelay(deadline)
|
||||
else:
|
||||
debug "RANDAO signature preparation timed out", epoch = epoch,
|
||||
validator = shortLog(validator),
|
||||
current_slot = currentSlot, destination_slot = destSlot,
|
||||
delay = vc.getDelay(deadline)
|
||||
|
||||
proc spawnProposalTask(vc: ValidatorClientRef,
|
||||
duty: RestProposerDuty): ProposerTask =
|
||||
ProposerTask(
|
||||
randaoFut: prepareRandao(vc, duty.slot, duty.pubkey),
|
||||
proposeFut: proposeBlock(vc, duty.slot, duty.pubkey),
|
||||
duty: duty
|
||||
)
|
||||
|
||||
proc publishBlock(vc: ValidatorClientRef, currentSlot, slot: Slot,
|
||||
validator: AttachedValidator) {.async.} =
|
||||
let
|
||||
|
@ -146,21 +200,22 @@ proc publishBlock(vc: ValidatorClientRef, currentSlot, slot: Slot,
|
|||
debug "Publishing block", delay = vc.getDelay(slot.block_deadline()),
|
||||
genesis_root = genesisRoot,
|
||||
graffiti = graffiti, fork = fork
|
||||
let randaoReveal =
|
||||
try:
|
||||
let res = await validator.getEpochSignature(fork, genesisRoot, slot.epoch)
|
||||
if res.isErr():
|
||||
warn "Unable to generate randao reveal using remote signer",
|
||||
reason = res.error()
|
||||
|
||||
let
|
||||
randaoReveal =
|
||||
try:
|
||||
(await validator.getEpochSignature(fork, genesisRoot,
|
||||
slot.epoch())).valueOr:
|
||||
warn "Unable to generate RANDAO reveal using remote signer",
|
||||
reason = error
|
||||
return
|
||||
except CancelledError as exc:
|
||||
debug "RANDAO reveal production has been interrupted"
|
||||
raise exc
|
||||
except CatchableError as exc:
|
||||
error "An unexpected error occurred while receiving RANDAO data",
|
||||
error_name = exc.name, error_msg = exc.msg
|
||||
return
|
||||
res.get()
|
||||
except CancelledError as exc:
|
||||
debug "Randao reveal production has been interrupted"
|
||||
raise exc
|
||||
except CatchableError as exc:
|
||||
error "An unexpected error occurred while receiving randao data",
|
||||
error_name = exc.name, error_msg = exc.msg
|
||||
return
|
||||
|
||||
var beaconBlocks =
|
||||
block:
|
||||
|
@ -408,11 +463,6 @@ proc proposeBlock(vc: ValidatorClientRef, slot: Slot,
|
|||
error "Unexpected error encountered while proposing block",
|
||||
slot = slot, validator = shortLog(validator)
|
||||
|
||||
proc spawnProposalTask(vc: ValidatorClientRef,
|
||||
duty: RestProposerDuty): ProposerTask =
|
||||
let future = proposeBlock(vc, duty.slot, duty.pubkey)
|
||||
ProposerTask(future: future, duty: duty)
|
||||
|
||||
proc contains(data: openArray[RestProposerDuty], task: ProposerTask): bool =
|
||||
for item in data:
|
||||
if (item.pubkey == task.duty.pubkey) and (item.slot == task.duty.slot):
|
||||
|
@ -462,13 +512,14 @@ proc addOrReplaceProposers*(vc: ValidatorClientRef, epoch: Epoch,
|
|||
for task in epochDuties.duties:
|
||||
if task notin duties:
|
||||
# Task is no more relevant, so cancel it.
|
||||
debug "Cancelling running proposal duty task",
|
||||
debug "Cancelling running proposal duty tasks",
|
||||
slot = task.duty.slot,
|
||||
validator = shortLog(task.duty.pubkey)
|
||||
task.future.cancelSoon()
|
||||
task.proposeFut.cancelSoon()
|
||||
task.randaoFut.cancelSoon()
|
||||
else:
|
||||
# If task is already running for proper slot, we keep it alive.
|
||||
debug "Keep running previous proposal duty task",
|
||||
debug "Keep running previous proposal duty tasks",
|
||||
slot = task.duty.slot,
|
||||
validator = shortLog(task.duty.pubkey)
|
||||
res.add(task)
|
||||
|
@ -783,8 +834,10 @@ proc mainLoop(service: BlockServiceRef) {.async.} =
|
|||
var res: seq[FutureBase]
|
||||
for epoch, data in vc.proposers.pairs():
|
||||
for duty in data.duties.items():
|
||||
if not(duty.future.finished()):
|
||||
res.add(duty.future.cancelAndWait())
|
||||
if not(duty.proposeFut.finished()):
|
||||
res.add(duty.proposeFut.cancelAndWait())
|
||||
if not(duty.randaoFut.finished()):
|
||||
res.add(duty.randaoFut.cancelAndWait())
|
||||
await noCancel allFutures(res)
|
||||
|
||||
proc init*(t: typedesc[BlockServiceRef],
|
||||
|
|
|
@ -95,7 +95,8 @@ type
|
|||
|
||||
ProposerTask* = object
|
||||
duty*: RestProposerDuty
|
||||
future*: Future[void]
|
||||
proposeFut*: Future[void]
|
||||
randaoFut*: Future[void]
|
||||
|
||||
ProposedData* = object
|
||||
epoch*: Epoch
|
||||
|
|
|
@ -66,6 +66,10 @@ type
|
|||
# if the validator will be aggregating (in the near future)
|
||||
slotSignature*: Opt[tuple[slot: Slot, signature: ValidatorSig]]
|
||||
|
||||
# Cache the latest epoch signature - the epoch signature is used for block
|
||||
# proposing.
|
||||
epochSignature*: Opt[tuple[epoch: Epoch, signature: ValidatorSig]]
|
||||
|
||||
# For the external payload builder; each epoch, the external payload
|
||||
# builder should be informed of current validators
|
||||
externalBuilderRegistration*: Opt[SignedValidatorRegistrationV1]
|
||||
|
@ -746,7 +750,10 @@ proc getContributionAndProofSignature*(v: AttachedValidator, fork: Fork,
|
|||
proc getEpochSignature*(v: AttachedValidator, fork: Fork,
|
||||
genesis_validators_root: Eth2Digest, epoch: Epoch
|
||||
): Future[SignatureResult] {.async.} =
|
||||
return
|
||||
if v.epochSignature.isSome and v.epochSignature.get.epoch == epoch:
|
||||
return SignatureResult.ok(v.epochSignature.get.signature)
|
||||
|
||||
let signature =
|
||||
case v.kind
|
||||
of ValidatorKind.Local:
|
||||
SignatureResult.ok(get_epoch_signature(
|
||||
|
@ -757,6 +764,12 @@ proc getEpochSignature*(v: AttachedValidator, fork: Fork,
|
|||
fork, genesis_validators_root, epoch)
|
||||
await v.signData(request)
|
||||
|
||||
if signature.isErr:
|
||||
return signature
|
||||
|
||||
v.epochSignature = Opt.some((epoch, signature.get))
|
||||
signature
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.1/specs/phase0/validator.md#aggregation-selection
|
||||
proc getSlotSignature*(v: AttachedValidator, fork: Fork,
|
||||
genesis_validators_root: Eth2Digest, slot: Slot
|
||||
|
|
Loading…
Reference in New Issue