Skip to content

Commit

Permalink
use RestPlainResponse to improve builder API rerror reporting (#5819)
Browse files Browse the repository at this point in the history
  • Loading branch information
tersec authored Jan 24, 2024
1 parent 228c790 commit 128834a
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 28 deletions.
4 changes: 2 additions & 2 deletions beacon_chain/spec/mev/rest_capella_mev_calls.nim
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ proc registerValidator*(body: seq[SignedValidatorRegistrationV1]
proc getHeaderCapella*(slot: Slot,
parent_hash: Eth2Digest,
pubkey: ValidatorPubKey
): RestResponse[GetHeaderResponseCapella] {.
): 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: capella_mev.SignedBlindedBeaconBlock
): RestResponse[SubmitBlindedBlockResponseCapella] {.
): RestPlainResponse {.
rest, endpoint: "/eth/v1/builder/blinded_blocks",
meth: MethodPost, connection: {Dedicated, Close}.}
## https://github.com/ethereum/builder-specs/blob/v0.4.0/apis/builder/blinded_blocks.yaml
4 changes: 2 additions & 2 deletions beacon_chain/spec/mev/rest_deneb_mev_calls.nim
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ export chronos, client, rest_types, eth2_rest_serialization
proc getHeaderDeneb*(slot: Slot,
parent_hash: Eth2Digest,
pubkey: ValidatorPubKey
): RestResponse[GetHeaderResponseDeneb] {.
): 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: deneb_mev.SignedBlindedBeaconBlock
): RestResponse[SubmitBlindedBlockResponseDeneb] {.
): RestPlainResponse {.
rest, endpoint: "/eth/v1/builder/blinded_blocks",
meth: MethodPost, connection: {Dedicated, Close}.}
## https://github.com/ethereum/builder-specs/blob/v0.4.0/apis/builder/blinded_blocks.yaml
51 changes: 36 additions & 15 deletions beacon_chain/validators/beacon_validators.nim
Original file line number Diff line number Diff line change
Expand Up @@ -568,34 +568,55 @@ proc getBlindedExecutionPayload[
# Not ideal to use `when` where instead of splitting into separate functions,
# but Nim doesn't overload on generic EPH type parameter.
when EPH is capella.ExecutionPayloadHeader:
let blindedHeader = awaitWithTimeout(
payloadBuilderClient.getHeaderCapella(slot, executionBlockRoot, pubkey),
BUILDER_PROPOSAL_DELAY_TOLERANCE):
return err "Timeout obtaining Capella blinded header from builder"
let
response = awaitWithTimeout(
payloadBuilderClient.getHeaderCapella(
slot, executionBlockRoot, pubkey),
BUILDER_PROPOSAL_DELAY_TOLERANCE):
return err "Timeout obtaining Capella blinded header from builder"

res = decodeBytes(
GetHeaderResponseCapella, response.data, response.contentType)

blindedHeader = res.valueOr:
return err(
"Unable to decode Capella blinded header: " & $res.error &
" with HTTP status " & $response.status & ", Content-Type " &
$response.contentType & " and content " & $response.data)
elif EPH is deneb_mev.BlindedExecutionPayloadAndBlobsBundle:
let blindedHeader = awaitWithTimeout(
payloadBuilderClient.getHeaderDeneb(slot, executionBlockRoot, pubkey),
BUILDER_PROPOSAL_DELAY_TOLERANCE):
return err "Timeout obtaining Deneb blinded header and blob bundle from builder"
let
response = awaitWithTimeout(
payloadBuilderClient.getHeaderDeneb(
slot, executionBlockRoot, pubkey),
BUILDER_PROPOSAL_DELAY_TOLERANCE):
return err "Timeout obtaining Deneb blinded header from builder"

res = decodeBytes(
GetHeaderResponseDeneb, response.data, response.contentType)

blindedHeader = res.valueOr:
return err(
"Unable to decode Deneb blinded header: " & $res.error &
" with HTTP status " & $response.status & ", Content-Type " &
$response.contentType & " and content " & $response.data)
else:
static: doAssert false

const httpOk = 200
if blindedHeader.status != httpOk:
if response.status != httpOk:
return err "getBlindedExecutionPayload: non-200 HTTP response"
else:
if not verify_builder_signature(
node.dag.cfg.genesisFork, blindedHeader.data.data.message,
blindedHeader.data.data.message.pubkey,
blindedHeader.data.data.signature):
node.dag.cfg.genesisFork, blindedHeader.data.message,
blindedHeader.data.message.pubkey, blindedHeader.data.signature):
return err "getBlindedExecutionPayload: signature verification failed"

when EPH is capella.ExecutionPayloadHeader:
return ok((
blindedBlckPart: blindedHeader.data.data.message.header,
blockValue: blindedHeader.data.data.message.value))
blindedBlckPart: blindedHeader.data.message.header,
blockValue: blindedHeader.data.message.value))
elif EPH is deneb_mev.BlindedExecutionPayloadAndBlobsBundle:
template builderBid: untyped = blindedHeader.data.data.message
template builderBid: untyped = blindedHeader.data.message
return ok((
blindedBlckPart: EPH(
execution_payload_header: builderBid.header,
Expand Down
35 changes: 26 additions & 9 deletions beacon_chain/validators/message_router_mev.nim
Original file line number Diff line number Diff line change
Expand Up @@ -55,34 +55,51 @@ proc unblindAndRouteBlockMEV*(

# By time submitBlindedBlock is called, must already have done slashing
# protection check
let bundle =
let response =
try:
awaitWithTimeout(
payloadBuilderRestClient.submitBlindedBlock(blindedBlock),
BUILDER_BLOCK_SUBMISSION_DELAY_TOLERANCE):
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:
return err("REST decoding error submitting blinded block: " & exc.msg)
except CatchableError as exc:
return err("exception in submitBlindedBlock: " & exc.msg)

const httpOk = 200
if bundle.status != httpOk:
if response.status != httpOk:
# https://github.com/ethereum/builder-specs/blob/v0.4.0/specs/bellatrix/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 builder network.
return err("submitBlindedBlock failed with HTTP error code " &
$bundle.status & ": " & $shortLog(blindedBlock))
$response.status & ": " & $shortLog(blindedBlock))

when consensusFork >= ConsensusFork.Deneb:
template execution_payload: untyped = bundle.data.data.execution_payload
let
res = decodeBytes(
SubmitBlindedBlockResponseDeneb, response.data, response.contentType)

bundle = res.valueOr:
return err("Could not decode Deneb blinded block: " & $res.error &
" with HTTP status " & $response.status & ", Content-Type " &
$response.contentType & " and content " & $response.data)

template execution_payload: untyped = bundle.data.execution_payload
else:
template execution_payload: untyped = bundle.data.data
let
res = decodeBytes(
SubmitBlindedBlockResponseCapella, response.data, response.contentType)

bundle = res.valueOr:
return err("Could not decode Capella blinded block: " & $res.error &
" with HTTP status " & $response.status & ", Content-Type " &
$response.contentType & " and content " & $response.data)

template execution_payload: untyped = bundle.data

if hash_tree_root(blindedBlock.message.body.execution_payload_header) !=
hash_tree_root(execution_payload):
return err("unblinded payload doesn't match blinded payload header: " &
Expand All @@ -105,9 +122,9 @@ proc unblindAndRouteBlockMEV*(

let blobsOpt =
when consensusFork >= ConsensusFork.Deneb:
template blobs_bundle: untyped = bundle.data.data.blobs_bundle
template blobs_bundle: untyped = bundle.data.blobs_bundle
if blindedBlock.message.body.blob_kzg_commitments !=
bundle.data.data.blobs_bundle.commitments:
bundle.data.blobs_bundle.commitments:
return err("unblinded blobs bundle has unexpected commitments")
let ok = verifyProofs(
asSeq blobs_bundle.blobs,
Expand Down

0 comments on commit 128834a

Please sign in to comment.