avoid code repetition across forks for signed block contents (#6150)

Use forks sugar to make `RestPublishedSignedBlockContents` more concise.
This commit is contained in:
Etan Kissling 2024-04-03 02:05:29 +02:00 committed by GitHub
parent 109007dc93
commit 5f4fa9ae69
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 92 additions and 202 deletions

View File

@ -129,21 +129,6 @@ proc toString*(kind: ValidatorFilterKind): string =
of ValidatorFilterKind.WithdrawalDone: of ValidatorFilterKind.WithdrawalDone:
"withdrawal_done" "withdrawal_done"
func checkRestBlockBlobsValid(
forkyBlck: deneb.SignedBeaconBlock | electra.SignedBeaconBlock,
kzg_proofs: KzgProofs,
blobs: Blobs): Result[void, string] =
if kzg_proofs.len != blobs.len:
return err("Invalid block publish: " & $kzg_proofs.len & " KZG proofs and " &
$blobs.len & " blobs")
if kzg_proofs.len != forkyBlck.message.body.blob_kzg_commitments.len:
return err("Invalid block publish: " & $kzg_proofs.len &
" KZG proofs and " & $forkyBlck.message.body.blob_kzg_commitments.len &
" KZG commitments")
ok()
proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) = proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
# https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4881.md # https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4881.md
router.api2(MethodGet, "/eth/v1/beacon/deposit_snapshot") do ( router.api2(MethodGet, "/eth/v1/beacon/deposit_snapshot") do (
@ -900,50 +885,23 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
let let
body = contentBody.get() body = contentBody.get()
version = request.headers.getString("eth-consensus-version") version = request.headers.getString("eth-consensus-version")
var restBlock = decodeBody(
restBlock = decodeBody(RestPublishedSignedBlockContents, body, RestPublishedSignedBlockContents, body, version).valueOr:
version).valueOr: return RestApiResponse.jsonError(error)
return RestApiResponse.jsonError(error)
forked = ForkedSignedBeaconBlock.init(restBlock)
if restBlock.kind != node.dag.cfg.consensusForkAtEpoch( withForkyBlck(restBlock):
getForkedBlockField(forked, slot).epoch): if restBlock.kind != node.dag.cfg.consensusForkAtEpoch(
doAssert strictVerification notin node.dag.updateFlags forkyBlck.message.slot.epoch):
return RestApiResponse.jsonError(Http400, InvalidBlockObjectError) doAssert strictVerification notin node.dag.updateFlags
return RestApiResponse.jsonError(Http400, InvalidBlockObjectError)
case restBlock.kind when consensusFork >= ConsensusFork.Deneb:
of ConsensusFork.Phase0: await node.router.routeSignedBeaconBlock(
var blck = restBlock.phase0Data forkyBlck, Opt.some(
blck.root = hash_tree_root(blck.message) forkyBlck.create_blob_sidecars(kzg_proofs, blobs)))
await node.router.routeSignedBeaconBlock( else:
blck, Opt.none(seq[BlobSidecar])) await node.router.routeSignedBeaconBlock(
of ConsensusFork.Altair: forkyBlck, Opt.none(seq[BlobSidecar]))
var blck = restBlock.altairData
blck.root = hash_tree_root(blck.message)
await node.router.routeSignedBeaconBlock(
blck, Opt.none(seq[BlobSidecar]))
of ConsensusFork.Bellatrix:
var blck = restBlock.bellatrixData
blck.root = hash_tree_root(blck.message)
await node.router.routeSignedBeaconBlock(
blck, Opt.none(seq[BlobSidecar]))
of ConsensusFork.Capella:
var blck = restBlock.capellaData
blck.root = hash_tree_root(blck.message)
await node.router.routeSignedBeaconBlock(
blck, Opt.none(seq[BlobSidecar]))
of ConsensusFork.Deneb:
var blck = restBlock.denebData.signed_block
blck.root = hash_tree_root(blck.message)
let validity = checkRestBlockBlobsValid(
blck, restBlock.denebData.kzg_proofs, restBlock.denebData.blobs)
if validity.isErr:
return RestApiResponse.jsonError(Http400, validity.error)
await node.router.routeSignedBeaconBlock(
blck, Opt.some(blck.create_blob_sidecars(
restBlock.denebData.kzg_proofs, restBlock.denebData.blobs)))
if res.isErr(): if res.isErr():
return RestApiResponse.jsonError( return RestApiResponse.jsonError(
@ -981,51 +939,24 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
if contentBody.isNone(): if contentBody.isNone():
return RestApiResponse.jsonError(Http400, EmptyRequestBodyError) return RestApiResponse.jsonError(Http400, EmptyRequestBodyError)
contentBody.get() contentBody.get()
var restBlock = decodeBodyJsonOrSsz(
restBlock = decodeBodyJsonOrSsz(RestPublishedSignedBlockContents, RestPublishedSignedBlockContents, body, version).valueOr:
body, version).valueOr: return RestApiResponse.jsonError(error)
return RestApiResponse.jsonError(error)
forked = ForkedSignedBeaconBlock.init(restBlock)
# TODO (henridf): handle broadcast_validation flag withForkyBlck(restBlock):
if restBlock.kind != node.dag.cfg.consensusForkAtEpoch( # TODO (henridf): handle broadcast_validation flag
getForkedBlockField(forked, slot).epoch): if restBlock.kind != node.dag.cfg.consensusForkAtEpoch(
doAssert strictVerification notin node.dag.updateFlags forkyBlck.message.slot.epoch):
return RestApiResponse.jsonError(Http400, InvalidBlockObjectError) doAssert strictVerification notin node.dag.updateFlags
return RestApiResponse.jsonError(Http400, InvalidBlockObjectError)
case restBlock.kind when consensusFork >= ConsensusFork.Deneb:
of ConsensusFork.Phase0: await node.router.routeSignedBeaconBlock(
var blck = restBlock.phase0Data forkyBlck, Opt.some(
blck.root = hash_tree_root(blck.message) forkyBlck.create_blob_sidecars(kzg_proofs, blobs)))
await node.router.routeSignedBeaconBlock( else:
blck, Opt.none(seq[BlobSidecar])) await node.router.routeSignedBeaconBlock(
of ConsensusFork.Altair: forkyBlck, Opt.none(seq[BlobSidecar]))
var blck = restBlock.altairData
blck.root = hash_tree_root(blck.message)
await node.router.routeSignedBeaconBlock(
blck, Opt.none(seq[BlobSidecar]))
of ConsensusFork.Bellatrix:
var blck = restBlock.bellatrixData
blck.root = hash_tree_root(blck.message)
await node.router.routeSignedBeaconBlock(
blck, Opt.none(seq[BlobSidecar]))
of ConsensusFork.Capella:
var blck = restBlock.capellaData
blck.root = hash_tree_root(blck.message)
await node.router.routeSignedBeaconBlock(
blck, Opt.none(seq[BlobSidecar]))
of ConsensusFork.Deneb:
var blck = restBlock.denebData.signed_block
blck.root = hash_tree_root(blck.message)
let validity = checkRestBlockBlobsValid(
blck, restBlock.denebData.kzg_proofs, restBlock.denebData.blobs)
if validity.isErr:
return RestApiResponse.jsonError(Http400, validity.error)
await node.router.routeSignedBeaconBlock(
blck, Opt.some(blck.create_blob_sidecars(
restBlock.denebData.kzg_proofs, restBlock.denebData.blobs)))
if res.isErr(): if res.isErr():
return RestApiResponse.jsonError( return RestApiResponse.jsonError(

View File

@ -2020,44 +2020,8 @@ proc readValue*(reader: var JsonReader[RestJson],
reader.raiseUnexpectedValue("Field `message` is missing") reader.raiseUnexpectedValue("Field `message` is missing")
let blck = ForkedBeaconBlock(message.get()) let blck = ForkedBeaconBlock(message.get())
value = RestPublishedSignedBeaconBlock( value = RestPublishedSignedBeaconBlock ForkedSignedBeaconBlock.init(
case blck.kind blck, blck.hash_tree_root(), signature.get())
of ConsensusFork.Phase0:
ForkedSignedBeaconBlock.init(
phase0.SignedBeaconBlock(
message: blck.phase0Data,
signature: signature.get()
)
)
of ConsensusFork.Altair:
ForkedSignedBeaconBlock.init(
altair.SignedBeaconBlock(
message: blck.altairData,
signature: signature.get()
)
)
of ConsensusFork.Bellatrix:
ForkedSignedBeaconBlock.init(
bellatrix.SignedBeaconBlock(
message: blck.bellatrixData,
signature: signature.get()
)
)
of ConsensusFork.Capella:
ForkedSignedBeaconBlock.init(
capella.SignedBeaconBlock(
message: blck.capellaData,
signature: signature.get()
)
)
of ConsensusFork.Deneb:
ForkedSignedBeaconBlock.init(
deneb.SignedBeaconBlock(
message: blck.denebData,
signature: signature.get()
)
)
)
proc readValue*(reader: var JsonReader[RestJson], proc readValue*(reader: var JsonReader[RestJson],
value: var RestPublishedSignedBlockContents) {. value: var RestPublishedSignedBlockContents) {.
@ -2104,17 +2068,6 @@ proc readValue*(reader: var JsonReader[RestJson],
Opt.none(RestPublishedSignedBeaconBlock) Opt.none(RestPublishedSignedBeaconBlock)
if signed_message.isNone(): if signed_message.isNone():
reader.raiseUnexpectedValue("Incorrect signed_block format") reader.raiseUnexpectedValue("Incorrect signed_block format")
# Only needed to signal fork to the blck.kind case selection
let blck = ForkedSignedBeaconBlock(signed_message.get())
message = Opt.some(RestPublishedBeaconBlock(
case blck.kind
of ConsensusFork.Phase0, ConsensusFork.Altair, ConsensusFork.Bellatrix,
ConsensusFork.Capella:
reader.raiseUnexpectedValue("Incorrect signed_block format")
of ConsensusFork.Deneb:
ForkedBeaconBlock.init(blck.denebData.message)
))
of "kzg_proofs": of "kzg_proofs":
if kzg_proofs.isSome(): if kzg_proofs.isSome():
reader.raiseUnexpectedField( reader.raiseUnexpectedField(
@ -2138,69 +2091,49 @@ proc readValue*(reader: var JsonReader[RestJson],
else: else:
unrecognizedFieldWarning() unrecognizedFieldWarning()
if signed_message.isNone(): if signed_message.isSome():
# Pre-Deneb; conditions for when signed_message.isSome checked in case body if message.isSome():
if signature.isNone(): reader.raiseUnexpectedValue("Field `message` found but unsupported")
reader.raiseUnexpectedValue("Field `signature` is missing") if signature.isSome():
if message.isNone(): reader.raiseUnexpectedValue("Field `signature` found but unsupported")
reader.raiseUnexpectedValue("Field `message` is missing")
let blck = ForkedBeaconBlock(message.get())
if blck.kind >= ConsensusFork.Deneb:
if kzg_proofs.isNone(): if kzg_proofs.isNone():
reader.raiseUnexpectedValue("Field `kzg_proofs` is missing") reader.raiseUnexpectedValue("Field `kzg_proofs` is missing")
if blobs.isNone(): if blobs.isNone():
reader.raiseUnexpectedValue("Field `blobs` is missing") reader.raiseUnexpectedValue("Field `blobs` is missing")
if kzg_proofs.get.len != blobs.get.len:
reader.raiseUnexpectedValue("Length mismatch of `kzg_proofs` and `blobs`")
withBlck(distinctBase(signed_message.get)):
when consensusFork >= ConsensusFork.Deneb:
template kzg_commitments: untyped =
forkyBlck.message.body.blob_kzg_commitments
if kzg_proofs.get().len != kzg_commitments.len:
reader.raiseUnexpectedValue(
"Length mismatch of `kzg_proofs` and `blob_kzg_commitments`")
value = RestPublishedSignedBlockContents.init(
consensusFork.BlockContents(
`block`: forkyBlck.message,
kzg_proofs: kzg_proofs.get(),
blobs: blobs.get()),
forkyBlck.root, forkyBlck.signature)
else:
reader.raiseUnexpectedValue("`signed_message` supported post-Deneb")
else: else:
if signature.isNone():
reader.raiseUnexpectedValue("Field `signature` is missing")
if message.isNone():
reader.raiseUnexpectedValue("Field `message` is missing")
if kzg_proofs.isSome(): if kzg_proofs.isSome():
reader.raiseUnexpectedValue("Field `kzg_proofs` found but unsupported") reader.raiseUnexpectedValue("Field `kzg_proofs` found but unsupported")
if blobs.isSome(): if blobs.isSome():
reader.raiseUnexpectedValue("Field `blobs` found but unsupported") reader.raiseUnexpectedValue("Field `blobs` found but unsupported")
case blck.kind withBlck(distinctBase(message.get)):
of ConsensusFork.Phase0: when consensusFork < ConsensusFork.Deneb:
value = RestPublishedSignedBlockContents( value = RestPublishedSignedBlockContents.init(
kind: ConsensusFork.Phase0, forkyBlck, forkyBlck.hash_tree_root(), signature.get)
phase0Data: phase0.SignedBeaconBlock( else:
message: blck.phase0Data, reader.raiseUnexpectedValue("`message` support stopped at Deneb")
signature: signature.get()
)
)
of ConsensusFork.Altair:
value = RestPublishedSignedBlockContents(
kind: ConsensusFork.Altair,
altairData: altair.SignedBeaconBlock(
message: blck.altairData,
signature: signature.get()
)
)
of ConsensusFork.Bellatrix:
value = RestPublishedSignedBlockContents(
kind: ConsensusFork.Bellatrix,
bellatrixData: bellatrix.SignedBeaconBlock(
message: blck.bellatrixData,
signature: signature.get()
)
)
of ConsensusFork.Capella:
value = RestPublishedSignedBlockContents(
kind: ConsensusFork.Capella,
capellaData: capella.SignedBeaconBlock(
message: blck.capellaData,
signature: signature.get()
)
)
of ConsensusFork.Deneb:
value = RestPublishedSignedBlockContents(
kind: ConsensusFork.Deneb,
denebData: DenebSignedBlockContents(
# Constructed to be internally consistent
signed_block: signed_message.get().distinctBase.denebData,
kzg_proofs: kzg_proofs.get(),
blobs: blobs.get()
)
)
## ForkedSignedBeaconBlock ## ForkedSignedBeaconBlock
proc readValue*(reader: var JsonReader[RestJson], proc readValue*(reader: var JsonReader[RestJson],

View File

@ -612,6 +612,32 @@ type
func `==`*(a, b: RestValidatorIndex): bool = func `==`*(a, b: RestValidatorIndex): bool =
uint64(a) == uint64(b) uint64(a) == uint64(b)
template withForkyBlck*(
x: RestPublishedSignedBlockContents, body: untyped): untyped =
case x.kind
of ConsensusFork.Deneb:
const consensusFork {.inject, used.} = ConsensusFork.Deneb
template forkyBlck: untyped {.inject, used.} = x.denebData.signed_block
template kzg_proofs: untyped {.inject, used.} = x.denebData.kzg_proofs
template blobs: untyped {.inject, used.} = x.denebData.blobs
body
of ConsensusFork.Capella:
const consensusFork {.inject, used.} = ConsensusFork.Capella
template forkyBlck: untyped {.inject, used.} = x.capellaData
body
of ConsensusFork.Bellatrix:
const consensusFork {.inject, used.} = ConsensusFork.Bellatrix
template forkyBlck: untyped {.inject, used.} = x.bellatrixData
body
of ConsensusFork.Altair:
const consensusFork {.inject, used.} = ConsensusFork.Altair
template forkyBlck: untyped {.inject, used.} = x.altairData
body
of ConsensusFork.Phase0:
const consensusFork {.inject, used.} = ConsensusFork.Phase0
template forkyBlck: untyped {.inject, used.} = x.phase0Data
body
func init*(T: type ForkedSignedBeaconBlock, func init*(T: type ForkedSignedBeaconBlock,
contents: RestPublishedSignedBlockContents): T = contents: RestPublishedSignedBlockContents): T =
return return