mirror of
https://github.com/status-im/nimbus-eth2.git
synced 2025-01-14 00:29:04 +00:00
support electra block proposals for internal BN validators (#6187)
This commit is contained in:
parent
b8eb51852c
commit
6ce5d5814c
@ -105,7 +105,6 @@ type
|
||||
processingDelay*: Opt[Duration]
|
||||
lastValidAttestedBlock*: Opt[BlockSlot]
|
||||
|
||||
# TODO stew/sequtils2
|
||||
template findIt*(s: openArray, predicate: untyped): int =
|
||||
var res = -1
|
||||
for i, it {.inject.} in s:
|
||||
|
@ -168,7 +168,6 @@ func get_attesting_indices*(shufflingRef: ShufflingRef,
|
||||
committee_index: CommitteeIndex,
|
||||
bits: CommitteeValidatorsBits):
|
||||
seq[ValidatorIndex] =
|
||||
# TODO sequtils2 mapIt
|
||||
for idx in get_attesting_indices(shufflingRef, slot, committee_index, bits):
|
||||
result.add(idx)
|
||||
|
||||
|
@ -88,6 +88,7 @@ RestJson.useDefaultSerializationFor(
|
||||
GetForkScheduleResponse,
|
||||
GetGenesisResponse,
|
||||
GetHeaderResponseDeneb,
|
||||
GetHeaderResponseElectra,
|
||||
GetKeystoresResponse,
|
||||
GetNextWithdrawalsResponse,
|
||||
GetPoolAttesterSlashingsResponse,
|
||||
@ -253,8 +254,10 @@ RestJson.useDefaultSerializationFor(
|
||||
electra.SignedBeaconBlock,
|
||||
electra_mev.BlindedBeaconBlock,
|
||||
electra_mev.BlindedBeaconBlockBody,
|
||||
electra_mev.BuilderBid,
|
||||
electra_mev.ExecutionPayloadAndBlobsBundle,
|
||||
electra_mev.SignedBlindedBeaconBlock,
|
||||
electra_mev.SignedBuilderBid,
|
||||
phase0.BeaconBlock,
|
||||
phase0.BeaconBlockBody,
|
||||
phase0.BeaconState,
|
||||
|
@ -548,6 +548,7 @@ type
|
||||
GetForkScheduleResponse* = DataEnclosedObject[seq[Fork]]
|
||||
GetGenesisResponse* = DataEnclosedObject[RestGenesis]
|
||||
GetHeaderResponseDeneb* = DataVersionEnclosedObject[deneb_mev.SignedBuilderBid]
|
||||
GetHeaderResponseElectra* = DataVersionEnclosedObject[electra_mev.SignedBuilderBid]
|
||||
GetNetworkIdentityResponse* = DataEnclosedObject[RestNetworkIdentity]
|
||||
GetPeerCountResponse* = DataMetaEnclosedObject[RestPeerCount]
|
||||
GetPeerResponse* = DataMetaEnclosedObject[RestNodePeer]
|
||||
|
@ -13,6 +13,14 @@ import
|
||||
|
||||
export chronos, client, rest_types, eth2_rest_serialization
|
||||
|
||||
proc getHeaderElectra*(slot: Slot,
|
||||
parent_hash: Eth2Digest,
|
||||
pubkey: ValidatorPubKey
|
||||
): RestPlainResponse {.
|
||||
rest, endpoint: "/eth/v1/builder/header/{slot}/{parent_hash}/{pubkey}",
|
||||
meth: MethodGet, connection: {Dedicated, Close}.}
|
||||
## https://github.com/ethereum/builder-specs/blob/v0.4.0/apis/builder/header.yaml
|
||||
|
||||
proc submitBlindedBlock*(body: electra_mev.SignedBlindedBeaconBlock
|
||||
): RestPlainResponse {.
|
||||
rest, endpoint: "/eth/v1/builder/blinded_blocks",
|
||||
|
@ -371,7 +371,8 @@ proc verify_contribution_and_proof_signature*(
|
||||
# https://github.com/ethereum/builder-specs/blob/v0.4.0/specs/bellatrix/builder.md#signing
|
||||
func compute_builder_signing_root(
|
||||
fork: Fork,
|
||||
msg: deneb_mev.BuilderBid | ValidatorRegistrationV1): Eth2Digest =
|
||||
msg: deneb_mev.BuilderBid | electra_mev.BuilderBid |
|
||||
ValidatorRegistrationV1): Eth2Digest =
|
||||
# Uses genesis fork version regardless
|
||||
doAssert fork.current_version == fork.previous_version
|
||||
|
||||
@ -386,7 +387,7 @@ proc get_builder_signature*(
|
||||
blsSign(privkey, signing_root.data)
|
||||
|
||||
proc verify_builder_signature*(
|
||||
fork: Fork, msg: deneb_mev.BuilderBid,
|
||||
fork: Fork, msg: deneb_mev.BuilderBid | electra_mev.BuilderBid,
|
||||
pubkey: ValidatorPubKey | CookedPubKey, signature: SomeSig): bool =
|
||||
let signing_root = compute_builder_signing_root(fork, msg)
|
||||
blsVerify(pubkey, signing_root.data, signature)
|
||||
|
@ -573,7 +573,6 @@ proc process_sync_aggregate*(
|
||||
# Apply participant and proposer rewards
|
||||
let indices = get_sync_committee_cache(state, cache).current_sync_committee
|
||||
|
||||
# TODO could use a sequtils2 zipIt
|
||||
for i in 0 ..< min(
|
||||
state.current_sync_committee.pubkeys.len,
|
||||
sync_aggregate.sync_committee_bits.len):
|
||||
|
@ -565,7 +565,8 @@ proc makeBeaconBlockForHeadAndSlot*(
|
||||
kzg_commitments = Opt.none(KzgCommitments))
|
||||
|
||||
proc getBlindedExecutionPayload[
|
||||
EPH: deneb_mev.BlindedExecutionPayloadAndBlobsBundle](
|
||||
EPH: deneb_mev.BlindedExecutionPayloadAndBlobsBundle |
|
||||
electra_mev.BlindedExecutionPayloadAndBlobsBundle](
|
||||
node: BeaconNode, payloadBuilderClient: RestClientRef, slot: Slot,
|
||||
executionBlockHash: Eth2Digest, pubkey: ValidatorPubKey):
|
||||
Future[BlindedBlockResult[EPH]] {.async: (raises: [CancelledError, RestError]).} =
|
||||
@ -587,6 +588,22 @@ proc getBlindedExecutionPayload[
|
||||
"Unable to decode Deneb blinded header: " & $res.error &
|
||||
" with HTTP status " & $response.status & ", Content-Type " &
|
||||
$response.contentType & " and content " & $response.data)
|
||||
elif EPH is electra_mev.BlindedExecutionPayloadAndBlobsBundle:
|
||||
let
|
||||
response = awaitWithTimeout(
|
||||
payloadBuilderClient.getHeaderElectra(
|
||||
slot, executionBlockHash, pubkey),
|
||||
BUILDER_PROPOSAL_DELAY_TOLERANCE):
|
||||
return err "Timeout obtaining Electra blinded header from builder"
|
||||
|
||||
res = decodeBytes(
|
||||
GetHeaderResponseElectra, response.data, response.contentType)
|
||||
|
||||
blindedHeader = res.valueOr:
|
||||
return err(
|
||||
"Unable to decode Electra blinded header: " & $res.error &
|
||||
" with HTTP status " & $response.status & ", Content-Type " &
|
||||
$response.contentType & " and content " & $response.data)
|
||||
else:
|
||||
static: doAssert false
|
||||
|
||||
@ -599,15 +616,12 @@ proc getBlindedExecutionPayload[
|
||||
blindedHeader.data.message.pubkey, blindedHeader.data.signature):
|
||||
return err "getBlindedExecutionPayload: signature verification failed"
|
||||
|
||||
when EPH is deneb_mev.BlindedExecutionPayloadAndBlobsBundle:
|
||||
template builderBid: untyped = blindedHeader.data.message
|
||||
return ok(BuilderBid[EPH](
|
||||
blindedBlckPart: EPH(
|
||||
execution_payload_header: builderBid.header,
|
||||
blob_kzg_commitments: builderBid.blob_kzg_commitments),
|
||||
executionPayloadValue: builderBid.value))
|
||||
else:
|
||||
static: doAssert false
|
||||
template builderBid: untyped = blindedHeader.data.message
|
||||
return ok(BuilderBid[EPH](
|
||||
blindedBlckPart: EPH(
|
||||
execution_payload_header: builderBid.header,
|
||||
blob_kzg_commitments: builderBid.blob_kzg_commitments),
|
||||
executionPayloadValue: builderBid.value))
|
||||
|
||||
from ./message_router_mev import
|
||||
copyFields, getFieldNames, unblindAndRouteBlockMEV
|
||||
@ -634,6 +648,28 @@ proc constructSignableBlindedBlock[T: deneb_mev.SignedBlindedBeaconBlock](
|
||||
|
||||
blindedBlock
|
||||
|
||||
proc constructSignableBlindedBlock[T: electra_mev.SignedBlindedBeaconBlock](
|
||||
blck: electra.BeaconBlock,
|
||||
blindedBundle: electra_mev.BlindedExecutionPayloadAndBlobsBundle): T =
|
||||
# Leaves signature field default, to be filled in by caller
|
||||
const
|
||||
blckFields = getFieldNames(typeof(blck))
|
||||
blckBodyFields = getFieldNames(typeof(blck.body))
|
||||
|
||||
var blindedBlock: T
|
||||
|
||||
# https://github.com/ethereum/builder-specs/blob/v0.4.0/specs/bellatrix/validator.md#block-proposal
|
||||
copyFields(blindedBlock.message, blck, blckFields)
|
||||
copyFields(blindedBlock.message.body, blck.body, blckBodyFields)
|
||||
assign(
|
||||
blindedBlock.message.body.execution_payload_header,
|
||||
blindedBundle.execution_payload_header)
|
||||
assign(
|
||||
blindedBlock.message.body.blob_kzg_commitments,
|
||||
blindedBundle.blob_kzg_commitments)
|
||||
|
||||
blindedBlock
|
||||
|
||||
func constructPlainBlindedBlock[T: deneb_mev.BlindedBeaconBlock](
|
||||
blck: ForkyBeaconBlock,
|
||||
blindedBundle: deneb_mev.BlindedExecutionPayloadAndBlobsBundle): T =
|
||||
@ -658,7 +694,9 @@ func constructPlainBlindedBlock[T: deneb_mev.BlindedBeaconBlock](
|
||||
|
||||
blindedBlock
|
||||
|
||||
proc blindedBlockCheckSlashingAndSign[T: deneb_mev.SignedBlindedBeaconBlock](
|
||||
proc blindedBlockCheckSlashingAndSign[
|
||||
T: deneb_mev.SignedBlindedBeaconBlock |
|
||||
electra_mev.SignedBlindedBeaconBlock](
|
||||
node: BeaconNode, slot: Slot, validator: AttachedValidator,
|
||||
validator_index: ValidatorIndex, nonsignedBlindedBlock: T):
|
||||
Future[Result[T, string]] {.async: (raises: [CancelledError]).} =
|
||||
@ -690,17 +728,21 @@ proc blindedBlockCheckSlashingAndSign[T: deneb_mev.SignedBlindedBeaconBlock](
|
||||
|
||||
return ok blindedBlock
|
||||
|
||||
proc getUnsignedBlindedBeaconBlock[T: deneb_mev.SignedBlindedBeaconBlock](
|
||||
proc getUnsignedBlindedBeaconBlock[
|
||||
T: deneb_mev.SignedBlindedBeaconBlock |
|
||||
electra_mev.SignedBlindedBeaconBlock](
|
||||
node: BeaconNode, slot: Slot,
|
||||
validator_index: ValidatorIndex, forkedBlock: ForkedBeaconBlock,
|
||||
executionPayloadHeader: capella.ExecutionPayloadHeader |
|
||||
deneb_mev.BlindedExecutionPayloadAndBlobsBundle):
|
||||
executionPayloadHeader: deneb_mev.BlindedExecutionPayloadAndBlobsBundle |
|
||||
electra_mev.BlindedExecutionPayloadAndBlobsBundle):
|
||||
Result[T, string] =
|
||||
withBlck(forkedBlock):
|
||||
when consensusFork >= ConsensusFork.Deneb:
|
||||
when not (
|
||||
(T is deneb_mev.SignedBlindedBeaconBlock and
|
||||
consensusFork == ConsensusFork.Deneb)):
|
||||
consensusFork == ConsensusFork.Deneb) or
|
||||
(T is electra_mev.SignedBlindedBeaconBlock and
|
||||
consensusFork == ConsensusFork.Electra)):
|
||||
return err("getUnsignedBlindedBeaconBlock: mismatched block/payload types")
|
||||
else:
|
||||
return ok constructSignableBlindedBlock[T](
|
||||
@ -709,8 +751,8 @@ proc getUnsignedBlindedBeaconBlock[T: deneb_mev.SignedBlindedBeaconBlock](
|
||||
return err("getUnsignedBlindedBeaconBlock: attempt to construct pre-Deneb blinded block")
|
||||
|
||||
proc getBlindedBlockParts[
|
||||
EPH: capella.ExecutionPayloadHeader |
|
||||
deneb_mev.BlindedExecutionPayloadAndBlobsBundle](
|
||||
EPH: deneb_mev.BlindedExecutionPayloadAndBlobsBundle |
|
||||
electra_mev.BlindedExecutionPayloadAndBlobsBundle](
|
||||
node: BeaconNode, payloadBuilderClient: RestClientRef, head: BlockRef,
|
||||
pubkey: ValidatorPubKey, slot: Slot, randao: ValidatorSig,
|
||||
validator_index: ValidatorIndex, graffiti: GraffitiBytes):
|
||||
@ -755,18 +797,7 @@ proc getBlindedBlockParts[
|
||||
#
|
||||
# This doesn't have withdrawals, which each node has regardless of engine or
|
||||
# builder API. makeBeaconBlockForHeadAndSlot fills it in later.
|
||||
when EPH is capella.ExecutionPayloadHeader:
|
||||
type PayloadType = capella.ExecutionPayloadForSigning
|
||||
template actualEPH: untyped = executionPayloadHeader.get.blindedBlckPart
|
||||
let withdrawals_root =
|
||||
Opt.some executionPayloadHeader.get.blindedBlckPart.withdrawals_root
|
||||
const kzg_commitments = Opt.none KzgCommitments
|
||||
|
||||
var shimExecutionPayload: PayloadType
|
||||
copyFields(
|
||||
shimExecutionPayload.executionPayload,
|
||||
executionPayloadHeader.get.blindedBlckPart, getFieldNames(EPH))
|
||||
elif EPH is deneb_mev.BlindedExecutionPayloadAndBlobsBundle:
|
||||
when EPH is deneb_mev.BlindedExecutionPayloadAndBlobsBundle:
|
||||
type PayloadType = deneb.ExecutionPayloadForSigning
|
||||
template actualEPH: untyped =
|
||||
executionPayloadHeader.get.blindedBlckPart.execution_payload_header
|
||||
@ -780,6 +811,20 @@ proc getBlindedBlockParts[
|
||||
deneb_mev.BlindedExecutionPayloadAndBlobsBundle.execution_payload_header
|
||||
copyFields(
|
||||
shimExecutionPayload.executionPayload, actualEPH, getFieldNames(DenebEPH))
|
||||
elif EPH is electra_mev.BlindedExecutionPayloadAndBlobsBundle:
|
||||
type PayloadType = electra.ExecutionPayloadForSigning
|
||||
template actualEPH: untyped =
|
||||
executionPayloadHeader.get.blindedBlckPart.execution_payload_header
|
||||
let
|
||||
withdrawals_root = Opt.some actualEPH.withdrawals_root
|
||||
kzg_commitments = Opt.some(
|
||||
executionPayloadHeader.get.blindedBlckPart.blob_kzg_commitments)
|
||||
|
||||
var shimExecutionPayload: PayloadType
|
||||
type ElectraEPH =
|
||||
electra_mev.BlindedExecutionPayloadAndBlobsBundle.execution_payload_header
|
||||
copyFields(
|
||||
shimExecutionPayload.executionPayload, actualEPH, getFieldNames(ElectraEPH))
|
||||
else:
|
||||
static: doAssert false
|
||||
|
||||
@ -803,7 +848,9 @@ proc getBlindedBlockParts[
|
||||
forkedBlck.consensusBlockValue,
|
||||
forkedBlck.blck))
|
||||
|
||||
proc getBuilderBid[SBBB: deneb_mev.SignedBlindedBeaconBlock](
|
||||
proc getBuilderBid[
|
||||
SBBB: deneb_mev.SignedBlindedBeaconBlock |
|
||||
electra_mev.SignedBlindedBeaconBlock](
|
||||
node: BeaconNode, payloadBuilderClient: RestClientRef, head: BlockRef,
|
||||
validator_pubkey: ValidatorPubKey, slot: Slot, randao: ValidatorSig,
|
||||
graffitiBytes: GraffitiBytes, validator_index: ValidatorIndex):
|
||||
@ -812,6 +859,8 @@ proc getBuilderBid[SBBB: deneb_mev.SignedBlindedBeaconBlock](
|
||||
## Used by the BN's own validators, but not the REST server
|
||||
when SBBB is deneb_mev.SignedBlindedBeaconBlock:
|
||||
type EPH = deneb_mev.BlindedExecutionPayloadAndBlobsBundle
|
||||
elif SBBB is electra_mev.SignedBlindedBeaconBlock:
|
||||
type EPH = electra_mev.BlindedExecutionPayloadAndBlobsBundle
|
||||
else:
|
||||
static: doAssert false
|
||||
|
||||
@ -842,7 +891,9 @@ proc getBuilderBid[SBBB: deneb_mev.SignedBlindedBeaconBlock](
|
||||
|
||||
proc proposeBlockMEV(
|
||||
node: BeaconNode, payloadBuilderClient: RestClientRef,
|
||||
blindedBlock: deneb_mev.SignedBlindedBeaconBlock):
|
||||
blindedBlock:
|
||||
deneb_mev.SignedBlindedBeaconBlock |
|
||||
electra_mev.SignedBlindedBeaconBlock):
|
||||
Future[Result[BlockRef, string]] {.async: (raises: [CancelledError]).} =
|
||||
let unblindedBlockRef = await node.unblindAndRouteBlockMEV(
|
||||
payloadBuilderClient, blindedBlock)
|
||||
@ -1198,10 +1249,7 @@ proc proposeBlock(node: BeaconNode,
|
||||
genesis_validators_root, node.config.localBlockValueBoost)
|
||||
|
||||
return withConsensusFork(node.dag.cfg.consensusForkAtEpoch(slot.epoch)):
|
||||
when consensusFork >= ConsensusFork.Electra:
|
||||
debugRaiseAssert "can't propose electra block"
|
||||
return default(BlockRef)
|
||||
elif consensusFork >= ConsensusFork.Deneb:
|
||||
when consensusFork >= ConsensusFork.Deneb:
|
||||
proposeBlockContinuation(
|
||||
consensusFork.SignedBlindedBeaconBlock,
|
||||
consensusFork.ExecutionPayloadForSigning)
|
||||
|
@ -33,11 +33,13 @@ macro copyFields*(
|
||||
dst: untyped, src: untyped, fieldNames: static[seq[string]]): untyped =
|
||||
result = newStmtList()
|
||||
for name in fieldNames:
|
||||
debugRaiseAssert "deposit_receipts_root and exits_root are not currently filled in anywhere properly, so blinded electra proposals will fail"
|
||||
if name notin [
|
||||
# These fields are the ones which vary between the blinded and
|
||||
# unblinded objects, and can't simply be copied.
|
||||
"transactions_root", "execution_payload",
|
||||
"execution_payload_header", "body", "withdrawals_root"]:
|
||||
"execution_payload_header", "body", "withdrawals_root",
|
||||
"deposit_receipts_root", "exits_root"]:
|
||||
# TODO use stew/assign2
|
||||
result.add newAssignment(
|
||||
newDotExpr(dst, ident(name)), newDotExpr(src, ident(name)))
|
||||
|
@ -502,7 +502,8 @@ proc getBlockSignature*(v: AttachedValidator, fork: Fork,
|
||||
block_root: Eth2Digest,
|
||||
blck: ForkedBeaconBlock | ForkedBlindedBeaconBlock |
|
||||
ForkedMaybeBlindedBeaconBlock |
|
||||
deneb_mev.BlindedBeaconBlock
|
||||
deneb_mev.BlindedBeaconBlock |
|
||||
electra_mev.BlindedBeaconBlock
|
||||
): Future[SignatureResult]
|
||||
{.async: (raises: [CancelledError]).} =
|
||||
type SomeBlockBody =
|
||||
@ -578,6 +579,19 @@ proc getBlockSignature*(v: AttachedValidator, fork: Fork,
|
||||
Web3SignerForkedBeaconBlock(kind: ConsensusFork.Deneb,
|
||||
data: blck.toBeaconBlockHeader),
|
||||
proofs)
|
||||
elif blck is electra_mev.BlindedBeaconBlock:
|
||||
case v.data.remoteType
|
||||
of RemoteSignerType.Web3Signer:
|
||||
Web3SignerRequest.init(fork, genesis_validators_root,
|
||||
Web3SignerForkedBeaconBlock(kind: ConsensusFork.Electra,
|
||||
data: blck.toBeaconBlockHeader))
|
||||
of RemoteSignerType.VerifyingWeb3Signer:
|
||||
let proofs = blockPropertiesProofs(
|
||||
blck.body, electraIndex)
|
||||
Web3SignerRequest.init(fork, genesis_validators_root,
|
||||
Web3SignerForkedBeaconBlock(kind: ConsensusFork.Electra,
|
||||
data: blck.toBeaconBlockHeader),
|
||||
proofs)
|
||||
elif blck is ForkedMaybeBlindedBeaconBlock:
|
||||
withForkyMaybeBlindedBlck(blck):
|
||||
# TODO why isn't this a case statement
|
||||
|
Loading…
x
Reference in New Issue
Block a user