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 a89b2c53fd7..37c26f58450 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 @@ -58,6 +58,7 @@ import org.hyperledger.besu.plugin.services.exception.StorageException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Optional; @@ -99,6 +100,20 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) final EnginePayloadParameter blockParam = requestContext.getRequiredParameter(0, EnginePayloadParameter.class); + Optional> maybeVersionedHashes = Optional.empty(); + + Optional maybeVersionedHashParam = requestContext.getOptionalParameter(1, String.class); + if(maybeVersionedHashParam.isPresent()) { + Bytes versionedHashArray = Bytes.fromHexString(maybeVersionedHashParam.get()); + if(versionedHashArray.size() % 32 != 0) { + LOG.info("CL sent versionedHash array indivisible by 32"); + return new JsonRpcErrorResponse(requestContext.getRequest().getId(), INVALID_PARAMS); + } else { + Bytes32[] versionedHashes = Bytes.segment(versionedHashArray); + maybeVersionedHashes = Optional.of(Arrays.stream(versionedHashes).toList()); + } + } + Object reqId = requestContext.getRequest().getId(); LOG.atTrace() @@ -218,8 +233,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) .map(vh -> vh.toBytes()) .collect(toList()))); // and compare with expected versioned hashes param - final Optional> maybeVersionedHashes = - Optional.ofNullable(blockParam.getVersionedHashes()); + // check if one is empty if (maybeVersionedHashes.isPresent() && transactionVersionedHashes.isEmpty()) { return respondWithInvalid( 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 8fc0fa94551..9cf5e5ceeeb 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 @@ -60,6 +60,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Deposit; import org.hyperledger.besu.ethereum.core.Withdrawal; +import org.hyperledger.besu.ethereum.core.blobs.VersionedHash; import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.mainnet.BodyValidation; import org.hyperledger.besu.ethereum.mainnet.DepositsValidator; @@ -617,10 +618,10 @@ private EnginePayloadParameter mockPayload( header.getPrevRandao().map(Bytes32::toHexString).orElse("0x0"), txs, withdrawals, - null, new UnsignedLongParameter(header.getDataGasUsed()), deposits, - header.getExcessDataGas().map(DataGas::toHexString).orElse(null)); + header.getExcessDataGas().map(DataGas::toHexString).orElse(null), + List.of(VersionedHash.DEFAULT_VERSIONED_HASH.toBytes())); } @NotNull diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java new file mode 100644 index 00000000000..8a68c2926fa --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.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.methods.engine; + +import org.apache.tuweni.bytes.Bytes; +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.parameters.EnginePayloadParameter; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponseType; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +@RunWith(MockitoJUnitRunner.class) +public class EngineNewPayloadV3Test extends AbstractEngineNewPayloadTest { + + public EngineNewPayloadV3Test() { + super(EngineNewPayloadV3::new); + } + + @Override + @Test + public void shouldReturnExpectedMethodName() { + assertThat(method.getName()).isEqualTo("engine_newPayloadV3"); + } + + @Test + public void shouldInvalidParamsOnShortVersionedHash() { + Bytes shortHash = Bytes.repeat((byte)0x69, 31); + shortHash.toHexString(); + EnginePayloadParameter payload = mock(EnginePayloadParameter.class); + JsonRpcResponse badParam = method.response( + new JsonRpcRequestContext( + new JsonRpcRequest( + "2.0", RpcMethod.ENGINE_NEW_PAYLOAD_V2.getMethodName(), new Object[] {payload, shortHash}))); + assertThat(badParam.getType()).isEqualTo(JsonRpcResponseType.ERROR); + } +}