Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 62 additions & 2 deletions beacon_chain/rpc/rest_beacon_api.nim
Original file line number Diff line number Diff line change
Expand Up @@ -894,8 +894,68 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =

return RestApiResponse.jsonMsgResponse(BlockValidationSuccess)

# TODO
# Add POST /eth/v2/beacon/blocks
# https://ethereum.github.io/beacon-APIs/#/Beacon/publishBlockV2
router.api(MethodPost, "/eth/v2/beacon/blocks") do (
contentBody: Option[ContentBody]) -> RestApiResponse:
let res =
block:
if contentBody.isNone():
return RestApiResponse.jsonError(Http400, EmptyRequestBodyError)
if request.headers.getString("broadcast_validation") != "gossip":
# TODO (henridf): support 'consensus' and 'consensus_and_equivocation'
# broadcast_validation
return RestApiResponse.jsonError(
Http500, "gossip broadcast_validation only supported")
let
body = contentBody.get()
version = request.headers.getString("eth-consensus-version")
var
restBlock = decodeBodyJsonOrSsz(RestPublishedSignedBlockContents,
body, version).valueOr:
return RestApiResponse.jsonError(Http400, InvalidBlockObjectError,
$error)
forked = ForkedSignedBeaconBlock.init(restBlock)

# TODO (henridf): handle broadcast_validation flag
if restBlock.kind != node.dag.cfg.consensusForkAtEpoch(
getForkedBlockField(forked, slot).epoch):
doAssert strictVerification notin node.dag.updateFlags
return RestApiResponse.jsonError(Http400, InvalidBlockObjectError)

case restBlock.kind
of ConsensusFork.Phase0:
var blck = restBlock.phase0Data
blck.root = hash_tree_root(blck.message)
await node.router.routeSignedBeaconBlock(blck,
Opt.none(SignedBlobSidecars))
of ConsensusFork.Altair:
var blck = restBlock.altairData
blck.root = hash_tree_root(blck.message)
await node.router.routeSignedBeaconBlock(blck,
Opt.none(SignedBlobSidecars))
of ConsensusFork.Bellatrix:
var blck = restBlock.bellatrixData
blck.root = hash_tree_root(blck.message)
await node.router.routeSignedBeaconBlock(blck,
Opt.none(SignedBlobSidecars))
of ConsensusFork.Capella:
var blck = restBlock.capellaData
blck.root = hash_tree_root(blck.message)
await node.router.routeSignedBeaconBlock(blck,
Opt.none(SignedBlobSidecars))
of ConsensusFork.Deneb:
var blck = restBlock.denebData.signed_block
blck.root = hash_tree_root(blck.message)
await node.router.routeSignedBeaconBlock(
blck, Opt.some(asSeq restBlock.denebData.signed_blob_sidecars))

if res.isErr():
return RestApiResponse.jsonError(
Http503, BeaconNodeInSyncError, $res.error())
if res.get().isNone():
return RestApiResponse.jsonError(Http202, BlockValidationError)

return RestApiResponse.jsonMsgResponse(BlockValidationSuccess)

# https://ethereum.github.io/beacon-APIs/#/Beacon/publishBlindedBlock
# https://github.com/ethereum/beacon-APIs/blob/v2.4.0/apis/beacon/blocks/blinded_blocks.yaml
Expand Down
98 changes: 96 additions & 2 deletions beacon_chain/spec/eth2_apis/eth2_rest_serialization.nim
Original file line number Diff line number Diff line change
Expand Up @@ -3027,7 +3027,7 @@ proc decodeBody*(
t: typedesc[RestPublishedSignedBlockContents],
body: ContentBody,
version: string
): Result[RestPublishedSignedBlockContents, cstring] =
): Result[RestPublishedSignedBlockContents, string] =
if body.contentType == ApplicationJsonMediaType:
let data =
try:
Expand All @@ -3043,7 +3043,9 @@ proc decodeBody*(
return err("Unexpected deserialization error")
ok(data)
elif body.contentType == OctetStreamMediaType:
let consensusFork = ? ConsensusFork.decodeString(version)
let consensusFork =
decodeEthConsensusVersion(version).valueOr:
return err("Invalid or Unsupported consensus version")
case consensusFork
of ConsensusFork.Phase0:
let blck =
Expand Down Expand Up @@ -3116,6 +3118,98 @@ proc decodeBody*[T](t: typedesc[T],
return err("Unexpected deserialization error")
ok(data)

proc decodeBodyJsonOrSsz*(
t: typedesc[RestPublishedSignedBlockContents],
body: ContentBody,
version: string
): Result[RestPublishedSignedBlockContents, string] =
if body.contentType == OctetStreamMediaType:
decodeBody(RestPublishedSignedBlockContents, body, version)
elif body.contentType == ApplicationJsonMediaType:
let consensusFork =
decodeEthConsensusVersion(version).valueOr:
return err("Invalid or Unsupported consensus version")
case consensusFork
of ConsensusFork.Phase0:
let blck =
try:
RestJson.decode(body.data, phase0.SignedBeaconBlock,
requireAllFields = true,
allowUnknownFields = true)
except SerializationError as exc:
debug "Failed to deserialize REST JSON data",
err = exc.formatMsg("<data>"),
data = string.fromBytes(body.data)
return err("Unable to deserialize JSON for fork " &
version & ": " & exc.formatMsg("<data>"))
except CatchableError as exc:
return err("Unexpected JSON deserialization error: " & exc.msg)
ok(RestPublishedSignedBlockContents(
kind: ConsensusFork.Phase0, phase0Data: blck))
of ConsensusFork.Altair:
let blck =
try:
RestJson.decode(body.data, altair.SignedBeaconBlock,
requireAllFields = true,
allowUnknownFields = true)
except SerializationError as exc:
debug "Failed to deserialize REST JSON data",
err = exc.formatMsg("<data>"),
data = string.fromBytes(body.data)
return err("Unable to deserialize data")
except CatchableError:
return err("Unexpected deserialization error")
ok(RestPublishedSignedBlockContents(
kind: ConsensusFork.Altair, altairData: blck))
of ConsensusFork.Bellatrix:
let blck =
try:
RestJson.decode(body.data, bellatrix.SignedBeaconBlock,
requireAllFields = true,
allowUnknownFields = true)
except SerializationError as exc:
debug "Failed to deserialize REST JSON data",
err = exc.formatMsg("<data>"),
data = string.fromBytes(body.data)
return err("Unable to deserialize data")
except CatchableError:
return err("Unexpected deserialization error")
ok(RestPublishedSignedBlockContents(
kind: ConsensusFork.Bellatrix, bellatrixData: blck))
of ConsensusFork.Capella:
let blck =
try:
RestJson.decode(body.data, capella.SignedBeaconBlock,
requireAllFields = true,
allowUnknownFields = true)
except SerializationError as exc:
debug "Failed to deserialize REST JSON data",
err = exc.formatMsg("<data>"),
data = string.fromBytes(body.data)
return err("Unable to deserialize data")
except CatchableError:
return err("Unexpected deserialization error")
ok(RestPublishedSignedBlockContents(
kind: ConsensusFork.Capella, capellaData: blck))
of ConsensusFork.Deneb:
let blckContents =
try:
RestJson.decode(body.data, DenebSignedBlockContents,
requireAllFields = true,
allowUnknownFields = true)
except SerializationError as exc:
debug "Failed to deserialize REST JSON data",
err = exc.formatMsg("<data>"),
data = string.fromBytes(body.data)
return err("Unable to deserialize data")
except CatchableError:
return err("Unexpected deserialization error")
ok(RestPublishedSignedBlockContents(
kind: ConsensusFork.Deneb, denebData: blckContents))
else:
return err("Unsupported or invalid content media type")


proc decodeBodyJsonOrSsz*[T](t: typedesc[T],
body: ContentBody): Result[T, cstring] =
if body.contentType == ApplicationJsonMediaType:
Expand Down
39 changes: 39 additions & 0 deletions beacon_chain/spec/eth2_apis/rest_beacon_calls.nim
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,45 @@ proc publishSszBlock*(
extraHeaders = @[("eth-consensus-version", consensus)])
return resp

proc publishBlockV2Plain(body: phase0.SignedBeaconBlock): RestPlainResponse {.
rest, endpoint: "/eth/v2/beacon/blocks",
meth: MethodPost.}
## https://ethereum.github.io/beacon-APIs/#/Beacon/publishBlockV2

proc publishBlockV2Plain(body: altair.SignedBeaconBlock): RestPlainResponse {.
rest, endpoint: "/eth/v2/beacon/blocks",
meth: MethodPost.}
## https://ethereum.github.io/beacon-APIs/#/Beacon/publishBlockV2

proc publishBlockV2Plain(body: bellatrix.SignedBeaconBlock): RestPlainResponse {.
rest, endpoint: "/eth/v2/beacon/blocks",
meth: MethodPost.}
## https://ethereum.github.io/beacon-APIs/#/Beacon/publishBlockV2

proc publishBlockV2Plain(body: capella.SignedBeaconBlock): RestPlainResponse {.
rest, endpoint: "/eth/v2/beacon/blocks",
meth: MethodPost.}
## https://ethereum.github.io/beacon-APIs/#/Beacon/publishBlockV2

proc publishBlockV2Plain(body: DenebSignedBlockContents): RestPlainResponse {.
rest, endpoint: "/eth/v2/beacon/blocks",
meth: MethodPost.}
## https://ethereum.github.io/beacon-APIs/#/Beacon/publishBlockV2

proc publishBlockV2*(
client: RestClientRef,
blck: phase0.SignedBeaconBlock | altair.SignedBeaconBlock |
bellatrix.SignedBeaconBlock | capella.SignedBeaconBlock |
deneb.SignedBeaconBlock
): Future[RestPlainResponse] {.async} =
let
consensus = typeof(blck).toFork.toString()
resp = await client.publishBlockV2Plain(
blck, extraHeaders = @[
("eth-consensus-version", consensus),
("broadcast_validation", "gossip")])
return resp

proc publishBlindedBlock*(body: phase0.SignedBeaconBlock): RestPlainResponse {.
rest, endpoint: "/eth/v1/beacon/blinded_blocks",
meth: MethodPost.}
Expand Down