From 0e728457acd9f7aae3e8f10933a35249971c06e4 Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Tue, 16 Jul 2024 10:44:06 +1000 Subject: [PATCH] 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 Signed-off-by: Sally MacFarlane --------- Signed-off-by: Sally MacFarlane Signed-off-by: Justin Florentine Co-authored-by: Justin Florentine Signed-off-by: Daniel Lehrner --- .../jsonrpc/engine/prague/genesis.json | 16 ++- .../test-cases/00_get_genesis_block_info.json | 43 ++++++ .../test-cases/01_cancun_prepare_payload.json | 8 +- .../test-cases/02_cancun_getPayloadV3.json | 8 +- .../test-cases/03_cancun_newPayloadV3.json | 8 +- .../04_cancun_forkchoiceUpdatedV3.json | 8 +- .../05_prague_forkchoiceUpdatedV3.json | 10 +- .../test-cases/06_prague_getPayloadV4.json | 9 +- ...invalid_null_deposits_execute_payload.json | 2 +- .../test-cases/09_prague_newPayloadV4.json | 9 +- .../10_prague_forkchoiceUpdatedV3.json | 10 +- .../test-cases/11_prague_getPayloadV4.json | 9 +- ...oadV4.json => 12_cancun_newPayloadV3.json} | 8 +- ...raw_transaction_consolidation_request.json | 14 ++ ...son => 15_prague_forkchoiceUpdatedV3.json} | 10 +- ...oadV4.json => 16_prague_getPayloadV4.json} | 24 ++-- .../besu/datatypes/RequestType.java | 5 +- .../engine/AbstractEngineNewPayload.java | 19 ++- .../engine/RequestValidatorProvider.java | 6 + .../ConsolidationRequestParameter.java | 102 +++++++++++++ .../parameters/EnginePayloadParameter.java | 11 +- .../internal/results/BlockResultFactory.java | 2 + .../results/EngineGetPayloadResultV4.java | 30 +++- .../engine/AbstractEngineNewPayloadTest.java | 9 +- .../engine/EngineGetPayloadV4Test.java | 1 + .../engine/EngineNewPayloadV2Test.java | 14 +- .../engine/EngineNewPayloadV3Test.java | 8 +- .../engine/EngineNewPayloadV4Test.java | 16 ++- .../ethereum/core/ConsolidationRequest.java | 90 ++++++++++++ .../encoding/ConsolidationRequestDecoder.java | 40 ++++++ .../encoding/ConsolidationRequestEncoder.java | 60 ++++++++ .../core/encoding/RequestDecoder.java | 4 +- .../core/encoding/RequestEncoder.java | 4 +- .../ConsolidationRequestProcessor.java | 68 +++++++++ .../ConsolidationRequestValidator.java | 92 ++++++++++++ .../requests/MainnetRequestsValidator.java | 2 + .../mainnet/requests/RequestUtil.java | 21 ++- .../ConsolidationRequestDecoderTest.java | 46 ++++++ .../ConsolidationRequestEncoderTest.java | 55 +++++++ ...st.java => DepositRequestDecoderTest.java} | 2 +- ...st.java => DepositRequestEncoderTest.java} | 2 +- ...olidationRequestValidatorTestFixtures.java | 136 ++++++++++++++++++ ...agueConsolidationRequestValidatorTest.java | 76 ++++++++++ .../hyperledger/besu/evmtool/T8nExecutor.java | 15 +- .../besu/evmtool/t8n/prague-deposit.json | 13 +- .../besu/evmtool/t8n/prague-withdrawal.json | 1 + .../vm/BlockchainReferenceTestTools.java | 4 +- plugin-api/build.gradle | 2 +- .../plugin/data/ConsolidationRequest.java | 45 ++++++ 49 files changed, 1099 insertions(+), 98 deletions(-) create mode 100644 acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/00_get_genesis_block_info.json rename acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/{12_cancun_newPayloadV4.json => 12_cancun_newPayloadV3.json} (80%) create mode 100644 acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/14_prague_send_raw_transaction_consolidation_request.json rename acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/{14_prague_forkchoiceUpdatedV3.json => 15_prague_forkchoiceUpdatedV3.json} (61%) rename acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/{15_prague_getPayloadV4.json => 16_prague_getPayloadV4.json} (62%) create mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/ConsolidationRequestParameter.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ConsolidationRequest.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/ConsolidationRequestDecoder.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/ConsolidationRequestEncoder.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/ConsolidationRequestProcessor.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/ConsolidationRequestValidator.java create mode 100644 ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/ConsolidationRequestDecoderTest.java create mode 100644 ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/ConsolidationRequestEncoderTest.java rename ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/{DepositRequestRequestDecoderTest.java => DepositRequestDecoderTest.java} (99%) rename ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/{DepositRequestRequestEncoderTest.java => DepositRequestEncoderTest.java} (98%) create mode 100644 ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ConsolidationRequestValidatorTestFixtures.java create mode 100644 ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PragueConsolidationRequestValidatorTest.java create mode 100644 plugin-api/src/main/java/org/hyperledger/besu/plugin/data/ConsolidationRequest.java diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/genesis.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/genesis.json index 3f2645d4d3a..ac474c02453 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/genesis.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/genesis.json @@ -33,7 +33,7 @@ "balance": "1000000000000000000000000000" }, "0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f": { - "comment": "This is the account used to sign the transaction that creates a validator exit", + "comment": "This is the account used to sign the transactions that create a validator exit, and consolidation request", "balance": "1000000000000000000000000000" }, "0x00A3ca265EBcb825B45F985A16CEFB49958cE017": { @@ -50,6 +50,20 @@ "0x0000000000000000000000000000000000000000000000000000000000000006": "5d8601f0cb3bcc4ce1af9864779a416e00000000000000000000000000000000" } }, + "0x00b42dbF2194e931E80326D950320f7d9Dbeac02": { + "comment": "This is the runtime bytecode for the Consolidation Request Smart Contract. It was created from the deployment transaction in EIP-7251 (https://eips.ethereum.org/EIPS/eip-7251#deployment)", + "balance": "0", + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe146098573615156028575f545f5260205ff35b36606014156101445760115f54600182026001905f5b5f82111560595781019083028483029004916001019190603e565b90939004341061014457600154600101600155600354806004026004013381556001015f35815560010160203581556001016040359055600101600355005b6003546002548082038060011160ac575060015b5f5b81811460f15780607402838201600402600401805490600101805490600101805490600101549260601b84529083601401528260340152906054015260010160ae565b9101809214610103579060025561010e565b90505f6002555f6003555b5f548061049d141561011d57505f5b6001546001828201116101325750505f610138565b01600190035b5f555f6001556074025ff35b5f5ffd", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000005": "0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000006": "0000000000000000000000000000000000000000000000000000000000000000" + } + }, "0x4242424242424242424242424242424242424242": { "balance": "0", "code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107bf565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610859573d6000803e3d6000fd5b5050506040513d602081101561086e57600080fd5b5051905060006002806108846040848a8c6116fe565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108f857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016108bb565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610955573d6000803e3d6000fd5b5050506040513d602081101561096a57600080fd5b5051600261097b896040818d6116fe565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106109f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016109b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610a51573d6000803e3d6000fd5b5050506040513d6020811015610a6657600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610ada57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610a9d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610b37573d6000803e3d6000fd5b5050506040513d6020811015610b4c57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610bd957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610b9c565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610c36573d6000803e3d6000fd5b5050506040513d6020811015610c4b57600080fd5b50516040518651600291889160009188916020918201918291908601908083835b60208310610ca957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c6c565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610d4e57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610d11565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610dab573d6000803e3d6000fd5b5050506040513d6020811015610dc057600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610e3457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610df7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610e91573d6000803e3d6000fd5b5050506040513d6020811015610ea657600080fd5b50519050858114610f02576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260548152602001806117486054913960600191505060405180910390fd5b60205463ffffffff11610f60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806117276021913960400191505060405180910390fd5b602080546001019081905560005b60208110156110a9578160011660011415610fa0578260008260208110610f9157fe5b0155506110ac95505050505050565b600260008260208110610faf57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061102557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610fe8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015611082573d6000803e3d6000fd5b5050506040513d602081101561109757600080fd5b50519250600282049150600101610f6e565b50fe5b50505050505050565b60606110c26020546114ba565b905090565b6020546000908190815b60208110156112f05781600116600114156111e6576002600082602081106110f557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061116b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161112e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156111c8573d6000803e3d6000fd5b5050506040513d60208110156111dd57600080fd5b505192506112e2565b600283602183602081106111f657fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061126b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161122e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156112c8573d6000803e3d6000fd5b5050506040513d60208110156112dd57600080fd5b505192505b6002820491506001016110d1565b506002826112ff6020546114ba565b600060401b6040516020018084815260200183805190602001908083835b6020831061135a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161131d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000095909516920191825250604080518083037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8018152601890920190819052815191955093508392850191508083835b6020831061143f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611402565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa15801561149c573d6000803e3d6000fd5b5050506040513d60208110156114b157600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106114f457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b8260018151811061153757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b8260028151811061157a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b826003815181106115bd57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b8260048151811061160057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b8260058151811061164357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b8260068151811061168657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106116c957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b6000808585111561170d578182fd5b83861115611719578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a26469706673582212201dd26f37a621703009abf16e77e69c93dc50c79db7f6cc37543e3e0e3decdc9764736f6c634300060b0033", diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/00_get_genesis_block_info.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/00_get_genesis_block_info.json new file mode 100644 index 00000000000..d1a18826a9e --- /dev/null +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/00_get_genesis_block_info.json @@ -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 +} \ No newline at end of file diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/01_cancun_prepare_payload.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/01_cancun_prepare_payload.json index 21a2e70a48d..ad4b9be2d08 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/01_cancun_prepare_payload.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/01_cancun_prepare_payload.json @@ -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 diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/02_cancun_getPayloadV3.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/02_cancun_getPayloadV3.json index 0c9281fc6a5..63cfeec26a1 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/02_cancun_getPayloadV3.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/02_cancun_getPayloadV3.json @@ -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": { diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/03_cancun_newPayloadV3.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/03_cancun_newPayloadV3.json index 583bdc1a20e..9f984b2f350 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/03_cancun_newPayloadV3.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/03_cancun_newPayloadV3.json @@ -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 } }, diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/04_cancun_forkchoiceUpdatedV3.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/04_cancun_forkchoiceUpdatedV3.json index 229ca2cf51c..b0ce0f70c1a 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/04_cancun_forkchoiceUpdatedV3.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/04_cancun_forkchoiceUpdatedV3.json @@ -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 diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/05_prague_forkchoiceUpdatedV3.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/05_prague_forkchoiceUpdatedV3.json index 721a625b6ab..1eae1c881ad 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/05_prague_forkchoiceUpdatedV3.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/05_prague_forkchoiceUpdatedV3.json @@ -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 diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/06_prague_getPayloadV4.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/06_prague_getPayloadV4.json index 6ff3614cdf7..4cb85d5f546 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/06_prague_getPayloadV4.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/06_prague_getPayloadV4.json @@ -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" }, diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/08_prague_invalid_null_deposits_execute_payload.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/08_prague_invalid_null_deposits_execute_payload.json index 7263aea00f7..ed75e54aafb 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/08_prague_invalid_null_deposits_execute_payload.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/08_prague_invalid_null_deposits_execute_payload.json @@ -4,7 +4,7 @@ "method": "engine_newPayloadV4", "params": [ { - "parentHash": "0xa7a92cc82e1d876476ad6433538599b0d592f88ba0823c23e80af93fb1748f14", + "parentHash": "0x27a2bc2ac21b3fc796f636bec1ec9cba100435f9a793176a83a5d4fa7cc13006", "feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", "stateRoot": "0x9b8c4a9a86cb49252075c0db2f0e72fb1e49350a0f70ea36f26f700201961e62", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/09_prague_newPayloadV4.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/09_prague_newPayloadV4.json index a5ff6fa7ec8..17496f9ed78 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/09_prague_newPayloadV4.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/09_prague_newPayloadV4.json @@ -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 } }, diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/10_prague_forkchoiceUpdatedV3.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/10_prague_forkchoiceUpdatedV3.json index d8594f62800..ba0f1e8e5bd 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/10_prague_forkchoiceUpdatedV3.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/10_prague_forkchoiceUpdatedV3.json @@ -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 diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/11_prague_getPayloadV4.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/11_prague_getPayloadV4.json index 6a22938a693..3b76fac10a1 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/11_prague_getPayloadV4.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/11_prague_getPayloadV4.json @@ -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" }, diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/12_cancun_newPayloadV4.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/12_cancun_newPayloadV3.json similarity index 80% rename from acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/12_cancun_newPayloadV4.json rename to acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/12_cancun_newPayloadV3.json index 5d9f96c53b3..546872807c5 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/12_cancun_newPayloadV4.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/12_cancun_newPayloadV3.json @@ -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 } }, diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/14_prague_send_raw_transaction_consolidation_request.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/14_prague_send_raw_transaction_consolidation_request.json new file mode 100644 index 00000000000..85c41f2991f --- /dev/null +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/14_prague_send_raw_transaction_consolidation_request.json @@ -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 +} \ No newline at end of file diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/14_prague_forkchoiceUpdatedV3.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/15_prague_forkchoiceUpdatedV3.json similarity index 61% rename from acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/14_prague_forkchoiceUpdatedV3.json rename to acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/15_prague_forkchoiceUpdatedV3.json index bf2b3dca5ad..61750afbe74 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/14_prague_forkchoiceUpdatedV3.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/15_prague_forkchoiceUpdatedV3.json @@ -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 diff --git a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/15_prague_getPayloadV4.json b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/16_prague_getPayloadV4.json similarity index 62% rename from acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/15_prague_getPayloadV4.json rename to acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/16_prague_getPayloadV4.json index c287cfaed8a..c3fdd33adae 100644 --- a/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/15_prague_getPayloadV4.json +++ b/acceptance-tests/tests/src/test/resources/jsonrpc/engine/prague/test-cases/16_prague_getPayloadV4.json @@ -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": [], diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/RequestType.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/RequestType.java index 628baa6d5f7..5a8fe97a36e 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/RequestType.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/RequestType.java @@ -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 static RequestType of(final int serializedTypeValue) { return switch (serializedTypeValue) { case 0x00 -> DEPOSIT; case 0x01 -> WITHDRAWAL; + case 0x02 -> CONSOLIDATION; default -> throw new IllegalArgumentException( String.format("Unsupported request type: 0x%02X", serializedTypeValue)); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java index e8134fdb1a5..543c965c804 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java @@ -20,6 +20,7 @@ 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.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 JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) reqId, new JsonRpcError(INVALID_PARAMS, "Invalid withdrawal request")); } + final Optional> 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> maybeRequests = - RequestUtil.combine(maybeDepositRequests, maybeWithdrawalRequests); + RequestUtil.combine( + maybeDepositRequests, maybeWithdrawalRequests, maybeConsolidationRequests); if (mergeContext.get().isSyncing()) { LOG.debug("We are syncing"); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/RequestValidatorProvider.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/RequestValidatorProvider.java index 505d3695186..c3d9c8376b2 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/RequestValidatorProvider.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/RequestValidatorProvider.java @@ -38,6 +38,12 @@ public static RequestValidator getWithdrawalRequestValidator( 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, diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/ConsolidationRequestParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/ConsolidationRequestParameter.java new file mode 100644 index 00000000000..d33b12c6a7b --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/ConsolidationRequestParameter.java @@ -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 + + '\'' + + '}'; + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadParameter.java index 4fd24e15a6f..fdcec45c6bd 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadParameter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadParameter.java @@ -45,6 +45,7 @@ public class EnginePayloadParameter { private final String excessBlobGas; private final List depositRequests; private final List withdrawalRequests; + private final List 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 EnginePayloadParameter( @JsonProperty("excessBlobGas") final String excessBlobGas, @JsonProperty("depositRequests") final List depositRequests, @JsonProperty("withdrawalRequests") - final List withdrawalRequestParameters) { + final List withdrawalRequestParameters, + @JsonProperty("consolidationRequests") + final List consolidationRequests) { this.blockHash = blockHash; this.parentHash = parentHash; this.feeRecipient = feeRecipient; @@ -110,6 +114,7 @@ public EnginePayloadParameter( this.excessBlobGas = excessBlobGas; this.depositRequests = depositRequests; this.withdrawalRequests = withdrawalRequestParameters; + this.consolidationRequests = consolidationRequests; } public Hash getBlockHash() { @@ -187,4 +192,8 @@ public List getDepositRequests() { public List getWithdrawalRequests() { return withdrawalRequests; } + + public List getConsolidationRequests() { + return consolidationRequests; + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java index 2f89ef12ce1..b8111c00c76 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java @@ -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 EngineGetPayloadResultV4 payloadTransactionCompleteV4(final PayloadWrappe blockWithReceipts.getBlock().getBody().getWithdrawals(), getDepositRequests(blockWithReceipts.getBlock().getBody().getRequests()), getWithdrawalRequests(blockWithReceipts.getBlock().getBody().getRequests()), + getConsolidationRequests(blockWithReceipts.getBlock().getBody().getRequests()), Quantity.create(payload.blockValue()), blobsBundleV1); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV4.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV4.java index 133fbabe609..39772ff7dbf 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV4.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV4.java @@ -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 EngineGetPayloadResultV4( final Optional> withdrawals, final Optional> depositRequests, final Optional> withdrawalRequests, + final Optional> 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 static class PayloadResult { private final List withdrawals; private final List depositRequests; private final List withdrawalRequests; + private final List consolidationRequests; public PayloadResult( final BlockHeader header, final List transactions, final Optional> withdrawals, final Optional> depositRequests, - final Optional> withdrawalRequests) { + final Optional> withdrawalRequests, + final Optional> consolidationRequests) { this.blockNumber = Quantity.create(header.getNumber()); this.blockHash = header.getHash().toString(); this.parentHash = header.getParentHash().toString(); @@ -141,6 +152,14 @@ public PayloadResult( .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 List getWithdrawalRequests() { return withdrawalRequests; } + @JsonGetter(value = "consolidationRequests") + public List getConsolidationRequests() { + return consolidationRequests; + } + @JsonGetter(value = "feeRecipient") @JsonInclude(JsonInclude.Include.NON_NULL) public String getFeeRecipient() { @@ -240,7 +264,7 @@ public String getExcessBlobGas() { } @JsonGetter(value = "blobGasUsed") - public String getBlobGasUseds() { + public String getBlobGasUsed() { return blobGasUsed; } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java index 26d0dad955d..10da8a4486f 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java @@ -38,6 +38,7 @@ 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 @@ protected JsonRpcResponse resp(final EnginePayloadParameter payload) { protected EnginePayloadParameter mockEnginePayload( final BlockHeader header, final List txs) { - return mockEnginePayload(header, txs, null, null, null); + return mockEnginePayload(header, txs, null, null, null, null); } protected EnginePayloadParameter mockEnginePayload( @@ -411,7 +412,8 @@ protected EnginePayloadParameter mockEnginePayload( final List txs, final List withdrawals, final List depositRequests, - final List withdrawalRequests) { + final List withdrawalRequests, + final List consolidationRequests) { return new EnginePayloadParameter( header.getHash(), header.getParentHash(), @@ -431,7 +433,8 @@ protected EnginePayloadParameter mockEnginePayload( header.getBlobGasUsed().map(UnsignedLongParameter::new).orElse(null), header.getExcessBlobGas().map(BlobGas::toHexString).orElse(null), depositRequests, - withdrawalRequests); + withdrawalRequests, + consolidationRequests); } protected BlockHeader setupValidPayload( diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV4Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV4Test.java index 535b2c9983e..134c7a2c0c6 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV4Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineGetPayloadV4Test.java @@ -150,6 +150,7 @@ public void shouldReturnBlockForKnownPayloadId() { 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)); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2Test.java index 1d794170216..412dc6f8927 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2Test.java @@ -87,7 +87,9 @@ public void shouldReturnValidIfWithdrawalsIsNotNull_WhenWithdrawalsAllowed() { .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 void shouldReturnValidIfWithdrawalsIsNull_WhenWithdrawalsProhibited() { .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 void shouldReturnInvalidIfWithdrawalsIsNotNull_WhenWithdrawalsProhibited( Collections.emptyList(), withdrawals, null, + null, null)); final JsonRpcError jsonRpcError = fromErrorResp(resp); @@ -143,7 +146,8 @@ public void shouldValidateBlobGasUsedCorrectly() { .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 void shouldValidateExcessBlobGasCorrectly() { .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 void shouldReturnInvalidIfWithdrawalsIsNull_WhenWithdrawalsAllowed() { Collections.emptyList(), withdrawals, null, + null, null)); assertThat(fromErrorResp(resp).getCode()).isEqualTo(INVALID_PARAMS.getCode()); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java index 98a71ebf35d..c19bb8fbcbd 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java @@ -137,7 +137,7 @@ public void shouldValidVersionedHash_whenListIsEmpty() { Optional.empty(), Optional.empty()); final EnginePayloadParameter payload = - mockEnginePayload(mockHeader, Collections.emptyList(), null, null, null); + mockEnginePayload(mockHeader, Collections.emptyList(), null, null, null, null); ValidationResult res = method.validateParameters( @@ -193,7 +193,8 @@ public void shouldValidateBlobGasUsedCorrectly() { .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 void shouldValidateExcessBlobGasCorrectly() { .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()); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV4Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV4Test.java index 86b096cf1e8..9ea17213059 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV4Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV4Test.java @@ -109,7 +109,9 @@ public void shouldReturnValidIfDepositRequestsIsNull_WhenDepositRequestsProhibit .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 void shouldReturnInvalidIfDepositRequestsIsNull_WhenDepositRequestsAllowe Collections.emptyList(), null, depositRequests, + null, null)); assertThat(fromErrorResp(resp).getCode()).isEqualTo(INVALID_PARAMS.getCode()); @@ -152,7 +155,7 @@ public void shouldReturnValidIfDepositRequestsIsNotNull_WhenDepositRequestsAllow 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 void shouldReturnInvalidIfDepositRequestsIsNotNull_WhenDepositRequestsPro Collections.emptyList(), null, depositRequests, + null, null)); final JsonRpcError jsonRpcError = fromErrorResp(resp); @@ -195,7 +199,7 @@ public void shouldReturnValidIfWithdrawalRequestsIsNull_WhenWithdrawalRequestsAr 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 void shouldReturnInvalidIfWithdrawalRequestsIsNull_WhenWithdrawalRequests Collections.emptyList(), null, null, + null, null)); assertThat(fromErrorResp(resp).getCode()).isEqualTo(INVALID_PARAMS.getCode()); @@ -239,7 +244,7 @@ public void shouldReturnValidIfWithdrawalRequestsIsNotNull_WhenWithdrawalRequest 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 void shouldReturnValidIfWithdrawalRequestsIsNotNull_WhenWithdrawalRequest Collections.emptyList(), null, null, - withdrawalRequests)); + withdrawalRequests, + null)); final JsonRpcError jsonRpcError = fromErrorResp(resp); assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode()); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ConsolidationRequest.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ConsolidationRequest.java new file mode 100644 index 00000000000..38345d1a31e --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ConsolidationRequest.java @@ -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); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/ConsolidationRequestDecoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/ConsolidationRequestDecoder.java new file mode 100644 index 00000000000..29be31f46de --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/ConsolidationRequestDecoder.java @@ -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)); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/ConsolidationRequestEncoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/ConsolidationRequestEncoder.java new file mode 100644 index 00000000000..9551f7b9740 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/ConsolidationRequestEncoder.java @@ -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)); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/RequestDecoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/RequestDecoder.java index 4953cbb84ff..64191e104b2 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/RequestDecoder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/RequestDecoder.java @@ -41,7 +41,9 @@ interface Decoder { RequestType.WITHDRAWAL, WithdrawalRequestDecoder::decode, RequestType.DEPOSIT, - DepositRequestDecoder::decode); + DepositRequestDecoder::decode, + RequestType.CONSOLIDATION, + ConsolidationRequestDecoder::decode); /** * Decodes a request from its RLP encoded bytes. diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/RequestEncoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/RequestEncoder.java index 4f79da453ca..3c61a77ac03 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/RequestEncoder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/RequestEncoder.java @@ -38,7 +38,9 @@ interface Encoder { RequestType.WITHDRAWAL, WithdrawalRequestEncoder::encode, RequestType.DEPOSIT, - DepositRequestEncoder::encode); + DepositRequestEncoder::encode, + RequestType.CONSOLIDATION, + ConsolidationRequestEncoder::encode); /** * Encodes a Request into the provided RLPOutput. diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/ConsolidationRequestProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/ConsolidationRequestProcessor.java new file mode 100644 index 00000000000..0a48d8278c9 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/ConsolidationRequestProcessor.java @@ -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 { + 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); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/ConsolidationRequestValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/ConsolidationRequestValidator.java new file mode 100644 index 00000000000..f03de5e6b53 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/ConsolidationRequestValidator.java @@ -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> consolidationRequests) { + return consolidationRequests.isPresent(); + } + + private boolean validateConsolidationRequestsInBlock( + final Block block, final List consolidationRequests) { + final Hash blockHash = block.getHash(); + + final List 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 requests, final List receipts) { + var consolidationRequests = + getConsolidationRequests(Optional.of(requests)).orElse(Collections.emptyList()); + return validateConsolidationRequestsInBlock(block, consolidationRequests); + } + + @Override + public boolean validateParameter(final Optional> request) { + if (request.isEmpty()) { + return true; + } + var consolidationRequests = + RequestUtil.filterRequestsOfType(request.get(), ConsolidationRequest.class); + return validateConsolidationRequestParameter(Optional.of(consolidationRequests)); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/MainnetRequestsValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/MainnetRequestsValidator.java index 56e47aea50b..d855544edee 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/MainnetRequestsValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/MainnetRequestsValidator.java @@ -22,6 +22,7 @@ public static RequestsValidatorCoordinator pragueRequestsValidator( 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 static RequestProcessorCoordinator pragueRequestsProcessors( final Address depositContractAddress) { return new RequestProcessorCoordinator.Builder() .addProcessor(RequestType.WITHDRAWAL, new WithdrawalRequestProcessor()) + .addProcessor(RequestType.CONSOLIDATION, new ConsolidationRequestProcessor()) .addProcessor(RequestType.DEPOSIT, new DepositRequestProcessor(depositContractAddress)) .build(); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/RequestUtil.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/RequestUtil.java index 459fdbe110a..f3a10161a49 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/RequestUtil.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/RequestUtil.java @@ -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 static Optional> getWithdrawalRequests( return requests.map(r -> filterRequestsOfType(r, WithdrawalRequest.class)); } + public static Optional> getConsolidationRequests( + final Optional> 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> combine( final Optional> maybeDepositRequests, - final Optional> maybeWithdrawalRequest) { - if (maybeDepositRequests.isEmpty() && maybeWithdrawalRequest.isEmpty()) { + final Optional> maybeWithdrawalRequest, + final Optional> maybeConsolidationRequest) { + if (maybeDepositRequests.isEmpty() + && maybeWithdrawalRequest.isEmpty() + && maybeConsolidationRequest.isEmpty()) { return Optional.empty(); } List requests = new ArrayList<>(); maybeDepositRequests.ifPresent(requests::addAll); maybeWithdrawalRequest.ifPresent(requests::addAll); + maybeConsolidationRequest.ifPresent(requests::addAll); return Optional.of(requests); } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/ConsolidationRequestDecoderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/ConsolidationRequestDecoderTest.java new file mode 100644 index 00000000000..bb264dfa23f --- /dev/null +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/ConsolidationRequestDecoderTest.java @@ -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); + } +} diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/ConsolidationRequestEncoderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/ConsolidationRequestEncoderTest.java new file mode 100644 index 00000000000..10a53379b83 --- /dev/null +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/ConsolidationRequestEncoderTest.java @@ -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))); + } +} diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/DepositRequestRequestDecoderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/DepositRequestDecoderTest.java similarity index 99% rename from ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/DepositRequestRequestDecoderTest.java rename to ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/DepositRequestDecoderTest.java index 0a6cee956d1..622bd897545 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/DepositRequestRequestDecoderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/DepositRequestDecoderTest.java @@ -31,7 +31,7 @@ import org.apache.tuweni.units.bigints.UInt64; import org.junit.jupiter.api.Test; -class DepositRequestRequestDecoderTest { +class DepositRequestDecoderTest { @Test void shouldDecodeDeposit() { final DepositRequest expectedDepositRequest = diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/DepositRequestRequestEncoderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/DepositRequestEncoderTest.java similarity index 98% rename from ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/DepositRequestRequestEncoderTest.java rename to ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/DepositRequestEncoderTest.java index 8f0de595f68..1e6dde6aa87 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/DepositRequestRequestEncoderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/DepositRequestEncoderTest.java @@ -26,7 +26,7 @@ import org.apache.tuweni.units.bigints.UInt64; import org.junit.jupiter.api.Test; -class DepositRequestRequestEncoderTest { +class DepositRequestEncoderTest { private final String expectedDepositEncodedBytes = "f8bbb0b10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416ea00017a7fcf06faf493d30bbe2632ea7c2383cd86825e12797165de7aa35589483850773594000b860a889db8300194050a2636c92a95bc7160515867614b7971a9500cdb62f9c0890217d2901c3241f86fac029428fc106930606154bd9e406d7588934a5f15b837180b17194d6e44bd6de23e43b163dfe12e369dcc75a3852cd997963f158217eb501"; diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ConsolidationRequestValidatorTestFixtures.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ConsolidationRequestValidatorTestFixtures.java new file mode 100644 index 00000000000..fbd304d1cd9 --- /dev/null +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ConsolidationRequestValidatorTestFixtures.java @@ -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> 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> 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 consolidationRequests = + IntStream.range(0, MAX_CONSOLIDATION_REQUESTS_PER_BLOCK + 1) + .mapToObj(__ -> createConsolidationRequest()) + .toList(); + + final Optional> maybeConsolidationRequest = + Optional.of(consolidationRequests); + final Optional> 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> maybeConsolidationRequest; + List expectedConsolidationRequest; + + public ConsolidationRequestTestParameter( + final String description, + final Block block, + final Optional> maybeConsolidationRequest) { + this( + description, + block, + maybeConsolidationRequest, + maybeConsolidationRequest.orElseGet(List::of)); + } + + public ConsolidationRequestTestParameter( + final String description, + final Block block, + final Optional> maybeConsolidationRequest, + final List expectedConsolidationRequest) { + this.description = description; + this.block = block; + this.maybeConsolidationRequest = maybeConsolidationRequest; + this.expectedConsolidationRequest = expectedConsolidationRequest; + } + + @Override + public String toString() { + return description; + } + } +} diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PragueConsolidationRequestValidatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PragueConsolidationRequestValidatorTest.java new file mode 100644 index 00000000000..9d0c9588cc8 --- /dev/null +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PragueConsolidationRequestValidatorTest.java @@ -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> maybeRequests, + final boolean expectedValidity) { + assertThat(new ConsolidationRequestValidator().validateParameter(maybeRequests)) + .isEqualTo(expectedValidity); + } + + private static Stream 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 validateConsolidationRequestsInBlockParamsForPrague() { + return Stream.of( + Arguments.of(blockWithConsolidationRequestsAndWithdrawalRequestsRoot(), true), + Arguments.of(blockWithConsolidationRequestsMismatch(), false), + Arguments.of(blockWithMoreThanMaximumConsolidationRequests(), false)); + } +} diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java index ae64a8a7ef4..cd955fa4a45 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java @@ -32,6 +32,7 @@ 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.SetCodeAuthorization; @@ -562,15 +563,25 @@ static T8nResult runTest( 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); diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-deposit.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-deposit.json index d48fc66c704..1a32e50e8b9 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-deposit.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-deposit.json @@ -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":[] } } } \ No newline at end of file diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-withdrawal.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-withdrawal.json index cc8958b07c5..148c7a23e30 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-withdrawal.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-withdrawal.json @@ -314,6 +314,7 @@ "amount": "0x0000000000000000" } ], + "consolidationRequests":[], "stateRoot": "0xf63d7552dc407993393315e99272781d04eedfcf369a1acd3e386d1e6710229d", "txRoot": "0x8521df63211790726b6f1a437bb0fd4b27c00e13e7678d324c4cfddb8d834ad2", "receiptsRoot": "0x4bd8bd5580caf4ed45f873794ad7ff9d6fd2363ae529269b17b891b68d349d75", diff --git a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTestTools.java b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTestTools.java index 5512923c613..1d9ce8eefaa 100644 --- a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTestTools.java +++ b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/BlockchainReferenceTestTools.java @@ -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\\]"); } diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index d55efa7fc99..30ab85d37ad 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -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') diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/ConsolidationRequest.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/ConsolidationRequest.java new file mode 100644 index 00000000000..5d7e66b4aeb --- /dev/null +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/ConsolidationRequest.java @@ -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(); +}