diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/RequestType.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/RequestType.java
index 5a8fe97a3..23a54ec1b 100644
--- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/RequestType.java
+++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/RequestType.java
@@ -52,8 +52,25 @@ public enum RequestType {
case 0x01 -> WITHDRAWAL;
case 0x02 -> CONSOLIDATION;
default ->
- throw new IllegalArgumentException(
+ throw new InvalidRequestTypeException(
String.format("Unsupported request type: 0x%02X", serializedTypeValue));
};
}
+
+ /**
+ * Exception thrown when an invalid request type is encountered.
+ *
+ *
This exception is thrown when a serialized type value does not correspond to any {@link
+ * RequestType}.
+ */
+ public static class InvalidRequestTypeException extends IllegalArgumentException {
+ /**
+ * Constructs an {@link InvalidRequestTypeException} with the specified detail message.
+ *
+ * @param message the detail message.
+ */
+ public InvalidRequestTypeException(final String message) {
+ super(message);
+ }
+ }
}
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 c9ad05600..929135ae5 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
@@ -202,13 +202,15 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
final Optional> maybeRequests;
try {
maybeRequests = extractRequests(maybeRequestsParam);
- } catch (RuntimeException ex) {
+ } catch (RequestType.InvalidRequestTypeException ex) {
return respondWithInvalid(
reqId,
blockParam,
mergeCoordinator.getLatestValidAncestor(blockParam.getParentHash()).orElse(null),
INVALID,
"Invalid execution requests");
+ } catch (Exception ex) {
+ return new JsonRpcErrorResponse(reqId, RpcErrorType.INVALID_EXECUTION_REQUESTS_PARAMS);
}
if (!getRequestsValidator(
@@ -591,14 +593,17 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
if (maybeRequestsParam.isEmpty()) {
return Optional.empty();
}
-
return maybeRequestsParam.map(
requests ->
requests.stream()
.map(
s -> {
final Bytes request = Bytes.fromHexString(s);
- return new Request(RequestType.of(request.get(0)), request.slice(1));
+ final Bytes requestData = request.slice(1);
+ if (requestData.isEmpty()) {
+ throw new IllegalArgumentException("Request data cannot be empty");
+ }
+ return new Request(RequestType.of(request.get(0)), requestData);
})
.collect(Collectors.toList()));
}
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java
index 97a8e1f7d..91e179ce3 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java
@@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.mainnet;
import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator.calculateExcessBlobGasForParent;
import org.hyperledger.besu.datatypes.Address;
+import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.BlockProcessingOutputs;
@@ -250,6 +251,19 @@ public abstract class AbstractBlockProcessor implements BlockProcessor {
maybeRequests = Optional.of(requestProcessor.get().process(context));
}
+ if (maybeRequests.isPresent() && blockHeader.getRequestsHash().isPresent()) {
+ Hash calculatedRequestHash = BodyValidation.requestsHash(maybeRequests.get());
+ Hash headerRequestsHash = blockHeader.getRequestsHash().get();
+ if (!calculatedRequestHash.equals(headerRequestsHash)) {
+ return new BlockProcessingResult(
+ Optional.empty(),
+ "Requests hash mismatch, calculated: "
+ + calculatedRequestHash.toHexString()
+ + " header: "
+ + headerRequestsHash.toHexString());
+ }
+ }
+
if (!rewardCoinbase(worldState, blockHeader, ommers, skipZeroBlockRewards)) {
// no need to log, rewardCoinbase logs the error.
if (worldState instanceof BonsaiWorldState) {
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/MainnetRequestsValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/MainnetRequestsValidator.java
index fb49ba71f..237e5cab4 100644
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/MainnetRequestsValidator.java
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/MainnetRequestsValidator.java
@@ -14,12 +14,14 @@
*/
package org.hyperledger.besu.ethereum.mainnet.requests;
+import org.hyperledger.besu.datatypes.RequestType;
import org.hyperledger.besu.ethereum.core.Request;
+import java.util.Comparator;
import java.util.List;
import java.util.Optional;
-import com.google.common.collect.Ordering;
+import com.google.common.collect.Comparators;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -46,15 +48,25 @@ public class MainnetRequestsValidator implements RequestsValidator {
return false;
}
- if (!isRequestOrderValid(maybeRequests.get())) {
- LOG.warn("Ordering across requests must be ascending by type");
+ List requests = maybeRequests.get();
+ if (!areRequestTypesUniqueAndOrderValid(requests)) {
+ LOG.warn("Request types must be unique and ordering must be ascending by type");
return false;
}
+ if (containsRequestWithEmptyData(requests)) {
+ LOG.warn("Request must not be empty");
+ return false;
+ }
return true;
}
- private static boolean isRequestOrderValid(final List requests) {
- return Ordering.natural().onResultOf(Request::getType).isOrdered(requests);
+ private static boolean areRequestTypesUniqueAndOrderValid(final List requests) {
+ final List requestTypes = requests.stream().map(Request::type).toList();
+ return Comparators.isInStrictOrder(requestTypes, Comparator.naturalOrder());
+ }
+
+ private static boolean containsRequestWithEmptyData(final List requests) {
+ return requests.stream().anyMatch(request -> request.getData().isEmpty());
}
}
diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/requests/MainnetRequestsValidatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/requests/MainnetRequestsValidatorTest.java
index 410a72630..4541d43d7 100644
--- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/requests/MainnetRequestsValidatorTest.java
+++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/requests/MainnetRequestsValidatorTest.java
@@ -55,4 +55,21 @@ class MainnetRequestsValidatorTest {
new Request(RequestType.CONSOLIDATION, Bytes.of(3)));
assertTrue(validator.validate(Optional.of(requests)));
}
+
+ @Test
+ void validateFalseForEmptyRequest() {
+ MainnetRequestsValidator validator = new MainnetRequestsValidator();
+ List requests = List.of(new Request(RequestType.DEPOSIT, Bytes.EMPTY));
+ assertFalse(validator.validate(Optional.of(requests)));
+ }
+
+ @Test
+ void validateFalseForDuplicatedRequests() {
+ MainnetRequestsValidator validator = new MainnetRequestsValidator();
+ List requests =
+ List.of(
+ new Request(RequestType.DEPOSIT, Bytes.of(1)),
+ new Request(RequestType.DEPOSIT, Bytes.of(1)));
+ assertFalse(validator.validate(Optional.of(requests)));
+ }
}
diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/block-test/osaka-eof-rjump.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/block-test/osaka-eof-rjump.json
index b70da91fc..7658ac3a9 100644
--- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/block-test/osaka-eof-rjump.json
+++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/block-test/osaka-eof-rjump.json
@@ -27,8 +27,8 @@
"blobGasUsed": "0x00",
"excessBlobGas": "0x00",
"parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
- "requestsHash": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
- "hash": "0x67315ef3267f6f654068ccbd317423b1028fd5305b94a56d1f27e6651e06d678"
+ "requestsHash": "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "hash": "0xf87b21fa838d23ffb4eb990363863611d2cbf707dd2e80cdcdf14bbd506bb369"
},
"pre": {
"0x00000000219ab540356cbb839cbe05303d7705fa": {
@@ -178,7 +178,7 @@
"balance": "0x00",
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500",
"storage": {
- "0x00": "0x67315ef3267f6f654068ccbd317423b1028fd5305b94a56d1f27e6651e06d678"
+ "0x00": "0xf87b21fa838d23ffb4eb990363863611d2cbf707dd2e80cdcdf14bbd506bb369"
}
},
"0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": {
@@ -194,15 +194,15 @@
"storage": {}
}
},
- "lastblockhash": "0x9ca58820df28ca6d09450fff5fdf93d39976e3aa098c6981ae08f391d44ffb3f",
- "genesisRLP": "0xf90262f9025ba00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a06cb1761e069313d13f39d755da011dc921b1f0fe5c4c3e951891639e479b4cfba056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808088016345785d8a0000808000a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421c0c0c0c0",
+ "lastblockhash": "0x63f38b8d65c153dacf94ab767f13d0919671e1d1ac703a377d2387782be31acf",
+ "genesisRLP": "0xf90262f9025ba00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a06cb1761e069313d13f39d755da011dc921b1f0fe5c4c3e951891639e479b4cfba056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808088016345785d8a0000808000a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a0e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855c0c0c0c0",
"blocks": [
{
"blockHeader": {
- "parentHash": "0x67315ef3267f6f654068ccbd317423b1028fd5305b94a56d1f27e6651e06d678",
+ "parentHash": "0xf87b21fa838d23ffb4eb990363863611d2cbf707dd2e80cdcdf14bbd506bb369",
"uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"coinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
- "stateRoot": "0x61171b085ffd8d099ca59ba13164e8883d89c89d3298256aa229b03a6e33d246",
+ "stateRoot": "0x499d3ba7df30b168f8af11e0b02041d802bdd9615ef0f363cb14e4872b9d9422",
"transactionsTrie": "0xec9d10cff79619f2df45db8c66526ef3fbd32d283fdd2dcc9b55c0efe643d8c3",
"receiptTrie": "0x9593f56abf23bcbb26d27b0c6e46a56415d9103ed6b4d8ac7b4182f9f250cafa",
"bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
@@ -219,8 +219,8 @@
"blobGasUsed": "0x00",
"excessBlobGas": "0x00",
"parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
- "requestsHash": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
- "hash": "0x9ca58820df28ca6d09450fff5fdf93d39976e3aa098c6981ae08f391d44ffb3f"
+ "requestsHash": "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "hash": "0x63f38b8d65c153dacf94ab767f13d0919671e1d1ac703a377d2387782be31acf"
},
"transactions": [
{
@@ -243,7 +243,7 @@
"depositRequests": [],
"withdrawalRequests": [],
"consolidationRequests": [],
- "rlp": "0xf902c8f9025fa067315ef3267f6f654068ccbd317423b1028fd5305b94a56d1f27e6651e06d678a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa061171b085ffd8d099ca59ba13164e8883d89c89d3298256aa229b03a6e33d246a0ec9d10cff79619f2df45db8c66526ef3fbd32d283fdd2dcc9b55c0efe643d8c3a09593f56abf23bcbb26d27b0c6e46a56415d9103ed6b4d8ac7b4182f9f250cafab9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800188016345785d8a000082a8648203e800a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f862f860800a83989680940000000000000000000000000000000000001000808026a0e5d462429669f661291a8dc4c49a092cfd4922b6f3f31c9189a2f4adf5ecd730a001494afaf472fbb80bcb107ffeb918a2b9115f454027840615d6d20d63c69ac0c0c0",
+ "rlp": "0xf902c8f9025fa0f87b21fa838d23ffb4eb990363863611d2cbf707dd2e80cdcdf14bbd506bb369a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa0499d3ba7df30b168f8af11e0b02041d802bdd9615ef0f363cb14e4872b9d9422a0ec9d10cff79619f2df45db8c66526ef3fbd32d283fdd2dcc9b55c0efe643d8c3a09593f56abf23bcbb26d27b0c6e46a56415d9103ed6b4d8ac7b4182f9f250cafab9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800188016345785d8a000082a8648203e800a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a0e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855f862f860800a83989680940000000000000000000000000000000000001000808026a0e5d462429669f661291a8dc4c49a092cfd4922b6f3f31c9189a2f4adf5ecd730a001494afaf472fbb80bcb107ffeb918a2b9115f454027840615d6d20d63c69ac0c0c0",
"blocknumber": "1"
}
],
@@ -259,5 +259,5 @@
}
}
},
- "stdout": "Considering tests/osaka/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py::test_rjump_zero[fork_Osaka-blockchain_test]\nBlock 1 (0x9ca58820df28ca6d09450fff5fdf93d39976e3aa098c6981ae08f391d44ffb3f) Imported\nChain import successful - tests/osaka/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py::test_rjump_zero[fork_Osaka-blockchain_test]\n"
+ "stdout": "Considering tests/osaka/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py::test_rjump_zero[fork_Osaka-blockchain_test]\nBlock 1 (0x63f38b8d65c153dacf94ab767f13d0919671e1d1ac703a377d2387782be31acf) Imported\nChain import successful - tests/osaka/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py::test_rjump_zero[fork_Osaka-blockchain_test]\n"
}