Change execution requests to use flat encoding (#7771)

Signed-off-by: Jason Frame <jason.frame@consensys.net>
pull/7813/head
Jason Frame 4 weeks ago committed by GitHub
parent 516559fadc
commit f16d3526db
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 21
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/ethereum/PragueAcceptanceTestHelper.java
  2. 12
      acceptance-tests/tests/src/test/resources/dev/dev_prague.json
  3. 23
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/genesis.json
  4. 4
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/00_get_genesis_block_info.json
  5. 8
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/01_cancun_prepare_payload.json
  6. 8
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/02_cancun_getPayloadV3.json
  7. 14
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/03_cancun_newPayloadV3.json
  8. 8
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/04_cancun_forkchoiceUpdatedV3.json
  9. 10
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/05_prague_forkchoiceUpdatedV3.json
  10. 26
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/06_prague_getPayloadV4.json
  11. 0
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/07_prague_send_raw_transaction_deposit_request.json
  12. 8
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/08_prague_invalid_null_deposit_request_execute_payload.json
  13. 34
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/09_prague_newPayloadV4.json
  14. 10
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/10_prague_forkchoiceUpdatedV3.json
  15. 20
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/11_prague_getPayloadV4.json
  16. 21
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/12_cancun_newPayloadV3.json
  17. 10
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/15_prague_forkchoiceUpdatedV3.json
  18. 40
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/16_prague_getPayloadV4.json
  19. 2
      besu/src/test/java/org/hyperledger/besu/services/RlpConverterServiceImplTest.java
  20. 19
      consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PayloadWrapper.java
  21. 8
      consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java
  22. 3
      consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/messagewrappers/ProposalTest.java
  23. 12
      datatypes/src/main/java/org/hyperledger/besu/datatypes/Hash.java
  24. 8
      datatypes/src/test/java/org/hyperledger/besu/datatypes/HashTest.java
  25. 2
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseKey.java
  26. 8
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseUtils.java
  27. 1
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/TracedJsonRpcProcessor.java
  28. 97
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java
  29. 3
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2.java
  30. 3
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3.java
  31. 8
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV4.java
  32. 49
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/RequestValidatorProvider.java
  33. 102
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/ConsolidationRequestParameter.java
  34. 144
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/DepositRequestParameter.java
  35. 28
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadParameter.java
  36. 103
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/WithdrawalRequestParameter.java
  37. 1
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/RpcErrorType.java
  38. 19
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java
  39. 81
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV4.java
  40. 15
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineGetPayloadTest.java
  41. 99
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java
  42. 7
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByHashV1Test.java
  43. 19
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadBodiesByRangeV1Test.java
  44. 3
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV2Test.java
  45. 4
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV3Test.java
  46. 29
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV4Test.java
  47. 43
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2Test.java
  48. 25
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java
  49. 225
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV4Test.java
  50. 42
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/DepositParameterTestFixture.java
  51. 61
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/DepositRequestRequestParameterTest.java
  52. 52
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/WithdrawalRequestParameterTest.java
  53. 31
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/WithdrawalRequestTestFixture.java
  54. 7
      ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java
  55. 115
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java
  56. 10
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/BlockProcessingResult.java
  57. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/BlockValidator.java
  58. 5
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/MainnetBlockValidator.java
  59. 7
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java
  60. 5
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Block.java
  61. 34
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockBody.java
  62. 22
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java
  63. 16
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java
  64. 90
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ConsolidationRequest.java
  65. 112
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/DepositRequest.java
  66. 23
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Request.java
  67. 14
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SealableBlockHeader.java
  68. 89
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/WithdrawalRequest.java
  69. 40
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/ConsolidationRequestDecoder.java
  70. 60
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/ConsolidationRequestEncoder.java
  71. 40
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/DepositLogDecoder.java
  72. 70
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/DepositRequestDecoder.java
  73. 42
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/DepositRequestEncoder.java
  74. 106
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/RequestDecoder.java
  75. 83
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/RequestEncoder.java
  76. 41
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/WithdrawalRequestDecoder.java
  77. 59
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/WithdrawalRequestEncoder.java
  78. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java
  79. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BaseFeeBlockBodyValidator.java
  80. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BlockBodyValidator.java
  81. 23
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BodyValidation.java
  82. 19
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockBodyValidator.java
  83. 8
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockImporter.java
  84. 6
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java
  85. 14
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpec.java
  86. 12
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java
  87. 5
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/SystemCallProcessor.java
  88. 102
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/AbstractSystemCallRequestProcessor.java
  89. 73
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/ConsolidationRequestProcessor.java
  90. 92
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/ConsolidationRequestValidator.java
  91. 29
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/DepositRequestProcessor.java
  92. 86
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/DepositRequestValidator.java
  93. 39
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/MainnetRequestsProcessor.java
  94. 67
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/MainnetRequestsValidator.java
  95. 38
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/ProhibitedRequestValidator.java
  96. 53
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/ProhibitedRequestsValidator.java
  97. 13
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/RequestContractAddresses.java
  98. 5
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/RequestProcessor.java
  99. 25
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/RequestProcessorCoordinator.java
  100. 85
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/RequestUtil.java
  101. Some files were not shown because too many files have changed in this diff Show More

@ -22,7 +22,9 @@ import org.hyperledger.besu.tests.acceptance.dsl.transaction.eth.EthTransactions
import java.io.IOException; import java.io.IOException;
import java.util.Optional; import java.util.Optional;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import okhttp3.Call; import okhttp3.Call;
import okhttp3.MediaType; import okhttp3.MediaType;
@ -74,17 +76,15 @@ public class PragueAcceptanceTestHelper {
final Call getPayloadRequest = createEngineCall(createGetPayloadRequest(payloadId)); final Call getPayloadRequest = createEngineCall(createGetPayloadRequest(payloadId));
final ObjectNode executionPayload; final ObjectNode executionPayload;
final ArrayNode executionRequests;
final String newBlockHash; final String newBlockHash;
final String parentBeaconBlockRoot; final String parentBeaconBlockRoot;
try (final Response getPayloadResponse = getPayloadRequest.execute()) { try (final Response getPayloadResponse = getPayloadRequest.execute()) {
assertThat(getPayloadResponse.code()).isEqualTo(200); assertThat(getPayloadResponse.code()).isEqualTo(200);
executionPayload = JsonNode result = mapper.readTree(getPayloadResponse.body().string()).get("result");
(ObjectNode) executionPayload = (ObjectNode) result.get("executionPayload");
mapper executionRequests = (ArrayNode) result.get("executionRequests");
.readTree(getPayloadResponse.body().string())
.get("result")
.get("executionPayload");
newBlockHash = executionPayload.get("blockHash").asText(); newBlockHash = executionPayload.get("blockHash").asText();
parentBeaconBlockRoot = executionPayload.remove("parentBeaconBlockRoot").asText(); parentBeaconBlockRoot = executionPayload.remove("parentBeaconBlockRoot").asText();
@ -94,7 +94,8 @@ public class PragueAcceptanceTestHelper {
final Call newPayloadRequest = final Call newPayloadRequest =
createEngineCall( createEngineCall(
createNewPayloadRequest(executionPayload.toString(), parentBeaconBlockRoot)); createNewPayloadRequest(
executionPayload.toString(), parentBeaconBlockRoot, executionRequests.toString()));
try (final Response newPayloadResponse = newPayloadRequest.execute()) { try (final Response newPayloadResponse = newPayloadRequest.execute()) {
assertThat(newPayloadResponse.code()).isEqualTo(200); assertThat(newPayloadResponse.code()).isEqualTo(200);
} }
@ -168,7 +169,9 @@ public class PragueAcceptanceTestHelper {
} }
private String createNewPayloadRequest( private String createNewPayloadRequest(
final String executionPayload, final String parentBeaconBlockRoot) { final String executionPayload,
final String parentBeaconBlockRoot,
final String executionRequests) {
return "{" return "{"
+ " \"jsonrpc\": \"2.0\"," + " \"jsonrpc\": \"2.0\","
+ " \"method\": \"engine_newPayloadV4\"," + " \"method\": \"engine_newPayloadV4\","
@ -178,6 +181,8 @@ public class PragueAcceptanceTestHelper {
+ "\"" + "\""
+ parentBeaconBlockRoot + parentBeaconBlockRoot
+ "\"" + "\""
+ ","
+ executionRequests
+ "]," + "],"
+ " \"id\": 67" + " \"id\": 67"
+ "}"; + "}";

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -12,14 +12,14 @@
"id": 67, "id": 67,
"result": { "result": {
"number": "0x0", "number": "0x0",
"hash" : "0x38d7daa68e8bac41a0a237b7cbfcef480cb9bd9adc7b282d7b0d23ff4eb8d6e5", "hash" : "0x01f5cbf33268c161f1526d704268db760bf82c9772a8f8ca412e0c6ce5684896",
"mixHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", "mixHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce" : "0x0000000000000042", "nonce" : "0x0000000000000042",
"sha3Uncles" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "sha3Uncles" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"logsBloom" : "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom" : "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"transactionsRoot" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "transactionsRoot" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0x3ed8435adb5f3526144e6babdd3fc8c661a86097cf7e743441b41fda096fc4dd", "stateRoot" : "0x860be6ab5a8fc2003c3739bfe2cdbcd9dbb273c8ea42951b832a8e1f22fb3a60",
"receiptsRoot" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "receiptsRoot" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"miner" : "0x0000000000000000000000000000000000000000", "miner" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x400000000", "difficulty" : "0x400000000",

@ -4,8 +4,8 @@
"method": "engine_forkchoiceUpdatedV3", "method": "engine_forkchoiceUpdatedV3",
"params": [ "params": [
{ {
"headBlockHash": "0x38d7daa68e8bac41a0a237b7cbfcef480cb9bd9adc7b282d7b0d23ff4eb8d6e5", "headBlockHash": "0x01f5cbf33268c161f1526d704268db760bf82c9772a8f8ca412e0c6ce5684896",
"safeBlockHash": "0x38d7daa68e8bac41a0a237b7cbfcef480cb9bd9adc7b282d7b0d23ff4eb8d6e5", "safeBlockHash": "0x01f5cbf33268c161f1526d704268db760bf82c9772a8f8ca412e0c6ce5684896",
"finalizedBlockHash": "0x0000000000000000000000000000000000000000000000000000000000000000" "finalizedBlockHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}, },
{ {
@ -24,10 +24,10 @@
"result": { "result": {
"payloadStatus": { "payloadStatus": {
"status": "VALID", "status": "VALID",
"latestValidHash": "0x38d7daa68e8bac41a0a237b7cbfcef480cb9bd9adc7b282d7b0d23ff4eb8d6e5", "latestValidHash": "0x01f5cbf33268c161f1526d704268db760bf82c9772a8f8ca412e0c6ce5684896",
"validationError": null "validationError": null
}, },
"payloadId": "0x28264396eca1deef" "payloadId": "0x282643b677b85211"
} }
}, },
"statusCode": 200 "statusCode": 200

@ -3,7 +3,7 @@
"jsonrpc": "2.0", "jsonrpc": "2.0",
"method": "engine_getPayloadV3", "method": "engine_getPayloadV3",
"params": [ "params": [
"0x28264396eca1deef" "0x282643b677b85211"
], ],
"id": 67 "id": 67
}, },
@ -12,9 +12,9 @@
"id": 67, "id": 67,
"result": { "result": {
"executionPayload": { "executionPayload": {
"parentHash": "0x38d7daa68e8bac41a0a237b7cbfcef480cb9bd9adc7b282d7b0d23ff4eb8d6e5", "parentHash": "0x01f5cbf33268c161f1526d704268db760bf82c9772a8f8ca412e0c6ce5684896",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", "feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0x3ed8435adb5f3526144e6babdd3fc8c661a86097cf7e743441b41fda096fc4dd", "stateRoot": "0x860be6ab5a8fc2003c3739bfe2cdbcd9dbb273c8ea42951b832a8e1f22fb3a60",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380", "gasLimit": "0x1c9c380",
@ -29,7 +29,7 @@
"blockNumber": "0x1", "blockNumber": "0x1",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"blobGasUsed": "0x0", "blobGasUsed": "0x0",
"blockHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593" "blockHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e"
}, },
"blockValue": "0x0", "blockValue": "0x0",
"blobsBundle": { "blobsBundle": {

@ -4,9 +4,9 @@
"method": "engine_newPayloadV3", "method": "engine_newPayloadV3",
"params": [ "params": [
{ {
"parentHash": "0x38d7daa68e8bac41a0a237b7cbfcef480cb9bd9adc7b282d7b0d23ff4eb8d6e5", "parentHash": "0x01f5cbf33268c161f1526d704268db760bf82c9772a8f8ca412e0c6ce5684896",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", "feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0x3ed8435adb5f3526144e6babdd3fc8c661a86097cf7e743441b41fda096fc4dd", "stateRoot": "0x860be6ab5a8fc2003c3739bfe2cdbcd9dbb273c8ea42951b832a8e1f22fb3a60",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380", "gasLimit": "0x1c9c380",
@ -14,13 +14,13 @@
"timestamp": "0x10", "timestamp": "0x10",
"extraData": "0x", "extraData": "0x",
"baseFeePerGas": "0x7", "baseFeePerGas": "0x7",
"excessBlobGas": "0x0",
"transactions": [], "transactions": [],
"withdrawals": [], "withdrawals": [],
"blockNumber": "0x1", "blockNumber": "0x1",
"blockHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593", "blobGasUsed": "0x0",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "blockHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e",
"excessBlobGas": "0x0", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
"blobGasUsed": "0x0"
}, },
[], [],
"0x0000000000000000000000000000000000000000000000000000000000000000" "0x0000000000000000000000000000000000000000000000000000000000000000"
@ -32,7 +32,7 @@
"id": 67, "id": 67,
"result": { "result": {
"status": "VALID", "status": "VALID",
"latestValidHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593", "latestValidHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e",
"validationError": null "validationError": null
} }
}, },

@ -4,9 +4,9 @@
"method": "engine_forkchoiceUpdatedV3", "method": "engine_forkchoiceUpdatedV3",
"params": [ "params": [
{ {
"headBlockHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593", "headBlockHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e",
"safeBlockHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593", "safeBlockHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e",
"finalizedBlockHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593" "finalizedBlockHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e"
}, },
null null
], ],
@ -18,7 +18,7 @@
"result": { "result": {
"payloadStatus": { "payloadStatus": {
"status": "VALID", "status": "VALID",
"latestValidHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593", "latestValidHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e",
"validationError": null "validationError": null
}, },
"payloadId": null "payloadId": null

@ -4,9 +4,9 @@
"method": "engine_forkchoiceUpdatedV3", "method": "engine_forkchoiceUpdatedV3",
"params": [ "params": [
{ {
"headBlockHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593", "headBlockHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e",
"safeBlockHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593", "safeBlockHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e",
"finalizedBlockHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593" "finalizedBlockHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e"
}, },
{ {
"timestamp": "0x20", "timestamp": "0x20",
@ -24,10 +24,10 @@
"result": { "result": {
"payloadStatus": { "payloadStatus": {
"status": "VALID", "status": "VALID",
"latestValidHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593", "latestValidHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e",
"validationError": null "validationError": null
}, },
"payloadId": "0x282643d3a905e721" "payloadId": "0x282643fdcbcb1ddf"
} }
}, },
"statusCode": 200 "statusCode": 200

@ -3,7 +3,7 @@
"jsonrpc": "2.0", "jsonrpc": "2.0",
"method": "engine_getPayloadV4", "method": "engine_getPayloadV4",
"params": [ "params": [
"0x282643d3a905e721" "0x282643fdcbcb1ddf"
], ],
"id": 67 "id": 67
}, },
@ -12,9 +12,9 @@
"id": 67, "id": 67,
"result": { "result": {
"executionPayload": { "executionPayload": {
"parentHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593", "parentHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", "feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0x2e59916a57b535875bcd80d8472aeaa0027aa685d159804e8caa2f12d060155e", "stateRoot": "0xed4093bcd157ba955245906a1cda7695d3b3f233af709f0adf17689abb4d93b4",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380", "gasLimit": "0x1c9c380",
@ -23,22 +23,13 @@
"extraData": "0x", "extraData": "0x",
"baseFeePerGas": "0x7", "baseFeePerGas": "0x7",
"excessBlobGas": "0x0", "excessBlobGas": "0x0",
"blobGasUsed": "0x0",
"parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
"transactions": [], "transactions": [],
"withdrawals": [], "withdrawals": [],
"depositRequests": [],
"withdrawalRequests": [
{
"sourceAddress": "0xa4664c40aacebd82a2db79f0ea36c06bc6a19adb",
"validatorPubkey": "0xb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e",
"amount": "0x0"
}
],
"consolidationRequests" : [],
"blockNumber": "0x2", "blockNumber": "0x2",
"blockHash": "0x27a2bc2ac21b3fc796f636bec1ec9cba100435f9a793176a83a5d4fa7cc13006",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"blobGasUsed": "0x0" "blockHash": "0x303fb51567c090ed3fb7ac50a082ae3a0bcb8ff522d071011a1ca433561a4569"
}, },
"blockValue": "0x0", "blockValue": "0x0",
"blobsBundle": { "blobsBundle": {
@ -46,7 +37,12 @@
"proofs": [], "proofs": [],
"blobs": [] "blobs": []
}, },
"shouldOverrideBuilder": false "shouldOverrideBuilder": false,
"executionRequests": [
"0x",
"0xa4664c40aacebd82a2db79f0ea36c06bc6a19adbb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e0000000000000000",
"0x"
]
} }
}, },
"statusCode": 200 "statusCode": 200

@ -17,14 +17,14 @@
"excessBlobGas": "0x0", "excessBlobGas": "0x0",
"transactions": [], "transactions": [],
"withdrawals": [], "withdrawals": [],
"depositRequests": null,
"blockNumber": "0x2", "blockNumber": "0x2",
"blockHash": "0x2331b2dc9c453e9a33685099742cbbcd529d42bd5681969f45754f06866c6766", "blockHash": "0x2331b2dc9c453e9a33685099742cbbcd529d42bd5681969f45754f06866c6766",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"blobGasUsed": "0x0" "blobGasUsed": "0x0"
}, },
[], [],
"0x0000000000000000000000000000000000000000000000000000000000000000" "0x0000000000000000000000000000000000000000000000000000000000000000",
null
], ],
"id": 67 "id": 67
}, },
@ -33,8 +33,8 @@
"id" : 67, "id" : 67,
"error" : { "error" : {
"code" : -32602, "code" : -32602,
"message": "Invalid params", "message" : "Invalid execution requests params",
"data": "Missing deposit field" "data" : "Missing execution requests field"
} }
}, },
"statusCode": 200 "statusCode": 200

@ -4,9 +4,9 @@
"method": "engine_newPayloadV4", "method": "engine_newPayloadV4",
"params": [ "params": [
{ {
"parentHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593", "parentHash": "0x7cccf6d9ce3e5acaeac9058959c27ace53af3a30b15763e1703bab2d0ae9438e",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", "feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0x961878fdcdff52ea42db0026f59aa414a5ec2835e56ed1a8ae50c80a9fe3a04b", "stateRoot": "0x176ea6dfa3b8efb148a025f759cccfaab02db38427b12a4ede73491eda397196",
"logsBloom": "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000", "logsBloom": "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380", "gasLimit": "0x1c9c380",
@ -15,34 +15,22 @@
"extraData": "0x", "extraData": "0x",
"baseFeePerGas": "0x7", "baseFeePerGas": "0x7",
"excessBlobGas": "0x0", "excessBlobGas": "0x0",
"blobGasUsed": "0x0",
"transactions": [ "transactions": [
"0x02f9021c8217de808459682f008459682f0e830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120749715de5d1226545c6b3790f515d551a5cc5bf1d49c87a696860554d2fc4f14000000000000000000000000000000000000000000000000000000000000003096a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9c080a09f597089338d7f44f5c59f8230bb38f243849228a8d4e9d2e2956e6050f5b2c7a076486996c7e62802b8f95eee114783e4b403fd11093ba96286ff42c595f24452" "0x02f9021c8217de808459682f008459682f0e830271009442424242424242424242424242424242424242428901bc16d674ec800000b901a422895118000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120749715de5d1226545c6b3790f515d551a5cc5bf1d49c87a696860554d2fc4f14000000000000000000000000000000000000000000000000000000000000003096a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20000000000000000000000000000000000000000000000000000000000000060b1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9c080a09f597089338d7f44f5c59f8230bb38f243849228a8d4e9d2e2956e6050f5b2c7a076486996c7e62802b8f95eee114783e4b403fd11093ba96286ff42c595f24452"
], ],
"withdrawals": [], "withdrawals": [],
"depositRequests": [
{
"amount": "0x773594000",
"index": "0x0",
"pubkey": "0x96a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9",
"signature": "0xb1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9",
"withdrawalCredentials": "0x003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef2"
}
],
"withdrawalRequests": [
{
"sourceAddress": "0xa4664c40aacebd82a2db79f0ea36c06bc6a19adb",
"amount": "0x0",
"validatorPubkey": "0xb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e"
}
],
"consolidationRequests": [],
"blockNumber": "0x2", "blockNumber": "0x2",
"blockHash": "0xc67a660f5d3c20ee603911bdff1e409e976f306883dff8ef4999dca3176f7dca",
"receiptsRoot": "0x79ee3424eb720a3ad4b1c5a372bb8160580cbe4d893778660f34213c685627a9", "receiptsRoot": "0x79ee3424eb720a3ad4b1c5a372bb8160580cbe4d893778660f34213c685627a9",
"blobGasUsed": "0x0" "blockHash": "0x14ba5ec415d827d9cab33e6097b307131e8119a1cd7dc1f6a4de088ebfa4c1b6"
}, },
[], [],
"0x0000000000000000000000000000000000000000000000000000000000000000" "0x0000000000000000000000000000000000000000000000000000000000000000",
[
"0xf84794a4664c40aacebd82a2db79f0ea36c06bc6a19adbb0b10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e80",
"0xa4664c40aacebd82a2db79f0ea36c06bc6a19adbb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e0000000000000000",
"0x"
]
], ],
"id": 67 "id": 67
}, },
@ -51,7 +39,7 @@
"id": 67, "id": 67,
"result": { "result": {
"status": "VALID", "status": "VALID",
"latestValidHash": "0xc67a660f5d3c20ee603911bdff1e409e976f306883dff8ef4999dca3176f7dca", "latestValidHash": "0x14ba5ec415d827d9cab33e6097b307131e8119a1cd7dc1f6a4de088ebfa4c1b6",
"validationError": null "validationError": null
} }
}, },

@ -4,9 +4,9 @@
"method": "engine_forkchoiceUpdatedV3", "method": "engine_forkchoiceUpdatedV3",
"params": [ "params": [
{ {
"headBlockHash": "0xc67a660f5d3c20ee603911bdff1e409e976f306883dff8ef4999dca3176f7dca", "headBlockHash": "0x14ba5ec415d827d9cab33e6097b307131e8119a1cd7dc1f6a4de088ebfa4c1b6",
"safeBlockHash": "0xc67a660f5d3c20ee603911bdff1e409e976f306883dff8ef4999dca3176f7dca", "safeBlockHash": "0x14ba5ec415d827d9cab33e6097b307131e8119a1cd7dc1f6a4de088ebfa4c1b6",
"finalizedBlockHash": "0xc67a660f5d3c20ee603911bdff1e409e976f306883dff8ef4999dca3176f7dca" "finalizedBlockHash": "0x14ba5ec415d827d9cab33e6097b307131e8119a1cd7dc1f6a4de088ebfa4c1b6"
}, },
{ {
"timestamp": "0x30", "timestamp": "0x30",
@ -24,10 +24,10 @@
"result": { "result": {
"payloadStatus": { "payloadStatus": {
"status": "VALID", "status": "VALID",
"latestValidHash": "0xc67a660f5d3c20ee603911bdff1e409e976f306883dff8ef4999dca3176f7dca", "latestValidHash": "0x14ba5ec415d827d9cab33e6097b307131e8119a1cd7dc1f6a4de088ebfa4c1b6",
"validationError": null "validationError": null
}, },
"payloadId": "0x282643a16a58b5cf" "payloadId": "0x282643aeecfdbccf"
} }
}, },
"statusCode": 200 "statusCode": 200

@ -3,7 +3,7 @@
"jsonrpc": "2.0", "jsonrpc": "2.0",
"method": "engine_getPayloadV4", "method": "engine_getPayloadV4",
"params": [ "params": [
"0x282643a16a58b5cf" "0x282643aeecfdbccf"
], ],
"id": 67 "id": 67
}, },
@ -12,9 +12,9 @@
"id": 67, "id": 67,
"result": { "result": {
"executionPayload": { "executionPayload": {
"parentHash": "0xc67a660f5d3c20ee603911bdff1e409e976f306883dff8ef4999dca3176f7dca", "parentHash": "0x14ba5ec415d827d9cab33e6097b307131e8119a1cd7dc1f6a4de088ebfa4c1b6",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", "feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0x5fc31c01a451fe02f0e938de7ec7044aaba1159a81a1be64357bc70af226f304", "stateRoot": "0xade3c29cae771ddfa994d3d2994f3bcbe084bc7bb23cdbb9bd7e35b39f007841",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380", "gasLimit": "0x1c9c380",
@ -23,16 +23,13 @@
"extraData": "0x", "extraData": "0x",
"baseFeePerGas": "0x7", "baseFeePerGas": "0x7",
"excessBlobGas": "0x0", "excessBlobGas": "0x0",
"blobGasUsed": "0x0",
"parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
"transactions": [], "transactions": [],
"withdrawals": [], "withdrawals": [],
"depositRequests": [],
"withdrawalRequests": [],
"consolidationRequests" : [],
"blockNumber": "0x3", "blockNumber": "0x3",
"blockHash": "0xdbb55a049f14b8152695bf3bbd754aa1fd55bbe10b306eb49caa4bd7d7fcb634",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"blobGasUsed": "0x0" "blockHash": "0x9f157012bdc439f5fe2bb3b4236eb07043e35d16256557d73e80a95d20054929"
}, },
"blockValue": "0x0", "blockValue": "0x0",
"blobsBundle": { "blobsBundle": {
@ -40,7 +37,12 @@
"proofs": [], "proofs": [],
"blobs": [] "blobs": []
}, },
"shouldOverrideBuilder": false "shouldOverrideBuilder": false,
"executionRequests": [
"0x",
"0x",
"0x"
]
} }
}, },
"statusCode": 200 "statusCode": 200

@ -4,9 +4,9 @@
"method": "engine_newPayloadV3", "method": "engine_newPayloadV3",
"params": [ "params": [
{ {
"parentHash": "0xc67a660f5d3c20ee603911bdff1e409e976f306883dff8ef4999dca3176f7dca", "parentHash": "0x14ba5ec415d827d9cab33e6097b307131e8119a1cd7dc1f6a4de088ebfa4c1b6",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", "feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0x5fc31c01a451fe02f0e938de7ec7044aaba1159a81a1be64357bc70af226f304", "stateRoot": "0xade3c29cae771ddfa994d3d2994f3bcbe084bc7bb23cdbb9bd7e35b39f007841",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380", "gasLimit": "0x1c9c380",
@ -14,18 +14,21 @@
"timestamp": "0x30", "timestamp": "0x30",
"extraData": "0x", "extraData": "0x",
"baseFeePerGas": "0x7", "baseFeePerGas": "0x7",
"excessBlobGas": "0x0",
"blobGasUsed": "0x0",
"transactions": [], "transactions": [],
"withdrawals": [], "withdrawals": [],
"depositRequests": [],
"withdrawalRequests": [],
"blockNumber": "0x3", "blockNumber": "0x3",
"blockHash": "0xdbb55a049f14b8152695bf3bbd754aa1fd55bbe10b306eb49caa4bd7d7fcb634",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"excessBlobGas": "0x0", "blockHash": "0x9f157012bdc439f5fe2bb3b4236eb07043e35d16256557d73e80a95d20054929"
"blobGasUsed": "0x0"
}, },
[], [],
"0x0000000000000000000000000000000000000000000000000000000000000000" "0x0000000000000000000000000000000000000000000000000000000000000000",
[
"0x",
"0x",
"0x"
]
], ],
"id": 67 "id": 67
}, },
@ -34,7 +37,7 @@
"id": 67, "id": 67,
"result": { "result": {
"status": "VALID", "status": "VALID",
"latestValidHash": "0xdbb55a049f14b8152695bf3bbd754aa1fd55bbe10b306eb49caa4bd7d7fcb634", "latestValidHash": "0x9f157012bdc439f5fe2bb3b4236eb07043e35d16256557d73e80a95d20054929",
"validationError": null "validationError": null
} }
}, },

@ -4,9 +4,9 @@
"method": "engine_forkchoiceUpdatedV3", "method": "engine_forkchoiceUpdatedV3",
"params": [ "params": [
{ {
"headBlockHash": "0xdbb55a049f14b8152695bf3bbd754aa1fd55bbe10b306eb49caa4bd7d7fcb634", "headBlockHash": "0x9f157012bdc439f5fe2bb3b4236eb07043e35d16256557d73e80a95d20054929",
"safeBlockHash": "0xdbb55a049f14b8152695bf3bbd754aa1fd55bbe10b306eb49caa4bd7d7fcb634", "safeBlockHash": "0x9f157012bdc439f5fe2bb3b4236eb07043e35d16256557d73e80a95d20054929",
"finalizedBlockHash": "0xdbb55a049f14b8152695bf3bbd754aa1fd55bbe10b306eb49caa4bd7d7fcb634" "finalizedBlockHash": "0x9f157012bdc439f5fe2bb3b4236eb07043e35d16256557d73e80a95d20054929"
}, },
{ {
"timestamp": "0x40", "timestamp": "0x40",
@ -24,10 +24,10 @@
"result": { "result": {
"payloadStatus": { "payloadStatus": {
"status": "VALID", "status": "VALID",
"latestValidHash": "0xdbb55a049f14b8152695bf3bbd754aa1fd55bbe10b306eb49caa4bd7d7fcb634", "latestValidHash": "0x9f157012bdc439f5fe2bb3b4236eb07043e35d16256557d73e80a95d20054929",
"validationError": null "validationError": null
}, },
"payloadId": "0x28264396a9634d41" "payloadId": "0x282643ae671b03bf"
} }
}, },
"statusCode": 200 "statusCode": 200

@ -3,7 +3,7 @@
"jsonrpc": "2.0", "jsonrpc": "2.0",
"method": "engine_getPayloadV4", "method": "engine_getPayloadV4",
"params": [ "params": [
"0x28264396a9634d41" "0x282643ae671b03bf"
], ],
"id": 67 "id": 67
}, },
@ -12,50 +12,40 @@
"id": 67, "id": 67,
"result": { "result": {
"executionPayload": { "executionPayload": {
"parentHash": "0xdbb55a049f14b8152695bf3bbd754aa1fd55bbe10b306eb49caa4bd7d7fcb634", "parentHash": "0x9f157012bdc439f5fe2bb3b4236eb07043e35d16256557d73e80a95d20054929",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", "feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0x49df1f1a1d28a23fa752230d442077768787d392e9edb70c83d727d31e55eaac", "stateRoot": "0xc7dbe7764cb5edd271a3e7fc4ffad23736aa1b8d4a5703e05a58db88d4ecbdc3",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000100000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000008000000000000000000000000000000000000000800000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380", "gasLimit": "0x1c9c380",
"gasUsed": "0x3ad4d", "gasUsed": "0x3b6c5",
"timestamp": "0x40", "timestamp": "0x40",
"extraData": "0x", "extraData": "0x",
"baseFeePerGas": "0x7", "baseFeePerGas": "0x7",
"excessBlobGas": "0x0", "excessBlobGas": "0x0",
"blobGasUsed": "0x0",
"parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
"transactions": [ "transactions": [
"0xf8a08085e8d4a51000832dc6c09400a3ca265ebcb825b45f985a16cefb49958ce01702b8388706d19a62f28a6a6549f96c5adaebac9124a61d44868ec94f6d2d707c6a2f82c9162071231dfeb40e24bfde4ffdf2430000000000000000822fdfa00476c1a81f80f4c130acb5f8b8075468ba0893d766b7ec51a8d9723c573ad034a03bd3eaedabbaaf745f15023185ba66584ad3ee8bb40b9bef8c0b9ed27f8b1959", "0xf8a08085e8d4a51000832dc6c09400a3ca265ebcb825b45f985a16cefb49958ce01702b8388706d19a62f28a6a6549f96c5adaebac9124a61d44868ec94f6d2d707c6a2f82c9162071231dfeb40e24bfde4ffdf2430000000000000000822fdfa00476c1a81f80f4c130acb5f8b8075468ba0893d766b7ec51a8d9723c573ad034a03bd3eaedabbaaf745f15023185ba66584ad3ee8bb40b9bef8c0b9ed27f8b1959",
"0xf8c80185e8d4a51000832dc6c09400b42dbf2194e931e80326d950320f7d9dbeac0201b860fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe822fe0a05b88b593926d340f448918ef1c6263356c37f2434774e0fdb1cb9d90cfa5a23ba003a86aac4adb774181ba51eda17efb5fbed99ad57895e6eb56ccdf508a88a7cc" "0xf8c80185e8d4a51000832dc6c09400b42dbf2194e931e80326d950320f7d9dbeac0201b860fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe822fe0a05b88b593926d340f448918ef1c6263356c37f2434774e0fdb1cb9d90cfa5a23ba003a86aac4adb774181ba51eda17efb5fbed99ad57895e6eb56ccdf508a88a7cc"
], ],
"withdrawals": [], "withdrawals": [],
"depositRequests": [],
"withdrawalRequests": [
{
"sourceAddress": "0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f",
"amount": "0x0",
"validatorPubkey": "0x8706d19a62f28a6a6549f96c5adaebac9124a61d44868ec94f6d2d707c6a2f82c9162071231dfeb40e24bfde4ffdf243"
}
],
"consolidationRequests": [
{
"sourceAddress": "0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f",
"sourcePubkey": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"targetPubkey": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
}
],
"blockNumber": "0x4", "blockNumber": "0x4",
"receiptsRoot": "0x970fc81bb3e7fb21435f9a65a184aa9e3fd2f52b89fd859302b46954354266b5", "receiptsRoot": "0x640f4036d53782ca4c5e9273ba6d657db4f5ff4fe526a8ed1997af9d0b8ae2d3",
"blobGasUsed": "0x0", "blockHash": "0x61642311e6c1e0af50abf17be1fcb6de8bd75af2ca2d188031d074f6e71bf5e6"
"blockHash": "0x93df6f3484202f24c692354e2ab96e9948ae45eea6ad85faea121a389e468ea8"
}, },
"blockValue": "0x3581baab15c12e5", "blockValue": "0x360b8482c4b509d",
"blobsBundle": { "blobsBundle": {
"commitments": [], "commitments": [],
"proofs": [], "proofs": [],
"blobs": [] "blobs": []
}, },
"shouldOverrideBuilder": false "shouldOverrideBuilder": false,
"executionRequests": [
"0x",
"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f8706d19a62f28a6a6549f96c5adaebac9124a61d44868ec94f6d2d707c6a2f82c9162071231dfeb40e24bfde4ffdf2430000000000000000",
"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
]
} }
}, },
"statusCode": 200, "statusCode": 200,

@ -38,7 +38,7 @@ public class RlpConverterServiceImplTest {
new BlockHeaderTestFixture() new BlockHeaderTestFixture()
.timestamp(1710338135 + 1) .timestamp(1710338135 + 1)
.baseFeePerGas(Wei.of(1000)) .baseFeePerGas(Wei.of(1000))
.requestsRoot(Hash.ZERO) .requestsHash(Hash.ZERO)
.withdrawalsRoot(Hash.ZERO) .withdrawalsRoot(Hash.ZERO)
.blobGasUsed(500L) .blobGasUsed(500L)
.excessBlobGas(BlobGas.of(500L)) .excessBlobGas(BlobGas.of(500L))

@ -18,12 +18,17 @@ import org.hyperledger.besu.consensus.merge.blockcreation.PayloadIdentifier;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.BlockValueCalculator; import org.hyperledger.besu.ethereum.core.BlockValueCalculator;
import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.core.BlockWithReceipts;
import org.hyperledger.besu.ethereum.core.Request;
import java.util.List;
import java.util.Optional;
/** Wrapper for payload plus extra info. */ /** Wrapper for payload plus extra info. */
public class PayloadWrapper { public class PayloadWrapper {
private final PayloadIdentifier payloadIdentifier; private final PayloadIdentifier payloadIdentifier;
private final BlockWithReceipts blockWithReceipts; private final BlockWithReceipts blockWithReceipts;
private final Wei blockValue; private final Wei blockValue;
private final Optional<List<Request>> requests;
/** /**
* Construct a wrapper with the following fields. * Construct a wrapper with the following fields.
@ -32,10 +37,13 @@ public class PayloadWrapper {
* @param blockWithReceipts Block with receipts * @param blockWithReceipts Block with receipts
*/ */
public PayloadWrapper( public PayloadWrapper(
final PayloadIdentifier payloadIdentifier, final BlockWithReceipts blockWithReceipts) { final PayloadIdentifier payloadIdentifier,
final BlockWithReceipts blockWithReceipts,
final Optional<List<Request>> requests) {
this.blockWithReceipts = blockWithReceipts; this.blockWithReceipts = blockWithReceipts;
this.payloadIdentifier = payloadIdentifier; this.payloadIdentifier = payloadIdentifier;
this.blockValue = BlockValueCalculator.calculateBlockValue(blockWithReceipts); this.blockValue = BlockValueCalculator.calculateBlockValue(blockWithReceipts);
this.requests = requests;
} }
/** /**
@ -64,4 +72,13 @@ public class PayloadWrapper {
public BlockWithReceipts blockWithReceipts() { public BlockWithReceipts blockWithReceipts() {
return blockWithReceipts; return blockWithReceipts;
} }
/**
* Get the requests
*
* @return requests
*/
public Optional<List<Request>> requests() {
return requests;
}
} }

@ -302,7 +302,9 @@ public class MergeCoordinator implements MergeMiningCoordinator, BadChainListene
if (result.isSuccessful()) { if (result.isSuccessful()) {
mergeContext.putPayloadById( mergeContext.putPayloadById(
new PayloadWrapper( new PayloadWrapper(
payloadIdentifier, new BlockWithReceipts(emptyBlock, result.getReceipts()))); payloadIdentifier,
new BlockWithReceipts(emptyBlock, result.getReceipts()),
result.getRequests()));
LOG.info( LOG.info(
"Start building proposals for block {} identified by {}", "Start building proposals for block {} identified by {}",
emptyBlock.getHeader().getNumber(), emptyBlock.getHeader().getNumber(),
@ -469,7 +471,9 @@ public class MergeCoordinator implements MergeMiningCoordinator, BadChainListene
mergeContext.putPayloadById( mergeContext.putPayloadById(
new PayloadWrapper( new PayloadWrapper(
payloadIdentifier, new BlockWithReceipts(bestBlock, resultBest.getReceipts()))); payloadIdentifier,
new BlockWithReceipts(bestBlock, resultBest.getReceipts()),
resultBest.getRequests()));
LOG.atDebug() LOG.atDebug()
.setMessage( .setMessage(
"Successfully built block {} for proposal identified by {}, with {} transactions, in {}ms") "Successfully built block {} for proposal identified by {}, with {} transactions, in {}ms")

@ -54,8 +54,7 @@ public class ProposalTest {
new BlockBody( new BlockBody(
Collections.emptyList(), Collections.emptyList(),
Collections.emptyList(), Collections.emptyList(),
Optional.of(Collections.emptyList()), Optional.of(Collections.emptyList())));
Optional.empty()));
@Test @Test
public void canRoundTripProposalMessage() { public void canRoundTripProposalMessage() {

@ -15,6 +15,7 @@
package org.hyperledger.besu.datatypes; package org.hyperledger.besu.datatypes;
import static org.hyperledger.besu.crypto.Hash.keccak256; import static org.hyperledger.besu.crypto.Hash.keccak256;
import static org.hyperledger.besu.crypto.Hash.sha256;
import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.rlp.RLP;
@ -50,6 +51,17 @@ public class Hash extends DelegatingBytes32 {
*/ */
public static final Hash EMPTY = hash(Bytes.EMPTY); public static final Hash EMPTY = hash(Bytes.EMPTY);
/**
* Hash of empty requests or "0x6036c41849da9c076ed79654d434017387a88fb833c2856b32e18218b3341c5f"
*/
public static final Hash EMPTY_REQUESTS_HASH =
Hash.wrap(
sha256(
Bytes.concatenate(
sha256(Bytes.of(RequestType.DEPOSIT.getSerializedType())),
sha256(Bytes.of(RequestType.WITHDRAWAL.getSerializedType())),
sha256(Bytes.of(RequestType.CONSOLIDATION.getSerializedType())))));
/** /**
* Instantiates a new Hash. * Instantiates a new Hash.
* *

@ -26,4 +26,12 @@ public class HashTest {
.isEqualTo( .isEqualTo(
Hash.fromHexString("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")); Hash.fromHexString("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"));
} }
@Test
public void shouldGetExpectedValueForEmptyRequestsHash() {
assertThat(Hash.EMPTY_REQUESTS_HASH)
.isEqualTo(
Hash.fromHexString(
"0x6036c41849da9c076ed79654d434017387a88fb833c2856b32e18218b3341c5f"));
}
} }

@ -38,5 +38,5 @@ public enum JsonRpcResponseKey {
TRANSACTION_ROOT, TRANSACTION_ROOT,
BASEFEE, BASEFEE,
WITHDRAWALS_ROOT, WITHDRAWALS_ROOT,
REQUESTS_ROOT REQUESTS_HASH
} }

@ -27,7 +27,7 @@ import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcResponseKey.NUMBE
import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcResponseKey.OMMERS_HASH; import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcResponseKey.OMMERS_HASH;
import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcResponseKey.PARENT_HASH; import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcResponseKey.PARENT_HASH;
import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcResponseKey.RECEIPTS_ROOT; import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcResponseKey.RECEIPTS_ROOT;
import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcResponseKey.REQUESTS_ROOT; import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcResponseKey.REQUESTS_HASH;
import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcResponseKey.SIZE; import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcResponseKey.SIZE;
import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcResponseKey.STATE_ROOT; import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcResponseKey.STATE_ROOT;
import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcResponseKey.TIMESTAMP; import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcResponseKey.TIMESTAMP;
@ -104,8 +104,8 @@ public class JsonRpcResponseUtils {
final int size = unsignedInt(values.get(SIZE)); final int size = unsignedInt(values.get(SIZE));
final Hash withdrawalsRoot = final Hash withdrawalsRoot =
values.containsKey(WITHDRAWALS_ROOT) ? hash(values.get(WITHDRAWALS_ROOT)) : null; values.containsKey(WITHDRAWALS_ROOT) ? hash(values.get(WITHDRAWALS_ROOT)) : null;
final Hash requestsRoot = final Hash requestsHash =
values.containsKey(REQUESTS_ROOT) ? hash(values.get(REQUESTS_ROOT)) : null; values.containsKey(REQUESTS_HASH) ? hash(values.get(REQUESTS_HASH)) : null;
final List<JsonNode> ommers = new ArrayList<>(); final List<JsonNode> ommers = new ArrayList<>();
final BlockHeader header = final BlockHeader header =
@ -130,7 +130,7 @@ public class JsonRpcResponseUtils {
null, // ToDo 4844: set with the value of blob_gas_used field null, // ToDo 4844: set with the value of blob_gas_used field
null, // ToDo 4844: set with the value of excess_blob_gas field null, // ToDo 4844: set with the value of excess_blob_gas field
null, // TODO 4788: set with the value of the parent beacon block root field null, // TODO 4788: set with the value of the parent beacon block root field
requestsRoot, requestsHash,
blockHeaderFunctions); blockHeaderFunctions);
return new JsonRpcSuccessResponse( return new JsonRpcSuccessResponse(

@ -79,6 +79,7 @@ public class TracedJsonRpcProcessor implements JsonRpcProcessor {
case INVALID_ENGINE_PREPARE_PAYLOAD_PARAMS: case INVALID_ENGINE_PREPARE_PAYLOAD_PARAMS:
case INVALID_ENODE_PARAMS: case INVALID_ENODE_PARAMS:
case INVALID_EXCESS_BLOB_GAS_PARAMS: case INVALID_EXCESS_BLOB_GAS_PARAMS:
case INVALID_EXECUTION_REQUESTS_PARAMS:
case INVALID_EXTRA_DATA_PARAMS: case INVALID_EXTRA_DATA_PARAMS:
case INVALID_FILTER_PARAMS: case INVALID_FILTER_PARAMS:
case INVALID_GAS_PRICE_PARAMS: case INVALID_GAS_PRICE_PARAMS:

@ -20,15 +20,14 @@ import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.Executi
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.INVALID_BLOCK_HASH; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.INVALID_BLOCK_HASH;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.SYNCING; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.SYNCING;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.VALID; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.VALID;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.RequestValidatorProvider.getConsolidationRequestValidator; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.RequestValidatorProvider.getRequestsValidator;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.RequestValidatorProvider.getDepositRequestValidator;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.RequestValidatorProvider.getWithdrawalRequestValidator;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.WithdrawalsValidatorProvider.getWithdrawalsValidator; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.WithdrawalsValidatorProvider.getWithdrawalsValidator;
import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator; import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.BlobGas;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.RequestType;
import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.BlockProcessingResult; import org.hyperledger.besu.ethereum.BlockProcessingResult;
@ -36,12 +35,9 @@ import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcRequestException; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcRequestException;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.ConsolidationRequestParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.DepositRequestParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EnginePayloadParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EnginePayloadParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalRequestParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; 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.JsonRpcResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
@ -64,7 +60,6 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.mainnet.ValidationResult;
import org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator; import org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestUtil;
import org.hyperledger.besu.ethereum.rlp.RLPException; import org.hyperledger.besu.ethereum.rlp.RLPException;
import org.hyperledger.besu.ethereum.trie.MerkleTrieException; import org.hyperledger.besu.ethereum.trie.MerkleTrieException;
import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.exception.StorageException;
@ -75,6 +70,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.IntStream;
import io.vertx.core.Vertx; import io.vertx.core.Vertx;
import io.vertx.core.json.Json; import io.vertx.core.json.Json;
@ -141,8 +137,22 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
final Optional<Bytes32> maybeParentBeaconBlockRoot = final Optional<Bytes32> maybeParentBeaconBlockRoot =
maybeParentBeaconBlockRootParam.map(Bytes32::fromHexString); maybeParentBeaconBlockRootParam.map(Bytes32::fromHexString);
final Optional<List<String>> maybeRequestsParam;
try {
maybeRequestsParam = requestContext.getOptionalList(3, String.class);
} catch (JsonRpcParameterException e) {
throw new InvalidJsonRpcRequestException(
"Invalid execution request parameters (index 3)",
RpcErrorType.INVALID_EXECUTION_REQUESTS_PARAMS,
e);
}
final ValidationResult<RpcErrorType> parameterValidationResult = final ValidationResult<RpcErrorType> parameterValidationResult =
validateParameters(blockParam, maybeVersionedHashParam, maybeParentBeaconBlockRootParam); validateParameters(
blockParam,
maybeVersionedHashParam,
maybeParentBeaconBlockRootParam,
maybeRequestsParam);
if (!parameterValidationResult.isValid()) { if (!parameterValidationResult.isValid()) {
return new JsonRpcErrorResponse(reqId, parameterValidationResult); return new JsonRpcErrorResponse(reqId, parameterValidationResult);
} }
@ -183,45 +193,24 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
return new JsonRpcErrorResponse(reqId, RpcErrorType.INVALID_WITHDRAWALS_PARAMS); return new JsonRpcErrorResponse(reqId, RpcErrorType.INVALID_WITHDRAWALS_PARAMS);
} }
final Optional<List<Request>> maybeDepositRequests = final Optional<List<Request>> maybeRequests;
Optional.ofNullable(blockParam.getDepositRequests()) try {
.map(ds -> ds.stream().map(DepositRequestParameter::toDeposit).collect(toList())); maybeRequests = extractRequests(maybeRequestsParam);
if (!getDepositRequestValidator( } catch (RuntimeException ex) {
protocolSchedule.get(), blockParam.getTimestamp(), blockParam.getBlockNumber()) return respondWithInvalid(
.validateParameter(maybeDepositRequests)) { reqId,
return new JsonRpcErrorResponse(reqId, RpcErrorType.INVALID_DEPOSIT_REQUEST_PARAMS); blockParam,
} mergeCoordinator.getLatestValidAncestor(blockParam.getParentHash()).orElse(null),
INVALID,
final Optional<List<Request>> maybeWithdrawalRequests = "Invalid execution requests");
Optional.ofNullable(blockParam.getWithdrawalRequests())
.map(
withdrawalRequest ->
withdrawalRequest.stream()
.map(WithdrawalRequestParameter::toWithdrawalRequest)
.collect(toList()));
if (!getWithdrawalRequestValidator(
protocolSchedule.get(), blockParam.getTimestamp(), blockParam.getBlockNumber())
.validateParameter(maybeWithdrawalRequests)) {
return new JsonRpcErrorResponse(reqId, RpcErrorType.INVALID_WITHDRAWALS_PARAMS);
} }
final Optional<List<Request>> maybeConsolidationRequests = if (!getRequestsValidator(
Optional.ofNullable(blockParam.getConsolidationRequests())
.map(
consolidationRequest ->
consolidationRequest.stream()
.map(ConsolidationRequestParameter::toConsolidationRequest)
.collect(toList()));
if (!getConsolidationRequestValidator(
protocolSchedule.get(), blockParam.getTimestamp(), blockParam.getBlockNumber()) protocolSchedule.get(), blockParam.getTimestamp(), blockParam.getBlockNumber())
.validateParameter(maybeConsolidationRequests)) { .validate(maybeRequests)) {
return new JsonRpcErrorResponse(reqId, RpcErrorType.INVALID_CONSOLIDATION_REQUEST_PARAMS); return new JsonRpcErrorResponse(reqId, RpcErrorType.INVALID_EXECUTION_REQUESTS_PARAMS);
} }
Optional<List<Request>> maybeRequests =
RequestUtil.combine(
maybeDepositRequests, maybeWithdrawalRequests, maybeConsolidationRequests);
if (mergeContext.get().isSyncing()) { if (mergeContext.get().isSyncing()) {
LOG.debug("We are syncing"); LOG.debug("We are syncing");
return respondWith(reqId, blockParam, null, SYNCING); return respondWith(reqId, blockParam, null, SYNCING);
@ -289,7 +278,7 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
? null ? null
: BlobGas.fromHexString(blockParam.getExcessBlobGas()), : BlobGas.fromHexString(blockParam.getExcessBlobGas()),
maybeParentBeaconBlockRoot.orElse(null), maybeParentBeaconBlockRoot.orElse(null),
maybeRequests.map(BodyValidation::requestsRoot).orElse(null), maybeRequests.map(BodyValidation::requestsHash).orElse(null),
headerFunctions); headerFunctions);
// ensure the block hash matches the blockParam hash // ensure the block hash matches the blockParam hash
@ -351,8 +340,7 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
final var block = final var block =
new Block( new Block(
newBlockHeader, newBlockHeader, new BlockBody(transactions, Collections.emptyList(), maybeWithdrawals));
new BlockBody(transactions, Collections.emptyList(), maybeWithdrawals, maybeRequests));
if (maybeParentHeader.isEmpty()) { if (maybeParentHeader.isEmpty()) {
LOG.atDebug() LOG.atDebug()
@ -466,7 +454,8 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
protected ValidationResult<RpcErrorType> validateParameters( protected ValidationResult<RpcErrorType> validateParameters(
final EnginePayloadParameter parameter, final EnginePayloadParameter parameter,
final Optional<List<String>> maybeVersionedHashParam, final Optional<List<String>> maybeVersionedHashParam,
final Optional<String> maybeBeaconBlockRootParam) { final Optional<String> maybeBeaconBlockRootParam,
final Optional<List<String>> maybeRequestsParam) {
return ValidationResult.valid(); return ValidationResult.valid();
} }
@ -562,6 +551,18 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
.collect(Collectors.toList())); .collect(Collectors.toList()));
} }
private Optional<List<Request>> extractRequests(final Optional<List<String>> maybeRequestsParam) {
if (maybeRequestsParam.isEmpty()) {
return Optional.empty();
}
return maybeRequestsParam.map(
requests ->
IntStream.range(0, requests.size())
.mapToObj(i -> new Request(RequestType.of(i), Bytes.fromHexString(requests.get(i))))
.collect(Collectors.toList()));
}
private void logImportedBlockInfo(final Block block, final int blobCount, final double timeInS) { private void logImportedBlockInfo(final Block block, final int blobCount, final double timeInS) {
final StringBuilder message = new StringBuilder(); final StringBuilder message = new StringBuilder();
message.append("Imported #%,d / %d tx"); message.append("Imported #%,d / %d tx");
@ -572,10 +573,6 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
message.append(" / %d ws"); message.append(" / %d ws");
messageArgs.add(block.getBody().getWithdrawals().get().size()); messageArgs.add(block.getBody().getWithdrawals().get().size());
} }
if (block.getBody().getRequests().isPresent()) {
message.append(" / %d rs");
messageArgs.add(block.getBody().getRequests().get().size());
}
message.append(" / %d blobs / base fee %s / %,d (%01.1f%%) gas / (%s) in %01.3fs. Peers: %d"); message.append(" / %d blobs / base fee %s / %,d (%01.1f%%) gas / (%s) in %01.3fs. Peers: %d");
messageArgs.addAll( messageArgs.addAll(
List.of( List.of(

@ -57,7 +57,8 @@ public class EngineNewPayloadV2 extends AbstractEngineNewPayload {
protected ValidationResult<RpcErrorType> validateParameters( protected ValidationResult<RpcErrorType> validateParameters(
final EnginePayloadParameter payloadParameter, final EnginePayloadParameter payloadParameter,
final Optional<List<String>> maybeVersionedHashParam, final Optional<List<String>> maybeVersionedHashParam,
final Optional<String> maybeBeaconBlockRootParam) { final Optional<String> maybeBeaconBlockRootParam,
final Optional<List<String>> maybeRequestsParam) {
if (payloadParameter.getBlobGasUsed() != null) { if (payloadParameter.getBlobGasUsed() != null) {
return ValidationResult.invalid( return ValidationResult.invalid(
RpcErrorType.INVALID_BLOB_GAS_USED_PARAMS, "Missing blob gas used field"); RpcErrorType.INVALID_BLOB_GAS_USED_PARAMS, "Missing blob gas used field");

@ -55,7 +55,8 @@ public class EngineNewPayloadV3 extends AbstractEngineNewPayload {
protected ValidationResult<RpcErrorType> validateParameters( protected ValidationResult<RpcErrorType> validateParameters(
final EnginePayloadParameter payloadParameter, final EnginePayloadParameter payloadParameter,
final Optional<List<String>> maybeVersionedHashParam, final Optional<List<String>> maybeVersionedHashParam,
final Optional<String> maybeBeaconBlockRootParam) { final Optional<String> maybeBeaconBlockRootParam,
final Optional<List<String>> maybeRequestsParam) {
if (payloadParameter.getBlobGasUsed() == null) { if (payloadParameter.getBlobGasUsed() == null) {
return ValidationResult.invalid( return ValidationResult.invalid(
RpcErrorType.INVALID_BLOB_GAS_USED_PARAMS, "Missing blob gas used field"); RpcErrorType.INVALID_BLOB_GAS_USED_PARAMS, "Missing blob gas used field");

@ -55,7 +55,8 @@ public class EngineNewPayloadV4 extends AbstractEngineNewPayload {
protected ValidationResult<RpcErrorType> validateParameters( protected ValidationResult<RpcErrorType> validateParameters(
final EnginePayloadParameter payloadParameter, final EnginePayloadParameter payloadParameter,
final Optional<List<String>> maybeVersionedHashParam, final Optional<List<String>> maybeVersionedHashParam,
final Optional<String> maybeBeaconBlockRootParam) { final Optional<String> maybeBeaconBlockRootParam,
final Optional<List<String>> maybeRequestsParam) {
if (payloadParameter.getBlobGasUsed() == null) { if (payloadParameter.getBlobGasUsed() == null) {
return ValidationResult.invalid( return ValidationResult.invalid(
RpcErrorType.INVALID_BLOB_GAS_USED_PARAMS, "Missing blob gas used field"); RpcErrorType.INVALID_BLOB_GAS_USED_PARAMS, "Missing blob gas used field");
@ -69,8 +70,9 @@ public class EngineNewPayloadV4 extends AbstractEngineNewPayload {
return ValidationResult.invalid( return ValidationResult.invalid(
RpcErrorType.INVALID_PARENT_BEACON_BLOCK_ROOT_PARAMS, RpcErrorType.INVALID_PARENT_BEACON_BLOCK_ROOT_PARAMS,
"Missing parent beacon block root field"); "Missing parent beacon block root field");
} else if (payloadParameter.getDepositRequests() == null) { } else if (maybeRequestsParam.isEmpty()) {
return ValidationResult.invalid(RpcErrorType.INVALID_PARAMS, "Missing deposit field"); return ValidationResult.invalid(
RpcErrorType.INVALID_EXECUTION_REQUESTS_PARAMS, "Missing execution requests field");
} else { } else {
return ValidationResult.valid(); return ValidationResult.valid();
} }

@ -14,64 +14,25 @@
*/ */
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine;
import org.hyperledger.besu.datatypes.RequestType;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.mainnet.requests.ProhibitedRequestsValidator; import org.hyperledger.besu.ethereum.mainnet.requests.RequestsValidator;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestValidator;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestsValidatorCoordinator;
import java.util.Optional; import java.util.Optional;
public class RequestValidatorProvider { public class RequestValidatorProvider {
public static RequestValidator getDepositRequestValidator( public static RequestsValidator getRequestsValidator(
final ProtocolSchedule protocolSchedule, final long blockTimestamp, final long blockNumber) { final ProtocolSchedule protocolSchedule, final long blockTimestamp, final long blockNumber) {
return getRequestValidator(protocolSchedule, blockTimestamp, blockNumber, RequestType.DEPOSIT);
}
public static RequestValidator getWithdrawalRequestValidator(
final ProtocolSchedule protocolSchedule, final long blockTimestamp, final long blockNumber) {
return getRequestValidator(
protocolSchedule, blockTimestamp, blockNumber, RequestType.WITHDRAWAL);
}
public static RequestValidator getConsolidationRequestValidator(
final ProtocolSchedule protocolSchedule, final long blockTimestamp, final long blockNumber) {
return getRequestValidator(
protocolSchedule, blockTimestamp, blockNumber, RequestType.CONSOLIDATION);
}
private static RequestValidator getRequestValidator(
final ProtocolSchedule protocolSchedule,
final long blockTimestamp,
final long blockNumber,
final RequestType requestType) {
RequestsValidatorCoordinator requestsValidatorCoordinator =
getRequestValidatorCoordinator(protocolSchedule, blockTimestamp, blockNumber);
return requestsValidatorCoordinator
.getRequestValidator(requestType)
.orElse(new ProhibitedRequestsValidator());
}
private static RequestsValidatorCoordinator getRequestValidatorCoordinator(
final ProtocolSchedule protocolSchedule, final long blockTimestamp, final long blockNumber) {
final BlockHeader blockHeader = final BlockHeader blockHeader =
BlockHeaderBuilder.createDefault() BlockHeaderBuilder.createDefault()
.timestamp(blockTimestamp) .timestamp(blockTimestamp)
.number(blockNumber) .number(blockNumber)
.buildBlockHeader(); .buildBlockHeader();
return getRequestValidatorCoordinator(protocolSchedule.getByBlockHeader(blockHeader)); return Optional.ofNullable(protocolSchedule.getByBlockHeader(blockHeader))
} .map(ProtocolSpec::getRequestsValidator)
.orElse(v -> true);
private static RequestsValidatorCoordinator getRequestValidatorCoordinator(
final ProtocolSpec protocolSchedule) {
return Optional.ofNullable(protocolSchedule)
.map(ProtocolSpec::getRequestsValidatorCoordinator)
.orElseGet(RequestsValidatorCoordinator::empty);
} }
} }

@ -1,102 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.parameters;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BLSPublicKey;
import org.hyperledger.besu.ethereum.core.ConsolidationRequest;
import java.util.Objects;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonProperty;
public class ConsolidationRequestParameter {
private final String sourceAddress;
private final String sourcePubkey;
private final String targetPubkey;
@JsonCreator
public ConsolidationRequestParameter(
@JsonProperty("sourceAddress") final String sourceAddress,
@JsonProperty("sourcePubkey") final String sourcePubkey,
@JsonProperty("targetPubkey") final String targetPubkey) {
this.sourceAddress = sourceAddress;
this.sourcePubkey = sourcePubkey;
this.targetPubkey = targetPubkey;
}
public static ConsolidationRequestParameter fromConsolidationRequest(
final ConsolidationRequest consolidationRequest) {
return new ConsolidationRequestParameter(
consolidationRequest.getSourceAddress().toHexString(),
consolidationRequest.getSourcePubkey().toHexString(),
consolidationRequest.getTargetPubkey().toHexString());
}
public ConsolidationRequest toConsolidationRequest() {
return new ConsolidationRequest(
Address.fromHexString(sourceAddress),
BLSPublicKey.fromHexString(sourcePubkey),
BLSPublicKey.fromHexString(targetPubkey));
}
@JsonGetter
public String getSourceAddress() {
return sourceAddress;
}
@JsonGetter
public String getSourcePubkey() {
return sourcePubkey;
}
@JsonGetter
public String getTargetPubkey() {
return targetPubkey;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final ConsolidationRequestParameter that = (ConsolidationRequestParameter) o;
return Objects.equals(sourceAddress, that.sourceAddress)
&& Objects.equals(sourcePubkey, that.sourcePubkey)
&& Objects.equals(targetPubkey, that.targetPubkey);
}
@Override
public int hashCode() {
return Objects.hash(sourceAddress, sourcePubkey, targetPubkey);
}
@Override
public String toString() {
return "ConsolidationRequestParameter{"
+ "sourceAddress='"
+ sourceAddress
+ '\''
+ ", sourcePubkey='"
+ sourcePubkey
+ '\''
+ ", targetPubkey='"
+ targetPubkey
+ '\''
+ '}';
}
}

@ -1,144 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.parameters;
import org.hyperledger.besu.datatypes.BLSPublicKey;
import org.hyperledger.besu.datatypes.BLSSignature;
import org.hyperledger.besu.datatypes.GWei;
import org.hyperledger.besu.ethereum.core.DepositRequest;
import java.util.Objects;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.vertx.core.json.JsonObject;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt64;
public class DepositRequestParameter {
private final String pubkey;
private final String withdrawalCredentials;
private final String amount;
private final String signature;
private final String index;
@JsonCreator
public DepositRequestParameter(
@JsonProperty("pubkey") final String pubkey,
@JsonProperty("withdrawalCredentials") final String withdrawalCredentials,
@JsonProperty("amount") final String amount,
@JsonProperty("signature") final String signature,
@JsonProperty("index") final String index) {
this.pubkey = pubkey;
this.withdrawalCredentials = withdrawalCredentials;
this.amount = amount;
this.signature = signature;
this.index = index;
}
public static DepositRequestParameter fromDeposit(final DepositRequest depositRequest) {
return new DepositRequestParameter(
depositRequest.getPubkey().toString(),
depositRequest.getWithdrawalCredentials().toString(),
depositRequest.getAmount().toShortHexString(),
depositRequest.getSignature().toString(),
depositRequest.getIndex().toBytes().toQuantityHexString());
}
public DepositRequest toDeposit() {
return new DepositRequest(
BLSPublicKey.fromHexString(pubkey),
Bytes32.fromHexString(withdrawalCredentials),
GWei.fromHexString(amount),
BLSSignature.fromHexString(signature),
UInt64.fromHexString(index));
}
public JsonObject asJsonObject() {
return new JsonObject()
.put("pubkey", pubkey)
.put("withdrawalCredentials", withdrawalCredentials)
.put("amount", amount)
.put("signature", signature)
.put("index", index);
}
@JsonGetter
public String getPubkey() {
return pubkey;
}
@JsonGetter
public String getWithdrawalCredentials() {
return withdrawalCredentials;
}
@JsonGetter
public String getAmount() {
return amount;
}
@JsonGetter
public String getSignature() {
return signature;
}
@JsonGetter
public String getIndex() {
return index;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final DepositRequestParameter that = (DepositRequestParameter) o;
return Objects.equals(pubkey, that.pubkey)
&& Objects.equals(withdrawalCredentials, that.withdrawalCredentials)
&& Objects.equals(amount, that.amount)
&& Objects.equals(signature, that.signature)
&& Objects.equals(index, that.index);
}
@Override
public int hashCode() {
return Objects.hash(pubkey, withdrawalCredentials, amount, signature, index);
}
@Override
public String toString() {
return "DepositRequestParameter{"
+ "pubKey='"
+ pubkey
+ '\''
+ ", withdrawalCredentials='"
+ withdrawalCredentials
+ '\''
+ ", amount='"
+ amount
+ '\''
+ ", signature='"
+ signature
+ '\''
+ ", index='"
+ index
+ '\''
+ '}';
}
}

@ -43,9 +43,6 @@ public class EnginePayloadParameter {
private final List<WithdrawalParameter> withdrawals; private final List<WithdrawalParameter> withdrawals;
private final Long blobGasUsed; private final Long blobGasUsed;
private final String excessBlobGas; private final String excessBlobGas;
private final List<DepositRequestParameter> depositRequests;
private final List<WithdrawalRequestParameter> withdrawalRequests;
private final List<ConsolidationRequestParameter> consolidationRequests;
/** /**
* Creates an instance of EnginePayloadParameter. * Creates an instance of EnginePayloadParameter.
@ -67,9 +64,6 @@ public class EnginePayloadParameter {
* @param withdrawals Array of Withdrawal * @param withdrawals Array of Withdrawal
* @param blobGasUsed QUANTITY, 64 Bits * @param blobGasUsed QUANTITY, 64 Bits
* @param excessBlobGas QUANTITY, 64 Bits * @param excessBlobGas QUANTITY, 64 Bits
* @param depositRequests List of deposit parameters.
* @param withdrawalRequestParameters List of withdrawal requests parameters.
* @param consolidationRequests List of consolidation requests parameters.
*/ */
@JsonCreator @JsonCreator
public EnginePayloadParameter( public EnginePayloadParameter(
@ -89,12 +83,7 @@ public class EnginePayloadParameter {
@JsonProperty("transactions") final List<String> transactions, @JsonProperty("transactions") final List<String> transactions,
@JsonProperty("withdrawals") final List<WithdrawalParameter> withdrawals, @JsonProperty("withdrawals") final List<WithdrawalParameter> withdrawals,
@JsonProperty("blobGasUsed") final UnsignedLongParameter blobGasUsed, @JsonProperty("blobGasUsed") final UnsignedLongParameter blobGasUsed,
@JsonProperty("excessBlobGas") final String excessBlobGas, @JsonProperty("excessBlobGas") final String excessBlobGas) {
@JsonProperty("depositRequests") final List<DepositRequestParameter> depositRequests,
@JsonProperty("withdrawalRequests")
final List<WithdrawalRequestParameter> withdrawalRequestParameters,
@JsonProperty("consolidationRequests")
final List<ConsolidationRequestParameter> consolidationRequests) {
this.blockHash = blockHash; this.blockHash = blockHash;
this.parentHash = parentHash; this.parentHash = parentHash;
this.feeRecipient = feeRecipient; this.feeRecipient = feeRecipient;
@ -112,9 +101,6 @@ public class EnginePayloadParameter {
this.withdrawals = withdrawals; this.withdrawals = withdrawals;
this.blobGasUsed = blobGasUsed == null ? null : blobGasUsed.getValue(); this.blobGasUsed = blobGasUsed == null ? null : blobGasUsed.getValue();
this.excessBlobGas = excessBlobGas; this.excessBlobGas = excessBlobGas;
this.depositRequests = depositRequests;
this.withdrawalRequests = withdrawalRequestParameters;
this.consolidationRequests = consolidationRequests;
} }
public Hash getBlockHash() { public Hash getBlockHash() {
@ -184,16 +170,4 @@ public class EnginePayloadParameter {
public String getExcessBlobGas() { public String getExcessBlobGas() {
return excessBlobGas; return excessBlobGas;
} }
public List<DepositRequestParameter> getDepositRequests() {
return depositRequests;
}
public List<WithdrawalRequestParameter> getWithdrawalRequests() {
return withdrawalRequests;
}
public List<ConsolidationRequestParameter> getConsolidationRequests() {
return consolidationRequests;
}
} }

@ -1,103 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.parameters;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BLSPublicKey;
import org.hyperledger.besu.datatypes.GWei;
import org.hyperledger.besu.ethereum.core.WithdrawalRequest;
import java.util.Objects;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonProperty;
public class WithdrawalRequestParameter {
private final String sourceAddress;
private final String validatorPubkey;
private final String amount;
@JsonCreator
public WithdrawalRequestParameter(
@JsonProperty("sourceAddress") final String sourceAddress,
@JsonProperty("validatorPubkey") final String validatorPubkey,
@JsonProperty("amount") final String amount) {
this.sourceAddress = sourceAddress;
this.validatorPubkey = validatorPubkey;
this.amount = amount;
}
public static WithdrawalRequestParameter fromWithdrawalRequest(
final WithdrawalRequest withdrawalRequest) {
return new WithdrawalRequestParameter(
withdrawalRequest.getSourceAddress().toHexString(),
withdrawalRequest.getValidatorPubkey().toHexString(),
withdrawalRequest.getAmount().toShortHexString());
}
public WithdrawalRequest toWithdrawalRequest() {
return new WithdrawalRequest(
Address.fromHexString(sourceAddress),
BLSPublicKey.fromHexString(validatorPubkey),
GWei.fromHexString(amount));
}
@JsonGetter
public String getSourceAddress() {
return sourceAddress;
}
@JsonGetter
public String getValidatorPubkey() {
return validatorPubkey;
}
@JsonGetter
public String getAmount() {
return amount;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final WithdrawalRequestParameter that = (WithdrawalRequestParameter) o;
return Objects.equals(sourceAddress, that.sourceAddress)
&& Objects.equals(validatorPubkey, that.validatorPubkey)
&& Objects.equals(amount, that.amount);
}
@Override
public int hashCode() {
return Objects.hash(sourceAddress, validatorPubkey, amount);
}
@Override
public String toString() {
return "WithdrawalRequestParameter{"
+ "sourceAddress='"
+ sourceAddress
+ '\''
+ ", validatorPubkey='"
+ validatorPubkey
+ '\''
+ ", amount='"
+ amount
+ '\''
+ '}';
}
}

@ -62,6 +62,7 @@ public enum RpcErrorType implements RpcMethodError {
INVALID_ENODE_PARAMS(INVALID_PARAMS_ERROR_CODE, "Invalid enode params"), INVALID_ENODE_PARAMS(INVALID_PARAMS_ERROR_CODE, "Invalid enode params"),
INVALID_EXCESS_BLOB_GAS_PARAMS( INVALID_EXCESS_BLOB_GAS_PARAMS(
INVALID_PARAMS_ERROR_CODE, "Invalid excess blob gas params (missing or invalid)"), INVALID_PARAMS_ERROR_CODE, "Invalid excess blob gas params (missing or invalid)"),
INVALID_EXECUTION_REQUESTS_PARAMS(INVALID_PARAMS_ERROR_CODE, "Invalid execution requests params"),
INVALID_EXTRA_DATA_PARAMS(INVALID_PARAMS_ERROR_CODE, "Invalid extra data params"), INVALID_EXTRA_DATA_PARAMS(INVALID_PARAMS_ERROR_CODE, "Invalid extra data params"),
INVALID_FILTER_PARAMS(INVALID_PARAMS_ERROR_CODE, "Invalid filter params"), INVALID_FILTER_PARAMS(INVALID_PARAMS_ERROR_CODE, "Invalid filter params"),
INVALID_GAS_PRICE_PARAMS(INVALID_PARAMS_ERROR_CODE, "Invalid gas price params"), INVALID_GAS_PRICE_PARAMS(INVALID_PARAMS_ERROR_CODE, "Invalid gas price params"),

@ -14,10 +14,6 @@
*/ */
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results;
import static org.hyperledger.besu.ethereum.mainnet.requests.RequestUtil.getConsolidationRequests;
import static org.hyperledger.besu.ethereum.mainnet.requests.RequestUtil.getDepositRequests;
import static org.hyperledger.besu.ethereum.mainnet.requests.RequestUtil.getWithdrawalRequests;
import org.hyperledger.besu.consensus.merge.PayloadWrapper; import org.hyperledger.besu.consensus.merge.PayloadWrapper;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetPayloadBodiesResultV1.PayloadBody; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EngineGetPayloadBodiesResultV1.PayloadBody;
@ -26,10 +22,12 @@ import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata;
import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockBody;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; import org.hyperledger.besu.ethereum.core.encoding.EncodingContext;
import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -162,6 +160,15 @@ public class BlockResultFactory {
TransactionEncoder.encodeOpaqueBytes(transaction, EncodingContext.BLOCK_BODY)) TransactionEncoder.encodeOpaqueBytes(transaction, EncodingContext.BLOCK_BODY))
.map(Bytes::toHexString) .map(Bytes::toHexString)
.collect(Collectors.toList()); .collect(Collectors.toList());
final Optional<List<String>> requestsWithoutRequestId =
payload
.requests()
.map(
rqs ->
rqs.stream()
.sorted(Comparator.comparing(Request::getType))
.map(r -> r.getData().toHexString())
.toList());
final BlobsBundleV1 blobsBundleV1 = final BlobsBundleV1 blobsBundleV1 =
new BlobsBundleV1(blockWithReceipts.getBlock().getBody().getTransactions()); new BlobsBundleV1(blockWithReceipts.getBlock().getBody().getTransactions());
@ -169,9 +176,7 @@ public class BlockResultFactory {
blockWithReceipts.getHeader(), blockWithReceipts.getHeader(),
txs, txs,
blockWithReceipts.getBlock().getBody().getWithdrawals(), blockWithReceipts.getBlock().getBody().getWithdrawals(),
getDepositRequests(blockWithReceipts.getBlock().getBody().getRequests()), requestsWithoutRequestId,
getWithdrawalRequests(blockWithReceipts.getBlock().getBody().getRequests()),
getConsolidationRequests(blockWithReceipts.getBlock().getBody().getRequests()),
Quantity.create(payload.blockValue()), Quantity.create(payload.blockValue()),
blobsBundleV1); blobsBundleV1);
} }

@ -14,15 +14,9 @@
*/ */
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.ConsolidationRequestParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.DepositRequestParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalRequestParameter;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.ConsolidationRequest;
import org.hyperledger.besu.ethereum.core.DepositRequest;
import org.hyperledger.besu.ethereum.core.Withdrawal; import org.hyperledger.besu.ethereum.core.Withdrawal;
import org.hyperledger.besu.ethereum.core.WithdrawalRequest;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -33,33 +27,32 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
@JsonPropertyOrder({"executionPayload", "blockValue", "blobsBundle", "shouldOverrideBuilder"}) @JsonPropertyOrder({
"executionPayload",
"blockValue",
"blobsBundle",
"shouldOverrideBuilder",
"executionRequests"
})
public class EngineGetPayloadResultV4 { public class EngineGetPayloadResultV4 {
protected final PayloadResult executionPayload; protected final PayloadResult executionPayload;
private final String blockValue; private final String blockValue;
private final BlobsBundleV1 blobsBundle; private final BlobsBundleV1 blobsBundle;
private final boolean shouldOverrideBuilder; private final boolean shouldOverrideBuilder;
private final List<String> executionRequests;
public EngineGetPayloadResultV4( public EngineGetPayloadResultV4(
final BlockHeader header, final BlockHeader header,
final List<String> transactions, final List<String> transactions,
final Optional<List<Withdrawal>> withdrawals, final Optional<List<Withdrawal>> withdrawals,
final Optional<List<DepositRequest>> depositRequests, final Optional<List<String>> executionRequests,
final Optional<List<WithdrawalRequest>> withdrawalRequests,
final Optional<List<ConsolidationRequest>> consolidationRequests,
final String blockValue, final String blockValue,
final BlobsBundleV1 blobsBundle) { final BlobsBundleV1 blobsBundle) {
this.executionPayload = this.executionPayload = new PayloadResult(header, transactions, withdrawals);
new PayloadResult(
header,
transactions,
withdrawals,
depositRequests,
withdrawalRequests,
consolidationRequests);
this.blockValue = blockValue; this.blockValue = blockValue;
this.blobsBundle = blobsBundle; this.blobsBundle = blobsBundle;
this.shouldOverrideBuilder = false; this.shouldOverrideBuilder = false;
this.executionRequests = executionRequests.orElse(null);
} }
@JsonGetter(value = "executionPayload") @JsonGetter(value = "executionPayload")
@ -82,6 +75,11 @@ public class EngineGetPayloadResultV4 {
return shouldOverrideBuilder; return shouldOverrideBuilder;
} }
@JsonGetter(value = "executionRequests")
public List<String> getExecutionRequests() {
return executionRequests;
}
public static class PayloadResult { public static class PayloadResult {
protected final String blockHash; protected final String blockHash;
@ -103,17 +101,11 @@ public class EngineGetPayloadResultV4 {
protected final List<String> transactions; protected final List<String> transactions;
private final List<WithdrawalParameter> withdrawals; private final List<WithdrawalParameter> withdrawals;
private final List<DepositRequestParameter> depositRequests;
private final List<WithdrawalRequestParameter> withdrawalRequests;
private final List<ConsolidationRequestParameter> consolidationRequests;
public PayloadResult( public PayloadResult(
final BlockHeader header, final BlockHeader header,
final List<String> transactions, final List<String> transactions,
final Optional<List<Withdrawal>> withdrawals, final Optional<List<Withdrawal>> withdrawals) {
final Optional<List<DepositRequest>> depositRequests,
final Optional<List<WithdrawalRequest>> withdrawalRequests,
final Optional<List<ConsolidationRequest>> consolidationRequests) {
this.blockNumber = Quantity.create(header.getNumber()); this.blockNumber = Quantity.create(header.getNumber());
this.blockHash = header.getHash().toString(); this.blockHash = header.getHash().toString();
this.parentHash = header.getParentHash().toString(); this.parentHash = header.getParentHash().toString();
@ -136,30 +128,6 @@ public class EngineGetPayloadResultV4 {
.map(WithdrawalParameter::fromWithdrawal) .map(WithdrawalParameter::fromWithdrawal)
.collect(Collectors.toList())) .collect(Collectors.toList()))
.orElse(null); .orElse(null);
this.depositRequests =
depositRequests
.map(
ds ->
ds.stream()
.map(DepositRequestParameter::fromDeposit)
.collect(Collectors.toList()))
.orElse(null);
this.withdrawalRequests =
withdrawalRequests
.map(
wr ->
wr.stream()
.map(WithdrawalRequestParameter::fromWithdrawalRequest)
.collect(Collectors.toList()))
.orElse(null);
this.consolidationRequests =
consolidationRequests
.map(
wr ->
wr.stream()
.map(ConsolidationRequestParameter::fromConsolidationRequest)
.collect(Collectors.toList()))
.orElse(null);
this.blobGasUsed = header.getBlobGasUsed().map(Quantity::create).orElse(Quantity.HEX_ZERO); this.blobGasUsed = header.getBlobGasUsed().map(Quantity::create).orElse(Quantity.HEX_ZERO);
this.excessBlobGas = this.excessBlobGas =
header.getExcessBlobGas().map(Quantity::create).orElse(Quantity.HEX_ZERO); header.getExcessBlobGas().map(Quantity::create).orElse(Quantity.HEX_ZERO);
@ -237,21 +205,6 @@ public class EngineGetPayloadResultV4 {
return withdrawals; return withdrawals;
} }
@JsonGetter(value = "depositRequests")
public List<DepositRequestParameter> getDepositRequests() {
return depositRequests;
}
@JsonGetter(value = "withdrawalRequests")
public List<WithdrawalRequestParameter> getWithdrawalRequests() {
return withdrawalRequests;
}
@JsonGetter(value = "consolidationRequests")
public List<ConsolidationRequestParameter> getConsolidationRequests() {
return consolidationRequests;
}
@JsonGetter(value = "feeRecipient") @JsonGetter(value = "feeRecipient")
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
public String getFeeRecipient() { public String getFeeRecipient() {

@ -99,32 +99,27 @@ public abstract class AbstractEngineGetPayloadTest extends AbstractScheduledApiT
protected static final BlockWithReceipts mockBlockWithReceipts = protected static final BlockWithReceipts mockBlockWithReceipts =
new BlockWithReceipts(mockBlock, Collections.emptyList()); new BlockWithReceipts(mockBlock, Collections.emptyList());
protected static final PayloadWrapper mockPayload = protected static final PayloadWrapper mockPayload =
new PayloadWrapper(mockPid, mockBlockWithReceipts); new PayloadWrapper(mockPid, mockBlockWithReceipts, Optional.empty());
private static final Block mockBlockWithWithdrawals = private static final Block mockBlockWithWithdrawals =
new Block( new Block(
mockHeader, mockHeader,
new BlockBody( new BlockBody(
Collections.emptyList(), Collections.emptyList(),
Collections.emptyList(), Collections.emptyList(),
Optional.of(Collections.emptyList()), Optional.of(Collections.emptyList())));
Optional.empty()));
private static final Block mockBlockWithDepositRequests = private static final Block mockBlockWithDepositRequests =
new Block( new Block(
mockHeader, mockHeader,
new BlockBody( new BlockBody(Collections.emptyList(), Collections.emptyList(), Optional.empty()));
Collections.emptyList(),
Collections.emptyList(),
Optional.empty(),
Optional.of(Collections.emptyList())));
protected static final BlockWithReceipts mockBlockWithReceiptsAndWithdrawals = protected static final BlockWithReceipts mockBlockWithReceiptsAndWithdrawals =
new BlockWithReceipts(mockBlockWithWithdrawals, Collections.emptyList()); new BlockWithReceipts(mockBlockWithWithdrawals, Collections.emptyList());
protected static final PayloadWrapper mockPayloadWithWithdrawals = protected static final PayloadWrapper mockPayloadWithWithdrawals =
new PayloadWrapper(mockPid, mockBlockWithReceiptsAndWithdrawals); new PayloadWrapper(mockPid, mockBlockWithReceiptsAndWithdrawals, Optional.empty());
protected static final BlockWithReceipts mockBlockWithReceiptsAndDepositRequests = protected static final BlockWithReceipts mockBlockWithReceiptsAndDepositRequests =
new BlockWithReceipts(mockBlockWithDepositRequests, Collections.emptyList()); new BlockWithReceipts(mockBlockWithDepositRequests, Collections.emptyList());
protected static final PayloadWrapper mockPayloadWithDepositRequests = protected static final PayloadWrapper mockPayloadWithDepositRequests =
new PayloadWrapper(mockPid, mockBlockWithReceiptsAndDepositRequests); new PayloadWrapper(mockPid, mockBlockWithReceiptsAndDepositRequests, Optional.empty());
@Mock protected ProtocolContext protocolContext; @Mock protected ProtocolContext protocolContext;

@ -38,12 +38,9 @@ import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; 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.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.ConsolidationRequestParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.DepositRequestParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EnginePayloadParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EnginePayloadParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.UnsignedLongParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.UnsignedLongParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalRequestParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; 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.JsonRpcErrorResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
@ -54,20 +51,17 @@ import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockBody;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.DepositRequest;
import org.hyperledger.besu.ethereum.core.Request; import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.core.Withdrawal; import org.hyperledger.besu.ethereum.core.Withdrawal;
import org.hyperledger.besu.ethereum.core.WithdrawalRequest;
import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.eth.manager.EthPeers;
import org.hyperledger.besu.ethereum.mainnet.BodyValidation; import org.hyperledger.besu.ethereum.mainnet.BodyValidation;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.mainnet.WithdrawalsValidator; import org.hyperledger.besu.ethereum.mainnet.WithdrawalsValidator;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestsValidatorCoordinator; import org.hyperledger.besu.ethereum.mainnet.requests.ProhibitedRequestValidator;
import org.hyperledger.besu.ethereum.trie.MerkleTrieException; import org.hyperledger.besu.ethereum.trie.MerkleTrieException;
import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.exception.StorageException;
import org.hyperledger.besu.plugin.services.rpc.RpcResponseType; import org.hyperledger.besu.plugin.services.rpc.RpcResponseType;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -130,7 +124,6 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
setupValidPayload( setupValidPayload(
new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))), new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))),
Optional.empty(), Optional.empty(),
Optional.empty(),
Optional.empty()); Optional.empty());
lenient() lenient()
.when(blockchain.getBlockHeader(mockHeader.getParentHash())) .when(blockchain.getBlockHeader(mockHeader.getParentHash()))
@ -144,10 +137,7 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
public void shouldReturnInvalidOnBlockExecutionError() { public void shouldReturnInvalidOnBlockExecutionError() {
BlockHeader mockHeader = BlockHeader mockHeader =
setupValidPayload( setupValidPayload(
new BlockProcessingResult("error 42"), new BlockProcessingResult("error 42"), Optional.empty(), Optional.empty());
Optional.empty(),
Optional.empty(),
Optional.empty());
lenient() lenient()
.when(blockchain.getBlockHeader(mockHeader.getParentHash())) .when(blockchain.getBlockHeader(mockHeader.getParentHash()))
.thenReturn(Optional.of(mock(BlockHeader.class))); .thenReturn(Optional.of(mock(BlockHeader.class)));
@ -162,8 +152,7 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
@Test @Test
public void shouldReturnAcceptedOnLatestValidAncestorEmpty() { public void shouldReturnAcceptedOnLatestValidAncestorEmpty() {
BlockHeader mockHeader = BlockHeader mockHeader = createBlockHeader(Optional.empty(), Optional.empty());
createBlockHeader(Optional.empty(), Optional.empty(), Optional.empty());
when(blockchain.getBlockByHash(mockHeader.getHash())).thenReturn(Optional.empty()); when(blockchain.getBlockByHash(mockHeader.getHash())).thenReturn(Optional.empty());
when(blockchain.getBlockHeader(mockHeader.getParentHash())) when(blockchain.getBlockHeader(mockHeader.getParentHash()))
.thenReturn(Optional.of(mock(BlockHeader.class))); .thenReturn(Optional.of(mock(BlockHeader.class)));
@ -181,8 +170,7 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
@Test @Test
public void shouldReturnSuccessOnAlreadyPresent() { public void shouldReturnSuccessOnAlreadyPresent() {
BlockHeader mockHeader = BlockHeader mockHeader = createBlockHeader(Optional.empty(), Optional.empty());
createBlockHeader(Optional.empty(), Optional.empty(), Optional.empty());
Block mockBlock = Block mockBlock =
new Block(mockHeader, new BlockBody(Collections.emptyList(), Collections.emptyList())); new Block(mockHeader, new BlockBody(Collections.emptyList(), Collections.emptyList()));
@ -195,8 +183,7 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
@Test @Test
public void shouldReturnInvalidWithLatestValidHashIsABadBlock() { public void shouldReturnInvalidWithLatestValidHashIsABadBlock() {
BlockHeader mockHeader = BlockHeader mockHeader = createBlockHeader(Optional.empty(), Optional.empty());
createBlockHeader(Optional.empty(), Optional.empty(), Optional.empty());
Hash latestValidHash = Hash.hash(Bytes32.fromHexStringLenient("0xcafebabe")); Hash latestValidHash = Hash.hash(Bytes32.fromHexStringLenient("0xcafebabe"));
when(blockchain.getBlockByHash(mockHeader.getHash())).thenReturn(Optional.empty()); when(blockchain.getBlockByHash(mockHeader.getHash())).thenReturn(Optional.empty());
@ -218,7 +205,6 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
setupValidPayload( setupValidPayload(
new BlockProcessingResult(Optional.empty(), new StorageException("database bedlam")), new BlockProcessingResult(Optional.empty(), new StorageException("database bedlam")),
Optional.empty(), Optional.empty(),
Optional.empty(),
Optional.empty()); Optional.empty());
lenient() lenient()
.when(blockchain.getBlockHeader(mockHeader.getParentHash())) .when(blockchain.getBlockHeader(mockHeader.getParentHash()))
@ -235,7 +221,6 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
setupValidPayload( setupValidPayload(
new BlockProcessingResult(Optional.empty(), new MerkleTrieException("missing leaf")), new BlockProcessingResult(Optional.empty(), new MerkleTrieException("missing leaf")),
Optional.empty(), Optional.empty(),
Optional.empty(),
Optional.empty()); Optional.empty());
lenient() lenient()
@ -250,8 +235,7 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
@Test @Test
public void shouldNotReturnInvalidOnThrownMerkleTrieException() { public void shouldNotReturnInvalidOnThrownMerkleTrieException() {
BlockHeader mockHeader = BlockHeader mockHeader = createBlockHeader(Optional.empty(), Optional.empty());
createBlockHeader(Optional.empty(), Optional.empty(), Optional.empty());
when(blockchain.getBlockByHash(mockHeader.getHash())).thenReturn(Optional.empty()); when(blockchain.getBlockByHash(mockHeader.getHash())).thenReturn(Optional.empty());
when(blockchain.getBlockHeader(mockHeader.getParentHash())) when(blockchain.getBlockHeader(mockHeader.getParentHash()))
.thenReturn(Optional.of(mock(BlockHeader.class))); .thenReturn(Optional.of(mock(BlockHeader.class)));
@ -268,8 +252,7 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
@Test @Test
public void shouldReturnInvalidBlockHashOnBadHashParameter() { public void shouldReturnInvalidBlockHashOnBadHashParameter() {
BlockHeader mockHeader = BlockHeader mockHeader = spy(createBlockHeader(Optional.empty(), Optional.empty()));
spy(createBlockHeader(Optional.empty(), Optional.empty(), Optional.empty()));
lenient() lenient()
.when(mergeCoordinator.getLatestValidAncestor(mockHeader.getBlockHash())) .when(mergeCoordinator.getLatestValidAncestor(mockHeader.getBlockHash()))
.thenReturn(Optional.empty()); .thenReturn(Optional.empty());
@ -286,8 +269,7 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
@Test @Test
public void shouldCheckBlockValidityBeforeCheckingByHashForExisting() { public void shouldCheckBlockValidityBeforeCheckingByHashForExisting() {
BlockHeader realHeader = BlockHeader realHeader = createBlockHeader(Optional.empty(), Optional.empty());
createBlockHeader(Optional.empty(), Optional.empty(), Optional.empty());
BlockHeader paramHeader = spy(realHeader); BlockHeader paramHeader = spy(realHeader);
when(paramHeader.getHash()).thenReturn(Hash.fromHexStringLenient("0x1337")); when(paramHeader.getHash()).thenReturn(Hash.fromHexStringLenient("0x1337"));
@ -301,8 +283,7 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
@Test @Test
public void shouldReturnInvalidOnMalformedTransactions() { public void shouldReturnInvalidOnMalformedTransactions() {
BlockHeader mockHeader = BlockHeader mockHeader = createBlockHeader(Optional.empty(), Optional.empty());
createBlockHeader(Optional.empty(), Optional.empty(), Optional.empty());
when(mergeCoordinator.getLatestValidAncestor(any(Hash.class))) when(mergeCoordinator.getLatestValidAncestor(any(Hash.class)))
.thenReturn(Optional.of(mockHash)); .thenReturn(Optional.of(mockHash));
@ -317,8 +298,7 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
@Test @Test
public void shouldRespondWithSyncingDuringForwardSync() { public void shouldRespondWithSyncingDuringForwardSync() {
BlockHeader mockHeader = BlockHeader mockHeader = createBlockHeader(Optional.empty(), Optional.empty());
createBlockHeader(Optional.empty(), Optional.empty(), Optional.empty());
when(mergeContext.isSyncing()).thenReturn(Boolean.TRUE); when(mergeContext.isSyncing()).thenReturn(Boolean.TRUE);
var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList())); var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList()));
@ -331,8 +311,7 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
@Test @Test
public void shouldRespondWithSyncingDuringBackwardsSync() { public void shouldRespondWithSyncingDuringBackwardsSync() {
BlockHeader mockHeader = BlockHeader mockHeader = createBlockHeader(Optional.empty(), Optional.empty());
createBlockHeader(Optional.empty(), Optional.empty(), Optional.empty());
when(mergeCoordinator.appendNewPayloadToSync(any())) when(mergeCoordinator.appendNewPayloadToSync(any()))
.thenReturn(CompletableFuture.completedFuture(null)); .thenReturn(CompletableFuture.completedFuture(null));
var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList())); var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList()));
@ -346,8 +325,7 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
@Test @Test
public void shouldRespondWithInvalidIfExtraDataIsNull() { public void shouldRespondWithInvalidIfExtraDataIsNull() {
BlockHeader realHeader = BlockHeader realHeader = createBlockHeader(Optional.empty(), Optional.empty());
createBlockHeader(Optional.empty(), Optional.empty(), Optional.empty());
BlockHeader paramHeader = spy(realHeader); BlockHeader paramHeader = spy(realHeader);
when(paramHeader.getHash()).thenReturn(Hash.fromHexStringLenient("0x1337")); when(paramHeader.getHash()).thenReturn(Hash.fromHexStringLenient("0x1337"));
when(paramHeader.getExtraData().toHexString()).thenReturn(null); when(paramHeader.getExtraData().toHexString()).thenReturn(null);
@ -364,8 +342,7 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
@Test @Test
public void shouldReturnInvalidWhenBadBlock() { public void shouldReturnInvalidWhenBadBlock() {
when(mergeCoordinator.isBadBlock(any(Hash.class))).thenReturn(true); when(mergeCoordinator.isBadBlock(any(Hash.class))).thenReturn(true);
BlockHeader mockHeader = BlockHeader mockHeader = createBlockHeader(Optional.empty(), Optional.empty());
createBlockHeader(Optional.empty(), Optional.empty(), Optional.empty());
var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList())); var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList()));
when(protocolSpec.getWithdrawalsValidator()) when(protocolSpec.getWithdrawalsValidator())
.thenReturn(new WithdrawalsValidator.AllowedWithdrawals()); .thenReturn(new WithdrawalsValidator.AllowedWithdrawals());
@ -383,7 +360,6 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
setupValidPayload( setupValidPayload(
new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))), new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))),
Optional.empty(), Optional.empty(),
Optional.empty(),
Optional.empty()); Optional.empty());
lenient() lenient()
.when(blockchain.getBlockHeader(mockHeader.getParentHash())) .when(blockchain.getBlockHeader(mockHeader.getParentHash()))
@ -404,16 +380,13 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
protected EnginePayloadParameter mockEnginePayload( protected EnginePayloadParameter mockEnginePayload(
final BlockHeader header, final List<String> txs) { final BlockHeader header, final List<String> txs) {
return mockEnginePayload(header, txs, null, null, null, null); return mockEnginePayload(header, txs, null);
} }
protected EnginePayloadParameter mockEnginePayload( protected EnginePayloadParameter mockEnginePayload(
final BlockHeader header, final BlockHeader header,
final List<String> txs, final List<String> txs,
final List<WithdrawalParameter> withdrawals, final List<WithdrawalParameter> withdrawals) {
final List<DepositRequestParameter> depositRequests,
final List<WithdrawalRequestParameter> withdrawalRequests,
final List<ConsolidationRequestParameter> consolidationRequests) {
return new EnginePayloadParameter( return new EnginePayloadParameter(
header.getHash(), header.getHash(),
header.getParentHash(), header.getParentHash(),
@ -431,23 +404,16 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
txs, txs,
withdrawals, withdrawals,
header.getBlobGasUsed().map(UnsignedLongParameter::new).orElse(null), header.getBlobGasUsed().map(UnsignedLongParameter::new).orElse(null),
header.getExcessBlobGas().map(BlobGas::toHexString).orElse(null), header.getExcessBlobGas().map(BlobGas::toHexString).orElse(null));
depositRequests,
withdrawalRequests,
consolidationRequests);
} }
protected BlockHeader setupValidPayload( protected BlockHeader setupValidPayload(
final BlockProcessingResult value, final BlockProcessingResult value,
final Optional<List<Withdrawal>> maybeWithdrawals, final Optional<List<Withdrawal>> maybeWithdrawals,
final Optional<List<DepositRequest>> maybeDepositRequests, final Optional<List<Request>> maybeRequests) {
final Optional<List<WithdrawalRequest>> maybeWithdrawalRequests) {
BlockHeader mockHeader = BlockHeader mockHeader = createBlockHeader(maybeWithdrawals, maybeRequests);
createBlockHeader(maybeWithdrawals, maybeDepositRequests, maybeWithdrawalRequests);
when(blockchain.getBlockByHash(mockHeader.getHash())).thenReturn(Optional.empty()); when(blockchain.getBlockByHash(mockHeader.getHash())).thenReturn(Optional.empty());
// when(blockchain.getBlockHeader(mockHeader.getParentHash()))
// .thenReturn(Optional.of(mock(BlockHeader.class)));
when(mergeCoordinator.getLatestValidAncestor(any(BlockHeader.class))) when(mergeCoordinator.getLatestValidAncestor(any(BlockHeader.class)))
.thenReturn(Optional.of(mockHash)); .thenReturn(Optional.of(mockHash));
when(mergeCoordinator.rememberBlock(any())).thenReturn(value); when(mergeCoordinator.rememberBlock(any())).thenReturn(value);
@ -477,27 +443,8 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
protected BlockHeader createBlockHeader( protected BlockHeader createBlockHeader(
final Optional<List<Withdrawal>> maybeWithdrawals, final Optional<List<Withdrawal>> maybeWithdrawals,
final Optional<List<DepositRequest>> maybeDepositRequests, final Optional<List<Request>> maybeRequests) {
final Optional<List<WithdrawalRequest>> maybeWithdrawalRequests) { return createBlockHeaderFixture(maybeWithdrawals, maybeRequests).buildHeader();
return createBlockHeaderFixture(maybeWithdrawals, maybeDepositRequests, maybeWithdrawalRequests)
.buildHeader();
}
protected BlockHeaderTestFixture createBlockHeaderFixture(
final Optional<List<Withdrawal>> maybeWithdrawals,
final Optional<List<DepositRequest>> maybeDepositRequests,
final Optional<List<WithdrawalRequest>> maybeWithdrawalRequests) {
Optional<List<Request>> maybeRequests;
if (maybeDepositRequests.isPresent() || maybeWithdrawalRequests.isPresent()) {
List<Request> requests = new ArrayList<>();
maybeDepositRequests.ifPresent(requests::addAll);
maybeWithdrawalRequests.ifPresent(requests::addAll);
maybeRequests = Optional.of(requests);
} else {
maybeRequests = Optional.empty();
}
return createBlockHeaderFixture(maybeWithdrawals, maybeRequests);
} }
protected BlockHeaderTestFixture createBlockHeaderFixture( protected BlockHeaderTestFixture createBlockHeaderFixture(
@ -512,7 +459,7 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
.timestamp(parentBlockHeader.getTimestamp() + 1) .timestamp(parentBlockHeader.getTimestamp() + 1)
.withdrawalsRoot(maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(null)) .withdrawalsRoot(maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(null))
.parentBeaconBlockRoot(maybeParentBeaconBlockRoot) .parentBeaconBlockRoot(maybeParentBeaconBlockRoot)
.requestsRoot(maybeRequests.map(BodyValidation::requestsRoot).orElse(null)); .requestsHash(maybeRequests.map(BodyValidation::requestsHash).orElse(null));
} }
protected void assertValidResponse(final BlockHeader mockHeader, final JsonRpcResponse resp) { protected void assertValidResponse(final BlockHeader mockHeader, final JsonRpcResponse resp) {
@ -524,7 +471,7 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
} }
private void mockProhibitedRequestsValidator() { private void mockProhibitedRequestsValidator() {
var validator = RequestsValidatorCoordinator.empty(); var validator = new ProhibitedRequestValidator();
when(protocolSpec.getRequestsValidatorCoordinator()).thenReturn(validator); when(protocolSpec.getRequestsValidator()).thenReturn(validator);
} }
} }

@ -180,7 +180,6 @@ public class EngineGetPayloadBodiesByHashV1Test {
new BlockBody( new BlockBody(
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())),
Collections.emptyList(), Collections.emptyList(),
Optional.empty(),
Optional.empty()); Optional.empty());
when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(preShanghaiBlockBody)); when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(preShanghaiBlockBody));
when(blockchain.getBlockBody(blockHash2)).thenReturn(Optional.of(preShanghaiBlockBody2)); when(blockchain.getBlockBody(blockHash2)).thenReturn(Optional.of(preShanghaiBlockBody2));
@ -211,15 +210,13 @@ public class EngineGetPayloadBodiesByHashV1Test {
new TransactionTestFixture().createTransaction(sig.generateKeyPair()), new TransactionTestFixture().createTransaction(sig.generateKeyPair()),
new TransactionTestFixture().createTransaction(sig.generateKeyPair())), new TransactionTestFixture().createTransaction(sig.generateKeyPair())),
Collections.emptyList(), Collections.emptyList(),
Optional.of(List.of(withdrawal)), Optional.of(List.of(withdrawal)));
Optional.empty());
final BlockBody shanghaiBlockBody2 = final BlockBody shanghaiBlockBody2 =
new BlockBody( new BlockBody(
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())),
Collections.emptyList(), Collections.emptyList(),
Optional.of(List.of(withdrawal2)), Optional.of(List.of(withdrawal2)));
Optional.empty());
when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(shanghaiBlockBody)); when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(shanghaiBlockBody));
when(blockchain.getBlockBody(blockHash2)).thenReturn(Optional.of(shanghaiBlockBody2)); when(blockchain.getBlockBody(blockHash2)).thenReturn(Optional.of(shanghaiBlockBody2));

@ -179,7 +179,6 @@ public class EngineGetPayloadBodiesByRangeV1Test {
new BlockBody( new BlockBody(
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())),
Collections.emptyList(), Collections.emptyList(),
Optional.empty(),
Optional.empty()); Optional.empty());
when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(130)); when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(130));
when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(preShanghaiBlockBody)); when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(preShanghaiBlockBody));
@ -214,15 +213,13 @@ public class EngineGetPayloadBodiesByRangeV1Test {
new TransactionTestFixture().createTransaction(sig.generateKeyPair()), new TransactionTestFixture().createTransaction(sig.generateKeyPair()),
new TransactionTestFixture().createTransaction(sig.generateKeyPair())), new TransactionTestFixture().createTransaction(sig.generateKeyPair())),
Collections.emptyList(), Collections.emptyList(),
Optional.of(List.of(withdrawal)), Optional.of(List.of(withdrawal)));
Optional.empty());
final BlockBody shanghaiBlockBody2 = final BlockBody shanghaiBlockBody2 =
new BlockBody( new BlockBody(
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())),
Collections.emptyList(), Collections.emptyList(),
Optional.of(List.of(withdrawal2)), Optional.of(List.of(withdrawal2)));
Optional.empty());
when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(130)); when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(130));
when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(shanghaiBlockBody)); when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(shanghaiBlockBody));
when(blockchain.getBlockBody(blockHash2)).thenReturn(Optional.of(shanghaiBlockBody2)); when(blockchain.getBlockBody(blockHash2)).thenReturn(Optional.of(shanghaiBlockBody2));
@ -252,8 +249,7 @@ public class EngineGetPayloadBodiesByRangeV1Test {
new TransactionTestFixture().createTransaction(sig.generateKeyPair()), new TransactionTestFixture().createTransaction(sig.generateKeyPair()),
new TransactionTestFixture().createTransaction(sig.generateKeyPair())), new TransactionTestFixture().createTransaction(sig.generateKeyPair())),
Collections.emptyList(), Collections.emptyList(),
Optional.of(List.of(withdrawal)), Optional.of(List.of(withdrawal)));
Optional.empty());
when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(123)); when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(123));
when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(shanghaiBlockBody)); when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(shanghaiBlockBody));
when(blockchain.getBlockHashByNumber(123)).thenReturn(Optional.of(blockHash1)); when(blockchain.getBlockHashByNumber(123)).thenReturn(Optional.of(blockHash1));
@ -276,20 +272,17 @@ public class EngineGetPayloadBodiesByRangeV1Test {
new BlockBody( new BlockBody(
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())),
Collections.emptyList(), Collections.emptyList(),
Optional.of(List.of(withdrawal)), Optional.of(List.of(withdrawal)));
Optional.empty());
final BlockBody shanghaiBlockBody2 = final BlockBody shanghaiBlockBody2 =
new BlockBody( new BlockBody(
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())),
Collections.emptyList(), Collections.emptyList(),
Optional.of(List.of(withdrawal)), Optional.of(List.of(withdrawal)));
Optional.empty());
final BlockBody shanghaiBlockBody3 = final BlockBody shanghaiBlockBody3 =
new BlockBody( new BlockBody(
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())), List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())),
Collections.emptyList(), Collections.emptyList(),
Optional.of(List.of(withdrawal)), Optional.of(List.of(withdrawal)));
Optional.empty());
when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(125)); when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(125));
when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(shanghaiBlockBody)); when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(shanghaiBlockBody));
when(blockchain.getBlockBody(blockHash2)).thenReturn(Optional.of(shanghaiBlockBody2)); when(blockchain.getBlockBody(blockHash2)).thenReturn(Optional.of(shanghaiBlockBody2));

@ -124,7 +124,8 @@ public class EngineGetPayloadV2Test extends AbstractEngineGetPayloadTest {
new Block(mockHeader, new BlockBody(Collections.emptyList(), Collections.emptyList())); new Block(mockHeader, new BlockBody(Collections.emptyList(), Collections.emptyList()));
final BlockWithReceipts mockBlockWithReceipts = final BlockWithReceipts mockBlockWithReceipts =
new BlockWithReceipts(mockBlock, Collections.emptyList()); new BlockWithReceipts(mockBlock, Collections.emptyList());
final PayloadWrapper mockPayload = new PayloadWrapper(mockPid, mockBlockWithReceipts); final PayloadWrapper mockPayload =
new PayloadWrapper(mockPid, mockBlockWithReceipts, Optional.empty());
when(mergeContext.retrievePayloadById(mockPid)).thenReturn(Optional.of(mockPayload)); when(mergeContext.retrievePayloadById(mockPid)).thenReturn(Optional.of(mockPayload));

@ -128,10 +128,10 @@ public class EngineGetPayloadV3Test extends AbstractEngineGetPayloadTest {
new BlockBody( new BlockBody(
List.of(blobTx), List.of(blobTx),
Collections.emptyList(), Collections.emptyList(),
Optional.of(Collections.emptyList()),
Optional.of(Collections.emptyList()))), Optional.of(Collections.emptyList()))),
List.of(blobReceipt)); List.of(blobReceipt));
PayloadWrapper payloadPostCancun = new PayloadWrapper(postCancunPid, postCancunBlock); PayloadWrapper payloadPostCancun =
new PayloadWrapper(postCancunPid, postCancunBlock, Optional.empty());
when(mergeContext.retrievePayloadById(postCancunPid)) when(mergeContext.retrievePayloadById(postCancunPid))
.thenReturn(Optional.of(payloadPostCancun)); .thenReturn(Optional.of(payloadPostCancun));

@ -14,6 +14,7 @@
*/ */
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine;
import static java.util.Collections.emptyList;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -27,6 +28,7 @@ import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.BlobGas;
import org.hyperledger.besu.datatypes.BlobsWithCommitments; import org.hyperledger.besu.datatypes.BlobsWithCommitments;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.RequestType;
import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
@ -41,12 +43,13 @@ import org.hyperledger.besu.ethereum.core.BlockBody;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.core.BlockWithReceipts;
import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.ethereum.core.TransactionTestFixture;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.Collections; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -128,19 +131,24 @@ public class EngineGetPayloadV4Test extends AbstractEngineGetPayloadTest {
BlockWithReceipts block = BlockWithReceipts block =
new BlockWithReceipts( new BlockWithReceipts(
new Block( new Block(
header, header, new BlockBody(List.of(blobTx), emptyList(), Optional.of(emptyList()))),
new BlockBody(
List.of(blobTx),
Collections.emptyList(),
Optional.of(Collections.emptyList()),
Optional.of(Collections.emptyList()))),
List.of(blobReceipt)); List.of(blobReceipt));
PayloadWrapper payload = new PayloadWrapper(payloadIdentifier, block); final List<Request> requests =
List.of(
new Request(RequestType.DEPOSIT, Bytes.of(1)),
new Request(RequestType.WITHDRAWAL, Bytes.of(1)),
new Request(RequestType.CONSOLIDATION, Bytes.of(1)));
PayloadWrapper payload = new PayloadWrapper(payloadIdentifier, block, Optional.of(requests));
when(mergeContext.retrievePayloadById(payloadIdentifier)).thenReturn(Optional.of(payload)); when(mergeContext.retrievePayloadById(payloadIdentifier)).thenReturn(Optional.of(payload));
final var resp = resp(RpcMethod.ENGINE_GET_PAYLOAD_V4.getMethodName(), payloadIdentifier); final var resp = resp(RpcMethod.ENGINE_GET_PAYLOAD_V4.getMethodName(), payloadIdentifier);
assertThat(resp).isInstanceOf(JsonRpcSuccessResponse.class); assertThat(resp).isInstanceOf(JsonRpcSuccessResponse.class);
final List<String> requestsWithoutRequestId =
requests.stream()
.sorted(Comparator.comparing(Request::getType))
.map(r -> r.getData().toHexString())
.toList();
Optional.of(resp) Optional.of(resp)
.map(JsonRpcSuccessResponse.class::cast) .map(JsonRpcSuccessResponse.class::cast)
.ifPresent( .ifPresent(
@ -148,9 +156,6 @@ public class EngineGetPayloadV4Test extends AbstractEngineGetPayloadTest {
assertThat(r.getResult()).isInstanceOf(EngineGetPayloadResultV4.class); assertThat(r.getResult()).isInstanceOf(EngineGetPayloadResultV4.class);
final EngineGetPayloadResultV4 res = (EngineGetPayloadResultV4) r.getResult(); final EngineGetPayloadResultV4 res = (EngineGetPayloadResultV4) r.getResult();
assertThat(res.getExecutionPayload().getWithdrawals()).isNotNull(); assertThat(res.getExecutionPayload().getWithdrawals()).isNotNull();
assertThat(res.getExecutionPayload().getDepositRequests()).isNotNull();
assertThat(res.getExecutionPayload().getWithdrawalRequests()).isNotNull();
assertThat(res.getExecutionPayload().getConsolidationRequests()).isNotNull();
assertThat(res.getExecutionPayload().getHash()) assertThat(res.getExecutionPayload().getHash())
.isEqualTo(header.getHash().toString()); .isEqualTo(header.getHash().toString());
assertThat(res.getBlockValue()).isEqualTo(Quantity.create(0)); assertThat(res.getBlockValue()).isEqualTo(Quantity.create(0));
@ -161,6 +166,8 @@ public class EngineGetPayloadV4Test extends AbstractEngineGetPayloadTest {
assertThat(res.getExecutionPayload().getExcessBlobGas()).isNotEmpty(); assertThat(res.getExecutionPayload().getExcessBlobGas()).isNotEmpty();
assertThat(res.getExecutionPayload().getExcessBlobGas()) assertThat(res.getExecutionPayload().getExcessBlobGas())
.isEqualTo(expectedQuantityOf10); .isEqualTo(expectedQuantityOf10);
assertThat(res.getExecutionRequests()).isNotEmpty();
assertThat(res.getExecutionRequests()).isEqualTo(requestsWithoutRequestId);
}); });
verify(engineCallListener, times(1)).executionEngineCalled(); verify(engineCallListener, times(1)).executionEngineCalled();
} }

@ -83,15 +83,11 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest {
setupValidPayload( setupValidPayload(
new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))), new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))),
Optional.of(withdrawals), Optional.of(withdrawals),
Optional.empty(),
Optional.empty()); Optional.empty());
lenient() lenient()
.when(blockchain.getBlockHeader(mockHeader.getParentHash())) .when(blockchain.getBlockHeader(mockHeader.getParentHash()))
.thenReturn(Optional.of(mock(BlockHeader.class))); .thenReturn(Optional.of(mock(BlockHeader.class)));
var resp = var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList(), withdrawalsParam));
resp(
mockEnginePayload(
mockHeader, Collections.emptyList(), withdrawalsParam, null, null, null));
assertValidResponse(mockHeader, resp); assertValidResponse(mockHeader, resp);
} }
@ -105,13 +101,11 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest {
setupValidPayload( setupValidPayload(
new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))), new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))),
Optional.empty(), Optional.empty(),
Optional.empty(),
Optional.empty()); Optional.empty());
lenient() lenient()
.when(blockchain.getBlockHeader(mockHeader.getParentHash())) .when(blockchain.getBlockHeader(mockHeader.getParentHash()))
.thenReturn(Optional.of(mock(BlockHeader.class))); .thenReturn(Optional.of(mock(BlockHeader.class)));
var resp = var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList(), withdrawals));
resp(mockEnginePayload(mockHeader, Collections.emptyList(), withdrawals, null, null, null));
assertValidResponse(mockHeader, resp); assertValidResponse(mockHeader, resp);
} }
@ -126,13 +120,9 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest {
var resp = var resp =
resp( resp(
mockEnginePayload( mockEnginePayload(
createBlockHeader( createBlockHeader(Optional.of(Collections.emptyList()), Optional.empty()),
Optional.of(Collections.emptyList()), Optional.empty(), Optional.empty()),
Collections.emptyList(), Collections.emptyList(),
withdrawals, withdrawals));
null,
null,
null));
final JsonRpcError jsonRpcError = fromErrorResp(resp); final JsonRpcError jsonRpcError = fromErrorResp(resp);
assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode()); assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode());
@ -143,13 +133,11 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest {
public void shouldValidateBlobGasUsedCorrectly() { public void shouldValidateBlobGasUsedCorrectly() {
// V2 should return error if non-null blobGasUsed // V2 should return error if non-null blobGasUsed
BlockHeader blockHeader = BlockHeader blockHeader =
createBlockHeaderFixture( createBlockHeaderFixture(Optional.of(Collections.emptyList()), Optional.empty())
Optional.of(Collections.emptyList()), Optional.empty(), Optional.empty())
.blobGasUsed(100L) .blobGasUsed(100L)
.buildHeader(); .buildHeader();
var resp = var resp = resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of()));
resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of(), null, null, null));
final JsonRpcError jsonRpcError = fromErrorResp(resp); final JsonRpcError jsonRpcError = fromErrorResp(resp);
assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_BLOB_GAS_USED_PARAMS.getCode()); assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_BLOB_GAS_USED_PARAMS.getCode());
assertThat(jsonRpcError.getData()).isEqualTo("Missing blob gas used field"); assertThat(jsonRpcError.getData()).isEqualTo("Missing blob gas used field");
@ -160,13 +148,11 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest {
public void shouldValidateExcessBlobGasCorrectly() { public void shouldValidateExcessBlobGasCorrectly() {
// V2 should return error if non-null ExcessBlobGas // V2 should return error if non-null ExcessBlobGas
BlockHeader blockHeader = BlockHeader blockHeader =
createBlockHeaderFixture( createBlockHeaderFixture(Optional.of(Collections.emptyList()), Optional.empty())
Optional.of(Collections.emptyList()), Optional.empty(), Optional.empty())
.excessBlobGas(BlobGas.MAX_BLOB_GAS) .excessBlobGas(BlobGas.MAX_BLOB_GAS)
.buildHeader(); .buildHeader();
var resp = var resp = resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of()));
resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of(), null, null, null));
final JsonRpcError jsonRpcError = fromErrorResp(resp); final JsonRpcError jsonRpcError = fromErrorResp(resp);
assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode()); assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode());
@ -183,12 +169,9 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest {
var resp = var resp =
resp( resp(
mockEnginePayload( mockEnginePayload(
createBlockHeader(Optional.empty(), Optional.empty(), Optional.empty()), createBlockHeader(Optional.empty(), Optional.empty()),
Collections.emptyList(), Collections.emptyList(),
withdrawals, withdrawals));
null,
null,
null));
assertThat(fromErrorResp(resp).getCode()).isEqualTo(INVALID_PARAMS.getCode()); assertThat(fromErrorResp(resp).getCode()).isEqualTo(INVALID_PARAMS.getCode());
verify(engineCallListener, times(1)).executionEngineCalled(); verify(engineCallListener, times(1)).executionEngineCalled();
@ -199,13 +182,11 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest {
// Cancun starte at timestamp 30 // Cancun starte at timestamp 30
final long blockTimestamp = 31L; final long blockTimestamp = 31L;
BlockHeader blockHeader = BlockHeader blockHeader =
createBlockHeaderFixture( createBlockHeaderFixture(Optional.of(Collections.emptyList()), Optional.empty())
Optional.of(Collections.emptyList()), Optional.empty(), Optional.empty())
.timestamp(blockTimestamp) .timestamp(blockTimestamp)
.buildHeader(); .buildHeader();
var resp = var resp = resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of()));
resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of(), null, null, null));
final JsonRpcError jsonRpcError = fromErrorResp(resp); final JsonRpcError jsonRpcError = fromErrorResp(resp);
assertThat(jsonRpcError.getCode()).isEqualTo(UNSUPPORTED_FORK.getCode()); assertThat(jsonRpcError.getCode()).isEqualTo(UNSUPPORTED_FORK.getCode());

@ -44,11 +44,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EnginePayloadS
import org.hyperledger.besu.ethereum.core.BlobTestFixture; import org.hyperledger.besu.ethereum.core.BlobTestFixture;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.DepositRequest; import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.ethereum.core.TransactionTestFixture;
import org.hyperledger.besu.ethereum.core.Withdrawal; import org.hyperledger.besu.ethereum.core.Withdrawal;
import org.hyperledger.besu.ethereum.core.WithdrawalRequest;
import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; import org.hyperledger.besu.ethereum.core.encoding.EncodingContext;
import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder;
import org.hyperledger.besu.ethereum.mainnet.BodyValidation; import org.hyperledger.besu.ethereum.mainnet.BodyValidation;
@ -135,24 +134,23 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test {
setupValidPayload( setupValidPayload(
new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))), new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))),
Optional.empty(), Optional.empty(),
Optional.empty(),
Optional.empty()); Optional.empty());
final EnginePayloadParameter payload = final EnginePayloadParameter payload =
mockEnginePayload(mockHeader, Collections.emptyList(), null, null, null, null); mockEnginePayload(mockHeader, Collections.emptyList(), null);
ValidationResult<RpcErrorType> res = ValidationResult<RpcErrorType> res =
method.validateParameters( method.validateParameters(
payload, payload,
Optional.of(List.of()), Optional.of(List.of()),
Optional.of("0x0000000000000000000000000000000000000000000000000000000000000000")); Optional.of("0x0000000000000000000000000000000000000000000000000000000000000000"),
Optional.empty());
assertThat(res.isValid()).isTrue(); assertThat(res.isValid()).isTrue();
} }
@Override @Override
protected BlockHeader createBlockHeader( protected BlockHeader createBlockHeader(
final Optional<List<Withdrawal>> maybeWithdrawals, final Optional<List<Withdrawal>> maybeWithdrawals,
final Optional<List<DepositRequest>> maybeDepositRequests, final Optional<List<Request>> maybeRequests) {
final Optional<List<WithdrawalRequest>> maybeWithdrawalRequests) {
BlockHeader parentBlockHeader = BlockHeader parentBlockHeader =
new BlockHeaderTestFixture() new BlockHeaderTestFixture()
.baseFeePerGas(Wei.ONE) .baseFeePerGas(Wei.ONE)
@ -188,14 +186,12 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test {
public void shouldValidateBlobGasUsedCorrectly() { public void shouldValidateBlobGasUsedCorrectly() {
// V3 must return error if null blobGasUsed // V3 must return error if null blobGasUsed
BlockHeader blockHeader = BlockHeader blockHeader =
createBlockHeaderFixture( createBlockHeaderFixture(Optional.of(Collections.emptyList()), Optional.empty())
Optional.of(Collections.emptyList()), Optional.empty(), Optional.empty())
.excessBlobGas(BlobGas.MAX_BLOB_GAS) .excessBlobGas(BlobGas.MAX_BLOB_GAS)
.blobGasUsed(null) .blobGasUsed(null)
.buildHeader(); .buildHeader();
var resp = var resp = resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of()));
resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of(), null, null, null));
final JsonRpcError jsonRpcError = fromErrorResp(resp); final JsonRpcError jsonRpcError = fromErrorResp(resp);
assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode()); assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode());
@ -208,14 +204,12 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test {
public void shouldValidateExcessBlobGasCorrectly() { public void shouldValidateExcessBlobGasCorrectly() {
// V3 must return error if null excessBlobGas // V3 must return error if null excessBlobGas
BlockHeader blockHeader = BlockHeader blockHeader =
createBlockHeaderFixture( createBlockHeaderFixture(Optional.of(Collections.emptyList()), Optional.empty())
Optional.of(Collections.emptyList()), Optional.empty(), Optional.empty())
.excessBlobGas(null) .excessBlobGas(null)
.blobGasUsed(100L) .blobGasUsed(100L)
.buildHeader(); .buildHeader();
var resp = var resp = resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of()));
resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of(), null, null, null));
final JsonRpcError jsonRpcError = fromErrorResp(resp); final JsonRpcError jsonRpcError = fromErrorResp(resp);
assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode()); assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode());
@ -236,7 +230,6 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test {
setupValidPayload( setupValidPayload(
new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))), new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))),
Optional.empty(), Optional.empty(),
Optional.empty(),
Optional.empty()); Optional.empty());
var resp = resp(mockEnginePayload(mockHeader, transactions)); var resp = resp(mockEnginePayload(mockHeader, transactions));

@ -15,9 +15,7 @@
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.DepositParameterTestFixture.DEPOSIT_PARAM_1; import static org.hyperledger.besu.ethereum.api.graphql.internal.response.GraphQLError.INVALID_PARAMS;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalRequestTestFixture.WITHDRAWAL_REQUEST_PARAMETER_1;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INVALID_PARAMS;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -25,7 +23,6 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.BlobGas;
import org.hyperledger.besu.datatypes.RequestType; import org.hyperledger.besu.datatypes.RequestType;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
@ -33,28 +30,24 @@ import org.hyperledger.besu.ethereum.BlockProcessingOutputs;
import org.hyperledger.besu.ethereum.BlockProcessingResult; import org.hyperledger.besu.ethereum.BlockProcessingResult;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; 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.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.DepositRequestParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EnginePayloadParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EnginePayloadParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalRequestParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.DepositRequest;
import org.hyperledger.besu.ethereum.core.Request; import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.core.Withdrawal; import org.hyperledger.besu.ethereum.core.Withdrawal;
import org.hyperledger.besu.ethereum.core.WithdrawalRequest;
import org.hyperledger.besu.ethereum.mainnet.BodyValidation; import org.hyperledger.besu.ethereum.mainnet.BodyValidation;
import org.hyperledger.besu.ethereum.mainnet.requests.DepositRequestValidator; import org.hyperledger.besu.ethereum.mainnet.requests.MainnetRequestsValidator;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestsValidatorCoordinator; import org.hyperledger.besu.ethereum.mainnet.requests.ProhibitedRequestValidator;
import org.hyperledger.besu.ethereum.mainnet.requests.WithdrawalRequestValidator;
import org.hyperledger.besu.evm.gascalculator.PragueGasCalculator; import org.hyperledger.besu.evm.gascalculator.PragueGasCalculator;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes32;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -63,8 +56,6 @@ import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test { public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
private static final Address depositContractAddress =
Address.fromHexString("0x00000000219ab540356cbb839cbe05303d7705fa");
public EngineNewPayloadV4Test() {} public EngineNewPayloadV4Test() {}
@ -92,8 +83,7 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
} }
@Test @Test
public void shouldReturnValidIfDepositRequestsIsNull_WhenDepositRequestsProhibited() { public void shouldReturnValidIfRequestsIsNull_WhenRequestsProhibited() {
final List<DepositRequestParameter> depositRequests = null;
mockProhibitedRequestsValidator(); mockProhibitedRequestsValidator();
BlockHeader mockHeader = BlockHeader mockHeader =
@ -101,170 +91,69 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
new BlockProcessingResult( new BlockProcessingResult(
Optional.of(new BlockProcessingOutputs(null, List.of(), Optional.empty()))), Optional.of(new BlockProcessingOutputs(null, List.of(), Optional.empty()))),
Optional.empty(), Optional.empty(),
Optional.empty(),
Optional.empty()); Optional.empty());
when(blockchain.getBlockHeader(mockHeader.getParentHash())) when(blockchain.getBlockHeader(mockHeader.getParentHash()))
.thenReturn(Optional.of(mock(BlockHeader.class))); .thenReturn(Optional.of(mock(BlockHeader.class)));
when(mergeCoordinator.getLatestValidAncestor(mockHeader)) when(mergeCoordinator.getLatestValidAncestor(mockHeader))
.thenReturn(Optional.of(mockHeader.getHash())); .thenReturn(Optional.of(mockHeader.getHash()));
var resp = var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList()));
resp(
mockEnginePayload(
mockHeader, Collections.emptyList(), null, depositRequests, null, null));
assertValidResponse(mockHeader, resp); assertValidResponse(mockHeader, resp);
} }
@Test @Test
public void shouldReturnInvalidIfDepositRequestsIsNull_WhenDepositRequestsAllowed() { public void shouldReturnInvalidIfRequestsIsNull_WhenRequestsAllowed() {
final List<DepositRequestParameter> depositRequests = null; mockAllowedRequestsValidator();
mockAllowedDepositRequestsRequestValidator();
var resp = var resp =
resp( resp(
mockEnginePayload( mockEnginePayload(
createBlockHeader(Optional.empty(), Optional.empty(), Optional.empty()), createBlockHeader(Optional.empty(), Optional.empty()), Collections.emptyList()));
Collections.emptyList(),
null,
depositRequests,
null,
null));
assertThat(fromErrorResp(resp).getCode()).isEqualTo(INVALID_PARAMS.getCode()); assertThat(fromErrorResp(resp).getCode()).isEqualTo(INVALID_PARAMS.getCode());
verify(engineCallListener, times(1)).executionEngineCalled(); verify(engineCallListener, times(1)).executionEngineCalled();
} }
@Test @Test
public void shouldReturnValidIfDepositRequestsIsNotNull_WhenDepositRequestsAllowed() { public void shouldReturnValidIfRequestsIsNotNull_WhenRequestsAllowed() {
final List<DepositRequestParameter> depositRequestsParam = List.of(DEPOSIT_PARAM_1); final List<Request> requests =
final List<Request> depositRequests = List.of(DEPOSIT_PARAM_1.toDeposit()); List.of(
new Request(RequestType.DEPOSIT, Bytes.of(1)),
mockAllowedDepositRequestsRequestValidator(); new Request(RequestType.WITHDRAWAL, Bytes.of(1)),
new Request(RequestType.CONSOLIDATION, Bytes.of(1)));
mockAllowedRequestsValidator();
BlockHeader mockHeader = BlockHeader mockHeader =
setupValidPayload( setupValidPayload(
new BlockProcessingResult( new BlockProcessingResult(
Optional.of( Optional.of(new BlockProcessingOutputs(null, List.of(), Optional.of(requests)))),
new BlockProcessingOutputs(null, List.of(), Optional.of(depositRequests)))),
Optional.empty(),
Optional.of(List.of(DEPOSIT_PARAM_1.toDeposit())),
Optional.empty());
when(blockchain.getBlockHeader(mockHeader.getParentHash()))
.thenReturn(Optional.of(mock(BlockHeader.class)));
when(mergeCoordinator.getLatestValidAncestor(mockHeader))
.thenReturn(Optional.of(mockHeader.getHash()));
var resp =
resp(
mockEnginePayload(
mockHeader, Collections.emptyList(), null, depositRequestsParam, null, null));
assertValidResponse(mockHeader, resp);
}
@Test
public void shouldReturnInvalidIfDepositRequestsIsNotNull_WhenDepositRequestsProhibited() {
final List<DepositRequestParameter> depositRequests = List.of();
lenient()
.when(protocolSpec.getRequestsValidatorCoordinator())
.thenReturn(RequestsValidatorCoordinator.empty());
var resp =
resp(
mockEnginePayload(
createBlockHeader(
Optional.empty(), Optional.of(Collections.emptyList()), Optional.empty()),
Collections.emptyList(),
null,
depositRequests,
null,
null));
final JsonRpcError jsonRpcError = fromErrorResp(resp);
assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode());
verify(engineCallListener, times(1)).executionEngineCalled();
}
@Test
public void shouldReturnValidIfWithdrawalRequestsIsNull_WhenWithdrawalRequestsAreProhibited() {
mockProhibitedRequestsValidator();
BlockHeader mockHeader =
setupValidPayload(
new BlockProcessingResult(
Optional.of(new BlockProcessingOutputs(null, List.of(), Optional.empty()))),
Optional.empty(),
Optional.empty(), Optional.empty(),
Optional.empty()); Optional.empty());
when(blockchain.getBlockHeader(mockHeader.getParentHash())) when(blockchain.getBlockHeader(mockHeader.getParentHash()))
.thenReturn(Optional.of(mock(BlockHeader.class))); .thenReturn(Optional.of(mock(BlockHeader.class)));
when(mergeCoordinator.getLatestValidAncestor(mockHeader)) when(mergeCoordinator.getLatestValidAncestor(mockHeader))
.thenReturn(Optional.of(mockHeader.getHash())); .thenReturn(Optional.of(mockHeader.getHash()));
var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList()), requests);
var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList(), null, null, null, null));
assertValidResponse(mockHeader, resp); assertValidResponse(mockHeader, resp);
} }
@Test @Test
public void shouldReturnInvalidIfWithdrawalRequestsIsNull_WhenWithdrawalRequestsAreAllowed() { public void shouldReturnInvalidIfRequestsIsNotNull_WhenRequestsProhibited() {
mockAllowedWithdrawalsRequestValidator(); final List<Request> requests =
List.of(
var resp = new Request(RequestType.DEPOSIT, Bytes.of(1)),
resp( new Request(RequestType.WITHDRAWAL, Bytes.of(1)),
mockEnginePayload( new Request(RequestType.CONSOLIDATION, Bytes.of(1)));
createBlockHeader(Optional.empty(), Optional.empty(), Optional.empty()),
Collections.emptyList(),
null,
null,
null,
null));
assertThat(fromErrorResp(resp).getCode()).isEqualTo(INVALID_PARAMS.getCode());
verify(engineCallListener, times(1)).executionEngineCalled();
}
@Test
public void shouldReturnValidIfWithdrawalRequestsIsNotNull_WhenWithdrawalRequestsAreAllowed() {
final List<WithdrawalRequestParameter> withdrawalRequestsParams =
List.of(WITHDRAWAL_REQUEST_PARAMETER_1);
final List<Request> withdrawalRequests =
List.of(WITHDRAWAL_REQUEST_PARAMETER_1.toWithdrawalRequest());
mockAllowedWithdrawalsRequestValidator();
BlockHeader mockHeader =
setupValidPayload(
new BlockProcessingResult(
Optional.of(
new BlockProcessingOutputs(null, List.of(), Optional.of(withdrawalRequests)))),
Optional.empty(),
Optional.empty(),
Optional.of(List.of(WITHDRAWAL_REQUEST_PARAMETER_1.toWithdrawalRequest())));
when(blockchain.getBlockHeader(mockHeader.getParentHash()))
.thenReturn(Optional.of(mock(BlockHeader.class)));
when(mergeCoordinator.getLatestValidAncestor(mockHeader))
.thenReturn(Optional.of(mockHeader.getHash()));
var resp =
resp(
mockEnginePayload(
mockHeader, Collections.emptyList(), null, null, withdrawalRequestsParams, null));
assertValidResponse(mockHeader, resp);
}
@Test
public void
shouldReturnInvalidIfWithdrawalRequestsIsNotNull_WhenWithdrawalRequestsAreProhibited() {
final List<WithdrawalRequestParameter> withdrawalRequests = List.of();
mockProhibitedRequestsValidator(); mockProhibitedRequestsValidator();
var resp = var resp =
resp( resp(
mockEnginePayload( mockEnginePayload(
createBlockHeader( createBlockHeader(Optional.empty(), Optional.of(Collections.emptyList())),
Optional.empty(), Optional.empty(), Optional.of(Collections.emptyList())), Collections.emptyList()),
Collections.emptyList(), requests);
null,
null,
withdrawalRequests,
null));
final JsonRpcError jsonRpcError = fromErrorResp(resp); final JsonRpcError jsonRpcError = fromErrorResp(resp);
assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode()); assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode());
@ -274,8 +163,7 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
@Override @Override
protected BlockHeader createBlockHeader( protected BlockHeader createBlockHeader(
final Optional<List<Withdrawal>> maybeWithdrawals, final Optional<List<Withdrawal>> maybeWithdrawals,
final Optional<List<DepositRequest>> maybeDepositRequests, final Optional<List<Request>> maybeRequests) {
final Optional<List<WithdrawalRequest>> maybeWithdrawalRequests) {
BlockHeader parentBlockHeader = BlockHeader parentBlockHeader =
new BlockHeaderTestFixture() new BlockHeaderTestFixture()
.baseFeePerGas(Wei.ONE) .baseFeePerGas(Wei.ONE)
@ -284,16 +172,6 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
.blobGasUsed(0L) .blobGasUsed(0L)
.buildHeader(); .buildHeader();
Optional<List<Request>> maybeRequests;
if (maybeDepositRequests.isPresent() || maybeWithdrawalRequests.isPresent()) {
List<Request> requests = new ArrayList<>();
maybeDepositRequests.ifPresent(requests::addAll);
maybeWithdrawalRequests.ifPresent(requests::addAll);
maybeRequests = Optional.of(requests);
} else {
maybeRequests = Optional.empty();
}
BlockHeader mockHeader = BlockHeader mockHeader =
new BlockHeaderTestFixture() new BlockHeaderTestFixture()
.baseFeePerGas(Wei.ONE) .baseFeePerGas(Wei.ONE)
@ -303,7 +181,7 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
.withdrawalsRoot(maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(null)) .withdrawalsRoot(maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(null))
.excessBlobGas(BlobGas.ZERO) .excessBlobGas(BlobGas.ZERO)
.blobGasUsed(0L) .blobGasUsed(0L)
.requestsRoot(maybeRequests.map(BodyValidation::requestsRoot).orElse(null)) .requestsHash(maybeRequests.map(BodyValidation::requestsHash).orElse(null))
.parentBeaconBlockRoot( .parentBeaconBlockRoot(
maybeParentBeaconBlockRoot.isPresent() ? maybeParentBeaconBlockRoot : null) maybeParentBeaconBlockRoot.isPresent() ? maybeParentBeaconBlockRoot : null)
.buildHeader(); .buildHeader();
@ -320,24 +198,35 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
new JsonRpcRequestContext(new JsonRpcRequest("2.0", this.method.getName(), params))); new JsonRpcRequestContext(new JsonRpcRequest("2.0", this.method.getName(), params)));
} }
private void mockProhibitedRequestsValidator() { protected JsonRpcResponse resp(
var validator = RequestsValidatorCoordinator.empty(); final EnginePayloadParameter payload, final List<Request> requests) {
when(protocolSpec.getRequestsValidatorCoordinator()).thenReturn(validator); final List<String> requestsWithoutRequestId =
requests.stream()
.sorted(Comparator.comparing(Request::getType))
.map(r -> r.getData().toHexString())
.toList();
Object[] params =
maybeParentBeaconBlockRoot
.map(
bytes32 ->
new Object[] {
payload,
Collections.emptyList(),
bytes32.toHexString(),
requestsWithoutRequestId
})
.orElseGet(() -> new Object[] {payload});
return method.response(
new JsonRpcRequestContext(new JsonRpcRequest("2.0", this.method.getName(), params)));
} }
private void mockAllowedDepositRequestsRequestValidator() { private void mockProhibitedRequestsValidator() {
var validator = var validator = new ProhibitedRequestValidator();
new RequestsValidatorCoordinator.Builder() when(protocolSpec.getRequestsValidator()).thenReturn(validator);
.addValidator(RequestType.DEPOSIT, new DepositRequestValidator(depositContractAddress))
.build();
when(protocolSpec.getRequestsValidatorCoordinator()).thenReturn(validator);
} }
private void mockAllowedWithdrawalsRequestValidator() { private void mockAllowedRequestsValidator() {
var validator = var validator = new MainnetRequestsValidator();
new RequestsValidatorCoordinator.Builder() when(protocolSpec.getRequestsValidator()).thenReturn(validator);
.addValidator(RequestType.WITHDRAWAL, new WithdrawalRequestValidator())
.build();
when(protocolSpec.getRequestsValidatorCoordinator()).thenReturn(validator);
} }
} }

@ -1,42 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.parameters;
public class DepositParameterTestFixture {
public static final DepositRequestParameter DEPOSIT_PARAM_1 =
createDeposit(
"0xb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e",
"0x0017a7fcf06faf493d30bbe2632ea7c2383cd86825e12797165de7aa35589483",
"0x773594000",
"0xa889db8300194050a2636c92a95bc7160515867614b7971a9500cdb62f9c0890217d2901c3241f86fac029428fc106930606154bd9e406d7588934a5f15b837180b17194d6e44bd6de23e43b163dfe12e369dcc75a3852cd997963f158217eb5",
"0x1");
static final DepositRequestParameter DEPOSIT_PARAM_2 =
createDeposit(
"0x8706d19a62f28a6a6549f96c5adaebac9124a61d44868ec94f6d2d707c6a2f82c9162071231dfeb40e24bfde4ffdf243",
"0x006a8dc800c6d8dd6977ef53264e2d030350f0145a91bcd167b4f1c3ea21b271",
"0x773594000",
"0x801b08ca107b623eca32ee9f9111b4e50eb9cfe19e38204b72de7dc04c5a5e00f61bab96f10842576f66020ce851083f1583dd9a6b73301bea6c245cf51f27cf96aeb018852c5f70bf485d16b957cfe49ca008913346b431e7653ae3ddb23b07",
"0x3");
private static DepositRequestParameter createDeposit(
final String pubKey,
final String withdrawalCredentials,
final String amount,
final String signature,
final String index) {
return new DepositRequestParameter(pubKey, withdrawalCredentials, amount, signature, index);
}
}

@ -1,61 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.parameters;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.DepositParameterTestFixture.DEPOSIT_PARAM_1;
import org.hyperledger.besu.datatypes.BLSPublicKey;
import org.hyperledger.besu.datatypes.BLSSignature;
import org.hyperledger.besu.datatypes.GWei;
import org.hyperledger.besu.ethereum.core.DepositRequest;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt64;
import org.junit.jupiter.api.Test;
public class DepositRequestRequestParameterTest {
@Test
public void toDeposit() {
DepositRequest expected =
new DepositRequest(
BLSPublicKey.fromHexString(
"0xb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e"),
Bytes32.fromHexString(
"0x0017a7fcf06faf493d30bbe2632ea7c2383cd86825e12797165de7aa35589483"),
GWei.of(32000000000L),
BLSSignature.fromHexString(
"0xa889db8300194050a2636c92a95bc7160515867614b7971a9500cdb62f9c0890217d2901c3241f86fac029428fc106930606154bd9e406d7588934a5f15b837180b17194d6e44bd6de23e43b163dfe12e369dcc75a3852cd997963f158217eb5"),
UInt64.ONE);
assertThat(DEPOSIT_PARAM_1.toDeposit()).isEqualTo(expected);
}
@Test
public void fromDeposit() {
DepositRequest depositRequest =
new DepositRequest(
BLSPublicKey.fromHexString(
"0xb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e"),
Bytes32.fromHexString(
"0x0017a7fcf06faf493d30bbe2632ea7c2383cd86825e12797165de7aa35589483"),
GWei.of(32000000000L),
BLSSignature.fromHexString(
"0xa889db8300194050a2636c92a95bc7160515867614b7971a9500cdb62f9c0890217d2901c3241f86fac029428fc106930606154bd9e406d7588934a5f15b837180b17194d6e44bd6de23e43b163dfe12e369dcc75a3852cd997963f158217eb5"),
UInt64.ONE);
assertThat(DepositRequestParameter.fromDeposit(depositRequest)).isEqualTo(DEPOSIT_PARAM_1);
}
}

@ -1,52 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.parameters;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalRequestTestFixture.WITHDRAWAL_REQUEST_PARAMETER_1;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BLSPublicKey;
import org.hyperledger.besu.datatypes.GWei;
import org.hyperledger.besu.ethereum.core.WithdrawalRequest;
import org.junit.jupiter.api.Test;
public class WithdrawalRequestParameterTest {
@Test
public void toWithdrawalRequest() {
WithdrawalRequest expected =
new WithdrawalRequest(
Address.fromHexString("0x814FaE9f487206471B6B0D713cD51a2D35980000"),
BLSPublicKey.fromHexString(
"0xb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e"),
GWei.ONE);
assertThat(WITHDRAWAL_REQUEST_PARAMETER_1.toWithdrawalRequest()).isEqualTo(expected);
}
@Test
public void fromWithdrawalRequest() {
WithdrawalRequest withdrawalRequest =
new WithdrawalRequest(
Address.fromHexString("0x814FaE9f487206471B6B0D713cD51a2D35980000"),
BLSPublicKey.fromHexString(
"0xb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e"),
GWei.ONE);
assertThat(WithdrawalRequestParameter.fromWithdrawalRequest(withdrawalRequest))
.isEqualTo(WITHDRAWAL_REQUEST_PARAMETER_1);
}
}

@ -1,31 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.parameters;
import org.hyperledger.besu.datatypes.GWei;
public class WithdrawalRequestTestFixture {
public static final WithdrawalRequestParameter WITHDRAWAL_REQUEST_PARAMETER_1 =
new WithdrawalRequestParameter(
"0x814fae9f487206471b6b0d713cd51a2d35980000",
"0xb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e",
GWei.ONE.toShortHexString());
static final WithdrawalRequestParameter WITHDRAWAL_REQUEST_PARAMETER_2 =
new WithdrawalRequestParameter(
"0x758b8178a9a4b7206d1f648c4a77c515cbac7000",
"0x8706d19a62f28a6a6549f96c5adaebac9124a61d44868ec94f6d2d707c6a2f82c9162071231dfeb40e24bfde4ffdf243",
GWei.ONE.toShortHexString());
}

@ -265,7 +265,7 @@ public abstract class AbstractBlockCreator implements AsyncBlockCreator {
operationTracer); operationTracer);
Optional<List<Request>> maybeRequests = Optional<List<Request>> maybeRequests =
requestProcessor.flatMap(processor -> processor.process(context)); requestProcessor.map(processor -> processor.process(context));
throwIfStopped(); throwIfStopped();
@ -304,7 +304,7 @@ public abstract class AbstractBlockCreator implements AsyncBlockCreator {
withdrawalsCanBeProcessed withdrawalsCanBeProcessed
? BodyValidation.withdrawalsRoot(maybeWithdrawals.get()) ? BodyValidation.withdrawalsRoot(maybeWithdrawals.get())
: null) : null)
.requestsRoot(maybeRequests.map(BodyValidation::requestsRoot).orElse(null)); .requestsHash(maybeRequests.map(BodyValidation::requestsHash).orElse(null));
if (usage != null) { if (usage != null) {
builder.blobGasUsed(usage.used.toLong()).excessBlobGas(usage.excessBlobGas); builder.blobGasUsed(usage.used.toLong()).excessBlobGas(usage.excessBlobGas);
} }
@ -316,8 +316,7 @@ public abstract class AbstractBlockCreator implements AsyncBlockCreator {
final Optional<List<Withdrawal>> withdrawals = final Optional<List<Withdrawal>> withdrawals =
withdrawalsCanBeProcessed ? maybeWithdrawals : Optional.empty(); withdrawalsCanBeProcessed ? maybeWithdrawals : Optional.empty();
final BlockBody blockBody = final BlockBody blockBody =
new BlockBody( new BlockBody(transactionResults.getSelectedTransactions(), ommers, withdrawals);
transactionResults.getSelectedTransactions(), ommers, withdrawals, maybeRequests);
final Block block = new Block(blockHeader, blockBody); final Block block = new Block(blockHeader, blockBody);
operationTracer.traceEndBlock(blockHeader, blockBody); operationTracer.traceEndBlock(blockHeader, blockBody);

@ -14,9 +14,8 @@
*/ */
package org.hyperledger.besu.ethereum.blockcreation; package org.hyperledger.besu.ethereum.blockcreation;
import static java.util.Collections.emptyList;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.mainnet.requests.DepositRequestProcessor.DEFAULT_DEPOSIT_CONTRACT_ADDRESS; import static org.hyperledger.besu.ethereum.mainnet.requests.RequestContractAddresses.DEFAULT_DEPOSIT_CONTRACT_ADDRESS;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
@ -31,8 +30,6 @@ import org.hyperledger.besu.crypto.SECPPrivateKey;
import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BLSPublicKey;
import org.hyperledger.besu.datatypes.BLSSignature;
import org.hyperledger.besu.datatypes.BlobGas; import org.hyperledger.besu.datatypes.BlobGas;
import org.hyperledger.besu.datatypes.BlobsWithCommitments; import org.hyperledger.besu.datatypes.BlobsWithCommitments;
import org.hyperledger.besu.datatypes.GWei; import org.hyperledger.besu.datatypes.GWei;
@ -48,7 +45,6 @@ import org.hyperledger.besu.ethereum.core.BlobTestFixture;
import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.BlockDataGenerator;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder;
import org.hyperledger.besu.ethereum.core.DepositRequest;
import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture; import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture;
import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters;
@ -81,10 +77,7 @@ import org.hyperledger.besu.ethereum.mainnet.TransactionValidatorFactory;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.mainnet.ValidationResult;
import org.hyperledger.besu.ethereum.mainnet.WithdrawalsProcessor; import org.hyperledger.besu.ethereum.mainnet.WithdrawalsProcessor;
import org.hyperledger.besu.ethereum.mainnet.requests.DepositRequestProcessor; import org.hyperledger.besu.ethereum.mainnet.requests.DepositRequestProcessor;
import org.hyperledger.besu.ethereum.mainnet.requests.DepositRequestValidator;
import org.hyperledger.besu.ethereum.mainnet.requests.ProcessRequestContext; import org.hyperledger.besu.ethereum.mainnet.requests.ProcessRequestContext;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestProcessorCoordinator;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestsValidatorCoordinator;
import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason;
import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.internal.EvmConfiguration;
@ -141,83 +134,16 @@ abstract class AbstractBlockCreatorTest {
List<TransactionReceipt> receipts = List<TransactionReceipt> receipts =
List.of(receiptWithoutDeposit1, receiptWithDeposit, receiptWithoutDeposit2); List.of(receiptWithoutDeposit1, receiptWithDeposit, receiptWithoutDeposit2);
DepositRequest expectedDepositRequest = Request expectedDepositRequest =
new DepositRequest( new Request(
BLSPublicKey.fromHexString( RequestType.DEPOSIT,
"0xb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e"), Bytes.fromHexString(
Bytes32.fromHexString( "0xb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e0017a7fcf06faf493d30bbe2632ea7c2383cd86825e12797165de7aa355894830040597307000000a889db8300194050a2636c92a95bc7160515867614b7971a9500cdb62f9c0890217d2901c3241f86fac029428fc106930606154bd9e406d7588934a5f15b837180b17194d6e44bd6de23e43b163dfe12e369dcc75a3852cd997963f158217eb53f3d080000000000"));
"0x0017a7fcf06faf493d30bbe2632ea7c2383cd86825e12797165de7aa35589483"),
GWei.of(32000000000L),
BLSSignature.fromHexString(
"0xa889db8300194050a2636c92a95bc7160515867614b7971a9500cdb62f9c0890217d2901c3241f86fac029428fc106930606154bd9e406d7588934a5f15b837180b17194d6e44bd6de23e43b163dfe12e369dcc75a3852cd997963f158217eb5"),
UInt64.valueOf(539967));
final List<DepositRequest> expectedDepositRequests = List.of(expectedDepositRequest);
var depositRequestsFromReceipts = var depositRequestsFromReceipts =
new DepositRequestProcessor(DEFAULT_DEPOSIT_CONTRACT_ADDRESS) new DepositRequestProcessor(DEFAULT_DEPOSIT_CONTRACT_ADDRESS)
.process(new ProcessRequestContext(null, null, null, receipts, null, null)); .process(new ProcessRequestContext(null, null, null, receipts, null, null));
assertThat(depositRequestsFromReceipts.get()).isEqualTo(expectedDepositRequests); assertThat(depositRequestsFromReceipts).isEqualTo(expectedDepositRequest);
}
@Test
void withAllowedDepositRequestsAndContractAddress_DepositRequestsAreParsed() {
final CreateOn miningOn =
blockCreatorWithAllowedDepositRequests(DEFAULT_DEPOSIT_CONTRACT_ADDRESS);
final BlockCreationResult blockCreationResult =
miningOn.blockCreator.createBlock(
Optional.empty(),
Optional.empty(),
Optional.of(emptyList()),
Optional.empty(),
Optional.empty(),
1L,
false,
miningOn.parentHeader);
List<Request> depositRequests = emptyList();
final Hash requestsRoot = BodyValidation.requestsRoot(depositRequests);
assertThat(blockCreationResult.getBlock().getHeader().getRequestsRoot()).hasValue(requestsRoot);
assertThat(blockCreationResult.getBlock().getBody().getRequests()).hasValue(depositRequests);
}
@Test
void withAllowedDepositRequestsAndNoContractAddress_DepositRequestsAreNotParsed() {
final CreateOn miningOn = blockCreatorWithAllowedDepositRequests(null);
final BlockCreationResult blockCreationResult =
miningOn.blockCreator.createBlock(
Optional.empty(),
Optional.empty(),
Optional.of(emptyList()),
Optional.empty(),
Optional.empty(),
1L,
false,
miningOn.parentHeader);
assertThat(blockCreationResult.getBlock().getHeader().getRequestsRoot()).isEmpty();
assertThat(blockCreationResult.getBlock().getBody().getRequests()).isEmpty();
}
@Test
void withProhibitedDepositRequests_DepositRequestsAreNotParsed() {
final CreateOn miningOn = blockCreatorWithProhibitedDepositRequests();
final BlockCreationResult blockCreationResult =
miningOn.blockCreator.createBlock(
Optional.empty(),
Optional.empty(),
Optional.of(emptyList()),
Optional.empty(),
Optional.empty(),
1L,
false,
miningOn.parentHeader);
assertThat(blockCreationResult.getBlock().getHeader().getRequestsRoot()).isEmpty();
assertThat(blockCreationResult.getBlock().getBody().getRequests()).isEmpty();
} }
@Test @Test
@ -355,12 +281,6 @@ abstract class AbstractBlockCreatorTest {
return createBlockCreator(protocolSpecAdapters); return createBlockCreator(protocolSpecAdapters);
} }
private CreateOn blockCreatorWithProhibitedDepositRequests() {
final ProtocolSpecAdapters protocolSpecAdapters =
ProtocolSpecAdapters.create(0, specBuilder -> specBuilder);
return createBlockCreator(protocolSpecAdapters);
}
private CreateOn blockCreatorWithWithdrawalsProcessor() { private CreateOn blockCreatorWithWithdrawalsProcessor() {
final ProtocolSpecAdapters protocolSpecAdapters = final ProtocolSpecAdapters protocolSpecAdapters =
ProtocolSpecAdapters.create( ProtocolSpecAdapters.create(
@ -374,27 +294,6 @@ abstract class AbstractBlockCreatorTest {
return createBlockCreator(protocolSpecAdapters); return createBlockCreator(protocolSpecAdapters);
} }
private CreateOn blockCreatorWithAllowedDepositRequests(final Address depositContractAddress) {
final ProtocolSpecAdapters protocolSpecAdapters =
ProtocolSpecAdapters.create(
0,
specBuilder ->
specBuilder
.requestsValidator(
new RequestsValidatorCoordinator.Builder()
.addValidator(
RequestType.DEPOSIT,
new DepositRequestValidator((depositContractAddress)))
.build())
.requestProcessorCoordinator(
new RequestProcessorCoordinator.Builder()
.addProcessor(
RequestType.DEPOSIT,
new DepositRequestProcessor(depositContractAddress))
.build()));
return createBlockCreator(protocolSpecAdapters);
}
record CreateOn(AbstractBlockCreator blockCreator, BlockHeader parentHeader) {} record CreateOn(AbstractBlockCreator blockCreator, BlockHeader parentHeader) {}
private CreateOn createBlockCreator(final ProtocolSpecAdapters protocolSpecAdapters) { private CreateOn createBlockCreator(final ProtocolSpecAdapters protocolSpecAdapters) {

@ -14,6 +14,7 @@
*/ */
package org.hyperledger.besu.ethereum; package org.hyperledger.besu.ethereum;
import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import java.util.ArrayList; import java.util.ArrayList;
@ -134,4 +135,13 @@ public class BlockProcessingResult extends BlockValidationResult {
return yield.get().getReceipts(); return yield.get().getReceipts();
} }
} }
/**
* Gets the requests of the result.
*
* @return the requests of the result
*/
public Optional<List<Request>> getRequests() {
return yield.flatMap(BlockProcessingOutputs::getRequests);
}
} }

@ -15,13 +15,11 @@
package org.hyperledger.besu.ethereum; package org.hyperledger.besu.ethereum;
import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.mainnet.BodyValidationMode; import org.hyperledger.besu.ethereum.mainnet.BodyValidationMode;
import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode;
import java.util.List; import java.util.List;
import java.util.Optional;
/** /**
* The BlockValidator interface defines the methods for validating and processing blocks in the * The BlockValidator interface defines the methods for validating and processing blocks in the
@ -90,7 +88,6 @@ public interface BlockValidator {
* @param context the protocol context * @param context the protocol context
* @param block the block to validate * @param block the block to validate
* @param receipts the transaction receipts * @param receipts the transaction receipts
* @param requests the requests
* @param headerValidationMode the header validation mode * @param headerValidationMode the header validation mode
* @param ommerValidationMode the ommer validation mode * @param ommerValidationMode the ommer validation mode
* @param bodyValidationMode the body validation mode * @param bodyValidationMode the body validation mode
@ -100,7 +97,6 @@ public interface BlockValidator {
final ProtocolContext context, final ProtocolContext context,
final Block block, final Block block,
final List<TransactionReceipt> receipts, final List<TransactionReceipt> receipts,
final Optional<List<Request>> requests,
final HeaderValidationMode headerValidationMode, final HeaderValidationMode headerValidationMode,
final HeaderValidationMode ommerValidationMode, final HeaderValidationMode ommerValidationMode,
final BodyValidationMode bodyValidationMode); final BodyValidationMode bodyValidationMode);

@ -171,7 +171,7 @@ public class MainnetBlockValidator implements BlockValidator {
Optional<List<Request>> maybeRequests = Optional<List<Request>> maybeRequests =
result.getYield().flatMap(BlockProcessingOutputs::getRequests); result.getYield().flatMap(BlockProcessingOutputs::getRequests);
if (!blockBodyValidator.validateBody( if (!blockBodyValidator.validateBody(
context, block, receipts, maybeRequests, worldState.rootHash(), ommerValidationMode)) { context, block, receipts, worldState.rootHash(), ommerValidationMode)) {
result = new BlockProcessingResult("failed to validate output of imported block"); result = new BlockProcessingResult("failed to validate output of imported block");
handleFailedBlockProcessing(block, result, shouldRecordBadBlock); handleFailedBlockProcessing(block, result, shouldRecordBadBlock);
return result; return result;
@ -243,7 +243,6 @@ public class MainnetBlockValidator implements BlockValidator {
final ProtocolContext context, final ProtocolContext context,
final Block block, final Block block,
final List<TransactionReceipt> receipts, final List<TransactionReceipt> receipts,
final Optional<List<Request>> requests,
final HeaderValidationMode headerValidationMode, final HeaderValidationMode headerValidationMode,
final HeaderValidationMode ommerValidationMode, final HeaderValidationMode ommerValidationMode,
final BodyValidationMode bodyValidationMode) { final BodyValidationMode bodyValidationMode) {
@ -255,7 +254,7 @@ public class MainnetBlockValidator implements BlockValidator {
} }
if (!blockBodyValidator.validateBodyLight( if (!blockBodyValidator.validateBodyLight(
context, block, receipts, requests, ommerValidationMode, bodyValidationMode)) { context, block, receipts, ommerValidationMode, bodyValidationMode)) {
badBlockManager.addBadBlock( badBlockManager.addBadBlock(
block, BadBlockCause.fromValidationFailure("Failed body validation (light)")); block, BadBlockCause.fromValidationFailure("Failed body validation (light)"));
return false; return false;

@ -28,7 +28,6 @@ import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder;
import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.core.Withdrawal; import org.hyperledger.besu.ethereum.core.Withdrawal;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions; import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions;
@ -145,10 +144,8 @@ public final class GenesisState {
private static BlockBody buildBody(final GenesisConfigFile config) { private static BlockBody buildBody(final GenesisConfigFile config) {
final Optional<List<Withdrawal>> withdrawals = final Optional<List<Withdrawal>> withdrawals =
isShanghaiAtGenesis(config) ? Optional.of(emptyList()) : Optional.empty(); isShanghaiAtGenesis(config) ? Optional.of(emptyList()) : Optional.empty();
final Optional<List<Request>> requests =
isPragueAtGenesis(config) ? Optional.of(emptyList()) : Optional.empty();
return new BlockBody(emptyList(), emptyList(), withdrawals, requests); return new BlockBody(emptyList(), emptyList(), withdrawals);
} }
public Block getBlock() { public Block getBlock() {
@ -220,7 +217,7 @@ public final class GenesisState {
.excessBlobGas(isCancunAtGenesis(genesis) ? parseExcessBlobGas(genesis) : null) .excessBlobGas(isCancunAtGenesis(genesis) ? parseExcessBlobGas(genesis) : null)
.parentBeaconBlockRoot( .parentBeaconBlockRoot(
(isCancunAtGenesis(genesis) ? parseParentBeaconBlockRoot(genesis) : null)) (isCancunAtGenesis(genesis) ? parseParentBeaconBlockRoot(genesis) : null))
.requestsRoot(isPragueAtGenesis(genesis) ? Hash.EMPTY_TRIE_HASH : null) .requestsHash(isPragueAtGenesis(genesis) ? Hash.EMPTY_REQUESTS_HASH : null)
.buildBlockHeader(); .buildBlockHeader();
} }

@ -62,7 +62,6 @@ public class Block {
out.writeList(body.getTransactions(), Transaction::writeTo); out.writeList(body.getTransactions(), Transaction::writeTo);
out.writeList(body.getOmmers(), BlockHeader::writeTo); out.writeList(body.getOmmers(), BlockHeader::writeTo);
body.getWithdrawals().ifPresent(withdrawals -> out.writeList(withdrawals, Withdrawal::writeTo)); body.getWithdrawals().ifPresent(withdrawals -> out.writeList(withdrawals, Withdrawal::writeTo));
body.getRequests().ifPresent(requests -> out.writeList(requests, Request::writeTo));
out.endList(); out.endList();
} }
@ -74,11 +73,9 @@ public class Block {
final List<BlockHeader> ommers = in.readList(rlp -> BlockHeader.readFrom(rlp, hashFunction)); final List<BlockHeader> ommers = in.readList(rlp -> BlockHeader.readFrom(rlp, hashFunction));
final Optional<List<Withdrawal>> withdrawals = final Optional<List<Withdrawal>> withdrawals =
in.isEndOfCurrentList() ? Optional.empty() : Optional.of(in.readList(Withdrawal::readFrom)); in.isEndOfCurrentList() ? Optional.empty() : Optional.of(in.readList(Withdrawal::readFrom));
final Optional<List<Request>> requests =
in.isEndOfCurrentList() ? Optional.empty() : Optional.of(in.readList(Request::readFrom));
in.leaveList(); in.leaveList();
return new Block(header, new BlockBody(transactions, ommers, withdrawals, requests)); return new Block(header, new BlockBody(transactions, ommers, withdrawals));
} }
@Override @Override

@ -37,24 +37,20 @@ public class BlockBody implements org.hyperledger.besu.plugin.data.BlockBody {
private final List<BlockHeader> ommers; private final List<BlockHeader> ommers;
private final Optional<List<Withdrawal>> withdrawals; private final Optional<List<Withdrawal>> withdrawals;
private final Optional<List<Request>> requests;
public BlockBody(final List<Transaction> transactions, final List<BlockHeader> ommers) { public BlockBody(final List<Transaction> transactions, final List<BlockHeader> ommers) {
this.transactions = transactions; this.transactions = transactions;
this.ommers = ommers; this.ommers = ommers;
this.withdrawals = Optional.empty(); this.withdrawals = Optional.empty();
this.requests = Optional.empty();
} }
public BlockBody( public BlockBody(
final List<Transaction> transactions, final List<Transaction> transactions,
final List<BlockHeader> ommers, final List<BlockHeader> ommers,
final Optional<List<Withdrawal>> withdrawals, final Optional<List<Withdrawal>> withdrawals) {
final Optional<List<Request>> requests) {
this.transactions = transactions; this.transactions = transactions;
this.ommers = ommers; this.ommers = ommers;
this.withdrawals = withdrawals; this.withdrawals = withdrawals;
this.requests = requests;
} }
public static BlockBody empty() { public static BlockBody empty() {
@ -87,16 +83,6 @@ public class BlockBody implements org.hyperledger.besu.plugin.data.BlockBody {
return withdrawals; return withdrawals;
} }
/**
* Returns the withdrawal requests of the block.
*
* @return The optional list of withdrawal requests included in the block.
*/
@Override
public Optional<List<Request>> getRequests() {
return requests;
}
/** /**
* Writes Block to {@link RLPOutput}. * Writes Block to {@link RLPOutput}.
* *
@ -112,7 +98,6 @@ public class BlockBody implements org.hyperledger.besu.plugin.data.BlockBody {
output.writeList(getTransactions(), Transaction::writeTo); output.writeList(getTransactions(), Transaction::writeTo);
output.writeList(getOmmers(), BlockHeader::writeTo); output.writeList(getOmmers(), BlockHeader::writeTo);
withdrawals.ifPresent(withdrawals -> output.writeList(withdrawals, Withdrawal::writeTo)); withdrawals.ifPresent(withdrawals -> output.writeList(withdrawals, Withdrawal::writeTo));
requests.ifPresent(requests -> output.writeList(requests, Request::writeTo));
} }
public static BlockBody readWrappedBodyFrom( public static BlockBody readWrappedBodyFrom(
@ -161,10 +146,7 @@ public class BlockBody implements org.hyperledger.besu.plugin.data.BlockBody {
input.readList(rlp -> BlockHeader.readFrom(rlp, blockHeaderFunctions)), input.readList(rlp -> BlockHeader.readFrom(rlp, blockHeaderFunctions)),
input.isEndOfCurrentList() input.isEndOfCurrentList()
? Optional.empty() ? Optional.empty()
: Optional.of(input.readList(Withdrawal::readFrom)), : Optional.of(input.readList(Withdrawal::readFrom)));
input.isEndOfCurrentList()
? Optional.empty()
: Optional.of(input.readList(Request::readFrom)));
} }
@Override @Override
@ -174,20 +156,16 @@ public class BlockBody implements org.hyperledger.besu.plugin.data.BlockBody {
BlockBody blockBody = (BlockBody) o; BlockBody blockBody = (BlockBody) o;
return Objects.equals(transactions, blockBody.transactions) return Objects.equals(transactions, blockBody.transactions)
&& Objects.equals(ommers, blockBody.ommers) && Objects.equals(ommers, blockBody.ommers)
&& Objects.equals(withdrawals, blockBody.withdrawals) && Objects.equals(withdrawals, blockBody.withdrawals);
&& Objects.equals(requests, blockBody.requests);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(transactions, ommers, withdrawals, requests); return Objects.hash(transactions, ommers, withdrawals);
} }
public boolean isEmpty() { public boolean isEmpty() {
return transactions.isEmpty() return transactions.isEmpty() && ommers.isEmpty() && withdrawals.isEmpty();
&& ommers.isEmpty()
&& withdrawals.isEmpty()
&& requests.isEmpty();
} }
@Override @Override
@ -199,8 +177,6 @@ public class BlockBody implements org.hyperledger.besu.plugin.data.BlockBody {
+ ommers + ommers
+ ", withdrawals=" + ", withdrawals="
+ withdrawals + withdrawals
+ ", withdrawal_requests="
+ requests
+ '}'; + '}';
} }
} }

@ -64,7 +64,7 @@ public class BlockHeader extends SealableBlockHeader
final Long blobGasUsed, final Long blobGasUsed,
final BlobGas excessBlobGas, final BlobGas excessBlobGas,
final Bytes32 parentBeaconBlockRoot, final Bytes32 parentBeaconBlockRoot,
final Hash requestsRoot, final Hash requestsHash,
final BlockHeaderFunctions blockHeaderFunctions) { final BlockHeaderFunctions blockHeaderFunctions) {
super( super(
parentHash, parentHash,
@ -86,7 +86,7 @@ public class BlockHeader extends SealableBlockHeader
blobGasUsed, blobGasUsed,
excessBlobGas, excessBlobGas,
parentBeaconBlockRoot, parentBeaconBlockRoot,
requestsRoot); requestsHash);
this.nonce = nonce; this.nonce = nonce;
this.hash = Suppliers.memoize(() -> blockHeaderFunctions.hash(this)); this.hash = Suppliers.memoize(() -> blockHeaderFunctions.hash(this));
this.parsedExtraData = Suppliers.memoize(() -> blockHeaderFunctions.parseExtraData(this)); this.parsedExtraData = Suppliers.memoize(() -> blockHeaderFunctions.parseExtraData(this));
@ -100,8 +100,8 @@ public class BlockHeader extends SealableBlockHeader
.map(wsRoot -> wsRoot.equals(Hash.EMPTY_TRIE_HASH)) .map(wsRoot -> wsRoot.equals(Hash.EMPTY_TRIE_HASH))
.orElse(true) .orElse(true)
&& blockHeader && blockHeader
.getRequestsRoot() .getRequestsHash()
.map(reqRoot -> reqRoot.equals(Hash.EMPTY_TRIE_HASH)) .map(reqHash -> reqHash.equals(Hash.EMPTY_REQUESTS_HASH))
.orElse(true); .orElse(true);
} }
@ -185,8 +185,8 @@ public class BlockHeader extends SealableBlockHeader
if (parentBeaconBlockRoot == null) break; if (parentBeaconBlockRoot == null) break;
out.writeBytes(parentBeaconBlockRoot); out.writeBytes(parentBeaconBlockRoot);
if (requestsRoot == null) break; if (requestsHash == null) break;
out.writeBytes(requestsRoot); out.writeBytes(requestsHash);
} while (false); } while (false);
out.endList(); out.endList();
} }
@ -218,7 +218,7 @@ public class BlockHeader extends SealableBlockHeader
final BlobGas excessBlobGas = final BlobGas excessBlobGas =
!input.isEndOfCurrentList() ? BlobGas.of(input.readUInt64Scalar()) : null; !input.isEndOfCurrentList() ? BlobGas.of(input.readUInt64Scalar()) : null;
final Bytes32 parentBeaconBlockRoot = !input.isEndOfCurrentList() ? input.readBytes32() : null; final Bytes32 parentBeaconBlockRoot = !input.isEndOfCurrentList() ? input.readBytes32() : null;
final Hash requestsRoot = !input.isEndOfCurrentList() ? Hash.wrap(input.readBytes32()) : null; final Hash requestsHash = !input.isEndOfCurrentList() ? Hash.wrap(input.readBytes32()) : null;
input.leaveList(); input.leaveList();
return new BlockHeader( return new BlockHeader(
parentHash, parentHash,
@ -241,7 +241,7 @@ public class BlockHeader extends SealableBlockHeader
blobGasUsed, blobGasUsed,
excessBlobGas, excessBlobGas,
parentBeaconBlockRoot, parentBeaconBlockRoot,
requestsRoot, requestsHash,
blockHeaderFunctions); blockHeaderFunctions);
} }
@ -292,8 +292,8 @@ public class BlockHeader extends SealableBlockHeader
if (parentBeaconBlockRoot != null) { if (parentBeaconBlockRoot != null) {
sb.append("parentBeaconBlockRoot=").append(parentBeaconBlockRoot).append(", "); sb.append("parentBeaconBlockRoot=").append(parentBeaconBlockRoot).append(", ");
} }
if (requestsRoot != null) { if (requestsHash != null) {
sb.append("requestsRoot=").append(requestsRoot); sb.append("requestsHash=").append(requestsHash);
} }
return sb.append("}").toString(); return sb.append("}").toString();
} }
@ -326,7 +326,7 @@ public class BlockHeader extends SealableBlockHeader
pluginBlockHeader.getExcessBlobGas().map(BlobGas.class::cast).orElse(null), pluginBlockHeader.getExcessBlobGas().map(BlobGas.class::cast).orElse(null),
pluginBlockHeader.getParentBeaconBlockRoot().orElse(null), pluginBlockHeader.getParentBeaconBlockRoot().orElse(null),
pluginBlockHeader pluginBlockHeader
.getRequestsRoot() .getRequestsHash()
.map(h -> Hash.fromHexString(h.toHexString())) .map(h -> Hash.fromHexString(h.toHexString()))
.orElse(null), .orElse(null),
blockHeaderFunctions); blockHeaderFunctions);

@ -45,7 +45,7 @@ public class BlockHeaderBuilder {
private Hash transactionsRoot; private Hash transactionsRoot;
private Hash withdrawalsRoot = null; private Hash withdrawalsRoot = null;
private Hash requestsRoot = null; private Hash requestsHash = null;
private Hash receiptsRoot; private Hash receiptsRoot;
@ -124,7 +124,7 @@ public class BlockHeaderBuilder {
.blobGasUsed(header.getBlobGasUsed().orElse(null)) .blobGasUsed(header.getBlobGasUsed().orElse(null))
.excessBlobGas(header.getExcessBlobGas().orElse(null)) .excessBlobGas(header.getExcessBlobGas().orElse(null))
.parentBeaconBlockRoot(header.getParentBeaconBlockRoot().orElse(null)) .parentBeaconBlockRoot(header.getParentBeaconBlockRoot().orElse(null))
.requestsRoot(header.getRequestsRoot().orElse(null)); .requestsHash(header.getRequestsHash().orElse(null));
} }
public static BlockHeaderBuilder fromBuilder(final BlockHeaderBuilder fromBuilder) { public static BlockHeaderBuilder fromBuilder(final BlockHeaderBuilder fromBuilder) {
@ -148,7 +148,7 @@ public class BlockHeaderBuilder {
.withdrawalsRoot(fromBuilder.withdrawalsRoot) .withdrawalsRoot(fromBuilder.withdrawalsRoot)
.excessBlobGas(fromBuilder.excessBlobGas) .excessBlobGas(fromBuilder.excessBlobGas)
.parentBeaconBlockRoot(fromBuilder.parentBeaconBlockRoot) .parentBeaconBlockRoot(fromBuilder.parentBeaconBlockRoot)
.requestsRoot(fromBuilder.requestsRoot) .requestsHash(fromBuilder.requestsHash)
.blockHeaderFunctions(fromBuilder.blockHeaderFunctions); .blockHeaderFunctions(fromBuilder.blockHeaderFunctions);
toBuilder.nonce = fromBuilder.nonce; toBuilder.nonce = fromBuilder.nonce;
return toBuilder; return toBuilder;
@ -178,7 +178,7 @@ public class BlockHeaderBuilder {
blobGasUsed, blobGasUsed,
excessBlobGas, excessBlobGas,
parentBeaconBlockRoot, parentBeaconBlockRoot,
requestsRoot, requestsHash,
blockHeaderFunctions); blockHeaderFunctions);
} }
@ -220,7 +220,7 @@ public class BlockHeaderBuilder {
blobGasUsed, blobGasUsed,
excessBlobGas, excessBlobGas,
parentBeaconBlockRoot, parentBeaconBlockRoot,
requestsRoot); requestsHash);
} }
private void validateBlockHeader() { private void validateBlockHeader() {
@ -284,7 +284,7 @@ public class BlockHeaderBuilder {
sealableBlockHeader.getBlobGasUsed().ifPresent(this::blobGasUsed); sealableBlockHeader.getBlobGasUsed().ifPresent(this::blobGasUsed);
sealableBlockHeader.getExcessBlobGas().ifPresent(this::excessBlobGas); sealableBlockHeader.getExcessBlobGas().ifPresent(this::excessBlobGas);
sealableBlockHeader.getParentBeaconBlockRoot().ifPresent(this::parentBeaconBlockRoot); sealableBlockHeader.getParentBeaconBlockRoot().ifPresent(this::parentBeaconBlockRoot);
requestsRoot(sealableBlockHeader.getRequestsRoot().orElse(null)); requestsHash(sealableBlockHeader.getRequestsHash().orElse(null));
return this; return this;
} }
@ -399,8 +399,8 @@ public class BlockHeaderBuilder {
return this; return this;
} }
public BlockHeaderBuilder requestsRoot(final Hash hash) { public BlockHeaderBuilder requestsHash(final Hash hash) {
this.requestsRoot = hash; this.requestsHash = hash;
return this; return this;
} }

@ -1,90 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.core;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BLSPublicKey;
import org.hyperledger.besu.datatypes.PublicKey;
import org.hyperledger.besu.datatypes.RequestType;
import java.util.Objects;
public class ConsolidationRequest extends Request
implements org.hyperledger.besu.plugin.data.ConsolidationRequest {
private final Address sourceAddress;
private final BLSPublicKey sourcePubkey;
private final BLSPublicKey targetPubkey;
public ConsolidationRequest(
final Address sourceAddress,
final BLSPublicKey sourcePubkey,
final BLSPublicKey targetPubkey) {
this.sourceAddress = sourceAddress;
this.sourcePubkey = sourcePubkey;
this.targetPubkey = targetPubkey;
}
@Override
public RequestType getType() {
return RequestType.CONSOLIDATION;
}
@Override
public Address getSourceAddress() {
return sourceAddress;
}
@Override
public PublicKey getSourcePubkey() {
return sourcePubkey;
}
@Override
public PublicKey getTargetPubkey() {
return targetPubkey;
}
@Override
public String toString() {
return "ConsolidationRequest{"
+ "sourceAddress="
+ sourceAddress
+ " sourcePubkey="
+ sourcePubkey
+ " targetPubkey="
+ targetPubkey
+ '}';
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final ConsolidationRequest that = (ConsolidationRequest) o;
return Objects.equals(sourceAddress, that.sourceAddress)
&& Objects.equals(sourcePubkey, that.sourcePubkey)
&& Objects.equals(targetPubkey, that.targetPubkey);
}
@Override
public int hashCode() {
return Objects.hash(sourceAddress, sourcePubkey, targetPubkey);
}
}

@ -1,112 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.core;
import org.hyperledger.besu.datatypes.BLSPublicKey;
import org.hyperledger.besu.datatypes.BLSSignature;
import org.hyperledger.besu.datatypes.GWei;
import org.hyperledger.besu.datatypes.PublicKey;
import org.hyperledger.besu.datatypes.RequestType;
import java.util.Objects;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt64;
public class DepositRequest extends Request
implements org.hyperledger.besu.plugin.data.DepositRequest {
private final BLSPublicKey pubkey;
private final Bytes32 depositWithdrawalCredentials;
private final GWei amount;
private final BLSSignature signature;
private final UInt64 index;
public DepositRequest(
final BLSPublicKey pubkey,
final Bytes32 depositWithdrawalCredentials,
final GWei amount,
final BLSSignature signature,
final UInt64 index) {
this.pubkey = pubkey;
this.depositWithdrawalCredentials = depositWithdrawalCredentials;
this.amount = amount;
this.signature = signature;
this.index = index;
}
@Override
public RequestType getType() {
return RequestType.DEPOSIT;
}
@Override
public PublicKey getPubkey() {
return pubkey;
}
@Override
public Bytes32 getWithdrawalCredentials() {
return depositWithdrawalCredentials;
}
@Override
public GWei getAmount() {
return amount;
}
@Override
public BLSSignature getSignature() {
return signature;
}
@Override
public UInt64 getIndex() {
return index;
}
@Override
public String toString() {
return "Deposit{"
+ "pubKey="
+ pubkey
+ ", withdrawalCredentials="
+ depositWithdrawalCredentials
+ ", amount="
+ amount
+ ", signature="
+ signature
+ ", index="
+ index
+ '}';
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final DepositRequest that = (DepositRequest) o;
return Objects.equals(pubkey, that.pubkey)
&& Objects.equals(depositWithdrawalCredentials, that.depositWithdrawalCredentials)
&& Objects.equals(amount, that.amount)
&& Objects.equals(signature, that.signature)
&& Objects.equals(index, that.index);
}
@Override
public int hashCode() {
return Objects.hash(pubkey, depositWithdrawalCredentials, amount, signature, index);
}
}

@ -15,27 +15,18 @@
package org.hyperledger.besu.ethereum.core; package org.hyperledger.besu.ethereum.core;
import org.hyperledger.besu.datatypes.RequestType; import org.hyperledger.besu.datatypes.RequestType;
import org.hyperledger.besu.ethereum.core.encoding.RequestDecoder;
import org.hyperledger.besu.ethereum.core.encoding.RequestEncoder;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.rlp.RLPInput;
import org.hyperledger.besu.ethereum.rlp.RLPOutput;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
public abstract class Request implements org.hyperledger.besu.plugin.data.Request { public record Request(RequestType type, Bytes data)
implements org.hyperledger.besu.plugin.data.Request {
@Override @Override
public abstract RequestType getType(); public RequestType getType() {
return type();
public static Request readFrom(final Bytes rlpBytes) {
return readFrom(RLP.input(rlpBytes));
}
public static Request readFrom(final RLPInput rlpInput) {
return RequestDecoder.decode(rlpInput);
} }
public void writeTo(final RLPOutput out) { @Override
RequestEncoder.encode(this, out); public Bytes getData() {
return data();
} }
} }

@ -43,7 +43,7 @@ public class SealableBlockHeader extends ProcessableBlockHeader {
protected final Hash withdrawalsRoot; protected final Hash withdrawalsRoot;
protected final Hash requestsRoot; protected final Hash requestsHash;
protected final Long blobGasUsed; protected final Long blobGasUsed;
@ -69,7 +69,7 @@ public class SealableBlockHeader extends ProcessableBlockHeader {
final Long blobGasUsed, final Long blobGasUsed,
final BlobGas excessBlobGas, final BlobGas excessBlobGas,
final Bytes32 parentBeaconBlockRoot, final Bytes32 parentBeaconBlockRoot,
final Hash requestsRoot) { final Hash requestsHash) {
super( super(
parentHash, parentHash,
coinbase, coinbase,
@ -85,7 +85,7 @@ public class SealableBlockHeader extends ProcessableBlockHeader {
this.transactionsRoot = transactionsRoot; this.transactionsRoot = transactionsRoot;
this.withdrawalsRoot = withdrawalsRoot; this.withdrawalsRoot = withdrawalsRoot;
this.receiptsRoot = receiptsRoot; this.receiptsRoot = receiptsRoot;
this.requestsRoot = requestsRoot; this.requestsHash = requestsHash;
this.logsBloom = logsBloom; this.logsBloom = logsBloom;
this.gasUsed = gasUsed; this.gasUsed = gasUsed;
this.extraData = extraData; this.extraData = extraData;
@ -166,12 +166,12 @@ public class SealableBlockHeader extends ProcessableBlockHeader {
} }
/** /**
* Returns the block requests root hash. * Returns the block requests hash.
* *
* @return the block requests root hash * @return the block requests hash
*/ */
public Optional<Hash> getRequestsRoot() { public Optional<Hash> getRequestsHash() {
return Optional.ofNullable(requestsRoot); return Optional.ofNullable(requestsHash);
} }
/** /**

@ -1,89 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.core;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BLSPublicKey;
import org.hyperledger.besu.datatypes.GWei;
import org.hyperledger.besu.datatypes.PublicKey;
import org.hyperledger.besu.datatypes.RequestType;
import java.util.Objects;
public class WithdrawalRequest extends Request
implements org.hyperledger.besu.plugin.data.WithdrawalRequest {
private final Address sourceAddress;
private final BLSPublicKey validatorPubkey;
private final GWei amount;
public WithdrawalRequest(
final Address sourceAddress, final BLSPublicKey validatorPubkey, final GWei amount) {
this.sourceAddress = sourceAddress;
this.validatorPubkey = validatorPubkey;
this.amount = amount;
}
@Override
public RequestType getType() {
return RequestType.WITHDRAWAL;
}
@Override
public Address getSourceAddress() {
return sourceAddress;
}
@Override
public PublicKey getValidatorPubkey() {
return validatorPubkey;
}
@Override
public GWei getAmount() {
return amount;
}
@Override
public String toString() {
return "WithdrawalRequest{"
+ "sourceAddress="
+ sourceAddress
+ " validatorPubkey="
+ validatorPubkey
+ " amount="
+ amount
+ '}';
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final WithdrawalRequest that = (WithdrawalRequest) o;
return Objects.equals(sourceAddress, that.sourceAddress)
&& Objects.equals(validatorPubkey, that.validatorPubkey)
&& Objects.equals(amount, that.amount);
}
@Override
public int hashCode() {
return Objects.hash(sourceAddress, validatorPubkey, amount);
}
}

@ -1,40 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.core.encoding;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BLSPublicKey;
import org.hyperledger.besu.ethereum.core.ConsolidationRequest;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.rlp.RLPInput;
import org.apache.tuweni.bytes.Bytes;
public class ConsolidationRequestDecoder {
public static ConsolidationRequest decode(final RLPInput rlpInput) {
rlpInput.enterList();
final Address sourceAddress = Address.readFrom(rlpInput);
final BLSPublicKey sourcePublicKey = BLSPublicKey.readFrom(rlpInput);
final BLSPublicKey targetPublicKey = BLSPublicKey.readFrom(rlpInput);
rlpInput.leaveList();
return new ConsolidationRequest(sourceAddress, sourcePublicKey, targetPublicKey);
}
public static ConsolidationRequest decodeOpaqueBytes(final Bytes input) {
return decode(RLP.input(input));
}
}

@ -1,60 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.core.encoding;
import org.hyperledger.besu.datatypes.RequestType;
import org.hyperledger.besu.ethereum.core.ConsolidationRequest;
import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.rlp.RLPOutput;
import org.apache.tuweni.bytes.Bytes;
public class ConsolidationRequestEncoder {
/**
* Encodes a Request into RLP format if it is a ConsolidationRequest.
*
* @param request The Request to encode, which must be a ConsolidationRequest.
* @param rlpOutput The RLPOutput to write the encoded data to.
* @throws IllegalArgumentException if the provided request is not a ConsolidationRequest.
*/
public static void encode(final Request request, final RLPOutput rlpOutput) {
if (!request.getType().equals(RequestType.CONSOLIDATION)) {
throw new IllegalArgumentException(
"The provided request is not of type ConsolidationRequest.");
}
encodeConsolidationRequest((ConsolidationRequest) request, rlpOutput);
}
/**
* Encodes the details of a ConsolidationRequest into RLP format.
*
* @param consolidationRequest The ConsolidationRequest to encode.
* @param rlpOutput The RLPOutput to write the encoded data to.
*/
private static void encodeConsolidationRequest(
final ConsolidationRequest consolidationRequest, final RLPOutput rlpOutput) {
rlpOutput.startList();
rlpOutput.writeBytes(consolidationRequest.getSourceAddress());
rlpOutput.writeBytes(consolidationRequest.getSourcePubkey());
rlpOutput.writeBytes(consolidationRequest.getTargetPubkey());
rlpOutput.endList();
}
public static Bytes encodeOpaqueBytes(final Request consolidationRequest) {
return RLP.encode(rlpOutput -> encode(consolidationRequest, rlpOutput));
}
}

@ -0,0 +1,40 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.core.encoding;
import org.hyperledger.besu.ethereum.core.DepositContract;
import org.hyperledger.besu.evm.log.Log;
import org.apache.tuweni.bytes.Bytes;
import org.web3j.tx.Contract;
public class DepositLogDecoder {
public static Bytes decodeFromLog(final Log log) {
Contract.EventValuesWithLog eventValues = DepositContract.staticExtractDepositEventWithLog(log);
final Bytes rawPublicKey =
Bytes.wrap((byte[]) eventValues.getNonIndexedValues().get(0).getValue());
final Bytes rawWithdrawalCredential =
Bytes.wrap((byte[]) eventValues.getNonIndexedValues().get(1).getValue());
final Bytes rawAmount =
Bytes.wrap((byte[]) eventValues.getNonIndexedValues().get(2).getValue());
final Bytes rawSignature =
Bytes.wrap((byte[]) eventValues.getNonIndexedValues().get(3).getValue());
final Bytes rawIndex = Bytes.wrap((byte[]) eventValues.getNonIndexedValues().get(4).getValue());
return Bytes.concatenate(
rawPublicKey, rawWithdrawalCredential, rawAmount, rawSignature, rawIndex);
}
}

@ -1,70 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.core.encoding;
import org.hyperledger.besu.datatypes.BLSPublicKey;
import org.hyperledger.besu.datatypes.BLSSignature;
import org.hyperledger.besu.datatypes.GWei;
import org.hyperledger.besu.ethereum.core.DepositContract;
import org.hyperledger.besu.ethereum.core.DepositRequest;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.rlp.RLPInput;
import org.hyperledger.besu.evm.log.Log;
import java.nio.ByteOrder;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt64;
import org.web3j.tx.Contract;
public class DepositRequestDecoder {
public static DepositRequest decode(final RLPInput rlpInput) {
rlpInput.enterList();
final BLSPublicKey publicKey = BLSPublicKey.readFrom(rlpInput);
final Bytes32 depositWithdrawalCredential = Bytes32.wrap(rlpInput.readBytes());
final GWei amount = GWei.of(rlpInput.readUInt64Scalar());
final BLSSignature signature = BLSSignature.readFrom(rlpInput);
final UInt64 index = UInt64.valueOf(rlpInput.readBigIntegerScalar());
rlpInput.leaveList();
return new DepositRequest(publicKey, depositWithdrawalCredential, amount, signature, index);
}
public static DepositRequest decodeFromLog(final Log log) {
Contract.EventValuesWithLog eventValues = DepositContract.staticExtractDepositEventWithLog(log);
final byte[] rawPublicKey = (byte[]) eventValues.getNonIndexedValues().get(0).getValue();
final byte[] rawWithdrawalCredential =
(byte[]) eventValues.getNonIndexedValues().get(1).getValue();
final byte[] rawAmount = (byte[]) eventValues.getNonIndexedValues().get(2).getValue();
final byte[] rawSignature = (byte[]) eventValues.getNonIndexedValues().get(3).getValue();
final byte[] rawIndex = (byte[]) eventValues.getNonIndexedValues().get(4).getValue();
return new DepositRequest(
BLSPublicKey.wrap(Bytes.wrap(rawPublicKey)),
Bytes32.wrap(Bytes.wrap(rawWithdrawalCredential)),
GWei.of(
Bytes.wrap(rawAmount)
.toLong(
ByteOrder.LITTLE_ENDIAN)), // Amount is little endian as per Deposit Contract
BLSSignature.wrap(Bytes.wrap(rawSignature)),
UInt64.valueOf(Bytes.wrap(rawIndex).reverse().toLong()));
}
public static DepositRequest decodeOpaqueBytes(final Bytes input) {
return decode(RLP.input(input));
}
}

@ -1,42 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.core.encoding;
import org.hyperledger.besu.ethereum.core.DepositRequest;
import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.rlp.RLPOutput;
import org.apache.tuweni.bytes.Bytes;
public class DepositRequestEncoder {
public static void encode(final Request request, final RLPOutput rlpOutput) {
if (!(request instanceof DepositRequest depositRequest)) {
throw new IllegalArgumentException("The provided request is not of type deposit.");
}
rlpOutput.startList();
rlpOutput.writeBytes(depositRequest.getPubkey());
rlpOutput.writeBytes(depositRequest.getWithdrawalCredentials());
rlpOutput.writeUInt64Scalar(depositRequest.getAmount());
rlpOutput.writeBytes(depositRequest.getSignature());
rlpOutput.writeUInt64Scalar(depositRequest.getIndex());
rlpOutput.endList();
}
public static Bytes encodeOpaqueBytes(final Request deposit) {
return RLP.encode(rlpOutput -> encode(deposit, rlpOutput));
}
}

@ -1,106 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.core.encoding;
import org.hyperledger.besu.datatypes.RequestType;
import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.rlp.RLPInput;
import java.util.Optional;
import com.google.common.collect.ImmutableMap;
import org.apache.tuweni.bytes.Bytes;
/**
* Decodes a request from its RLP encoded form.
*
* <p>This class provides functionality to decode requests based on their type.
*/
public class RequestDecoder {
@FunctionalInterface
interface Decoder {
Request decode(RLPInput input);
}
private static final ImmutableMap<RequestType, Decoder> DECODERS =
ImmutableMap.of(
RequestType.WITHDRAWAL,
WithdrawalRequestDecoder::decode,
RequestType.DEPOSIT,
DepositRequestDecoder::decode,
RequestType.CONSOLIDATION,
ConsolidationRequestDecoder::decode);
/**
* Decodes a request from its RLP encoded bytes.
*
* <p>This method first determines the type of the request and then decodes the request data
* according to the request type.
*
* @param rlpInput The RLP encoded request.
* @return The decoded Request object.
* @throws IllegalArgumentException if the request type is unsupported or invalid.
*/
public static Request decode(final RLPInput rlpInput) {
final Bytes requestBytes = rlpInput.readBytes();
return getRequestType(requestBytes)
.map(type -> decodeRequest(requestBytes, type))
.orElseThrow(() -> new IllegalArgumentException("Unsupported or invalid request type"));
}
/**
* Decodes the request data according to the request type.
*
* @param requestBytes The bytes representing the request, including the request type byte.
* @param requestType The type of the request to decode.
* @return The decoded Request.
* @throws IllegalStateException if no decoder is found for the specified request type.
*/
private static Request decodeRequest(final Bytes requestBytes, final RequestType requestType) {
// Skip the first byte which is the request type
RLPInput requestInput = RLP.input(requestBytes.slice(1));
Decoder decoder =
Optional.ofNullable(DECODERS.get(requestType))
.orElseThrow(
() ->
new IllegalStateException(
"Decoder not found for request type: " + requestType));
return decoder.decode(requestInput);
}
/**
* Extracts the request type from the given bytes.
*
* @param bytes The bytes from which to extract the request type.
* @return An Optional containing the RequestType if it could be determined, or an empty Optional
* otherwise.
*/
private static Optional<RequestType> getRequestType(final Bytes bytes) {
try {
byte typeByte = bytes.get(0);
return Optional.of(RequestType.of(typeByte));
} catch (IllegalArgumentException ex) {
return Optional.empty();
}
}
public static Request decodeOpaqueBytes(final Bytes input) {
RequestType type = getRequestType(input).orElseThrow();
return decodeRequest(input.slice(1), type);
}
}

@ -1,83 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.core.encoding;
import static com.google.common.base.Preconditions.checkNotNull;
import org.hyperledger.besu.datatypes.RequestType;
import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.rlp.RLPOutput;
import com.google.common.collect.ImmutableMap;
import org.apache.tuweni.bytes.Bytes;
/** Encodes Request objects into RLP format. */
public class RequestEncoder {
@FunctionalInterface
interface Encoder {
void encode(Request request, RLPOutput output);
}
private static final ImmutableMap<RequestType, RequestEncoder.Encoder> ENCODERS =
ImmutableMap.of(
RequestType.WITHDRAWAL,
WithdrawalRequestEncoder::encode,
RequestType.DEPOSIT,
DepositRequestEncoder::encode,
RequestType.CONSOLIDATION,
ConsolidationRequestEncoder::encode);
/**
* Encodes a Request into the provided RLPOutput.
*
* @param request The Request to encode.
* @param rlpOutput The RLPOutput to write the encoded data to.
*/
public static void encode(final Request request, final RLPOutput rlpOutput) {
final RequestEncoder.Encoder encoder = getEncoder(request.getType());
Bytes requestBytes = RLP.encode(out -> encoder.encode(request, out));
rlpOutput.writeBytes(
Bytes.concatenate(Bytes.of(request.getType().getSerializedType()), requestBytes));
}
/**
* Encodes a Request into a Bytes object representing the RLP-encoded data.
*
* @param request The Request to encode.
* @return The RLP-encoded data as a Bytes object.
*/
public static Bytes encodeOpaqueBytes(final Request request) {
final RequestEncoder.Encoder encoder = getEncoder(request.getType());
final BytesValueRLPOutput out = new BytesValueRLPOutput();
out.writeByte(request.getType().getSerializedType());
encoder.encode(request, out);
return out.encoded();
}
/**
* Retrieves the encoder for the specified RequestType.
*
* @param requestType The type of the request.
* @return The encoder for the specified type.
* @throws NullPointerException if no encoder is found for the specified type.
*/
private static RequestEncoder.Encoder getEncoder(final RequestType requestType) {
return checkNotNull(
ENCODERS.get(requestType), "Encoder not found for request type: %s", requestType);
}
}

@ -1,41 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.core.encoding;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BLSPublicKey;
import org.hyperledger.besu.datatypes.GWei;
import org.hyperledger.besu.ethereum.core.WithdrawalRequest;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.rlp.RLPInput;
import org.apache.tuweni.bytes.Bytes;
public class WithdrawalRequestDecoder {
public static WithdrawalRequest decode(final RLPInput rlpInput) {
rlpInput.enterList();
final Address sourceAddress = Address.readFrom(rlpInput);
final BLSPublicKey validatorPubkey = BLSPublicKey.readFrom(rlpInput);
final GWei amount = GWei.of(rlpInput.readUInt64Scalar());
rlpInput.leaveList();
return new WithdrawalRequest(sourceAddress, validatorPubkey, amount);
}
public static WithdrawalRequest decodeOpaqueBytes(final Bytes input) {
return decode(RLP.input(input));
}
}

@ -1,59 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.core.encoding;
import org.hyperledger.besu.datatypes.RequestType;
import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.core.WithdrawalRequest;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.rlp.RLPOutput;
import org.apache.tuweni.bytes.Bytes;
public class WithdrawalRequestEncoder {
/**
* Encodes a Request into RLP format if it is a WithdrawalRequest.
*
* @param request The Request to encode, which must be a WithdrawalRequest.
* @param rlpOutput The RLPOutput to write the encoded data to.
* @throws IllegalArgumentException if the provided request is not a WithdrawalRequest.
*/
public static void encode(final Request request, final RLPOutput rlpOutput) {
if (!request.getType().equals(RequestType.WITHDRAWAL)) {
throw new IllegalArgumentException("The provided request is not of type WithdrawalRequest.");
}
encodeWithdrawalRequest((WithdrawalRequest) request, rlpOutput);
}
/**
* Encodes the details of a WithdrawalRequest into RLP format.
*
* @param withdrawalRequest The WithdrawalRequest to encode.
* @param rlpOutput The RLPOutput to write the encoded data to.
*/
private static void encodeWithdrawalRequest(
final WithdrawalRequest withdrawalRequest, final RLPOutput rlpOutput) {
rlpOutput.startList();
rlpOutput.writeBytes(withdrawalRequest.getSourceAddress());
rlpOutput.writeBytes(withdrawalRequest.getValidatorPubkey());
rlpOutput.writeUInt64Scalar(withdrawalRequest.getAmount());
rlpOutput.endList();
}
public static Bytes encodeOpaqueBytes(final Request withdrawalRequest) {
return RLP.encode(rlpOutput -> encode(withdrawalRequest, rlpOutput));
}
}

@ -218,7 +218,7 @@ public abstract class AbstractBlockProcessor implements BlockProcessor {
blockHashLookup, blockHashLookup,
OperationTracer.NO_TRACING); OperationTracer.NO_TRACING);
maybeRequests = requestProcessor.get().process(context); maybeRequests = Optional.of(requestProcessor.get().process(context));
} }
if (!rewardCoinbase(worldState, blockHeader, ommers, skipZeroBlockRewards)) { if (!rewardCoinbase(worldState, blockHeader, ommers, skipZeroBlockRewards)) {

@ -18,7 +18,6 @@ import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockBody;
import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.core.feemarket.TransactionPriceCalculator; import org.hyperledger.besu.ethereum.core.feemarket.TransactionPriceCalculator;
@ -42,12 +41,11 @@ public class BaseFeeBlockBodyValidator extends MainnetBlockBodyValidator {
final ProtocolContext context, final ProtocolContext context,
final Block block, final Block block,
final List<TransactionReceipt> receipts, final List<TransactionReceipt> receipts,
final Optional<List<Request>> requests,
final HeaderValidationMode ommerValidationMode, final HeaderValidationMode ommerValidationMode,
final BodyValidationMode bodyValidationMode) { final BodyValidationMode bodyValidationMode) {
return super.validateBodyLight( return super.validateBodyLight(
context, block, receipts, requests, ommerValidationMode, bodyValidationMode) context, block, receipts, ommerValidationMode, bodyValidationMode)
&& validateTransactionGasPrice(block); && validateTransactionGasPrice(block);
} }

@ -17,11 +17,9 @@ package org.hyperledger.besu.ethereum.mainnet;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import java.util.List; import java.util.List;
import java.util.Optional;
/** Validates block bodies. */ /** Validates block bodies. */
public interface BlockBodyValidator { public interface BlockBodyValidator {
@ -41,7 +39,6 @@ public interface BlockBodyValidator {
ProtocolContext context, ProtocolContext context,
Block block, Block block,
List<TransactionReceipt> receipts, List<TransactionReceipt> receipts,
Optional<List<Request>> requests,
Hash worldStateRootHash, Hash worldStateRootHash,
final HeaderValidationMode ommerValidationMode); final HeaderValidationMode ommerValidationMode);
@ -58,7 +55,6 @@ public interface BlockBodyValidator {
ProtocolContext context, ProtocolContext context,
Block block, Block block,
List<TransactionReceipt> receipts, List<TransactionReceipt> receipts,
final Optional<List<Request>> requests,
final HeaderValidationMode ommerValidationMode, final HeaderValidationMode ommerValidationMode,
final BodyValidationMode bodyValidationMode); final BodyValidationMode bodyValidationMode);
} }

@ -15,6 +15,7 @@
package org.hyperledger.besu.ethereum.mainnet; package org.hyperledger.besu.ethereum.mainnet;
import static org.hyperledger.besu.crypto.Hash.keccak256; import static org.hyperledger.besu.crypto.Hash.keccak256;
import static org.hyperledger.besu.crypto.Hash.sha256;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
@ -23,7 +24,6 @@ import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.core.Withdrawal; import org.hyperledger.besu.ethereum.core.Withdrawal;
import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; import org.hyperledger.besu.ethereum.core.encoding.EncodingContext;
import org.hyperledger.besu.ethereum.core.encoding.RequestEncoder;
import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder;
import org.hyperledger.besu.ethereum.core.encoding.WithdrawalEncoder; import org.hyperledger.besu.ethereum.core.encoding.WithdrawalEncoder;
import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.rlp.RLP;
@ -31,6 +31,7 @@ import org.hyperledger.besu.ethereum.trie.MerkleTrie;
import org.hyperledger.besu.ethereum.trie.patricia.SimpleMerklePatriciaTrie; import org.hyperledger.besu.ethereum.trie.patricia.SimpleMerklePatriciaTrie;
import org.hyperledger.besu.evm.log.LogsBloomFilter; import org.hyperledger.besu.evm.log.LogsBloomFilter;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.IntStream; import java.util.stream.IntStream;
@ -89,16 +90,24 @@ public final class BodyValidation {
} }
/** /**
* Generates the requests root for a list of requests * Generates the requests hash for a list of requests
* *
* @param requests list of request * @param requests list of request
* @return the requests root * @return the requests hash
*/ */
public static Hash requestsRoot(final List<Request> requests) { public static Hash requestsHash(final List<Request> requests) {
final MerkleTrie<Bytes, Bytes> trie = trie(); List<Bytes> requestHashes = new ArrayList<>();
IntStream.range(0, requests.size()) IntStream.range(0, requests.size())
.forEach(i -> trie.put(indexKey(i), RequestEncoder.encodeOpaqueBytes(requests.get(i)))); .forEach(
return Hash.wrap(trie.getRootHash()); i -> {
final Request request = requests.get(i);
final Bytes requestBytes =
Bytes.concatenate(
Bytes.of(request.getType().getSerializedType()), request.getData());
requestHashes.add(sha256(requestBytes));
});
return Hash.wrap(sha256(Bytes.wrap(requestHashes)));
} }
/** /**

@ -19,14 +19,11 @@ import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockBody;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestsValidatorCoordinator;
import org.hyperledger.besu.evm.log.LogsBloomFilter; import org.hyperledger.besu.evm.log.LogsBloomFilter;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
@ -52,12 +49,11 @@ public class MainnetBlockBodyValidator implements BlockBodyValidator {
final ProtocolContext context, final ProtocolContext context,
final Block block, final Block block,
final List<TransactionReceipt> receipts, final List<TransactionReceipt> receipts,
final Optional<List<Request>> requests,
final Hash worldStateRootHash, final Hash worldStateRootHash,
final HeaderValidationMode ommerValidationMode) { final HeaderValidationMode ommerValidationMode) {
if (!validateBodyLight( if (!validateBodyLight(
context, block, receipts, requests, ommerValidationMode, BodyValidationMode.FULL)) { context, block, receipts, ommerValidationMode, BodyValidationMode.FULL)) {
return false; return false;
} }
@ -78,7 +74,6 @@ public class MainnetBlockBodyValidator implements BlockBodyValidator {
final ProtocolContext context, final ProtocolContext context,
final Block block, final Block block,
final List<TransactionReceipt> receipts, final List<TransactionReceipt> receipts,
final Optional<List<Request>> requests,
final HeaderValidationMode ommerValidationMode, final HeaderValidationMode ommerValidationMode,
final BodyValidationMode bodyValidationMode) { final BodyValidationMode bodyValidationMode) {
if (bodyValidationMode == BodyValidationMode.NONE) { if (bodyValidationMode == BodyValidationMode.NONE) {
@ -119,9 +114,6 @@ public class MainnetBlockBodyValidator implements BlockBodyValidator {
return false; return false;
} }
if (!validateRequests(block, requests, receipts)) {
return false;
}
return true; return true;
} }
@ -324,13 +316,4 @@ public class MainnetBlockBodyValidator implements BlockBodyValidator {
return true; return true;
} }
private boolean validateRequests(
final Block block,
final Optional<List<Request>> requests,
final List<TransactionReceipt> receipts) {
final RequestsValidatorCoordinator requestValidator =
protocolSchedule.getByBlockHeader(block.getHeader()).getRequestsValidatorCoordinator();
return requestValidator.validate(block, requests, receipts);
}
} }

@ -66,13 +66,7 @@ public class MainnetBlockImporter implements BlockImporter {
final BodyValidationMode bodyValidationMode) { final BodyValidationMode bodyValidationMode) {
if (blockValidator.validateBlockForSyncing( if (blockValidator.validateBlockForSyncing(
context, context, block, receipts, headerValidationMode, ommerValidationMode, bodyValidationMode)) {
block,
receipts,
block.getBody().getRequests(),
headerValidationMode,
ommerValidationMode,
bodyValidationMode)) {
context.getBlockchain().appendBlock(block, receipts); context.getBlockchain().appendBlock(block, receipts);
return new BlockImportResult(true); return new BlockImportResult(true);
} }

@ -14,8 +14,7 @@
*/ */
package org.hyperledger.besu.ethereum.mainnet; package org.hyperledger.besu.ethereum.mainnet;
import static org.hyperledger.besu.ethereum.mainnet.requests.MainnetRequestsValidator.pragueRequestsProcessors; import static org.hyperledger.besu.ethereum.mainnet.requests.MainnetRequestsProcessor.pragueRequestsProcessors;
import static org.hyperledger.besu.ethereum.mainnet.requests.MainnetRequestsValidator.pragueRequestsValidator;
import org.hyperledger.besu.config.GenesisConfigOptions; import org.hyperledger.besu.config.GenesisConfigOptions;
import org.hyperledger.besu.config.PowAlgorithm; import org.hyperledger.besu.config.PowAlgorithm;
@ -39,6 +38,7 @@ import org.hyperledger.besu.ethereum.mainnet.blockhash.PragueBlockHashProcessor;
import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.ethereum.mainnet.parallelization.MainnetParallelBlockProcessor; import org.hyperledger.besu.ethereum.mainnet.parallelization.MainnetParallelBlockProcessor;
import org.hyperledger.besu.ethereum.mainnet.requests.MainnetRequestsValidator;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestContractAddresses; import org.hyperledger.besu.ethereum.mainnet.requests.RequestContractAddresses;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionProcessor; import org.hyperledger.besu.ethereum.privacy.PrivateTransactionProcessor;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionValidator; import org.hyperledger.besu.ethereum.privacy.PrivateTransactionValidator;
@ -789,7 +789,7 @@ public abstract class MainnetProtocolSpecs {
.precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::prague) .precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::prague)
// EIP-7002 Withdrawals / EIP-6610 Deposits / EIP-7685 Requests // EIP-7002 Withdrawals / EIP-6610 Deposits / EIP-7685 Requests
.requestsValidator(pragueRequestsValidator(requestContractAddresses)) .requestsValidator(new MainnetRequestsValidator())
// EIP-7002 Withdrawals / EIP-6610 Deposits / EIP-7685 Requests // EIP-7002 Withdrawals / EIP-6610 Deposits / EIP-7685 Requests
.requestProcessorCoordinator(pragueRequestsProcessors(requestContractAddresses)) .requestProcessorCoordinator(pragueRequestsProcessors(requestContractAddresses))

@ -22,7 +22,7 @@ import org.hyperledger.besu.ethereum.core.BlockImporter;
import org.hyperledger.besu.ethereum.mainnet.blockhash.BlockHashProcessor; import org.hyperledger.besu.ethereum.mainnet.blockhash.BlockHashProcessor;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestProcessorCoordinator; import org.hyperledger.besu.ethereum.mainnet.requests.RequestProcessorCoordinator;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestsValidatorCoordinator; import org.hyperledger.besu.ethereum.mainnet.requests.RequestsValidator;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionProcessor; import org.hyperledger.besu.ethereum.privacy.PrivateTransactionProcessor;
import org.hyperledger.besu.evm.EVM; import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.gascalculator.GasCalculator; import org.hyperledger.besu.evm.gascalculator.GasCalculator;
@ -78,7 +78,7 @@ public class ProtocolSpec {
private final WithdrawalsValidator withdrawalsValidator; private final WithdrawalsValidator withdrawalsValidator;
private final Optional<WithdrawalsProcessor> withdrawalsProcessor; private final Optional<WithdrawalsProcessor> withdrawalsProcessor;
private final RequestsValidatorCoordinator requestsValidatorCoordinator; private final RequestsValidator requestsValidator;
private final Optional<RequestProcessorCoordinator> requestProcessorCoordinator; private final Optional<RequestProcessorCoordinator> requestProcessorCoordinator;
private final BlockHashProcessor blockHashProcessor; private final BlockHashProcessor blockHashProcessor;
private final boolean isPoS; private final boolean isPoS;
@ -110,7 +110,7 @@ public class ProtocolSpec {
* @param feeMarket an {@link Optional} wrapping {@link FeeMarket} class if appropriate. * @param feeMarket an {@link Optional} wrapping {@link FeeMarket} class if appropriate.
* @param powHasher the proof-of-work hasher * @param powHasher the proof-of-work hasher
* @param withdrawalsProcessor the Withdrawals processor to use * @param withdrawalsProcessor the Withdrawals processor to use
* @param requestsValidatorCoordinator the request validator to use * @param requestsValidator the request validator to use
* @param requestProcessorCoordinator the request processor to use * @param requestProcessorCoordinator the request processor to use
* @param blockHashProcessor the blockHash processor to use * @param blockHashProcessor the blockHash processor to use
* @param isPoS indicates whether the current spec is PoS * @param isPoS indicates whether the current spec is PoS
@ -142,7 +142,7 @@ public class ProtocolSpec {
final Optional<PoWHasher> powHasher, final Optional<PoWHasher> powHasher,
final WithdrawalsValidator withdrawalsValidator, final WithdrawalsValidator withdrawalsValidator,
final Optional<WithdrawalsProcessor> withdrawalsProcessor, final Optional<WithdrawalsProcessor> withdrawalsProcessor,
final RequestsValidatorCoordinator requestsValidatorCoordinator, final RequestsValidator requestsValidator,
final Optional<RequestProcessorCoordinator> requestProcessorCoordinator, final Optional<RequestProcessorCoordinator> requestProcessorCoordinator,
final BlockHashProcessor blockHashProcessor, final BlockHashProcessor blockHashProcessor,
final boolean isPoS, final boolean isPoS,
@ -171,7 +171,7 @@ public class ProtocolSpec {
this.powHasher = powHasher; this.powHasher = powHasher;
this.withdrawalsValidator = withdrawalsValidator; this.withdrawalsValidator = withdrawalsValidator;
this.withdrawalsProcessor = withdrawalsProcessor; this.withdrawalsProcessor = withdrawalsProcessor;
this.requestsValidatorCoordinator = requestsValidatorCoordinator; this.requestsValidator = requestsValidator;
this.requestProcessorCoordinator = requestProcessorCoordinator; this.requestProcessorCoordinator = requestProcessorCoordinator;
this.blockHashProcessor = blockHashProcessor; this.blockHashProcessor = blockHashProcessor;
this.isPoS = isPoS; this.isPoS = isPoS;
@ -375,8 +375,8 @@ public class ProtocolSpec {
return withdrawalsProcessor; return withdrawalsProcessor;
} }
public RequestsValidatorCoordinator getRequestsValidatorCoordinator() { public RequestsValidator getRequestsValidator() {
return requestsValidatorCoordinator; return requestsValidator;
} }
public Optional<RequestProcessorCoordinator> getRequestProcessorCoordinator() { public Optional<RequestProcessorCoordinator> getRequestProcessorCoordinator() {

@ -31,8 +31,9 @@ import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.ethereum.mainnet.precompiles.privacy.FlexiblePrivacyPrecompiledContract; import org.hyperledger.besu.ethereum.mainnet.precompiles.privacy.FlexiblePrivacyPrecompiledContract;
import org.hyperledger.besu.ethereum.mainnet.precompiles.privacy.PrivacyPluginPrecompiledContract; import org.hyperledger.besu.ethereum.mainnet.precompiles.privacy.PrivacyPluginPrecompiledContract;
import org.hyperledger.besu.ethereum.mainnet.precompiles.privacy.PrivacyPrecompiledContract; import org.hyperledger.besu.ethereum.mainnet.precompiles.privacy.PrivacyPrecompiledContract;
import org.hyperledger.besu.ethereum.mainnet.requests.ProhibitedRequestValidator;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestProcessorCoordinator; import org.hyperledger.besu.ethereum.mainnet.requests.RequestProcessorCoordinator;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestsValidatorCoordinator; import org.hyperledger.besu.ethereum.mainnet.requests.RequestsValidator;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionProcessor; import org.hyperledger.besu.ethereum.privacy.PrivateTransactionProcessor;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionValidator; import org.hyperledger.besu.ethereum.privacy.PrivateTransactionValidator;
import org.hyperledger.besu.evm.EVM; import org.hyperledger.besu.evm.EVM;
@ -80,8 +81,7 @@ public class ProtocolSpecBuilder {
private WithdrawalsValidator withdrawalsValidator = private WithdrawalsValidator withdrawalsValidator =
new WithdrawalsValidator.ProhibitedWithdrawals(); new WithdrawalsValidator.ProhibitedWithdrawals();
private WithdrawalsProcessor withdrawalsProcessor; private WithdrawalsProcessor withdrawalsProcessor;
private RequestsValidatorCoordinator requestsValidatorCoordinator = private RequestsValidator requestsValidator = new ProhibitedRequestValidator();
RequestsValidatorCoordinator.empty();
private RequestProcessorCoordinator requestProcessorCoordinator; private RequestProcessorCoordinator requestProcessorCoordinator;
protected BlockHashProcessor blockHashProcessor; protected BlockHashProcessor blockHashProcessor;
private FeeMarket feeMarket = FeeMarket.legacy(); private FeeMarket feeMarket = FeeMarket.legacy();
@ -268,8 +268,8 @@ public class ProtocolSpecBuilder {
} }
public ProtocolSpecBuilder requestsValidator( public ProtocolSpecBuilder requestsValidator(
final RequestsValidatorCoordinator requestsValidatorCoordinator) { final RequestsValidator requestsValidatorCoordinator) {
this.requestsValidatorCoordinator = requestsValidatorCoordinator; this.requestsValidator = requestsValidatorCoordinator;
return this; return this;
} }
@ -402,7 +402,7 @@ public class ProtocolSpecBuilder {
Optional.ofNullable(powHasher), Optional.ofNullable(powHasher),
withdrawalsValidator, withdrawalsValidator,
Optional.ofNullable(withdrawalsProcessor), Optional.ofNullable(withdrawalsProcessor),
requestsValidatorCoordinator, requestsValidator,
Optional.ofNullable(requestProcessorCoordinator), Optional.ofNullable(requestProcessorCoordinator),
blockHashProcessor, blockHashProcessor,
isPoS, isPoS,

@ -56,7 +56,8 @@ public class SystemCallProcessor {
* @param blockHeader the current block header. * @param blockHeader the current block header.
* @param operationTracer the operation tracer for tracing EVM operations. * @param operationTracer the operation tracer for tracing EVM operations.
* @param blockHashLookup the block hash lookup function. * @param blockHashLookup the block hash lookup function.
* @return the output data from the call * @return the output data from the call. If no code exists at the callAddress then an empty Bytes
* is returned.
*/ */
public Bytes process( public Bytes process(
final Address callAddress, final Address callAddress,
@ -69,7 +70,7 @@ public class SystemCallProcessor {
final Account maybeContract = worldState.get(callAddress); final Account maybeContract = worldState.get(callAddress);
if (maybeContract == null) { if (maybeContract == null) {
LOG.trace("System call address not found {}", callAddress); LOG.trace("System call address not found {}", callAddress);
return null; return Bytes.EMPTY;
} }
final AbstractMessageProcessor messageProcessor = final AbstractMessageProcessor messageProcessor =

@ -1,102 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.mainnet.requests;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.mainnet.SystemCallProcessor;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
/**
* Abstract base class for processing system call requests.
*
* @param <T> The type of request to be processed.
*/
public abstract class AbstractSystemCallRequestProcessor<T extends Request>
implements RequestProcessor {
/**
* Processes a system call and converts the result into requests of type T.
*
* @param context The request context being processed.
* @return An {@link Optional} containing a list of {@link T} objects if any are found
*/
@Override
public Optional<List<? extends Request>> process(final ProcessRequestContext context) {
SystemCallProcessor systemCallProcessor =
new SystemCallProcessor(context.protocolSpec().getTransactionProcessor());
Bytes systemCallOutput =
systemCallProcessor.process(
getCallAddress(),
context.mutableWorldState().updater(),
context.blockHeader(),
context.operationTracer(),
context.blockHashLookup());
List<T> requests = parseRequests(systemCallOutput);
return Optional.ofNullable(requests);
}
/**
* Parses the provided bytes into a list of {@link T} objects.
*
* @param bytes The bytes representing requests.
* @return A list of parsed {@link T} objects.
*/
protected List<T> parseRequests(final Bytes bytes) {
if (bytes == null) {
return null;
}
final List<T> requests = new ArrayList<>();
if (bytes.isEmpty()) {
return requests;
}
int count = bytes.size() / getRequestBytesSize();
for (int i = 0; i < count; i++) {
Bytes requestBytes = bytes.slice(i * getRequestBytesSize(), getRequestBytesSize());
requests.add(parseRequest(requestBytes));
}
return requests;
}
/**
* Parses a single request from the provided bytes.
*
* @param requestBytes The bytes representing a single request.
* @return A parsed {@link T} object.
*/
protected abstract T parseRequest(final Bytes requestBytes);
/**
* Gets the call address for the specific request type.
*
* @return The call address.
*/
protected abstract Address getCallAddress();
/**
* Gets the size of the bytes representing a single request.
*
* @return The size of the bytes representing a single request.
*/
protected abstract int getRequestBytesSize();
}

@ -1,73 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.mainnet.requests;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BLSPublicKey;
import org.hyperledger.besu.ethereum.core.ConsolidationRequest;
import org.apache.tuweni.bytes.Bytes;
public class ConsolidationRequestProcessor
extends AbstractSystemCallRequestProcessor<ConsolidationRequest> {
public static final Address CONSOLIDATION_REQUEST_CONTRACT_ADDRESS =
Address.fromHexString("0x00b42dbF2194e931E80326D950320f7d9Dbeac02");
private static final int ADDRESS_BYTES = 20;
private static final int PUBLIC_KEY_BYTES = 48;
private static final int CONSOLIDATION_REQUEST_BYTES_SIZE =
ADDRESS_BYTES + PUBLIC_KEY_BYTES + PUBLIC_KEY_BYTES;
private final Address consolidationRequestContractAddress;
public ConsolidationRequestProcessor(final Address consolidationRequestContractAddress) {
this.consolidationRequestContractAddress = consolidationRequestContractAddress;
}
/**
* Gets the call address for consolidation requests.
*
* @return The call address.
*/
@Override
protected Address getCallAddress() {
return consolidationRequestContractAddress;
}
/**
* Gets the size of the bytes representing a single consolidation request.
*
* @return The size of the bytes representing a single consolidation request.
*/
@Override
protected int getRequestBytesSize() {
return CONSOLIDATION_REQUEST_BYTES_SIZE;
}
/**
* Parses a single consolidation request from the provided bytes.
*
* @param requestBytes The bytes representing a single consolidation request.
* @return A parsed {@link ConsolidationRequest} object.
*/
@Override
protected ConsolidationRequest parseRequest(final Bytes requestBytes) {
final Address sourceAddress = Address.wrap(requestBytes.slice(0, ADDRESS_BYTES));
final BLSPublicKey sourcePublicKey =
BLSPublicKey.wrap(requestBytes.slice(ADDRESS_BYTES, PUBLIC_KEY_BYTES));
final BLSPublicKey targetPublicKey =
BLSPublicKey.wrap(requestBytes.slice(ADDRESS_BYTES + PUBLIC_KEY_BYTES, PUBLIC_KEY_BYTES));
return new ConsolidationRequest(sourceAddress, sourcePublicKey, targetPublicKey);
}
}

@ -1,92 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.mainnet.requests;
import static org.hyperledger.besu.ethereum.mainnet.requests.RequestUtil.getConsolidationRequests;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.ConsolidationRequest;
import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ConsolidationRequestValidator implements RequestValidator {
private static final Logger LOG = LoggerFactory.getLogger(ConsolidationRequestValidator.class);
public static final int MAX_CONSOLIDATION_REQUESTS_PER_BLOCK = 1;
private boolean validateConsolidationRequestParameter(
final Optional<List<ConsolidationRequest>> consolidationRequests) {
return consolidationRequests.isPresent();
}
private boolean validateConsolidationRequestsInBlock(
final Block block, final List<ConsolidationRequest> consolidationRequests) {
final Hash blockHash = block.getHash();
final List<ConsolidationRequest> consolidationRequestsInBlock =
block
.getBody()
.getRequests()
.flatMap(requests -> getConsolidationRequests(Optional.of(requests)))
.orElse(Collections.emptyList());
if (consolidationRequestsInBlock.size() > MAX_CONSOLIDATION_REQUESTS_PER_BLOCK) {
LOG.warn(
"Block {} has more than the allowed maximum number of consolidation requests", blockHash);
return false;
}
// Validate ConsolidationRequests
final boolean expectedConsolidationRequestMatch =
consolidationRequests.equals(consolidationRequestsInBlock);
if (!expectedConsolidationRequestMatch) {
LOG.warn(
"Block {} has a mismatch between block consolidations and RPC consolidation requests (in_block = {}, "
+ "expected = {})",
blockHash,
consolidationRequestsInBlock,
consolidationRequests);
return false;
}
return true;
}
@Override
public boolean validate(
final Block block, final List<Request> requests, final List<TransactionReceipt> receipts) {
var consolidationRequests =
getConsolidationRequests(Optional.of(requests)).orElse(Collections.emptyList());
return validateConsolidationRequestsInBlock(block, consolidationRequests);
}
@Override
public boolean validateParameter(final Optional<List<Request>> request) {
if (request.isEmpty()) {
return true;
}
var consolidationRequests =
RequestUtil.filterRequestsOfType(request.get(), ConsolidationRequest.class);
return validateConsolidationRequestParameter(Optional.of(consolidationRequests));
}
}

@ -15,22 +15,19 @@
package org.hyperledger.besu.ethereum.mainnet.requests; package org.hyperledger.besu.ethereum.mainnet.requests;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.core.DepositRequest; import org.hyperledger.besu.datatypes.RequestType;
import org.hyperledger.besu.ethereum.core.Request; import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.core.encoding.DepositRequestDecoder; import org.hyperledger.besu.ethereum.core.encoding.DepositLogDecoder;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import org.apache.tuweni.bytes.Bytes;
public class DepositRequestProcessor implements RequestProcessor { public class DepositRequestProcessor implements RequestProcessor {
public static final Address DEFAULT_DEPOSIT_CONTRACT_ADDRESS =
Address.fromHexString("0x00000000219ab540356cbb839cbe05303d7705fa");
private final Optional<Address> depositContractAddress; private final Optional<Address> depositContractAddress;
public DepositRequestProcessor(final Address depositContractAddress) { public DepositRequestProcessor(final Address depositContractAddress) {
@ -38,26 +35,22 @@ public class DepositRequestProcessor implements RequestProcessor {
} }
@Override @Override
public Optional<List<? extends Request>> process(final ProcessRequestContext context) { public Request process(final ProcessRequestContext context) {
if (depositContractAddress.isEmpty()) { if (depositContractAddress.isEmpty()) {
return Optional.empty(); return new Request(RequestType.DEPOSIT, Bytes.EMPTY);
} }
List<DepositRequest> depositRequests = Optional<Bytes> depositRequests = getDepositRequestData(context.transactionReceipts());
findDepositRequestsFromReceipts(context.transactionReceipts()); return new Request(RequestType.DEPOSIT, depositRequests.orElse(Bytes.EMPTY));
return Optional.of(depositRequests);
} }
@VisibleForTesting @VisibleForTesting
List<DepositRequest> findDepositRequestsFromReceipts( Optional<Bytes> getDepositRequestData(final List<TransactionReceipt> transactionReceipts) {
final List<TransactionReceipt> transactionReceipts) { return depositContractAddress.flatMap(
return depositContractAddress
.map(
address -> address ->
transactionReceipts.stream() transactionReceipts.stream()
.flatMap(receipt -> receipt.getLogsList().stream()) .flatMap(receipt -> receipt.getLogsList().stream())
.filter(log -> address.equals(log.getLogger())) .filter(log -> address.equals(log.getLogger()))
.map(DepositRequestDecoder::decodeFromLog) .map(DepositLogDecoder::decodeFromLog)
.toList()) .reduce(Bytes::concatenate));
.orElse(Collections.emptyList());
} }
} }

@ -1,86 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.mainnet.requests;
import static org.hyperledger.besu.ethereum.mainnet.requests.RequestUtil.getDepositRequests;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.DepositRequest;
import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.core.encoding.DepositRequestDecoder;
import org.hyperledger.besu.evm.log.Log;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DepositRequestValidator implements RequestValidator {
private static final Logger LOG = LoggerFactory.getLogger(DepositRequestValidator.class);
private final Address depositContractAddress;
public DepositRequestValidator(final Address depositContractAddress) {
this.depositContractAddress = depositContractAddress;
}
@Override
public boolean validateParameter(final Optional<List<Request>> depositRequests) {
return depositRequests.isPresent();
}
public boolean validateDepositRequests(
final Block block,
final List<DepositRequest> actualDepositRequests,
final List<TransactionReceipt> receipts) {
List<DepositRequest> expectedDepositRequests = new ArrayList<>();
for (TransactionReceipt receipt : receipts) {
for (Log log : receipt.getLogsList()) {
if (depositContractAddress.equals(log.getLogger())) {
DepositRequest depositRequest = DepositRequestDecoder.decodeFromLog(log);
expectedDepositRequests.add(depositRequest);
}
}
}
boolean isValid = actualDepositRequests.equals(expectedDepositRequests);
if (!isValid) {
LOG.warn(
"Deposits validation failed. Deposits from block body do not match deposits from logs. Block hash: {}",
block.getHash());
LOG.debug(
"Deposits from logs: {}, deposits from block body: {}",
expectedDepositRequests,
actualDepositRequests);
}
return isValid;
}
@Override
public boolean validate(
final Block block, final List<Request> requests, final List<TransactionReceipt> receipts) {
var depositRequests = getDepositRequests(Optional.of(requests)).orElse(Collections.emptyList());
return validateDepositRequests(block, depositRequests, receipts);
}
}

@ -0,0 +1,39 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.mainnet.requests;
import org.hyperledger.besu.datatypes.RequestType;
public class MainnetRequestsProcessor {
public static RequestProcessorCoordinator pragueRequestsProcessors(
final RequestContractAddresses requestContractAddresses) {
return new RequestProcessorCoordinator.Builder()
.addProcessor(
RequestType.WITHDRAWAL,
new SystemCallRequestProcessor(
requestContractAddresses.getWithdrawalRequestContractAddress(),
RequestType.WITHDRAWAL))
.addProcessor(
RequestType.CONSOLIDATION,
new SystemCallRequestProcessor(
requestContractAddresses.getConsolidationRequestContractAddress(),
RequestType.CONSOLIDATION))
.addProcessor(
RequestType.DEPOSIT,
new DepositRequestProcessor(requestContractAddresses.getDepositContractAddress()))
.build();
}
}

@ -14,34 +14,47 @@
*/ */
package org.hyperledger.besu.ethereum.mainnet.requests; package org.hyperledger.besu.ethereum.mainnet.requests;
import org.hyperledger.besu.datatypes.RequestType; import org.hyperledger.besu.ethereum.core.Request;
public class MainnetRequestsValidator { import java.util.List;
public static RequestsValidatorCoordinator pragueRequestsValidator( import java.util.Optional;
final RequestContractAddresses requestContractAddresses) {
return new RequestsValidatorCoordinator.Builder() import com.google.common.collect.Ordering;
.addValidator(RequestType.WITHDRAWAL, new WithdrawalRequestValidator()) import org.slf4j.Logger;
.addValidator(RequestType.CONSOLIDATION, new ConsolidationRequestValidator()) import org.slf4j.LoggerFactory;
.addValidator(
RequestType.DEPOSIT, /**
new DepositRequestValidator(requestContractAddresses.getDepositContractAddress())) * Validates requests within a block against a set of predefined validators. This class delegates
.build(); * the validation of requests of specific types to corresponding validators. It ensures that
* requests are properly ordered, have a valid hash, and meet the criteria defined by their
* validators.
*/
public class MainnetRequestsValidator implements RequestsValidator {
private static final Logger LOG = LoggerFactory.getLogger(MainnetRequestsValidator.class);
/**
* Validates a block's requests by ensuring they are correctly ordered, have a valid hash, and
* pass their respective type-specific validations.
*
* @param maybeRequests The list of requests to be validated.
* @return true if all validations pass; false otherwise.
*/
@Override
public boolean validate(final Optional<List<Request>> maybeRequests) {
if (maybeRequests.isEmpty()) {
LOG.warn("Must contain requests (even if empty list)");
return false;
}
if (!isRequestOrderValid(maybeRequests.get())) {
LOG.warn("Ordering across requests must be ascending by type");
return false;
}
return true;
} }
public static RequestProcessorCoordinator pragueRequestsProcessors( private static boolean isRequestOrderValid(final List<Request> requests) {
final RequestContractAddresses requestContractAddresses) { return Ordering.natural().onResultOf(Request::getType).isOrdered(requests);
return new RequestProcessorCoordinator.Builder()
.addProcessor(
RequestType.WITHDRAWAL,
new WithdrawalRequestProcessor(
requestContractAddresses.getWithdrawalRequestContractAddress()))
.addProcessor(
RequestType.CONSOLIDATION,
new ConsolidationRequestProcessor(
requestContractAddresses.getConsolidationRequestContractAddress()))
.addProcessor(
RequestType.DEPOSIT,
new DepositRequestProcessor(requestContractAddresses.getDepositContractAddress()))
.build();
} }
} }

@ -0,0 +1,38 @@
/*
* Copyright contributors to Besu.
*
* 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.mainnet.requests;
import org.hyperledger.besu.ethereum.core.Request;
import java.util.List;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ProhibitedRequestValidator implements RequestsValidator {
private static final Logger LOG = LoggerFactory.getLogger(MainnetRequestsValidator.class);
@Override
public boolean validate(final Optional<List<Request>> maybeRequests) {
boolean hasRequests = maybeRequests.isPresent();
if (hasRequests) {
LOG.warn("There are requests but requests are prohibited");
}
return !hasRequests;
}
}

@ -1,53 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.mainnet.requests;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import java.util.List;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** Validates that a block does not contain any prohibited requests. */
public class ProhibitedRequestsValidator implements RequestValidator {
private static final Logger LOG = LoggerFactory.getLogger(ProhibitedRequestsValidator.class);
@Override
public boolean validate(
final Block block, final List<Request> request, final List<TransactionReceipt> receipts) {
boolean hasRequests = block.getBody().getRequests().isPresent();
boolean hasRequestsRoot = block.getHeader().getRequestsRoot().isPresent();
if (hasRequests) {
LOG.warn("Block {} contains requests but requests are prohibited", block.getHash());
}
if (hasRequestsRoot) {
LOG.warn(
"Block {} header contains requests_root but requests are prohibited", block.getHash());
}
return !(hasRequests || hasRequestsRoot);
}
@Override
public boolean validateParameter(final Optional<List<Request>> request) {
return request.isEmpty();
}
}

@ -14,10 +14,6 @@
*/ */
package org.hyperledger.besu.ethereum.mainnet.requests; package org.hyperledger.besu.ethereum.mainnet.requests;
import static org.hyperledger.besu.ethereum.mainnet.requests.ConsolidationRequestProcessor.CONSOLIDATION_REQUEST_CONTRACT_ADDRESS;
import static org.hyperledger.besu.ethereum.mainnet.requests.DepositRequestProcessor.DEFAULT_DEPOSIT_CONTRACT_ADDRESS;
import static org.hyperledger.besu.ethereum.mainnet.requests.WithdrawalRequestProcessor.DEFAULT_WITHDRAWAL_REQUEST_CONTRACT_ADDRESS;
import org.hyperledger.besu.config.GenesisConfigOptions; import org.hyperledger.besu.config.GenesisConfigOptions;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
@ -26,6 +22,13 @@ public class RequestContractAddresses {
private final Address depositContractAddress; private final Address depositContractAddress;
private final Address consolidationRequestContractAddress; private final Address consolidationRequestContractAddress;
public static final Address DEFAULT_WITHDRAWAL_REQUEST_CONTRACT_ADDRESS =
Address.fromHexString("0x09FC772D0857550724B07B850A4323F39112AAAA");
public static final Address DEFAULT_CONSOLIDATION_REQUEST_CONTRACT_ADDRESS =
Address.fromHexString("0x01ABEA29659E5E97C95107F20BB753CD3E09BBBB");
public static final Address DEFAULT_DEPOSIT_CONTRACT_ADDRESS =
Address.fromHexString("0x00000000219ab540356cbb839cbe05303d7705fa");
public RequestContractAddresses( public RequestContractAddresses(
final Address withdrawalRequestContractAddress, final Address withdrawalRequestContractAddress,
final Address depositContractAddress, final Address depositContractAddress,
@ -44,7 +47,7 @@ public class RequestContractAddresses {
genesisConfigOptions.getDepositContractAddress().orElse(DEFAULT_DEPOSIT_CONTRACT_ADDRESS), genesisConfigOptions.getDepositContractAddress().orElse(DEFAULT_DEPOSIT_CONTRACT_ADDRESS),
genesisConfigOptions genesisConfigOptions
.getConsolidationRequestContractAddress() .getConsolidationRequestContractAddress()
.orElse(CONSOLIDATION_REQUEST_CONTRACT_ADDRESS)); .orElse(DEFAULT_CONSOLIDATION_REQUEST_CONTRACT_ADDRESS));
} }
public Address getWithdrawalRequestContractAddress() { public Address getWithdrawalRequestContractAddress() {

@ -16,9 +16,6 @@ package org.hyperledger.besu.ethereum.mainnet.requests;
import org.hyperledger.besu.ethereum.core.Request; import org.hyperledger.besu.ethereum.core.Request;
import java.util.List;
import java.util.Optional;
public interface RequestProcessor { public interface RequestProcessor {
Optional<List<? extends Request>> process(final ProcessRequestContext context); Request process(final ProcessRequestContext context);
} }

@ -17,9 +17,7 @@ package org.hyperledger.besu.ethereum.mainnet.requests;
import org.hyperledger.besu.datatypes.RequestType; import org.hyperledger.besu.datatypes.RequestType;
import org.hyperledger.besu.ethereum.core.Request; import org.hyperledger.besu.ethereum.core.Request;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
import com.google.common.collect.ImmutableSortedMap; import com.google.common.collect.ImmutableSortedMap;
@ -37,18 +35,10 @@ public class RequestProcessorCoordinator {
this.processors = processors; this.processors = processors;
} }
public Optional<List<Request>> process(final ProcessRequestContext context) { public List<Request> process(final ProcessRequestContext context) {
List<Request> requests = null; return processors.values().stream()
for (RequestProcessor requestProcessor : processors.values()) { .map(requestProcessor -> requestProcessor.process(context))
var r = requestProcessor.process(context); .toList();
if (r.isPresent()) {
if (requests == null) {
requests = new ArrayList<>();
}
requests.addAll(r.get());
}
}
return Optional.ofNullable(requests);
} }
public static class Builder { public static class Builder {
@ -62,7 +52,12 @@ public class RequestProcessorCoordinator {
} }
public RequestProcessorCoordinator build() { public RequestProcessorCoordinator build() {
return new RequestProcessorCoordinator(requestProcessorBuilder.build()); final ImmutableSortedMap<RequestType, RequestProcessor> processors =
requestProcessorBuilder.build();
if (processors.isEmpty()) {
throw new IllegalStateException("No processors added to RequestProcessorCoordinator");
}
return new RequestProcessorCoordinator(processors);
} }
} }
} }

@ -1,85 +0,0 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.mainnet.requests;
import org.hyperledger.besu.ethereum.core.ConsolidationRequest;
import org.hyperledger.besu.ethereum.core.DepositRequest;
import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.core.WithdrawalRequest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
public class RequestUtil {
/**
* Filters and returns a list of requests of a specific type from a given list of requests.
*
* @param <T> The type of the request to filter by, extending Request.
* @param requests The list of requests to filter.
* @param requestType The class of the request type to filter for.
* @return A List containing only requests of the specified type, or an empty list if the input
* list is null or contains no requests of the specified type.
*/
public static <T extends Request> List<T> filterRequestsOfType(
final List<Request> requests, final Class<T> requestType) {
if (requests == null) {
return Collections.emptyList();
}
return requests.stream().filter(requestType::isInstance).map(requestType::cast).toList();
}
public static Optional<List<DepositRequest>> getDepositRequests(
final Optional<List<Request>> requests) {
return requests.map(r -> filterRequestsOfType(r, DepositRequest.class));
}
public static Optional<List<WithdrawalRequest>> getWithdrawalRequests(
final Optional<List<Request>> requests) {
return requests.map(r -> filterRequestsOfType(r, WithdrawalRequest.class));
}
public static Optional<List<ConsolidationRequest>> getConsolidationRequests(
final Optional<List<Request>> requests) {
return requests.map(r -> filterRequestsOfType(r, ConsolidationRequest.class));
}
/**
* Combines multiple optional lists of requests into a single optional list.
*
* @param maybeDepositRequests Optional list of deposit requests.
* @param maybeWithdrawalRequest Optional list of withdrawal requests.
* @param maybeConsolidationRequest Optional list of withdrawal requests.
* @return An Optional containing the combined list of requests, or an empty Optional if all input
* lists are empty.
*/
public static Optional<List<Request>> combine(
final Optional<List<Request>> maybeDepositRequests,
final Optional<List<Request>> maybeWithdrawalRequest,
final Optional<List<Request>> maybeConsolidationRequest) {
if (maybeDepositRequests.isEmpty()
&& maybeWithdrawalRequest.isEmpty()
&& maybeConsolidationRequest.isEmpty()) {
return Optional.empty();
}
List<Request> requests = new ArrayList<>();
maybeDepositRequests.ifPresent(requests::addAll);
maybeWithdrawalRequest.ifPresent(requests::addAll);
maybeConsolidationRequest.ifPresent(requests::addAll);
return Optional.of(requests);
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save