EIP-7251 add consolidation request type (#7266)

* add request type for consolidations, encoder, decoder and tests

* added raw tx for consolidation

* add consolidation reqs to EngineGetPayloadResultV4

* set storage slot value to 0 initially and value for tx

* updates plugin api

Signed-off-by: Justin Florentine <justin+github@florentine.us>

Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>

---------

Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>
Signed-off-by: Justin Florentine <justin+github@florentine.us>
Co-authored-by: Justin Florentine <justin+github@florentine.us>
pull/7330/head
Sally MacFarlane 4 months ago committed by GitHub
parent 23123719fb
commit 223f1bc3bb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 16
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/genesis.json
  2. 43
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/00_get_genesis_block_info.json
  3. 8
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/01_cancun_prepare_payload.json
  4. 8
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/02_cancun_getPayloadV3.json
  5. 8
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/03_cancun_newPayloadV3.json
  6. 8
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/04_cancun_forkchoiceUpdatedV3.json
  7. 10
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/05_prague_forkchoiceUpdatedV3.json
  8. 9
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/06_prague_getPayloadV4.json
  9. 2
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/08_prague_invalid_null_deposits_execute_payload.json
  10. 9
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/09_prague_newPayloadV4.json
  11. 10
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/10_prague_forkchoiceUpdatedV3.json
  12. 9
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/11_prague_getPayloadV4.json
  13. 8
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/12_cancun_newPayloadV3.json
  14. 14
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/14_prague_send_raw_transaction_consolidation_request.json
  15. 10
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/15_prague_forkchoiceUpdatedV3.json
  16. 24
      acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/16_prague_getPayloadV4.json
  17. 5
      datatypes/src/main/java/org/hyperledger/besu/datatypes/RequestType.java
  18. 19
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java
  19. 6
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/RequestValidatorProvider.java
  20. 102
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/ConsolidationRequestParameter.java
  21. 11
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadParameter.java
  22. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java
  23. 30
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV4.java
  24. 9
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java
  25. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV4Test.java
  26. 14
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2Test.java
  27. 8
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java
  28. 16
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV4Test.java
  29. 90
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ConsolidationRequest.java
  30. 40
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/ConsolidationRequestDecoder.java
  31. 60
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/ConsolidationRequestEncoder.java
  32. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/RequestDecoder.java
  33. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/RequestEncoder.java
  34. 68
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/ConsolidationRequestProcessor.java
  35. 92
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/ConsolidationRequestValidator.java
  36. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/MainnetRequestsValidator.java
  37. 21
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/RequestUtil.java
  38. 46
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/ConsolidationRequestDecoderTest.java
  39. 55
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/ConsolidationRequestEncoderTest.java
  40. 2
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/DepositRequestDecoderTest.java
  41. 2
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/DepositRequestEncoderTest.java
  42. 136
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ConsolidationRequestValidatorTestFixtures.java
  43. 76
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PragueConsolidationRequestValidatorTest.java
  44. 15
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java
  45. 13
      ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-deposit.json
  46. 1
      ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-withdrawal.json
  47. 4
      ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTestTools.java
  48. 2
      plugin-api/build.gradle
  49. 45
      plugin-api/src/main/java/org/hyperledger/besu/plugin/data/ConsolidationRequest.java

File diff suppressed because one or more lines are too long

@ -0,0 +1,43 @@
{
"request": {
"jsonrpc": "2.0",
"method": "eth_getBlockByNumber",
"params": [
"0x00", true
],
"id": 67
},
"response": {
"jsonrpc": "2.0",
"id": 67,
"result": {
"number": "0x0",
"hash" : "0x38d7daa68e8bac41a0a237b7cbfcef480cb9bd9adc7b282d7b0d23ff4eb8d6e5",
"mixHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce" : "0x0000000000000042",
"sha3Uncles" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"logsBloom" : "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"transactionsRoot" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"stateRoot" : "0x3ed8435adb5f3526144e6babdd3fc8c661a86097cf7e743441b41fda096fc4dd",
"receiptsRoot" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"miner" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x400000000",
"totalDifficulty" : "0x400000000",
"extraData" : "0x0000000000000000000000000000000000000000000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"baseFeePerGas" : "0x7",
"size" : "0x2ba",
"gasLimit" : "0x1c9c380",
"gasUsed" : "0x0",
"timestamp" : "0x0",
"uncles" : [ ],
"transactions" : [ ],
"withdrawalsRoot" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"withdrawals" : [ ],
"blobGasUsed" : "0x0",
"excessBlobGas" : "0x0",
"parentBeaconBlockRoot" : "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"statusCode": 200
}

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

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

@ -4,9 +4,9 @@
"method": "engine_newPayloadV3",
"params": [
{
"parentHash": "0x3ca89f1d6b71aeb56389ac8270e9ae369d0bb8edeea747f2d868a5eb31892b04",
"parentHash": "0x38d7daa68e8bac41a0a237b7cbfcef480cb9bd9adc7b282d7b0d23ff4eb8d6e5",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0x2b6a1166ce24fe0af741c7313e6049e9e19351742bfaf4179154bc594ca9eb90",
"stateRoot": "0x3ed8435adb5f3526144e6babdd3fc8c661a86097cf7e743441b41fda096fc4dd",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380",
@ -17,7 +17,7 @@
"transactions": [],
"withdrawals": [],
"blockNumber": "0x1",
"blockHash": "0x74e8ce9d96d325a605675a34175adfa34581f35091dcd7b107c525a82b0b9950",
"blockHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"excessBlobGas": "0x0",
"blobGasUsed": "0x0"
@ -32,7 +32,7 @@
"id": 67,
"result": {
"status": "VALID",
"latestValidHash": "0x74e8ce9d96d325a605675a34175adfa34581f35091dcd7b107c525a82b0b9950",
"latestValidHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593",
"validationError": null
}
},

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

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

@ -3,7 +3,7 @@
"jsonrpc": "2.0",
"method": "engine_getPayloadV4",
"params": [
"0x282643c6d89e12df"
"0x282643d3a905e721"
],
"id": 67
},
@ -12,9 +12,9 @@
"id": 67,
"result": {
"executionPayload": {
"parentHash": "0x74e8ce9d96d325a605675a34175adfa34581f35091dcd7b107c525a82b0b9950",
"parentHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0x546ac65b9d37c72d7185f8dd67419803c636dd4e5ddf9b325fb64e9ecf570871",
"stateRoot": "0x2e59916a57b535875bcd80d8472aeaa0027aa685d159804e8caa2f12d060155e",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380",
@ -34,8 +34,9 @@
"amount": "0x0"
}
],
"consolidationRequests" : [],
"blockNumber": "0x2",
"blockHash": "0xa7a92cc82e1d876476ad6433538599b0d592f88ba0823c23e80af93fb1748f14",
"blockHash": "0x27a2bc2ac21b3fc796f636bec1ec9cba100435f9a793176a83a5d4fa7cc13006",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"blobGasUsed": "0x0"
},

@ -4,7 +4,7 @@
"method": "engine_newPayloadV4",
"params": [
{
"parentHash": "0xa7a92cc82e1d876476ad6433538599b0d592f88ba0823c23e80af93fb1748f14",
"parentHash": "0x27a2bc2ac21b3fc796f636bec1ec9cba100435f9a793176a83a5d4fa7cc13006",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0x9b8c4a9a86cb49252075c0db2f0e72fb1e49350a0f70ea36f26f700201961e62",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",

@ -4,9 +4,9 @@
"method": "engine_newPayloadV4",
"params": [
{
"parentHash": "0x74e8ce9d96d325a605675a34175adfa34581f35091dcd7b107c525a82b0b9950",
"parentHash": "0x8082deff44f79489ea92415be59afb48b6f46b939553f855479828a6f87f9593",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0xdb2a9bb9097dd6946525203a14437cd925ef549289e1fe17c6ed845c53647a26",
"stateRoot": "0x961878fdcdff52ea42db0026f59aa414a5ec2835e56ed1a8ae50c80a9fe3a04b",
"logsBloom": "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380",
@ -35,8 +35,9 @@
"validatorPubkey": "0xb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e"
}
],
"consolidationRequests": [],
"blockNumber": "0x2",
"blockHash": "0x5200df2eb24d08e7bceec64194d073e81a6e9c00c4f61d323fad5d70b40e6d6d",
"blockHash": "0xc67a660f5d3c20ee603911bdff1e409e976f306883dff8ef4999dca3176f7dca",
"receiptsRoot": "0x79ee3424eb720a3ad4b1c5a372bb8160580cbe4d893778660f34213c685627a9",
"blobGasUsed": "0x0"
},
@ -50,7 +51,7 @@
"id": 67,
"result": {
"status": "VALID",
"latestValidHash": "0x5200df2eb24d08e7bceec64194d073e81a6e9c00c4f61d323fad5d70b40e6d6d",
"latestValidHash": "0xc67a660f5d3c20ee603911bdff1e409e976f306883dff8ef4999dca3176f7dca",
"validationError": null
}
},

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

@ -3,7 +3,7 @@
"jsonrpc": "2.0",
"method": "engine_getPayloadV4",
"params": [
"0x282643e2da21a7cf"
"0x282643a16a58b5cf"
],
"id": 67
},
@ -12,9 +12,9 @@
"id": 67,
"result": {
"executionPayload": {
"parentHash": "0x5200df2eb24d08e7bceec64194d073e81a6e9c00c4f61d323fad5d70b40e6d6d",
"parentHash": "0xc67a660f5d3c20ee603911bdff1e409e976f306883dff8ef4999dca3176f7dca",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0xcd9f15de5f17cf87a02bf795a0dc98c108eead4651eca57fc7195bda0d9c20ee",
"stateRoot": "0x5fc31c01a451fe02f0e938de7ec7044aaba1159a81a1be64357bc70af226f304",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380",
@ -28,8 +28,9 @@
"withdrawals": [],
"depositRequests": [],
"withdrawalRequests": [],
"consolidationRequests" : [],
"blockNumber": "0x3",
"blockHash": "0x79858f6eb8e82f0ec11087983ce4eb8c7edc10c9363a2a124dd78fd2c305dc42",
"blockHash": "0xdbb55a049f14b8152695bf3bbd754aa1fd55bbe10b306eb49caa4bd7d7fcb634",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"blobGasUsed": "0x0"
},

@ -4,9 +4,9 @@
"method": "engine_newPayloadV3",
"params": [
{
"parentHash": "0x5200df2eb24d08e7bceec64194d073e81a6e9c00c4f61d323fad5d70b40e6d6d",
"parentHash": "0xc67a660f5d3c20ee603911bdff1e409e976f306883dff8ef4999dca3176f7dca",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0xcd9f15de5f17cf87a02bf795a0dc98c108eead4651eca57fc7195bda0d9c20ee",
"stateRoot": "0x5fc31c01a451fe02f0e938de7ec7044aaba1159a81a1be64357bc70af226f304",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380",
@ -19,7 +19,7 @@
"depositRequests": [],
"withdrawalRequests": [],
"blockNumber": "0x3",
"blockHash": "0x79858f6eb8e82f0ec11087983ce4eb8c7edc10c9363a2a124dd78fd2c305dc42",
"blockHash": "0xdbb55a049f14b8152695bf3bbd754aa1fd55bbe10b306eb49caa4bd7d7fcb634",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"excessBlobGas": "0x0",
"blobGasUsed": "0x0"
@ -34,7 +34,7 @@
"id": 67,
"result": {
"status": "VALID",
"latestValidHash": "0x79858f6eb8e82f0ec11087983ce4eb8c7edc10c9363a2a124dd78fd2c305dc42",
"latestValidHash": "0xdbb55a049f14b8152695bf3bbd754aa1fd55bbe10b306eb49caa4bd7d7fcb634",
"validationError": null
}
},

@ -0,0 +1,14 @@
{
"request": {
"jsonrpc": "2.0",
"method": "eth_sendRawTransaction",
"params": ["0xf8c80185e8d4a51000832dc6c09400b42dbf2194e931e80326d950320f7d9dbeac0201b860fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe822fe0a05b88b593926d340f448918ef1c6263356c37f2434774e0fdb1cb9d90cfa5a23ba003a86aac4adb774181ba51eda17efb5fbed99ad57895e6eb56ccdf508a88a7cc"],
"id": 67
},
"response": {
"jsonrpc": "2.0",
"id": 67,
"result": "0xa4252f576c4e16cb020f86f8a30d4fa990ee0cbfc84198a6d0eb118dd2f8b72d"
},
"statusCode": 200
}

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

@ -3,7 +3,7 @@
"jsonrpc": "2.0",
"method": "engine_getPayloadV4",
"params": [
"0x282643de0e3d43bf"
"0x28264396a9634d41"
],
"id": 67
},
@ -12,20 +12,21 @@
"id": 67,
"result": {
"executionPayload": {
"parentHash": "0x79858f6eb8e82f0ec11087983ce4eb8c7edc10c9363a2a124dd78fd2c305dc42",
"parentHash": "0xdbb55a049f14b8152695bf3bbd754aa1fd55bbe10b306eb49caa4bd7d7fcb634",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0xe4642cc58d61f2392fe056042c226e286f22a25e3104f4a4acb423dad9a43311",
"stateRoot": "0x49df1f1a1d28a23fa752230d442077768787d392e9edb70c83d727d31e55eaac",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380",
"gasUsed": "0x145d3",
"gasUsed": "0x3ad4d",
"timestamp": "0x40",
"extraData": "0x",
"baseFeePerGas": "0x7",
"excessBlobGas": "0x0",
"parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
"transactions": [
"0xf8a08085e8d4a51000832dc6c09400a3ca265ebcb825b45f985a16cefb49958ce01702b8388706d19a62f28a6a6549f96c5adaebac9124a61d44868ec94f6d2d707c6a2f82c9162071231dfeb40e24bfde4ffdf2430000000000000000822fdfa00476c1a81f80f4c130acb5f8b8075468ba0893d766b7ec51a8d9723c573ad034a03bd3eaedabbaaf745f15023185ba66584ad3ee8bb40b9bef8c0b9ed27f8b1959"
"0xf8a08085e8d4a51000832dc6c09400a3ca265ebcb825b45f985a16cefb49958ce01702b8388706d19a62f28a6a6549f96c5adaebac9124a61d44868ec94f6d2d707c6a2f82c9162071231dfeb40e24bfde4ffdf2430000000000000000822fdfa00476c1a81f80f4c130acb5f8b8075468ba0893d766b7ec51a8d9723c573ad034a03bd3eaedabbaaf745f15023185ba66584ad3ee8bb40b9bef8c0b9ed27f8b1959",
"0xf8c80185e8d4a51000832dc6c09400b42dbf2194e931e80326d950320f7d9dbeac0201b860fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe822fe0a05b88b593926d340f448918ef1c6263356c37f2434774e0fdb1cb9d90cfa5a23ba003a86aac4adb774181ba51eda17efb5fbed99ad57895e6eb56ccdf508a88a7cc"
],
"withdrawals": [],
"depositRequests": [],
@ -36,12 +37,19 @@
"validatorPubkey": "0x8706d19a62f28a6a6549f96c5adaebac9124a61d44868ec94f6d2d707c6a2f82c9162071231dfeb40e24bfde4ffdf243"
}
],
"consolidationRequests": [
{
"sourceAddress": "0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f",
"sourcePubKey": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"targetPubKey": "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
}
],
"blockNumber": "0x4",
"receiptsRoot": "0x765bd9d63cc10fa47117d6cc0958f15e55a3bde540d4ed15d220f573fbb82cba",
"receiptsRoot": "0x970fc81bb3e7fb21435f9a65a184aa9e3fd2f52b89fd859302b46954354266b5",
"blobGasUsed": "0x0",
"blockHash": "0xb2d60adb2a0c73313ebdacf425b1d6bbd810c3ec6b28ad0d62a73cdc34cb696a"
"blockHash": "0x93df6f3484202f24c692354e2ab96e9948ae45eea6ad85faea121a389e468ea8"
},
"blockValue": "0x12855dcd153473b",
"blockValue": "0x3581baab15c12e5",
"blobsBundle": {
"commitments": [],
"proofs": [],

@ -19,7 +19,9 @@ public enum RequestType {
/** DEPOSITS */
DEPOSIT(0x00),
/** WITHDRAWAL */
WITHDRAWAL(0x01);
WITHDRAWAL(0x01),
/** CONSOLIDATION */
CONSOLIDATION(0x02);
private final int typeValue;
@ -48,6 +50,7 @@ public enum RequestType {
return switch (serializedTypeValue) {
case 0x00 -> DEPOSIT;
case 0x01 -> WITHDRAWAL;
case 0x02 -> CONSOLIDATION;
default ->
throw new IllegalArgumentException(
String.format("Unsupported request type: 0x%02X", serializedTypeValue));

@ -20,6 +20,7 @@ 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.WithdrawalsValidatorProvider.getWithdrawalsValidator;
@ -35,6 +36,7 @@ import org.hyperledger.besu.ethereum.BlockProcessingResult;
import org.hyperledger.besu.ethereum.ProtocolContext;
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.WithdrawalParameter;
@ -185,8 +187,23 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
reqId, new JsonRpcError(INVALID_PARAMS, "Invalid withdrawal request"));
}
final Optional<List<Request>> maybeConsolidationRequests =
Optional.ofNullable(blockParam.getConsolidationRequests())
.map(
consolidationRequest ->
consolidationRequest.stream()
.map(ConsolidationRequestParameter::toConsolidationRequest)
.collect(toList()));
if (!getConsolidationRequestValidator(
protocolSchedule.get(), blockParam.getTimestamp(), blockParam.getBlockNumber())
.validateParameter(maybeConsolidationRequests)) {
return new JsonRpcErrorResponse(
reqId, new JsonRpcError(INVALID_PARAMS, "Invalid consolidation request"));
}
Optional<List<Request>> maybeRequests =
RequestUtil.combine(maybeDepositRequests, maybeWithdrawalRequests);
RequestUtil.combine(
maybeDepositRequests, maybeWithdrawalRequests, maybeConsolidationRequests);
if (mergeContext.get().isSyncing()) {
LOG.debug("We are syncing");

@ -38,6 +38,12 @@ public class RequestValidatorProvider {
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,

@ -0,0 +1,102 @@
/*
* 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
+ '\''
+ '}';
}
}

@ -45,6 +45,7 @@ public class EnginePayloadParameter {
private final String excessBlobGas;
private final List<DepositRequestParameter> depositRequests;
private final List<WithdrawalRequestParameter> withdrawalRequests;
private final List<ConsolidationRequestParameter> consolidationRequests;
/**
* Creates an instance of EnginePayloadParameter.
@ -68,6 +69,7 @@ public class EnginePayloadParameter {
* @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(
@ -90,7 +92,9 @@ public class EnginePayloadParameter {
@JsonProperty("excessBlobGas") final String excessBlobGas,
@JsonProperty("depositRequests") final List<DepositRequestParameter> depositRequests,
@JsonProperty("withdrawalRequests")
final List<WithdrawalRequestParameter> withdrawalRequestParameters) {
final List<WithdrawalRequestParameter> withdrawalRequestParameters,
@JsonProperty("consolidationRequests")
final List<ConsolidationRequestParameter> consolidationRequests) {
this.blockHash = blockHash;
this.parentHash = parentHash;
this.feeRecipient = feeRecipient;
@ -110,6 +114,7 @@ public class EnginePayloadParameter {
this.excessBlobGas = excessBlobGas;
this.depositRequests = depositRequests;
this.withdrawalRequests = withdrawalRequestParameters;
this.consolidationRequests = consolidationRequests;
}
public Hash getBlockHash() {
@ -187,4 +192,8 @@ public class EnginePayloadParameter {
public List<WithdrawalRequestParameter> getWithdrawalRequests() {
return withdrawalRequests;
}
public List<ConsolidationRequestParameter> getConsolidationRequests() {
return consolidationRequests;
}
}

@ -14,6 +14,7 @@
*/
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;
@ -170,6 +171,7 @@ public class BlockResultFactory {
blockWithReceipts.getBlock().getBody().getWithdrawals(),
getDepositRequests(blockWithReceipts.getBlock().getBody().getRequests()),
getWithdrawalRequests(blockWithReceipts.getBlock().getBody().getRequests()),
getConsolidationRequests(blockWithReceipts.getBlock().getBody().getRequests()),
Quantity.create(payload.blockValue()),
blobsBundleV1);
}

@ -14,10 +14,12 @@
*/
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;
@ -44,10 +46,17 @@ public class EngineGetPayloadResultV4 {
final Optional<List<Withdrawal>> withdrawals,
final Optional<List<DepositRequest>> depositRequests,
final Optional<List<WithdrawalRequest>> withdrawalRequests,
final Optional<List<ConsolidationRequest>> consolidationRequests,
final String blockValue,
final BlobsBundleV1 blobsBundle) {
this.executionPayload =
new PayloadResult(header, transactions, withdrawals, depositRequests, withdrawalRequests);
new PayloadResult(
header,
transactions,
withdrawals,
depositRequests,
withdrawalRequests,
consolidationRequests);
this.blockValue = blockValue;
this.blobsBundle = blobsBundle;
this.shouldOverrideBuilder = false;
@ -96,13 +105,15 @@ public class EngineGetPayloadResultV4 {
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<WithdrawalRequest>> withdrawalRequests,
final Optional<List<ConsolidationRequest>> consolidationRequests) {
this.blockNumber = Quantity.create(header.getNumber());
this.blockHash = header.getHash().toString();
this.parentHash = header.getParentHash().toString();
@ -141,6 +152,14 @@ public class EngineGetPayloadResultV4 {
.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);
@ -228,6 +247,11 @@ public class EngineGetPayloadResultV4 {
return withdrawalRequests;
}
@JsonGetter(value = "consolidationRequests")
public List<ConsolidationRequestParameter> getConsolidationRequests() {
return consolidationRequests;
}
@JsonGetter(value = "feeRecipient")
@JsonInclude(JsonInclude.Include.NON_NULL)
public String getFeeRecipient() {
@ -240,7 +264,7 @@ public class EngineGetPayloadResultV4 {
}
@JsonGetter(value = "blobGasUsed")
public String getBlobGasUseds() {
public String getBlobGasUsed() {
return blobGasUsed;
}

@ -38,6 +38,7 @@ 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;
@ -403,7 +404,7 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
protected EnginePayloadParameter mockEnginePayload(
final BlockHeader header, final List<String> txs) {
return mockEnginePayload(header, txs, null, null, null);
return mockEnginePayload(header, txs, null, null, null, null);
}
protected EnginePayloadParameter mockEnginePayload(
@ -411,7 +412,8 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
final List<String> txs,
final List<WithdrawalParameter> withdrawals,
final List<DepositRequestParameter> depositRequests,
final List<WithdrawalRequestParameter> withdrawalRequests) {
final List<WithdrawalRequestParameter> withdrawalRequests,
final List<ConsolidationRequestParameter> consolidationRequests) {
return new EnginePayloadParameter(
header.getHash(),
header.getParentHash(),
@ -431,7 +433,8 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT
header.getBlobGasUsed().map(UnsignedLongParameter::new).orElse(null),
header.getExcessBlobGas().map(BlobGas::toHexString).orElse(null),
depositRequests,
withdrawalRequests);
withdrawalRequests,
consolidationRequests);
}
protected BlockHeader setupValidPayload(

@ -150,6 +150,7 @@ public class EngineGetPayloadV4Test extends AbstractEngineGetPayloadTest {
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));

@ -87,7 +87,9 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest {
.when(blockchain.getBlockHeader(mockHeader.getParentHash()))
.thenReturn(Optional.of(mock(BlockHeader.class)));
var resp =
resp(mockEnginePayload(mockHeader, Collections.emptyList(), withdrawalsParam, null, null));
resp(
mockEnginePayload(
mockHeader, Collections.emptyList(), withdrawalsParam, null, null, null));
assertValidResponse(mockHeader, resp);
}
@ -107,7 +109,7 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest {
.when(blockchain.getBlockHeader(mockHeader.getParentHash()))
.thenReturn(Optional.of(mock(BlockHeader.class)));
var resp =
resp(mockEnginePayload(mockHeader, Collections.emptyList(), withdrawals, null, null));
resp(mockEnginePayload(mockHeader, Collections.emptyList(), withdrawals, null, null, null));
assertValidResponse(mockHeader, resp);
}
@ -127,6 +129,7 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest {
Collections.emptyList(),
withdrawals,
null,
null,
null));
final JsonRpcError jsonRpcError = fromErrorResp(resp);
@ -143,7 +146,8 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest {
.blobGasUsed(100L)
.buildHeader();
var resp = resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of(), null, null));
var resp =
resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of(), null, null, null));
final JsonRpcError jsonRpcError = fromErrorResp(resp);
assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode());
assertThat(jsonRpcError.getData()).isEqualTo("non-null BlobGasUsed pre-cancun");
@ -159,7 +163,8 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest {
.excessBlobGas(BlobGas.MAX_BLOB_GAS)
.buildHeader();
var resp = resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of(), null, null));
var resp =
resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of(), null, null, null));
final JsonRpcError jsonRpcError = fromErrorResp(resp);
assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode());
@ -180,6 +185,7 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest {
Collections.emptyList(),
withdrawals,
null,
null,
null));
assertThat(fromErrorResp(resp).getCode()).isEqualTo(INVALID_PARAMS.getCode());

@ -137,7 +137,7 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test {
Optional.empty(),
Optional.empty());
final EnginePayloadParameter payload =
mockEnginePayload(mockHeader, Collections.emptyList(), null, null, null);
mockEnginePayload(mockHeader, Collections.emptyList(), null, null, null, null);
ValidationResult<RpcErrorType> res =
method.validateParameters(
@ -193,7 +193,8 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test {
.blobGasUsed(null)
.buildHeader();
var resp = resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of(), null, null));
var resp =
resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of(), null, null, null));
final JsonRpcError jsonRpcError = fromErrorResp(resp);
assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode());
@ -212,7 +213,8 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test {
.blobGasUsed(100L)
.buildHeader();
var resp = resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of(), null, null));
var resp =
resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of(), null, null, null));
final JsonRpcError jsonRpcError = fromErrorResp(resp);
assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode());

@ -109,7 +109,9 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
.thenReturn(Optional.of(mockHeader.getHash()));
var resp =
resp(mockEnginePayload(mockHeader, Collections.emptyList(), null, depositRequests, null));
resp(
mockEnginePayload(
mockHeader, Collections.emptyList(), null, depositRequests, null, null));
assertValidResponse(mockHeader, resp);
}
@ -125,6 +127,7 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
Collections.emptyList(),
null,
depositRequests,
null,
null));
assertThat(fromErrorResp(resp).getCode()).isEqualTo(INVALID_PARAMS.getCode());
@ -152,7 +155,7 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
var resp =
resp(
mockEnginePayload(
mockHeader, Collections.emptyList(), null, depositRequestsParam, null));
mockHeader, Collections.emptyList(), null, depositRequestsParam, null, null));
assertValidResponse(mockHeader, resp);
}
@ -172,6 +175,7 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
Collections.emptyList(),
null,
depositRequests,
null,
null));
final JsonRpcError jsonRpcError = fromErrorResp(resp);
@ -195,7 +199,7 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
when(mergeCoordinator.getLatestValidAncestor(mockHeader))
.thenReturn(Optional.of(mockHeader.getHash()));
var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList(), null, null, null));
var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList(), null, null, null, null));
assertValidResponse(mockHeader, resp);
}
@ -211,6 +215,7 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
Collections.emptyList(),
null,
null,
null,
null));
assertThat(fromErrorResp(resp).getCode()).isEqualTo(INVALID_PARAMS.getCode());
@ -239,7 +244,7 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
var resp =
resp(
mockEnginePayload(
mockHeader, Collections.emptyList(), null, null, withdrawalRequestsParams));
mockHeader, Collections.emptyList(), null, null, withdrawalRequestsParams, null));
assertValidResponse(mockHeader, resp);
}
@ -258,7 +263,8 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
Collections.emptyList(),
null,
null,
withdrawalRequests));
withdrawalRequests,
null));
final JsonRpcError jsonRpcError = fromErrorResp(resp);
assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode());

@ -0,0 +1,90 @@
/*
* 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);
}
}

@ -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.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));
}
}

@ -0,0 +1,60 @@
/*
* 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));
}
}

@ -41,7 +41,9 @@ public class RequestDecoder {
RequestType.WITHDRAWAL,
WithdrawalRequestDecoder::decode,
RequestType.DEPOSIT,
DepositRequestDecoder::decode);
DepositRequestDecoder::decode,
RequestType.CONSOLIDATION,
ConsolidationRequestDecoder::decode);
/**
* Decodes a request from its RLP encoded bytes.

@ -38,7 +38,9 @@ public class RequestEncoder {
RequestType.WITHDRAWAL,
WithdrawalRequestEncoder::encode,
RequestType.DEPOSIT,
DepositRequestEncoder::encode);
DepositRequestEncoder::encode,
RequestType.CONSOLIDATION,
ConsolidationRequestEncoder::encode);
/**
* Encodes a Request into the provided RLPOutput.

@ -0,0 +1,68 @@
/*
* 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_PREDEPLOY_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;
/**
* Gets the call address for consolidation requests.
*
* @return The call address.
*/
@Override
protected Address getCallAddress() {
return CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS;
}
/**
* 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);
}
}

@ -0,0 +1,92 @@
/*
* 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));
}
}

@ -22,6 +22,7 @@ public class MainnetRequestsValidator {
final Address depositContractAddress) {
return new RequestsValidatorCoordinator.Builder()
.addValidator(RequestType.WITHDRAWAL, new WithdrawalRequestValidator())
.addValidator(RequestType.CONSOLIDATION, new ConsolidationRequestValidator())
.addValidator(RequestType.DEPOSIT, new DepositRequestValidator(depositContractAddress))
.build();
}
@ -30,6 +31,7 @@ public class MainnetRequestsValidator {
final Address depositContractAddress) {
return new RequestProcessorCoordinator.Builder()
.addProcessor(RequestType.WITHDRAWAL, new WithdrawalRequestProcessor())
.addProcessor(RequestType.CONSOLIDATION, new ConsolidationRequestProcessor())
.addProcessor(RequestType.DEPOSIT, new DepositRequestProcessor(depositContractAddress))
.build();
}

@ -14,6 +14,7 @@
*/
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;
@ -52,23 +53,33 @@ public class RequestUtil {
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 two optional lists of requests into a single optional list.
* 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.
* @return An Optional containing the combined list of requests, or an empty Optional if both
* inputs are empty.
* @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) {
if (maybeDepositRequests.isEmpty() && maybeWithdrawalRequest.isEmpty()) {
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);
}
}

@ -0,0 +1,46 @@
/*
* 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.core.Request;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
class ConsolidationRequestDecoderTest {
@Test
public void shouldDecodeWithdrawalRequest() {
final ConsolidationRequest expectedConsolidationRequest =
new ConsolidationRequest(
Address.fromHexString("0x814FaE9f487206471B6B0D713cD51a2D35980000"),
BLSPublicKey.fromHexString(
"0xb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e"),
BLSPublicKey.fromHexString(
"0xa09a4a15bf67b328c9b101d09e5c6ee6672978f7ad9ef0d9e2c457aee99223555d8601f0cb3bcc4ce1af9864779a416e"));
final BytesValueRLPOutput out = new BytesValueRLPOutput();
expectedConsolidationRequest.writeTo(out);
final Request decodedWithdrawalRequest = RequestDecoder.decode(RLP.input(out.encoded()));
Assertions.assertThat(decodedWithdrawalRequest).isEqualTo(expectedConsolidationRequest);
}
}

@ -0,0 +1,55 @@
/*
* 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 org.assertj.core.api.Assertions.assertThat;
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;
import org.junit.jupiter.api.Test;
class ConsolidationRequestEncoderTest {
private final String expectedEncodedBytes =
"f87794763c396673f9c391dce3361a9a71c8e161388000b0b10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416eb0a09a4a15bf67b328c9b101d09e5c6ee6672978f7ad9ef0d9e2c457aee99223555d8601f0cb3bcc4ce1af9864779a416e";
final ConsolidationRequest consolidationRequest =
new ConsolidationRequest(
Address.fromHexString("0x763c396673F9c391DCe3361A9A71C8E161388000"),
BLSPublicKey.fromHexString(
"0xb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e"),
BLSPublicKey.fromHexString(
"0xa09a4a15bf67b328c9b101d09e5c6ee6672978f7ad9ef0d9e2c457aee99223555d8601f0cb3bcc4ce1af9864779a416e"));
@Test
void shouldEncodeConsolidationRequest() {
final Bytes encoded = ConsolidationRequestEncoder.encodeOpaqueBytes(consolidationRequest);
assertThat(encoded).isEqualTo(Bytes.fromHexString(expectedEncodedBytes));
}
@Test
void shouldEncodeRequest() {
final Bytes encoded = RequestEncoder.encodeOpaqueBytes(consolidationRequest);
assertThat(encoded)
.isEqualTo(
Bytes.fromHexString(
String.format(
"0x%02X%s",
consolidationRequest.getType().getSerializedType(), expectedEncodedBytes)));
}
}

@ -31,7 +31,7 @@ import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt64;
import org.junit.jupiter.api.Test;
class DepositRequestRequestDecoderTest {
class DepositRequestDecoderTest {
@Test
void shouldDecodeDeposit() {
final DepositRequest expectedDepositRequest =

@ -26,7 +26,7 @@ import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt64;
import org.junit.jupiter.api.Test;
class DepositRequestRequestEncoderTest {
class DepositRequestEncoderTest {
private final String expectedDepositEncodedBytes =
"f8bbb0b10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416ea00017a7fcf06faf493d30bbe2632ea7c2383cd86825e12797165de7aa35589483850773594000b860a889db8300194050a2636c92a95bc7160515867614b7971a9500cdb62f9c0890217d2901c3241f86fac029428fc106930606154bd9e406d7588934a5f15b837180b17194d6e44bd6de23e43b163dfe12e369dcc75a3852cd997963f158217eb501";

@ -0,0 +1,136 @@
/*
* 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;
import static org.hyperledger.besu.ethereum.mainnet.requests.ConsolidationRequestValidator.MAX_CONSOLIDATION_REQUESTS_PER_BLOCK;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BLSPublicKey;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockDataGenerator;
import org.hyperledger.besu.ethereum.core.ConsolidationRequest;
import org.hyperledger.besu.ethereum.core.Request;
import java.util.List;
import java.util.Optional;
import java.util.stream.IntStream;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.bytes.Bytes48;
public class ConsolidationRequestValidatorTestFixtures {
private static final BlockDataGenerator blockDataGenerator = new BlockDataGenerator();
static ConsolidationRequestTestParameter
blockWithConsolidationRequestsAndWithdrawalRequestsRoot() {
final ConsolidationRequest consolidationRequest = createConsolidationRequest();
final Optional<List<Request>> maybeConsolidationRequests =
Optional.of(List.of(consolidationRequest));
final BlockDataGenerator.BlockOptions blockOptions =
BlockDataGenerator.BlockOptions.create()
.setRequestsRoot(BodyValidation.requestsRoot(maybeConsolidationRequests.get()))
.setRequests(maybeConsolidationRequests);
final Block block = blockDataGenerator.block(blockOptions);
return new ConsolidationRequestTestParameter(
"Block with consolidation requests and withdrawal_requests_root",
block,
Optional.of(List.of(consolidationRequest)));
}
static ConsolidationRequestTestParameter blockWithConsolidationRequestsMismatch() {
final ConsolidationRequest consolidationRequest = createConsolidationRequest();
final Optional<List<Request>> requests =
Optional.of(List.of(consolidationRequest, consolidationRequest));
final BlockDataGenerator.BlockOptions blockOptions =
BlockDataGenerator.BlockOptions.create()
.setRequestsRoot(BodyValidation.requestsRoot(requests.get()))
.setRequests(requests);
final Block block = blockDataGenerator.block(blockOptions);
return new ConsolidationRequestTestParameter(
"Block with consolidation requests mismatch",
block,
Optional.of(List.of(consolidationRequest, consolidationRequest)),
List.of(createConsolidationRequest()));
}
static ConsolidationRequestTestParameter blockWithMoreThanMaximumConsolidationRequests() {
final List<ConsolidationRequest> consolidationRequests =
IntStream.range(0, MAX_CONSOLIDATION_REQUESTS_PER_BLOCK + 1)
.mapToObj(__ -> createConsolidationRequest())
.toList();
final Optional<List<ConsolidationRequest>> maybeConsolidationRequest =
Optional.of(consolidationRequests);
final Optional<List<Request>> maybeRequests =
Optional.of(consolidationRequests.stream().map(r -> (Request) r).toList());
final BlockDataGenerator.BlockOptions blockOptions =
BlockDataGenerator.BlockOptions.create()
.setRequestsRoot(BodyValidation.requestsRoot(maybeRequests.get()))
.setRequests(maybeRequests);
final Block block = blockDataGenerator.block(blockOptions);
return new ConsolidationRequestTestParameter(
"Block with more than maximum consolidation requests", block, maybeConsolidationRequest);
}
static ConsolidationRequest createConsolidationRequest() {
return new ConsolidationRequest(
Address.extract(Bytes32.random()),
BLSPublicKey.wrap(Bytes48.random()),
BLSPublicKey.wrap(Bytes48.random()));
}
static class ConsolidationRequestTestParameter {
String description;
Block block;
Optional<List<ConsolidationRequest>> maybeConsolidationRequest;
List<ConsolidationRequest> expectedConsolidationRequest;
public ConsolidationRequestTestParameter(
final String description,
final Block block,
final Optional<List<ConsolidationRequest>> maybeConsolidationRequest) {
this(
description,
block,
maybeConsolidationRequest,
maybeConsolidationRequest.orElseGet(List::of));
}
public ConsolidationRequestTestParameter(
final String description,
final Block block,
final Optional<List<ConsolidationRequest>> maybeConsolidationRequest,
final List<ConsolidationRequest> expectedConsolidationRequest) {
this.description = description;
this.block = block;
this.maybeConsolidationRequest = maybeConsolidationRequest;
this.expectedConsolidationRequest = expectedConsolidationRequest;
}
@Override
public String toString() {
return description;
}
}
}

@ -0,0 +1,76 @@
/*
* 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;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.ethereum.mainnet.ConsolidationRequestValidatorTestFixtures.blockWithConsolidationRequestsAndWithdrawalRequestsRoot;
import static org.hyperledger.besu.ethereum.mainnet.ConsolidationRequestValidatorTestFixtures.blockWithConsolidationRequestsMismatch;
import static org.hyperledger.besu.ethereum.mainnet.ConsolidationRequestValidatorTestFixtures.blockWithMoreThanMaximumConsolidationRequests;
import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.mainnet.ConsolidationRequestValidatorTestFixtures.ConsolidationRequestTestParameter;
import org.hyperledger.besu.ethereum.mainnet.requests.ConsolidationRequestValidator;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
class PragueConsolidationRequestValidatorTest {
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("paramsForValidateConsolidationRequestParameter")
public void validateConsolidationRequestParameter(
final String description,
final Optional<List<Request>> maybeRequests,
final boolean expectedValidity) {
assertThat(new ConsolidationRequestValidator().validateParameter(maybeRequests))
.isEqualTo(expectedValidity);
}
private static Stream<Arguments> paramsForValidateConsolidationRequestParameter() {
return Stream.of(
Arguments.of(
"Allowed ConsolidationRequests - validating empty ConsolidationRequests",
Optional.empty(),
true),
Arguments.of(
"Allowed ConsolidationRequests - validating present ConsolidationRequests",
Optional.of(List.of()),
true));
}
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("validateConsolidationRequestsInBlockParamsForPrague")
public void validateConsolidationRequestsInBlock_WhenPrague(
final ConsolidationRequestTestParameter param, final boolean expectedValidity) {
assertThat(
new ConsolidationRequestValidator()
.validate(
param.block, new ArrayList<>(param.expectedConsolidationRequest), List.of()))
.isEqualTo(expectedValidity);
}
private static Stream<Arguments> validateConsolidationRequestsInBlockParamsForPrague() {
return Stream.of(
Arguments.of(blockWithConsolidationRequestsAndWithdrawalRequestsRoot(), true),
Arguments.of(blockWithConsolidationRequestsMismatch(), false),
Arguments.of(blockWithMoreThanMaximumConsolidationRequests(), false));
}
}

@ -32,6 +32,7 @@ import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.chain.Blockchain;
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.Request;
import org.hyperledger.besu.ethereum.core.Transaction;
@ -495,15 +496,25 @@ public class T8nExecutor {
obj.put("index", deposit.getIndex().toHexString());
});
var withdrawlRequests = resultObject.putArray("withdrawalRequests");
var withdrawalRequests = resultObject.putArray("withdrawalRequests");
RequestUtil.filterRequestsOfType(maybeRequests.orElse(List.of()), WithdrawalRequest.class)
.forEach(
wr -> {
var obj = withdrawlRequests.addObject();
var obj = withdrawalRequests.addObject();
obj.put("sourceAddress", wr.getSourceAddress().toHexString());
obj.put("validatorPubkey", wr.getValidatorPubkey().toHexString());
obj.put("amount", wr.getAmount().toHexString());
});
var consolidationRequests = resultObject.putArray("consolidationRequests");
RequestUtil.filterRequestsOfType(maybeRequests.orElse(List.of()), ConsolidationRequest.class)
.forEach(
cr -> {
var obj = consolidationRequests.addObject();
obj.put("sourceAddress", cr.getSourceAddress().toHexString());
obj.put("sourcePubkey", cr.getSourcePubkey().toHexString());
obj.put("targetPubkey", cr.getTargetPubkey().toHexString());
});
}
worldState.persist(blockHeader);

@ -172,6 +172,11 @@
"balance": "0x3782dace9d9000000",
"nonce": "0x1"
},
"0x00a3ca265ebcb825b45f985a16cefb49958ce017": {
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe146090573615156028575f545f5260205ff35b366038141561012e5760115f54600182026001905f5b5f82111560595781019083028483029004916001019190603e565b90939004341061012e57600154600101600155600354806003026004013381556001015f3581556001016020359055600101600355005b6003546002548082038060101160a4575060105b5f5b81811460dd5780604c02838201600302600401805490600101805490600101549160601b83528260140152906034015260010160a6565b910180921460ed579060025560f8565b90505f6002555f6003555b5f548061049d141561010757505f5b60015460028282011161011c5750505f610122565b01600290035b5f555f600155604c025ff35b5f5ffd",
"balance": "0x0",
"nonce": "0x1"
},
"0x000f3df6d732807ef1319fb7b8bb8522d0beac02": {
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500",
"storage": {
@ -180,11 +185,6 @@
"balance": "0x0",
"nonce": "0x1"
},
"0x00a3ca265ebcb825b45f985a16cefb49958ce017": {
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe146090573615156028575f545f5260205ff35b366038141561012e5760115f54600182026001905f5b5f82111560595781019083028483029004916001019190603e565b90939004341061012e57600154600101600155600354806003026004013381556001015f3581556001016020359055600101600355005b6003546002548082038060101160a4575060105b5f5b81811460dd5780604c02838201600302600401805490600101805490600101549160601b83528260140152906034015260010160a6565b910180921460ed579060025560f8565b90505f6002555f6003555b5f548061049d141561010757505f5b60015460028282011161011c5750505f610122565b01600290035b5f555f600155604c025ff35b5f5ffd",
"balance": "0x0",
"nonce": "0x1"
},
"0x0aae40965e6800cd9b1f4b05ff21581047e3f91e": {
"code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460575767ffffffffffffffff5f3511605357600143035f3511604b575f35612000014311604b57611fff5f3516545f5260205ff35b5f5f5260205ff35b5f5ffd5b5f35611fff60014303165500",
"storage": {
@ -282,7 +282,8 @@
"index": "0x0000000000000001"
}
],
"withdrawalRequests": []
"withdrawalRequests": [],
"consolidationRequests":[]
}
}
}

@ -314,6 +314,7 @@
"amount": "0x0000000000000000"
}
],
"consolidationRequests":[],
"stateRoot": "0xf63d7552dc407993393315e99272781d04eedfcf369a1acd3e386d1e6710229d",
"txRoot": "0x8521df63211790726b6f1a437bb0fd4b27c00e13e7678d324c4cfddb8d834ad2",
"receiptsRoot": "0x4bd8bd5580caf4ed45f873794ad7ff9d6fd2363ae529269b17b891b68d349d75",

@ -90,10 +90,10 @@ public class BlockchainReferenceTestTools {
params.ignore(
"UncleFromSideChain_(Merge|Paris|Shanghai|Cancun|Prague|Osaka|Amsterdam|Bogota|Polis|Bangkok)");
// EOF tests don't have Prague stuff like deopsits right now
// EOF tests don't have Prague stuff like deposits right now
params.ignore("/stEOF/");
// None of the Prague tests have withdrawls and deposits handling
// None of the Prague tests have withdrawals and deposits handling
params.ignore("\\[Prague\\]");
}

@ -70,7 +70,7 @@ Calculated : ${currentHash}
tasks.register('checkAPIChanges', FileStateChecker) {
description = "Checks that the API for the Plugin-API project does not change without deliberate thought"
files = sourceSets.main.allJava.files
knownHash = 'yH50m+z1tnzshJQPdwR86pb2EU3m6iZxwkqoy/5spcs='
knownHash = 'Yv6CY8fh0yrIz3Q8Moy/j1TNGL+O8Mewp4SIgM1JE6M='
}
check.dependsOn('checkAPIChanges')

@ -0,0 +1,45 @@
/*
* 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.plugin.data;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.PublicKey;
import org.hyperledger.besu.plugin.Unstable;
/** A consolidation request is an operation sent to the Beacon Node for processing. */
@Unstable
public interface ConsolidationRequest {
/**
* Withdrawal credential (0x01) associated with the validator
*
* @return withdrawal credential address
*/
Address getSourceAddress();
/**
* Public key of the address that sends the consolidation
*
* @return public key of sender
*/
PublicKey getSourcePubkey();
/**
* Public key of the address to receives the consolidation
*
* @return public key of target
*/
PublicKey getTargetPubkey();
}
Loading…
Cancel
Save