From a483f79cc8b7741cb9fb0145d92307b6d5cfdc62 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Wed, 21 Dec 2022 21:53:41 +1100 Subject: [PATCH] Initial implementation of EngineGetPayloadV2 (#4833) Signed-off-by: Gabriel-Trintinalia --- .../besu/ethereum/api/jsonrpc/RpcMethod.java | 1 + ...oad.java => AbstractEngineGetPayload.java} | 34 ++-- .../methods/engine/EngineGetPayloadV1.java | 49 ++++++ .../methods/engine/EngineGetPayloadV2.java | 49 ++++++ .../internal/results/BlockResultFactory.java | 19 ++- ...ult.java => EngineGetPayloadResultV1.java} | 4 +- .../results/EngineGetPayloadResultV2.java | 155 ++++++++++++++++++ .../ExecutionEngineJsonRpcMethods.java | 11 +- ...dTest.java => EngineGetPayloadV1Test.java} | 16 +- .../engine/EngineGetPayloadV2Test.java | 127 ++++++++++++++ 10 files changed, 431 insertions(+), 34 deletions(-) rename ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/{EngineGetPayload.java => AbstractEngineGetPayload.java} (77%) create mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV1.java create mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV2.java rename ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/{EngineGetPayloadResult.java => EngineGetPayloadResultV1.java} (96%) create mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV2.java rename ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/{EngineGetPayloadTest.java => EngineGetPayloadV1Test.java} (94%) create mode 100644 ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV2Test.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 130955c7fb3..ff06bb3a828 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 @@ -47,6 +47,7 @@ public enum RpcMethod { DEBUG_GET_BAD_BLOCKS("debug_getBadBlocks"), ENGINE_GET_PAYLOAD("engine_getPayloadV1"), + ENGINE_GET_PAYLOAD_V2("engine_getPayloadV2"), ENGINE_EXECUTE_PAYLOAD("engine_executePayloadV1"), ENGINE_NEW_PAYLOAD("engine_newPayloadV1"), ENGINE_FORKCHOICE_UPDATED("engine_forkchoiceUpdatedV1"), diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayload.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayload.java similarity index 77% rename from ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayload.java rename to ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayload.java index 41daf4360ab..5f70c8f6564 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayload.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayload.java @@ -20,13 +20,11 @@ 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; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod; 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.BlockResultFactory; import org.hyperledger.besu.ethereum.core.Block; @@ -36,13 +34,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class EngineGetPayload extends ExecutionEngineJsonRpcMethod { +public abstract class AbstractEngineGetPayload extends ExecutionEngineJsonRpcMethod { private final MergeMiningCoordinator mergeMiningCoordinator; - private final BlockResultFactory blockResultFactory; - private static final Logger LOG = LoggerFactory.getLogger(EngineGetPayload.class); + protected final BlockResultFactory blockResultFactory; + private static final Logger LOG = LoggerFactory.getLogger(AbstractEngineGetPayload.class); - public EngineGetPayload( + public AbstractEngineGetPayload( final Vertx vertx, final ProtocolContext protocolContext, final MergeMiningCoordinator mergeMiningCoordinator, @@ -53,11 +51,6 @@ public EngineGetPayload( this.blockResultFactory = blockResultFactory; } - @Override - public String getName() { - return RpcMethod.ENGINE_GET_PAYLOAD.getMethodName(); - } - @Override public JsonRpcResponse syncResponse(final JsonRpcRequestContext request) { engineCallListener.executionEngineCalled(); @@ -66,21 +59,22 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext request) { mergeMiningCoordinator.finalizeProposalById(payloadId); final Optional block = mergeContext.get().retrieveBlockById(payloadId); if (block.isPresent()) { - var proposal = block.get(); - var proposalHeader = proposal.getHeader(); + final var proposal = block.get(); + final var proposalHeader = proposal.getHeader(); infoLambda( LOG, "Fetch block proposal by identifier: {}, hash: {}, number: {}, coinbase: {}, transaction count: {}", - () -> payloadId.toHexString(), - () -> proposalHeader.getHash(), - () -> proposalHeader.getNumber(), - () -> proposalHeader.getCoinbase(), + payloadId::toHexString, + proposalHeader::getHash, + proposalHeader::getNumber, + proposalHeader::getCoinbase, () -> proposal.getBody().getTransactions().size()); debugLambda(LOG, "assembledBlock {}", () -> block.map(Block::toString).get()); - return new JsonRpcSuccessResponse( - request.getRequest().getId(), - blockResultFactory.enginePayloadTransactionComplete(block.get())); + return createResponse(request, block.get()); } return new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.UNKNOWN_PAYLOAD); } + + protected abstract JsonRpcResponse createResponse( + final JsonRpcRequestContext request, final Block block); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV1.java new file mode 100644 index 00000000000..bdea602d9c4 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV1.java @@ -0,0 +1,49 @@ +/* + * 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 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.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; +import org.hyperledger.besu.ethereum.core.Block; + +import io.vertx.core.Vertx; + +public class EngineGetPayloadV1 extends AbstractEngineGetPayload { + + public EngineGetPayloadV1( + final Vertx vertx, + final ProtocolContext protocolContext, + final MergeMiningCoordinator mergeMiningCoordinator, + final BlockResultFactory blockResultFactory, + final EngineCallListener engineCallListener) { + super(vertx, protocolContext, mergeMiningCoordinator, blockResultFactory, engineCallListener); + } + + @Override + public String getName() { + return RpcMethod.ENGINE_GET_PAYLOAD.getMethodName(); + } + + @Override + protected JsonRpcResponse createResponse(final JsonRpcRequestContext request, final Block block) { + return new JsonRpcSuccessResponse( + request.getRequest().getId(), blockResultFactory.payloadTransactionCompleteV1(block)); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV2.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV2.java new file mode 100644 index 00000000000..22aadfd5b59 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV2.java @@ -0,0 +1,49 @@ +/* + * 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 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.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; +import org.hyperledger.besu.ethereum.core.Block; + +import io.vertx.core.Vertx; + +public class EngineGetPayloadV2 extends AbstractEngineGetPayload { + + public EngineGetPayloadV2( + final Vertx vertx, + final ProtocolContext protocolContext, + final MergeMiningCoordinator mergeMiningCoordinator, + final BlockResultFactory blockResultFactory, + final EngineCallListener engineCallListener) { + super(vertx, protocolContext, mergeMiningCoordinator, blockResultFactory, engineCallListener); + } + + @Override + public String getName() { + return RpcMethod.ENGINE_GET_PAYLOAD_V2.getMethodName(); + } + + @Override + protected JsonRpcResponse createResponse(final JsonRpcRequestContext request, final Block block) { + return new JsonRpcSuccessResponse( + request.getRequest().getId(), blockResultFactory.payloadTransactionCompleteV2(block)); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java index e4311753542..3ee515a448c 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java @@ -85,14 +85,29 @@ public BlockResult transactionComplete(final Block block) { block.getHeader(), txs, ommers, block.getHeader().getDifficulty(), block.calculateSize()); } - public EngineGetPayloadResult enginePayloadTransactionComplete(final Block block) { + public EngineGetPayloadResultV1 payloadTransactionCompleteV1(final Block block) { final List txs = block.getBody().getTransactions().stream() .map(TransactionEncoder::encodeOpaqueBytes) .map(Bytes::toHexString) .collect(Collectors.toList()); - return new EngineGetPayloadResult(block.getHeader(), txs); + return new EngineGetPayloadResultV1(block.getHeader(), txs); + } + + public EngineGetPayloadResultV2 payloadTransactionCompleteV2(final Block block) { + final List txs = + block.getBody().getTransactions().stream() + .map(TransactionEncoder::encodeOpaqueBytes) + .map(Bytes::toHexString) + .collect(Collectors.toList()); + + final long blockValue = calculateBlockValue(txs); + return new EngineGetPayloadResultV2(block.getHeader(), txs, Quantity.create(blockValue)); + } + + private long calculateBlockValue(final List ignored) { + return 0L; } public BlockResult transactionHash(final BlockWithMetadata blockWithMetadata) { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV1.java similarity index 96% rename from ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResult.java rename to ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV1.java index 9e827e1d8cf..0b21d15ef62 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV1.java @@ -39,7 +39,7 @@ "blockHash", "transactions" }) -public class EngineGetPayloadResult { +public class EngineGetPayloadResultV1 { protected final String blockHash; private final String parentHash; private final String feeRecipient; @@ -55,7 +55,7 @@ public class EngineGetPayloadResult { private final String baseFeePerGas; protected final List transactions; - public EngineGetPayloadResult(final BlockHeader header, final List transactions) { + public EngineGetPayloadResultV1(final BlockHeader header, final List transactions) { this.blockNumber = Quantity.create(header.getNumber()); this.blockHash = header.getHash().toString(); this.parentHash = header.getParentHash().toString(); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV2.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV2.java new file mode 100644 index 00000000000..458becbc316 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV2.java @@ -0,0 +1,155 @@ +/* + * 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.results; + +import org.hyperledger.besu.ethereum.core.BlockHeader; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.tuweni.bytes.Bytes32; + +@JsonPropertyOrder({ + "executionPayload", + "blockValue", +}) +public class EngineGetPayloadResultV2 { + protected final PayloadResult executionPayload; + private final String blockValue; + + public EngineGetPayloadResultV2( + final BlockHeader header, final List transactions, final String blockValue) { + this.executionPayload = new PayloadResult(header, transactions); + this.blockValue = blockValue; + } + + @JsonGetter(value = "executionPayload") + public PayloadResult getExecutionPayload() { + return executionPayload; + } + + @JsonGetter(value = "blockValue") + public String getBlockValue() { + return blockValue; + } + + public static class PayloadResult { + + protected final String blockHash; + private final String parentHash; + private final String feeRecipient; + private final String stateRoot; + private final String receiptsRoot; + private final String logsBloom; + private final String prevRandao; + private final String blockNumber; + private final String gasLimit; + private final String gasUsed; + private final String timestamp; + private final String extraData; + private final String baseFeePerGas; + protected final List transactions; + + public PayloadResult(final BlockHeader header, final List transactions) { + this.blockNumber = Quantity.create(header.getNumber()); + this.blockHash = header.getHash().toString(); + this.parentHash = header.getParentHash().toString(); + this.logsBloom = header.getLogsBloom().toString(); + this.stateRoot = header.getStateRoot().toString(); + this.receiptsRoot = header.getReceiptsRoot().toString(); + this.extraData = header.getExtraData().toString(); + this.baseFeePerGas = header.getBaseFee().map(Quantity::create).orElse(null); + this.gasLimit = Quantity.create(header.getGasLimit()); + this.gasUsed = Quantity.create(header.getGasUsed()); + this.timestamp = Quantity.create(header.getTimestamp()); + this.transactions = transactions; + this.feeRecipient = header.getCoinbase().toString(); + this.prevRandao = header.getPrevRandao().map(Bytes32::toHexString).orElse(null); + } + + @JsonGetter(value = "blockNumber") + public String getNumber() { + return blockNumber; + } + + @JsonGetter(value = "blockHash") + public String getHash() { + return blockHash; + } + + @JsonGetter(value = "parentHash") + public String getParentHash() { + return parentHash; + } + + @JsonGetter(value = "logsBloom") + public String getLogsBloom() { + return logsBloom; + } + + @JsonGetter(value = "prevRandao") + public String getPrevRandao() { + return prevRandao; + } + + @JsonGetter(value = "stateRoot") + public String getStateRoot() { + return stateRoot; + } + + @JsonGetter(value = "receiptsRoot") + public String getReceiptRoot() { + return receiptsRoot; + } + + @JsonGetter(value = "extraData") + public String getExtraData() { + return extraData; + } + + @JsonGetter(value = "baseFeePerGas") + public String getBaseFeePerGas() { + return baseFeePerGas; + } + + @JsonGetter(value = "gasLimit") + public String getGasLimit() { + return gasLimit; + } + + @JsonGetter(value = "gasUsed") + public String getGasUsed() { + return gasUsed; + } + + @JsonGetter(value = "timestamp") + public String getTimestamp() { + return timestamp; + } + + @JsonGetter(value = "transactions") + public List getTransactions() { + return transactions; + } + + @JsonGetter(value = "feeRecipient") + @JsonInclude(JsonInclude.Include.NON_NULL) + public String getFeeRecipient() { + return feeRecipient; + } + } +} 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 a29022aa0ab..8d64b41d22f 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 @@ -20,7 +20,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineExchangeTransitionConfiguration; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineForkchoiceUpdated; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetPayload; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetPayloadV1; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetPayloadV2; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineNewPayload; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineQosTimer; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; @@ -67,7 +68,13 @@ protected Map create() { if (mergeCoordinator.isPresent()) { return mapOf( - new EngineGetPayload( + new EngineGetPayloadV1( + consensusEngineServer, + protocolContext, + mergeCoordinator.get(), + blockResultFactory, + engineQosTimer), + new EngineGetPayloadV2( consensusEngineServer, protocolContext, mergeCoordinator.get(), diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV1Test.java similarity index 94% rename from ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadTest.java rename to ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV1Test.java index da53dd26746..bc8988f2d78 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV1Test.java @@ -32,7 +32,7 @@ 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.BlockResultFactory; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetPayloadResult; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetPayloadResultV1; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -51,9 +51,9 @@ import org.mockito.junit.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) -public class EngineGetPayloadTest { +public class EngineGetPayloadV1Test { - private EngineGetPayload method; + private EngineGetPayloadV1 method; private static final Vertx vertx = Vertx.vertx(); private static final BlockResultFactory factory = new BlockResultFactory(); private static final PayloadIdentifier mockPid = @@ -76,7 +76,7 @@ public void before() { when(mergeContext.retrieveBlockById(mockPid)).thenReturn(Optional.of(mockBlock)); when(protocolContext.safeConsensusContext(Mockito.any())).thenReturn(Optional.of(mergeContext)); this.method = - new EngineGetPayload( + new EngineGetPayloadV1( vertx, protocolContext, mergeMiningCoordinator, factory, engineCallListener); } @@ -88,14 +88,14 @@ public void shouldReturnExpectedMethodName() { @Test public void shouldReturnBlockForKnownPayloadId() { - var resp = resp(mockPid); + final var resp = resp(mockPid); assertThat(resp).isInstanceOf(JsonRpcSuccessResponse.class); Optional.of(resp) .map(JsonRpcSuccessResponse.class::cast) .ifPresent( r -> { - assertThat(r.getResult()).isInstanceOf(EngineGetPayloadResult.class); - EngineGetPayloadResult res = (EngineGetPayloadResult) r.getResult(); + assertThat(r.getResult()).isInstanceOf(EngineGetPayloadResultV1.class); + final EngineGetPayloadResultV1 res = (EngineGetPayloadResultV1) r.getResult(); assertThat(res.getHash()).isEqualTo(mockHeader.getHash().toString()); assertThat(res.getPrevRandao()) .isEqualTo(mockHeader.getPrevRandao().map(Bytes32::toString).orElse("")); @@ -105,7 +105,7 @@ public void shouldReturnBlockForKnownPayloadId() { @Test public void shouldFailForUnknownPayloadId() { - var resp = + final var resp = resp( PayloadIdentifier.forPayloadParams( Hash.ZERO, 0L, Bytes32.random(), Address.fromHexString("0x42"))); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV2Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV2Test.java new file mode 100644 index 00000000000..6034c6a6559 --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV2Test.java @@ -0,0 +1,127 @@ +/* + * 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.Assertions.assertThat; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +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.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.ProtocolContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +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.BlockResultFactory; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetPayloadResultV2; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockBody; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; + +import java.util.Collections; +import java.util.Optional; + +import io.vertx.core.Vertx; +import org.apache.tuweni.bytes.Bytes32; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class EngineGetPayloadV2Test { + + private EngineGetPayloadV2 method; + private static final Vertx vertx = Vertx.vertx(); + private static final BlockResultFactory factory = new BlockResultFactory(); + private static final PayloadIdentifier mockPid = + PayloadIdentifier.forPayloadParams( + Hash.ZERO, 1337L, Bytes32.random(), Address.fromHexString("0x42")); + private static final BlockHeader mockHeader = + new BlockHeaderTestFixture().prevRandao(Bytes32.random()).buildHeader(); + private static final Block mockBlock = + new Block(mockHeader, new BlockBody(Collections.emptyList(), Collections.emptyList())); + + @Mock private ProtocolContext protocolContext; + + @Mock private MergeContext mergeContext; + @Mock private MergeMiningCoordinator mergeMiningCoordinator; + + @Mock private EngineCallListener engineCallListener; + + @Before + public void before() { + when(mergeContext.retrieveBlockById(mockPid)).thenReturn(Optional.of(mockBlock)); + when(protocolContext.safeConsensusContext(Mockito.any())).thenReturn(Optional.of(mergeContext)); + this.method = + new EngineGetPayloadV2( + vertx, protocolContext, mergeMiningCoordinator, factory, engineCallListener); + } + + @Test + public void shouldReturnExpectedMethodName() { + // will break as specs change, intentional: + assertThat(method.getName()).isEqualTo("engine_getPayloadV2"); + } + + @Test + public void shouldReturnBlockForKnownPayloadId() { + final var resp = resp(mockPid); + assertThat(resp).isInstanceOf(JsonRpcSuccessResponse.class); + Optional.of(resp) + .map(JsonRpcSuccessResponse.class::cast) + .ifPresent( + r -> { + assertThat(r.getResult()).isInstanceOf(EngineGetPayloadResultV2.class); + final EngineGetPayloadResultV2 res = (EngineGetPayloadResultV2) r.getResult(); + assertThat(res.getExecutionPayload().getHash()) + .isEqualTo(mockHeader.getHash().toString()); + assertThat(res.getBlockValue()).isEqualTo(Quantity.create(0)); + assertThat(res.getExecutionPayload().getPrevRandao()) + .isEqualTo(mockHeader.getPrevRandao().map(Bytes32::toString).orElse("")); + }); + verify(engineCallListener, times(1)).executionEngineCalled(); + } + + @Test + public void shouldFailForUnknownPayloadId() { + final var resp = + resp( + PayloadIdentifier.forPayloadParams( + Hash.ZERO, 0L, Bytes32.random(), Address.fromHexString("0x42"))); + assertThat(resp).isInstanceOf(JsonRpcErrorResponse.class); + verify(engineCallListener, times(1)).executionEngineCalled(); + } + + private JsonRpcResponse resp(final PayloadIdentifier pid) { + return method.response( + new JsonRpcRequestContext( + new JsonRpcRequest( + "2.0", + RpcMethod.ENGINE_GET_PAYLOAD_V2.getMethodName(), + new Object[] {pid.serialize()}))); + } +}