From a32bcff2e6a5498eb23c157e2db311f09be22b56 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Thu, 23 Feb 2023 11:20:35 -0800 Subject: [PATCH 1/5] rebase on origin/main Signed-off-by: garyschulte --- .../besu/ethereum/api/jsonrpc/RpcMethod.java | 2 +- .../engine/EnginePreparePayloadDebug.java | 80 +++++++++++++++++++ .../EnginePreparePayloadParameter.java | 59 ++++++++++++++ .../results/EnginePreparePayloadResult.java | 34 ++++++++ .../ExecutionEngineJsonRpcMethods.java | 5 +- 5 files changed, 178 insertions(+), 2 deletions(-) create mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java create mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePreparePayloadParameter.java create mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EnginePreparePayloadResult.java diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java index 31f1e99c20f..bdecee7c9e9 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java @@ -58,7 +58,7 @@ public enum RpcMethod { ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1("engine_getPayloadBodiesByHashV1"), ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1("engine_getPayloadBodiesByRangeV1"), ENGINE_EXCHANGE_CAPABILITIES("engine_exchangeCapabilities"), - + ENGINE_PREPARE_PAYLOAD_DEBUG("engine_preparePayload_debug"), PRIV_CALL("priv_call"), PRIV_GET_PRIVATE_TRANSACTION("priv_getPrivateTransaction"), PRIV_GET_TRANSACTION_COUNT("priv_getTransactionCount"), diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java new file mode 100644 index 00000000000..927bc71f07d --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java @@ -0,0 +1,80 @@ +/* + * Copyright ConsenSys AG. + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; + +import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator; +import org.hyperledger.besu.ethereum.ProtocolContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EnginePreparePayloadParameter; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EnginePreparePayloadResult; + +import java.util.Collections; +import java.util.Optional; + +import io.vertx.core.Vertx; + +public class EnginePreparePayloadDebug extends ExecutionEngineJsonRpcMethod { + private final MergeMiningCoordinator mergeCoordinator; + + public EnginePreparePayloadDebug( + final Vertx vertx, + final ProtocolContext protocolContext, + final EngineCallListener engineCallListener, + final MergeMiningCoordinator mergeCoordinator) { + super(vertx, protocolContext, engineCallListener); + this.mergeCoordinator = mergeCoordinator; + } + + @Override + public String getName() { + return RpcMethod.ENGINE_PREPARE_PAYLOAD_DEBUG.getMethodName(); + } + + @Override + public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) { + final EnginePreparePayloadParameter enginePreparePayloadParameter = + requestContext.getRequiredParameter(0, EnginePreparePayloadParameter.class); + + // TODO: respond with error if we're syncing + + return enginePreparePayloadParameter + .getParentHash() + .map(header -> protocolContext.getBlockchain().getBlockHeader(header)) + .orElseGet(() -> Optional.of(protocolContext.getBlockchain().getChainHeadHeader())) + .map( + parentHeader -> + new JsonRpcSuccessResponse( + requestContext.getRequest().getId(), + new EnginePreparePayloadResult( + mergeCoordinator.preparePayload( + parentHeader, + enginePreparePayloadParameter + .getTimestamp() + .orElse(parentHeader.getTimestamp() + 1L), + enginePreparePayloadParameter.getPrevRandao(), + enginePreparePayloadParameter.getFeeRecipient(), + Optional.of(Collections.emptyList()))))) + .orElseGet( + () -> + new JsonRpcErrorResponse( + requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS)); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePreparePayloadParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePreparePayloadParameter.java new file mode 100644 index 00000000000..1339c0e81e4 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePreparePayloadParameter.java @@ -0,0 +1,59 @@ +/* + * Copyright ConsenSys AG. + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; + +import java.util.Optional; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.tuweni.bytes.Bytes32; + +public class EnginePreparePayloadParameter { + private final Optional parentHash; + private final Address feeRecipient; + private final Bytes32 prevRandao; + private final Optional timestamp; + + @JsonCreator + public EnginePreparePayloadParameter( + @JsonProperty("parentHash") final Optional parentHash, + @JsonProperty("feeRecipient") final Address feeRecipient, + @JsonProperty("timestamp") final Optional timestamp, + @JsonProperty("prevRandao") final String prevRandao) { + this.parentHash = parentHash; + this.feeRecipient = feeRecipient; + this.timestamp = timestamp.map(UnsignedLongParameter::getValue); + this.prevRandao = Bytes32.fromHexStringLenient(prevRandao); + } + + public Optional getParentHash() { + return parentHash; + } + + public Address getFeeRecipient() { + return feeRecipient; + } + + public Optional getTimestamp() { + return timestamp; + } + + public Bytes32 getPrevRandao() { + return prevRandao; + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EnginePreparePayloadResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EnginePreparePayloadResult.java new file mode 100644 index 00000000000..2983356e908 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EnginePreparePayloadResult.java @@ -0,0 +1,34 @@ +/* + * Copyright ConsenSys AG. + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; + +import org.hyperledger.besu.consensus.merge.blockcreation.PayloadIdentifier; + +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonPropertyOrder({"payloadId"}) +public class EnginePreparePayloadResult { + private final PayloadIdentifier payloadId; + + public EnginePreparePayloadResult(final PayloadIdentifier payloadId) { + this.payloadId = payloadId; + } + + @JsonGetter(value = "payloadId") + public String getNumber() { + return payloadId.toShortHexString(); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java index ccf50334784..abe82b8e399 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java @@ -28,6 +28,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetPayloadV2; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineNewPayloadV1; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineNewPayloadV2; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EnginePreparePayloadDebug; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineQosTimer; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; @@ -120,7 +121,9 @@ protected Map create() { consensusEngineServer, protocolContext, blockResultFactory, engineQosTimer), new EngineGetPayloadBodiesByRangeV1( consensusEngineServer, protocolContext, blockResultFactory, engineQosTimer), - new EngineExchangeCapabilities(consensusEngineServer, protocolContext, engineQosTimer)); + new EngineExchangeCapabilities(consensusEngineServer, protocolContext, engineQosTimer), + new EnginePreparePayloadDebug( + consensusEngineServer, protocolContext, engineQosTimer, mergeCoordinator.get())); } else { return mapOf( new EngineExchangeTransitionConfiguration( From b5d835170ebc624d135a776e68299a82cdb4fea7 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Tue, 18 Apr 2023 20:15:02 -0700 Subject: [PATCH 2/5] address feedback, add withdrawals Signed-off-by: garyschulte --- .../methods/engine/EnginePreparePayloadDebug.java | 14 +++++++++++--- .../parameters/EnginePreparePayloadParameter.java | 12 ++++++++++-- .../results/EnginePreparePayloadResult.java | 2 +- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java index 927bc71f07d..1977bcc7b14 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java @@ -1,5 +1,5 @@ /* - * Copyright ConsenSys AG. + * Copyright contributors to Hyperledger Besu * * 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 @@ -14,19 +14,23 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; +import static java.util.stream.Collectors.toList; + import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EnginePreparePayloadParameter; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EnginePreparePayloadResult; +import org.hyperledger.besu.ethereum.core.Withdrawal; -import java.util.Collections; +import java.util.List; import java.util.Optional; import io.vertx.core.Vertx; @@ -54,6 +58,10 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) requestContext.getRequiredParameter(0, EnginePreparePayloadParameter.class); // TODO: respond with error if we're syncing + final List withdrawals = + enginePreparePayloadParameter.getWithdrawals().stream() + .map(WithdrawalParameter::toWithdrawal) + .collect(toList()); return enginePreparePayloadParameter .getParentHash() @@ -71,7 +79,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) .orElse(parentHeader.getTimestamp() + 1L), enginePreparePayloadParameter.getPrevRandao(), enginePreparePayloadParameter.getFeeRecipient(), - Optional.of(Collections.emptyList()))))) + Optional.of(withdrawals))))) .orElseGet( () -> new JsonRpcErrorResponse( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePreparePayloadParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePreparePayloadParameter.java index 1339c0e81e4..bc5c04d149e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePreparePayloadParameter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePreparePayloadParameter.java @@ -1,5 +1,5 @@ /* - * Copyright ConsenSys AG. + * Copyright contributors to Hyperledger Besu * * 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 @@ -17,6 +17,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; +import java.util.List; import java.util.Optional; import com.fasterxml.jackson.annotation.JsonCreator; @@ -28,17 +29,20 @@ public class EnginePreparePayloadParameter { private final Address feeRecipient; private final Bytes32 prevRandao; private final Optional timestamp; + final List withdrawals; @JsonCreator public EnginePreparePayloadParameter( @JsonProperty("parentHash") final Optional parentHash, @JsonProperty("feeRecipient") final Address feeRecipient, @JsonProperty("timestamp") final Optional timestamp, - @JsonProperty("prevRandao") final String prevRandao) { + @JsonProperty("prevRandao") final String prevRandao, + @JsonProperty("withdrawals") final List withdrawals) { this.parentHash = parentHash; this.feeRecipient = feeRecipient; this.timestamp = timestamp.map(UnsignedLongParameter::getValue); this.prevRandao = Bytes32.fromHexStringLenient(prevRandao); + this.withdrawals = withdrawals; } public Optional getParentHash() { @@ -56,4 +60,8 @@ public Optional getTimestamp() { public Bytes32 getPrevRandao() { return prevRandao; } + + public List getWithdrawals() { + return withdrawals; + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EnginePreparePayloadResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EnginePreparePayloadResult.java index 2983356e908..9beeaee022d 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EnginePreparePayloadResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EnginePreparePayloadResult.java @@ -1,5 +1,5 @@ /* - * Copyright ConsenSys AG. + * Copyright contributors to Hyperledger Besu * * 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 From c845900347d4287522dac50e8e16bd731a30d0ab Mon Sep 17 00:00:00 2001 From: garyschulte Date: Wed, 19 Apr 2023 10:26:43 -0700 Subject: [PATCH 3/5] filter debug payload from engine capabilities, add a syncing response, unit test coverage Signed-off-by: garyschulte --- .../engine/EngineExchangeCapabilities.java | 2 + .../engine/EnginePreparePayloadDebug.java | 50 +++++++----- .../results/EnginePreparePayloadResult.java | 18 ++++- .../engine/EnginePreparePayloadDebugTest.java | 80 +++++++++++++++++++ 4 files changed, 125 insertions(+), 25 deletions(-) create mode 100644 ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebugTest.java diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeCapabilities.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeCapabilities.java index 3e4ca2d0a99..f59681a3854 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeCapabilities.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeCapabilities.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod.ENGINE_EXCHANGE_CAPABILITIES; +import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod.ENGINE_PREPARE_PAYLOAD_DEBUG; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; @@ -61,6 +62,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) Stream.of(RpcMethod.values()) .filter(e -> e.getMethodName().startsWith("engine_")) .filter(e -> !e.equals(ENGINE_EXCHANGE_CAPABILITIES)) + .filter(e -> !e.equals(ENGINE_PREPARE_PAYLOAD_DEBUG)) .map(RpcMethod::getMethodName) .collect(Collectors.toList()); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java index 1977bcc7b14..49c7863766d 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java @@ -15,8 +15,11 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; import static java.util.stream.Collectors.toList; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.SYNCING; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.VALID; import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator; +import org.hyperledger.besu.consensus.merge.blockcreation.PayloadIdentifier; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; @@ -33,6 +36,7 @@ import java.util.List; import java.util.Optional; +import graphql.VisibleForTesting; import io.vertx.core.Vertx; public class EnginePreparePayloadDebug extends ExecutionEngineJsonRpcMethod { @@ -57,32 +61,36 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) final EnginePreparePayloadParameter enginePreparePayloadParameter = requestContext.getRequiredParameter(0, EnginePreparePayloadParameter.class); - // TODO: respond with error if we're syncing + final var requestId = requestContext.getRequest().getId(); + + if (mergeContext.get().isSyncing()) { + return new JsonRpcSuccessResponse(requestId, new EnginePreparePayloadResult(SYNCING, null)); + } + + return generatePayload(enginePreparePayloadParameter) + .map( + payloadIdentifier -> + new JsonRpcSuccessResponse( + requestId, new EnginePreparePayloadResult(VALID, payloadIdentifier))) + .orElseGet(() -> new JsonRpcErrorResponse(requestId, JsonRpcError.INVALID_PARAMS)); + } + + @VisibleForTesting + Optional generatePayload(final EnginePreparePayloadParameter param) { final List withdrawals = - enginePreparePayloadParameter.getWithdrawals().stream() - .map(WithdrawalParameter::toWithdrawal) - .collect(toList()); + param.getWithdrawals().stream().map(WithdrawalParameter::toWithdrawal).collect(toList()); - return enginePreparePayloadParameter + return param .getParentHash() .map(header -> protocolContext.getBlockchain().getBlockHeader(header)) .orElseGet(() -> Optional.of(protocolContext.getBlockchain().getChainHeadHeader())) - .map( + .map( parentHeader -> - new JsonRpcSuccessResponse( - requestContext.getRequest().getId(), - new EnginePreparePayloadResult( - mergeCoordinator.preparePayload( - parentHeader, - enginePreparePayloadParameter - .getTimestamp() - .orElse(parentHeader.getTimestamp() + 1L), - enginePreparePayloadParameter.getPrevRandao(), - enginePreparePayloadParameter.getFeeRecipient(), - Optional.of(withdrawals))))) - .orElseGet( - () -> - new JsonRpcErrorResponse( - requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS)); + mergeCoordinator.preparePayload( + parentHeader, + param.getTimestamp().orElse(parentHeader.getTimestamp() + 1L), + param.getPrevRandao(), + param.getFeeRecipient(), + Optional.of(withdrawals))); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EnginePreparePayloadResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EnginePreparePayloadResult.java index 9beeaee022d..650ad973875 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EnginePreparePayloadResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EnginePreparePayloadResult.java @@ -15,20 +15,30 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; import org.hyperledger.besu.consensus.merge.blockcreation.PayloadIdentifier; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus; + +import java.util.Optional; import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonPropertyOrder; -@JsonPropertyOrder({"payloadId"}) +@JsonPropertyOrder({"status", "payloadId"}) public class EnginePreparePayloadResult { + private final EngineStatus status; private final PayloadIdentifier payloadId; - public EnginePreparePayloadResult(final PayloadIdentifier payloadId) { + public EnginePreparePayloadResult(final EngineStatus status, final PayloadIdentifier payloadId) { + this.status = status; this.payloadId = payloadId; } + @JsonGetter(value = "status") + public String getStatus() { + return status.name(); + } + @JsonGetter(value = "payloadId") - public String getNumber() { - return payloadId.toShortHexString(); + public String getPayloadId() { + return Optional.ofNullable(payloadId).map(PayloadIdentifier::toShortHexString).orElse(""); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebugTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebugTest.java new file mode 100644 index 00000000000..71d0fc3efaa --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebugTest.java @@ -0,0 +1,80 @@ +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.SYNCING; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.VALID; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.consensus.merge.MergeContext; +import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator; +import org.hyperledger.besu.consensus.merge.blockcreation.PayloadIdentifier; +import org.hyperledger.besu.ethereum.ProtocolContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EnginePreparePayloadParameter; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EnginePreparePayloadResult; + +import java.util.Optional; + +import io.vertx.core.Vertx; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class EnginePreparePayloadDebugTest { + private static final Vertx vertx = Vertx.vertx(); + EnginePreparePayloadDebug method; + @Mock private ProtocolContext protocolContext; + @Mock private EngineCallListener engineCallListener; + @Mock private MergeMiningCoordinator mergeCoordinator; + @Mock private MergeContext mergeContext; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private JsonRpcRequestContext requestContext; + + @Mock private EnginePreparePayloadParameter param; + + @Before + public void setUp() { + when(protocolContext.safeConsensusContext(MergeContext.class)) + .thenReturn(Optional.of(mergeContext)); + when(requestContext.getRequiredParameter(0, EnginePreparePayloadParameter.class)) + .thenReturn(param); + method = + spy( + new EnginePreparePayloadDebug( + vertx, protocolContext, engineCallListener, mergeCoordinator)); + } + + @Test + public void shouldReturnSyncing() { + when(mergeContext.isSyncing()).thenReturn(true); + var resp = method.syncResponse(requestContext); + assertThat(resp).isInstanceOf(JsonRpcSuccessResponse.class); + var result = ((JsonRpcSuccessResponse) resp).getResult(); + assertThat(result).isInstanceOf(EnginePreparePayloadResult.class); + var payloadResult = (EnginePreparePayloadResult) result; + assertThat(payloadResult.getStatus()).isEqualTo(SYNCING.name()); + } + + @Test + public void shouldReturnPayloadId() { + doAnswer(__ -> Optional.of(new PayloadIdentifier(0xdeadbeefL))) + .when(method) + .generatePayload(any()); + var resp = method.syncResponse(requestContext); + assertThat(resp).isInstanceOf(JsonRpcSuccessResponse.class); + var result = ((JsonRpcSuccessResponse) resp).getResult(); + assertThat(result).isInstanceOf(EnginePreparePayloadResult.class); + var payloadResult = (EnginePreparePayloadResult) result; + assertThat(payloadResult.getStatus()).isEqualTo(VALID.name()); + assertThat(payloadResult.getPayloadId()).isEqualTo("0xdeadbeef"); + } +} From 12314e421870844bfe60f937e55766db79417d00 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Wed, 19 Apr 2023 10:42:11 -0700 Subject: [PATCH 4/5] make any/all parameters optional for debug payload Signed-off-by: garyschulte --- .../methods/engine/EnginePreparePayloadDebug.java | 10 +++++++++- .../parameters/EnginePreparePayloadParameter.java | 13 +++++++------ .../engine/EnginePreparePayloadDebugTest.java | 15 +++++++++++++-- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java index 49c7863766d..fe8f377d91b 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java @@ -59,7 +59,15 @@ public String getName() { @Override public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) { final EnginePreparePayloadParameter enginePreparePayloadParameter = - requestContext.getRequiredParameter(0, EnginePreparePayloadParameter.class); + requestContext + .getOptionalParameter(0, EnginePreparePayloadParameter.class) + .orElse( + new EnginePreparePayloadParameter( + Optional.empty(), + Optional.empty(), + Optional.empty(), + Optional.empty(), + Optional.empty())); final var requestId = requestContext.getRequest().getId(); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePreparePayloadParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePreparePayloadParameter.java index bc5c04d149e..698d3888ed4 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePreparePayloadParameter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePreparePayloadParameter.java @@ -17,6 +17,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; +import java.util.Collections; import java.util.List; import java.util.Optional; @@ -34,15 +35,15 @@ public class EnginePreparePayloadParameter { @JsonCreator public EnginePreparePayloadParameter( @JsonProperty("parentHash") final Optional parentHash, - @JsonProperty("feeRecipient") final Address feeRecipient, + @JsonProperty("feeRecipient") final Optional
feeRecipient, @JsonProperty("timestamp") final Optional timestamp, - @JsonProperty("prevRandao") final String prevRandao, - @JsonProperty("withdrawals") final List withdrawals) { + @JsonProperty("prevRandao") final Optional prevRandao, + @JsonProperty("withdrawals") final Optional> withdrawals) { this.parentHash = parentHash; - this.feeRecipient = feeRecipient; + this.feeRecipient = feeRecipient.orElse(Address.ZERO); this.timestamp = timestamp.map(UnsignedLongParameter::getValue); - this.prevRandao = Bytes32.fromHexStringLenient(prevRandao); - this.withdrawals = withdrawals; + this.prevRandao = Bytes32.fromHexStringLenient(prevRandao.orElse("deadbeef")); + this.withdrawals = withdrawals.orElse(Collections.emptyList()); } public Optional getParentHash() { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebugTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebugTest.java index 71d0fc3efaa..205d99b1941 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebugTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebugTest.java @@ -45,8 +45,8 @@ public class EnginePreparePayloadDebugTest { public void setUp() { when(protocolContext.safeConsensusContext(MergeContext.class)) .thenReturn(Optional.of(mergeContext)); - when(requestContext.getRequiredParameter(0, EnginePreparePayloadParameter.class)) - .thenReturn(param); + when(requestContext.getOptionalParameter(0, EnginePreparePayloadParameter.class)) + .thenReturn(Optional.of(param)); method = spy( new EnginePreparePayloadDebug( @@ -66,6 +66,17 @@ public void shouldReturnSyncing() { @Test public void shouldReturnPayloadId() { + checkForPayloadId(); + } + + @Test + public void shouldReturnPayloadIdWhenNoParams() { + when(requestContext.getOptionalParameter(0, EnginePreparePayloadParameter.class)) + .thenReturn(Optional.empty()); + checkForPayloadId(); + } + + private void checkForPayloadId() { doAnswer(__ -> Optional.of(new PayloadIdentifier(0xdeadbeefL))) .when(method) .generatePayload(any()); From 01f73e94f9dabf0ad49843a7f8b1dcf24a4e53cd Mon Sep 17 00:00:00 2001 From: garyschulte Date: Wed, 19 Apr 2023 10:43:44 -0700 Subject: [PATCH 5/5] spdx header Signed-off-by: garyschulte --- .../engine/EnginePreparePayloadDebugTest.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebugTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebugTest.java index 205d99b1941..c89df2fff80 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebugTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebugTest.java @@ -1,3 +1,17 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; import static org.assertj.core.api.AssertionsForClassTypes.assertThat;