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 dd49f650c91..b9cf7789436 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 @@ -184,7 +184,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) "Failed to parse block body: "+rlpE.getMessage()); } Hash txRoot = BodyValidation.transactionsRoot(allegedBody.getTransactions()); - BlockHeader allegedHeader = composeNewHeader(requestContext, txRoot).buildBlockHeader(); + BlockHeader allegedHeader = composeNewHeader(requestContext, newPayloadParam, txRoot).buildBlockHeader(); Block allegedBlock = new Block(allegedHeader, allegedBody); @@ -207,20 +207,8 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) return respondWith(reqId, blockId, null, SYNCING); } - /* - if (allegedHeader.getExtraData() == null) { - return respondWithInvalid( - reqId, - allegedHeader, - mergeCoordinator.getLatestValidAncestor(allegedHeader.getParentHash()).orElse(null), - INVALID, - "Field extraData must not be null"); - } - - */ - // ensure the block hash matches the blockParam hash - // this must be done before any other check + // this must be done before other block validity checks if (!allegedHeader.getHash().equals(blockId.blockHash())) { String errorMessage = String.format( @@ -341,8 +329,8 @@ protected abstract ValidationResult validateRequest( public record EngineBlockValidationResult(EngineStatus status, BlockValidationResult validationResult) {}; protected abstract

EngineBlockValidationResult validateBlock(P payload); - protected abstract BlockHeaderBuilder composeNewHeader( - final JsonRpcRequestContext requestContext, final Hash txroot); + protected abstract

BlockHeaderBuilder composeNewHeader( + final JsonRpcRequestContext requestContext, final P newPayloadParam, final Hash txroot); protected abstract ValidationResult validateBlobs( final Block newBlock, diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadEIP6110.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadEIP6110.java index 5d809895bd5..53573ae34fa 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadEIP6110.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadEIP6110.java @@ -25,6 +25,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.engine.DepositParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.engine.NewPayloadParameterEIP6110; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.engine.NewPayloadParameterV1; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; import org.hyperledger.besu.ethereum.core.Deposit; @@ -105,15 +106,14 @@ protected ValidationResult validateForkSupported( } @Override - protected BlockHeaderBuilder composeNewHeader( - final JsonRpcRequestContext context, final Hash txRoot) { - final NewPayloadParameterEIP6110 blockParam = - context.getRequiredParameter(0, NewPayloadParameterEIP6110.class); + protected

BlockHeaderBuilder composeNewHeader( + final JsonRpcRequestContext context, final P newPayloadParam, final Hash txRoot) { + final Optional> maybeDeposits = - Optional.ofNullable(blockParam.getDeposits()) + Optional.ofNullable(((NewPayloadParameterEIP6110)newPayloadParam).getDeposits()) .map(ds -> ds.stream().map(DepositParameter::toDeposit).collect(toList())); - final BlockHeaderBuilder builder = super.composeNewHeader(context, txRoot); + final BlockHeaderBuilder builder = super.composeNewHeader(context, newPayloadParam, txRoot); builder.depositsRoot(maybeDeposits.map(BodyValidation::depositsRoot).orElse(null)); return builder; } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV1.java index 15c9454b92e..20f57ba3710 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV1.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV1.java @@ -92,27 +92,26 @@ protected

EngineBlockValidationResult validate @Override @SuppressWarnings("signedness:argument") - protected BlockHeaderBuilder composeNewHeader( - final JsonRpcRequestContext requestContext, final Hash txRoot) { - NewPayloadParameterV1 blockParam = - requestContext.getRequiredParameter(0, NewPayloadParameterV1.class); + protected

BlockHeaderBuilder composeNewHeader( + final JsonRpcRequestContext requestContext, final P newPayloadParam, final Hash txRoot) { + final BlockHeaderBuilder builder = new BlockHeaderBuilder(); builder - .parentHash(blockParam.getParentHash()) + .parentHash(newPayloadParam.getParentHash()) .ommersHash(OMMERS_HASH_CONSTANT) - .coinbase(blockParam.getFeeRecipient()) - .stateRoot(blockParam.getStateRoot()) + .coinbase(newPayloadParam.getFeeRecipient()) + .stateRoot(newPayloadParam.getStateRoot()) .transactionsRoot(txRoot) - .receiptsRoot(blockParam.getReceiptsRoot()) - .logsBloom(blockParam.getLogsBloom()) + .receiptsRoot(newPayloadParam.getReceiptsRoot()) + .logsBloom(newPayloadParam.getLogsBloom()) .difficulty(Difficulty.ZERO) - .number(blockParam.getBlockNumber()) - .gasLimit(blockParam.getGasLimit()) - .gasUsed(blockParam.getGasUsed()) - .timestamp(blockParam.getTimestamp()) - .extraData(Bytes.fromHexString(blockParam.getExtraData())) - .baseFee(blockParam.getBaseFeePerGas()) - .prevRandao(blockParam.getPrevRandao()) + .number(newPayloadParam.getBlockNumber()) + .gasLimit(newPayloadParam.getGasLimit()) + .gasUsed(newPayloadParam.getGasUsed()) + .timestamp(newPayloadParam.getTimestamp()) + .extraData(Bytes.fromHexString(newPayloadParam.getExtraData())) + .baseFee(newPayloadParam.getBaseFeePerGas()) + .prevRandao(newPayloadParam.getPrevRandao()) .nonce(0) .blockHeaderFunctions(headerFunctions); return builder; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2.java index 1e962ad81b9..9173f0abce9 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2.java @@ -63,8 +63,16 @@ public EngineNewPayloadV2( @Override @SuppressWarnings("unchecked") - protected

P parseVersionedParam(final JsonRpcRequestContext request) { - return (P) request.getRequiredParameter(0, NewPayloadParameterV2.class); + protected

P parseVersionedParam(final JsonRpcRequestContext requestContext) { + final NewPayloadParameterV1 newPayloadParam = + requestContext.getRequiredParameter(0, NewPayloadParameterV1.class); + WithdrawalsValidator validator = getWithdrawalsValidator( + protocolSchedule.get(), newPayloadParam.getTimestamp(), newPayloadParam.getBlockNumber()); + if(validator instanceof WithdrawalsValidator.AllowedWithdrawals) { + return (P) requestContext.getRequiredParameter(0, NewPayloadParameterV2.class); + } else { + return (P) newPayloadParam; + } } @Override @@ -100,16 +108,17 @@ protected ValidationResult validateRequest( } @Override - protected BlockHeaderBuilder composeNewHeader( - final JsonRpcRequestContext requestContext, final Hash txRoot) { - BlockHeaderBuilder builder = super.composeNewHeader(requestContext, txRoot); - NewPayloadParameterV2 blockParam = - requestContext.getRequiredParameter(0, NewPayloadParameterV2.class); - final Optional> maybeWithdrawals = - Optional.ofNullable(blockParam.getWithdrawals()) - .map(ws -> ws.stream().map(WithdrawalParameter::toWithdrawal).collect(toList())); + protected

BlockHeaderBuilder composeNewHeader( + final JsonRpcRequestContext requestContext, final P newPayloadParam, final Hash txRoot) { + BlockHeaderBuilder builder = super.composeNewHeader(requestContext, newPayloadParam, txRoot); + if(newPayloadParam instanceof NewPayloadParameterV2) { + final Optional> maybeWithdrawals = + Optional.ofNullable(((NewPayloadParameterV2)newPayloadParam).getWithdrawals()) + .map(ws -> ws.stream().map(WithdrawalParameter::toWithdrawal).collect(toList())); + + builder.withdrawalsRoot(maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(BodyValidation.withdrawalsRoot(Collections.emptyList()))); + } - builder.withdrawalsRoot(maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(BodyValidation.withdrawalsRoot(Collections.emptyList()))); return builder; } 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 index 776439b6a04..aa1f11c7403 100644 --- 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 @@ -222,16 +222,14 @@ private Optional> extractVersionedHashes( @Override @SuppressWarnings("signedness:argument") - protected BlockHeaderBuilder composeNewHeader( - final JsonRpcRequestContext context, final Hash txRoot) { - final NewPayloadParameterV3 blockParam = - context.getRequiredParameter(0, NewPayloadParameterV3.class); + protected

BlockHeaderBuilder composeNewHeader( + final JsonRpcRequestContext context, final P newPayloadParam, final Hash txRoot) { String parentBeaconBlockRootParam = context.getRequiredParameter(2, String.class); - final BlockHeaderBuilder builder = super.composeNewHeader(context, txRoot); + final BlockHeaderBuilder builder = super.composeNewHeader(context, newPayloadParam, txRoot); builder - .blobGasUsed(blockParam.getBlobGasUsed()) - .excessBlobGas(BlobGas.fromHexString(blockParam.getExcessBlobGas())) + .blobGasUsed(((NewPayloadParameterV3)newPayloadParam).getBlobGasUsed()) + .excessBlobGas(BlobGas.fromHexString(((NewPayloadParameterV3)newPayloadParam).getExcessBlobGas())) .parentBeaconBlockRoot(Bytes32.fromHexString(parentBeaconBlockRootParam)); return builder; } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/engine/NewPayloadV2Serializer.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/engine/NewPayloadV2Serializer.java index 5d90426964e..5768e4b0be8 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/engine/NewPayloadV2Serializer.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/engine/NewPayloadV2Serializer.java @@ -16,13 +16,15 @@ public NewPayloadV2Serializer() { protected void serializeToOpenObject(final NewPayloadParameterV2 value, final JsonGenerator gen, final SerializerProvider provider) throws IOException { v1Serializer.serializeToOpenObject(value, gen, provider); - gen.writeArrayFieldStart("withdrawals"); + if(value.getWithdrawals() != null) { + gen.writeArrayFieldStart("withdrawals"); for (WithdrawalParameter withdrawal : value.getWithdrawals()) { gen.writeObject(withdrawal); } + gen.writeEndArray(); } - gen.writeEndArray(); + } @Override diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2Test.java index c02041dd7a3..68995feba47 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2Test.java @@ -106,8 +106,7 @@ public void shouldReturnValidIfWithdrawalsIsNotNull_WhenWithdrawalsAllowed() thr } @Test - public void shouldReturnValidIfWithdrawalsIsNull_WhenWithdrawalsProhibited() throws JsonProcessingException { - final List withdrawals = null; + public void shouldReturnValidIfWithdrawalsIsNull_WhenWithdrawalsProhibited() { when(protocolSpec.getWithdrawalsValidator()) .thenReturn(new WithdrawalsValidator.ProhibitedWithdrawals()); BlockHeader mockHeader = @@ -120,7 +119,7 @@ public void shouldReturnValidIfWithdrawalsIsNull_WhenWithdrawalsProhibited() thr .thenReturn(Optional.of(mock(BlockHeader.class))); var resp = respondTo( - new Object[] {createNewPayloadParam(mockHeader, Collections.emptyList(), withdrawals)}); + new Object[] {createNewPayloadParam(mockHeader, Collections.emptyList())}); assertValidResponse(mockHeader, resp); } @@ -207,15 +206,18 @@ protected BlockHeaderTestFixture createBlockHeaderTestFixture( final Optional> maybeDeposits) { BlockHeader parentBlockHeader = new BlockHeaderTestFixture().baseFeePerGas(Wei.ONE).buildHeader(); - return new BlockHeaderTestFixture() + BlockHeaderTestFixture testFixture = new BlockHeaderTestFixture() .baseFeePerGas(Wei.ONE) .parentHash(parentBlockHeader.getParentHash()) .number(parentBlockHeader.getNumber() + 1) .timestamp(parentBlockHeader.getTimestamp() + 1) .extraData(Bytes.fromHexString("0xDEADBEEF")) - .withdrawalsRoot(maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(null)) .depositsRoot(maybeDeposits.map(BodyValidation::depositsRoot).orElse(null)) .transactionsRoot(BodyValidation.transactionsRoot(maybeTransactions)) .parentBeaconBlockRoot(maybeParentBeaconBlockRoot); + if(maybeWithdrawals.isPresent() && maybeWithdrawals.get().size() > 0) { + testFixture.withdrawalsRoot(maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(null)); + } + return testFixture; } }