-
Notifications
You must be signed in to change notification settings - Fork 258
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
implement /eth/v1/beacon/blinded_blocks BN endpoint
- Loading branch information
Showing
6 changed files
with
263 additions
and
106 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
# beacon_chain | ||
# Copyright (c) 2018-2022 Status Research & Development GmbH | ||
# Licensed and distributed under either of | ||
# * 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). | ||
# at your option. This file may not be copied, modified, or distributed except according to those terms. | ||
|
||
when (NimMajor, NimMinor) < (1, 4): | ||
{.push raises: [Defect].} | ||
else: | ||
{.push raises: [].} | ||
|
||
import std/macros | ||
import metrics | ||
import ../beacon_node | ||
|
||
from eth/async_utils import awaitWithTimeout | ||
from ../spec/mev/rest_bellatrix_mev_calls import submitBlindedBlock | ||
|
||
const | ||
BUILDER_BLOCK_SUBMISSION_DELAY_TOLERANCE = 4.seconds | ||
|
||
declareCounter beacon_block_builder_proposed, | ||
"Number of beacon chain blocks produced using an external block builder" | ||
|
||
func getFieldNames*(x: typedesc[auto]): seq[string] {.compileTime.} = | ||
var res: seq[string] | ||
for name, _ in fieldPairs(default(x)): | ||
res.add name | ||
res | ||
|
||
macro copyFields*( | ||
dst: untyped, src: untyped, fieldNames: static[seq[string]]): untyped = | ||
result = newStmtList() | ||
for name in fieldNames: | ||
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"]: | ||
# TODO use stew/assign2 | ||
result.add newAssignment( | ||
newDotExpr(dst, ident(name)), newDotExpr(src, ident(name))) | ||
|
||
proc unblindAndRouteBlockMEV*( | ||
node: BeaconNode, blindedBlock: SignedBlindedBeaconBlock): | ||
Future[Result[Opt[BlockRef], string]] {.async.} = | ||
# By time submitBlindedBlock is called, must already have done slashing | ||
# protection check | ||
let unblindedPayload = | ||
try: | ||
awaitWithTimeout( | ||
node.payloadBuilderRestClient.submitBlindedBlock(blindedBlock), | ||
BUILDER_BLOCK_SUBMISSION_DELAY_TOLERANCE): | ||
error "Submitting blinded block timed out", | ||
blk = shortLog(blindedBlock) | ||
return err("Submitting blinded block timed out") | ||
# From here on, including error paths, disallow local EL production by | ||
# returning Opt.some, regardless of whether on head or newBlock. | ||
except RestDecodingError as exc: | ||
error "unblindAndRouteBlockMEV: REST decoding error submitting blinded block", | ||
blindedBlock, error = exc.msg | ||
return err("REST decoding error submitting blinded block: " & exc.msg) | ||
except CatchableError as exc: | ||
error "unblindAndRouteBlockMEV: exception in submitBlindedBlock", | ||
blindedBlock, error = exc.msg | ||
return err("exception in submitBlindedBlock: " & exc.msg) | ||
|
||
const httpOk = 200 | ||
if unblindedPayload.status == httpOk: | ||
if hash_tree_root( | ||
blindedBlock.message.body.execution_payload_header) != | ||
hash_tree_root(unblindedPayload.data.data): | ||
debug "unblindAndRouteBlockMEV: unblinded payload doesn't match blinded payload", | ||
blindedPayload = | ||
blindedBlock.message.body.execution_payload_header | ||
else: | ||
# Signature provided is consistent with unblinded execution payload, | ||
# so construct full beacon block | ||
# https://github.com/ethereum/builder-specs/blob/v0.2.0/specs/validator.md#block-proposal | ||
var signedBlock = bellatrix.SignedBeaconBlock( | ||
signature: blindedBlock.signature) | ||
copyFields( | ||
signedBlock.message, blindedBlock.message, | ||
getFieldNames(typeof(signedBlock.message))) | ||
copyFields( | ||
signedBlock.message.body, blindedBlock.message.body, | ||
getFieldNames(typeof(signedBlock.message.body))) | ||
signedBlock.message.body.execution_payload = unblindedPayload.data.data | ||
|
||
if signedBlock.root != hash_tree_root(blindedBlock.message): | ||
return err("Unblinded block doesn't match blinded block SSZ root") | ||
|
||
signedBlock.root = hash_tree_root(signedBlock.message) | ||
|
||
debug "unblindAndRouteBlockMEV: proposing unblinded block", | ||
blck = shortLog(signedBlock) | ||
|
||
let newBlockRef = | ||
(await node.router.routeSignedBeaconBlock(signedBlock)).valueOr: | ||
# submitBlindedBlock has run, so don't allow fallback to run | ||
return err("routeSignedBeaconBlock error") # Errors logged in router | ||
|
||
if newBlockRef.isSome: | ||
beacon_block_builder_proposed.inc() | ||
notice "Block proposed (MEV)", | ||
blockRoot = shortLog(signedBlock.root), blck = shortLog(signedBlock), | ||
signature = shortLog(signedBlock.signature) | ||
|
||
return ok newBlockRef | ||
else: | ||
debug "unblindAndRouteBlockMEV: submitBlindedBlock failed", | ||
blindedBlock, payloadStatus = unblindedPayload.status | ||
|
||
# https://github.com/ethereum/builder-specs/blob/v0.2.0/specs/validator.md#proposer-slashing | ||
# This means if a validator publishes a signature for a | ||
# `BlindedBeaconBlock` (via a dissemination of a | ||
# `SignedBlindedBeaconBlock`) then the validator **MUST** not use the | ||
# local build process as a fallback, even in the event of some failure | ||
# with the external buildernetwork. | ||
return err("unblindAndRouteBlockMEV error") | ||
|
Oops, something went wrong.