From 22131b90f89ac59e99ea820303a1451114ac593f Mon Sep 17 00:00:00 2001 From: Gabriel Fukushima Date: Thu, 25 Jul 2024 15:25:19 +1000 Subject: [PATCH] Add GetAttesterSlashingV2 (#8466) * Add initial endpoint with minimal implementation Signed-off-by: Gabriel Fukushima * throw not implemented in request handler Signed-off-by: Gabriel Fukushima * added 200 test for phase0 Signed-off-by: Gabriel Fukushima --------- Signed-off-by: Gabriel Fukushima --- ...eth_v2_beacon_pool_attester_slashings.json | 40 +++++++++ .../GetPoolAttesterSlashingsV2Response.json | 29 +++++++ .../JsonTypeDefinitionBeaconRestApi.java | 2 + .../v2/beacon/GetAttesterSlashingsV2.java | 83 +++++++++++++++++++ .../v2/beacon/GetAttesterSlashingsV2Test.java | 66 +++++++++++++++ .../v2/beacon/getAttesterSlashings.json | 1 + 6 files changed, 221 insertions(+) create mode 100644 data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/paths/_eth_v2_beacon_pool_attester_slashings.json create mode 100644 data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/schema/GetPoolAttesterSlashingsV2Response.json create mode 100644 data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v2/beacon/GetAttesterSlashingsV2.java create mode 100644 data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v2/beacon/GetAttesterSlashingsV2Test.java create mode 100644 data/beaconrestapi/src/test/resources/tech/pegasys/teku/beaconrestapi/handlers/v2/beacon/getAttesterSlashings.json diff --git a/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/paths/_eth_v2_beacon_pool_attester_slashings.json b/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/paths/_eth_v2_beacon_pool_attester_slashings.json new file mode 100644 index 00000000000..f9b856f5326 --- /dev/null +++ b/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/paths/_eth_v2_beacon_pool_attester_slashings.json @@ -0,0 +1,40 @@ +{ + "get" : { + "tags" : [ "Beacon" ], + "operationId" : "getPoolAttesterSlashingsV2", + "summary" : "Get AttesterSlashings from operations pool", + "description" : "Retrieves attester slashings known by the node but not necessarily incorporated into any block.", + "responses" : { + "200" : { + "description" : "Request successful", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/GetPoolAttesterSlashingsV2Response" + } + } + } + }, + "400" : { + "description" : "The request could not be processed, check the response for more information.", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/HttpErrorResponse" + } + } + } + }, + "500" : { + "description" : "Internal server error", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/HttpErrorResponse" + } + } + } + } + } + } +} \ No newline at end of file diff --git a/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/schema/GetPoolAttesterSlashingsV2Response.json b/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/schema/GetPoolAttesterSlashingsV2Response.json new file mode 100644 index 00000000000..f7101bdc4fd --- /dev/null +++ b/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/schema/GetPoolAttesterSlashingsV2Response.json @@ -0,0 +1,29 @@ +{ + "title" : "GetPoolAttesterSlashingsV2Response", + "type" : "object", + "required" : [ "version", "data" ], + "properties" : { + "version": { + "type": "string", + "enum": [ + "phase0", + "altair", + "bellatrix", + "capella", + "deneb", + "electra" + ] + }, + "data": { + "type": "object", + "oneOf": [ + { + "type": "array", + "items": { + "$ref": "#/components/schemas/AttesterSlashing" + } + } + ] + } + } +} \ No newline at end of file diff --git a/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/JsonTypeDefinitionBeaconRestApi.java b/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/JsonTypeDefinitionBeaconRestApi.java index 7ef4d86beb3..bbf8abaf299 100644 --- a/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/JsonTypeDefinitionBeaconRestApi.java +++ b/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/JsonTypeDefinitionBeaconRestApi.java @@ -101,6 +101,7 @@ import tech.pegasys.teku.beaconrestapi.handlers.v1.validator.PostSyncCommitteeSubscriptions; import tech.pegasys.teku.beaconrestapi.handlers.v1.validator.PostSyncDuties; import tech.pegasys.teku.beaconrestapi.handlers.v1.validator.PostValidatorLiveness; +import tech.pegasys.teku.beaconrestapi.handlers.v2.beacon.GetAttesterSlashingsV2; import tech.pegasys.teku.beaconrestapi.handlers.v2.beacon.GetBlock; import tech.pegasys.teku.beaconrestapi.handlers.v2.beacon.GetBlockAttestationsV2; import tech.pegasys.teku.beaconrestapi.handlers.v2.beacon.PostBlindedBlockV2; @@ -237,6 +238,7 @@ private static RestApi create( .endpoint(new GetAttestations(dataProvider, spec)) .endpoint(new PostAttestation(dataProvider, schemaCache)) .endpoint(new GetAttesterSlashings(dataProvider, spec)) + .endpoint(new GetAttesterSlashingsV2(dataProvider, schemaCache)) .endpoint(new PostAttesterSlashing(dataProvider, spec)) .endpoint(new GetProposerSlashings(dataProvider)) .endpoint(new PostProposerSlashing(dataProvider)) diff --git a/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v2/beacon/GetAttesterSlashingsV2.java b/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v2/beacon/GetAttesterSlashingsV2.java new file mode 100644 index 00000000000..83b0a897831 --- /dev/null +++ b/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v2/beacon/GetAttesterSlashingsV2.java @@ -0,0 +1,83 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.beaconrestapi.handlers.v2.beacon; + +import static tech.pegasys.teku.beaconrestapi.handlers.tekuv1.beacon.GetAllBlocksAtSlot.getResponseType; +import static tech.pegasys.teku.ethereum.json.types.EthereumTypes.MILESTONE_TYPE; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_OK; +import static tech.pegasys.teku.infrastructure.http.RestApiConstants.TAG_BEACON; +import static tech.pegasys.teku.infrastructure.json.types.SerializableTypeDefinition.listOf; + +import com.fasterxml.jackson.core.JsonProcessingException; +import java.util.List; +import org.apache.commons.lang3.NotImplementedException; +import tech.pegasys.teku.api.DataProvider; +import tech.pegasys.teku.api.NodeDataProvider; +import tech.pegasys.teku.infrastructure.json.types.SerializableOneOfTypeDefinition; +import tech.pegasys.teku.infrastructure.json.types.SerializableOneOfTypeDefinitionBuilder; +import tech.pegasys.teku.infrastructure.json.types.SerializableTypeDefinition; +import tech.pegasys.teku.infrastructure.restapi.endpoints.EndpointMetadata; +import tech.pegasys.teku.infrastructure.restapi.endpoints.RestApiEndpoint; +import tech.pegasys.teku.infrastructure.restapi.endpoints.RestApiRequest; +import tech.pegasys.teku.spec.SpecMilestone; +import tech.pegasys.teku.spec.datastructures.metadata.ObjectAndMetaData; +import tech.pegasys.teku.spec.datastructures.operations.AttesterSlashing; +import tech.pegasys.teku.spec.schemas.SchemaDefinitionCache; + +public class GetAttesterSlashingsV2 extends RestApiEndpoint { + public static final String ROUTE = "/eth/v2/beacon/pool/attester_slashings"; + + public GetAttesterSlashingsV2( + final DataProvider dataProvider, final SchemaDefinitionCache schemaDefinitionCache) { + this(dataProvider.getNodeDataProvider(), schemaDefinitionCache); + } + + GetAttesterSlashingsV2( + final NodeDataProvider provider, final SchemaDefinitionCache schemaDefinitionCache) { + super( + EndpointMetadata.get(ROUTE) + .operationId("getPoolAttesterSlashingsV2") + .summary("Get AttesterSlashings from operations pool") + .description( + "Retrieves attester slashings known by the node but not necessarily incorporated into any block.") + .tags(TAG_BEACON) + .response(SC_OK, "Request successful", getResponseType(schemaDefinitionCache)) + .build()); + } + + @Override + public void handleRequest(final RestApiRequest request) throws JsonProcessingException { + throw new NotImplementedException("Not implemented"); + } + + private static SerializableTypeDefinition>> + getResponseType(final SchemaDefinitionCache schemaDefinitionCache) { + + final AttesterSlashing.AttesterSlashingSchema attesterSlashingSchema = + schemaDefinitionCache + .getSchemaDefinition(SpecMilestone.ELECTRA) + .getAttesterSlashingSchema(); + + final SerializableOneOfTypeDefinition> oneOfTypeDefinition = + new SerializableOneOfTypeDefinitionBuilder>() + .withType(__ -> true, listOf(attesterSlashingSchema.getJsonTypeDefinition())) + .build(); + + return SerializableTypeDefinition.>>object() + .name("GetPoolAttesterSlashingsV2Response") + .withField("version", MILESTONE_TYPE, ObjectAndMetaData::getMilestone) + .withField("data", oneOfTypeDefinition, ObjectAndMetaData::getData) + .build(); + } +} diff --git a/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v2/beacon/GetAttesterSlashingsV2Test.java b/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v2/beacon/GetAttesterSlashingsV2Test.java new file mode 100644 index 00000000000..4a9faa1526e --- /dev/null +++ b/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v2/beacon/GetAttesterSlashingsV2Test.java @@ -0,0 +1,66 @@ +/* + * Copyright Consensys Software Inc., 2022 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.beaconrestapi.handlers.v2.beacon; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_BAD_REQUEST; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_INTERNAL_SERVER_ERROR; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_OK; +import static tech.pegasys.teku.infrastructure.restapi.MetadataTestUtil.getResponseStringFromMetadata; +import static tech.pegasys.teku.infrastructure.restapi.MetadataTestUtil.verifyMetadataErrorResponse; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.google.common.io.Resources; +import java.io.IOException; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import tech.pegasys.teku.beaconrestapi.AbstractMigratedBeaconHandlerTest; +import tech.pegasys.teku.spec.datastructures.metadata.ObjectAndMetaData; +import tech.pegasys.teku.spec.datastructures.operations.AttesterSlashing; + +class GetAttesterSlashingsV2Test extends AbstractMigratedBeaconHandlerTest { + + @BeforeEach + void setUp() { + setHandler(new GetAttesterSlashingsV2(nodeDataProvider, schemaDefinitionCache)); + } + + @Test + void metadata_shouldHandle200_phase0() throws IOException { + final ObjectAndMetaData> responseData = + withMetaData( + List.of( + dataStructureUtil.randomAttesterSlashing(), + dataStructureUtil.randomAttesterSlashing())); + + final String data = getResponseStringFromMetadata(handler, SC_OK, responseData); + final String expected = + Resources.toString( + Resources.getResource(GetAttesterSlashingsV2Test.class, "getAttesterSlashings.json"), + UTF_8); + assertThat(data).isEqualTo(expected); + } + + @Test + void metadata_shouldHandle400() throws JsonProcessingException { + verifyMetadataErrorResponse(handler, SC_BAD_REQUEST); + } + + @Test + void metadata_shouldHandle500() throws JsonProcessingException { + verifyMetadataErrorResponse(handler, SC_INTERNAL_SERVER_ERROR); + } +} diff --git a/data/beaconrestapi/src/test/resources/tech/pegasys/teku/beaconrestapi/handlers/v2/beacon/getAttesterSlashings.json b/data/beaconrestapi/src/test/resources/tech/pegasys/teku/beaconrestapi/handlers/v2/beacon/getAttesterSlashings.json new file mode 100644 index 00000000000..41a55e72824 --- /dev/null +++ b/data/beaconrestapi/src/test/resources/tech/pegasys/teku/beaconrestapi/handlers/v2/beacon/getAttesterSlashings.json @@ -0,0 +1 @@ +{"version":"phase0","data":[{"attestation_1":{"attesting_indices":["4666673844721362956","4665021361504678828","4669978815449698508"],"data":{"slot":"4668326327938047084","index":"4660063907559659148","beacon_block_root":"0x8200a6402ca295554fb9562193cc71d60272d63beeaf2201fdf53e846e77f919","source":{"epoch":"542887588","root":"0x5cbeb140ec0ad7cb653388caecba483cf66bd817821ed18ca1f3b7f3b9b58a04"},"target":{"epoch":"535577359","root":"0x32a7d23faa44fc04cc23dc3b560a55ade3deb2c393e9de2e6d20bdad2416c39b"}},"signature":"0x992e2695a49aaedcb373280f375a08adaafafff0bab131d48674136f5e452c8bb0797618eeb99bc3a4835bca2bd6aec6067807e927604548997a795d7ba982a5274f0d1d55624a8c7b66973c6e717f3c46bd2d92bc1696d3173751a6b0bf6a63"},"attestation_2":{"attesting_indices":["4666673844721362956","4665021361504678828","4669978815449698508"],"data":{"slot":"4602226973500878187","index":"4593964548827522954","beacon_block_root":"0x7e2bbb3f2a737918a12f79e9a52da7e1fceaae0b6c0c82172425cbce8d99a0c6","source":{"epoch":"535192610","root":"0x58e9c63feadbba8eb6a9aa92fd1b7e47efe4b0e7ff7a30a3c822443ed8d731b1"},"target":{"epoch":"534038364","root":"0xcbafa33faaa1f62b763b1697f350f91515f7aa53462f2500db29d9eff71c7ef1"}},"signature":"0x9776d892cbc6c914554d0153158c9a7c72164e9f60d3fe5816bdaf08a9bf3ca67d77a9c1d6431ba3294ec9032424322b0ab9e9a58fb0b9d8de93946ff414d2bef1f58da9f4a9b1e585c57571a6c8c8c2c0aa1c574939b7acd228d3f35d7b6e6e"}},{"attestation_1":{"attesting_indices":["4589007099177470570","4580744678799082634","4579092195582398506"],"data":{"slot":"4584049649527418186","index":"4582397162015766762","beacon_block_root":"0xed7436400b3f287283b1005a48f4f70e79abc311779529d2628c4161a3a79565","source":{"epoch":"538462976","root":"0xc7324240cba769e8982b3203a1e2ce746ca5c5ed0a04d85d078abad0efe52650"},"target":{"epoch":"538847725","root":"0x3af91e408b6da58558bd9d0797174a4392b7bf5950b8ccba1a914f820d2b7390"}},"signature":"0x88a276eb43fd6674df0c66f4a2d988eb33b7d1dd992b71ccc4a6a8202cd12533828bc067f6b424fc554ed97bf16202bd0e4a9e9ba9bcde870fe7a51ae3351e2f63999138f8bc8ef315b0e168beda213ce3cbb7776026257c65b88fe28f00318f"},"attestation_2":{"attesting_indices":["4589007099177470570","4580744678799082634","4579092195582398506"],"data":{"slot":"4623709263907706443","index":"4622056780691022315","beacon_block_root":"0x867d07400b9c22992dc93ab5e53a9c77abc3bba12adb6fa3d1955da376ae50bb","source":{"epoch":"536923980","root":"0x603b1340cb04640f42436c5e3e2973dd9ebdbd7dbd491e2f7593d612c2ece1a5"},"target":{"epoch":"537308729","root":"0xd301f03f8bca9fac02d5d762345eeeabc4cfb7e903fe128c889a6bc4e0312ee6"}},"signature":"0xaa6e7c4619474f9b282e9f9bacf70496bee8b8fc79bb139ce047ffe273b1198bd34d35a9e42aab7ea1650b777218eaa706d3b1f017fff3be70a00851ad131c8877550e53ab01fd4850f5546664d1696c122a92ba49e68da2656ebcf43a82078b"}}]} \ No newline at end of file