From 36577b68016db8b1a08fca367512d950f7a533d8 Mon Sep 17 00:00:00 2001 From: Justin Florentine Date: Tue, 24 Jan 2023 10:54:16 -0500 Subject: [PATCH] 4844 engine api (#4991) * json container for getting blob bundles * spdx headers, formatting, npe fix Signed-off-by: Justin Florentine Co-authored-by: Jason Frame Co-authored-by: garyschulte (cherry picked from commit 5fa943380176a18c9b5c394756fca6d3aabfe66f) (cherry picked from commit af8466f1561b4d5995bfa85782acee0644c3f879) --- .../merge/TransitionProtocolSchedule.java | 9 + .../org/hyperledger/besu/datatypes/Blob.java | 18 ++ .../besu/datatypes/KZGCommitment.java | 18 ++ .../besu/ethereum/api/jsonrpc/RpcMethod.java | 4 + .../engine/AbstractEngineGetPayload.java | 7 +- .../engine/AbstractEngineNewPayload.java | 8 +- .../engine/EngineGetBlobsBundleV1.java | 89 +++++++++ .../methods/engine/EngineGetPayloadV1.java | 12 +- .../methods/engine/EngineGetPayloadV2.java | 12 +- .../methods/engine/EngineGetPayloadV3.java | 79 ++++++++ .../methods/engine/EngineNewPayloadV3.java | 42 ++++ .../parameters/EnginePayloadParameter.java | 10 +- .../internal/results/BlobsBundleV1.java | 55 +++++ .../internal/results/BlockResultFactory.java | 16 ++ .../results/EngineGetPayloadResultV3.java | 188 ++++++++++++++++++ .../ExecutionEngineJsonRpcMethods.java | 30 ++- .../engine/AbstractEngineGetPayloadTest.java | 15 +- .../engine/AbstractEngineNewPayloadTest.java | 27 +-- .../engine/EngineGetPayloadV3Test.java | 128 ++++++++++++ .../besu/ethereum/core/Transaction.java | 18 ++ .../ethereum/core/BlockHeaderTestFixture.java | 8 + 21 files changed, 762 insertions(+), 31 deletions(-) create mode 100644 datatypes/src/main/java/org/hyperledger/besu/datatypes/Blob.java create mode 100644 datatypes/src/main/java/org/hyperledger/besu/datatypes/KZGCommitment.java create mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetBlobsBundleV1.java create mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3.java create mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3.java create mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlobsBundleV1.java create mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV3.java create mode 100644 ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3Test.java diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java index f934e4cd30d..3a6ca26b5ff 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java @@ -246,4 +246,13 @@ public void setPublicWorldStateArchiveForPrivacyBlockProcessor( public void setProtocolContext(final ProtocolContext protocolContext) { this.protocolContext = protocolContext; } + + /** + * Exposes timestamp based schedules for reference. + * + * @return timestampSchedule the timestamp schedule + */ + public TimestampSchedule getTimestampSchedule() { + return timestampSchedule; + } } diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Blob.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Blob.java new file mode 100644 index 00000000000..70b22d58691 --- /dev/null +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Blob.java @@ -0,0 +1,18 @@ +/* + * 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.datatypes; + +public class Blob {} diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/KZGCommitment.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/KZGCommitment.java new file mode 100644 index 00000000000..3ccffa485e2 --- /dev/null +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/KZGCommitment.java @@ -0,0 +1,18 @@ +/* + * 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.datatypes; + +public class KZGCommitment {} 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 4530e22baab..4d01fe9b1c4 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 @@ -51,8 +51,11 @@ public enum RpcMethod { DEBUG_GET_RAW_RECEIPTS("debug_getRawReceipts"), ENGINE_GET_PAYLOAD_V1("engine_getPayloadV1"), ENGINE_GET_PAYLOAD_V2("engine_getPayloadV2"), + ENGINE_GET_PAYLOAD_V3("engine_getPayloadV3"), + ENGINE_EXECUTE_PAYLOAD("engine_executePayloadV1"), ENGINE_NEW_PAYLOAD_V1("engine_newPayloadV1"), ENGINE_NEW_PAYLOAD_V2("engine_newPayloadV2"), + ENGINE_NEW_PAYLOAD_V3("engine_newPayloadV3"), ENGINE_FORKCHOICE_UPDATED_V1("engine_forkchoiceUpdatedV1"), ENGINE_FORKCHOICE_UPDATED_V2("engine_forkchoiceUpdatedV2"), ENGINE_EXCHANGE_TRANSITION_CONFIGURATION("engine_exchangeTransitionConfigurationV1"), @@ -60,6 +63,7 @@ public enum RpcMethod { ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1("engine_getPayloadBodiesByRangeV1"), ENGINE_EXCHANGE_CAPABILITIES("engine_exchangeCapabilities"), ENGINE_PREPARE_PAYLOAD_DEBUG("engine_preparePayload_debug"), + ENGINE_GET_BLOBS_BUNDLE_V1("engine_getBlobsBundleV1"), 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/AbstractEngineGetPayload.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayload.java index d5eb2c04778..287d0e9ac34 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayload.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayload.java @@ -26,6 +26,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockWithReceipts; +import org.hyperledger.besu.ethereum.mainnet.TimestampSchedule; import java.util.Optional; @@ -39,15 +40,19 @@ public abstract class AbstractEngineGetPayload extends ExecutionEngineJsonRpcMet protected final BlockResultFactory blockResultFactory; private static final Logger LOG = LoggerFactory.getLogger(AbstractEngineGetPayload.class); + protected final Optional schedule; + public AbstractEngineGetPayload( final Vertx vertx, final ProtocolContext protocolContext, final MergeMiningCoordinator mergeMiningCoordinator, final BlockResultFactory blockResultFactory, - final EngineCallListener engineCallListener) { + final EngineCallListener engineCallListener, + final TimestampSchedule schedule) { super(vertx, protocolContext, engineCallListener); this.mergeMiningCoordinator = mergeMiningCoordinator; this.blockResultFactory = blockResultFactory; + this.schedule = Optional.ofNullable(schedule); } @Override diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java index 62b918863f2..9c303329dbb 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java @@ -24,6 +24,7 @@ import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INVALID_PARAMS; import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator; +import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.BlockProcessingResult; @@ -160,9 +161,10 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) blockParam.getPrevRandao(), 0, maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(null), - null, - null, - headerFunctions); + blockParam.getExcessDataGas() == null + ? null + : DataGas.fromHexString(blockParam.getExcessDataGas()), + null, headerFunctions); // ensure the block hash matches the blockParam hash // this must be done before any other check diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetBlobsBundleV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetBlobsBundleV1.java new file mode 100644 index 00000000000..5a46450990e --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetBlobsBundleV1.java @@ -0,0 +1,89 @@ +/* + * 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.BlobsBundleV1; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockWithReceipts; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.mainnet.TimestampSchedule; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import io.vertx.core.Vertx; +import org.apache.tuweni.bytes.Bytes; + +public class EngineGetBlobsBundleV1 extends AbstractEngineGetPayload { + + public EngineGetBlobsBundleV1( + final Vertx vertx, + final ProtocolContext protocolContext, + final MergeMiningCoordinator mergeMiningCoordinator, + final BlockResultFactory blockResultFactory, + final EngineCallListener engineCallListener, + final TimestampSchedule schedule) { + super( + vertx, + protocolContext, + mergeMiningCoordinator, + blockResultFactory, + engineCallListener, + schedule); + } + + @Override + protected JsonRpcResponse createResponse( + final JsonRpcRequestContext request, final BlockWithReceipts blockWithReceipts) { + + return new JsonRpcSuccessResponse( + request.getRequest().getId(), createResponse(blockWithReceipts.getBlock())); + } + + private BlobsBundleV1 createResponse(final Block block) { + + List kzgs = + block.getBody().getTransactions().stream() + .map(Transaction::getBlobsWithCommitments) + .filter(Optional::isPresent) + .map(Optional::get) + .flatMap(b -> b.getKzgCommitments().stream()) + .collect(Collectors.toList()); + + List blobs = + block.getBody().getTransactions().stream() + .map(Transaction::getBlobsWithCommitments) + .filter(Optional::isPresent) + .map(Optional::get) + .flatMap(b -> b.getBlobs().stream()) + .collect(Collectors.toList()); + + return new BlobsBundleV1(block.getHash(), kzgs, blobs); + } + + @Override + public String getName() { + return RpcMethod.ENGINE_GET_BLOBS_BUNDLE_V1.getMethodName(); + } +} 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 index 2484ac961e3..3f0d0b29470 100644 --- 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 @@ -23,6 +23,7 @@ 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.BlockWithReceipts; +import org.hyperledger.besu.ethereum.mainnet.TimestampSchedule; import java.util.Optional; @@ -35,8 +36,15 @@ public EngineGetPayloadV1( final ProtocolContext protocolContext, final MergeMiningCoordinator mergeMiningCoordinator, final BlockResultFactory blockResultFactory, - final EngineCallListener engineCallListener) { - super(vertx, protocolContext, mergeMiningCoordinator, blockResultFactory, engineCallListener); + final EngineCallListener engineCallListener, + final TimestampSchedule schedule) { + super( + vertx, + protocolContext, + mergeMiningCoordinator, + blockResultFactory, + engineCallListener, + schedule); } @Override 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 index d14e9dec8a6..5fc2ec0b5c7 100644 --- 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 @@ -24,6 +24,7 @@ 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.BlockWithReceipts; +import org.hyperledger.besu.ethereum.mainnet.TimestampSchedule; import java.util.Optional; @@ -36,8 +37,15 @@ public EngineGetPayloadV2( final ProtocolContext protocolContext, final MergeMiningCoordinator mergeMiningCoordinator, final BlockResultFactory blockResultFactory, - final EngineCallListener engineCallListener) { - super(vertx, protocolContext, mergeMiningCoordinator, blockResultFactory, engineCallListener); + final EngineCallListener engineCallListener, + final TimestampSchedule schedule) { + super( + vertx, + protocolContext, + mergeMiningCoordinator, + blockResultFactory, + engineCallListener, + schedule); } @Override diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3.java new file mode 100644 index 00000000000..d3ca9e9b048 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3.java @@ -0,0 +1,79 @@ +/* + * 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.BlockWithReceipts; +import org.hyperledger.besu.ethereum.mainnet.DefaultTimestampSchedule; +import org.hyperledger.besu.ethereum.mainnet.TimestampSchedule; + +import io.vertx.core.Vertx; + +public class EngineGetPayloadV3 extends AbstractEngineGetPayload { + + public EngineGetPayloadV3( + final Vertx vertx, + final ProtocolContext protocolContext, + final MergeMiningCoordinator mergeMiningCoordinator, + final BlockResultFactory blockResultFactory, + final EngineCallListener engineCallListener, + final TimestampSchedule schedule) { + super( + vertx, + protocolContext, + mergeMiningCoordinator, + blockResultFactory, + engineCallListener, + schedule); + } + + @Override + public String getName() { + return RpcMethod.ENGINE_GET_PAYLOAD_V3.getMethodName(); + } + + @Override + protected JsonRpcResponse createResponse( + final JsonRpcRequestContext request, final BlockWithReceipts blockWithReceipts) { + + DefaultTimestampSchedule tsched = (DefaultTimestampSchedule) this.schedule.get(); + long shanghaiTimestamp = tsched.scheduledAt("Shanghai"); + long cancunTimestamp = tsched.scheduledAt("Cancun"); + long builtAt = blockWithReceipts.getHeader().getTimestamp(); + if (builtAt < shanghaiTimestamp) { + return new JsonRpcSuccessResponse( + request.getRequest().getId(), + blockResultFactory.payloadTransactionCompleteV1(blockWithReceipts.getBlock())); + } else if (builtAt >= shanghaiTimestamp && builtAt < cancunTimestamp) { + return new JsonRpcSuccessResponse( + request.getRequest().getId(), + blockResultFactory.payloadTransactionCompleteV2(blockWithReceipts)); + } else if (builtAt >= cancunTimestamp) { + return new JsonRpcSuccessResponse( + request.getRequest().getId(), + blockResultFactory.payloadTransactionCompleteV3(blockWithReceipts)); + } + + return new JsonRpcSuccessResponse( + request.getRequest().getId(), + blockResultFactory.payloadTransactionCompleteV3(blockWithReceipts)); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3.java new file mode 100644 index 00000000000..68b388a3b01 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3.java @@ -0,0 +1,42 @@ +/* + * 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.eth.manager.EthPeers; +import org.hyperledger.besu.ethereum.mainnet.TimestampSchedule; + +import io.vertx.core.Vertx; + +public class EngineNewPayloadV3 extends AbstractEngineNewPayload { + + public EngineNewPayloadV3( + final Vertx vertx, + final TimestampSchedule timestampSchedule, + final ProtocolContext protocolContext, + final MergeMiningCoordinator mergeCoordinator, + final EthPeers ethPeers, + final EngineCallListener engineCallListener) { + super( + vertx, timestampSchedule, protocolContext, mergeCoordinator, ethPeers, engineCallListener); + } + + @Override + public String getName() { + return RpcMethod.ENGINE_NEW_PAYLOAD_V3.getMethodName(); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadParameter.java index d6e5923b539..5af7e408ff9 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadParameter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadParameter.java @@ -48,6 +48,8 @@ public class EnginePayloadParameter { private final List transactions; private final List withdrawals; + private final String excessDataGas; + @JsonCreator public EnginePayloadParameter( @JsonProperty("blockHash") final Hash blockHash, @@ -64,7 +66,8 @@ public EnginePayloadParameter( @JsonProperty("logsBloom") final LogsBloomFilter logsBloom, @JsonProperty("prevRandao") final String prevRandao, @JsonProperty("transactions") final List transactions, - @JsonProperty("withdrawals") final List withdrawals) { + @JsonProperty("withdrawals") final List withdrawals, + @JsonProperty("excessDataGas") final String excessDataGas) { this.blockHash = blockHash; this.parentHash = parentHash; this.feeRecipient = feeRecipient; @@ -80,6 +83,7 @@ public EnginePayloadParameter( this.prevRandao = Bytes32.fromHexString(prevRandao); this.transactions = transactions; this.withdrawals = withdrawals; + this.excessDataGas = excessDataGas; } public Hash getBlockHash() { @@ -141,4 +145,8 @@ public List getTransactions() { public List getWithdrawals() { return withdrawals; } + + public String getExcessDataGas() { + return excessDataGas; + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlobsBundleV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlobsBundleV1.java new file mode 100644 index 00000000000..71ca6172271 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlobsBundleV1.java @@ -0,0 +1,55 @@ +/* + * 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.datatypes.Hash; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.apache.tuweni.bytes.Bytes; + +@JsonPropertyOrder({"blockHash", "kzgs", "blobs"}) +public class BlobsBundleV1 { + + private final Hash blockHash; + + private final List kzgs; + + private final List blobs; + + public BlobsBundleV1(final Hash blockHash, final List kzgs, final List blobs) { + this.blockHash = blockHash; + this.kzgs = kzgs; + this.blobs = blobs; + } + + @JsonGetter("blockHash") + public Hash getBlockHash() { + return blockHash; + } + + @JsonGetter("kzgs") + public List getKzgs() { + return kzgs; + } + + @JsonGetter("blobs") + public List getBlobs() { + return blobs; + } +} 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 2685f888a37..37ca5827b14 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 @@ -127,6 +127,22 @@ public EngineGetPayloadBodiesResultV1 payloadBodiesCompleteV1( return new EngineGetPayloadBodiesResultV1(payloadBodies); } + public EngineGetPayloadResultV3 payloadTransactionCompleteV3( + final BlockWithReceipts blockWithReceipts) { + final List txs = + blockWithReceipts.getBlock().getBody().getTransactions().stream() + .map(TransactionEncoder::encodeOpaqueBytes) + .map(Bytes::toHexString) + .collect(Collectors.toList()); + + final Wei blockValue = new BlockValueCalculator().calculateBlockValue(blockWithReceipts); + return new EngineGetPayloadResultV3( + blockWithReceipts.getHeader(), + txs, + blockWithReceipts.getBlock().getBody().getWithdrawals(), + Quantity.create(blockValue)); + } + public BlockResult transactionHash(final BlockWithMetadata blockWithMetadata) { return transactionHash(blockWithMetadata, false); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV3.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV3.java new file mode 100644 index 00000000000..65b53b5fbec --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV3.java @@ -0,0 +1,188 @@ +/* + * 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.api.jsonrpc.internal.parameters.WithdrawalParameter; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.Withdrawal; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +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 EngineGetPayloadResultV3 { + protected final PayloadResult executionPayload; + private final String blockValue; + + public EngineGetPayloadResultV3( + final BlockHeader header, + final List transactions, + final Optional> withdrawals, + final String blockValue) { + this.executionPayload = new PayloadResult(header, transactions, withdrawals); + 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; + + private final String excessDataGas; + + protected final List transactions; + private final List withdrawals; + + public PayloadResult( + final BlockHeader header, + final List transactions, + final Optional> withdrawals) { + 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.excessDataGas = header.getExcessDataGas().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); + this.withdrawals = + withdrawals + .map( + ws -> + ws.stream() + .map(WithdrawalParameter::fromWithdrawal) + .collect(Collectors.toList())) + .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 = "withdrawals") + public List getWithdrawals() { + return withdrawals; + } + + @JsonGetter(value = "feeRecipient") + @JsonInclude(JsonInclude.Include.NON_NULL) + public String getFeeRecipient() { + return feeRecipient; + } + + @JsonGetter(value = "excessDataGas") + public String getExcessDataGas() { + return excessDataGas; + } + } +} 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 d42049b59e3..f416b01cfbb 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 @@ -24,11 +24,14 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineForkchoiceUpdatedV2; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetPayloadBodiesByHashV1; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetPayloadBodiesByRangeV1; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetBlobsBundleV1; 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.EngineGetPayloadV3; 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.EngineNewPayloadV3; 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; @@ -82,13 +85,22 @@ protected Map create() { protocolContext, mergeCoordinator.get(), blockResultFactory, - engineQosTimer), + engineQosTimer, + timestampSchedule), new EngineGetPayloadV2( consensusEngineServer, protocolContext, mergeCoordinator.get(), blockResultFactory, - engineQosTimer), + engineQosTimer, + timestampSchedule), + new EngineGetPayloadV3( + consensusEngineServer, + protocolContext, + mergeCoordinator.get(), + blockResultFactory, + engineQosTimer, + timestampSchedule), new EngineNewPayloadV1( consensusEngineServer, protocolSchedule, @@ -103,6 +115,13 @@ protected Map create() { mergeCoordinator.get(), ethPeers, engineQosTimer), + new EngineNewPayloadV3( + consensusEngineServer, + timestampSchedule, + protocolContext, + mergeCoordinator.get(), + ethPeers, + engineQosTimer), new EngineForkchoiceUpdatedV1( consensusEngineServer, protocolSchedule, @@ -115,6 +134,13 @@ protected Map create() { protocolContext, mergeCoordinator.get(), engineQosTimer), + new EngineGetBlobsBundleV1( + consensusEngineServer, + protocolContext, + mergeCoordinator.get(), + new BlockResultFactory(), + engineQosTimer, + timestampSchedule), new EngineExchangeTransitionConfiguration( consensusEngineServer, protocolContext, engineQosTimer), new EngineGetPayloadBodiesByHashV1( diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayloadTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayloadTest.java index c66a408a86a..efed3b1180c 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayloadTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayloadTest.java @@ -35,6 +35,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.BlockWithReceipts; +import org.hyperledger.besu.ethereum.mainnet.TimestampSchedule; import java.util.Collections; import java.util.Optional; @@ -58,7 +59,8 @@ AbstractEngineGetPayload create( final ProtocolContext protocolContext, final MergeMiningCoordinator mergeCoordinator, final BlockResultFactory ethPeers, - final EngineCallListener engineCallListener); + final EngineCallListener engineCallListener, + final TimestampSchedule schedule); } private final MethodFactory methodFactory; @@ -103,7 +105,16 @@ public void before() { when(protocolContext.safeConsensusContext(Mockito.any())).thenReturn(Optional.of(mergeContext)); this.method = methodFactory.create( - vertx, protocolContext, mergeMiningCoordinator, factory, engineCallListener); + vertx, + protocolContext, + mergeMiningCoordinator, + factory, + engineCallListener, + getTimestampSchedule()); + } + + protected TimestampSchedule getTimestampSchedule() { + return null; } @Test diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java index bf5a6c6c04f..3f195d46650 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java @@ -31,6 +31,7 @@ import org.hyperledger.besu.consensus.merge.MergeContext; import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator; +import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.BlockProcessingOutputs; @@ -347,7 +348,11 @@ public void shouldRespondWithSyncingDuringForwardSync() { @Test public void shouldRespondWithSyncingDuringBackwardsSync() { - BlockHeader mockHeader = new BlockHeaderTestFixture().baseFeePerGas(Wei.ONE).buildHeader(); + BlockHeader mockHeader = + new BlockHeaderTestFixture() + .baseFeePerGas(Wei.ONE) + .excessDataGas(DataGas.ZERO) + .buildHeader(); when(mergeCoordinator.appendNewPayloadToSync(any())) .thenReturn(CompletableFuture.completedFuture(null)); var resp = resp(mockPayload(mockHeader, Collections.emptyList())); @@ -480,22 +485,7 @@ protected JsonRpcResponse resp(final EnginePayloadParameter payload) { } protected EnginePayloadParameter mockPayload(final BlockHeader header, final List txs) { - return new EnginePayloadParameter( - header.getHash(), - header.getParentHash(), - header.getCoinbase(), - header.getStateRoot(), - new UnsignedLongParameter(header.getNumber()), - header.getBaseFee().map(w -> w.toHexString()).orElse("0x0"), - new UnsignedLongParameter(header.getGasLimit()), - new UnsignedLongParameter(header.getGasUsed()), - new UnsignedLongParameter(header.getTimestamp()), - header.getExtraData() == null ? null : header.getExtraData().toHexString(), - header.getReceiptsRoot(), - header.getLogsBloom(), - header.getPrevRandao().map(Bytes32::toHexString).orElse("0x0"), - txs, - null); + return mockPayload(header, txs, null); } private EnginePayloadParameter mockPayload( @@ -517,7 +507,8 @@ private EnginePayloadParameter mockPayload( header.getLogsBloom(), header.getPrevRandao().map(Bytes32::toHexString).orElse("0x0"), txs, - withdrawals); + withdrawals, + header.getExcessDataGas().map(DataGas::toHexString).orElse(null)); } @NotNull diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3Test.java new file mode 100644 index 00000000000..6db6c1c51b4 --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3Test.java @@ -0,0 +1,128 @@ +/* + * 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.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.consensus.merge.blockcreation.PayloadIdentifier; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.DataGas; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetPayloadResultV3; +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 org.hyperledger.besu.ethereum.core.BlockWithReceipts; +import org.hyperledger.besu.ethereum.mainnet.DefaultTimestampSchedule; +import org.hyperledger.besu.ethereum.mainnet.TimestampSchedule; + +import java.util.Collections; +import java.util.Optional; + +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith( + MockitoJUnitRunner.Silent + .class) // mocks in parent class may not be used, throwing unnecessary stubbing +public class EngineGetPayloadV3Test extends AbstractEngineGetPayloadTest { + + private static final long SHANGHAI_AT = 1337L; + private static final long CANCUN_AT = 31337L; + + public EngineGetPayloadV3Test() { + super(EngineGetPayloadV3::new); + } + + @Override + public TimestampSchedule getTimestampSchedule() { + DefaultTimestampSchedule mockSchedule = mock(DefaultTimestampSchedule.class); + when(mockSchedule.scheduledAt("Cancun")).thenReturn(CANCUN_AT); + when(mockSchedule.scheduledAt("Shanghai")).thenReturn(SHANGHAI_AT); + return mockSchedule; + } + + @Override + @Test + public void shouldReturnExpectedMethodName() { + assertThat(method.getName()).isEqualTo("engine_getPayloadV3"); + } + + @Override + @Test + public void shouldReturnBlockForKnownPayloadId() { + + BlockHeader cancunHeader = + new BlockHeaderTestFixture() + .prevRandao(Bytes32.random()) + .timestamp(CANCUN_AT + 1) + .excessDataGas(DataGas.of(10L)) + .buildHeader(); + // should return withdrawals and excessGas for a post-cancun block + PayloadIdentifier postCancunPid = + PayloadIdentifier.forPayloadParams( + Hash.ZERO, CANCUN_AT, Bytes32.random(), Address.fromHexString("0x42")); + + BlockWithReceipts postCancunBlock = + new BlockWithReceipts( + new Block( + cancunHeader, + new BlockBody( + Collections.emptyList(), + Collections.emptyList(), + Optional.of(Collections.emptyList()))), + Collections.emptyList()); + + when(mergeContext.retrieveBlockById(postCancunPid)).thenReturn(Optional.of(postCancunBlock)); + + final var resp = resp(RpcMethod.ENGINE_GET_PAYLOAD_V3.getMethodName(), postCancunPid); + assertThat(resp).isInstanceOf(JsonRpcSuccessResponse.class); + Optional.of(resp) + .map(JsonRpcSuccessResponse.class::cast) + .ifPresent( + r -> { + assertThat(r.getResult()).isInstanceOf(EngineGetPayloadResultV3.class); + final EngineGetPayloadResultV3 res = (EngineGetPayloadResultV3) r.getResult(); + assertThat(res.getExecutionPayload().getWithdrawals()).isNotNull(); + assertThat(res.getExecutionPayload().getHash()) + .isEqualTo(cancunHeader.getHash().toString()); + assertThat(res.getBlockValue()).isEqualTo(Quantity.create(0)); + assertThat(res.getExecutionPayload().getPrevRandao()) + .isEqualTo(cancunHeader.getPrevRandao().map(Bytes32::toString).orElse("")); + // excessDataGas: QUANTITY, 256 bits + String expectedQuantityOf10 = Bytes32.leftPad(Bytes.of(10)).toQuantityHexString(); + assertThat(res.getExecutionPayload().getExcessDataGas()).isNotEmpty(); + assertThat(res.getExecutionPayload().getExcessDataGas()) + .isEqualTo(expectedQuantityOf10); + }); + verify(engineCallListener, times(1)).executionEngineCalled(); + } + + @Override + protected String getMethodName() { + return RpcMethod.ENGINE_GET_PAYLOAD_V2.getMethodName(); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java index 19e2e7dbbe7..0d9e7e86b38 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java @@ -1363,5 +1363,23 @@ public BlobsWithCommitments( this.blobs = blobs; this.kzgProof = kzgProof; } + + public List getBlobs() { + return blobs.getElements().stream() + .map( + blob -> { + return blob.getElements().stream() + .map(sszuInt256Wrapper -> (Bytes) sszuInt256Wrapper.getData().toBytes()) + .reduce(Bytes::concatenate) + .orElseThrow(); + }) + .collect(Collectors.toList()); + } + + public List getKzgCommitments() { + return kzgCommitments.getElements().stream() + .map(c -> c.getData()) + .collect(Collectors.toList()); + } } } diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockHeaderTestFixture.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockHeaderTestFixture.java index 4976184a8a7..195b079d27f 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockHeaderTestFixture.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockHeaderTestFixture.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.core; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; @@ -50,6 +51,7 @@ public class BlockHeaderTestFixture { private long nonce = 0; private Optional withdrawalsRoot = Optional.empty(); private BlockHeaderFunctions blockHeaderFunctions = new MainnetBlockHeaderFunctions(); + private Optional excessDataGas = Optional.empty(); public BlockHeader buildHeader() { final BlockHeaderBuilder builder = BlockHeaderBuilder.create(); @@ -71,6 +73,7 @@ public BlockHeader buildHeader() { builder.mixHash(mixHash); builder.nonce(nonce); withdrawalsRoot.ifPresent(builder::withdrawalsRoot); + excessDataGas.ifPresent(builder::excessDataGas); builder.blockHeaderFunctions(blockHeaderFunctions); return builder.buildBlockHeader(); @@ -166,6 +169,11 @@ public BlockHeaderTestFixture withdrawalsRoot(final Hash withdrawalsRoot) { return this; } + public BlockHeaderTestFixture excessDataGas(final DataGas excessDataGas) { + this.excessDataGas = Optional.ofNullable(excessDataGas); + return this; + } + public BlockHeaderTestFixture blockHeaderFunctions( final BlockHeaderFunctions blockHeaderFunctions) { this.blockHeaderFunctions = blockHeaderFunctions;