diff --git a/data/beaconrestapi/src/integration-test/java/tech/pegasys/teku/beaconrestapi/v1/validator/PostBlindedAndUnblindedBlockTest.java b/data/beaconrestapi/src/integration-test/java/tech/pegasys/teku/beaconrestapi/beacon/PostBlindedAndUnblindedBlockTest.java similarity index 82% rename from data/beaconrestapi/src/integration-test/java/tech/pegasys/teku/beaconrestapi/v1/validator/PostBlindedAndUnblindedBlockTest.java rename to data/beaconrestapi/src/integration-test/java/tech/pegasys/teku/beaconrestapi/beacon/PostBlindedAndUnblindedBlockTest.java index 27a1fdc00ff..e8609905565 100644 --- a/data/beaconrestapi/src/integration-test/java/tech/pegasys/teku/beaconrestapi/v1/validator/PostBlindedAndUnblindedBlockTest.java +++ b/data/beaconrestapi/src/integration-test/java/tech/pegasys/teku/beaconrestapi/beacon/PostBlindedAndUnblindedBlockTest.java @@ -11,12 +11,12 @@ * specific language governing permissions and limitations under the License. */ -package tech.pegasys.teku.beaconrestapi.v1.validator; +package tech.pegasys.teku.beaconrestapi.beacon; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.when; -import static tech.pegasys.teku.beaconrestapi.v1.validator.PostBlindedAndUnblindedBlockTest.Version.V1; -import static tech.pegasys.teku.beaconrestapi.v1.validator.PostBlindedAndUnblindedBlockTest.Version.V2; +import static tech.pegasys.teku.beaconrestapi.beacon.PostBlindedAndUnblindedBlockTest.Version.V1; +import static tech.pegasys.teku.beaconrestapi.beacon.PostBlindedAndUnblindedBlockTest.Version.V2; import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_OK; import java.io.IOException; @@ -58,22 +58,30 @@ public static Stream postBlockCases() { .flatMap( route -> Stream.of( - // route, useSsz - Arguments.of(route, false), Arguments.of(route, true))) + // route, useSsz, set consensus header + Arguments.of(route, false, true), + Arguments.of(route, false, false), + Arguments.of(route, true, false), + Arguments.of(route, true, true))) .map( args -> { final String route = (String) args.get()[0]; final boolean isBlindedBlock = route.contains("blinded"); final Version version = route.contains("/v2/") ? V2 : V1; final boolean useSsz = (boolean) args.get()[1]; - return Arguments.of(version, isBlindedBlock, route, useSsz); + final boolean setConsensusHeader = (boolean) args.get()[2]; + return Arguments.of(version, isBlindedBlock, route, useSsz, setConsensusHeader); }); } - @ParameterizedTest(name = "version:{0}_blinded:{1}_ssz:{3}") + @ParameterizedTest(name = "version:{0}_blinded:{1}_ssz:{3}_setConsensusHeader:{4}") @MethodSource("postBlockCases") void preDeneb( - final Version version, final boolean isBlindedBlock, final String route, final boolean useSsz) + final Version version, + final boolean isBlindedBlock, + final String route, + final boolean useSsz, + final boolean setConsensusHeader) throws IOException { startRestAPIAtGenesis(SpecMilestone.BELLATRIX); @@ -96,21 +104,20 @@ void preDeneb( prepareResponse(request, version); - postRequestAndAssert( - route, - request, - signedBeaconBlockSchema, - Optional.of(SpecMilestone.BELLATRIX.name()), - useSsz, - version); - postRequestAndAssert( - route, request, signedBeaconBlockSchema, Optional.empty(), useSsz, version); + final Optional consensusHeader = + setConsensusHeader ? Optional.of(SpecMilestone.BELLATRIX.name()) : Optional.empty(); + + postRequestAndAssert(route, request, signedBeaconBlockSchema, consensusHeader, useSsz, version); } - @ParameterizedTest(name = "version:{0}_blinded:{1}_ssz:{3}") + @ParameterizedTest(name = "version:{0}_blinded:{1}_ssz:{3}_setConsensusHeader:{4}") @MethodSource("postBlockCases") void postDeneb( - final Version version, final boolean isBlindedBlock, final String route, final boolean useSsz) + final Version version, + final boolean isBlindedBlock, + final String route, + final boolean useSsz, + final boolean setConsensusHeader) throws IOException { startRestAPIAtGenesis(SpecMilestone.DENEB); dataStructureUtil = new DataStructureUtil(spec); @@ -132,15 +139,11 @@ void postDeneb( prepareResponse(request, version); + final Optional consensusHeader = + setConsensusHeader ? Optional.of(SpecMilestone.DENEB.name()) : Optional.empty(); + postRequestAndAssert( - route, - request, - signedBlockContainerSchema, - Optional.of(SpecMilestone.DENEB.name()), - useSsz, - version); - postRequestAndAssert( - route, request, signedBlockContainerSchema, Optional.empty(), useSsz, version); + route, request, signedBlockContainerSchema, consensusHeader, useSsz, version); } private void prepareResponse(final SignedBeaconBlock request, final Version version) { diff --git a/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/paths/_eth_v2_beacon_blinded_blocks.json b/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/paths/_eth_v2_beacon_blinded_blocks.json index 0d3ab2a43dd..e67b63bc5d2 100644 --- a/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/paths/_eth_v2_beacon_blinded_blocks.json +++ b/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/paths/_eth_v2_beacon_blinded_blocks.json @@ -83,7 +83,7 @@ } }, "503" : { - "description" : "Beacon node is currently syncing.", + "description" : "Beacon node is currently syncing and not serving requests", "content" : { "application/json" : { "schema" : { diff --git a/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/paths/_eth_v2_beacon_blocks.json b/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/paths/_eth_v2_beacon_blocks.json index 998d4331504..91bea9a6f03 100644 --- a/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/paths/_eth_v2_beacon_blocks.json +++ b/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/paths/_eth_v2_beacon_blocks.json @@ -83,7 +83,7 @@ } }, "503" : { - "description" : "Beacon node is currently syncing.", + "description" : "Beacon node is currently syncing and not serving requests", "content" : { "application/json" : { "schema" : { diff --git a/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v2/beacon/PostBlindedBlockV2.java b/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v2/beacon/PostBlindedBlockV2.java index 77c5de04450..78759d28646 100644 --- a/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v2/beacon/PostBlindedBlockV2.java +++ b/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v2/beacon/PostBlindedBlockV2.java @@ -21,6 +21,7 @@ import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_NO_CONTENT; import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_OK; import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_SERVICE_UNAVAILABLE; +import static tech.pegasys.teku.infrastructure.http.RestApiConstants.SERVICE_UNAVAILABLE; import static tech.pegasys.teku.infrastructure.http.RestApiConstants.TAG_BEACON; import static tech.pegasys.teku.infrastructure.http.RestApiConstants.TAG_VALIDATOR_REQUIRED; import static tech.pegasys.teku.infrastructure.json.types.CoreTypes.HTTP_ERROR_RESPONSE_TYPE; @@ -64,7 +65,7 @@ public PostBlindedBlockV2( @Override public void handleRequest(final RestApiRequest request) throws JsonProcessingException { if (syncDataProvider.isSyncing()) { - request.respondError(SC_SERVICE_UNAVAILABLE, "Beacon node is currently syncing."); + request.respondError(SC_SERVICE_UNAVAILABLE, SERVICE_UNAVAILABLE); return; } @@ -127,8 +128,7 @@ broadcast but a different status code is returned (202). Pre-Bellatrix, this end SC_ACCEPTED, "Block has been successfully broadcast, but failed validation and has not been imported.") .withBadRequestResponse(Optional.of("Unable to parse request body.")) - .response( - SC_SERVICE_UNAVAILABLE, "Beacon node is currently syncing.", HTTP_ERROR_RESPONSE_TYPE) + .response(SC_SERVICE_UNAVAILABLE, SERVICE_UNAVAILABLE, HTTP_ERROR_RESPONSE_TYPE) .response( SC_NO_CONTENT, "Data is unavailable because the chain has not yet reached genesis") .build(); diff --git a/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v2/beacon/PostBlockV2.java b/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v2/beacon/PostBlockV2.java index 3dec9966d6c..4b9369bda15 100644 --- a/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v2/beacon/PostBlockV2.java +++ b/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v2/beacon/PostBlockV2.java @@ -127,8 +127,7 @@ validation, a separate success response code (202) is used to indicate that the SC_ACCEPTED, "Block has been successfully broadcast, but failed validation and has not been imported.") .withBadRequestResponse(Optional.of("Unable to parse request body.")) - .response( - SC_SERVICE_UNAVAILABLE, "Beacon node is currently syncing.", HTTP_ERROR_RESPONSE_TYPE) + .response(SC_SERVICE_UNAVAILABLE, SERVICE_UNAVAILABLE, HTTP_ERROR_RESPONSE_TYPE) .response( SC_NO_CONTENT, "Data is unavailable because the chain has not yet reached genesis") .build(); diff --git a/validator/remote/src/main/java/tech/pegasys/teku/validator/remote/apiclient/ValidatorApiMethod.java b/validator/remote/src/main/java/tech/pegasys/teku/validator/remote/apiclient/ValidatorApiMethod.java index fd314926817..06464c87e46 100644 --- a/validator/remote/src/main/java/tech/pegasys/teku/validator/remote/apiclient/ValidatorApiMethod.java +++ b/validator/remote/src/main/java/tech/pegasys/teku/validator/remote/apiclient/ValidatorApiMethod.java @@ -22,11 +22,8 @@ public enum ValidatorApiMethod { GET_SYNCING_STATUS("/eth/v1/node/syncing"), GET_GENESIS("eth/v1/beacon/genesis"), GET_VALIDATORS("eth/v1/beacon/states/head/validators"), - GET_DUTIES("validator/duties"), GET_UNSIGNED_BLOCK_V3("eth/v3/validator/blocks/:slot"), - SEND_SIGNED_BLOCK("eth/v1/beacon/blocks"), SEND_SIGNED_BLOCK_V2("eth/v2/beacon/blocks"), - SEND_SIGNED_BLINDED_BLOCK("eth/v1/beacon/blinded_blocks"), SEND_SIGNED_BLINDED_BLOCK_V2("eth/v2/beacon/blinded_blocks"), GET_ATTESTATION_DATA("eth/v1/validator/attestation_data"), SEND_SIGNED_ATTESTATION("eth/v1/beacon/pool/attestations"), diff --git a/validator/remote/src/main/java/tech/pegasys/teku/validator/remote/typedef/handlers/CreateBlockRequest.java b/validator/remote/src/main/java/tech/pegasys/teku/validator/remote/typedef/handlers/CreateBlockRequest.java deleted file mode 100644 index ce9a58228a0..00000000000 --- a/validator/remote/src/main/java/tech/pegasys/teku/validator/remote/typedef/handlers/CreateBlockRequest.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * 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.validator.remote.typedef.handlers; - -import static java.util.Collections.emptyMap; -import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_NOT_FOUND; -import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_OK; -import static tech.pegasys.teku.validator.remote.apiclient.ValidatorApiMethod.GET_UNSIGNED_BLOCK_V3; - -import com.google.common.net.MediaType; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; -import org.apache.tuweni.units.bigints.UInt256; -import tech.pegasys.teku.bls.BLSSignature; -import tech.pegasys.teku.infrastructure.json.JsonUtil; -import tech.pegasys.teku.infrastructure.json.types.DeserializableTypeDefinition; -import tech.pegasys.teku.infrastructure.unsigned.UInt64; -import tech.pegasys.teku.spec.Spec; -import tech.pegasys.teku.spec.SpecMilestone; -import tech.pegasys.teku.spec.datastructures.blocks.BlockContainer; -import tech.pegasys.teku.spec.datastructures.blocks.BlockContainerSchema; -import tech.pegasys.teku.spec.datastructures.metadata.BlockContainerAndMetaData; -import tech.pegasys.teku.validator.remote.apiclient.ValidatorApiMethod; -import tech.pegasys.teku.validator.remote.typedef.BlindedBlockEndpointNotAvailableException; -import tech.pegasys.teku.validator.remote.typedef.ResponseHandler; - -public class CreateBlockRequest extends AbstractTypeDefRequest { - - private static final Logger LOG = LogManager.getLogger(); - - private final UInt64 slot; - private final boolean preferSszBlockEncoding; - private final ValidatorApiMethod apiMethod; - private final BlockContainerSchema blockContainerSchema; - private final DeserializableTypeDefinition getBlockResponseDefinition; - private final ResponseHandler responseHandler; - - public CreateBlockRequest( - final HttpUrl baseEndpoint, - final OkHttpClient okHttpClient, - final Spec spec, - final UInt64 slot, - final boolean blinded, - final boolean preferSszBlockEncoding) { - super(baseEndpoint, okHttpClient); - this.slot = slot; - this.preferSszBlockEncoding = preferSszBlockEncoding; - apiMethod = GET_UNSIGNED_BLOCK_V3; - blockContainerSchema = spec.atSlot(slot).getSchemaDefinitions().getBlockContainerSchema(); - getBlockResponseDefinition = - DeserializableTypeDefinition.object(GetBlockResponse.class) - .initializer(GetBlockResponse::new) - .withField( - "data", - blockContainerSchema.getJsonTypeDefinition(), - GetBlockResponse::getData, - GetBlockResponse::setData) - .withField( - "version", - DeserializableTypeDefinition.enumOf(SpecMilestone.class), - GetBlockResponse::getSpecMilestone, - GetBlockResponse::setSpecMilestone) - .build(); - final ResponseHandler responseHandler = - new ResponseHandler<>(getBlockResponseDefinition) - .withHandler(SC_OK, this::handleBlockContainerResult); - this.responseHandler = - blinded - ? responseHandler.withHandler( - SC_NOT_FOUND, - (__, ___) -> { - throw new BlindedBlockEndpointNotAvailableException(); - }) - : responseHandler; - } - - public Optional submit( - final BLSSignature randaoReveal, final Optional graffiti) { - final Map queryParams = new HashMap<>(); - queryParams.put("randao_reveal", randaoReveal.toString()); - final Map headers = new HashMap<>(); - graffiti.ifPresent(bytes32 -> queryParams.put("graffiti", bytes32.toHexString())); - - if (preferSszBlockEncoding) { - // application/octet-stream is preferred, but will accept application/json - headers.put("Accept", "application/octet-stream;q=0.9, application/json;q=0.4"); - } - return get( - apiMethod, - Map.of("slot", slot.toString()), - queryParams, - emptyMap(), - headers, - responseHandler) - .map( - response -> - new BlockContainerAndMetaData( - response.getData(), response.getSpecMilestone(), UInt256.ZERO, UInt256.ZERO)); - } - - private Optional handleBlockContainerResult( - final Request request, final Response response) { - try { - final String responseContentType = response.header("Content-Type"); - if (responseContentType != null - && MediaType.parse(responseContentType).is(MediaType.OCTET_STREAM)) { - return Optional.of( - new GetBlockResponse( - blockContainerSchema.sszDeserialize(Bytes.of(response.body().bytes())))); - } - return Optional.of(JsonUtil.parse(response.body().string(), getBlockResponseDefinition)); - } catch (final IOException ex) { - LOG.trace("Failed to parse response object creating block", ex); - } - return Optional.empty(); - } - - static class GetBlockResponse { - private BlockContainer data; - private SpecMilestone specMilestone; - - public GetBlockResponse() {} - - public GetBlockResponse(final BlockContainer data) { - this.data = data; - } - - public BlockContainer getData() { - return data; - } - - public void setData(final BlockContainer data) { - this.data = data; - } - - public SpecMilestone getSpecMilestone() { - return specMilestone; - } - - public void setSpecMilestone(final SpecMilestone specMilestone) { - this.specMilestone = specMilestone; - } - } -}