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. 16
      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. 37
      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.util.Optional;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import okhttp3.Call;
import okhttp3.MediaType;
@ -74,17 +76,15 @@ public class PragueAcceptanceTestHelper {
final Call getPayloadRequest = createEngineCall(createGetPayloadRequest(payloadId));
final ObjectNode executionPayload;
final ArrayNode executionRequests;
final String newBlockHash;
final String parentBeaconBlockRoot;
try (final Response getPayloadResponse = getPayloadRequest.execute()) {
assertThat(getPayloadResponse.code()).isEqualTo(200);
executionPayload =
(ObjectNode)
mapper
.readTree(getPayloadResponse.body().string())
.get("result")
.get("executionPayload");
JsonNode result = mapper.readTree(getPayloadResponse.body().string()).get("result");
executionPayload = (ObjectNode) result.get("executionPayload");
executionRequests = (ArrayNode) result.get("executionRequests");
newBlockHash = executionPayload.get("blockHash").asText();
parentBeaconBlockRoot = executionPayload.remove("parentBeaconBlockRoot").asText();
@ -94,7 +94,8 @@ public class PragueAcceptanceTestHelper {
final Call newPayloadRequest =
createEngineCall(
createNewPayloadRequest(executionPayload.toString(), parentBeaconBlockRoot));
createNewPayloadRequest(
executionPayload.toString(), parentBeaconBlockRoot, executionRequests.toString()));
try (final Response newPayloadResponse = newPayloadRequest.execute()) {
assertThat(newPayloadResponse.code()).isEqualTo(200);
}
@ -168,7 +169,9 @@ public class PragueAcceptanceTestHelper {
}
private String createNewPayloadRequest(
final String executionPayload, final String parentBeaconBlockRoot) {
final String executionPayload,
final String parentBeaconBlockRoot,
final String executionRequests) {
return "{"
+ " \"jsonrpc\": \"2.0\","
+ " \"method\": \"engine_newPayloadV4\","
@ -178,6 +181,8 @@ public class PragueAcceptanceTestHelper {
+ "\""
+ parentBeaconBlockRoot
+ "\""
+ ","
+ executionRequests
+ "],"
+ " \"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,
"result": {
"number": "0x0",
"hash" : "0x38d7daa68e8bac41a0a237b7cbfcef480cb9bd9adc7b282d7b0d23ff4eb8d6e5",
"hash" : "0x01f5cbf33268c161f1526d704268db760bf82c9772a8f8ca412e0c6ce5684896",
"mixHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce" : "0x0000000000000042",
"sha3Uncles" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"logsBloom" : "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"transactionsRoot" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0x3ed8435adb5f3526144e6babdd3fc8c661a86097cf7e743441b41fda096fc4dd",
"stateRoot" : "0x860be6ab5a8fc2003c3739bfe2cdbcd9dbb273c8ea42951b832a8e1f22fb3a60",
"receiptsRoot" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"miner" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x400000000",

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -38,7 +38,7 @@ public class RlpConverterServiceImplTest {
new BlockHeaderTestFixture()
.timestamp(1710338135 + 1)
.baseFeePerGas(Wei.of(1000))
.requestsRoot(Hash.ZERO)
.requestsHash(Hash.ZERO)
.withdrawalsRoot(Hash.ZERO)
.blobGasUsed(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.ethereum.core.BlockValueCalculator;
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. */
public class PayloadWrapper {
private final PayloadIdentifier payloadIdentifier;
private final BlockWithReceipts blockWithReceipts;
private final Wei blockValue;
private final Optional<List<Request>> requests;
/**
* Construct a wrapper with the following fields.
@ -32,10 +37,13 @@ public class PayloadWrapper {
* @param blockWithReceipts Block with receipts
*/
public PayloadWrapper(
final PayloadIdentifier payloadIdentifier, final BlockWithReceipts blockWithReceipts) {
final PayloadIdentifier payloadIdentifier,
final BlockWithReceipts blockWithReceipts,
final Optional<List<Request>> requests) {
this.blockWithReceipts = blockWithReceipts;
this.payloadIdentifier = payloadIdentifier;
this.blockValue = BlockValueCalculator.calculateBlockValue(blockWithReceipts);
this.requests = requests;
}
/**
@ -64,4 +72,13 @@ public class PayloadWrapper {
public BlockWithReceipts 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()) {
mergeContext.putPayloadById(
new PayloadWrapper(
payloadIdentifier, new BlockWithReceipts(emptyBlock, result.getReceipts())));
payloadIdentifier,
new BlockWithReceipts(emptyBlock, result.getReceipts()),
result.getRequests()));
LOG.info(
"Start building proposals for block {} identified by {}",
emptyBlock.getHeader().getNumber(),
@ -469,7 +471,9 @@ public class MergeCoordinator implements MergeMiningCoordinator, BadChainListene
mergeContext.putPayloadById(
new PayloadWrapper(
payloadIdentifier, new BlockWithReceipts(bestBlock, resultBest.getReceipts())));
payloadIdentifier,
new BlockWithReceipts(bestBlock, resultBest.getReceipts()),
resultBest.getRequests()));
LOG.atDebug()
.setMessage(
"Successfully built block {} for proposal identified by {}, with {} transactions, in {}ms")

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

@ -15,6 +15,7 @@
package org.hyperledger.besu.datatypes;
import static org.hyperledger.besu.crypto.Hash.keccak256;
import static org.hyperledger.besu.crypto.Hash.sha256;
import org.hyperledger.besu.ethereum.rlp.RLP;
@ -50,6 +51,17 @@ public class Hash extends DelegatingBytes32 {
*/
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.
*

@ -26,4 +26,12 @@ public class HashTest {
.isEqualTo(
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,
BASEFEE,
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.PARENT_HASH;
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.STATE_ROOT;
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 Hash withdrawalsRoot =
values.containsKey(WITHDRAWALS_ROOT) ? hash(values.get(WITHDRAWALS_ROOT)) : null;
final Hash requestsRoot =
values.containsKey(REQUESTS_ROOT) ? hash(values.get(REQUESTS_ROOT)) : null;
final Hash requestsHash =
values.containsKey(REQUESTS_HASH) ? hash(values.get(REQUESTS_HASH)) : null;
final List<JsonNode> ommers = new ArrayList<>();
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 excess_blob_gas field
null, // TODO 4788: set with the value of the parent beacon block root field
requestsRoot,
requestsHash,
blockHeaderFunctions);
return new JsonRpcSuccessResponse(

@ -79,6 +79,7 @@ public class TracedJsonRpcProcessor implements JsonRpcProcessor {
case INVALID_ENGINE_PREPARE_PAYLOAD_PARAMS:
case INVALID_ENODE_PARAMS:
case INVALID_EXCESS_BLOB_GAS_PARAMS:
case INVALID_EXECUTION_REQUESTS_PARAMS:
case INVALID_EXTRA_DATA_PARAMS:
case INVALID_FILTER_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.SYNCING;
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.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.RequestValidatorProvider.getRequestsValidator;
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.datatypes.Address;
import org.hyperledger.besu.datatypes.BlobGas;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.RequestType;
import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei;
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.exception.InvalidJsonRpcRequestException;
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.JsonRpcParameter.JsonRpcParameterException;
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.JsonRpcResponse;
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.ValidationResult;
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.trie.MerkleTrieException;
import org.hyperledger.besu.plugin.services.exception.StorageException;
@ -75,6 +70,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import io.vertx.core.Vertx;
import io.vertx.core.json.Json;
@ -141,8 +137,22 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
final Optional<Bytes32> maybeParentBeaconBlockRoot =
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 =
validateParameters(blockParam, maybeVersionedHashParam, maybeParentBeaconBlockRootParam);
validateParameters(
blockParam,
maybeVersionedHashParam,
maybeParentBeaconBlockRootParam,
maybeRequestsParam);
if (!parameterValidationResult.isValid()) {
return new JsonRpcErrorResponse(reqId, parameterValidationResult);
}
@ -183,45 +193,24 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
return new JsonRpcErrorResponse(reqId, RpcErrorType.INVALID_WITHDRAWALS_PARAMS);
}
final Optional<List<Request>> maybeDepositRequests =
Optional.ofNullable(blockParam.getDepositRequests())
.map(ds -> ds.stream().map(DepositRequestParameter::toDeposit).collect(toList()));
if (!getDepositRequestValidator(
protocolSchedule.get(), blockParam.getTimestamp(), blockParam.getBlockNumber())
.validateParameter(maybeDepositRequests)) {
return new JsonRpcErrorResponse(reqId, RpcErrorType.INVALID_DEPOSIT_REQUEST_PARAMS);
}
final Optional<List<Request>> maybeWithdrawalRequests =
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>> maybeRequests;
try {
maybeRequests = extractRequests(maybeRequestsParam);
} catch (RuntimeException ex) {
return respondWithInvalid(
reqId,
blockParam,
mergeCoordinator.getLatestValidAncestor(blockParam.getParentHash()).orElse(null),
INVALID,
"Invalid execution requests");
}
final Optional<List<Request>> maybeConsolidationRequests =
Optional.ofNullable(blockParam.getConsolidationRequests())
.map(
consolidationRequest ->
consolidationRequest.stream()
.map(ConsolidationRequestParameter::toConsolidationRequest)
.collect(toList()));
if (!getConsolidationRequestValidator(
if (!getRequestsValidator(
protocolSchedule.get(), blockParam.getTimestamp(), blockParam.getBlockNumber())
.validateParameter(maybeConsolidationRequests)) {
return new JsonRpcErrorResponse(reqId, RpcErrorType.INVALID_CONSOLIDATION_REQUEST_PARAMS);
.validate(maybeRequests)) {
return new JsonRpcErrorResponse(reqId, RpcErrorType.INVALID_EXECUTION_REQUESTS_PARAMS);
}
Optional<List<Request>> maybeRequests =
RequestUtil.combine(
maybeDepositRequests, maybeWithdrawalRequests, maybeConsolidationRequests);
if (mergeContext.get().isSyncing()) {
LOG.debug("We are syncing");
return respondWith(reqId, blockParam, null, SYNCING);
@ -289,7 +278,7 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
? null
: BlobGas.fromHexString(blockParam.getExcessBlobGas()),
maybeParentBeaconBlockRoot.orElse(null),
maybeRequests.map(BodyValidation::requestsRoot).orElse(null),
maybeRequests.map(BodyValidation::requestsHash).orElse(null),
headerFunctions);
// ensure the block hash matches the blockParam hash
@ -351,8 +340,7 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
final var block =
new Block(
newBlockHeader,
new BlockBody(transactions, Collections.emptyList(), maybeWithdrawals, maybeRequests));
newBlockHeader, new BlockBody(transactions, Collections.emptyList(), maybeWithdrawals));
if (maybeParentHeader.isEmpty()) {
LOG.atDebug()
@ -466,7 +454,8 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
protected ValidationResult<RpcErrorType> validateParameters(
final EnginePayloadParameter parameter,
final Optional<List<String>> maybeVersionedHashParam,
final Optional<String> maybeBeaconBlockRootParam) {
final Optional<String> maybeBeaconBlockRootParam,
final Optional<List<String>> maybeRequestsParam) {
return ValidationResult.valid();
}
@ -562,6 +551,18 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
.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) {
final StringBuilder message = new StringBuilder();
message.append("Imported #%,d / %d tx");
@ -572,10 +573,6 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
message.append(" / %d ws");
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");
messageArgs.addAll(
List.of(

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

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

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

@ -14,64 +14,25 @@
*/
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.BlockHeaderBuilder;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.mainnet.requests.ProhibitedRequestsValidator;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestValidator;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestsValidatorCoordinator;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestsValidator;
import java.util.Optional;
public class RequestValidatorProvider {
public static RequestValidator getDepositRequestValidator(
public static RequestsValidator getRequestsValidator(
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 =
BlockHeaderBuilder.createDefault()
.timestamp(blockTimestamp)
.number(blockNumber)
.buildBlockHeader();
return getRequestValidatorCoordinator(protocolSchedule.getByBlockHeader(blockHeader));
}
private static RequestsValidatorCoordinator getRequestValidatorCoordinator(
final ProtocolSpec protocolSchedule) {
return Optional.ofNullable(protocolSchedule)
.map(ProtocolSpec::getRequestsValidatorCoordinator)
.orElseGet(RequestsValidatorCoordinator::empty);
return Optional.ofNullable(protocolSchedule.getByBlockHeader(blockHeader))
.map(ProtocolSpec::getRequestsValidator)
.orElse(v -> true);
}
}

@ -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 Long blobGasUsed;
private final String excessBlobGas;
private final List<DepositRequestParameter> depositRequests;
private final List<WithdrawalRequestParameter> withdrawalRequests;
private final List<ConsolidationRequestParameter> consolidationRequests;
/**
* Creates an instance of EnginePayloadParameter.
@ -67,9 +64,6 @@ public class EnginePayloadParameter {
* @param withdrawals Array of Withdrawal
* @param blobGasUsed 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
public EnginePayloadParameter(
@ -89,12 +83,7 @@ public class EnginePayloadParameter {
@JsonProperty("transactions") final List<String> transactions,
@JsonProperty("withdrawals") final List<WithdrawalParameter> withdrawals,
@JsonProperty("blobGasUsed") final UnsignedLongParameter blobGasUsed,
@JsonProperty("excessBlobGas") final String excessBlobGas,
@JsonProperty("depositRequests") final List<DepositRequestParameter> depositRequests,
@JsonProperty("withdrawalRequests")
final List<WithdrawalRequestParameter> withdrawalRequestParameters,
@JsonProperty("consolidationRequests")
final List<ConsolidationRequestParameter> consolidationRequests) {
@JsonProperty("excessBlobGas") final String excessBlobGas) {
this.blockHash = blockHash;
this.parentHash = parentHash;
this.feeRecipient = feeRecipient;
@ -112,9 +101,6 @@ public class EnginePayloadParameter {
this.withdrawals = withdrawals;
this.blobGasUsed = blobGasUsed == null ? null : blobGasUsed.getValue();
this.excessBlobGas = excessBlobGas;
this.depositRequests = depositRequests;
this.withdrawalRequests = withdrawalRequestParameters;
this.consolidationRequests = consolidationRequests;
}
public Hash getBlockHash() {
@ -184,16 +170,4 @@ public class EnginePayloadParameter {
public String getExcessBlobGas() {
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_EXCESS_BLOB_GAS_PARAMS(
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_FILTER_PARAMS(INVALID_PARAMS_ERROR_CODE, "Invalid filter 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;
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.datatypes.Hash;
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.BlockBody;
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.TransactionEncoder;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@ -162,6 +160,15 @@ public class BlockResultFactory {
TransactionEncoder.encodeOpaqueBytes(transaction, EncodingContext.BLOCK_BODY))
.map(Bytes::toHexString)
.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 =
new BlobsBundleV1(blockWithReceipts.getBlock().getBody().getTransactions());
@ -169,9 +176,7 @@ public class BlockResultFactory {
blockWithReceipts.getHeader(),
txs,
blockWithReceipts.getBlock().getBody().getWithdrawals(),
getDepositRequests(blockWithReceipts.getBlock().getBody().getRequests()),
getWithdrawalRequests(blockWithReceipts.getBlock().getBody().getRequests()),
getConsolidationRequests(blockWithReceipts.getBlock().getBody().getRequests()),
requestsWithoutRequestId,
Quantity.create(payload.blockValue()),
blobsBundleV1);
}

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

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

@ -180,7 +180,6 @@ public class EngineGetPayloadBodiesByHashV1Test {
new BlockBody(
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())),
Collections.emptyList(),
Optional.empty(),
Optional.empty());
when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(preShanghaiBlockBody));
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())),
Collections.emptyList(),
Optional.of(List.of(withdrawal)),
Optional.empty());
Optional.of(List.of(withdrawal)));
final BlockBody shanghaiBlockBody2 =
new BlockBody(
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())),
Collections.emptyList(),
Optional.of(List.of(withdrawal2)),
Optional.empty());
Optional.of(List.of(withdrawal2)));
when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(shanghaiBlockBody));
when(blockchain.getBlockBody(blockHash2)).thenReturn(Optional.of(shanghaiBlockBody2));

@ -179,7 +179,6 @@ public class EngineGetPayloadBodiesByRangeV1Test {
new BlockBody(
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())),
Collections.emptyList(),
Optional.empty(),
Optional.empty());
when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(130));
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())),
Collections.emptyList(),
Optional.of(List.of(withdrawal)),
Optional.empty());
Optional.of(List.of(withdrawal)));
final BlockBody shanghaiBlockBody2 =
new BlockBody(
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())),
Collections.emptyList(),
Optional.of(List.of(withdrawal2)),
Optional.empty());
Optional.of(List.of(withdrawal2)));
when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(130));
when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(shanghaiBlockBody));
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())),
Collections.emptyList(),
Optional.of(List.of(withdrawal)),
Optional.empty());
Optional.of(List.of(withdrawal)));
when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(123));
when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(shanghaiBlockBody));
when(blockchain.getBlockHashByNumber(123)).thenReturn(Optional.of(blockHash1));
@ -276,20 +272,17 @@ public class EngineGetPayloadBodiesByRangeV1Test {
new BlockBody(
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())),
Collections.emptyList(),
Optional.of(List.of(withdrawal)),
Optional.empty());
Optional.of(List.of(withdrawal)));
final BlockBody shanghaiBlockBody2 =
new BlockBody(
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())),
Collections.emptyList(),
Optional.of(List.of(withdrawal)),
Optional.empty());
Optional.of(List.of(withdrawal)));
final BlockBody shanghaiBlockBody3 =
new BlockBody(
List.of(new TransactionTestFixture().createTransaction(sig.generateKeyPair())),
Collections.emptyList(),
Optional.of(List.of(withdrawal)),
Optional.empty());
Optional.of(List.of(withdrawal)));
when(blockchain.getChainHeadBlockNumber()).thenReturn(Long.valueOf(125));
when(blockchain.getBlockBody(blockHash1)).thenReturn(Optional.of(shanghaiBlockBody));
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()));
final BlockWithReceipts mockBlockWithReceipts =
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));

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

@ -14,6 +14,7 @@
*/
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.mockito.Mockito.lenient;
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.BlobsWithCommitments;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.RequestType;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.Wei;
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.BlockHeaderTestFixture;
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.TransactionReceipt;
import org.hyperledger.besu.ethereum.core.TransactionTestFixture;
import java.math.BigInteger;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
@ -128,19 +131,24 @@ public class EngineGetPayloadV4Test extends AbstractEngineGetPayloadTest {
BlockWithReceipts block =
new BlockWithReceipts(
new Block(
header,
new BlockBody(
List.of(blobTx),
Collections.emptyList(),
Optional.of(Collections.emptyList()),
Optional.of(Collections.emptyList()))),
header, new BlockBody(List.of(blobTx), emptyList(), Optional.of(emptyList()))),
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));
final var resp = resp(RpcMethod.ENGINE_GET_PAYLOAD_V4.getMethodName(), payloadIdentifier);
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)
.map(JsonRpcSuccessResponse.class::cast)
.ifPresent(
@ -148,9 +156,6 @@ public class EngineGetPayloadV4Test extends AbstractEngineGetPayloadTest {
assertThat(r.getResult()).isInstanceOf(EngineGetPayloadResultV4.class);
final EngineGetPayloadResultV4 res = (EngineGetPayloadResultV4) r.getResult();
assertThat(res.getExecutionPayload().getWithdrawals()).isNotNull();
assertThat(res.getExecutionPayload().getDepositRequests()).isNotNull();
assertThat(res.getExecutionPayload().getWithdrawalRequests()).isNotNull();
assertThat(res.getExecutionPayload().getConsolidationRequests()).isNotNull();
assertThat(res.getExecutionPayload().getHash())
.isEqualTo(header.getHash().toString());
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())
.isEqualTo(expectedQuantityOf10);
assertThat(res.getExecutionRequests()).isNotEmpty();
assertThat(res.getExecutionRequests()).isEqualTo(requestsWithoutRequestId);
});
verify(engineCallListener, times(1)).executionEngineCalled();
}

@ -83,15 +83,11 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest {
setupValidPayload(
new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))),
Optional.of(withdrawals),
Optional.empty(),
Optional.empty());
lenient()
.when(blockchain.getBlockHeader(mockHeader.getParentHash()))
.thenReturn(Optional.of(mock(BlockHeader.class)));
var resp =
resp(
mockEnginePayload(
mockHeader, Collections.emptyList(), withdrawalsParam, null, null, null));
var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList(), withdrawalsParam));
assertValidResponse(mockHeader, resp);
}
@ -105,13 +101,11 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest {
setupValidPayload(
new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))),
Optional.empty(),
Optional.empty(),
Optional.empty());
lenient()
.when(blockchain.getBlockHeader(mockHeader.getParentHash()))
.thenReturn(Optional.of(mock(BlockHeader.class)));
var resp =
resp(mockEnginePayload(mockHeader, Collections.emptyList(), withdrawals, null, null, null));
var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList(), withdrawals));
assertValidResponse(mockHeader, resp);
}
@ -126,13 +120,9 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest {
var resp =
resp(
mockEnginePayload(
createBlockHeader(
Optional.of(Collections.emptyList()), Optional.empty(), Optional.empty()),
createBlockHeader(Optional.of(Collections.emptyList()), Optional.empty()),
Collections.emptyList(),
withdrawals,
null,
null,
null));
withdrawals));
final JsonRpcError jsonRpcError = fromErrorResp(resp);
assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode());
@ -143,13 +133,11 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest {
public void shouldValidateBlobGasUsedCorrectly() {
// V2 should return error if non-null blobGasUsed
BlockHeader blockHeader =
createBlockHeaderFixture(
Optional.of(Collections.emptyList()), Optional.empty(), Optional.empty())
createBlockHeaderFixture(Optional.of(Collections.emptyList()), Optional.empty())
.blobGasUsed(100L)
.buildHeader();
var resp =
resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of(), null, null, null));
var resp = resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of()));
final JsonRpcError jsonRpcError = fromErrorResp(resp);
assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_BLOB_GAS_USED_PARAMS.getCode());
assertThat(jsonRpcError.getData()).isEqualTo("Missing blob gas used field");
@ -160,13 +148,11 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest {
public void shouldValidateExcessBlobGasCorrectly() {
// V2 should return error if non-null ExcessBlobGas
BlockHeader blockHeader =
createBlockHeaderFixture(
Optional.of(Collections.emptyList()), Optional.empty(), Optional.empty())
createBlockHeaderFixture(Optional.of(Collections.emptyList()), Optional.empty())
.excessBlobGas(BlobGas.MAX_BLOB_GAS)
.buildHeader();
var resp =
resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of(), null, null, null));
var resp = resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of()));
final JsonRpcError jsonRpcError = fromErrorResp(resp);
assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode());
@ -183,12 +169,9 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest {
var resp =
resp(
mockEnginePayload(
createBlockHeader(Optional.empty(), Optional.empty(), Optional.empty()),
createBlockHeader(Optional.empty(), Optional.empty()),
Collections.emptyList(),
withdrawals,
null,
null,
null));
withdrawals));
assertThat(fromErrorResp(resp).getCode()).isEqualTo(INVALID_PARAMS.getCode());
verify(engineCallListener, times(1)).executionEngineCalled();
@ -199,13 +182,11 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest {
// Cancun starte at timestamp 30
final long blockTimestamp = 31L;
BlockHeader blockHeader =
createBlockHeaderFixture(
Optional.of(Collections.emptyList()), Optional.empty(), Optional.empty())
createBlockHeaderFixture(Optional.of(Collections.emptyList()), Optional.empty())
.timestamp(blockTimestamp)
.buildHeader();
var resp =
resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of(), null, null, null));
var resp = resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of()));
final JsonRpcError jsonRpcError = fromErrorResp(resp);
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.BlockHeader;
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.TransactionTestFixture;
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.TransactionEncoder;
import org.hyperledger.besu.ethereum.mainnet.BodyValidation;
@ -135,24 +134,23 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test {
setupValidPayload(
new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))),
Optional.empty(),
Optional.empty(),
Optional.empty());
final EnginePayloadParameter payload =
mockEnginePayload(mockHeader, Collections.emptyList(), null, null, null, null);
mockEnginePayload(mockHeader, Collections.emptyList(), null);
ValidationResult<RpcErrorType> res =
method.validateParameters(
payload,
Optional.of(List.of()),
Optional.of("0x0000000000000000000000000000000000000000000000000000000000000000"));
Optional.of("0x0000000000000000000000000000000000000000000000000000000000000000"),
Optional.empty());
assertThat(res.isValid()).isTrue();
}
@Override
protected BlockHeader createBlockHeader(
final Optional<List<Withdrawal>> maybeWithdrawals,
final Optional<List<DepositRequest>> maybeDepositRequests,
final Optional<List<WithdrawalRequest>> maybeWithdrawalRequests) {
final Optional<List<Request>> maybeRequests) {
BlockHeader parentBlockHeader =
new BlockHeaderTestFixture()
.baseFeePerGas(Wei.ONE)
@ -188,14 +186,12 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test {
public void shouldValidateBlobGasUsedCorrectly() {
// V3 must return error if null blobGasUsed
BlockHeader blockHeader =
createBlockHeaderFixture(
Optional.of(Collections.emptyList()), Optional.empty(), Optional.empty())
createBlockHeaderFixture(Optional.of(Collections.emptyList()), Optional.empty())
.excessBlobGas(BlobGas.MAX_BLOB_GAS)
.blobGasUsed(null)
.buildHeader();
var resp =
resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of(), null, null, null));
var resp = resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of()));
final JsonRpcError jsonRpcError = fromErrorResp(resp);
assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode());
@ -208,14 +204,12 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test {
public void shouldValidateExcessBlobGasCorrectly() {
// V3 must return error if null excessBlobGas
BlockHeader blockHeader =
createBlockHeaderFixture(
Optional.of(Collections.emptyList()), Optional.empty(), Optional.empty())
createBlockHeaderFixture(Optional.of(Collections.emptyList()), Optional.empty())
.excessBlobGas(null)
.blobGasUsed(100L)
.buildHeader();
var resp =
resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of(), null, null, null));
var resp = resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of()));
final JsonRpcError jsonRpcError = fromErrorResp(resp);
assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode());
@ -236,7 +230,6 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test {
setupValidPayload(
new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))),
Optional.empty(),
Optional.empty(),
Optional.empty());
var resp = resp(mockEnginePayload(mockHeader, transactions));

@ -15,9 +15,7 @@
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine;
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.jsonrpc.internal.parameters.WithdrawalRequestTestFixture.WITHDRAWAL_REQUEST_PARAMETER_1;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INVALID_PARAMS;
import static org.hyperledger.besu.ethereum.api.graphql.internal.response.GraphQLError.INVALID_PARAMS;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.lenient;
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.when;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BlobGas;
import org.hyperledger.besu.datatypes.RequestType;
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.api.jsonrpc.internal.JsonRpcRequest;
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.WithdrawalRequestParameter;
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.core.BlockHeader;
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.Withdrawal;
import org.hyperledger.besu.ethereum.core.WithdrawalRequest;
import org.hyperledger.besu.ethereum.mainnet.BodyValidation;
import org.hyperledger.besu.ethereum.mainnet.requests.DepositRequestValidator;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestsValidatorCoordinator;
import org.hyperledger.besu.ethereum.mainnet.requests.WithdrawalRequestValidator;
import org.hyperledger.besu.ethereum.mainnet.requests.MainnetRequestsValidator;
import org.hyperledger.besu.ethereum.mainnet.requests.ProhibitedRequestValidator;
import org.hyperledger.besu.evm.gascalculator.PragueGasCalculator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -63,8 +56,6 @@ import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
private static final Address depositContractAddress =
Address.fromHexString("0x00000000219ab540356cbb839cbe05303d7705fa");
public EngineNewPayloadV4Test() {}
@ -92,8 +83,7 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
}
@Test
public void shouldReturnValidIfDepositRequestsIsNull_WhenDepositRequestsProhibited() {
final List<DepositRequestParameter> depositRequests = null;
public void shouldReturnValidIfRequestsIsNull_WhenRequestsProhibited() {
mockProhibitedRequestsValidator();
BlockHeader mockHeader =
@ -101,170 +91,69 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
new BlockProcessingResult(
Optional.of(new BlockProcessingOutputs(null, List.of(), Optional.empty()))),
Optional.empty(),
Optional.empty(),
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, depositRequests, null, null));
var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList()));
assertValidResponse(mockHeader, resp);
}
@Test
public void shouldReturnInvalidIfDepositRequestsIsNull_WhenDepositRequestsAllowed() {
final List<DepositRequestParameter> depositRequests = null;
mockAllowedDepositRequestsRequestValidator();
public void shouldReturnInvalidIfRequestsIsNull_WhenRequestsAllowed() {
mockAllowedRequestsValidator();
var resp =
resp(
mockEnginePayload(
createBlockHeader(Optional.empty(), Optional.empty(), Optional.empty()),
Collections.emptyList(),
null,
depositRequests,
null,
null));
createBlockHeader(Optional.empty(), Optional.empty()), Collections.emptyList()));
assertThat(fromErrorResp(resp).getCode()).isEqualTo(INVALID_PARAMS.getCode());
verify(engineCallListener, times(1)).executionEngineCalled();
}
@Test
public void shouldReturnValidIfDepositRequestsIsNotNull_WhenDepositRequestsAllowed() {
final List<DepositRequestParameter> depositRequestsParam = List.of(DEPOSIT_PARAM_1);
final List<Request> depositRequests = List.of(DEPOSIT_PARAM_1.toDeposit());
mockAllowedDepositRequestsRequestValidator();
BlockHeader mockHeader =
setupValidPayload(
new BlockProcessingResult(
Optional.of(
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();
public void shouldReturnValidIfRequestsIsNotNull_WhenRequestsAllowed() {
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)));
mockAllowedRequestsValidator();
BlockHeader mockHeader =
setupValidPayload(
new BlockProcessingResult(
Optional.of(new BlockProcessingOutputs(null, List.of(), Optional.empty()))),
Optional.empty(),
Optional.of(new BlockProcessingOutputs(null, List.of(), Optional.of(requests)))),
Optional.empty(),
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, null, null, null));
var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList()), requests);
assertValidResponse(mockHeader, resp);
}
@Test
public void shouldReturnInvalidIfWithdrawalRequestsIsNull_WhenWithdrawalRequestsAreAllowed() {
mockAllowedWithdrawalsRequestValidator();
var resp =
resp(
mockEnginePayload(
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);
}
public void shouldReturnInvalidIfRequestsIsNotNull_WhenRequestsProhibited() {
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)));
@Test
public void
shouldReturnInvalidIfWithdrawalRequestsIsNotNull_WhenWithdrawalRequestsAreProhibited() {
final List<WithdrawalRequestParameter> withdrawalRequests = List.of();
mockProhibitedRequestsValidator();
var resp =
resp(
mockEnginePayload(
createBlockHeader(
Optional.empty(), Optional.empty(), Optional.of(Collections.emptyList())),
Collections.emptyList(),
null,
null,
withdrawalRequests,
null));
createBlockHeader(Optional.empty(), Optional.of(Collections.emptyList())),
Collections.emptyList()),
requests);
final JsonRpcError jsonRpcError = fromErrorResp(resp);
assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode());
@ -274,8 +163,7 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
@Override
protected BlockHeader createBlockHeader(
final Optional<List<Withdrawal>> maybeWithdrawals,
final Optional<List<DepositRequest>> maybeDepositRequests,
final Optional<List<WithdrawalRequest>> maybeWithdrawalRequests) {
final Optional<List<Request>> maybeRequests) {
BlockHeader parentBlockHeader =
new BlockHeaderTestFixture()
.baseFeePerGas(Wei.ONE)
@ -284,16 +172,6 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
.blobGasUsed(0L)
.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 =
new BlockHeaderTestFixture()
.baseFeePerGas(Wei.ONE)
@ -303,7 +181,7 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
.withdrawalsRoot(maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(null))
.excessBlobGas(BlobGas.ZERO)
.blobGasUsed(0L)
.requestsRoot(maybeRequests.map(BodyValidation::requestsRoot).orElse(null))
.requestsHash(maybeRequests.map(BodyValidation::requestsHash).orElse(null))
.parentBeaconBlockRoot(
maybeParentBeaconBlockRoot.isPresent() ? maybeParentBeaconBlockRoot : null)
.buildHeader();
@ -320,24 +198,35 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
new JsonRpcRequestContext(new JsonRpcRequest("2.0", this.method.getName(), params)));
}
private void mockProhibitedRequestsValidator() {
var validator = RequestsValidatorCoordinator.empty();
when(protocolSpec.getRequestsValidatorCoordinator()).thenReturn(validator);
protected JsonRpcResponse resp(
final EnginePayloadParameter payload, final List<Request> requests) {
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() {
var validator =
new RequestsValidatorCoordinator.Builder()
.addValidator(RequestType.DEPOSIT, new DepositRequestValidator(depositContractAddress))
.build();
when(protocolSpec.getRequestsValidatorCoordinator()).thenReturn(validator);
private void mockProhibitedRequestsValidator() {
var validator = new ProhibitedRequestValidator();
when(protocolSpec.getRequestsValidator()).thenReturn(validator);
}
private void mockAllowedWithdrawalsRequestValidator() {
var validator =
new RequestsValidatorCoordinator.Builder()
.addValidator(RequestType.WITHDRAWAL, new WithdrawalRequestValidator())
.build();
when(protocolSpec.getRequestsValidatorCoordinator()).thenReturn(validator);
private void mockAllowedRequestsValidator() {
var validator = new MainnetRequestsValidator();
when(protocolSpec.getRequestsValidator()).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);
Optional<List<Request>> maybeRequests =
requestProcessor.flatMap(processor -> processor.process(context));
requestProcessor.map(processor -> processor.process(context));
throwIfStopped();
@ -304,7 +304,7 @@ public abstract class AbstractBlockCreator implements AsyncBlockCreator {
withdrawalsCanBeProcessed
? BodyValidation.withdrawalsRoot(maybeWithdrawals.get())
: null)
.requestsRoot(maybeRequests.map(BodyValidation::requestsRoot).orElse(null));
.requestsHash(maybeRequests.map(BodyValidation::requestsHash).orElse(null));
if (usage != null) {
builder.blobGasUsed(usage.used.toLong()).excessBlobGas(usage.excessBlobGas);
}
@ -316,8 +316,7 @@ public abstract class AbstractBlockCreator implements AsyncBlockCreator {
final Optional<List<Withdrawal>> withdrawals =
withdrawalsCanBeProcessed ? maybeWithdrawals : Optional.empty();
final BlockBody blockBody =
new BlockBody(
transactionResults.getSelectedTransactions(), ommers, withdrawals, maybeRequests);
new BlockBody(transactionResults.getSelectedTransactions(), ommers, withdrawals);
final Block block = new Block(blockHeader, blockBody);
operationTracer.traceEndBlock(blockHeader, blockBody);

@ -14,9 +14,8 @@
*/
package org.hyperledger.besu.ethereum.blockcreation;
import static java.util.Collections.emptyList;
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.eq;
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.SignatureAlgorithmFactory;
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.BlobsWithCommitments;
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.BlockHeader;
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.ExecutionContextTestFixture;
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.WithdrawalsProcessor;
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.RequestProcessorCoordinator;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestsValidatorCoordinator;
import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
@ -141,83 +134,16 @@ abstract class AbstractBlockCreatorTest {
List<TransactionReceipt> receipts =
List.of(receiptWithoutDeposit1, receiptWithDeposit, receiptWithoutDeposit2);
DepositRequest expectedDepositRequest =
new DepositRequest(
BLSPublicKey.fromHexString(
"0xb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e"),
Bytes32.fromHexString(
"0x0017a7fcf06faf493d30bbe2632ea7c2383cd86825e12797165de7aa35589483"),
GWei.of(32000000000L),
BLSSignature.fromHexString(
"0xa889db8300194050a2636c92a95bc7160515867614b7971a9500cdb62f9c0890217d2901c3241f86fac029428fc106930606154bd9e406d7588934a5f15b837180b17194d6e44bd6de23e43b163dfe12e369dcc75a3852cd997963f158217eb5"),
UInt64.valueOf(539967));
final List<DepositRequest> expectedDepositRequests = List.of(expectedDepositRequest);
Request expectedDepositRequest =
new Request(
RequestType.DEPOSIT,
Bytes.fromHexString(
"0xb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e0017a7fcf06faf493d30bbe2632ea7c2383cd86825e12797165de7aa355894830040597307000000a889db8300194050a2636c92a95bc7160515867614b7971a9500cdb62f9c0890217d2901c3241f86fac029428fc106930606154bd9e406d7588934a5f15b837180b17194d6e44bd6de23e43b163dfe12e369dcc75a3852cd997963f158217eb53f3d080000000000"));
var depositRequestsFromReceipts =
new DepositRequestProcessor(DEFAULT_DEPOSIT_CONTRACT_ADDRESS)
.process(new ProcessRequestContext(null, null, null, receipts, null, null));
assertThat(depositRequestsFromReceipts.get()).isEqualTo(expectedDepositRequests);
}
@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();
assertThat(depositRequestsFromReceipts).isEqualTo(expectedDepositRequest);
}
@Test
@ -355,12 +281,6 @@ abstract class AbstractBlockCreatorTest {
return createBlockCreator(protocolSpecAdapters);
}
private CreateOn blockCreatorWithProhibitedDepositRequests() {
final ProtocolSpecAdapters protocolSpecAdapters =
ProtocolSpecAdapters.create(0, specBuilder -> specBuilder);
return createBlockCreator(protocolSpecAdapters);
}
private CreateOn blockCreatorWithWithdrawalsProcessor() {
final ProtocolSpecAdapters protocolSpecAdapters =
ProtocolSpecAdapters.create(
@ -374,27 +294,6 @@ abstract class AbstractBlockCreatorTest {
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) {}
private CreateOn createBlockCreator(final ProtocolSpecAdapters protocolSpecAdapters) {

@ -14,6 +14,7 @@
*/
package org.hyperledger.besu.ethereum;
import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import java.util.ArrayList;
@ -134,4 +135,13 @@ public class BlockProcessingResult extends BlockValidationResult {
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;
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.mainnet.BodyValidationMode;
import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode;
import java.util.List;
import java.util.Optional;
/**
* 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 block the block to validate
* @param receipts the transaction receipts
* @param requests the requests
* @param headerValidationMode the header validation mode
* @param ommerValidationMode the ommer validation mode
* @param bodyValidationMode the body validation mode
@ -100,7 +97,6 @@ public interface BlockValidator {
final ProtocolContext context,
final Block block,
final List<TransactionReceipt> receipts,
final Optional<List<Request>> requests,
final HeaderValidationMode headerValidationMode,
final HeaderValidationMode ommerValidationMode,
final BodyValidationMode bodyValidationMode);

@ -171,7 +171,7 @@ public class MainnetBlockValidator implements BlockValidator {
Optional<List<Request>> maybeRequests =
result.getYield().flatMap(BlockProcessingOutputs::getRequests);
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");
handleFailedBlockProcessing(block, result, shouldRecordBadBlock);
return result;
@ -243,7 +243,6 @@ public class MainnetBlockValidator implements BlockValidator {
final ProtocolContext context,
final Block block,
final List<TransactionReceipt> receipts,
final Optional<List<Request>> requests,
final HeaderValidationMode headerValidationMode,
final HeaderValidationMode ommerValidationMode,
final BodyValidationMode bodyValidationMode) {
@ -255,7 +254,7 @@ public class MainnetBlockValidator implements BlockValidator {
}
if (!blockBodyValidator.validateBodyLight(
context, block, receipts, requests, ommerValidationMode, bodyValidationMode)) {
context, block, receipts, ommerValidationMode, bodyValidationMode)) {
badBlockManager.addBadBlock(
block, BadBlockCause.fromValidationFailure("Failed body validation (light)"));
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.Difficulty;
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.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions;
@ -145,10 +144,8 @@ public final class GenesisState {
private static BlockBody buildBody(final GenesisConfigFile config) {
final Optional<List<Withdrawal>> withdrawals =
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() {
@ -220,7 +217,7 @@ public final class GenesisState {
.excessBlobGas(isCancunAtGenesis(genesis) ? parseExcessBlobGas(genesis) : null)
.parentBeaconBlockRoot(
(isCancunAtGenesis(genesis) ? parseParentBeaconBlockRoot(genesis) : null))
.requestsRoot(isPragueAtGenesis(genesis) ? Hash.EMPTY_TRIE_HASH : null)
.requestsHash(isPragueAtGenesis(genesis) ? Hash.EMPTY_REQUESTS_HASH : null)
.buildBlockHeader();
}

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

@ -37,24 +37,20 @@ public class BlockBody implements org.hyperledger.besu.plugin.data.BlockBody {
private final List<BlockHeader> ommers;
private final Optional<List<Withdrawal>> withdrawals;
private final Optional<List<Request>> requests;
public BlockBody(final List<Transaction> transactions, final List<BlockHeader> ommers) {
this.transactions = transactions;
this.ommers = ommers;
this.withdrawals = Optional.empty();
this.requests = Optional.empty();
}
public BlockBody(
final List<Transaction> transactions,
final List<BlockHeader> ommers,
final Optional<List<Withdrawal>> withdrawals,
final Optional<List<Request>> requests) {
final Optional<List<Withdrawal>> withdrawals) {
this.transactions = transactions;
this.ommers = ommers;
this.withdrawals = withdrawals;
this.requests = requests;
}
public static BlockBody empty() {
@ -87,16 +83,6 @@ public class BlockBody implements org.hyperledger.besu.plugin.data.BlockBody {
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}.
*
@ -112,7 +98,6 @@ public class BlockBody implements org.hyperledger.besu.plugin.data.BlockBody {
output.writeList(getTransactions(), Transaction::writeTo);
output.writeList(getOmmers(), BlockHeader::writeTo);
withdrawals.ifPresent(withdrawals -> output.writeList(withdrawals, Withdrawal::writeTo));
requests.ifPresent(requests -> output.writeList(requests, Request::writeTo));
}
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.isEndOfCurrentList()
? Optional.empty()
: Optional.of(input.readList(Withdrawal::readFrom)),
input.isEndOfCurrentList()
? Optional.empty()
: Optional.of(input.readList(Request::readFrom)));
: Optional.of(input.readList(Withdrawal::readFrom)));
}
@Override
@ -174,20 +156,16 @@ public class BlockBody implements org.hyperledger.besu.plugin.data.BlockBody {
BlockBody blockBody = (BlockBody) o;
return Objects.equals(transactions, blockBody.transactions)
&& Objects.equals(ommers, blockBody.ommers)
&& Objects.equals(withdrawals, blockBody.withdrawals)
&& Objects.equals(requests, blockBody.requests);
&& Objects.equals(withdrawals, blockBody.withdrawals);
}
@Override
public int hashCode() {
return Objects.hash(transactions, ommers, withdrawals, requests);
return Objects.hash(transactions, ommers, withdrawals);
}
public boolean isEmpty() {
return transactions.isEmpty()
&& ommers.isEmpty()
&& withdrawals.isEmpty()
&& requests.isEmpty();
return transactions.isEmpty() && ommers.isEmpty() && withdrawals.isEmpty();
}
@Override
@ -199,8 +177,6 @@ public class BlockBody implements org.hyperledger.besu.plugin.data.BlockBody {
+ ommers
+ ", withdrawals="
+ withdrawals
+ ", withdrawal_requests="
+ requests
+ '}';
}
}

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

@ -45,7 +45,7 @@ public class BlockHeaderBuilder {
private Hash transactionsRoot;
private Hash withdrawalsRoot = null;
private Hash requestsRoot = null;
private Hash requestsHash = null;
private Hash receiptsRoot;
@ -124,7 +124,7 @@ public class BlockHeaderBuilder {
.blobGasUsed(header.getBlobGasUsed().orElse(null))
.excessBlobGas(header.getExcessBlobGas().orElse(null))
.parentBeaconBlockRoot(header.getParentBeaconBlockRoot().orElse(null))
.requestsRoot(header.getRequestsRoot().orElse(null));
.requestsHash(header.getRequestsHash().orElse(null));
}
public static BlockHeaderBuilder fromBuilder(final BlockHeaderBuilder fromBuilder) {
@ -148,7 +148,7 @@ public class BlockHeaderBuilder {
.withdrawalsRoot(fromBuilder.withdrawalsRoot)
.excessBlobGas(fromBuilder.excessBlobGas)
.parentBeaconBlockRoot(fromBuilder.parentBeaconBlockRoot)
.requestsRoot(fromBuilder.requestsRoot)
.requestsHash(fromBuilder.requestsHash)
.blockHeaderFunctions(fromBuilder.blockHeaderFunctions);
toBuilder.nonce = fromBuilder.nonce;
return toBuilder;
@ -178,7 +178,7 @@ public class BlockHeaderBuilder {
blobGasUsed,
excessBlobGas,
parentBeaconBlockRoot,
requestsRoot,
requestsHash,
blockHeaderFunctions);
}
@ -220,7 +220,7 @@ public class BlockHeaderBuilder {
blobGasUsed,
excessBlobGas,
parentBeaconBlockRoot,
requestsRoot);
requestsHash);
}
private void validateBlockHeader() {
@ -284,7 +284,7 @@ public class BlockHeaderBuilder {
sealableBlockHeader.getBlobGasUsed().ifPresent(this::blobGasUsed);
sealableBlockHeader.getExcessBlobGas().ifPresent(this::excessBlobGas);
sealableBlockHeader.getParentBeaconBlockRoot().ifPresent(this::parentBeaconBlockRoot);
requestsRoot(sealableBlockHeader.getRequestsRoot().orElse(null));
requestsHash(sealableBlockHeader.getRequestsHash().orElse(null));
return this;
}
@ -399,8 +399,8 @@ public class BlockHeaderBuilder {
return this;
}
public BlockHeaderBuilder requestsRoot(final Hash hash) {
this.requestsRoot = hash;
public BlockHeaderBuilder requestsHash(final Hash hash) {
this.requestsHash = hash;
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;
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;
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
public abstract RequestType getType();
public static Request readFrom(final Bytes rlpBytes) {
return readFrom(RLP.input(rlpBytes));
}
public static Request readFrom(final RLPInput rlpInput) {
return RequestDecoder.decode(rlpInput);
public RequestType getType() {
return type();
}
public void writeTo(final RLPOutput out) {
RequestEncoder.encode(this, out);
@Override
public Bytes getData() {
return data();
}
}

@ -43,7 +43,7 @@ public class SealableBlockHeader extends ProcessableBlockHeader {
protected final Hash withdrawalsRoot;
protected final Hash requestsRoot;
protected final Hash requestsHash;
protected final Long blobGasUsed;
@ -69,7 +69,7 @@ public class SealableBlockHeader extends ProcessableBlockHeader {
final Long blobGasUsed,
final BlobGas excessBlobGas,
final Bytes32 parentBeaconBlockRoot,
final Hash requestsRoot) {
final Hash requestsHash) {
super(
parentHash,
coinbase,
@ -85,7 +85,7 @@ public class SealableBlockHeader extends ProcessableBlockHeader {
this.transactionsRoot = transactionsRoot;
this.withdrawalsRoot = withdrawalsRoot;
this.receiptsRoot = receiptsRoot;
this.requestsRoot = requestsRoot;
this.requestsHash = requestsHash;
this.logsBloom = logsBloom;
this.gasUsed = gasUsed;
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() {
return Optional.ofNullable(requestsRoot);
public Optional<Hash> getRequestsHash() {
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,
OperationTracer.NO_TRACING);
maybeRequests = requestProcessor.get().process(context);
maybeRequests = Optional.of(requestProcessor.get().process(context));
}
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.core.Block;
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.TransactionReceipt;
import org.hyperledger.besu.ethereum.core.feemarket.TransactionPriceCalculator;
@ -42,12 +41,11 @@ public class BaseFeeBlockBodyValidator extends MainnetBlockBodyValidator {
final ProtocolContext context,
final Block block,
final List<TransactionReceipt> receipts,
final Optional<List<Request>> requests,
final HeaderValidationMode ommerValidationMode,
final BodyValidationMode bodyValidationMode) {
return super.validateBodyLight(
context, block, receipts, requests, ommerValidationMode, bodyValidationMode)
context, block, receipts, ommerValidationMode, bodyValidationMode)
&& validateTransactionGasPrice(block);
}

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

@ -15,6 +15,7 @@
package org.hyperledger.besu.ethereum.mainnet;
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.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.Withdrawal;
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.WithdrawalEncoder;
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.evm.log.LogsBloomFilter;
import java.util.ArrayList;
import java.util.List;
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
* @return the requests root
* @return the requests hash
*/
public static Hash requestsRoot(final List<Request> requests) {
final MerkleTrie<Bytes, Bytes> trie = trie();
public static Hash requestsHash(final List<Request> requests) {
List<Bytes> requestHashes = new ArrayList<>();
IntStream.range(0, requests.size())
.forEach(i -> trie.put(indexKey(i), RequestEncoder.encodeOpaqueBytes(requests.get(i))));
return Hash.wrap(trie.getRootHash());
.forEach(
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.BlockBody;
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.mainnet.requests.RequestsValidatorCoordinator;
import org.hyperledger.besu.evm.log.LogsBloomFilter;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import com.google.common.annotations.VisibleForTesting;
@ -52,12 +49,11 @@ public class MainnetBlockBodyValidator implements BlockBodyValidator {
final ProtocolContext context,
final Block block,
final List<TransactionReceipt> receipts,
final Optional<List<Request>> requests,
final Hash worldStateRootHash,
final HeaderValidationMode ommerValidationMode) {
if (!validateBodyLight(
context, block, receipts, requests, ommerValidationMode, BodyValidationMode.FULL)) {
context, block, receipts, ommerValidationMode, BodyValidationMode.FULL)) {
return false;
}
@ -78,7 +74,6 @@ public class MainnetBlockBodyValidator implements BlockBodyValidator {
final ProtocolContext context,
final Block block,
final List<TransactionReceipt> receipts,
final Optional<List<Request>> requests,
final HeaderValidationMode ommerValidationMode,
final BodyValidationMode bodyValidationMode) {
if (bodyValidationMode == BodyValidationMode.NONE) {
@ -119,9 +114,6 @@ public class MainnetBlockBodyValidator implements BlockBodyValidator {
return false;
}
if (!validateRequests(block, requests, receipts)) {
return false;
}
return true;
}
@ -324,13 +316,4 @@ public class MainnetBlockBodyValidator implements BlockBodyValidator {
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) {
if (blockValidator.validateBlockForSyncing(
context,
block,
receipts,
block.getBody().getRequests(),
headerValidationMode,
ommerValidationMode,
bodyValidationMode)) {
context, block, receipts, headerValidationMode, ommerValidationMode, bodyValidationMode)) {
context.getBlockchain().appendBlock(block, receipts);
return new BlockImportResult(true);
}

@ -14,8 +14,7 @@
*/
package org.hyperledger.besu.ethereum.mainnet;
import static org.hyperledger.besu.ethereum.mainnet.requests.MainnetRequestsValidator.pragueRequestsProcessors;
import static org.hyperledger.besu.ethereum.mainnet.requests.MainnetRequestsValidator.pragueRequestsValidator;
import static org.hyperledger.besu.ethereum.mainnet.requests.MainnetRequestsProcessor.pragueRequestsProcessors;
import org.hyperledger.besu.config.GenesisConfigOptions;
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.FeeMarket;
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.privacy.PrivateTransactionProcessor;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionValidator;
@ -789,7 +789,7 @@ public abstract class MainnetProtocolSpecs {
.precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::prague)
// EIP-7002 Withdrawals / EIP-6610 Deposits / EIP-7685 Requests
.requestsValidator(pragueRequestsValidator(requestContractAddresses))
.requestsValidator(new MainnetRequestsValidator())
// EIP-7002 Withdrawals / EIP-6610 Deposits / EIP-7685 Requests
.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.feemarket.FeeMarket;
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.evm.EVM;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
@ -78,7 +78,7 @@ public class ProtocolSpec {
private final WithdrawalsValidator withdrawalsValidator;
private final Optional<WithdrawalsProcessor> withdrawalsProcessor;
private final RequestsValidatorCoordinator requestsValidatorCoordinator;
private final RequestsValidator requestsValidator;
private final Optional<RequestProcessorCoordinator> requestProcessorCoordinator;
private final BlockHashProcessor blockHashProcessor;
private final boolean isPoS;
@ -110,7 +110,7 @@ public class ProtocolSpec {
* @param feeMarket an {@link Optional} wrapping {@link FeeMarket} class if appropriate.
* @param powHasher the proof-of-work hasher
* @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 blockHashProcessor the blockHash processor to use
* @param isPoS indicates whether the current spec is PoS
@ -142,7 +142,7 @@ public class ProtocolSpec {
final Optional<PoWHasher> powHasher,
final WithdrawalsValidator withdrawalsValidator,
final Optional<WithdrawalsProcessor> withdrawalsProcessor,
final RequestsValidatorCoordinator requestsValidatorCoordinator,
final RequestsValidator requestsValidator,
final Optional<RequestProcessorCoordinator> requestProcessorCoordinator,
final BlockHashProcessor blockHashProcessor,
final boolean isPoS,
@ -171,7 +171,7 @@ public class ProtocolSpec {
this.powHasher = powHasher;
this.withdrawalsValidator = withdrawalsValidator;
this.withdrawalsProcessor = withdrawalsProcessor;
this.requestsValidatorCoordinator = requestsValidatorCoordinator;
this.requestsValidator = requestsValidator;
this.requestProcessorCoordinator = requestProcessorCoordinator;
this.blockHashProcessor = blockHashProcessor;
this.isPoS = isPoS;
@ -375,8 +375,8 @@ public class ProtocolSpec {
return withdrawalsProcessor;
}
public RequestsValidatorCoordinator getRequestsValidatorCoordinator() {
return requestsValidatorCoordinator;
public RequestsValidator getRequestsValidator() {
return requestsValidator;
}
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.PrivacyPluginPrecompiledContract;
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.RequestsValidatorCoordinator;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestsValidator;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionProcessor;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionValidator;
import org.hyperledger.besu.evm.EVM;
@ -80,8 +81,7 @@ public class ProtocolSpecBuilder {
private WithdrawalsValidator withdrawalsValidator =
new WithdrawalsValidator.ProhibitedWithdrawals();
private WithdrawalsProcessor withdrawalsProcessor;
private RequestsValidatorCoordinator requestsValidatorCoordinator =
RequestsValidatorCoordinator.empty();
private RequestsValidator requestsValidator = new ProhibitedRequestValidator();
private RequestProcessorCoordinator requestProcessorCoordinator;
protected BlockHashProcessor blockHashProcessor;
private FeeMarket feeMarket = FeeMarket.legacy();
@ -268,8 +268,8 @@ public class ProtocolSpecBuilder {
}
public ProtocolSpecBuilder requestsValidator(
final RequestsValidatorCoordinator requestsValidatorCoordinator) {
this.requestsValidatorCoordinator = requestsValidatorCoordinator;
final RequestsValidator requestsValidatorCoordinator) {
this.requestsValidator = requestsValidatorCoordinator;
return this;
}
@ -402,7 +402,7 @@ public class ProtocolSpecBuilder {
Optional.ofNullable(powHasher),
withdrawalsValidator,
Optional.ofNullable(withdrawalsProcessor),
requestsValidatorCoordinator,
requestsValidator,
Optional.ofNullable(requestProcessorCoordinator),
blockHashProcessor,
isPoS,

@ -56,7 +56,8 @@ public class SystemCallProcessor {
* @param blockHeader the current block header.
* @param operationTracer the operation tracer for tracing EVM operations.
* @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(
final Address callAddress,
@ -69,7 +70,7 @@ public class SystemCallProcessor {
final Account maybeContract = worldState.get(callAddress);
if (maybeContract == null) {
LOG.trace("System call address not found {}", callAddress);
return null;
return Bytes.EMPTY;
}
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;
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.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.Optional;
import com.google.common.annotations.VisibleForTesting;
import org.apache.tuweni.bytes.Bytes;
public class DepositRequestProcessor implements RequestProcessor {
public static final Address DEFAULT_DEPOSIT_CONTRACT_ADDRESS =
Address.fromHexString("0x00000000219ab540356cbb839cbe05303d7705fa");
private final Optional<Address> depositContractAddress;
public DepositRequestProcessor(final Address depositContractAddress) {
@ -38,26 +35,22 @@ public class DepositRequestProcessor implements RequestProcessor {
}
@Override
public Optional<List<? extends Request>> process(final ProcessRequestContext context) {
public Request process(final ProcessRequestContext context) {
if (depositContractAddress.isEmpty()) {
return Optional.empty();
return new Request(RequestType.DEPOSIT, Bytes.EMPTY);
}
List<DepositRequest> depositRequests =
findDepositRequestsFromReceipts(context.transactionReceipts());
return Optional.of(depositRequests);
Optional<Bytes> depositRequests = getDepositRequestData(context.transactionReceipts());
return new Request(RequestType.DEPOSIT, depositRequests.orElse(Bytes.EMPTY));
}
@VisibleForTesting
List<DepositRequest> findDepositRequestsFromReceipts(
final List<TransactionReceipt> transactionReceipts) {
return depositContractAddress
.map(
address ->
transactionReceipts.stream()
.flatMap(receipt -> receipt.getLogsList().stream())
.filter(log -> address.equals(log.getLogger()))
.map(DepositRequestDecoder::decodeFromLog)
.toList())
.orElse(Collections.emptyList());
Optional<Bytes> getDepositRequestData(final List<TransactionReceipt> transactionReceipts) {
return depositContractAddress.flatMap(
address ->
transactionReceipts.stream()
.flatMap(receipt -> receipt.getLogsList().stream())
.filter(log -> address.equals(log.getLogger()))
.map(DepositLogDecoder::decodeFromLog)
.reduce(Bytes::concatenate));
}
}

@ -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;
import org.hyperledger.besu.datatypes.RequestType;
public class MainnetRequestsValidator {
public static RequestsValidatorCoordinator pragueRequestsValidator(
final RequestContractAddresses requestContractAddresses) {
return new RequestsValidatorCoordinator.Builder()
.addValidator(RequestType.WITHDRAWAL, new WithdrawalRequestValidator())
.addValidator(RequestType.CONSOLIDATION, new ConsolidationRequestValidator())
.addValidator(
RequestType.DEPOSIT,
new DepositRequestValidator(requestContractAddresses.getDepositContractAddress()))
.build();
import org.hyperledger.besu.ethereum.core.Request;
import java.util.List;
import java.util.Optional;
import com.google.common.collect.Ordering;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Validates requests within a block against a set of predefined validators. This class delegates
* 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(
final RequestContractAddresses requestContractAddresses) {
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();
private static boolean isRequestOrderValid(final List<Request> requests) {
return Ordering.natural().onResultOf(Request::getType).isOrdered(requests);
}
}

@ -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;
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.datatypes.Address;
@ -26,6 +22,13 @@ public class RequestContractAddresses {
private final Address depositContractAddress;
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(
final Address withdrawalRequestContractAddress,
final Address depositContractAddress,
@ -44,7 +47,7 @@ public class RequestContractAddresses {
genesisConfigOptions.getDepositContractAddress().orElse(DEFAULT_DEPOSIT_CONTRACT_ADDRESS),
genesisConfigOptions
.getConsolidationRequestContractAddress()
.orElse(CONSOLIDATION_REQUEST_CONTRACT_ADDRESS));
.orElse(DEFAULT_CONSOLIDATION_REQUEST_CONTRACT_ADDRESS));
}
public Address getWithdrawalRequestContractAddress() {

@ -16,9 +16,6 @@ package org.hyperledger.besu.ethereum.mainnet.requests;
import org.hyperledger.besu.ethereum.core.Request;
import java.util.List;
import java.util.Optional;
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.ethereum.core.Request;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import com.google.common.collect.ImmutableSortedMap;
@ -37,18 +35,10 @@ public class RequestProcessorCoordinator {
this.processors = processors;
}
public Optional<List<Request>> process(final ProcessRequestContext context) {
List<Request> requests = null;
for (RequestProcessor requestProcessor : processors.values()) {
var r = requestProcessor.process(context);
if (r.isPresent()) {
if (requests == null) {
requests = new ArrayList<>();
}
requests.addAll(r.get());
}
}
return Optional.ofNullable(requests);
public List<Request> process(final ProcessRequestContext context) {
return processors.values().stream()
.map(requestProcessor -> requestProcessor.process(context))
.toList();
}
public static class Builder {
@ -62,7 +52,12 @@ public class RequestProcessorCoordinator {
}
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