diff --git a/ethereum/executionclient/src/integration-test/java/tech/pegasys/teku/ethereum/executionclient/rest/RestBuilderClientTest.java b/ethereum/executionclient/src/integration-test/java/tech/pegasys/teku/ethereum/executionclient/rest/RestBuilderClientTest.java index 6eb283c7d16..2481c887066 100644 --- a/ethereum/executionclient/src/integration-test/java/tech/pegasys/teku/ethereum/executionclient/rest/RestBuilderClientTest.java +++ b/ethereum/executionclient/src/integration-test/java/tech/pegasys/teku/ethereum/executionclient/rest/RestBuilderClientTest.java @@ -60,7 +60,7 @@ import tech.pegasys.teku.spec.networks.Eth2Network; import tech.pegasys.teku.spec.schemas.SchemaDefinitionsBellatrix; -// TODO Re-enable electra as part of https://github.com/Consensys/teku/issues/8620 +// TODO Re-enable electra as part of https://github.com/Consensys/teku/issues/8624 @TestSpecContext( milestone = {BELLATRIX, CAPELLA, DENEB}, network = Eth2Network.MAINNET) 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 3426bb968f5..146186e0a5f 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 @@ -50,7 +50,6 @@ import tech.pegasys.teku.ethereum.events.ExecutionClientEventsChannel; import tech.pegasys.teku.ethereum.executionclient.schema.ClientVersionV1; import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV3; -import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV4; import tech.pegasys.teku.ethereum.executionclient.schema.ForkChoiceStateV1; import tech.pegasys.teku.ethereum.executionclient.schema.ForkChoiceUpdatedResult; import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV1; @@ -317,14 +316,16 @@ public void newPayloadV4_shouldBuildRequestAndResponseSuccessfully() { mockSuccessfulResponse(bodyResponse); final ExecutionPayload executionPayload = dataStructureUtil.randomExecutionPayload(); - final ExecutionPayloadV4 executionPayloadV4 = - ExecutionPayloadV4.fromInternalExecutionPayload(executionPayload); + final ExecutionPayloadV3 executionPayloadV3 = + ExecutionPayloadV3.fromInternalExecutionPayload(executionPayload); final List blobVersionedHashes = dataStructureUtil.randomVersionedHashes(3); final Bytes32 parentBeaconBlockRoot = dataStructureUtil.randomBytes32(); + final Bytes32 executionRequestHash = dataStructureUtil.randomBytes32(); final SafeFuture> futureResponse = - eeClient.newPayloadV4(executionPayloadV4, blobVersionedHashes, parentBeaconBlockRoot); + eeClient.newPayloadV4( + executionPayloadV3, blobVersionedHashes, parentBeaconBlockRoot, executionRequestHash); assertThat(futureResponse) .succeedsWithin(1, TimeUnit.SECONDS) @@ -335,13 +336,13 @@ public void newPayloadV4_shouldBuildRequestAndResponseSuccessfully() { final Map requestData = takeRequest(); verifyJsonRpcMethodCall(requestData, "engine_newPayloadV4"); - final Map executionPayloadV4Parameter = + final Map executionPayloadV3Parameter = (Map) ((List) requestData.get("params")).get(0); // 17 fields in ExecutionPayloadV4 - assertThat(executionPayloadV4Parameter).hasSize(17); + assertThat(executionPayloadV3Parameter).hasSize(17); // sanity check - assertThat(executionPayloadV4Parameter.get("parentHash")) - .isEqualTo(executionPayloadV4.parentHash.toHexString()); + assertThat(executionPayloadV3Parameter.get("parentHash")) + .isEqualTo(executionPayloadV3.parentHash.toHexString()); assertThat(((List) requestData.get("params")).get(1)) .asInstanceOf(LIST) 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 02ee14282b5..e66b17999e2 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 @@ -20,7 +20,6 @@ import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV1; import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV2; import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV3; -import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV4; import tech.pegasys.teku.ethereum.executionclient.schema.ForkChoiceStateV1; import tech.pegasys.teku.ethereum.executionclient.schema.ForkChoiceUpdatedResult; import tech.pegasys.teku.ethereum.executionclient.schema.GetPayloadV2Response; @@ -61,9 +60,10 @@ SafeFuture> newPayloadV3( Bytes32 parentBeaconBlockRoot); SafeFuture> newPayloadV4( - ExecutionPayloadV4 executionPayload, + ExecutionPayloadV3 executionPayload, List blobVersionedHashes, - Bytes32 parentBeaconBlockRoot); + Bytes32 parentBeaconBlockRoot, + Bytes32 executionRequestHash); 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 964c527cd4b..ef0600b784a 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 @@ -21,7 +21,6 @@ import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV1; import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV2; import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV3; -import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV4; import tech.pegasys.teku.ethereum.executionclient.schema.ForkChoiceStateV1; import tech.pegasys.teku.ethereum.executionclient.schema.ForkChoiceUpdatedResult; import tech.pegasys.teku.ethereum.executionclient.schema.GetPayloadV2Response; @@ -109,11 +108,17 @@ public SafeFuture> newPayloadV3( @Override public SafeFuture> newPayloadV4( - final ExecutionPayloadV4 executionPayload, + final ExecutionPayloadV3 executionPayload, final List blobVersionedHashes, - final Bytes32 parentBeaconBlockRoot) { + final Bytes32 parentBeaconBlockRoot, + final Bytes32 executionRequestHash) { return taskQueue.queueTask( - () -> delegate.newPayloadV4(executionPayload, blobVersionedHashes, parentBeaconBlockRoot)); + () -> + delegate.newPayloadV4( + executionPayload, + blobVersionedHashes, + parentBeaconBlockRoot, + executionRequestHash)); } @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 250ddfcc8f9..8a72db49295 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 @@ -19,7 +19,7 @@ import org.apache.tuweni.bytes.Bytes32; import tech.pegasys.teku.ethereum.executionclient.ExecutionEngineClient; import tech.pegasys.teku.ethereum.executionclient.response.ResponseUnwrapper; -import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV4; +import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV3; import tech.pegasys.teku.ethereum.executionclient.schema.PayloadStatusV1; import tech.pegasys.teku.infrastructure.async.SafeFuture; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload; @@ -51,18 +51,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); LOG.trace( - "Calling {}(executionPayload={}, blobVersionedHashes={}, parentBeaconBlockRoot={})", + "Calling {}(executionPayload={}, blobVersionedHashes={}, parentBeaconBlockRoot={}, executionRequestHash={})", getVersionedName(), executionPayload, blobVersionedHashes, - parentBeaconBlockRoot); + parentBeaconBlockRoot, + executionRequestHash); - final ExecutionPayloadV4 executionPayloadV4 = - ExecutionPayloadV4.fromInternalExecutionPayload(executionPayload); + final ExecutionPayloadV3 executionPayloadV3 = + ExecutionPayloadV3.fromInternalExecutionPayload(executionPayload); return executionEngineClient - .newPayloadV4(executionPayloadV4, blobVersionedHashes, parentBeaconBlockRoot) + .newPayloadV4( + executionPayloadV3, blobVersionedHashes, parentBeaconBlockRoot, executionRequestHash) .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 f45056c92a0..b7a17765912 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 @@ -23,7 +23,6 @@ import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV1; import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV2; import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV3; -import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV4; import tech.pegasys.teku.ethereum.executionclient.schema.ForkChoiceStateV1; import tech.pegasys.teku.ethereum.executionclient.schema.ForkChoiceUpdatedResult; import tech.pegasys.teku.ethereum.executionclient.schema.GetPayloadV2Response; @@ -139,11 +138,14 @@ public SafeFuture> newPayloadV3( @Override public SafeFuture> newPayloadV4( - final ExecutionPayloadV4 executionPayload, + final ExecutionPayloadV3 executionPayload, final List blobVersionedHashes, - final Bytes32 parentBeaconBlockRoot) { + final Bytes32 parentBeaconBlockRoot, + final Bytes32 executionRequestHash) { return countRequest( - () -> delegate.newPayloadV4(executionPayload, blobVersionedHashes, parentBeaconBlockRoot), + () -> + delegate.newPayloadV4( + executionPayload, blobVersionedHashes, parentBeaconBlockRoot, executionRequestHash), NEW_PAYLOAD_V4_METHOD); } 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 f5550f60b1e..0dd296f366c 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 @@ -31,7 +31,6 @@ import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV1; import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV2; import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV3; -import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV4; import tech.pegasys.teku.ethereum.executionclient.schema.ForkChoiceStateV1; import tech.pegasys.teku.ethereum.executionclient.schema.ForkChoiceUpdatedResult; import tech.pegasys.teku.ethereum.executionclient.schema.GetPayloadV2Response; @@ -176,16 +175,20 @@ public SafeFuture> newPayloadV3( @Override public SafeFuture> newPayloadV4( - final ExecutionPayloadV4 executionPayload, + final ExecutionPayloadV3 executionPayload, final List blobVersionedHashes, - final Bytes32 parentBeaconBlockRoot) { + final Bytes32 parentBeaconBlockRoot, + final Bytes32 executionRequestHash) { final List expectedBlobVersionedHashes = blobVersionedHashes.stream().map(VersionedHash::toHexString).toList(); final Request web3jRequest = new Request<>( "engine_newPayloadV4", list( - executionPayload, expectedBlobVersionedHashes, parentBeaconBlockRoot.toHexString()), + executionPayload, + expectedBlobVersionedHashes, + parentBeaconBlockRoot.toHexString(), + executionRequestHash.toHexString()), 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/EngineNewPayloadV4Test.java b/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineNewPayloadV4Test.java index c27ea6f9cc6..524875313a9 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 @@ -29,7 +29,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import tech.pegasys.teku.ethereum.executionclient.ExecutionEngineClient; -import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV4; +import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV3; import tech.pegasys.teku.ethereum.executionclient.schema.PayloadStatusV1; import tech.pegasys.teku.ethereum.executionclient.schema.Response; import tech.pegasys.teku.infrastructure.async.SafeFuture; @@ -71,14 +71,58 @@ public void executionPayloadParamIsRequired() { verifyNoInteractions(executionEngineClient); } + @Test + public void blobVersionedHashesParamIsRequired() { + final JsonRpcRequestParams params = + new JsonRpcRequestParams.Builder().add(dataStructureUtil.randomExecutionPayload()).build(); + + assertThatThrownBy(() -> jsonRpcMethod.execute(params)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Missing required parameter at index 1"); + + verifyNoInteractions(executionEngineClient); + } + + @Test + public void parentBeaconBlockRootParamIsRequired() { + final JsonRpcRequestParams params = + new JsonRpcRequestParams.Builder() + .add(dataStructureUtil.randomExecutionPayload()) + .add(dataStructureUtil.randomVersionedHashes(3)) + .build(); + + assertThatThrownBy(() -> jsonRpcMethod.execute(params)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Missing required parameter at index 2"); + + verifyNoInteractions(executionEngineClient); + } + + @Test + public void executionRequestHashParamIsRequired() { + final JsonRpcRequestParams params = + new JsonRpcRequestParams.Builder() + .add(dataStructureUtil.randomExecutionPayload()) + .add(dataStructureUtil.randomVersionedHashes(3)) + .add(dataStructureUtil.randomBytes32()) + .build(); + + assertThatThrownBy(() -> jsonRpcMethod.execute(params)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Missing required parameter at index 3"); + + verifyNoInteractions(executionEngineClient); + } + @Test 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 String errorResponseFromClient = "error!"; - when(executionEngineClient.newPayloadV4(any(), any(), any())) + when(executionEngineClient.newPayloadV4(any(), any(), any(), any())) .thenReturn(dummyFailedResponse(errorResponseFromClient)); final JsonRpcRequestParams params = @@ -86,6 +130,7 @@ public void shouldReturnFailedExecutionWhenEngineClientRequestFails() { .add(executionPayload) .add(blobVersionedHashes) .add(parentBeaconBlockRoot) + .add(executionRequestHash) .build(); assertThat(jsonRpcMethod.execute(params)) @@ -94,19 +139,23 @@ public void shouldReturnFailedExecutionWhenEngineClientRequestFails() { } @Test - public void shouldCallNewPayloadV4WithExecutionPayloadV4AndBlobVersionedHashes() { + 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 ExecutionPayloadV4 executionPayloadV4 = - ExecutionPayloadV4.fromInternalExecutionPayload(executionPayload); - assertThat(executionPayloadV4).isExactlyInstanceOf(ExecutionPayloadV4.class); + final ExecutionPayloadV3 executionPayloadV3 = + ExecutionPayloadV3.fromInternalExecutionPayload(executionPayload); + assertThat(executionPayloadV3).isExactlyInstanceOf(ExecutionPayloadV3.class); jsonRpcMethod = new EngineNewPayloadV4(executionEngineClient); when(executionEngineClient.newPayloadV4( - executionPayloadV4, blobVersionedHashes, parentBeaconBlockRoot)) + eq(executionPayloadV3), + eq(blobVersionedHashes), + eq(parentBeaconBlockRoot), + eq(executionRequestHash))) .thenReturn(dummySuccessfulResponse()); final JsonRpcRequestParams params = @@ -114,12 +163,17 @@ public void shouldCallNewPayloadV4WithExecutionPayloadV4AndBlobVersionedHashes() .add(executionPayload) .add(blobVersionedHashes) .add(parentBeaconBlockRoot) + .add(executionRequestHash) .build(); assertThat(jsonRpcMethod.execute(params)).isCompleted(); verify(executionEngineClient) - .newPayloadV4(eq(executionPayloadV4), eq(blobVersionedHashes), eq(parentBeaconBlockRoot)); + .newPayloadV4( + eq(executionPayloadV3), + eq(blobVersionedHashes), + eq(parentBeaconBlockRoot), + eq(executionRequestHash)); verifyNoMoreInteractions(executionEngineClient); } diff --git a/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/ExecutionClientHandler.java b/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/ExecutionClientHandler.java index 9c8290fd1d6..41bb13f2b66 100644 --- a/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/ExecutionClientHandler.java +++ b/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/ExecutionClientHandler.java @@ -41,7 +41,7 @@ SafeFuture engineForkChoiceUpdated( SafeFuture engineGetPayload( ExecutionPayloadContext executionPayloadContext, UInt64 slot); - SafeFuture engineNewPayload(NewPayloadRequest newPayloadRequest); + SafeFuture engineNewPayload(NewPayloadRequest newPayloadRequest, UInt64 slot); SafeFuture> engineGetClientVersion(ClientVersion clientVersion); } 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 301d4d46ca0..a7e082cafd1 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 @@ -100,17 +100,21 @@ public SafeFuture engineGetPayload( } @Override - public SafeFuture engineNewPayload(final NewPayloadRequest newPayloadRequest) { + public SafeFuture engineNewPayload( + final NewPayloadRequest newPayloadRequest, final UInt64 slot) { final ExecutionPayload executionPayload = newPayloadRequest.getExecutionPayload(); final JsonRpcRequestParams.Builder paramsBuilder = new JsonRpcRequestParams.Builder() .add(executionPayload) .addOptional(newPayloadRequest.getVersionedHashes()) - .addOptional(newPayloadRequest.getParentBeaconBlockRoot()); + .addOptional(newPayloadRequest.getParentBeaconBlockRoot()) + .addOptional(newPayloadRequest.getExecutionRequestsHash()); return engineMethodsResolver .getMethod( - EngineApiMethod.ENGINE_NEW_PAYLOAD, executionPayload::getMilestone, PayloadStatus.class) + EngineApiMethod.ENGINE_NEW_PAYLOAD, + () -> spec.atSlot(slot).getMilestone(), + PayloadStatus.class) .execute(paramsBuilder.build()); } diff --git a/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/ExecutionLayerManagerImpl.java b/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/ExecutionLayerManagerImpl.java index 3dad1c3b220..1c44c9c5e48 100644 --- a/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/ExecutionLayerManagerImpl.java +++ b/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/ExecutionLayerManagerImpl.java @@ -207,9 +207,10 @@ private SafeFuture engineGetPayload( } @Override - public SafeFuture engineNewPayload(final NewPayloadRequest newPayloadRequest) { + public SafeFuture engineNewPayload( + final NewPayloadRequest newPayloadRequest, final UInt64 slot) { LOG.trace("calling engineNewPayload(newPayloadRequest={})", newPayloadRequest); - return executionClientHandler.engineNewPayload(newPayloadRequest); + return executionClientHandler.engineNewPayload(newPayloadRequest, slot); } @Override diff --git a/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/BellatrixExecutionClientHandlerTest.java b/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/BellatrixExecutionClientHandlerTest.java index 96e11434079..8685323e91f 100644 --- a/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/BellatrixExecutionClientHandlerTest.java +++ b/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/BellatrixExecutionClientHandlerTest.java @@ -78,7 +78,7 @@ void engineNewPayload_shouldCallNewPayloadV1() { new PayloadStatusV1( ExecutionPayloadStatus.ACCEPTED, dataStructureUtil.randomBytes32(), null))); when(executionEngineClient.newPayloadV1(payloadV1)).thenReturn(dummyResponse); - handler.engineNewPayload(newPayloadRequest); + handler.engineNewPayload(newPayloadRequest, UInt64.ZERO); verify(executionEngineClient).newPayloadV1(payloadV1); } diff --git a/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/CapellaExecutionClientHandlerTest.java b/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/CapellaExecutionClientHandlerTest.java index 3b20b22790d..7ff06867007 100644 --- a/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/CapellaExecutionClientHandlerTest.java +++ b/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/CapellaExecutionClientHandlerTest.java @@ -89,7 +89,8 @@ void engineNewPayload_shouldCallNewPayloadV2() { new PayloadStatusV1( ExecutionPayloadStatus.ACCEPTED, dataStructureUtil.randomBytes32(), null))); when(executionEngineClient.newPayloadV2(payloadV2)).thenReturn(dummyResponse); - final SafeFuture future = handler.engineNewPayload(newPayloadRequest); + final SafeFuture future = + handler.engineNewPayload(newPayloadRequest, UInt64.ZERO); verify(executionEngineClient).newPayloadV2(payloadV2); assertThat(future).isCompleted(); } diff --git a/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/DenebExecutionClientHandlerTest.java b/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/DenebExecutionClientHandlerTest.java index af50e6cecfe..415875b9746 100644 --- a/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/DenebExecutionClientHandlerTest.java +++ b/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/DenebExecutionClientHandlerTest.java @@ -96,7 +96,8 @@ void engineNewPayload_shouldCallNewPayloadV3() { ExecutionPayloadStatus.ACCEPTED, dataStructureUtil.randomBytes32(), null))); when(executionEngineClient.newPayloadV3(payloadV3, versionedHashes, parentBeaconBlockRoot)) .thenReturn(dummyResponse); - final SafeFuture future = handler.engineNewPayload(newPayloadRequest); + final SafeFuture future = + handler.engineNewPayload(newPayloadRequest, UInt64.ZERO); verify(executionEngineClient).newPayloadV3(payloadV3, versionedHashes, parentBeaconBlockRoot); assertThat(future).isCompleted(); } 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 0f67f059f8a..31058fbf262 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 @@ -14,6 +14,7 @@ package tech.pegasys.teku.ethereum.executionlayer; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -23,9 +24,9 @@ import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt256; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import tech.pegasys.teku.ethereum.executionclient.schema.BlobsBundleV1; +import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV3; import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV4; import tech.pegasys.teku.ethereum.executionclient.schema.ForkChoiceStateV1; import tech.pegasys.teku.ethereum.executionclient.schema.ForkChoiceUpdatedResult; @@ -48,7 +49,6 @@ import tech.pegasys.teku.spec.logic.versions.deneb.types.VersionedHash; import tech.pegasys.teku.spec.util.DataStructureUtil; -@Disabled("Waiting for https://github.com/Consensys/teku/issues/8620") public class ElectraExecutionClientHandlerTest extends ExecutionHandlerClientTest { @BeforeEach @@ -86,20 +86,32 @@ void engineGetPayload_shouldCallGetPayloadV4() throws ExecutionException, Interr void engineNewPayload_shouldCallNewPayloadV4() { final ExecutionClientHandler handler = getHandler(); final ExecutionPayload payload = dataStructureUtil.randomExecutionPayload(); - final Bytes32 parentBeaconBlockRoot = dataStructureUtil.randomBytes32(); final List versionedHashes = dataStructureUtil.randomVersionedHashes(3); + final Bytes32 parentBeaconBlockRoot = dataStructureUtil.randomBytes32(); + final Bytes32 executionRequestsHash = dataStructureUtil.randomBytes32(); final NewPayloadRequest newPayloadRequest = - new NewPayloadRequest(payload, versionedHashes, parentBeaconBlockRoot); - final ExecutionPayloadV4 payloadV4 = ExecutionPayloadV4.fromInternalExecutionPayload(payload); + new NewPayloadRequest( + payload, versionedHashes, parentBeaconBlockRoot, executionRequestsHash); + final ExecutionPayloadV3 payloadV3 = ExecutionPayloadV3.fromInternalExecutionPayload(payload); final SafeFuture> dummyResponse = SafeFuture.completedFuture( new Response<>( new PayloadStatusV1( ExecutionPayloadStatus.ACCEPTED, dataStructureUtil.randomBytes32(), null))); - when(executionEngineClient.newPayloadV4(payloadV4, versionedHashes, parentBeaconBlockRoot)) + when(executionEngineClient.newPayloadV4( + eq(payloadV3), + eq(versionedHashes), + eq(parentBeaconBlockRoot), + eq(executionRequestsHash))) .thenReturn(dummyResponse); - final SafeFuture future = handler.engineNewPayload(newPayloadRequest); - verify(executionEngineClient).newPayloadV4(payloadV4, versionedHashes, parentBeaconBlockRoot); + final SafeFuture future = + handler.engineNewPayload(newPayloadRequest, UInt64.ZERO); + verify(executionEngineClient) + .newPayloadV4( + eq(payloadV3), + eq(versionedHashes), + eq(parentBeaconBlockRoot), + eq(executionRequestsHash)); assertThat(future).isCompleted(); } 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 eb2ccc740b2..e8a112eac9f 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 @@ -25,11 +25,13 @@ public class NewPayloadRequest { private final ExecutionPayload executionPayload; private final Optional> versionedHashes; private final Optional parentBeaconBlockRoot; + private final Optional executionRequestsHash; public NewPayloadRequest(final ExecutionPayload executionPayload) { this.executionPayload = executionPayload; this.versionedHashes = Optional.empty(); this.parentBeaconBlockRoot = Optional.empty(); + this.executionRequestsHash = Optional.empty(); } public NewPayloadRequest( @@ -39,6 +41,18 @@ public NewPayloadRequest( this.executionPayload = executionPayload; this.versionedHashes = Optional.of(versionedHashes); this.parentBeaconBlockRoot = Optional.of(parentBeaconBlockRoot); + this.executionRequestsHash = Optional.empty(); + } + + public NewPayloadRequest( + final ExecutionPayload executionPayload, + final List versionedHashes, + final Bytes32 parentBeaconBlockRoot, + final Bytes32 executionRequestsHash) { + this.executionPayload = executionPayload; + this.versionedHashes = Optional.of(versionedHashes); + this.parentBeaconBlockRoot = Optional.of(parentBeaconBlockRoot); + this.executionRequestsHash = Optional.of(executionRequestsHash); } public ExecutionPayload getExecutionPayload() { @@ -53,6 +67,10 @@ public Optional getParentBeaconBlockRoot() { return parentBeaconBlockRoot; } + public Optional getExecutionRequestsHash() { + return executionRequestsHash; + } + @Override public boolean equals(final Object o) { if (this == o) { @@ -64,12 +82,14 @@ public boolean equals(final Object o) { final NewPayloadRequest that = (NewPayloadRequest) o; return Objects.equals(executionPayload, that.executionPayload) && Objects.equals(versionedHashes, that.versionedHashes) - && Objects.equals(parentBeaconBlockRoot, that.parentBeaconBlockRoot); + && Objects.equals(parentBeaconBlockRoot, that.parentBeaconBlockRoot) + && Objects.equals(executionRequestsHash, that.executionRequestsHash); } @Override public int hashCode() { - return Objects.hash(executionPayload, versionedHashes, parentBeaconBlockRoot); + return Objects.hash( + executionPayload, versionedHashes, parentBeaconBlockRoot, executionRequestsHash); } @Override @@ -78,6 +98,7 @@ public String toString() { .add("executionPayload", executionPayload) .add("versionedHashes", versionedHashes) .add("parentBeaconBlockRoot", parentBeaconBlockRoot) + .add("executionRequestsHash", executionRequestsHash) .toString(); } } diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/executionlayer/ExecutionLayerChannel.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/executionlayer/ExecutionLayerChannel.java index 77ec790fa06..5daaceb026e 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/executionlayer/ExecutionLayerChannel.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/executionlayer/ExecutionLayerChannel.java @@ -66,7 +66,7 @@ public SafeFuture engineGetPayload( @Override public SafeFuture engineNewPayload( - final NewPayloadRequest newPayloadRequest) { + final NewPayloadRequest newPayloadRequest, final UInt64 slot) { return SafeFuture.completedFuture(PayloadStatus.SYNCING); } @@ -111,7 +111,8 @@ SafeFuture engineForkChoiceUpdated( ForkChoiceState forkChoiceState, Optional payloadBuildingAttributes); - SafeFuture engineNewPayload(NewPayloadRequest newPayloadRequest); + SafeFuture engineNewPayload( + NewPayloadRequest newPayloadRequest, final UInt64 slot); SafeFuture> engineGetClientVersion(ClientVersion clientVersion); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/executionlayer/ExecutionLayerChannelStub.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/executionlayer/ExecutionLayerChannelStub.java index f1777120e15..203e1a63222 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/executionlayer/ExecutionLayerChannelStub.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/executionlayer/ExecutionLayerChannelStub.java @@ -325,7 +325,8 @@ public SafeFuture engineGetPayload( } @Override - public SafeFuture engineNewPayload(final NewPayloadRequest newPayloadRequest) { + public SafeFuture engineNewPayload( + final NewPayloadRequest newPayloadRequest, final UInt64 slot) { offlineCheck(); final ExecutionPayload executionPayload = newPayloadRequest.getExecutionPayload(); diff --git a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoicePayloadExecutor.java b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoicePayloadExecutor.java index 85fbb28a3e7..0aef2b68f04 100644 --- a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoicePayloadExecutor.java +++ b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoicePayloadExecutor.java @@ -71,11 +71,10 @@ public boolean optimisticallyExecute( // because it checks the parentRoot matches return true; } - result = Optional.of( executionLayer - .engineNewPayload(payloadToExecute) + .engineNewPayload(payloadToExecute, block.getSlot()) .thenCompose( result -> { if (result.hasValidStatus()) { diff --git a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/block/BlockManagerTest.java b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/block/BlockManagerTest.java index c27d1abfb7e..0753bb160d8 100644 --- a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/block/BlockManagerTest.java +++ b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/block/BlockManagerTest.java @@ -658,7 +658,7 @@ void onImportBlock_shouldImportWithBroadcastValidationCompletedWhileStillImporti // let's delay EL so importResult SafeFuture doesn't complete final SafeFuture payloadStatusSafeFuture = new SafeFuture<>(); - doReturn(payloadStatusSafeFuture).when(executionLayer).engineNewPayload(any()); + doReturn(payloadStatusSafeFuture).when(executionLayer).engineNewPayload(any(), any()); final Optional preImportHead = localRecentChainData.getChainHead(); diff --git a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoiceNotifierTest.java b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoiceNotifierTest.java index 968e81c4781..31034f62e4e 100644 --- a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoiceNotifierTest.java +++ b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoiceNotifierTest.java @@ -151,7 +151,7 @@ void setUp( when(executionLayerChannel.builderRegisterValidators(any(), any())) .thenReturn(SafeFuture.COMPLETE); - when(executionLayerChannel.engineNewPayload(any())) + when(executionLayerChannel.engineNewPayload(any(), any())) .thenReturn(SafeFuture.completedFuture(PayloadStatus.VALID)); when(executionLayerChannel.engineForkChoiceUpdated(any(), any())) .thenReturn( diff --git a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoicePayloadExecutorTest.java b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoicePayloadExecutorTest.java index 32c4e6dc82a..13e4818e9ed 100644 --- a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoicePayloadExecutorTest.java +++ b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoicePayloadExecutorTest.java @@ -28,6 +28,7 @@ import org.junit.jupiter.api.Test; import tech.pegasys.teku.bls.BLSSignatureVerifier; import tech.pegasys.teku.infrastructure.async.SafeFuture; +import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.TestSpecFactory; import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock; @@ -74,14 +75,14 @@ public static void resetSession() { @BeforeEach void setUp() { - when(executionLayer.engineNewPayload(any())).thenReturn(executionResult); + when(executionLayer.engineNewPayload(any(), any())).thenReturn(executionResult); } @Test void optimisticallyExecute_shouldSendToExecutionEngineAndReturnTrue() { final ForkChoicePayloadExecutor payloadExecutor = createPayloadExecutor(); final boolean result = payloadExecutor.optimisticallyExecute(payloadHeader, payloadRequest); - verify(executionLayer).engineNewPayload(payloadRequest); + verify(executionLayer).engineNewPayload(payloadRequest, UInt64.ZERO); assertThat(result).isTrue(); } @@ -90,7 +91,7 @@ void optimisticallyExecute_shouldNotExecuteDefaultPayload() { final ForkChoicePayloadExecutor payloadExecutor = createPayloadExecutor(); final boolean result = payloadExecutor.optimisticallyExecute(payloadHeader, defaultPayloadRequest); - verify(executionLayer, never()).engineNewPayload(any()); + verify(executionLayer, never()).engineNewPayload(any(), any()); assertThat(result).isTrue(); assertThat(payloadExecutor.getExecutionResult()) .isCompletedWithValue(new PayloadValidationResult(PayloadStatus.VALID)); @@ -98,7 +99,7 @@ void optimisticallyExecute_shouldNotExecuteDefaultPayload() { @Test void optimisticallyExecute_shouldValidateMergeBlockWhenThisIsTheMergeBlock() { - when(executionLayer.engineNewPayload(payloadRequest)) + when(executionLayer.engineNewPayload(payloadRequest, UInt64.ZERO)) .thenReturn(SafeFuture.completedFuture(VALID)); when(executionLayer.eth1GetPowBlock(payload.getParentHash())).thenReturn(new SafeFuture<>()); final ForkChoicePayloadExecutor payloadExecutor = createPayloadExecutor(); @@ -106,14 +107,14 @@ void optimisticallyExecute_shouldValidateMergeBlockWhenThisIsTheMergeBlock() { payloadExecutor.optimisticallyExecute(defaultPayloadHeader, payloadRequest); // Should execute first and then begin validation of the transition block conditions. - verify(executionLayer).engineNewPayload(payloadRequest); + verify(executionLayer).engineNewPayload(payloadRequest, UInt64.ZERO); verify(transitionValidator).verifyTransitionBlock(defaultPayloadHeader, block); assertThat(result).isTrue(); } @Test void optimisticallyExecute_shouldReturnFailedExecutionOnMergeBlockWhenELOfflineAtExecution() { - when(executionLayer.engineNewPayload(payloadRequest)) + when(executionLayer.engineNewPayload(payloadRequest, UInt64.ZERO)) .thenReturn(SafeFuture.failedFuture(new Error())); final ForkChoicePayloadExecutor payloadExecutor = createPayloadExecutor(); final boolean execution = @@ -121,7 +122,7 @@ void optimisticallyExecute_shouldReturnFailedExecutionOnMergeBlockWhenELOfflineA // Should not attempt to validate transition conditions because execute payload failed verify(transitionValidator, never()).verifyTransitionBlock(defaultPayloadHeader, block); - verify(executionLayer).engineNewPayload(payloadRequest); + verify(executionLayer).engineNewPayload(payloadRequest, UInt64.ZERO); assertThat(execution).isTrue(); assertThat(payloadExecutor.getExecutionResult()) .isCompletedWithValueMatching(result -> result.getStatus().hasFailedExecution()); @@ -130,7 +131,7 @@ void optimisticallyExecute_shouldReturnFailedExecutionOnMergeBlockWhenELOfflineA @Test void optimisticallyExecute_shouldReturnFailedExecutionOnMergeBlockWhenELGoesOfflineAfterExecution() { - when(executionLayer.engineNewPayload(payloadRequest)) + when(executionLayer.engineNewPayload(payloadRequest, UInt64.ZERO)) .thenReturn(SafeFuture.completedFuture(VALID)); when(transitionValidator.verifyTransitionBlock(defaultPayloadHeader, block)) .thenReturn(SafeFuture.failedFuture(new Error())); @@ -139,7 +140,7 @@ void optimisticallyExecute_shouldReturnFailedExecutionOnMergeBlockWhenELOfflineA payloadExecutor.optimisticallyExecute(defaultPayloadHeader, payloadRequest); verify(transitionValidator).verifyTransitionBlock(defaultPayloadHeader, block); - verify(executionLayer).engineNewPayload(payloadRequest); + verify(executionLayer).engineNewPayload(payloadRequest, UInt64.ZERO); assertThat(execution).isTrue(); assertThat(payloadExecutor.getExecutionResult()) .isCompletedWithValueMatching(result -> result.getStatus().hasFailedExecution()); @@ -149,13 +150,13 @@ void optimisticallyExecute_shouldReturnFailedExecutionOnMergeBlockWhenELOfflineA void optimisticallyExecute_shouldNotVerifyTransitionIfExecutePayloadIsInvalid() { final PayloadStatus expectedResult = PayloadStatus.invalid(Optional.empty(), Optional.of("Nope")); - when(executionLayer.engineNewPayload(payloadRequest)) + when(executionLayer.engineNewPayload(payloadRequest, UInt64.ZERO)) .thenReturn(SafeFuture.completedFuture(expectedResult)); final ForkChoicePayloadExecutor payloadExecutor = createPayloadExecutor(); final boolean execution = payloadExecutor.optimisticallyExecute(defaultPayloadHeader, payloadRequest); - verify(executionLayer).engineNewPayload(payloadRequest); + verify(executionLayer).engineNewPayload(payloadRequest, UInt64.ZERO); verify(transitionValidator, never()).verifyTransitionBlock(defaultPayloadHeader, block); assertThat(execution).isTrue(); assertThat(payloadExecutor.getExecutionResult()) diff --git a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoiceTest.java b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoiceTest.java index e57ccfd501e..6273128322b 100644 --- a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoiceTest.java +++ b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/forkchoice/ForkChoiceTest.java @@ -358,7 +358,7 @@ void onBlock_consensusValidationShouldReturnRegardlessExecutionPayloadValidation // let's prepare a mocked EL with lazy newPayload executionLayer = mock(ExecutionLayerChannelStub.class); final SafeFuture payloadStatusSafeFuture = new SafeFuture<>(); - when(executionLayer.engineNewPayload(any())).thenReturn(payloadStatusSafeFuture); + when(executionLayer.engineNewPayload(any(), any())).thenReturn(payloadStatusSafeFuture); // let's import a valid consensus block final SafeFuture importResult =