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..d6c62b20de 100644 --- a/beacon_chain/rpc/rest_validator_api.nim +++ b/beacon_chain/rpc/rest_validator_api.nim @@ -890,6 +890,48 @@ 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: + + if contentBody.isNone(): + return RestApiResponse.jsonError(Http400, EmptyRequestBodyError) + + let + headerVersion = request.headers.getString("Eth-Consensus-Version") + consensusVersion = ConsensusFork.init(headerVersion) + if consensusVersion.isNone(): + return RestApiResponse.jsonError(Http400, FailedToObtainConsensusForkError) + + 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: + 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