From a1d3b0705d6285563a318760f4ef8a3ec3cb947b Mon Sep 17 00:00:00 2001 From: Pedro Miranda Date: Thu, 12 Sep 2024 18:07:22 +0100 Subject: [PATCH 1/3] added new endpoint version(v2) for validator aggregate and proof --- beacon_chain/networking/eth2_network.nim | 3 +- beacon_chain/rpc/rest_validator_api.nim | 60 +++++++++++++++++++ .../eth2_apis/eth2_rest_serialization.nim | 2 + .../spec/eth2_apis/rest_validator_calls.nim | 7 +++ beacon_chain/validators/message_router.nim | 3 +- 5 files changed, 73 insertions(+), 2 deletions(-) diff --git a/beacon_chain/networking/eth2_network.nim b/beacon_chain/networking/eth2_network.nim index 84b7060aca..45615514f2 100644 --- a/beacon_chain/networking/eth2_network.nim +++ b/beacon_chain/networking/eth2_network.nim @@ -2648,7 +2648,8 @@ proc broadcastBlsToExecutionChange*( node.broadcast(topic, bls_to_execution_change) proc broadcastAggregateAndProof*( - node: Eth2Node, proof: phase0.SignedAggregateAndProof): + node: Eth2Node, + proof: phase0.SignedAggregateAndProof | electra.SignedAggregateAndProof): Future[SendResult] {.async: (raises: [CancelledError], raw: true).} = let topic = getAggregateAndProofsTopic( node.forkDigestAtEpoch(node.getWallEpoch)) diff --git a/beacon_chain/rpc/rest_validator_api.nim b/beacon_chain/rpc/rest_validator_api.nim index c7e6966f0c..b3935b327c 100644 --- a/beacon_chain/rpc/rest_validator_api.nim +++ b/beacon_chain/rpc/rest_validator_api.nim @@ -890,6 +890,66 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) = "Unexpected server failure, while sending aggregate and proof") RestApiResponse.jsonMsgResponse(AggregateAndProofValidationSuccess) + # https://ethereum.github.io/beacon-APIs/?urls.primaryName=dev#/Validator/publishAggregateAndProofsV2 + router.api2(MethodPost, "/eth/v2/validator/aggregate_and_proofs") do ( + contentBody: Option[ContentBody]) -> RestApiResponse: + + type + MultiForkProof = object + case isElectra: bool + of false: + phase0Proofs: seq[phase0.SignedAggregateAndProof] + of true: + electraProofs: seq[electra.SignedAggregateAndProof] + + let + consensusVersion = request.headers.getString("Eth-Consensus-Version") + isElectra = consensusVersion == "electra" + + if contentBody.isNone(): + return RestApiResponse.jsonError(Http400, EmptyRequestBodyError) + + let proofs = + block: + if isElectra: + let dres = decodeBody(seq[electra.SignedAggregateAndProof], contentBody.get()) + if dres.isErr(): + return RestApiResponse.jsonError(Http400, + InvalidAggregateAndProofObjectError, + $dres.error()) + MultiForkProof(isElectra: true, electraProofs: dres.get()) + else: + let dres = decodeBody(seq[phase0.SignedAggregateAndProof], contentBody.get()) + if dres.isErr(): + return RestApiResponse.jsonError(Http400, + InvalidAggregateAndProofObjectError, + $dres.error()) + MultiForkProof(isElectra: false, phase0Proofs: dres.get()) + + let pending = + block: + var res: seq[Future[SendResult]] + if proofs.isElectra: + for proof in proofs.electraProofs: + res.add(node.router.routeSignedAggregateAndProof(proof)) + else: + for proof in proofs.phase0Proofs: + res.add(node.router.routeSignedAggregateAndProof(proof)) + + res + await allFutures(pending) + for future in pending: + if future.completed(): + let res = future.value() + if res.isErr(): + return RestApiResponse.jsonError(Http400, + AggregateAndProofValidationError, + $res.error()) + else: + return RestApiResponse.jsonError(Http500, + "Unexpected server failure, while sending aggregate and proof") + RestApiResponse.jsonMsgResponse(AggregateAndProofValidationSuccess) + # https://ethereum.github.io/beacon-APIs/#/Validator/prepareBeaconCommitteeSubnet router.api2(MethodPost, "/eth/v1/validator/beacon_committee_subscriptions") do ( diff --git a/beacon_chain/spec/eth2_apis/eth2_rest_serialization.nim b/beacon_chain/spec/eth2_apis/eth2_rest_serialization.nim index 9433938dfe..213a133f6c 100644 --- a/beacon_chain/spec/eth2_apis/eth2_rest_serialization.nim +++ b/beacon_chain/spec/eth2_apis/eth2_rest_serialization.nim @@ -243,6 +243,7 @@ RestJson.useDefaultSerializationFor( deneb_mev.ExecutionPayloadAndBlobsBundle, deneb_mev.SignedBlindedBeaconBlock, deneb_mev.SignedBuilderBid, + electra.AggregateAndProof, electra.Attestation, electra.AttesterSlashing, electra.BeaconBlock, @@ -257,6 +258,7 @@ RestJson.useDefaultSerializationFor( electra.LightClientHeader, electra.LightClientOptimisticUpdate, electra.LightClientUpdate, + electra.SignedAggregateAndProof, electra.SignedBeaconBlock, electra.TrustedAttestation, electra_mev.BlindedBeaconBlock, diff --git a/beacon_chain/spec/eth2_apis/rest_validator_calls.nim b/beacon_chain/spec/eth2_apis/rest_validator_calls.nim index f46d136b24..7ec88a48bb 100644 --- a/beacon_chain/spec/eth2_apis/rest_validator_calls.nim +++ b/beacon_chain/spec/eth2_apis/rest_validator_calls.nim @@ -87,6 +87,13 @@ proc publishAggregateAndProofs*( meth: MethodPost.} ## https://ethereum.github.io/beacon-APIs/#/Validator/publishAggregateAndProofs +proc publishAggregateAndProofsV2*( + body: seq[phase0.SignedAggregateAndProof | electra.SignedAggregateAndProof] + ): RestPlainResponse {. + rest, endpoint: "/eth/v2/validator/aggregate_and_proofs", + meth: MethodPost.} + ## https://ethereum.github.io/beacon-APIs/?urls.primaryName=dev#/Validator/publishAggregateAndProofsV2 + proc prepareBeaconCommitteeSubnet*( body: seq[RestCommitteeSubscription] ): RestPlainResponse {. diff --git a/beacon_chain/validators/message_router.nim b/beacon_chain/validators/message_router.nim index 2ebd2e65ab..a96d865e13 100644 --- a/beacon_chain/validators/message_router.nim +++ b/beacon_chain/validators/message_router.nim @@ -264,7 +264,8 @@ proc routeAttestation*( attestation, subnet_id, checkSignature = true, checkValidator = true) proc routeSignedAggregateAndProof*( - router: ref MessageRouter, proof: phase0.SignedAggregateAndProof, + router: ref MessageRouter, + proof: phase0.SignedAggregateAndProof | electra.SignedAggregateAndProof, checkSignature = true): Future[SendResult] {.async: (raises: [CancelledError]).} = ## Validate and broadcast aggregate From f9bd4ef5f7184a9fa43e1cb0a6a1115b5a3fc019 Mon Sep 17 00:00:00 2001 From: Pedro Miranda Date: Fri, 13 Sep 2024 09:36:40 +0100 Subject: [PATCH 2/3] review improvements --- beacon_chain/rpc/rest_validator_api.nim | 55 +++++++++---------------- 1 file changed, 19 insertions(+), 36 deletions(-) diff --git a/beacon_chain/rpc/rest_validator_api.nim b/beacon_chain/rpc/rest_validator_api.nim index b3935b327c..7c7390effb 100644 --- a/beacon_chain/rpc/rest_validator_api.nim +++ b/beacon_chain/rpc/rest_validator_api.nim @@ -894,14 +894,6 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) = router.api2(MethodPost, "/eth/v2/validator/aggregate_and_proofs") do ( contentBody: Option[ContentBody]) -> RestApiResponse: - type - MultiForkProof = object - case isElectra: bool - of false: - phase0Proofs: seq[phase0.SignedAggregateAndProof] - of true: - electraProofs: seq[electra.SignedAggregateAndProof] - let consensusVersion = request.headers.getString("Eth-Consensus-Version") isElectra = consensusVersion == "electra" @@ -909,36 +901,27 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) = if contentBody.isNone(): return RestApiResponse.jsonError(Http400, EmptyRequestBodyError) - let proofs = - block: - if isElectra: - let dres = decodeBody(seq[electra.SignedAggregateAndProof], contentBody.get()) - if dres.isErr(): - return RestApiResponse.jsonError(Http400, - InvalidAggregateAndProofObjectError, - $dres.error()) - MultiForkProof(isElectra: true, electraProofs: dres.get()) - else: - let dres = decodeBody(seq[phase0.SignedAggregateAndProof], contentBody.get()) - if dres.isErr(): - return RestApiResponse.jsonError(Http400, - InvalidAggregateAndProofObjectError, - $dres.error()) - MultiForkProof(isElectra: false, phase0Proofs: dres.get()) + var proofs: seq[Future[SendResult]] + if isElectra: + let dres = decodeBody(seq[electra.SignedAggregateAndProof], contentBody.get()) + if dres.isErr(): + return RestApiResponse.jsonError(Http400, + InvalidAggregateAndProofObjectError, + $dres.error()) + for proof in dres.get(): + proofs.add(node.router.routeSignedAggregateAndProof(proof)) - let pending = - block: - var res: seq[Future[SendResult]] - if proofs.isElectra: - for proof in proofs.electraProofs: - res.add(node.router.routeSignedAggregateAndProof(proof)) - else: - for proof in proofs.phase0Proofs: - res.add(node.router.routeSignedAggregateAndProof(proof)) + else: + let dres = decodeBody(seq[phase0.SignedAggregateAndProof], contentBody.get()) + if dres.isErr(): + return RestApiResponse.jsonError(Http400, + InvalidAggregateAndProofObjectError, + $dres.error()) + for proof in dres.get(): + proofs.add(node.router.routeSignedAggregateAndProof(proof)) - res - await allFutures(pending) - for future in pending: + await allFutures(proofs) + for future in proofs: if future.completed(): let res = future.value() if res.isErr(): From e48df14ead6cc6b887762c52d6c3578547e62dea Mon Sep 17 00:00:00 2001 From: Pedro Miranda Date: Fri, 13 Sep 2024 18:59:14 +0100 Subject: [PATCH 3/3] introduced nim template for proof executiion --- beacon_chain/rpc/rest_validator_api.nim | 41 ++++++++++++------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/beacon_chain/rpc/rest_validator_api.nim b/beacon_chain/rpc/rest_validator_api.nim index 7c7390effb..d6c62b20de 100644 --- a/beacon_chain/rpc/rest_validator_api.nim +++ b/beacon_chain/rpc/rest_validator_api.nim @@ -894,31 +894,30 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) = router.api2(MethodPost, "/eth/v2/validator/aggregate_and_proofs") do ( contentBody: Option[ContentBody]) -> RestApiResponse: - let - consensusVersion = request.headers.getString("Eth-Consensus-Version") - isElectra = consensusVersion == "electra" - if contentBody.isNone(): return RestApiResponse.jsonError(Http400, EmptyRequestBodyError) - var proofs: seq[Future[SendResult]] - if isElectra: - let dres = decodeBody(seq[electra.SignedAggregateAndProof], contentBody.get()) - if dres.isErr(): - return RestApiResponse.jsonError(Http400, - InvalidAggregateAndProofObjectError, - $dres.error()) - for proof in dres.get(): - proofs.add(node.router.routeSignedAggregateAndProof(proof)) + let + headerVersion = request.headers.getString("Eth-Consensus-Version") + consensusVersion = ConsensusFork.init(headerVersion) + if consensusVersion.isNone(): + return RestApiResponse.jsonError(Http400, FailedToObtainConsensusForkError) - else: - let dres = decodeBody(seq[phase0.SignedAggregateAndProof], contentBody.get()) - if dres.isErr(): - return RestApiResponse.jsonError(Http400, - InvalidAggregateAndProofObjectError, - $dres.error()) - for proof in dres.get(): - proofs.add(node.router.routeSignedAggregateAndProof(proof)) + var proofs: seq[Future[SendResult]] + template addDecodedProofs(ProofType: untyped) = + let dres = decodeBody(seq[ProofType], contentBody.get()) + if dres.isErr(): + return RestApiResponse.jsonError(Http400, + InvalidAggregateAndProofObjectError, + $dres.error()) + for proof in dres.get(): + proofs.add(node.router.routeSignedAggregateAndProof(proof)) + + case consensusVersion.get(): + of ConsensusFork.Phase0 .. ConsensusFork.Deneb: + addDecodedProofs(phase0.SignedAggregateAndProof) + of ConsensusFork.Electra: + addDecodedProofs(electra.SignedAggregateAndProof) await allFutures(proofs) for future in proofs: