capella builder API support (#4643)
* capella builder API support * use capella EPH when appropriate * fill in ExecutionPayload.withdrawals and sanity-check builder API withdrawals root
This commit is contained in:
parent
68cb9fe7b1
commit
79eddcde40
|
@ -1,4 +1,4 @@
|
||||||
# Copyright (c) 2018-2022 Status Research & Development GmbH
|
# Copyright (c) 2018-2023 Status Research & Development GmbH
|
||||||
# Licensed and distributed under either of
|
# Licensed and distributed under either of
|
||||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
@ -470,8 +470,22 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
||||||
else:
|
else:
|
||||||
RestApiResponse.jsonError(Http500, InvalidAcceptError)
|
RestApiResponse.jsonError(Http500, InvalidAcceptError)
|
||||||
|
|
||||||
if node.currentSlot().epoch() >= node.dag.cfg.BELLATRIX_FORK_EPOCH:
|
static: doAssert high(ConsensusFork) == ConsensusFork.EIP4844
|
||||||
let res = await makeBlindedBeaconBlockForHeadAndSlot(
|
let currentEpoch = node.currentSlot().epoch()
|
||||||
|
if currentEpoch >= node.dag.cfg.DENEB_FORK_EPOCH:
|
||||||
|
debugRaiseAssert $eip4844ImplementationMissing & ": GET /eth/v1/validator/blinded_blocks/{slot}"
|
||||||
|
elif currentEpoch >= node.dag.cfg.CAPELLA_FORK_EPOCH:
|
||||||
|
let res = await makeBlindedBeaconBlockForHeadAndSlot[
|
||||||
|
capella_mev.BlindedBeaconBlock](
|
||||||
|
node, qrandao, proposer, qgraffiti, qhead, qslot)
|
||||||
|
if res.isErr():
|
||||||
|
return RestApiResponse.jsonError(Http400, res.error())
|
||||||
|
return responsePlain(ForkedBlindedBeaconBlock(
|
||||||
|
kind: ConsensusFork.Capella,
|
||||||
|
capellaData: res.get()))
|
||||||
|
elif currentEpoch >= node.dag.cfg.BELLATRIX_FORK_EPOCH:
|
||||||
|
let res = await makeBlindedBeaconBlockForHeadAndSlot[
|
||||||
|
bellatrix_mev.BlindedBeaconBlock](
|
||||||
node, qrandao, proposer, qgraffiti, qhead, qslot)
|
node, qrandao, proposer, qgraffiti, qhead, qslot)
|
||||||
if res.isErr():
|
if res.isErr():
|
||||||
return RestApiResponse.jsonError(Http400, res.error())
|
return RestApiResponse.jsonError(Http400, res.error())
|
||||||
|
|
|
@ -1044,7 +1044,7 @@ proc readValue*[BlockType: ForkedBlindedBeaconBlock](
|
||||||
let res =
|
let res =
|
||||||
try:
|
try:
|
||||||
RestJson.decode(string(data.get()),
|
RestJson.decode(string(data.get()),
|
||||||
BlindedBeaconBlock,
|
bellatrix_mev.BlindedBeaconBlock,
|
||||||
requireAllFields = true,
|
requireAllFields = true,
|
||||||
allowUnknownFields = true)
|
allowUnknownFields = true)
|
||||||
except SerializationError as exc:
|
except SerializationError as exc:
|
||||||
|
@ -1056,7 +1056,7 @@ proc readValue*[BlockType: ForkedBlindedBeaconBlock](
|
||||||
let res =
|
let res =
|
||||||
try:
|
try:
|
||||||
RestJson.decode(string(data.get()),
|
RestJson.decode(string(data.get()),
|
||||||
BlindedBeaconBlock,
|
capella_mev.BlindedBeaconBlock,
|
||||||
requireAllFields = true,
|
requireAllFields = true,
|
||||||
allowUnknownFields = true)
|
allowUnknownFields = true)
|
||||||
except SerializationError as exc:
|
except SerializationError as exc:
|
||||||
|
|
|
@ -149,6 +149,12 @@ proc publishBlindedBlock*(body: bellatrix_mev.SignedBlindedBeaconBlock):
|
||||||
meth: MethodPost.}
|
meth: MethodPost.}
|
||||||
## https://ethereum.github.io/beacon-APIs/#/Beacon/publishBlindedBlock
|
## https://ethereum.github.io/beacon-APIs/#/Beacon/publishBlindedBlock
|
||||||
|
|
||||||
|
proc publishBlindedBlock*(body: capella_mev.SignedBlindedBeaconBlock):
|
||||||
|
RestPlainResponse {.
|
||||||
|
rest, endpoint: "/eth/v1/beacon/blinded_blocks",
|
||||||
|
meth: MethodPost.}
|
||||||
|
## https://ethereum.github.io/beacon-APIs/#/Beacon/publishBlindedBlock
|
||||||
|
|
||||||
proc publishSszBlindedBlock*(
|
proc publishSszBlindedBlock*(
|
||||||
client: RestClientRef,
|
client: RestClientRef,
|
||||||
blck: ForkySignedBeaconBlock
|
blck: ForkySignedBeaconBlock
|
||||||
|
|
|
@ -631,7 +631,8 @@ type
|
||||||
GetEpochCommitteesResponse* = DataEnclosedObject[seq[RestBeaconStatesCommittees]]
|
GetEpochCommitteesResponse* = DataEnclosedObject[seq[RestBeaconStatesCommittees]]
|
||||||
GetForkScheduleResponse* = DataEnclosedObject[seq[Fork]]
|
GetForkScheduleResponse* = DataEnclosedObject[seq[Fork]]
|
||||||
GetGenesisResponse* = DataEnclosedObject[RestGenesis]
|
GetGenesisResponse* = DataEnclosedObject[RestGenesis]
|
||||||
GetHeaderResponse* = DataVersionEnclosedObject[bellatrix_mev.SignedBuilderBid]
|
GetHeaderResponseBellatrix* = DataVersionEnclosedObject[bellatrix_mev.SignedBuilderBid]
|
||||||
|
GetHeaderResponseCapella* = DataVersionEnclosedObject[capella_mev.SignedBuilderBid]
|
||||||
GetNetworkIdentityResponse* = DataEnclosedObject[RestNetworkIdentity]
|
GetNetworkIdentityResponse* = DataEnclosedObject[RestNetworkIdentity]
|
||||||
GetPeerCountResponse* = DataMetaEnclosedObject[RestPeerCount]
|
GetPeerCountResponse* = DataMetaEnclosedObject[RestPeerCount]
|
||||||
GetPeerResponse* = DataMetaEnclosedObject[RestNodePeer]
|
GetPeerResponse* = DataMetaEnclosedObject[RestNodePeer]
|
||||||
|
|
|
@ -17,12 +17,12 @@ import
|
||||||
block_id, eth2_merkleization, eth2_ssz_serialization,
|
block_id, eth2_merkleization, eth2_ssz_serialization,
|
||||||
forks_light_client, presets],
|
forks_light_client, presets],
|
||||||
./datatypes/[phase0, altair, bellatrix, capella, deneb],
|
./datatypes/[phase0, altair, bellatrix, capella, deneb],
|
||||||
./mev/bellatrix_mev
|
./mev/bellatrix_mev, ./mev/capella_mev
|
||||||
|
|
||||||
export
|
export
|
||||||
extras, block_id, phase0, altair, bellatrix, capella, deneb,
|
extras, block_id, phase0, altair, bellatrix, capella, deneb,
|
||||||
eth2_merkleization, eth2_ssz_serialization, forks_light_client,
|
eth2_merkleization, eth2_ssz_serialization, forks_light_client,
|
||||||
presets, bellatrix_mev
|
presets, bellatrix_mev, capella_mev
|
||||||
|
|
||||||
# This file contains helpers for dealing with forks - we have two ways we can
|
# This file contains helpers for dealing with forks - we have two ways we can
|
||||||
# deal with forks:
|
# deal with forks:
|
||||||
|
@ -152,9 +152,9 @@ type
|
||||||
case kind*: ConsensusFork
|
case kind*: ConsensusFork
|
||||||
of ConsensusFork.Phase0: phase0Data*: phase0.BeaconBlock
|
of ConsensusFork.Phase0: phase0Data*: phase0.BeaconBlock
|
||||||
of ConsensusFork.Altair: altairData*: altair.BeaconBlock
|
of ConsensusFork.Altair: altairData*: altair.BeaconBlock
|
||||||
of ConsensusFork.Bellatrix: bellatrixData*: BlindedBeaconBlock
|
of ConsensusFork.Bellatrix: bellatrixData*: bellatrix_mev.BlindedBeaconBlock
|
||||||
of ConsensusFork.Capella: capellaData*: BlindedBeaconBlock
|
of ConsensusFork.Capella: capellaData*: capella_mev.BlindedBeaconBlock
|
||||||
of ConsensusFork.EIP4844: eip4844Data*: BlindedBeaconBlock
|
of ConsensusFork.EIP4844: eip4844Data*: capella_mev.BlindedBeaconBlock
|
||||||
|
|
||||||
ForkedTrustedBeaconBlock* = object
|
ForkedTrustedBeaconBlock* = object
|
||||||
case kind*: ConsensusFork
|
case kind*: ConsensusFork
|
||||||
|
@ -182,15 +182,16 @@ type
|
||||||
ForkySignedBlindedBeaconBlock* =
|
ForkySignedBlindedBeaconBlock* =
|
||||||
phase0.SignedBeaconBlock |
|
phase0.SignedBeaconBlock |
|
||||||
altair.SignedBeaconBlock |
|
altair.SignedBeaconBlock |
|
||||||
SignedBlindedBeaconBlock
|
bellatrix_mev.SignedBlindedBeaconBlock |
|
||||||
|
capella_mev.SignedBlindedBeaconBlock
|
||||||
|
|
||||||
ForkedSignedBlindedBeaconBlock* = object
|
ForkedSignedBlindedBeaconBlock* = object
|
||||||
case kind*: ConsensusFork
|
case kind*: ConsensusFork
|
||||||
of ConsensusFork.Phase0: phase0Data*: phase0.SignedBeaconBlock
|
of ConsensusFork.Phase0: phase0Data*: phase0.SignedBeaconBlock
|
||||||
of ConsensusFork.Altair: altairData*: altair.SignedBeaconBlock
|
of ConsensusFork.Altair: altairData*: altair.SignedBeaconBlock
|
||||||
of ConsensusFork.Bellatrix: bellatrixData*: SignedBlindedBeaconBlock
|
of ConsensusFork.Bellatrix: bellatrixData*: bellatrix_mev.SignedBlindedBeaconBlock
|
||||||
of ConsensusFork.Capella: capellaData*: SignedBlindedBeaconBlock
|
of ConsensusFork.Capella: capellaData*: capella_mev.SignedBlindedBeaconBlock
|
||||||
of ConsensusFork.EIP4844: eip4844Data*: SignedBlindedBeaconBlock
|
of ConsensusFork.EIP4844: eip4844Data*: capella_mev.SignedBlindedBeaconBlock
|
||||||
|
|
||||||
ForkySigVerifiedSignedBeaconBlock* =
|
ForkySigVerifiedSignedBeaconBlock* =
|
||||||
phase0.SigVerifiedSignedBeaconBlock |
|
phase0.SigVerifiedSignedBeaconBlock |
|
||||||
|
@ -417,16 +418,17 @@ func init*(T: type ForkedSignedBlindedBeaconBlock,
|
||||||
signature: signature))
|
signature: signature))
|
||||||
of ConsensusFork.Bellatrix:
|
of ConsensusFork.Bellatrix:
|
||||||
T(kind: ConsensusFork.Bellatrix,
|
T(kind: ConsensusFork.Bellatrix,
|
||||||
bellatrixData: SignedBlindedBeaconBlock(message: forked.bellatrixData,
|
bellatrixData: bellatrix_mev.SignedBlindedBeaconBlock(message: forked.bellatrixData,
|
||||||
signature: signature))
|
signature: signature))
|
||||||
of ConsensusFork.Capella:
|
of ConsensusFork.Capella:
|
||||||
T(kind: ConsensusFork.Capella,
|
T(kind: ConsensusFork.Capella,
|
||||||
capellaData: SignedBlindedBeaconBlock(message: forked.capellaData,
|
capellaData: capella_mev.SignedBlindedBeaconBlock(message: forked.capellaData,
|
||||||
signature: signature))
|
signature: signature))
|
||||||
of ConsensusFork.EIP4844:
|
of ConsensusFork.EIP4844:
|
||||||
|
discard $eip4844ImplementationMissing & "forks.nim:init(T: type ForkedSignedBlindedBeaconBlock)"
|
||||||
T(kind: ConsensusFork.EIP4844,
|
T(kind: ConsensusFork.EIP4844,
|
||||||
eip4844Data: SignedBlindedBeaconBlock(message: forked.eip4844Data,
|
eip4844Data: capella_mev.SignedBlindedBeaconBlock(message: forked.eip4844Data,
|
||||||
signature: signature))
|
signature: signature))
|
||||||
|
|
||||||
template init*(T: type ForkedMsgTrustedSignedBeaconBlock, blck: phase0.MsgTrustedSignedBeaconBlock): T =
|
template init*(T: type ForkedMsgTrustedSignedBeaconBlock, blck: phase0.MsgTrustedSignedBeaconBlock): T =
|
||||||
T(kind: ConsensusFork.Phase0, phase0Data: blck)
|
T(kind: ConsensusFork.Phase0, phase0Data: blck)
|
||||||
|
@ -838,7 +840,8 @@ template withStateAndBlck*(
|
||||||
body
|
body
|
||||||
|
|
||||||
func toBeaconBlockHeader*(
|
func toBeaconBlockHeader*(
|
||||||
blck: SomeForkyBeaconBlock | BlindedBeaconBlock): BeaconBlockHeader =
|
blck: SomeForkyBeaconBlock | bellatrix_mev.BlindedBeaconBlock |
|
||||||
|
capella_mev.BlindedBeaconBlock): BeaconBlockHeader =
|
||||||
## Reduce a given `BeaconBlock` to its `BeaconBlockHeader`.
|
## Reduce a given `BeaconBlock` to its `BeaconBlockHeader`.
|
||||||
BeaconBlockHeader(
|
BeaconBlockHeader(
|
||||||
slot: blck.slot,
|
slot: blck.slot,
|
||||||
|
|
|
@ -73,7 +73,7 @@ func shortLog*(v: BlindedBeaconBlock): auto =
|
||||||
block_number: v.body.execution_payload_header.block_number,
|
block_number: v.body.execution_payload_header.block_number,
|
||||||
# TODO checksum hex? shortlog?
|
# TODO checksum hex? shortlog?
|
||||||
fee_recipient: to0xHex(v.body.execution_payload_header.fee_recipient.data),
|
fee_recipient: to0xHex(v.body.execution_payload_header.fee_recipient.data),
|
||||||
bls_to_execution_changes_len: v.body.bls_to_execution_changes.len()
|
#bls_to_execution_changes_len: v.body.bls_to_execution_changes.len(), # TODO validator_client/block_service.nim seems to want same shape of shortLogs across all block types
|
||||||
)
|
)
|
||||||
|
|
||||||
func shortLog*(v: SignedBlindedBeaconBlock): auto =
|
func shortLog*(v: SignedBlindedBeaconBlock): auto =
|
||||||
|
|
|
@ -19,10 +19,10 @@ proc registerValidator*(body: seq[SignedValidatorRegistrationV1]
|
||||||
## https://github.com/ethereum/builder-specs/blob/v0.3.0/apis/builder/validators.yaml
|
## https://github.com/ethereum/builder-specs/blob/v0.3.0/apis/builder/validators.yaml
|
||||||
## https://github.com/ethereum/beacon-APIs/blob/v2.3.0/apis/validator/register_validator.yaml
|
## https://github.com/ethereum/beacon-APIs/blob/v2.3.0/apis/validator/register_validator.yaml
|
||||||
|
|
||||||
proc getHeader*(slot: Slot,
|
proc getHeaderBellatrix*(slot: Slot,
|
||||||
parent_hash: Eth2Digest,
|
parent_hash: Eth2Digest,
|
||||||
pubkey: ValidatorPubKey
|
pubkey: ValidatorPubKey
|
||||||
): RestResponse[GetHeaderResponse] {.
|
): RestResponse[GetHeaderResponseBellatrix] {.
|
||||||
rest, endpoint: "/eth/v1/builder/header/{slot}/{parent_hash}/{pubkey}",
|
rest, endpoint: "/eth/v1/builder/header/{slot}/{parent_hash}/{pubkey}",
|
||||||
meth: MethodGet, connection: {Dedicated, Close}.}
|
meth: MethodGet, connection: {Dedicated, Close}.}
|
||||||
## https://github.com/ethereum/builder-specs/blob/v0.3.0/apis/builder/header.yaml
|
## https://github.com/ethereum/builder-specs/blob/v0.3.0/apis/builder/header.yaml
|
||||||
|
|
|
@ -12,17 +12,16 @@ import
|
||||||
|
|
||||||
export chronos, client, rest_types, eth2_rest_serialization
|
export chronos, client, rest_types, eth2_rest_serialization
|
||||||
|
|
||||||
# TODO
|
proc getHeaderCapella*(slot: Slot,
|
||||||
#proc getHeader*(slot: Slot,
|
parent_hash: Eth2Digest,
|
||||||
# parent_hash: Eth2Digest,
|
pubkey: ValidatorPubKey
|
||||||
# pubkey: ValidatorPubKey
|
): RestResponse[GetHeaderResponseCapella] {.
|
||||||
# ): RestResponse[GetHeaderResponse] {.
|
rest, endpoint: "/eth/v1/builder/header/{slot}/{parent_hash}/{pubkey}",
|
||||||
# rest, endpoint: "/eth/v1/builder/header/{slot}/{parent_hash}/{pubkey}",
|
meth: MethodGet, connection: {Dedicated, Close}.}
|
||||||
# meth: MethodGet, connection: {Dedicated, Close}.}
|
## https://github.com/ethereum/builder-specs/blob/v0.3.0/apis/builder/header.yaml
|
||||||
# ## https://github.com/jimmygchen/builder-specs/blob/0e15394bc239d3fee1ba9e42f4ce67ff6565537b/apis/builder/header.yaml
|
|
||||||
|
|
||||||
proc submitBlindedBlock*(body: capella_mev.SignedBlindedBeaconBlock
|
proc submitBlindedBlock*(body: capella_mev.SignedBlindedBeaconBlock
|
||||||
): RestResponse[SubmitBlindedBlockResponseCapella] {.
|
): RestResponse[SubmitBlindedBlockResponseCapella] {.
|
||||||
rest, endpoint: "/eth/v1/builder/blinded_blocks",
|
rest, endpoint: "/eth/v1/builder/blinded_blocks",
|
||||||
meth: MethodPost, connection: {Dedicated, Close}.}
|
meth: MethodPost, connection: {Dedicated, Close}.}
|
||||||
## https://github.com/jimmygchen/builder-specs/blob/0e15394bc239d3fee1ba9e42f4ce67ff6565537b/apis/builder/blinded_blocks.yaml
|
## https://github.com/ethereum/builder-specs/blob/v0.3.0/apis/builder/blinded_blocks.yaml
|
||||||
|
|
|
@ -17,8 +17,7 @@
|
||||||
## functions.
|
## functions.
|
||||||
|
|
||||||
import
|
import
|
||||||
./datatypes/[phase0, altair, bellatrix], ./mev/bellatrix_mev, ./helpers,
|
./datatypes/[phase0, altair, bellatrix], ./helpers, ./eth2_merkleization
|
||||||
./eth2_merkleization
|
|
||||||
|
|
||||||
from ./datatypes/capella import BLSToExecutionChange, SignedBLSToExecutionChange
|
from ./datatypes/capella import BLSToExecutionChange, SignedBLSToExecutionChange
|
||||||
|
|
||||||
|
@ -91,7 +90,8 @@ func compute_block_signing_root*(
|
||||||
fork: Fork, genesis_validators_root: Eth2Digest, slot: Slot,
|
fork: Fork, genesis_validators_root: Eth2Digest, slot: Slot,
|
||||||
blck: Eth2Digest | SomeForkyBeaconBlock | BeaconBlockHeader |
|
blck: Eth2Digest | SomeForkyBeaconBlock | BeaconBlockHeader |
|
||||||
# https://github.com/ethereum/builder-specs/blob/v0.3.0/specs/bellatrix/builder.md#signing
|
# https://github.com/ethereum/builder-specs/blob/v0.3.0/specs/bellatrix/builder.md#signing
|
||||||
BlindedBeaconBlock): Eth2Digest =
|
bellatrix_mev.BlindedBeaconBlock | capella_mev.BlindedBeaconBlock):
|
||||||
|
Eth2Digest =
|
||||||
let
|
let
|
||||||
epoch = epoch(slot)
|
epoch = epoch(slot)
|
||||||
domain = get_domain(
|
domain = get_domain(
|
||||||
|
@ -347,7 +347,9 @@ proc verify_contribution_and_proof_signature*(
|
||||||
|
|
||||||
# https://github.com/ethereum/builder-specs/blob/v0.3.0/specs/bellatrix/builder.md#signing
|
# https://github.com/ethereum/builder-specs/blob/v0.3.0/specs/bellatrix/builder.md#signing
|
||||||
func compute_builder_signing_root*(
|
func compute_builder_signing_root*(
|
||||||
fork: Fork, msg: BuilderBid | ValidatorRegistrationV1): Eth2Digest =
|
fork: Fork,
|
||||||
|
msg: bellatrix_mev.BuilderBid | capella_mev.BuilderBid |
|
||||||
|
ValidatorRegistrationV1): Eth2Digest =
|
||||||
# Uses genesis fork version regardless
|
# Uses genesis fork version regardless
|
||||||
doAssert fork.current_version == fork.previous_version
|
doAssert fork.current_version == fork.previous_version
|
||||||
|
|
||||||
|
@ -362,7 +364,7 @@ proc get_builder_signature*(
|
||||||
blsSign(privkey, signing_root.data)
|
blsSign(privkey, signing_root.data)
|
||||||
|
|
||||||
proc verify_builder_signature*(
|
proc verify_builder_signature*(
|
||||||
fork: Fork, msg: BuilderBid,
|
fork: Fork, msg: bellatrix_mev.BuilderBid | capella_mev.BuilderBid,
|
||||||
pubkey: ValidatorPubKey | CookedPubKey, signature: SomeSig): bool =
|
pubkey: ValidatorPubKey | CookedPubKey, signature: SomeSig): bool =
|
||||||
let signing_root = compute_builder_signing_root(fork, msg)
|
let signing_root = compute_builder_signing_root(fork, msg)
|
||||||
blsVerify(pubkey, signing_root.data, signature)
|
blsVerify(pubkey, signing_root.data, signature)
|
||||||
|
|
|
@ -36,7 +36,7 @@ macro copyFields*(
|
||||||
# These fields are the ones which vary between the blinded and
|
# These fields are the ones which vary between the blinded and
|
||||||
# unblinded objects, and can't simply be copied.
|
# unblinded objects, and can't simply be copied.
|
||||||
"transactions_root", "execution_payload",
|
"transactions_root", "execution_payload",
|
||||||
"execution_payload_header", "body"]:
|
"execution_payload_header", "body", "withdrawals_root"]:
|
||||||
# TODO use stew/assign2
|
# TODO use stew/assign2
|
||||||
result.add newAssignment(
|
result.add newAssignment(
|
||||||
newDotExpr(dst, ident(name)), newDotExpr(src, ident(name)))
|
newDotExpr(dst, ident(name)), newDotExpr(src, ident(name)))
|
||||||
|
|
|
@ -16,7 +16,7 @@ import
|
||||||
std/[os, tables, sequtils],
|
std/[os, tables, sequtils],
|
||||||
|
|
||||||
# Nimble packages
|
# Nimble packages
|
||||||
stew/byteutils,
|
stew/[assign2, byteutils],
|
||||||
chronos, metrics,
|
chronos, metrics,
|
||||||
chronicles, chronicles/timings,
|
chronicles, chronicles/timings,
|
||||||
json_serialization/std/[options, sets, net],
|
json_serialization/std/[options, sets, net],
|
||||||
|
@ -86,7 +86,6 @@ logScope: topics = "beacval"
|
||||||
|
|
||||||
type
|
type
|
||||||
ForkedBlockResult* = Result[ForkedBeaconBlock, string]
|
ForkedBlockResult* = Result[ForkedBeaconBlock, string]
|
||||||
BlindedBlockResult* = Result[bellatrix_mev.BlindedBeaconBlock, string]
|
|
||||||
|
|
||||||
SyncStatus* {.pure.} = enum
|
SyncStatus* {.pure.} = enum
|
||||||
synced
|
synced
|
||||||
|
@ -337,7 +336,8 @@ proc getGasLimit(node: BeaconNode,
|
||||||
|
|
||||||
from web3/engine_api_types import PayloadExecutionStatus
|
from web3/engine_api_types import PayloadExecutionStatus
|
||||||
from ../spec/datatypes/capella import BeaconBlock, ExecutionPayload
|
from ../spec/datatypes/capella import BeaconBlock, ExecutionPayload
|
||||||
from ../spec/datatypes/eip4844 import BeaconBlock, ExecutionPayload
|
from ../spec/datatypes/eip4844 import
|
||||||
|
BeaconBlock, ExecutionPayload, shortLog
|
||||||
|
|
||||||
proc getExecutionPayload[T](
|
proc getExecutionPayload[T](
|
||||||
node: BeaconNode, proposalState: ref ForkedHashedBeaconState,
|
node: BeaconNode, proposalState: ref ForkedHashedBeaconState,
|
||||||
|
@ -487,9 +487,12 @@ proc makeBeaconBlockForHeadAndSlot*[EP](
|
||||||
node: BeaconNode, randao_reveal: ValidatorSig,
|
node: BeaconNode, randao_reveal: ValidatorSig,
|
||||||
validator_index: ValidatorIndex, graffiti: GraffitiBytes, head: BlockRef,
|
validator_index: ValidatorIndex, graffiti: GraffitiBytes, head: BlockRef,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
|
|
||||||
|
# Thse parameters are for the builder API
|
||||||
execution_payload: Opt[EP],
|
execution_payload: Opt[EP],
|
||||||
transactions_root: Opt[Eth2Digest],
|
transactions_root: Opt[Eth2Digest],
|
||||||
execution_payload_root: Opt[Eth2Digest]):
|
execution_payload_root: Opt[Eth2Digest],
|
||||||
|
withdrawals_root: Opt[Eth2Digest]):
|
||||||
Future[ForkedBlockResult] {.async.} =
|
Future[ForkedBlockResult] {.async.} =
|
||||||
# Advance state to the slot that we're proposing for
|
# Advance state to the slot that we're proposing for
|
||||||
var cache = StateCache()
|
var cache = StateCache()
|
||||||
|
@ -510,14 +513,31 @@ proc makeBeaconBlockForHeadAndSlot*[EP](
|
||||||
state = maybeState.get
|
state = maybeState.get
|
||||||
payloadFut =
|
payloadFut =
|
||||||
if execution_payload.isSome:
|
if execution_payload.isSome:
|
||||||
|
# Builder API
|
||||||
|
|
||||||
|
# In Capella, only get withdrawals root from relay.
|
||||||
|
# The execution payload will be small enough to be safe to copy because
|
||||||
|
# it won't have transactions (it's blinded)
|
||||||
|
var modified_execution_payload = execution_payload
|
||||||
|
withState(state[]):
|
||||||
|
when stateFork >= ConsensusFork.Capella and
|
||||||
|
EP isnot bellatrix.ExecutionPayload:
|
||||||
|
let withdrawals = List[Withdrawal, MAX_WITHDRAWALS_PER_PAYLOAD](
|
||||||
|
get_expected_withdrawals(forkyState.data))
|
||||||
|
if withdrawals_root.isNone or
|
||||||
|
hash_tree_root(withdrawals) != withdrawals_root.get:
|
||||||
|
return err("Builder relay provided incorrect withdrawals root")
|
||||||
|
# Otherwise, the state transition function notices that there are
|
||||||
|
# too few withdrawals.
|
||||||
|
assign(modified_execution_payload.get.withdrawals, withdrawals)
|
||||||
|
|
||||||
let fut = newFuture[Opt[EP]]("given-payload")
|
let fut = newFuture[Opt[EP]]("given-payload")
|
||||||
fut.complete(execution_payload)
|
fut.complete(modified_execution_payload)
|
||||||
fut
|
fut
|
||||||
elif slot.epoch < node.dag.cfg.BELLATRIX_FORK_EPOCH or not (
|
elif slot.epoch < node.dag.cfg.BELLATRIX_FORK_EPOCH or not (
|
||||||
state[].is_merge_transition_complete or
|
state[].is_merge_transition_complete or
|
||||||
slot.epoch >= node.mergeAtEpoch):
|
slot.epoch >= node.mergeAtEpoch):
|
||||||
let fut = newFuture[Opt[EP]]("empty-payload")
|
let fut = newFuture[Opt[EP]]("empty-payload")
|
||||||
# https://github.com/nim-lang/Nim/issues/19802
|
|
||||||
fut.complete(Opt.some(default(EP)))
|
fut.complete(Opt.some(default(EP)))
|
||||||
fut
|
fut
|
||||||
else:
|
else:
|
||||||
|
@ -586,19 +606,30 @@ proc makeBeaconBlockForHeadAndSlot*[EP](
|
||||||
node, randao_reveal, validator_index, graffiti, head, slot,
|
node, randao_reveal, validator_index, graffiti, head, slot,
|
||||||
execution_payload = Opt.none(EP),
|
execution_payload = Opt.none(EP),
|
||||||
transactions_root = Opt.none(Eth2Digest),
|
transactions_root = Opt.none(Eth2Digest),
|
||||||
execution_payload_root = Opt.none(Eth2Digest))
|
execution_payload_root = Opt.none(Eth2Digest),
|
||||||
|
withdrawals_root = Opt.none(Eth2Digest))
|
||||||
|
|
||||||
proc getBlindedExecutionPayload(
|
proc getBlindedExecutionPayload[
|
||||||
|
EPH: bellatrix.ExecutionPayloadHeader | capella.ExecutionPayloadHeader](
|
||||||
node: BeaconNode, slot: Slot, executionBlockRoot: Eth2Digest,
|
node: BeaconNode, slot: Slot, executionBlockRoot: Eth2Digest,
|
||||||
pubkey: ValidatorPubKey):
|
pubkey: ValidatorPubKey): Future[Result[EPH, string]] {.async.} =
|
||||||
Future[Result[bellatrix.ExecutionPayloadHeader, string]] {.async.} =
|
|
||||||
if node.payloadBuilderRestClient.isNil:
|
if node.payloadBuilderRestClient.isNil:
|
||||||
return err "getBlindedExecutionPayload: nil REST client"
|
return err "getBlindedExecutionPayload: nil REST client"
|
||||||
|
|
||||||
let blindedHeader = awaitWithTimeout(
|
when EPH is capella.ExecutionPayloadHeader:
|
||||||
node.payloadBuilderRestClient.getHeader(slot, executionBlockRoot, pubkey),
|
let blindedHeader = awaitWithTimeout(
|
||||||
BUILDER_PROPOSAL_DELAY_TOLERANCE):
|
node.payloadBuilderRestClient.getHeaderCapella(
|
||||||
return err "Timeout when obtaining blinded header from builder"
|
slot, executionBlockRoot, pubkey),
|
||||||
|
BUILDER_PROPOSAL_DELAY_TOLERANCE):
|
||||||
|
return err "Timeout when obtaining Capella blinded header from builder"
|
||||||
|
elif EPH is bellatrix.ExecutionPayloadHeader:
|
||||||
|
let blindedHeader = awaitWithTimeout(
|
||||||
|
node.payloadBuilderRestClient.getHeaderBellatrix(
|
||||||
|
slot, executionBlockRoot, pubkey),
|
||||||
|
BUILDER_PROPOSAL_DELAY_TOLERANCE):
|
||||||
|
return err "Timeout when obtaining Bellatrix blinded header from builder"
|
||||||
|
else:
|
||||||
|
static: doAssert false
|
||||||
|
|
||||||
const httpOk = 200
|
const httpOk = 200
|
||||||
if blindedHeader.status != httpOk:
|
if blindedHeader.status != httpOk:
|
||||||
|
@ -616,35 +647,37 @@ from ./message_router_mev import
|
||||||
copyFields, getFieldNames, unblindAndRouteBlockMEV
|
copyFields, getFieldNames, unblindAndRouteBlockMEV
|
||||||
|
|
||||||
func constructSignableBlindedBlock[T](
|
func constructSignableBlindedBlock[T](
|
||||||
forkedBlock: ForkedBeaconBlock,
|
blck: bellatrix.BeaconBlock | capella.BeaconBlock,
|
||||||
executionPayloadHeader: bellatrix.ExecutionPayloadHeader): T =
|
executionPayloadHeader: bellatrix.ExecutionPayloadHeader |
|
||||||
|
capella.ExecutionPayloadHeader): T =
|
||||||
const
|
const
|
||||||
blckFields = getFieldNames(typeof(forkedBlock.bellatrixData))
|
blckFields = getFieldNames(typeof(blck))
|
||||||
blckBodyFields = getFieldNames(typeof(forkedBlock.bellatrixData.body))
|
blckBodyFields = getFieldNames(typeof(blck.body))
|
||||||
|
|
||||||
var blindedBlock: T
|
var blindedBlock: T
|
||||||
|
|
||||||
# https://github.com/ethereum/builder-specs/blob/v0.3.0/specs/bellatrix/validator.md#block-proposal
|
# https://github.com/ethereum/builder-specs/blob/v0.3.0/specs/bellatrix/validator.md#block-proposal
|
||||||
copyFields(blindedBlock.message, forkedBlock.bellatrixData, blckFields)
|
copyFields(blindedBlock.message, blck, blckFields)
|
||||||
copyFields(
|
copyFields(blindedBlock.message.body, blck.body, blckBodyFields)
|
||||||
blindedBlock.message.body, forkedBlock.bellatrixData.body, blckBodyFields)
|
assign(
|
||||||
blindedBlock.message.body.execution_payload_header = executionPayloadHeader
|
blindedBlock.message.body.execution_payload_header, executionPayloadHeader)
|
||||||
|
|
||||||
blindedBlock
|
blindedBlock
|
||||||
|
|
||||||
func constructPlainBlindedBlock[T](
|
func constructPlainBlindedBlock[
|
||||||
forkedBlock: ForkedBeaconBlock,
|
T: bellatrix_mev.BlindedBeaconBlock | capella_mev.BlindedBeaconBlock,
|
||||||
executionPayloadHeader: bellatrix.ExecutionPayloadHeader): T =
|
EPH: bellatrix.ExecutionPayloadHeader | capella.ExecutionPayloadHeader](
|
||||||
|
blck: ForkyBeaconBlock, executionPayloadHeader: EPH): T =
|
||||||
const
|
const
|
||||||
blckFields = getFieldNames(typeof(forkedBlock.bellatrixData))
|
blckFields = getFieldNames(typeof(blck))
|
||||||
blckBodyFields = getFieldNames(typeof(forkedBlock.bellatrixData.body))
|
blckBodyFields = getFieldNames(typeof(blck.body))
|
||||||
|
|
||||||
var blindedBlock: T
|
var blindedBlock: T
|
||||||
|
|
||||||
# https://github.com/ethereum/builder-specs/blob/v0.3.0/specs/bellatrix/validator.md#block-proposal
|
# https://github.com/ethereum/builder-specs/blob/v0.3.0/specs/bellatrix/validator.md#block-proposal
|
||||||
copyFields(blindedBlock, forkedBlock.bellatrixData, blckFields)
|
copyFields(blindedBlock, blck, blckFields)
|
||||||
copyFields(blindedBlock.body, forkedBlock.bellatrixData.body, blckBodyFields)
|
copyFields(blindedBlock.body, blck.body, blckBodyFields)
|
||||||
blindedBlock.body.execution_payload_header = executionPayloadHeader
|
assign(blindedBlock.body.execution_payload_header, executionPayloadHeader)
|
||||||
|
|
||||||
blindedBlock
|
blindedBlock
|
||||||
|
|
||||||
|
@ -683,40 +716,55 @@ proc blindedBlockCheckSlashingAndSign[T](
|
||||||
|
|
||||||
return ok blindedBlock
|
return ok blindedBlock
|
||||||
|
|
||||||
proc getBlindedBeaconBlock[T](
|
proc getBlindedBeaconBlock[
|
||||||
|
T: bellatrix_mev.SignedBlindedBeaconBlock |
|
||||||
|
capella_mev.SignedBlindedBeaconBlock](
|
||||||
node: BeaconNode, slot: Slot, validator: AttachedValidator,
|
node: BeaconNode, slot: Slot, validator: AttachedValidator,
|
||||||
validator_index: ValidatorIndex, forkedBlock: ForkedBeaconBlock,
|
validator_index: ValidatorIndex, forkedBlock: ForkedBeaconBlock,
|
||||||
executionPayloadHeader: bellatrix.ExecutionPayloadHeader):
|
executionPayloadHeader: bellatrix.ExecutionPayloadHeader |
|
||||||
|
capella.ExecutionPayloadHeader):
|
||||||
Future[Result[T, string]] {.async.} =
|
Future[Result[T, string]] {.async.} =
|
||||||
return await blindedBlockCheckSlashingAndSign(
|
withBlck(forkedBlock):
|
||||||
node, slot, validator, validator_index, constructSignableBlindedBlock[T](
|
when stateFork >= ConsensusFork.EIP4844:
|
||||||
forkedBlock, executionPayloadHeader))
|
debugRaiseAssert $eip4844ImplementationMissing & ": getBlindedBeaconBlock"
|
||||||
|
return err("getBlindedBeaconBlock: Deneb blinded block creation not implemented")
|
||||||
|
elif stateFork >= ConsensusFork.Bellatrix:
|
||||||
|
when not (
|
||||||
|
(T is bellatrix_mev.SignedBlindedBeaconBlock and
|
||||||
|
stateFork == ConsensusFork.Bellatrix) or
|
||||||
|
(T is capella_mev.SignedBlindedBeaconBlock and
|
||||||
|
stateFork == ConsensusFork.Capella)):
|
||||||
|
return err("getBlindedBeaconBlock: mismatched block/payload types")
|
||||||
|
else:
|
||||||
|
return await blindedBlockCheckSlashingAndSign(
|
||||||
|
node, slot, validator, validator_index,
|
||||||
|
constructSignableBlindedBlock[T](blck, executionPayloadHeader))
|
||||||
|
else:
|
||||||
|
return err("getBlindedBeaconBlock: attempt to construct pre-Bellatrix blinded block")
|
||||||
|
|
||||||
proc getBlindedBlockParts(
|
proc getBlindedBlockParts[
|
||||||
|
EPH: bellatrix.ExecutionPayloadHeader | capella.ExecutionPayloadHeader](
|
||||||
node: BeaconNode, head: BlockRef, pubkey: ValidatorPubKey,
|
node: BeaconNode, head: BlockRef, pubkey: ValidatorPubKey,
|
||||||
slot: Slot, randao: ValidatorSig, validator_index: ValidatorIndex,
|
slot: Slot, randao: ValidatorSig, validator_index: ValidatorIndex,
|
||||||
graffiti: GraffitiBytes):
|
graffiti: GraffitiBytes): Future[Result[(EPH, ForkedBeaconBlock), string]]
|
||||||
Future[Result[(bellatrix.ExecutionPayloadHeader, ForkedBeaconBlock), string]]
|
|
||||||
{.async.} =
|
{.async.} =
|
||||||
let
|
let
|
||||||
executionBlockRoot = node.dag.loadExecutionBlockRoot(head)
|
executionBlockRoot = node.dag.loadExecutionBlockRoot(head)
|
||||||
executionPayloadHeader =
|
executionPayloadHeader =
|
||||||
try:
|
try:
|
||||||
awaitWithTimeout(
|
awaitWithTimeout(
|
||||||
node.getBlindedExecutionPayload(
|
getBlindedExecutionPayload[EPH](
|
||||||
slot, executionBlockRoot, pubkey),
|
node, slot, executionBlockRoot, pubkey),
|
||||||
BUILDER_PROPOSAL_DELAY_TOLERANCE):
|
BUILDER_PROPOSAL_DELAY_TOLERANCE):
|
||||||
Result[bellatrix.ExecutionPayloadHeader, string].err(
|
Result[EPH, string].err("getBlindedExecutionPayload timed out")
|
||||||
"getBlindedExecutionPayload timed out")
|
|
||||||
except RestDecodingError as exc:
|
except RestDecodingError as exc:
|
||||||
Result[bellatrix.ExecutionPayloadHeader, string].err(
|
Result[EPH, string].err(
|
||||||
"getBlindedExecutionPayload REST decoding error")
|
"getBlindedExecutionPayload REST decoding error")
|
||||||
except CatchableError as exc:
|
except CatchableError as exc:
|
||||||
Result[bellatrix.ExecutionPayloadHeader, string].err(
|
Result[EPH, string].err("getBlindedExecutionPayload error")
|
||||||
"getBlindedExecutionPayload error")
|
|
||||||
|
|
||||||
if executionPayloadHeader.isErr:
|
if executionPayloadHeader.isErr:
|
||||||
debug "proposeBlockMEV: getBlindedExecutionPayload failed",
|
debug "getBlindedBlockParts: getBlindedExecutionPayload failed",
|
||||||
error = executionPayloadHeader.error, slot, validator_index,
|
error = executionPayloadHeader.error, slot, validator_index,
|
||||||
head = shortLog(head)
|
head = shortLog(head)
|
||||||
# Haven't committed to the MEV block, so allow EL fallback.
|
# Haven't committed to the MEV block, so allow EL fallback.
|
||||||
|
@ -728,17 +776,29 @@ proc getBlindedBlockParts(
|
||||||
# processing does not work directly using blinded blocks, fix up transactions
|
# processing does not work directly using blinded blocks, fix up transactions
|
||||||
# root after running the state transition function on an otherwise equivalent
|
# root after running the state transition function on an otherwise equivalent
|
||||||
# non-blinded block without transactions.
|
# non-blinded block without transactions.
|
||||||
var shimExecutionPayload: bellatrix.ExecutionPayload
|
when EPH is bellatrix.ExecutionPayloadHeader:
|
||||||
copyFields(
|
type EP = bellatrix.ExecutionPayload
|
||||||
shimExecutionPayload, executionPayloadHeader.get,
|
let withdrawals_root = Opt.none Eth2Digest
|
||||||
getFieldNames(bellatrix.ExecutionPayloadHeader))
|
elif EPH is capella.ExecutionPayloadHeader:
|
||||||
|
type EP = capella.ExecutionPayload
|
||||||
|
let withdrawals_root = Opt.some executionPayloadHeader.get.withdrawals_root
|
||||||
|
else:
|
||||||
|
static: doAssert false
|
||||||
|
|
||||||
let newBlock = await makeBeaconBlockForHeadAndSlot[bellatrix.ExecutionPayload](
|
var shimExecutionPayload: EP
|
||||||
|
copyFields(
|
||||||
|
shimExecutionPayload, executionPayloadHeader.get, getFieldNames(EPH))
|
||||||
|
# In Capella and later, this doesn't have withdrawals, which each node knows
|
||||||
|
# regardless of EL or builder API. makeBeaconBlockForHeadAndSlot fills it in
|
||||||
|
# when it detects builder API usage.
|
||||||
|
|
||||||
|
let newBlock = await makeBeaconBlockForHeadAndSlot[EP](
|
||||||
node, randao, validator_index, graffiti, head, slot,
|
node, randao, validator_index, graffiti, head, slot,
|
||||||
execution_payload = Opt.some shimExecutionPayload,
|
execution_payload = Opt.some shimExecutionPayload,
|
||||||
transactions_root = Opt.some executionPayloadHeader.get.transactions_root,
|
transactions_root = Opt.some executionPayloadHeader.get.transactions_root,
|
||||||
execution_payload_root =
|
execution_payload_root =
|
||||||
Opt.some hash_tree_root(executionPayloadHeader.get))
|
Opt.some hash_tree_root(executionPayloadHeader.get),
|
||||||
|
withdrawals_root = withdrawals_root)
|
||||||
|
|
||||||
if newBlock.isErr():
|
if newBlock.isErr():
|
||||||
# Haven't committed to the MEV block, so allow EL fallback.
|
# Haven't committed to the MEV block, so allow EL fallback.
|
||||||
|
@ -748,11 +808,20 @@ proc getBlindedBlockParts(
|
||||||
|
|
||||||
return ok((executionPayloadHeader.get, forkedBlck))
|
return ok((executionPayloadHeader.get, forkedBlck))
|
||||||
|
|
||||||
proc proposeBlockMEV(
|
proc proposeBlockMEV[
|
||||||
|
SBBB: bellatrix_mev.SignedBlindedBeaconBlock |
|
||||||
|
capella_mev.SignedBlindedBeaconBlock](
|
||||||
node: BeaconNode, head: BlockRef, validator: AttachedValidator, slot: Slot,
|
node: BeaconNode, head: BlockRef, validator: AttachedValidator, slot: Slot,
|
||||||
randao: ValidatorSig, validator_index: ValidatorIndex):
|
randao: ValidatorSig, validator_index: ValidatorIndex):
|
||||||
Future[Opt[BlockRef]] {.async.} =
|
Future[Opt[BlockRef]] {.async.} =
|
||||||
let blindedBlockParts = await getBlindedBlockParts(
|
when SBBB is bellatrix_mev.SignedBlindedBeaconBlock:
|
||||||
|
type EPH = bellatrix.ExecutionPayloadHeader
|
||||||
|
elif SBBB is capella_mev.SignedBlindedBeaconBlock:
|
||||||
|
type EPH = capella.ExecutionPayloadHeader
|
||||||
|
else:
|
||||||
|
static: doAssert false
|
||||||
|
|
||||||
|
let blindedBlockParts = await getBlindedBlockParts[EPH](
|
||||||
node, head, validator.pubkey, slot, randao, validator_index,
|
node, head, validator.pubkey, slot, randao, validator_index,
|
||||||
node.graffitiBytes)
|
node.graffitiBytes)
|
||||||
if blindedBlockParts.isErr:
|
if blindedBlockParts.isErr:
|
||||||
|
@ -766,12 +835,11 @@ proc proposeBlockMEV(
|
||||||
|
|
||||||
# This is only substantively asynchronous with a remote key signer
|
# This is only substantively asynchronous with a remote key signer
|
||||||
let blindedBlock = awaitWithTimeout(
|
let blindedBlock = awaitWithTimeout(
|
||||||
getBlindedBeaconBlock[bellatrix_mev.SignedBlindedBeaconBlock](
|
getBlindedBeaconBlock[SBBB](
|
||||||
node, slot, validator, validator_index, forkedBlck,
|
node, slot, validator, validator_index, forkedBlck,
|
||||||
executionPayloadHeader),
|
executionPayloadHeader),
|
||||||
500.milliseconds):
|
500.milliseconds):
|
||||||
Result[bellatrix_mev.SignedBlindedBeaconBlock, string].err(
|
Result[SBBB, string].err("getBlindedBlock timed out")
|
||||||
"getBlindedBlock timed out")
|
|
||||||
|
|
||||||
if blindedBlock.isErr:
|
if blindedBlock.isErr:
|
||||||
info "proposeBlockMEV: getBlindedBeaconBlock failed",
|
info "proposeBlockMEV: getBlindedBeaconBlock failed",
|
||||||
|
@ -800,19 +868,27 @@ proc proposeBlockMEV(
|
||||||
unblindedBlockRef.error
|
unblindedBlockRef.error
|
||||||
else:
|
else:
|
||||||
"Unblinded block failed either to validate or integrate into validated store"
|
"Unblinded block failed either to validate or integrate into validated store"
|
||||||
warn "proposeBlockMEV: blinded block not successfully unblinded and proposed",
|
warn "proposeBlockMEV: blinded block either not successfully unblinded or not successfully proposed",
|
||||||
head = shortLog(head), slot, validator_index,
|
head = shortLog(head), slot, validator_index,
|
||||||
validator = shortLog(validator),
|
validator = shortLog(validator),
|
||||||
err = errMsg, blindedBlck = shortLog(blindedBlock.get)
|
err = errMsg, blindedBlck = shortLog(blindedBlock.get)
|
||||||
Opt.some head
|
Opt.some head
|
||||||
|
|
||||||
proc makeBlindedBeaconBlockForHeadAndSlot*(
|
proc makeBlindedBeaconBlockForHeadAndSlot*[
|
||||||
|
BBB: bellatrix_mev.BlindedBeaconBlock | capella_mev.BlindedBeaconBlock](
|
||||||
node: BeaconNode, randao_reveal: ValidatorSig,
|
node: BeaconNode, randao_reveal: ValidatorSig,
|
||||||
validator_index: ValidatorIndex, graffiti: GraffitiBytes, head: BlockRef,
|
validator_index: ValidatorIndex, graffiti: GraffitiBytes, head: BlockRef,
|
||||||
slot: Slot): Future[BlindedBlockResult] {.async.} =
|
slot: Slot): Future[Result[BBB, string]] {.async.} =
|
||||||
## Requests a beacon node to produce a valid blinded block, which can then be
|
## Requests a beacon node to produce a valid blinded block, which can then be
|
||||||
## signed by a validator. A blinded block is a block with only a transactions
|
## signed by a validator. A blinded block is a block with only a transactions
|
||||||
## root, rather than a full transactions list.
|
## root, rather than a full transactions list.
|
||||||
|
when BBB is bellatrix_mev.BlindedBeaconBlock:
|
||||||
|
type EPH = bellatrix.ExecutionPayloadHeader
|
||||||
|
elif BBB is capella_mev.BlindedBeaconBlock:
|
||||||
|
type EPH = capella.ExecutionPayloadHeader
|
||||||
|
else:
|
||||||
|
static: doAssert false
|
||||||
|
|
||||||
let
|
let
|
||||||
pubkey =
|
pubkey =
|
||||||
# Relevant state for knowledge of validators
|
# Relevant state for knowledge of validators
|
||||||
|
@ -826,17 +902,27 @@ proc makeBlindedBeaconBlockForHeadAndSlot*(
|
||||||
|
|
||||||
forkyState.data.validators.item(validator_index).pubkey
|
forkyState.data.validators.item(validator_index).pubkey
|
||||||
|
|
||||||
blindedBlockParts = await getBlindedBlockParts(
|
blindedBlockParts = await getBlindedBlockParts[EPH](
|
||||||
node, head, pubkey, slot, randao_reveal, validator_index, graffiti)
|
node, head, pubkey, slot, randao_reveal, validator_index, graffiti)
|
||||||
if blindedBlockParts.isErr:
|
if blindedBlockParts.isErr:
|
||||||
# Don't try EL fallback -- VC specifically requested a blinded block
|
# Don't try EL fallback -- VC specifically requested a blinded block
|
||||||
return err("Unable to create blinded block")
|
return err("Unable to create blinded block")
|
||||||
|
|
||||||
let (executionPayloadHeader, forkedBlck) = blindedBlockParts.get
|
let (executionPayloadHeader, forkedBlck) = blindedBlockParts.get
|
||||||
return ok constructPlainBlindedBlock[bellatrix_mev.BlindedBeaconBlock](
|
withBlck(forkedBlck):
|
||||||
forkedBlck, executionPayloadHeader)
|
when stateFork >= ConsensusFork.EIP4844:
|
||||||
|
debugRaiseAssert $eip4844ImplementationMissing & ": makeBlindedBeaconBlockForHeadAndSlot"
|
||||||
from ../spec/datatypes/eip4844 import shortLog
|
elif stateFork >= ConsensusFork.Bellatrix:
|
||||||
|
when ((stateFork == ConsensusFork.Bellatrix and
|
||||||
|
EPH is bellatrix.ExecutionPayloadHeader) or
|
||||||
|
(stateFork == ConsensusFork.Capella and
|
||||||
|
EPH is capella.ExecutionPayloadHeader)):
|
||||||
|
return ok constructPlainBlindedBlock[BBB, EPH](
|
||||||
|
blck, executionPayloadHeader)
|
||||||
|
else:
|
||||||
|
return err("makeBlindedBeaconBlockForHeadAndSlot: mismatched block/payload types")
|
||||||
|
else:
|
||||||
|
return err("Attempt to create pre-Bellatrix blinded block")
|
||||||
|
|
||||||
proc proposeBlock(node: BeaconNode,
|
proc proposeBlock(node: BeaconNode,
|
||||||
validator: AttachedValidator,
|
validator: AttachedValidator,
|
||||||
|
@ -866,8 +952,20 @@ proc proposeBlock(node: BeaconNode,
|
||||||
res.get()
|
res.get()
|
||||||
|
|
||||||
if node.config.payloadBuilderEnable:
|
if node.config.payloadBuilderEnable:
|
||||||
let newBlockMEV = await node.proposeBlockMEV(
|
let newBlockMEV =
|
||||||
head, validator, slot, randao, validator_index)
|
if slot.epoch >= node.dag.cfg.DENEB_FORK_EPOCH:
|
||||||
|
debugRaiseAssert $eip4844ImplementationMissing & ": proposeBlock"
|
||||||
|
await proposeBlockMEV[
|
||||||
|
capella_mev.SignedBlindedBeaconBlock](
|
||||||
|
node, head, validator, slot, randao, validator_index)
|
||||||
|
elif slot.epoch >= node.dag.cfg.CAPELLA_FORK_EPOCH:
|
||||||
|
await proposeBlockMEV[
|
||||||
|
capella_mev.SignedBlindedBeaconBlock](
|
||||||
|
node, head, validator, slot, randao, validator_index)
|
||||||
|
else:
|
||||||
|
await proposeBlockMEV[
|
||||||
|
bellatrix_mev.SignedBlindedBeaconBlock](
|
||||||
|
node, head, validator, slot, randao, validator_index)
|
||||||
|
|
||||||
if newBlockMEV.isSome:
|
if newBlockMEV.isSome:
|
||||||
# This might be equivalent to the `head` passed in, but it signals that
|
# This might be equivalent to the `head` passed in, but it signals that
|
||||||
|
|
|
@ -418,7 +418,8 @@ proc getBlockSignature*(v: AttachedValidator, fork: Fork,
|
||||||
genesis_validators_root: Eth2Digest, slot: Slot,
|
genesis_validators_root: Eth2Digest, slot: Slot,
|
||||||
block_root: Eth2Digest,
|
block_root: Eth2Digest,
|
||||||
blck: ForkedBeaconBlock | ForkedBlindedBeaconBlock |
|
blck: ForkedBeaconBlock | ForkedBlindedBeaconBlock |
|
||||||
bellatrix_mev.BlindedBeaconBlock
|
bellatrix_mev.BlindedBeaconBlock |
|
||||||
|
capella_mev.BlindedBeaconBlock
|
||||||
): Future[SignatureResult] {.async.} =
|
): Future[SignatureResult] {.async.} =
|
||||||
return
|
return
|
||||||
case v.kind
|
case v.kind
|
||||||
|
@ -456,13 +457,20 @@ proc getBlockSignature*(v: AttachedValidator, fork: Fork,
|
||||||
request = Web3SignerRequest.init(
|
request = Web3SignerRequest.init(
|
||||||
fork, genesis_validators_root, web3SignerBlock)
|
fork, genesis_validators_root, web3SignerBlock)
|
||||||
await v.signData(request)
|
await v.signData(request)
|
||||||
elif blck is BlindedBeaconBlock:
|
elif blck is bellatrix_mev.BlindedBeaconBlock:
|
||||||
let request = Web3SignerRequest.init(
|
let request = Web3SignerRequest.init(
|
||||||
fork, genesis_validators_root,
|
fork, genesis_validators_root,
|
||||||
Web3SignerForkedBeaconBlock(
|
Web3SignerForkedBeaconBlock(
|
||||||
kind: ConsensusFork.Bellatrix,
|
kind: ConsensusFork.Bellatrix,
|
||||||
bellatrixData: blck.toBeaconBlockHeader))
|
bellatrixData: blck.toBeaconBlockHeader))
|
||||||
await v.signData(request)
|
await v.signData(request)
|
||||||
|
elif blck is capella_mev.BlindedBeaconBlock:
|
||||||
|
let request = Web3SignerRequest.init(
|
||||||
|
fork, genesis_validators_root,
|
||||||
|
Web3SignerForkedBeaconBlock(
|
||||||
|
kind: ConsensusFork.Capella,
|
||||||
|
capellaData: blck.toBeaconBlockHeader))
|
||||||
|
await v.signData(request)
|
||||||
else:
|
else:
|
||||||
let
|
let
|
||||||
web3SignerBlock =
|
web3SignerBlock =
|
||||||
|
|
Loading…
Reference in New Issue