From 8ef3a38676767641f7c221726b357d2b2362485b Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 10 Oct 2024 00:54:06 +0530 Subject: [PATCH 01/12] Standardise the Engine JSON-RPC error codes --- .../web3j/JsonRpcErrorCodes.java | 60 +++++++++++++++++++ .../executionclient/web3j/Web3JClient.java | 34 ++++++++--- 2 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java new file mode 100644 index 00000000000..cc08bcc116e --- /dev/null +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java @@ -0,0 +1,60 @@ +/* + * 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.ethereum.executionclient.web3j; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public final class JsonRpcErrorCodes { + public static final int PARSE_ERROR = -32700; + public static final int INVALID_REQUEST = -32600; + public static final int METHOD_NOT_FOUND = -32601; + public static final int INVALID_PARAMS = -32602; + public static final int INTERNAL_ERROR = -32603; + public static final int SERVER_ERROR_RANGE_START = -32000; + public static final int SERVER_ERROR_RANGE_END = -32099; + + private static final Map ERROR_MESSAGES; + + static { + Map messages = new HashMap<>(); + messages.put(PARSE_ERROR, "Parse error"); + messages.put(INVALID_REQUEST, "Invalid request"); + messages.put(METHOD_NOT_FOUND, "Method not found"); + messages.put(INVALID_PARAMS, "Invalid params"); + messages.put(INTERNAL_ERROR, "Internal error"); + messages.put(SERVER_ERROR_RANGE_START, "Server error"); + ERROR_MESSAGES = Collections.unmodifiableMap(messages); + } + + private JsonRpcErrorCodes() { + // Utility class, do not instantiate + } + + public static String getErrorMessage(final int errorCode) { + if (isServerError(errorCode)) { + return ERROR_MESSAGES.get(SERVER_ERROR_RANGE_START); + } + return ERROR_MESSAGES.getOrDefault(errorCode, "Unknown error"); + } + + public static boolean isServerError(final int errorCode) { + return errorCode >= SERVER_ERROR_RANGE_END && errorCode <= SERVER_ERROR_RANGE_START; + } + + public static boolean isStandardError(final int errorCode) { + return ERROR_MESSAGES.containsKey(errorCode) || isServerError(errorCode); + } +} diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClient.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClient.java index b8cf68f6729..fb7f1e28354 100644 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClient.java +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClient.java @@ -15,7 +15,6 @@ import static tech.pegasys.teku.infrastructure.exceptions.ExceptionUtil.getMessageOrSimpleName; -import java.io.IOException; import java.net.ConnectException; import java.time.Duration; import java.util.Collection; @@ -86,14 +85,9 @@ public SafeFuture> doRequest( (response, exception) -> { final boolean isCriticalRequest = isCriticalRequest(web3jRequest); if (exception != null) { - final boolean couldBeAuthError = isAuthenticationException(exception); - handleError(isCriticalRequest, exception, couldBeAuthError); - return Response.withErrorMessage(getMessageOrSimpleName(exception)); + return handleException(exception, isCriticalRequest); } else if (response.hasError()) { - final String errorMessage = - response.getError().getCode() + ": " + response.getError().getMessage(); - handleError(isCriticalRequest, new IOException(errorMessage), false); - return Response.withErrorMessage(errorMessage); + return handleJsonRpcError(response.getError(), isCriticalRequest); } else { handleSuccess(isCriticalRequest); return new Response<>(response.getResult()); @@ -101,6 +95,30 @@ public SafeFuture> doRequest( }); } + private Response handleException( + final Throwable exception, final boolean isCriticalRequest) { + final boolean couldBeAuthError = isAuthenticationException(exception); + handleError(isCriticalRequest, exception, couldBeAuthError); + return Response.withErrorMessage(getMessageOrSimpleName(exception)); + } + + private Response handleJsonRpcError( + final org.web3j.protocol.core.Response.Error error, final boolean isCriticalRequest) { + int errorCode = error.getCode(); + String errorType = JsonRpcErrorCodes.getErrorMessage(errorCode); + String formattedError = String.format("%s (%d): %s", errorType, errorCode, error.getMessage()); + + if (isCriticalRequest) { + logError(formattedError); + } + + return Response.withErrorMessage(formattedError); + } + + private void logError(final String errorMessage) { + eventLog.executionClientRequestFailed(new Exception(errorMessage), false); + } + private boolean isCriticalRequest(final Request request) { return !nonCriticalMethods.contains(request.getMethod()); } From 7514da8960c92c545b500231d02f1c877061ee30 Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Fri, 11 Oct 2024 13:12:24 +1300 Subject: [PATCH 02/12] Refactor JsonRpcErrorCodes to enum for improved efficiency and structure --- .circleci/config.yml | 2 +- ...PeersStandAloneVcBlocksAcceptanceTest.java | 40 ++++------ ...idatorSlashingDetectionAcceptanceTest.java | 2 +- .../test/acceptance/dsl/TekuBeaconNode.java | 2 + .../acceptance/dsl/TekuNodeConfigBuilder.java | 6 ++ .../web3j/Web3JExecutionEngineClientTest.java | 4 +- .../ExecutionEngineClient.java | 3 +- .../ThrottlingExecutionEngineClient.java | 8 +- .../methods/EngineNewPayloadV4.java | 9 ++- .../MetricRecordingExecutionEngineClient.java | 5 +- .../web3j/JsonRpcErrorCodes.java | 62 +++++++-------- .../web3j/Web3JExecutionEngineClient.java | 5 +- .../methods/EngineGetPayloadV4Test.java | 2 +- .../methods/EngineNewPayloadV4Test.java | 13 ++-- .../ExecutionClientHandlerImpl.java | 2 +- .../ElectraExecutionClientHandlerTest.java | 9 ++- .../blocks/blockbody/BeaconBlockBody.java | 5 ++ .../blockbody/common/BlockBodyFields.java | 1 - .../BeaconBlockBodySchemaElectraImpl.java | 11 +-- .../BlindedBeaconBlockBodyElectra.java | 8 ++ .../BlindedBeaconBlockBodyElectraImpl.java | 5 ++ .../ExecutionPayloadHeaderBuilder.java | 8 -- .../execution/NewPayloadRequest.java | 21 ++--- ...xecutionPayloadHeaderBuilderBellatrix.java | 18 ----- .../electra/ExecutionRequestsDataCodec.java | 40 ++++------ .../interop/GenesisStateBuilder.java | 6 +- .../versions/electra/SpecLogicElectra.java | 6 +- .../electra/block/BlockProcessorElectra.java | 8 +- .../forktransition/ElectraStateUpgrade.java | 36 +-------- .../schemas/SchemaDefinitionsElectra.java | 30 ++++---- .../ExecutionRequestsDataCodecTest.java | 77 ++++++------------- .../block/BlockProcessorElectraTest.java | 8 +- .../interop/MergedGenesisTestBuilder.java | 7 +- .../teku/spec/util/DataStructureUtil.java | 7 +- 34 files changed, 192 insertions(+), 284 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index eb5c38b23b7..38c2560c4dc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -363,7 +363,7 @@ jobs: path: build/test-results acceptanceTests: - parallelism: 5 + parallelism: 4 executor: machine_large_executor_amd64 steps: - install_java_21 diff --git a/acceptance-tests/src/acceptance-test/java/tech/pegasys/teku/test/acceptance/validatorslashing/MultiPeersStandAloneVcBlocksAcceptanceTest.java b/acceptance-tests/src/acceptance-test/java/tech/pegasys/teku/test/acceptance/validatorslashing/MultiPeersStandAloneVcBlocksAcceptanceTest.java index abe7d557cb7..c63f5532783 100644 --- a/acceptance-tests/src/acceptance-test/java/tech/pegasys/teku/test/acceptance/validatorslashing/MultiPeersStandAloneVcBlocksAcceptanceTest.java +++ b/acceptance-tests/src/acceptance-test/java/tech/pegasys/teku/test/acceptance/validatorslashing/MultiPeersStandAloneVcBlocksAcceptanceTest.java @@ -17,7 +17,6 @@ import org.junit.jupiter.params.provider.MethodSource; import tech.pegasys.teku.bls.BLSKeyPair; import tech.pegasys.teku.infrastructure.unsigned.UInt64; -import tech.pegasys.teku.spec.SpecMilestone; import tech.pegasys.teku.test.acceptance.dsl.TekuBeaconNode; import tech.pegasys.teku.test.acceptance.dsl.TekuNodeConfigBuilder; import tech.pegasys.teku.test.acceptance.dsl.TekuValidatorNode; @@ -39,8 +38,7 @@ public class MultiPeersStandAloneVcBlocksAcceptanceTest shouldShutDownWhenOwnedValidatorSlashed_StandAloneVC_MultiplePeers_SlashingThroughBlock_NoSlashingEventsGossip( final SlashingEventType slashingEventType) throws Exception { - final int genesisTime = timeProvider.getTimeInSeconds().plus(10).intValue(); - final UInt64 altairEpoch = UInt64.valueOf(100); + final int genesisTime = timeProvider.getTimeInSeconds().plus(30).intValue(); final TekuBeaconNode firstTekuNode = createTekuBeaconNode( @@ -48,34 +46,17 @@ public class MultiPeersStandAloneVcBlocksAcceptanceTest .withGenesisTime(genesisTime) .withNetwork(network) .withRealNetwork() - .withAltairEpoch(altairEpoch) + .withSubscribeAllSubnetsEnabled() .withInteropValidators(0, 32) .build()); - firstTekuNode.start(); - - firstTekuNode.waitForEpochAtOrAbove(2); - - final int slashedValidatorIndex = 34; - final BLSKeyPair slashedValidatorKeyPair = getBlsKeyPair(slashedValidatorIndex); - final int slotInThirdEpoch = - firstTekuNode.getSpec().forMilestone(SpecMilestone.ALTAIR).getSlotsPerEpoch() * 2 + 3; - - postSlashing( - firstTekuNode, - UInt64.valueOf(slotInThirdEpoch), - UInt64.valueOf(slashedValidatorIndex), - slashedValidatorKeyPair.getSecretKey(), - slashingEventType); - final TekuBeaconNode secondBeaconNode = createTekuBeaconNode( TekuNodeConfigBuilder.createBeaconNode() .withGenesisTime(genesisTime) .withNetwork(network) .withRealNetwork() - .withRealNetwork() - .withAltairEpoch(altairEpoch) + .withSubscribeAllSubnetsEnabled() .withPeers(firstTekuNode) .build()); @@ -89,10 +70,23 @@ public class MultiPeersStandAloneVcBlocksAcceptanceTest .withBeaconNodes(secondBeaconNode) .build()); + firstTekuNode.start(); secondBeaconNode.start(); - secondValidatorClient.start(); + firstTekuNode.waitForEpochAtOrAbove(1); + + final int slashedValidatorIndex = 34; + final BLSKeyPair slashedValidatorKeyPair = getBlsKeyPair(slashedValidatorIndex); + final int slotInSecondEpoch = firstTekuNode.getSpec().getGenesisSpec().getSlotsPerEpoch() + 3; + + postSlashing( + firstTekuNode, + UInt64.valueOf(slotInSecondEpoch), + UInt64.valueOf(slashedValidatorIndex), + slashedValidatorKeyPair.getSecretKey(), + slashingEventType); + secondValidatorClient.waitForLogMessageContaining( String.format(slashingActionLog, slashedValidatorKeyPair.getPublicKey().toHexString())); diff --git a/acceptance-tests/src/acceptance-test/java/tech/pegasys/teku/test/acceptance/validatorslashing/ValidatorSlashingDetectionAcceptanceTest.java b/acceptance-tests/src/acceptance-test/java/tech/pegasys/teku/test/acceptance/validatorslashing/ValidatorSlashingDetectionAcceptanceTest.java index c177ddc9053..7259cdbd201 100644 --- a/acceptance-tests/src/acceptance-test/java/tech/pegasys/teku/test/acceptance/validatorslashing/ValidatorSlashingDetectionAcceptanceTest.java +++ b/acceptance-tests/src/acceptance-test/java/tech/pegasys/teku/test/acceptance/validatorslashing/ValidatorSlashingDetectionAcceptanceTest.java @@ -47,7 +47,7 @@ public class ValidatorSlashingDetectionAcceptanceTest extends AcceptanceTestBase final String slashingActionLog = "Validator slashing detection is enabled and validator(s) with public key(s) %s detected as slashed. " + "Shutting down..."; - final int shutdownWaitingSeconds = 60; + final int shutdownWaitingSeconds = 90; enum SlashingEventType { PROPOSER_SLASHING, diff --git a/acceptance-tests/src/testFixtures/java/tech/pegasys/teku/test/acceptance/dsl/TekuBeaconNode.java b/acceptance-tests/src/testFixtures/java/tech/pegasys/teku/test/acceptance/dsl/TekuBeaconNode.java index cb0f1852276..40cc58845aa 100644 --- a/acceptance-tests/src/testFixtures/java/tech/pegasys/teku/test/acceptance/dsl/TekuBeaconNode.java +++ b/acceptance-tests/src/testFixtures/java/tech/pegasys/teku/test/acceptance/dsl/TekuBeaconNode.java @@ -226,6 +226,7 @@ public void postProposerSlashing( randomSignedBeaconBlockHeader(slot, index, secretKey, signingRootUtil, forkInfo); final SignedBeaconBlockHeader header2 = randomSignedBeaconBlockHeader(slot, index, secretKey, signingRootUtil, forkInfo); + LOG.debug("Inserting proposer slashing for index {} at slot {}", index, slot); final String body = JsonUtil.serialize( new ProposerSlashing(header1, header2), @@ -256,6 +257,7 @@ public void postAttesterSlashing( spec.getGenesisSchemaDefinitions() .getAttesterSlashingSchema() .create(indexedAttestation1, indexedAttestation2); + LOG.debug("Inserting attester slashing for index {} at slot {}", slashedIndex, slashingSlot); final String body = JsonUtil.serialize( attesterSlashing, diff --git a/acceptance-tests/src/testFixtures/java/tech/pegasys/teku/test/acceptance/dsl/TekuNodeConfigBuilder.java b/acceptance-tests/src/testFixtures/java/tech/pegasys/teku/test/acceptance/dsl/TekuNodeConfigBuilder.java index b1947a653be..b931a600a78 100644 --- a/acceptance-tests/src/testFixtures/java/tech/pegasys/teku/test/acceptance/dsl/TekuNodeConfigBuilder.java +++ b/acceptance-tests/src/testFixtures/java/tech/pegasys/teku/test/acceptance/dsl/TekuNodeConfigBuilder.java @@ -417,6 +417,12 @@ public TekuNodeConfigBuilder withDoppelgangerDetectionEnabled() { return this; } + public TekuNodeConfigBuilder withSubscribeAllSubnetsEnabled() { + LOG.debug("p2p-subscribe-all-subnets-enabled=true"); + configMap.put("p2p-subscribe-all-subnets-enabled", true); + return this; + } + public TekuNodeConfigBuilder withDepositsFrom(final BesuNode eth1Node) { mustBe(NodeType.BEACON_NODE); configMap.put("Xinterop-enabled", false); diff --git a/ethereum/executionclient/src/integration-test/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JExecutionEngineClientTest.java b/ethereum/executionclient/src/integration-test/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JExecutionEngineClientTest.java index 61b01eda021..e9a70f36b0c 100644 --- a/ethereum/executionclient/src/integration-test/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JExecutionEngineClientTest.java +++ b/ethereum/executionclient/src/integration-test/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JExecutionEngineClientTest.java @@ -323,11 +323,11 @@ public void newPayloadV4_shouldBuildRequestAndResponseSuccessfully() { final List blobVersionedHashes = dataStructureUtil.randomVersionedHashes(3); final Bytes32 parentBeaconBlockRoot = dataStructureUtil.randomBytes32(); - final Bytes32 executionRequestHash = dataStructureUtil.randomBytes32(); + final List executionRequests = dataStructureUtil.randomEncodedExecutionRequests(); final SafeFuture> futureResponse = eeClient.newPayloadV4( - executionPayloadV3, blobVersionedHashes, parentBeaconBlockRoot, executionRequestHash); + executionPayloadV3, blobVersionedHashes, parentBeaconBlockRoot, executionRequests); assertThat(futureResponse) .succeedsWithin(1, TimeUnit.SECONDS) diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/ExecutionEngineClient.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/ExecutionEngineClient.java index ebbdd3d4286..19d8d8a3d97 100644 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/ExecutionEngineClient.java +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/ExecutionEngineClient.java @@ -15,6 +15,7 @@ import java.util.List; import java.util.Optional; +import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import tech.pegasys.teku.ethereum.executionclient.schema.BlobAndProofV1; import tech.pegasys.teku.ethereum.executionclient.schema.ClientVersionV1; @@ -64,7 +65,7 @@ SafeFuture> newPayloadV4( ExecutionPayloadV3 executionPayload, List blobVersionedHashes, Bytes32 parentBeaconBlockRoot, - Bytes32 executionRequestHash); + List executionRequests); SafeFuture> forkChoiceUpdatedV1( ForkChoiceStateV1 forkChoiceState, Optional payloadAttributes); diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/ThrottlingExecutionEngineClient.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/ThrottlingExecutionEngineClient.java index 8ee347e077b..646a513c8dc 100644 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/ThrottlingExecutionEngineClient.java +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/ThrottlingExecutionEngineClient.java @@ -15,6 +15,7 @@ import java.util.List; import java.util.Optional; +import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.hyperledger.besu.plugin.services.MetricsSystem; import tech.pegasys.teku.ethereum.executionclient.schema.BlobAndProofV1; @@ -112,14 +113,11 @@ public SafeFuture> newPayloadV4( final ExecutionPayloadV3 executionPayload, final List blobVersionedHashes, final Bytes32 parentBeaconBlockRoot, - final Bytes32 executionRequestHash) { + final List executionRequests) { return taskQueue.queueTask( () -> delegate.newPayloadV4( - executionPayload, - blobVersionedHashes, - parentBeaconBlockRoot, - executionRequestHash)); + executionPayload, blobVersionedHashes, parentBeaconBlockRoot, executionRequests)); } @Override diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineNewPayloadV4.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineNewPayloadV4.java index 8a72db49295..57ff1341bd7 100644 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineNewPayloadV4.java +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineNewPayloadV4.java @@ -16,6 +16,7 @@ import java.util.List; 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 tech.pegasys.teku.ethereum.executionclient.ExecutionEngineClient; import tech.pegasys.teku.ethereum.executionclient.response.ResponseUnwrapper; @@ -51,21 +52,21 @@ public SafeFuture execute(final JsonRpcRequestParams params) { final List blobVersionedHashes = params.getRequiredListParameter(1, VersionedHash.class); final Bytes32 parentBeaconBlockRoot = params.getRequiredParameter(2, Bytes32.class); - final Bytes32 executionRequestHash = params.getRequiredParameter(3, Bytes32.class); + final List executionRequests = params.getRequiredListParameter(3, Bytes.class); LOG.trace( - "Calling {}(executionPayload={}, blobVersionedHashes={}, parentBeaconBlockRoot={}, executionRequestHash={})", + "Calling {}(executionPayload={}, blobVersionedHashes={}, parentBeaconBlockRoot={}, executionRequests={})", getVersionedName(), executionPayload, blobVersionedHashes, parentBeaconBlockRoot, - executionRequestHash); + executionRequests); final ExecutionPayloadV3 executionPayloadV3 = ExecutionPayloadV3.fromInternalExecutionPayload(executionPayload); return executionEngineClient .newPayloadV4( - executionPayloadV3, blobVersionedHashes, parentBeaconBlockRoot, executionRequestHash) + executionPayloadV3, blobVersionedHashes, parentBeaconBlockRoot, executionRequests) .thenApply(ResponseUnwrapper::unwrapExecutionClientResponseOrThrow) .thenApply(PayloadStatusV1::asInternalExecutionPayload) .thenPeek( diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/metrics/MetricRecordingExecutionEngineClient.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/metrics/MetricRecordingExecutionEngineClient.java index 4e6d59668a0..62d3a4def02 100644 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/metrics/MetricRecordingExecutionEngineClient.java +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/metrics/MetricRecordingExecutionEngineClient.java @@ -16,6 +16,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.hyperledger.besu.plugin.services.MetricsSystem; import tech.pegasys.teku.ethereum.executionclient.ExecutionEngineClient; @@ -143,11 +144,11 @@ public SafeFuture> newPayloadV4( final ExecutionPayloadV3 executionPayload, final List blobVersionedHashes, final Bytes32 parentBeaconBlockRoot, - final Bytes32 executionRequestHash) { + final List executionRequests) { return countRequest( () -> delegate.newPayloadV4( - executionPayload, blobVersionedHashes, parentBeaconBlockRoot, executionRequestHash), + executionPayload, blobVersionedHashes, parentBeaconBlockRoot, executionRequests), NEW_PAYLOAD_V4_METHOD); } diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java index cc08bcc116e..8a66b6017d1 100644 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java @@ -13,48 +13,40 @@ package tech.pegasys.teku.ethereum.executionclient.web3j; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -public final class JsonRpcErrorCodes { - public static final int PARSE_ERROR = -32700; - public static final int INVALID_REQUEST = -32600; - public static final int METHOD_NOT_FOUND = -32601; - public static final int INVALID_PARAMS = -32602; - public static final int INTERNAL_ERROR = -32603; - public static final int SERVER_ERROR_RANGE_START = -32000; - public static final int SERVER_ERROR_RANGE_END = -32099; - - private static final Map ERROR_MESSAGES; - - static { - Map messages = new HashMap<>(); - messages.put(PARSE_ERROR, "Parse error"); - messages.put(INVALID_REQUEST, "Invalid request"); - messages.put(METHOD_NOT_FOUND, "Method not found"); - messages.put(INVALID_PARAMS, "Invalid params"); - messages.put(INTERNAL_ERROR, "Internal error"); - messages.put(SERVER_ERROR_RANGE_START, "Server error"); - ERROR_MESSAGES = Collections.unmodifiableMap(messages); +public enum JsonRpcErrorCodes { + PARSE_ERROR(-32700, "Parse error"), + INVALID_REQUEST(-32600, "Invalid Request"), + METHOD_NOT_FOUND(-32601, "Method not found"), + INVALID_PARAMS(-32602, "Invalid params"), + INTERNAL_ERROR(-32603, "Internal error"), + SERVER_ERROR(-32000, "Server error"); + + private final int errorCode; + private final String description; + + JsonRpcErrorCodes(int errorCode, String description) { + this.errorCode = errorCode; + this.description = description; } - private JsonRpcErrorCodes() { - // Utility class, do not instantiate + public int getErrorCode() { + return errorCode; } - public static String getErrorMessage(final int errorCode) { - if (isServerError(errorCode)) { - return ERROR_MESSAGES.get(SERVER_ERROR_RANGE_START); - } - return ERROR_MESSAGES.getOrDefault(errorCode, "Unknown error"); + public String getDescription() { + return description; } - public static boolean isServerError(final int errorCode) { - return errorCode >= SERVER_ERROR_RANGE_END && errorCode <= SERVER_ERROR_RANGE_START; + public static String getErrorMessage(int errorCode) { + return fromCode(errorCode).getDescription(); } - public static boolean isStandardError(final int errorCode) { - return ERROR_MESSAGES.containsKey(errorCode) || isServerError(errorCode); + public static JsonRpcErrorCodes fromCode(int errorCode) { + for (JsonRpcErrorCodes error : values()) { + if (error.getErrorCode() == errorCode) { + return error; + } + } + return errorCode >= -32099 && errorCode <= -32000 ? SERVER_ERROR : INTERNAL_ERROR; } } diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JExecutionEngineClient.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JExecutionEngineClient.java index 137d99b3211..c47e6f87b61 100644 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JExecutionEngineClient.java +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JExecutionEngineClient.java @@ -21,6 +21,7 @@ import java.util.Collections; import java.util.List; import java.util.Optional; +import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt256; import org.web3j.protocol.core.DefaultBlockParameterName; @@ -180,7 +181,7 @@ public SafeFuture> newPayloadV4( final ExecutionPayloadV3 executionPayload, final List blobVersionedHashes, final Bytes32 parentBeaconBlockRoot, - final Bytes32 executionRequestHash) { + final List executionRequests) { final List expectedBlobVersionedHashes = blobVersionedHashes.stream().map(VersionedHash::toHexString).toList(); final Request web3jRequest = @@ -190,7 +191,7 @@ public SafeFuture> newPayloadV4( executionPayload, expectedBlobVersionedHashes, parentBeaconBlockRoot.toHexString(), - executionRequestHash.toHexString()), + executionRequests), web3JClient.getWeb3jService(), PayloadStatusV1Web3jResponse.class); return web3JClient.doRequest(web3jRequest, EL_ENGINE_BLOCK_EXECUTION_TIMEOUT); diff --git a/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineGetPayloadV4Test.java b/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineGetPayloadV4Test.java index 860e2c2bb51..1d79c160606 100644 --- a/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineGetPayloadV4Test.java +++ b/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineGetPayloadV4Test.java @@ -130,7 +130,7 @@ public void shouldCallGetPayloadV4AndParseResponseSuccessfully() { final ExecutionPayload executionPayloadElectra = dataStructureUtil.randomExecutionPayload(); final ExecutionRequests executionRequests = dataStructureUtil.randomExecutionRequests(); final List encodedExecutionRequests = - executionRequestsDataCodec.encodeWithoutTypePrefix(executionRequests); + executionRequestsDataCodec.encode(executionRequests); assertThat(executionPayloadElectra).isInstanceOf(ExecutionPayloadDeneb.class); when(executionEngineClient.getPayloadV4(eq(executionPayloadContext.getPayloadId()))) diff --git a/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineNewPayloadV4Test.java b/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineNewPayloadV4Test.java index 524875313a9..9035576e852 100644 --- a/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineNewPayloadV4Test.java +++ b/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineNewPayloadV4Test.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.concurrent.TimeUnit; +import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -119,7 +120,7 @@ public void shouldReturnFailedExecutionWhenEngineClientRequestFails() { final ExecutionPayload executionPayload = dataStructureUtil.randomExecutionPayload(); final List blobVersionedHashes = dataStructureUtil.randomVersionedHashes(3); final Bytes32 parentBeaconBlockRoot = dataStructureUtil.randomBytes32(); - final Bytes32 executionRequestHash = dataStructureUtil.randomBytes32(); + final List executionRequests = dataStructureUtil.randomEncodedExecutionRequests(); final String errorResponseFromClient = "error!"; when(executionEngineClient.newPayloadV4(any(), any(), any(), any())) @@ -130,7 +131,7 @@ public void shouldReturnFailedExecutionWhenEngineClientRequestFails() { .add(executionPayload) .add(blobVersionedHashes) .add(parentBeaconBlockRoot) - .add(executionRequestHash) + .add(executionRequests) .build(); assertThat(jsonRpcMethod.execute(params)) @@ -143,7 +144,7 @@ public void shouldCallNewPayloadV4WithExecutionPayloadV3AndCorrectParameters() { final ExecutionPayload executionPayload = dataStructureUtil.randomExecutionPayload(); final List blobVersionedHashes = dataStructureUtil.randomVersionedHashes(4); final Bytes32 parentBeaconBlockRoot = dataStructureUtil.randomBytes32(); - final Bytes32 executionRequestHash = dataStructureUtil.randomBytes32(); + final List executionRequests = dataStructureUtil.randomEncodedExecutionRequests(); final ExecutionPayloadV3 executionPayloadV3 = ExecutionPayloadV3.fromInternalExecutionPayload(executionPayload); @@ -155,7 +156,7 @@ public void shouldCallNewPayloadV4WithExecutionPayloadV3AndCorrectParameters() { eq(executionPayloadV3), eq(blobVersionedHashes), eq(parentBeaconBlockRoot), - eq(executionRequestHash))) + eq(executionRequests))) .thenReturn(dummySuccessfulResponse()); final JsonRpcRequestParams params = @@ -163,7 +164,7 @@ public void shouldCallNewPayloadV4WithExecutionPayloadV3AndCorrectParameters() { .add(executionPayload) .add(blobVersionedHashes) .add(parentBeaconBlockRoot) - .add(executionRequestHash) + .add(executionRequests) .build(); assertThat(jsonRpcMethod.execute(params)).isCompleted(); @@ -173,7 +174,7 @@ public void shouldCallNewPayloadV4WithExecutionPayloadV3AndCorrectParameters() { eq(executionPayloadV3), eq(blobVersionedHashes), eq(parentBeaconBlockRoot), - eq(executionRequestHash)); + eq(executionRequests)); verifyNoMoreInteractions(executionEngineClient); } diff --git a/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/ExecutionClientHandlerImpl.java b/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/ExecutionClientHandlerImpl.java index 06cd24fd07e..581f494cb0a 100644 --- a/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/ExecutionClientHandlerImpl.java +++ b/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/ExecutionClientHandlerImpl.java @@ -110,7 +110,7 @@ public SafeFuture engineNewPayload( .add(executionPayload) .addOptional(newPayloadRequest.getVersionedHashes()) .addOptional(newPayloadRequest.getParentBeaconBlockRoot()) - .addOptional(newPayloadRequest.getExecutionRequestsHash()); + .addOptional(newPayloadRequest.getExecutionRequests()); return engineMethodsResolver .getMethod( diff --git a/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/ElectraExecutionClientHandlerTest.java b/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/ElectraExecutionClientHandlerTest.java index 0bd039d2d65..1665419dfba 100644 --- a/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/ElectraExecutionClientHandlerTest.java +++ b/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/ElectraExecutionClientHandlerTest.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.Optional; +import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt256; import org.junit.jupiter.api.BeforeEach; @@ -98,10 +99,10 @@ void engineNewPayload_shouldCallNewPayloadV4() { final ExecutionPayload payload = dataStructureUtil.randomExecutionPayload(); final List versionedHashes = dataStructureUtil.randomVersionedHashes(3); final Bytes32 parentBeaconBlockRoot = dataStructureUtil.randomBytes32(); - final Bytes32 executionRequestsHash = dataStructureUtil.randomBytes32(); + final List encodedExecutionRequests = dataStructureUtil.randomEncodedExecutionRequests(); final NewPayloadRequest newPayloadRequest = new NewPayloadRequest( - payload, versionedHashes, parentBeaconBlockRoot, executionRequestsHash); + payload, versionedHashes, parentBeaconBlockRoot, encodedExecutionRequests); final ExecutionPayloadV3 payloadV3 = ExecutionPayloadV3.fromInternalExecutionPayload(payload); final PayloadStatusV1 responseData = new PayloadStatusV1( @@ -112,7 +113,7 @@ void engineNewPayload_shouldCallNewPayloadV4() { eq(payloadV3), eq(versionedHashes), eq(parentBeaconBlockRoot), - eq(executionRequestsHash))) + eq(encodedExecutionRequests))) .thenReturn(dummyResponse); final SafeFuture future = handler.engineNewPayload(newPayloadRequest, UInt64.ZERO); @@ -121,7 +122,7 @@ void engineNewPayload_shouldCallNewPayloadV4() { eq(payloadV3), eq(versionedHashes), eq(parentBeaconBlockRoot), - eq(executionRequestsHash)); + eq(encodedExecutionRequests)); assertThat(future).isCompletedWithValue(responseData.asInternalExecutionPayload()); } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/BeaconBlockBody.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/BeaconBlockBody.java index 2240f7549e7..369bafe934e 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/BeaconBlockBody.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/BeaconBlockBody.java @@ -33,6 +33,7 @@ import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadSummary; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionRequests; import tech.pegasys.teku.spec.datastructures.operations.Attestation; import tech.pegasys.teku.spec.datastructures.operations.AttesterSlashing; import tech.pegasys.teku.spec.datastructures.operations.Deposit; @@ -87,6 +88,10 @@ default Optional> getOptionalBlobKzgCommitments() { return Optional.empty(); } + default Optional getOptionalExecutionRequests() { + return Optional.empty(); + } + default boolean isBlinded() { return false; } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/common/BlockBodyFields.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/common/BlockBodyFields.java index 9cccaf129bb..95608eabd54 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/common/BlockBodyFields.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/common/BlockBodyFields.java @@ -30,7 +30,6 @@ public enum BlockBodyFields implements SszFieldName { EXECUTION_PAYLOAD_HEADER, BLS_TO_EXECUTION_CHANGES, BLOB_KZG_COMMITMENTS, - CONSOLIDATIONS, EXECUTION_REQUESTS; private final String sszFieldName; diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BeaconBlockBodySchemaElectraImpl.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BeaconBlockBodySchemaElectraImpl.java index 0fb52b91539..e769e2a1884 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BeaconBlockBodySchemaElectraImpl.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BeaconBlockBodySchemaElectraImpl.java @@ -223,6 +223,12 @@ public ExecutionPayloadSchema getExecutionPayloadSchema() { getChildSchema(getFieldIndex(BlockBodyFields.BLOB_KZG_COMMITMENTS)); } + @Override + public ExecutionRequestsSchema getExecutionRequestsSchema() { + return (ExecutionRequestsSchema) + getChildSchema(getFieldIndex(BlockBodyFields.EXECUTION_REQUESTS)); + } + @Override public long getBlobKzgCommitmentsGeneralizedIndex() { return getChildGeneralizedIndex(getFieldIndex(BlockBodyFields.BLOB_KZG_COMMITMENTS)); @@ -234,9 +240,4 @@ public LongList getBlindedNodeGeneralizedIndices() { getChildGeneralizedIndex(getFieldIndex(BlockBodyFields.EXECUTION_PAYLOAD)), getExecutionPayloadSchema().getBlindedNodeGeneralizedIndices()); } - - @Override - public ExecutionRequestsSchema getExecutionRequestsSchema() { - return (ExecutionRequestsSchema) getFieldSchema12(); - } } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BlindedBeaconBlockBodyElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BlindedBeaconBlockBodyElectra.java index e4118f7a27e..c97c7916b36 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BlindedBeaconBlockBodyElectra.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BlindedBeaconBlockBodyElectra.java @@ -16,6 +16,7 @@ import java.util.Optional; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.deneb.BlindedBeaconBlockBodyDeneb; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionRequests; public interface BlindedBeaconBlockBodyElectra extends BlindedBeaconBlockBodyDeneb { static BlindedBeaconBlockBodyElectra required(final BeaconBlockBody body) { @@ -27,6 +28,13 @@ static BlindedBeaconBlockBodyElectra required(final BeaconBlockBody body) { + body.getClass().getSimpleName())); } + ExecutionRequests getExecutionRequests(); + + @Override + default Optional getOptionalExecutionRequests() { + return Optional.of(getExecutionRequests()); + } + @Override default Optional toBlindedVersionElectra() { return Optional.of(this); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BlindedBeaconBlockBodyElectraImpl.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BlindedBeaconBlockBodyElectraImpl.java index 36d58dc096e..55348da1584 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BlindedBeaconBlockBodyElectraImpl.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/blocks/blockbody/versions/electra/BlindedBeaconBlockBodyElectraImpl.java @@ -173,6 +173,11 @@ public SszList getBlobKzgCommitments() { return getField11(); } + @Override + public ExecutionRequests getExecutionRequests() { + return getField12(); + } + @Override public BlindedBeaconBlockBodySchemaElectraImpl getSchema() { return (BlindedBeaconBlockBodySchemaElectraImpl) super.getSchema(); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadHeaderBuilder.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadHeaderBuilder.java index 90c404df0a2..ead0c8f0bd4 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadHeaderBuilder.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/ExecutionPayloadHeaderBuilder.java @@ -55,13 +55,5 @@ public interface ExecutionPayloadHeaderBuilder { ExecutionPayloadHeaderBuilder excessBlobGas(Supplier excessBlobGasSupplier); - ExecutionPayloadHeaderBuilder depositRequestsRoot(Supplier depositRequestsRootSupplier); - - ExecutionPayloadHeaderBuilder withdrawalRequestsRoot( - Supplier withdrawalRequestsRootSupplier); - - ExecutionPayloadHeaderBuilder consolidationRequestsRoot( - Supplier consolidationRequestsRootSupplier); - ExecutionPayloadHeader build(); } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/NewPayloadRequest.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/NewPayloadRequest.java index e8a112eac9f..174e7e686a4 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/NewPayloadRequest.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/NewPayloadRequest.java @@ -17,6 +17,7 @@ import java.util.List; import java.util.Objects; import java.util.Optional; +import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import tech.pegasys.teku.spec.logic.versions.deneb.types.VersionedHash; @@ -25,13 +26,13 @@ public class NewPayloadRequest { private final ExecutionPayload executionPayload; private final Optional> versionedHashes; private final Optional parentBeaconBlockRoot; - private final Optional executionRequestsHash; + private final Optional> executionRequests; public NewPayloadRequest(final ExecutionPayload executionPayload) { this.executionPayload = executionPayload; this.versionedHashes = Optional.empty(); this.parentBeaconBlockRoot = Optional.empty(); - this.executionRequestsHash = Optional.empty(); + this.executionRequests = Optional.empty(); } public NewPayloadRequest( @@ -41,18 +42,18 @@ public NewPayloadRequest( this.executionPayload = executionPayload; this.versionedHashes = Optional.of(versionedHashes); this.parentBeaconBlockRoot = Optional.of(parentBeaconBlockRoot); - this.executionRequestsHash = Optional.empty(); + this.executionRequests = Optional.empty(); } public NewPayloadRequest( final ExecutionPayload executionPayload, final List versionedHashes, final Bytes32 parentBeaconBlockRoot, - final Bytes32 executionRequestsHash) { + final List executionRequests) { this.executionPayload = executionPayload; this.versionedHashes = Optional.of(versionedHashes); this.parentBeaconBlockRoot = Optional.of(parentBeaconBlockRoot); - this.executionRequestsHash = Optional.of(executionRequestsHash); + this.executionRequests = Optional.of(executionRequests); } public ExecutionPayload getExecutionPayload() { @@ -67,8 +68,8 @@ public Optional getParentBeaconBlockRoot() { return parentBeaconBlockRoot; } - public Optional getExecutionRequestsHash() { - return executionRequestsHash; + public Optional> getExecutionRequests() { + return executionRequests; } @Override @@ -83,13 +84,13 @@ public boolean equals(final Object o) { return Objects.equals(executionPayload, that.executionPayload) && Objects.equals(versionedHashes, that.versionedHashes) && Objects.equals(parentBeaconBlockRoot, that.parentBeaconBlockRoot) - && Objects.equals(executionRequestsHash, that.executionRequestsHash); + && Objects.equals(executionRequests, that.executionRequests); } @Override public int hashCode() { return Objects.hash( - executionPayload, versionedHashes, parentBeaconBlockRoot, executionRequestsHash); + executionPayload, versionedHashes, parentBeaconBlockRoot, executionRequests); } @Override @@ -98,7 +99,7 @@ public String toString() { .add("executionPayload", executionPayload) .add("versionedHashes", versionedHashes) .add("parentBeaconBlockRoot", parentBeaconBlockRoot) - .add("executionRequestsHash", executionRequestsHash) + .add("executionRequests", executionRequests) .toString(); } } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/bellatrix/ExecutionPayloadHeaderBuilderBellatrix.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/bellatrix/ExecutionPayloadHeaderBuilderBellatrix.java index 8b9e80a74ea..2df8d8af280 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/bellatrix/ExecutionPayloadHeaderBuilderBellatrix.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/bellatrix/ExecutionPayloadHeaderBuilderBellatrix.java @@ -152,24 +152,6 @@ public ExecutionPayloadHeaderBuilder excessBlobGas(final Supplier excess return this; } - @Override - public ExecutionPayloadHeaderBuilder depositRequestsRoot( - final Supplier depositRequestsRootSupplier) { - return this; - } - - @Override - public ExecutionPayloadHeaderBuilder withdrawalRequestsRoot( - final Supplier withdrawalRequestsRootSupplier) { - return this; - } - - @Override - public ExecutionPayloadHeaderBuilder consolidationRequestsRoot( - final Supplier consolidationRequestsRootSupplier) { - return this; - } - protected void validateSchema() { checkNotNull(schema, "schema must be specified"); } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodec.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodec.java index 1e51ad64264..e3127504af6 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodec.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodec.java @@ -13,11 +13,8 @@ package tech.pegasys.teku.spec.datastructures.execution.versions.electra; -import com.google.common.annotations.VisibleForTesting; import java.util.List; import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; -import tech.pegasys.teku.infrastructure.crypto.Hash; import tech.pegasys.teku.infrastructure.ssz.SszList; import tech.pegasys.teku.spec.datastructures.execution.ExecutionRequestsBuilder; @@ -27,10 +24,6 @@ public class ExecutionRequestsDataCodec { private static final int EXPECTED_REQUEST_DATA_ELEMENTS = 3; - private static final Bytes DEPOSIT_REQUEST_PREFIX = Bytes.of(DepositRequest.REQUEST_TYPE); - private static final Bytes WITHDRAWAL_REQUEST_PREFIX = Bytes.of(WithdrawalRequest.REQUEST_TYPE); - private static final Bytes CONSOLIDATION_REQUEST_PREFIX = - Bytes.of(ConsolidationRequest.REQUEST_TYPE); private final ExecutionRequestsSchema executionRequestsSchema; @@ -38,6 +31,12 @@ public ExecutionRequestsDataCodec(final ExecutionRequestsSchema executionRequest this.executionRequestsSchema = executionRequestsSchema; } + /** + * Decodes the execution requests received from the EL. + * + * @param executionRequestData list of encoded execution requests from the EL + * @return an ExecutionRequests object with the requests + */ public ExecutionRequests decode(final List executionRequestData) { if (executionRequestData.size() != EXPECTED_REQUEST_DATA_ELEMENTS) { throw new IllegalArgumentException( @@ -78,17 +77,13 @@ public ExecutionRequests decode(final List executionRequestData) { return executionRequestsBuilder.build(); } - public Bytes32 hash(final ExecutionRequests executionRequests) { - final Bytes sortedEncodedRequests = - encodeWithTypePrefix(executionRequests).stream() - .map(Hash::sha256) - .map(Bytes.class::cast) - .reduce(Bytes.EMPTY, Bytes::concatenate); - return Hash.sha256(sortedEncodedRequests); - } - - @VisibleForTesting - public List encodeWithoutTypePrefix(final ExecutionRequests executionRequests) { + /** + * Encodes the provided ExecutionRequests object to send the requests to the EL for validation. + * + * @param executionRequests the execution requests in the BeaconBlock + * @return list of encoded execution requests + */ + public List encode(final ExecutionRequests executionRequests) { final SszList depositRequestsSszList = executionRequestsSchema .getDepositRequestsSchema() @@ -107,13 +102,4 @@ public List encodeWithoutTypePrefix(final ExecutionRequests executionRequ withdrawalRequestsSszList.sszSerialize(), consolidationRequestsSszList.sszSerialize()); } - - @VisibleForTesting - List encodeWithTypePrefix(final ExecutionRequests executionRequests) { - final List encodeWithoutTypePrefix = encodeWithoutTypePrefix(executionRequests); - return List.of( - Bytes.concatenate(DEPOSIT_REQUEST_PREFIX, encodeWithoutTypePrefix.get(0)), - Bytes.concatenate(WITHDRAWAL_REQUEST_PREFIX, encodeWithoutTypePrefix.get(1)), - Bytes.concatenate(CONSOLIDATION_REQUEST_PREFIX, encodeWithoutTypePrefix.get(2))); - } } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/interop/GenesisStateBuilder.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/interop/GenesisStateBuilder.java index 27c32dfa87f..96970adefde 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/interop/GenesisStateBuilder.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/interop/GenesisStateBuilder.java @@ -163,12 +163,8 @@ private ExecutionPayloadHeader mockExecutionPayloadHeader() { // Capella b.withdrawalsRoot(() -> Bytes32.ZERO); // Deneb - b.excessBlobGas(() -> UInt64.ZERO); b.blobGasUsed(() -> UInt64.ZERO); - // Electra - b.depositRequestsRoot(() -> Bytes32.ZERO); - b.withdrawalRequestsRoot(() -> Bytes32.ZERO); - b.consolidationRequestsRoot(() -> Bytes32.ZERO); + b.excessBlobGas(() -> UInt64.ZERO); }); } } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/SpecLogicElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/SpecLogicElectra.java index 3dce3a95d9a..96cc8954090 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/SpecLogicElectra.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/SpecLogicElectra.java @@ -16,6 +16,7 @@ import java.util.Optional; import tech.pegasys.teku.infrastructure.time.TimeProvider; import tech.pegasys.teku.spec.config.SpecConfigElectra; +import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionRequestsDataCodec; import tech.pegasys.teku.spec.logic.common.AbstractSpecLogic; import tech.pegasys.teku.spec.logic.common.helpers.Predicates; import tech.pegasys.teku.spec.logic.common.operations.OperationSignatureVerifier; @@ -153,6 +154,8 @@ public static SpecLogicElectra create( beaconStateAccessors, validatorsUtil, config, miscHelpers, schemaDefinitions); final LightClientUtil lightClientUtil = new LightClientUtil(beaconStateAccessors, syncCommitteeUtil, schemaDefinitions); + final ExecutionRequestsDataCodec executionRequestsDataCodec = + new ExecutionRequestsDataCodec(schemaDefinitions.getExecutionRequestsSchema()); final BlockProcessorElectra blockProcessor = new BlockProcessorElectra( config, @@ -166,7 +169,8 @@ public static SpecLogicElectra create( attestationUtil, validatorsUtil, operationValidator, - schemaDefinitions); + schemaDefinitions, + executionRequestsDataCodec); final ForkChoiceUtil forkChoiceUtil = new ForkChoiceUtilDeneb( config, beaconStateAccessors, epochProcessor, attestationUtil, miscHelpers); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java index ed5a8a7b684..dffd43c51d7 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectra.java @@ -105,7 +105,8 @@ public BlockProcessorElectra( final AttestationUtil attestationUtil, final ValidatorsUtil validatorsUtil, final OperationValidator operationValidator, - final SchemaDefinitionsElectra schemaDefinitions) { + final SchemaDefinitionsElectra schemaDefinitions, + final ExecutionRequestsDataCodec executionRequestsDataCodec) { super( specConfig, predicates, @@ -124,8 +125,7 @@ public BlockProcessorElectra( this.beaconStateMutatorsElectra = beaconStateMutators; this.beaconStateAccessorsElectra = beaconStateAccessors; this.schemaDefinitionsElectra = schemaDefinitions; - this.executionRequestsDataCodec = - new ExecutionRequestsDataCodec(schemaDefinitions.getExecutionRequestsSchema()); + this.executionRequestsDataCodec = executionRequestsDataCodec; } @Override @@ -146,7 +146,7 @@ public NewPayloadRequest computeNewPayloadRequest( executionPayload, versionedHashes, parentBeaconBlockRoot, - executionRequestsDataCodec.hash(executionRequests)); + executionRequestsDataCodec.encode(executionRequests)); } @Override diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/forktransition/ElectraStateUpgrade.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/forktransition/ElectraStateUpgrade.java index e1797446ce5..6cd637e4b49 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/forktransition/ElectraStateUpgrade.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/electra/forktransition/ElectraStateUpgrade.java @@ -17,12 +17,9 @@ import java.util.Comparator; import java.util.stream.IntStream; -import org.apache.tuweni.bytes.Bytes32; import tech.pegasys.teku.infrastructure.ssz.SszMutableList; import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.config.SpecConfigElectra; -import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadHeader; -import tech.pegasys.teku.spec.datastructures.execution.versions.deneb.ExecutionPayloadHeaderDeneb; import tech.pegasys.teku.spec.datastructures.state.Fork; import tech.pegasys.teku.spec.datastructures.state.Validator; import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; @@ -80,37 +77,8 @@ public BeaconStateElectra upgrade(final BeaconState preState) { specConfig.getElectraForkVersion(), epoch)); - final ExecutionPayloadHeaderDeneb denebHeader = - preStateDeneb.getLatestExecutionPayloadHeader().toVersionDeneb().orElseThrow(); - final ExecutionPayloadHeader upgradedExecutionPayloadHeader = - schemaDefinitions - .getExecutionPayloadHeaderSchema() - .createExecutionPayloadHeader( - builder -> - builder - .parentHash(denebHeader.getParentHash()) - .feeRecipient(denebHeader.getFeeRecipient()) - .stateRoot(denebHeader.getStateRoot()) - .receiptsRoot(denebHeader.getReceiptsRoot()) - .logsBloom(denebHeader.getLogsBloom()) - .prevRandao(denebHeader.getPrevRandao()) - .blockNumber(denebHeader.getBlockNumber()) - .gasLimit(denebHeader.getGasLimit()) - .gasUsed(denebHeader.getGasUsed()) - .timestamp(denebHeader.getTimestamp()) - .extraData(denebHeader.getExtraData()) - .baseFeePerGas(denebHeader.getBaseFeePerGas()) - .blockHash(denebHeader.getBlockHash()) - .transactionsRoot(denebHeader.getTransactionsRoot()) - .withdrawalsRoot(denebHeader::getWithdrawalsRoot) - .blobGasUsed(denebHeader::getBlobGasUsed) - .excessBlobGas(denebHeader::getExcessBlobGas) - .depositRequestsRoot(() -> Bytes32.ZERO) - .withdrawalRequestsRoot(() -> Bytes32.ZERO) - .consolidationRequestsRoot(() -> Bytes32.ZERO)); - - state.setLatestExecutionPayloadHeader(upgradedExecutionPayloadHeader); - + state.setLatestExecutionPayloadHeader( + preStateDeneb.getLatestExecutionPayloadHeader()); state.setNextWithdrawalValidatorIndex( preStateDeneb.getNextWithdrawalValidatorIndex()); state.setNextWithdrawalIndex(preStateDeneb.getNextWithdrawalIndex()); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitionsElectra.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitionsElectra.java index 6c858851a1e..e6f9cdca094 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitionsElectra.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/schemas/SchemaDefinitionsElectra.java @@ -314,25 +314,33 @@ public WithdrawalRequestSchema getWithdrawalRequestSchema() { return withdrawalRequestSchema; } + public ConsolidationRequestSchema getConsolidationRequestSchema() { + return consolidationRequestSchema; + } + public PendingDeposit.PendingDepositSchema getPendingDepositSchema() { return pendingDepositSchema; } - public SszListSchema getPendingDepositsSchema() { - return beaconStateSchema.getPendingDepositsSchema(); + public PendingPartialWithdrawal.PendingPartialWithdrawalSchema + getPendingPartialWithdrawalSchema() { + return pendingPartialWithdrawalSchema; } - public SszListSchema getPendingConsolidationsSchema() { - return beaconStateSchema.getPendingConsolidationsSchema(); + public PendingConsolidation.PendingConsolidationSchema getPendingConsolidationSchema() { + return pendingConsolidationSchema; + } + + public SszListSchema getPendingDepositsSchema() { + return beaconStateSchema.getPendingDepositsSchema(); } public SszListSchema getPendingPartialWithdrawalsSchema() { return beaconStateSchema.getPendingPartialWithdrawalsSchema(); } - public PendingPartialWithdrawal.PendingPartialWithdrawalSchema - getPendingPartialWithdrawalSchema() { - return pendingPartialWithdrawalSchema; + public SszListSchema getPendingConsolidationsSchema() { + return beaconStateSchema.getPendingConsolidationsSchema(); } @Override @@ -340,14 +348,6 @@ public Optional toVersionElectra() { return Optional.of(this); } - public PendingConsolidation.PendingConsolidationSchema getPendingConsolidationSchema() { - return pendingConsolidationSchema; - } - - public ConsolidationRequestSchema getConsolidationRequestSchema() { - return consolidationRequestSchema; - } - @Override long getMaxValidatorPerAttestation(final SpecConfig specConfig) { return (long) specConfig.getMaxValidatorsPerCommittee() * specConfig.getMaxCommitteesPerSlot(); diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodecTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodecTest.java index 520565983b2..73d5f595432 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodecTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodecTest.java @@ -39,6 +39,19 @@ class ExecutionRequestsDataCodecTest { private final ExecutionRequestsDataCodec codec = new ExecutionRequestsDataCodec(executionRequestsSchema); + @Test + public void codecRoundTrip() { + final List expectedExecutionRequestsData = + List.of( + depositRequestListEncoded, + withdrawalRequestsListEncoded, + consolidationRequestsListEncoded); + + final List encodedExecutionRequestData = + codec.encode(codec.decode(expectedExecutionRequestsData)); + assertThat(encodedExecutionRequestData).isEqualTo(expectedExecutionRequestsData); + } + @Test public void decodeExecutionRequestData() { final List executionRequestsData = @@ -122,7 +135,7 @@ public void decodeExecutionRequestDataWithZeroElements() { } @Test - public void encodeWithTypePrefixExecutionRequests() { + public void encodeExecutionRequests() { final ExecutionRequests executionRequests = new ExecutionRequestsBuilderElectra(executionRequestsSchema) .deposits(List.of(depositRequest1, depositRequest2)) @@ -130,19 +143,17 @@ public void encodeWithTypePrefixExecutionRequests() { .consolidations(List.of(consolidationRequest1)) .build(); - final List encodedRequests = codec.encodeWithTypePrefix(executionRequests); + final List encodedRequests = codec.encode(executionRequests); assertThat(encodedRequests) .containsExactly( - Bytes.concatenate(Bytes.of(DepositRequest.REQUEST_TYPE), depositRequestListEncoded), - Bytes.concatenate( - Bytes.of(WithdrawalRequest.REQUEST_TYPE), withdrawalRequestsListEncoded), - Bytes.concatenate( - Bytes.of(ConsolidationRequest.REQUEST_TYPE), consolidationRequestsListEncoded)); + depositRequestListEncoded, + withdrawalRequestsListEncoded, + consolidationRequestsListEncoded); } @Test - public void encodeWithTypePrefixExecutionRequestsWithOneEmptyRequestList() { + public void encodeWithWithOneEmptyRequestList() { final ExecutionRequests executionRequests = new ExecutionRequestsBuilderElectra(executionRequestsSchema) .deposits(List.of(depositRequest1, depositRequest2)) @@ -150,18 +161,14 @@ public void encodeWithTypePrefixExecutionRequestsWithOneEmptyRequestList() { .consolidations(List.of(consolidationRequest1)) .build(); - final List encodedRequests = codec.encodeWithTypePrefix(executionRequests); + final List encodedRequests = codec.encode(executionRequests); assertThat(encodedRequests) - .containsExactly( - Bytes.concatenate(Bytes.of(DepositRequest.REQUEST_TYPE), depositRequestListEncoded), - Bytes.of(WithdrawalRequest.REQUEST_TYPE), - Bytes.concatenate( - Bytes.of(ConsolidationRequest.REQUEST_TYPE), consolidationRequestsListEncoded)); + .containsExactly(depositRequestListEncoded, Bytes.EMPTY, consolidationRequestsListEncoded); } @Test - public void encodeWithTypePrefixExecutionRequestsWithAllEmptyRequestLists() { + public void encodeWithAllEmptyRequestLists() { final ExecutionRequests executionRequests = new ExecutionRequestsBuilderElectra(executionRequestsSchema) .deposits(List.of()) @@ -169,45 +176,9 @@ public void encodeWithTypePrefixExecutionRequestsWithAllEmptyRequestLists() { .consolidations(List.of()) .build(); - final List encodedRequests = codec.encodeWithTypePrefix(executionRequests); - - assertThat(encodedRequests) - .containsExactly( - Bytes.of(DepositRequest.REQUEST_TYPE), - Bytes.of(WithdrawalRequest.REQUEST_TYPE), - Bytes.of(ConsolidationRequest.REQUEST_TYPE)); - } - - @Test - public void hashExecutionRequests() { - // Previously known hash of the encoded execution requests - final Bytes expectedHash = - Bytes.fromHexString("0xc0ff01be6ca468a08f1f5fb1dc83b3d92cc782b47ee567bcf17f925e73ff9c00"); - final ExecutionRequests executionRequests = - new ExecutionRequestsBuilderElectra(executionRequestsSchema) - .deposits(List.of(depositRequest1, depositRequest2)) - .withdrawals(List.of(withdrawalRequest1, withdrawalRequest2)) - .consolidations(List.of(consolidationRequest1)) - .build(); - - // Hash will only match if elements and order are correct - assertThat(codec.hash(executionRequests)).isEqualTo(expectedHash); - } - - @Test - public void hashExecutionRequestsWithAllEmptyRequestLists() { - // Previously known hash of the encoded execution requests - final Bytes expectedHash = - Bytes.fromHexString("0x6036c41849da9c076ed79654d434017387a88fb833c2856b32e18218b3341c5f"); - final ExecutionRequests executionRequests = - new ExecutionRequestsBuilderElectra(executionRequestsSchema) - .deposits(List.of()) - .withdrawals(List.of()) - .consolidations(List.of()) - .build(); + final List encodedRequests = codec.encode(executionRequests); - // Hash will only match if elements and order are correct - assertThat(codec.hash(executionRequests)).isEqualTo(expectedHash); + assertThat(encodedRequests).containsExactly(Bytes.EMPTY, Bytes.EMPTY, Bytes.EMPTY); } // Examples taken from diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectraTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectraTest.java index 3add055fa7f..8a33c73de79 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectraTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/electra/block/BlockProcessorElectraTest.java @@ -22,6 +22,7 @@ import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.IntStream; +import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.junit.jupiter.api.Test; import tech.pegasys.teku.bls.BLSPublicKey; @@ -545,8 +546,8 @@ public void shouldCreateNewPayloadRequestWithExecutionRequestsHash() throws Exce .map(SszKZGCommitment::getKZGCommitment) .map(miscHelpers::kzgCommitmentToVersionedHash) .collect(Collectors.toList()); - final Bytes32 expectedExecutionRequestsHash = - getExecutionRequestsDataCodec().hash(blockBody.getExecutionRequests()); + final List expectedExecutionRequests = + getExecutionRequestsDataCodec().encode(blockBody.getExecutionRequests()); final NewPayloadRequest newPayloadRequest = spec.getBlockProcessor(UInt64.ONE).computeNewPayloadRequest(preState, blockBody); @@ -564,8 +565,7 @@ public void shouldCreateNewPayloadRequestWithExecutionRequestsHash() throws Exce assertThat(newPayloadRequest.getParentBeaconBlockRoot()).isPresent(); assertThat(newPayloadRequest.getParentBeaconBlockRoot().get()) .isEqualTo(preState.getLatestBlockHeader().getParentRoot()); - assertThat(newPayloadRequest.getExecutionRequestsHash()) - .hasValue(expectedExecutionRequestsHash); + assertThat(newPayloadRequest.getExecutionRequests()).hasValue(expectedExecutionRequests); } private Supplier validatorExitContextSupplier(final BeaconState state) { diff --git a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/datastructures/interop/MergedGenesisTestBuilder.java b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/datastructures/interop/MergedGenesisTestBuilder.java index e4a6e1f3e74..712f56403ef 100644 --- a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/datastructures/interop/MergedGenesisTestBuilder.java +++ b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/datastructures/interop/MergedGenesisTestBuilder.java @@ -14,7 +14,6 @@ package tech.pegasys.teku.spec.datastructures.interop; import java.util.Collections; -import org.apache.tuweni.bytes.Bytes32; import org.hyperledger.besu.config.GenesisConfigFile; import org.hyperledger.besu.config.GenesisConfigOptions; import org.hyperledger.besu.datatypes.Wei; @@ -74,10 +73,6 @@ public static ExecutionPayloadHeader createPayloadForBesuGenesis( .orElseThrow()) // New in Deneb .blobGasUsed(() -> UInt64.ZERO) - .excessBlobGas(() -> UInt64.ZERO) - // New in Electra - .depositRequestsRoot(() -> Bytes32.ZERO) - .withdrawalRequestsRoot(() -> Bytes32.ZERO) - .consolidationRequestsRoot(() -> Bytes32.ZERO)); + .excessBlobGas(() -> UInt64.ZERO)); } } diff --git a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/util/DataStructureUtil.java b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/util/DataStructureUtil.java index 98c31a885e7..5bcd653e928 100644 --- a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/util/DataStructureUtil.java +++ b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/util/DataStructureUtil.java @@ -603,10 +603,7 @@ public ExecutionPayloadHeader randomExecutionPayloadHeader( .transactionsRoot(randomBytes32()) .withdrawalsRoot(() -> withdrawalsRoot) .blobGasUsed(this::randomUInt64) - .excessBlobGas(this::randomUInt64) - .depositRequestsRoot(this::randomBytes32) - .withdrawalRequestsRoot(this::randomBytes32) - .consolidationRequestsRoot(this::randomBytes32)); + .excessBlobGas(this::randomUInt64)); } public ExecutionPayloadHeader randomExecutionPayloadHeader(final SpecVersion specVersion) { @@ -2512,7 +2509,7 @@ public List randomEncodedExecutionRequests() { spec.forMilestone(SpecMilestone.ELECTRA).getSchemaDefinitions()) .getExecutionRequestsSchema(); return new ExecutionRequestsDataCodec(executionRequestsSchema) - .encodeWithoutTypePrefix(randomExecutionRequests()); + .encode(randomExecutionRequests()); } public WithdrawalRequest randomWithdrawalRequest() { From 4b8711efe1aca49403a05f0f8798bc33154d5a76 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 11 Oct 2024 15:28:11 +0530 Subject: [PATCH 03/12] Make method parameters final in JsonRpcErrorCodes --- .../ethereum/executionclient/web3j/JsonRpcErrorCodes.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java index 8a66b6017d1..cdff5877fd4 100644 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java @@ -24,7 +24,7 @@ public enum JsonRpcErrorCodes { private final int errorCode; private final String description; - JsonRpcErrorCodes(int errorCode, String description) { + JsonRpcErrorCodes(final int errorCode, final String description) { this.errorCode = errorCode; this.description = description; } @@ -37,11 +37,11 @@ public String getDescription() { return description; } - public static String getErrorMessage(int errorCode) { + public static String getErrorMessage(final int errorCode) { return fromCode(errorCode).getDescription(); } - public static JsonRpcErrorCodes fromCode(int errorCode) { + public static JsonRpcErrorCodes fromCode(final int errorCode) { for (JsonRpcErrorCodes error : values()) { if (error.getErrorCode() == errorCode) { return error; From 7e468d506b904a94c6e9bfb63c3fdca4eefd6941 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 11 Oct 2024 17:27:42 +0530 Subject: [PATCH 04/12] Optimize JsonRpcErrorCodes lookup using Int2ObjectOpenHashMap --- .../web3j/JsonRpcErrorCodes.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java index cdff5877fd4..76b4a73db58 100644 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java @@ -13,6 +13,8 @@ package tech.pegasys.teku.ethereum.executionclient.web3j; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; + public enum JsonRpcErrorCodes { PARSE_ERROR(-32700, "Parse error"), INVALID_REQUEST(-32600, "Invalid Request"), @@ -23,6 +25,14 @@ public enum JsonRpcErrorCodes { private final int errorCode; private final String description; + private static final Int2ObjectOpenHashMap CODE_TO_ERROR_MAP; + + static { + CODE_TO_ERROR_MAP = new Int2ObjectOpenHashMap<>(); + for (JsonRpcErrorCodes error : values()) { + CODE_TO_ERROR_MAP.put(error.getErrorCode(), error); + } + } JsonRpcErrorCodes(final int errorCode, final String description) { this.errorCode = errorCode; @@ -42,10 +52,9 @@ public static String getErrorMessage(final int errorCode) { } public static JsonRpcErrorCodes fromCode(final int errorCode) { - for (JsonRpcErrorCodes error : values()) { - if (error.getErrorCode() == errorCode) { - return error; - } + JsonRpcErrorCodes error = CODE_TO_ERROR_MAP.get(errorCode); + if (error != null) { + return error; } return errorCode >= -32099 && errorCode <= -32000 ? SERVER_ERROR : INTERNAL_ERROR; } From a9f1d803b02111791f592e0e0b27b149ef898734 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 10 Oct 2024 00:54:06 +0530 Subject: [PATCH 05/12] Standardise the Engine JSON-RPC error codes --- .../web3j/JsonRpcErrorCodes.java | 60 +++++++++++++++++++ .../executionclient/web3j/Web3JClient.java | 34 ++++++++--- 2 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java new file mode 100644 index 00000000000..cc08bcc116e --- /dev/null +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java @@ -0,0 +1,60 @@ +/* + * 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.ethereum.executionclient.web3j; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public final class JsonRpcErrorCodes { + public static final int PARSE_ERROR = -32700; + public static final int INVALID_REQUEST = -32600; + public static final int METHOD_NOT_FOUND = -32601; + public static final int INVALID_PARAMS = -32602; + public static final int INTERNAL_ERROR = -32603; + public static final int SERVER_ERROR_RANGE_START = -32000; + public static final int SERVER_ERROR_RANGE_END = -32099; + + private static final Map ERROR_MESSAGES; + + static { + Map messages = new HashMap<>(); + messages.put(PARSE_ERROR, "Parse error"); + messages.put(INVALID_REQUEST, "Invalid request"); + messages.put(METHOD_NOT_FOUND, "Method not found"); + messages.put(INVALID_PARAMS, "Invalid params"); + messages.put(INTERNAL_ERROR, "Internal error"); + messages.put(SERVER_ERROR_RANGE_START, "Server error"); + ERROR_MESSAGES = Collections.unmodifiableMap(messages); + } + + private JsonRpcErrorCodes() { + // Utility class, do not instantiate + } + + public static String getErrorMessage(final int errorCode) { + if (isServerError(errorCode)) { + return ERROR_MESSAGES.get(SERVER_ERROR_RANGE_START); + } + return ERROR_MESSAGES.getOrDefault(errorCode, "Unknown error"); + } + + public static boolean isServerError(final int errorCode) { + return errorCode >= SERVER_ERROR_RANGE_END && errorCode <= SERVER_ERROR_RANGE_START; + } + + public static boolean isStandardError(final int errorCode) { + return ERROR_MESSAGES.containsKey(errorCode) || isServerError(errorCode); + } +} diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClient.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClient.java index b8cf68f6729..fb7f1e28354 100644 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClient.java +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClient.java @@ -15,7 +15,6 @@ import static tech.pegasys.teku.infrastructure.exceptions.ExceptionUtil.getMessageOrSimpleName; -import java.io.IOException; import java.net.ConnectException; import java.time.Duration; import java.util.Collection; @@ -86,14 +85,9 @@ public SafeFuture> doRequest( (response, exception) -> { final boolean isCriticalRequest = isCriticalRequest(web3jRequest); if (exception != null) { - final boolean couldBeAuthError = isAuthenticationException(exception); - handleError(isCriticalRequest, exception, couldBeAuthError); - return Response.withErrorMessage(getMessageOrSimpleName(exception)); + return handleException(exception, isCriticalRequest); } else if (response.hasError()) { - final String errorMessage = - response.getError().getCode() + ": " + response.getError().getMessage(); - handleError(isCriticalRequest, new IOException(errorMessage), false); - return Response.withErrorMessage(errorMessage); + return handleJsonRpcError(response.getError(), isCriticalRequest); } else { handleSuccess(isCriticalRequest); return new Response<>(response.getResult()); @@ -101,6 +95,30 @@ public SafeFuture> doRequest( }); } + private Response handleException( + final Throwable exception, final boolean isCriticalRequest) { + final boolean couldBeAuthError = isAuthenticationException(exception); + handleError(isCriticalRequest, exception, couldBeAuthError); + return Response.withErrorMessage(getMessageOrSimpleName(exception)); + } + + private Response handleJsonRpcError( + final org.web3j.protocol.core.Response.Error error, final boolean isCriticalRequest) { + int errorCode = error.getCode(); + String errorType = JsonRpcErrorCodes.getErrorMessage(errorCode); + String formattedError = String.format("%s (%d): %s", errorType, errorCode, error.getMessage()); + + if (isCriticalRequest) { + logError(formattedError); + } + + return Response.withErrorMessage(formattedError); + } + + private void logError(final String errorMessage) { + eventLog.executionClientRequestFailed(new Exception(errorMessage), false); + } + private boolean isCriticalRequest(final Request request) { return !nonCriticalMethods.contains(request.getMethod()); } From 3bad1b81bc31a8f5c203b9be8c412d83221af17c Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Fri, 11 Oct 2024 13:12:24 +1300 Subject: [PATCH 06/12] Refactor JsonRpcErrorCodes to enum for improved efficiency and structure --- .../web3j/JsonRpcErrorCodes.java | 62 ++++++++----------- 1 file changed, 27 insertions(+), 35 deletions(-) diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java index cc08bcc116e..8a66b6017d1 100644 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java @@ -13,48 +13,40 @@ package tech.pegasys.teku.ethereum.executionclient.web3j; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -public final class JsonRpcErrorCodes { - public static final int PARSE_ERROR = -32700; - public static final int INVALID_REQUEST = -32600; - public static final int METHOD_NOT_FOUND = -32601; - public static final int INVALID_PARAMS = -32602; - public static final int INTERNAL_ERROR = -32603; - public static final int SERVER_ERROR_RANGE_START = -32000; - public static final int SERVER_ERROR_RANGE_END = -32099; - - private static final Map ERROR_MESSAGES; - - static { - Map messages = new HashMap<>(); - messages.put(PARSE_ERROR, "Parse error"); - messages.put(INVALID_REQUEST, "Invalid request"); - messages.put(METHOD_NOT_FOUND, "Method not found"); - messages.put(INVALID_PARAMS, "Invalid params"); - messages.put(INTERNAL_ERROR, "Internal error"); - messages.put(SERVER_ERROR_RANGE_START, "Server error"); - ERROR_MESSAGES = Collections.unmodifiableMap(messages); +public enum JsonRpcErrorCodes { + PARSE_ERROR(-32700, "Parse error"), + INVALID_REQUEST(-32600, "Invalid Request"), + METHOD_NOT_FOUND(-32601, "Method not found"), + INVALID_PARAMS(-32602, "Invalid params"), + INTERNAL_ERROR(-32603, "Internal error"), + SERVER_ERROR(-32000, "Server error"); + + private final int errorCode; + private final String description; + + JsonRpcErrorCodes(int errorCode, String description) { + this.errorCode = errorCode; + this.description = description; } - private JsonRpcErrorCodes() { - // Utility class, do not instantiate + public int getErrorCode() { + return errorCode; } - public static String getErrorMessage(final int errorCode) { - if (isServerError(errorCode)) { - return ERROR_MESSAGES.get(SERVER_ERROR_RANGE_START); - } - return ERROR_MESSAGES.getOrDefault(errorCode, "Unknown error"); + public String getDescription() { + return description; } - public static boolean isServerError(final int errorCode) { - return errorCode >= SERVER_ERROR_RANGE_END && errorCode <= SERVER_ERROR_RANGE_START; + public static String getErrorMessage(int errorCode) { + return fromCode(errorCode).getDescription(); } - public static boolean isStandardError(final int errorCode) { - return ERROR_MESSAGES.containsKey(errorCode) || isServerError(errorCode); + public static JsonRpcErrorCodes fromCode(int errorCode) { + for (JsonRpcErrorCodes error : values()) { + if (error.getErrorCode() == errorCode) { + return error; + } + } + return errorCode >= -32099 && errorCode <= -32000 ? SERVER_ERROR : INTERNAL_ERROR; } } From 2ddbb0ffd590af52f7d3e6998a1ce43014907fe2 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 11 Oct 2024 15:28:11 +0530 Subject: [PATCH 07/12] Make method parameters final in JsonRpcErrorCodes --- .../ethereum/executionclient/web3j/JsonRpcErrorCodes.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java index 8a66b6017d1..cdff5877fd4 100644 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java @@ -24,7 +24,7 @@ public enum JsonRpcErrorCodes { private final int errorCode; private final String description; - JsonRpcErrorCodes(int errorCode, String description) { + JsonRpcErrorCodes(final int errorCode, final String description) { this.errorCode = errorCode; this.description = description; } @@ -37,11 +37,11 @@ public String getDescription() { return description; } - public static String getErrorMessage(int errorCode) { + public static String getErrorMessage(final int errorCode) { return fromCode(errorCode).getDescription(); } - public static JsonRpcErrorCodes fromCode(int errorCode) { + public static JsonRpcErrorCodes fromCode(final int errorCode) { for (JsonRpcErrorCodes error : values()) { if (error.getErrorCode() == errorCode) { return error; From dc68ccc89fa5602410775c96bcb273c326591f81 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 11 Oct 2024 17:27:42 +0530 Subject: [PATCH 08/12] Optimize JsonRpcErrorCodes lookup using Int2ObjectOpenHashMap --- .../web3j/JsonRpcErrorCodes.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java index cdff5877fd4..76b4a73db58 100644 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java @@ -13,6 +13,8 @@ package tech.pegasys.teku.ethereum.executionclient.web3j; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; + public enum JsonRpcErrorCodes { PARSE_ERROR(-32700, "Parse error"), INVALID_REQUEST(-32600, "Invalid Request"), @@ -23,6 +25,14 @@ public enum JsonRpcErrorCodes { private final int errorCode; private final String description; + private static final Int2ObjectOpenHashMap CODE_TO_ERROR_MAP; + + static { + CODE_TO_ERROR_MAP = new Int2ObjectOpenHashMap<>(); + for (JsonRpcErrorCodes error : values()) { + CODE_TO_ERROR_MAP.put(error.getErrorCode(), error); + } + } JsonRpcErrorCodes(final int errorCode, final String description) { this.errorCode = errorCode; @@ -42,10 +52,9 @@ public static String getErrorMessage(final int errorCode) { } public static JsonRpcErrorCodes fromCode(final int errorCode) { - for (JsonRpcErrorCodes error : values()) { - if (error.getErrorCode() == errorCode) { - return error; - } + JsonRpcErrorCodes error = CODE_TO_ERROR_MAP.get(errorCode); + if (error != null) { + return error; } return errorCode >= -32099 && errorCode <= -32000 ? SERVER_ERROR : INTERNAL_ERROR; } From 08a236644fa793c43ea41d053f65da0352a8d721 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 14 Oct 2024 00:17:03 +0530 Subject: [PATCH 09/12] change JsonRpcErrorCodes to package private --- .../web3j/JsonRpcErrorCodes.java | 6 ++-- .../web3j/Web3JClientTest.java | 32 +++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java index 76b4a73db58..50d0007f6aa 100644 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java @@ -15,7 +15,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -public enum JsonRpcErrorCodes { +enum JsonRpcErrorCodes { PARSE_ERROR(-32700, "Parse error"), INVALID_REQUEST(-32600, "Invalid Request"), METHOD_NOT_FOUND(-32601, "Method not found"), @@ -29,7 +29,7 @@ public enum JsonRpcErrorCodes { static { CODE_TO_ERROR_MAP = new Int2ObjectOpenHashMap<>(); - for (JsonRpcErrorCodes error : values()) { + for (final JsonRpcErrorCodes error : values()) { CODE_TO_ERROR_MAP.put(error.getErrorCode(), error); } } @@ -52,7 +52,7 @@ public static String getErrorMessage(final int errorCode) { } public static JsonRpcErrorCodes fromCode(final int errorCode) { - JsonRpcErrorCodes error = CODE_TO_ERROR_MAP.get(errorCode); + final JsonRpcErrorCodes error = CODE_TO_ERROR_MAP.get(errorCode); if (error != null) { return error; } diff --git a/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClientTest.java b/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClientTest.java index dce5771ce05..b989054ad14 100644 --- a/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClientTest.java +++ b/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClientTest.java @@ -14,6 +14,7 @@ package tech.pegasys.teku.ethereum.executionclient.web3j; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -272,6 +273,37 @@ void shouldNotUpdateAvailabilityWhenNonCriticalMethodFailsWithErrorResponse( verifyNoInteractions(executionClientEventsPublisher); } + @ParameterizedTest + @MethodSource("getClientInstances") + void shouldDecodeJsonRpcErrorCodesCorrectly(final ClientFactory clientFactory) throws Exception { + final Web3JClient client = clientFactory.create(eventLog, executionClientEventsPublisher); + Request request = createRequest(client); + + // Create a response with a specific JSON-RPC error + VoidResponse errorResponse = new VoidResponse(); + errorResponse.setError( + new Error(JsonRpcErrorCodes.INVALID_PARAMS.getErrorCode(), "Invalid parameters")); + + when(client.getWeb3jService().sendAsync(request, VoidResponse.class)) + .thenReturn(SafeFuture.completedFuture(errorResponse)); + + final SafeFuture> result = client.doRequest(request, DEFAULT_TIMEOUT); + Waiter.waitFor(result); + + SafeFutureAssert.assertThatSafeFuture(result).isCompleted(); + final Response response = SafeFutureAssert.safeJoin(result); + + assertThat(response.getErrorMessage()) + .isEqualTo( + String.format( + "%s (%d): %s", + JsonRpcErrorCodes.INVALID_PARAMS.getDescription(), + JsonRpcErrorCodes.INVALID_PARAMS.getErrorCode(), + "Invalid parameters")); + + verify(eventLog).executionClientRequestFailed(any(Exception.class), eq(false)); + } + private static Request createRequest(final Web3JClient client) { return new Request<>("test", new ArrayList<>(), client.getWeb3jService(), VoidResponse.class); } From 6aa34bcb6b81a5b367eb5f3a4e9f5c773e6b4d25 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 14 Oct 2024 19:12:17 +0530 Subject: [PATCH 10/12] change method name for getter --- .../teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java | 2 +- .../teku/ethereum/executionclient/web3j/Web3JClient.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java index 50d0007f6aa..d83f6429dfe 100644 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/JsonRpcErrorCodes.java @@ -47,7 +47,7 @@ public String getDescription() { return description; } - public static String getErrorMessage(final int errorCode) { + public static String getDescription(final int errorCode) { return fromCode(errorCode).getDescription(); } diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClient.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClient.java index fb7f1e28354..e65eed3b452 100644 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClient.java +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClient.java @@ -105,7 +105,7 @@ private Response handleException( private Response handleJsonRpcError( final org.web3j.protocol.core.Response.Error error, final boolean isCriticalRequest) { int errorCode = error.getCode(); - String errorType = JsonRpcErrorCodes.getErrorMessage(errorCode); + String errorType = JsonRpcErrorCodes.getDescription(errorCode); String formattedError = String.format("%s (%d): %s", errorType, errorCode, error.getMessage()); if (isCriticalRequest) { From ed9d033efa3dcc5a69de34904042d322f28baf49 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 14 Oct 2024 23:55:45 +0530 Subject: [PATCH 11/12] Improve JSON-RPC error message formatting --- .../teku/ethereum/executionclient/web3j/Web3JClient.java | 7 ++++--- .../ethereum/executionclient/web3j/Web3JClientTest.java | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClient.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClient.java index e65eed3b452..c1bcc331e29 100644 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClient.java +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClient.java @@ -104,9 +104,10 @@ private Response handleException( private Response handleJsonRpcError( final org.web3j.protocol.core.Response.Error error, final boolean isCriticalRequest) { - int errorCode = error.getCode(); - String errorType = JsonRpcErrorCodes.getDescription(errorCode); - String formattedError = String.format("%s (%d): %s", errorType, errorCode, error.getMessage()); + final int errorCode = error.getCode(); + final String errorType = JsonRpcErrorCodes.getDescription(errorCode); + final String formattedError = + String.format("JSON-RPC error: %s (%d): %s", errorType, errorCode, error.getMessage()); if (isCriticalRequest) { logError(formattedError); diff --git a/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClientTest.java b/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClientTest.java index b989054ad14..16dba2f7b56 100644 --- a/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClientTest.java +++ b/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClientTest.java @@ -296,7 +296,7 @@ void shouldDecodeJsonRpcErrorCodesCorrectly(final ClientFactory clientFactory) t assertThat(response.getErrorMessage()) .isEqualTo( String.format( - "%s (%d): %s", + "JSON-RPC error: %s (%d): %s", JsonRpcErrorCodes.INVALID_PARAMS.getDescription(), JsonRpcErrorCodes.INVALID_PARAMS.getErrorCode(), "Invalid parameters")); From 598cd71b5afe9455bc7165af74a18d31a610ceac Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 16 Oct 2024 23:57:07 +0530 Subject: [PATCH 12/12] Improve JSON-RPC error handling test coverage --- .../ethereum/executionclient/web3j/Web3JClientTest.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClientTest.java b/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClientTest.java index 16dba2f7b56..5ef46e59e4a 100644 --- a/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClientTest.java +++ b/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/web3j/Web3JClientTest.java @@ -281,8 +281,11 @@ void shouldDecodeJsonRpcErrorCodesCorrectly(final ClientFactory clientFactory) t // Create a response with a specific JSON-RPC error VoidResponse errorResponse = new VoidResponse(); - errorResponse.setError( - new Error(JsonRpcErrorCodes.INVALID_PARAMS.getErrorCode(), "Invalid parameters")); + Error rpcError = + new Error( + JsonRpcErrorCodes.INVALID_PARAMS.getErrorCode(), + "engine_newPayload method has been called with invalid parameters"); + errorResponse.setError(rpcError); when(client.getWeb3jService().sendAsync(request, VoidResponse.class)) .thenReturn(SafeFuture.completedFuture(errorResponse)); @@ -299,7 +302,7 @@ void shouldDecodeJsonRpcErrorCodesCorrectly(final ClientFactory clientFactory) t "JSON-RPC error: %s (%d): %s", JsonRpcErrorCodes.INVALID_PARAMS.getDescription(), JsonRpcErrorCodes.INVALID_PARAMS.getErrorCode(), - "Invalid parameters")); + "engine_newPayload method has been called with invalid parameters")); verify(eventLog).executionClientRequestFailed(any(Exception.class), eq(false)); }