From b6615dfaed73d8834457c83e0b8f9a20a97515f2 Mon Sep 17 00:00:00 2001 From: Stefan Date: Fri, 4 Aug 2023 10:09:35 +1000 Subject: [PATCH] passing beacon block root hash from RPC calls, implement precompile and storage of root hash when executing a block Signed-off-by: Stefan --- .../besu/tests/acceptance/dsl/BlockUtils.java | 2 +- .../besu/services/BesuEventsImplTest.java | 2 +- .../blockcreation/MergeBlockCreator.java | 19 ++-- .../merge/blockcreation/MergeCoordinator.java | 26 ++--- .../blockcreation/MergeMiningCoordinator.java | 21 ++-- .../blockcreation/TransitionCoordinator.java | 12 +-- .../blockcreation/MergeCoordinatorTest.java | 28 +++--- .../hyperledger/besu/datatypes/Address.java | 24 ++--- .../api/jsonrpc/JsonRpcResponseUtils.java | 2 +- .../AbstractEngineForkchoiceUpdated.java | 4 +- .../engine/AbstractEngineNewPayload.java | 3 + .../engine/EnginePreparePayloadDebug.java | 4 +- .../EnginePayloadAttributesParameter.java | 18 +++- .../parameters/EnginePayloadParameter.java | 2 +- .../EnginePreparePayloadParameter.java | 9 +- .../results/EngineGetPayloadResultV3.java | 11 ++- .../internal/methods/EthGasPriceTest.java | 4 +- .../AbstractEngineForkchoiceUpdatedTest.java | 26 ++--- ...neExchangeTransitionConfigurationTest.java | 2 +- .../EnginePayloadAttributesParameterTest.java | 4 +- .../query/BlockchainQueriesLogCacheTest.java | 2 +- .../cache/TransactionLogBloomCacherTest.java | 4 +- .../blockcreation/AbstractBlockCreator.java | 26 ++--- .../AbstractBlockCreatorTest.java | 16 ++-- .../besu/ethereum/core/BlockHeader.java | 96 +++++-------------- .../ethereum/core/BlockHeaderBuilder.java | 19 +++- .../ethereum/core/ProcessableBlockHeader.java | 27 ++++-- .../ethereum/core/SealableBlockHeader.java | 42 ++++---- .../mainnet/AbstractBlockProcessor.java | 12 +++ .../besu/ethereum/bonsai/LogRollingTests.java | 4 +- .../eth/messages/MessageWrapperTest.java | 2 +- .../backwardsync/ChainForTestCreator.java | 6 +- .../BlockchainReferenceTestCaseSpec.java | 2 +- .../referencetests/ReferenceTestEnv.java | 2 +- ...entBeaconBlockRootPrecompiledContract.java | 91 ++++++++++++++++++ 35 files changed, 345 insertions(+), 229 deletions(-) create mode 100644 evm/src/main/java/org/hyperledger/besu/evm/precompile/ParentBeaconBlockRootPrecompiledContract.java diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/BlockUtils.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/BlockUtils.java index a24280b0ed3..4d4620c225e 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/BlockUtils.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/BlockUtils.java @@ -56,7 +56,7 @@ public static BlockHeader createBlockHeader( null, null, null, - null, + null, null, blockHeaderFunctions); } } diff --git a/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java index 281cb2b2ea1..1057ae45a9d 100644 --- a/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java +++ b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java @@ -200,7 +200,7 @@ private void setSyncTarget() { mock(EthPeer.class), new org.hyperledger.besu.ethereum.core.BlockHeader( null, null, null, null, null, null, null, null, 1, 1, 1, 1, null, null, null, 1, null, - null, null, null, null)); + null, null, null, null, null)); } private void clearSyncTarget() { diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeBlockCreator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeBlockCreator.java index 792544f187b..a548cda9eb6 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeBlockCreator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeBlockCreator.java @@ -86,23 +86,26 @@ public MergeBlockCreator( /** * Create block and return block creation result. * - * @param maybeTransactions the maybe transactions - * @param random the random - * @param timestamp the timestamp - * @param withdrawals optional list of withdrawals + * @param maybeTransactions the maybe transactions + * @param random the random + * @param timestamp the timestamp + * @param withdrawals optional list of withdrawals + * @param parentBeaconBlockRoot optional root hash of the parent beacon block * @return the block creation result */ public BlockCreationResult createBlock( - final Optional> maybeTransactions, - final Bytes32 random, - final long timestamp, - final Optional> withdrawals) { + final Optional> maybeTransactions, + final Bytes32 random, + final long timestamp, + final Optional> withdrawals, + final Optional parentBeaconBlockRoot) { return createBlock( maybeTransactions, Optional.of(Collections.emptyList()), withdrawals, Optional.of(random), + parentBeaconBlockRoot, timestamp, false); } diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java index 47d6970007a..b153b04ea7d 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java @@ -242,11 +242,11 @@ public void changeTargetGasLimit(final Long newTargetGasLimit) { @Override public PayloadIdentifier preparePayload( - final BlockHeader parentHeader, - final Long timestamp, - final Bytes32 prevRandao, - final Address feeRecipient, - final Optional> withdrawals) { + final BlockHeader parentHeader, + final Long timestamp, + final Bytes32 prevRandao, + final Address feeRecipient, + final Optional> withdrawals, final Optional parentBeaconBlockRoot) { // we assume that preparePayload is always called sequentially, since the RPC Engine calls // are sequential, if this assumption changes then more synchronization should be added to @@ -273,7 +273,7 @@ public PayloadIdentifier preparePayload( // put the empty block in first final Block emptyBlock = mergeBlockCreator - .createBlock(Optional.of(Collections.emptyList()), prevRandao, timestamp, withdrawals) + .createBlock(Optional.of(Collections.emptyList()), prevRandao, timestamp, withdrawals, parentBeaconBlockRoot) .getBlock(); BlockProcessingResult result = validateProposedBlock(emptyBlock); @@ -294,7 +294,7 @@ public PayloadIdentifier preparePayload( } } - tryToBuildBetterBlock(timestamp, prevRandao, payloadIdentifier, mergeBlockCreator, withdrawals); + tryToBuildBetterBlock(timestamp, prevRandao, payloadIdentifier, mergeBlockCreator, withdrawals, parentBeaconBlockRoot); return payloadIdentifier; } @@ -330,14 +330,14 @@ public void finalizeProposalById(final PayloadIdentifier payloadId) { } private void tryToBuildBetterBlock( - final Long timestamp, - final Bytes32 random, - final PayloadIdentifier payloadIdentifier, - final MergeBlockCreator mergeBlockCreator, - final Optional> withdrawals) { + final Long timestamp, + final Bytes32 random, + final PayloadIdentifier payloadIdentifier, + final MergeBlockCreator mergeBlockCreator, + final Optional> withdrawals, final Optional parentBeaconBlockRoot) { final Supplier blockCreator = - () -> mergeBlockCreator.createBlock(Optional.empty(), random, timestamp, withdrawals); + () -> mergeBlockCreator.createBlock(Optional.empty(), random, timestamp, withdrawals, parentBeaconBlockRoot); LOG.debug( "Block creation started for payload id {}, remaining time is {}ms", diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeMiningCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeMiningCoordinator.java index 303a32752b9..9a5164d3a9f 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeMiningCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeMiningCoordinator.java @@ -36,19 +36,20 @@ public interface MergeMiningCoordinator extends MiningCoordinator { /** * Prepare payload identifier. * - * @param parentHeader the parent header - * @param timestamp the timestamp - * @param prevRandao the prev randao - * @param feeRecipient the fee recipient - * @param withdrawals the optional list of withdrawals + * @param parentHeader the parent header + * @param timestamp the timestamp + * @param prevRandao the prev randao + * @param feeRecipient the fee recipient + * @param withdrawals the optional list of withdrawals + * @param parentBeaconBlockRoot optional root hash of the parent beacon block * @return the payload identifier */ PayloadIdentifier preparePayload( - final BlockHeader parentHeader, - final Long timestamp, - final Bytes32 prevRandao, - final Address feeRecipient, - final Optional> withdrawals); + final BlockHeader parentHeader, + final Long timestamp, + final Bytes32 prevRandao, + final Address feeRecipient, + final Optional> withdrawals, final Optional parentBeaconBlockRoot); @Override default boolean isCompatibleWithEngineApi() { diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java index fe5bdfbe9ac..c37ae14c9b1 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java @@ -143,13 +143,13 @@ public void changeTargetGasLimit(final Long targetGasLimit) { @Override public PayloadIdentifier preparePayload( - final BlockHeader parentHeader, - final Long timestamp, - final Bytes32 prevRandao, - final Address feeRecipient, - final Optional> withdrawals) { + final BlockHeader parentHeader, + final Long timestamp, + final Bytes32 prevRandao, + final Address feeRecipient, + final Optional> withdrawals, final Optional parentBeaconBlockRoot) { return mergeCoordinator.preparePayload( - parentHeader, timestamp, prevRandao, feeRecipient, withdrawals); + parentHeader, timestamp, prevRandao, feeRecipient, withdrawals, parentBeaconBlockRoot); } @Override diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java index 12e236d37f1..d39c7dded8b 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java @@ -256,7 +256,7 @@ public void coinbaseShouldMatchSuggestedFeeRecipient() { System.currentTimeMillis() / 1000, Bytes32.ZERO, suggestedFeeRecipient, - EMPTY_WITHDRAWALS); + EMPTY_WITHDRAWALS, Optional.empty()); ArgumentCaptor blockWithReceipts = ArgumentCaptor.forClass(BlockWithReceipts.class); @@ -294,7 +294,7 @@ public void exceptionDuringBuildingBlockShouldNotBeInvalid() .doThrow(new MerkleTrieException("missing leaf")) .doCallRealMethod() .when(beingSpiedOn) - .createBlock(any(), any(Bytes32.class), anyLong(), eq(Optional.empty())); + .createBlock(any(), any(Bytes32.class), anyLong(), eq(Optional.empty()), Optional.empty()); return beingSpiedOn; }; @@ -330,7 +330,7 @@ public void exceptionDuringBuildingBlockShouldNotBeInvalid() System.currentTimeMillis() / 1000, Bytes32.random(), suggestedFeeRecipient, - Optional.empty()); + Optional.empty(), Optional.empty()); verify(willThrow, never()).addBadBlock(any(), any()); blockCreationTask.get(); @@ -362,7 +362,7 @@ public void shouldNotRecordProposedBadBlockToBadBlockManager() System.currentTimeMillis() / 1000, Bytes32.ZERO, suggestedFeeRecipient, - Optional.empty()); + Optional.empty(), Optional.empty()); verify(badBlockManager, never()).addBadBlock(any(), any()); assertThat(badBlockManager.getBadBlocks().size()).isEqualTo(0); @@ -394,7 +394,7 @@ public void shouldContinueBuildingBlocksUntilFinalizeIsCalled() System.currentTimeMillis() / 1000, Bytes32.ZERO, suggestedFeeRecipient, - Optional.empty()); + Optional.empty(), Optional.empty()); blockCreationTask.get(); @@ -445,7 +445,7 @@ public void blockCreationRepetitionShouldTakeNotLessThanRepetitionMinDuration() System.currentTimeMillis() / 1000, Bytes32.ZERO, suggestedFeeRecipient, - Optional.empty()); + Optional.empty(), Optional.empty()); blockCreationTask.get(); @@ -491,7 +491,7 @@ public void shouldRetryBlockCreationOnRecoverableError() System.currentTimeMillis() / 1000, Bytes32.ZERO, suggestedFeeRecipient, - Optional.empty()); + Optional.empty(), Optional.empty()); blockCreationTask.get(); @@ -525,7 +525,7 @@ public void shouldStopRetryBlockCreationIfTimeExpired() throws InterruptedExcept System.currentTimeMillis() / 1000, Bytes32.ZERO, suggestedFeeRecipient, - Optional.empty()); + Optional.empty(), Optional.empty()); try { blockCreationTask.get(); @@ -567,7 +567,7 @@ public void shouldStopInProgressBlockCreationIfFinalizedIsCalled() System.currentTimeMillis() / 1000, Bytes32.ZERO, suggestedFeeRecipient, - Optional.empty()); + Optional.empty(), Optional.empty()); waitForBlockCreationInProgress.await(); coordinator.finalizeProposalById(payloadId); @@ -613,7 +613,7 @@ public void shouldNotStartAnotherBlockCreationJobIfCalledAgainWithTheSamePayload timestamp, Bytes32.ZERO, suggestedFeeRecipient, - Optional.empty()); + Optional.empty(), Optional.empty()); final CompletableFuture task1 = blockCreationTask; @@ -623,7 +623,7 @@ public void shouldNotStartAnotherBlockCreationJobIfCalledAgainWithTheSamePayload timestamp, Bytes32.ZERO, suggestedFeeRecipient, - Optional.empty()); + Optional.empty(), Optional.empty()); assertThat(payloadId1).isEqualTo(payloadId2); @@ -658,7 +658,7 @@ public void shouldCancelPreviousBlockCreationJobIfCalledAgainWithNewPayloadId() timestamp, Bytes32.ZERO, suggestedFeeRecipient, - Optional.empty()); + Optional.empty(), Optional.empty()); assertThat(coordinator.isBlockCreationCancelled(payloadId1)).isFalse(); @@ -668,7 +668,7 @@ public void shouldCancelPreviousBlockCreationJobIfCalledAgainWithNewPayloadId() timestamp + 1, Bytes32.ZERO, suggestedFeeRecipient, - Optional.empty()); + Optional.empty(), Optional.empty()); assertThat(payloadId1).isNotEqualTo(payloadId2); assertThat(coordinator.isBlockCreationCancelled(payloadId1)).isTrue(); @@ -697,7 +697,7 @@ public void shouldUseExtraDataFromMiningParameters() { 1L, Bytes32.ZERO, suggestedFeeRecipient, - Optional.empty()); + Optional.empty(), Optional.empty()); ArgumentCaptor blockWithReceipts = ArgumentCaptor.forClass(BlockWithReceipts.class); diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Address.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Address.java index 8862d9461e2..457fc0204fb 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Address.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Address.java @@ -52,26 +52,28 @@ public class Address extends DelegatingBytes { public static final Address ALTBN128_PAIRING = Address.precompiled(0x08); /** The constant BLAKE2B_F_COMPRESSION. */ public static final Address BLAKE2B_F_COMPRESSION = Address.precompiled(0x09); + /** The constant KZG_POINT_EVAL aka POINT_EVALUATION_PRECOMPILE_ADDRESS. */ + public static final Address KZG_POINT_EVAL = Address.precompiled(0xA); + /** The constant PARENT_BEACON_BLOCK_ROOT_REGISTRY aka HISTORY_STORAGE_ADDRESS. */ + public static final Address PARENT_BEACON_BLOCK_ROOT_REGISTRY = Address.precompiled(0xB); /** The constant BLS12_G1ADD. */ - public static final Address BLS12_G1ADD = Address.precompiled(0xA); + public static final Address BLS12_G1ADD = Address.precompiled(0xC); /** The constant BLS12_G1MUL. */ - public static final Address BLS12_G1MUL = Address.precompiled(0xB); + public static final Address BLS12_G1MUL = Address.precompiled(0xD); /** The constant BLS12_G1MULTIEXP. */ - public static final Address BLS12_G1MULTIEXP = Address.precompiled(0xC); + public static final Address BLS12_G1MULTIEXP = Address.precompiled(0xE); /** The constant BLS12_G2ADD. */ - public static final Address BLS12_G2ADD = Address.precompiled(0xD); + public static final Address BLS12_G2ADD = Address.precompiled(0xF); /** The constant BLS12_G2MUL. */ - public static final Address BLS12_G2MUL = Address.precompiled(0xE); + public static final Address BLS12_G2MUL = Address.precompiled(0x10); /** The constant BLS12_G2MULTIEXP. */ - public static final Address BLS12_G2MULTIEXP = Address.precompiled(0xF); + public static final Address BLS12_G2MULTIEXP = Address.precompiled(0x11); /** The constant BLS12_PAIRING. */ - public static final Address BLS12_PAIRING = Address.precompiled(0x10); + public static final Address BLS12_PAIRING = Address.precompiled(0x12); /** The constant BLS12_MAP_FP_TO_G1. */ - public static final Address BLS12_MAP_FP_TO_G1 = Address.precompiled(0x11); + public static final Address BLS12_MAP_FP_TO_G1 = Address.precompiled(0x13); /** The constant BLS12_MAP_FP2_TO_G2. */ - public static final Address BLS12_MAP_FP2_TO_G2 = Address.precompiled(0x12); - /** The constant KZG_POINT_EVAL. */ - public static final Address KZG_POINT_EVAL = Address.precompiled(0x14); + public static final Address BLS12_MAP_FP2_TO_G2 = Address.precompiled(0x14); /** The constant ZERO. */ public static final Address ZERO = Address.fromHexString("0x0"); diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseUtils.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseUtils.java index 9c0a7490240..2fe5c08b600 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseUtils.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcResponseUtils.java @@ -129,7 +129,7 @@ public JsonRpcResponse response( withdrawalsRoot, null, // ToDo 4844: set with the value of data_gas_used field null, // ToDo 4844: set with the value of excess_data_gas field - depositsRoot, + null, depositsRoot, blockHeaderFunctions); return new JsonRpcSuccessResponse( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdated.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdated.java index 89002bf4534..7ad98aa9245 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdated.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdated.java @@ -178,7 +178,8 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) payloadAttributes.getTimestamp(), payloadAttributes.getPrevRandao(), payloadAttributes.getSuggestedFeeRecipient(), - withdrawals)); + withdrawals, + Optional.ofNullable(payloadAttributes.getParentBeaconBlockRoot()))); payloadId.ifPresent( pid -> @@ -210,6 +211,7 @@ private boolean isPayloadAttributesValid( && getWithdrawalsValidator( protocolSchedule, headBlockHeader, payloadAttributes.getTimestamp()) .validateWithdrawals(maybeWithdrawals); + // TODO: stefan Add a parentBeaconBlockRoot validator to the protocolSchedule } private JsonRpcResponse handleNonValidForkchoiceUpdate( 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 8215eae8be3..f1ca430c9ee 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 @@ -115,6 +115,8 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) return respondWithInvalid(reqId, blockParam, null, INVALID, "Invalid versionedHash"); } + Optional maybeParentBeaconBlockRootParam = requestContext.getOptionalParameter(2, String.class); + final Optional maybeParentHeader = protocolContext.getBlockchain().getBlockHeader(blockParam.getParentHash()); @@ -202,6 +204,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) blockParam.getExcessDataGas() == null ? null : DataGas.fromHexString(blockParam.getExcessDataGas()), + maybeParentBeaconBlockRootParam.map(Bytes32::fromHexString).orElse(null), maybeDeposits.map(BodyValidation::depositsRoot).orElse(null), headerFunctions); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java index 2e763aa5499..7f18250ec27 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EnginePreparePayloadDebug.java @@ -67,6 +67,7 @@ public JsonRpcResponse syncResponse(final JsonRpcRequestContext requestContext) Optional.empty(), Optional.empty(), Optional.empty(), + Optional.empty(), Optional.empty())); final var requestId = requestContext.getRequest().getId(); @@ -99,6 +100,7 @@ Optional generatePayload(final EnginePreparePayloadParameter param.getTimestamp().orElse(parentHeader.getTimestamp() + 1L), param.getPrevRandao(), param.getFeeRecipient(), - Optional.of(withdrawals))); + Optional.of(withdrawals), + param.getParentBeaconBlockRoot())); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadAttributesParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadAttributesParameter.java index caa0fa5d74b..01239670aad 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadAttributesParameter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadAttributesParameter.java @@ -30,17 +30,20 @@ public class EnginePayloadAttributesParameter { final Bytes32 prevRandao; final Address suggestedFeeRecipient; final List withdrawals; + private final Bytes32 parentBeaconBlockRoot; @JsonCreator public EnginePayloadAttributesParameter( - @JsonProperty("timestamp") final String timestamp, - @JsonProperty("prevRandao") final String prevRandao, - @JsonProperty("suggestedFeeRecipient") final String suggestedFeeRecipient, - @JsonProperty("withdrawals") final List withdrawals) { + @JsonProperty("timestamp") final String timestamp, + @JsonProperty("prevRandao") final String prevRandao, + @JsonProperty("suggestedFeeRecipient") final String suggestedFeeRecipient, + @JsonProperty("withdrawals") final List withdrawals, + @JsonProperty("parentBeaconBlockRoot") final String parentBeaconBlockRoot) { this.timestamp = Long.decode(timestamp); this.prevRandao = Bytes32.fromHexString(prevRandao); this.suggestedFeeRecipient = Address.fromHexString(suggestedFeeRecipient); this.withdrawals = withdrawals; + this.parentBeaconBlockRoot = parentBeaconBlockRoot == null ? null : Bytes32.fromHexString(parentBeaconBlockRoot); } public Long getTimestamp() { @@ -55,6 +58,10 @@ public Address getSuggestedFeeRecipient() { return suggestedFeeRecipient; } + public Bytes32 getParentBeaconBlockRoot() { + return parentBeaconBlockRoot; + } + public List getWithdrawals() { return withdrawals; } @@ -70,6 +77,9 @@ public String serialize() { "withdrawals", withdrawals.stream().map(WithdrawalParameter::asJsonObject).collect(Collectors.toList())); } + if (parentBeaconBlockRoot != null) { + json.put("parentBeaconBlockRoot", parentBeaconBlockRoot.toHexString()); + } return json.encode(); } } 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 a643c4d1dba..308e7e0aa3f 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 @@ -48,7 +48,7 @@ public class EnginePayloadParameter { private final List transactions; private final List withdrawals; private final Long dataGasUsed; - private final String excessDataGas; + private final String excessDataGas; // TODO: should be changed to Long private final List versionedHashes; private final List deposits; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePreparePayloadParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePreparePayloadParameter.java index 698d3888ed4..049ae4608d3 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePreparePayloadParameter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePreparePayloadParameter.java @@ -31,6 +31,7 @@ public class EnginePreparePayloadParameter { private final Bytes32 prevRandao; private final Optional timestamp; final List withdrawals; + private final Optional parentBeaconBlockRoot; @JsonCreator public EnginePreparePayloadParameter( @@ -38,12 +39,14 @@ public EnginePreparePayloadParameter( @JsonProperty("feeRecipient") final Optional
feeRecipient, @JsonProperty("timestamp") final Optional timestamp, @JsonProperty("prevRandao") final Optional prevRandao, - @JsonProperty("withdrawals") final Optional> withdrawals) { + @JsonProperty("withdrawals") final Optional> withdrawals, + @JsonProperty("parentBeaconBlockRoot") final Optional parentBeaconBlockRoot) { this.parentHash = parentHash; this.feeRecipient = feeRecipient.orElse(Address.ZERO); this.timestamp = timestamp.map(UnsignedLongParameter::getValue); this.prevRandao = Bytes32.fromHexStringLenient(prevRandao.orElse("deadbeef")); this.withdrawals = withdrawals.orElse(Collections.emptyList()); + this.parentBeaconBlockRoot = parentBeaconBlockRoot; } public Optional getParentHash() { @@ -65,4 +68,8 @@ public Bytes32 getPrevRandao() { public List getWithdrawals() { return withdrawals; } + + public Optional getParentBeaconBlockRoot() { + return parentBeaconBlockRoot; + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV3.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV3.java index f499e6da868..b52634a3cc5 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV3.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadResultV3.java @@ -74,10 +74,9 @@ public static class PayloadResult { private final String timestamp; private final String extraData; private final String baseFeePerGas; - - private final String excessDataGas; - private final String dataGasUsed; + private final String excessDataGas; + private final String parentBeaconBlockRoot; protected final List transactions; private final List withdrawals; @@ -111,6 +110,7 @@ public PayloadResult( this.dataGasUsed = header.getDataGasUsed().map(Quantity::create).orElse(Quantity.HEX_ZERO); this.excessDataGas = header.getExcessDataGas().map(Quantity::create).orElse(Quantity.HEX_ZERO); + this.parentBeaconBlockRoot = header.getParentBeaconBlockRoot().map(Bytes32::toHexString).orElse(null); } @JsonGetter(value = "blockNumber") @@ -198,5 +198,10 @@ public String getExcessDataGas() { public String getDataGasUseds() { return dataGasUsed; } + + @JsonGetter(value = "parentBeaconBlockRoot") + public String getParentBeaconBlockRoot() { + return parentBeaconBlockRoot; + } } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java index 7c1d753e05a..dee7722d877 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java @@ -164,7 +164,7 @@ private Object createFakeBlock(final Long height) { null, null, null, - null, + null, null, null), new BlockBody( List.of( @@ -205,7 +205,7 @@ private Object createEmptyBlock(final Long height) { null, null, null, - null, + null, null, null), new BlockBody(List.of(), List.of()))); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdatedTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdatedTest.java index b45b221a9bd..6e8da7d59fe 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdatedTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineForkchoiceUpdatedTest.java @@ -243,7 +243,7 @@ public void shouldReturnValidWithoutFinalizedWithPayload() { String.valueOf(System.currentTimeMillis()), Bytes32.fromHexStringLenient("0xDEADBEEF").toHexString(), Address.ECREC.toString(), - null); + null, null); var mockPayloadId = PayloadIdentifier.forPayloadParams( mockHeader.getHash(), @@ -257,7 +257,7 @@ public void shouldReturnValidWithoutFinalizedWithPayload() { payloadParams.getTimestamp(), payloadParams.getPrevRandao(), Address.ECREC, - Optional.empty())) + Optional.empty(), Optional.empty())) .thenReturn(mockPayloadId); var res = @@ -432,7 +432,7 @@ public void shouldIgnoreUpdateToOldHeadAndNotPreparePayload() { String.valueOf(System.currentTimeMillis()), Bytes32.fromHexStringLenient("0xDEADBEEF").toHexString(), Address.ECREC.toString(), - null); + null, null); var resp = (JsonRpcSuccessResponse) @@ -443,7 +443,7 @@ public void shouldIgnoreUpdateToOldHeadAndNotPreparePayload() { var forkchoiceRes = (EngineUpdateForkchoiceResult) resp.getResult(); - verify(mergeCoordinator, never()).preparePayload(any(), any(), any(), any(), any()); + verify(mergeCoordinator, never()).preparePayload(any(), any(), any(), any(), any(), Optional.empty()); assertThat(forkchoiceRes.getPayloadStatus().getStatus()).isEqualTo(VALID); assertThat(forkchoiceRes.getPayloadStatus().getError()).isNull(); @@ -468,7 +468,7 @@ public void shouldReturnInvalidIfPayloadTimestampNotGreaterThanHead() { String.valueOf(timestampNotGreaterThanHead), Bytes32.fromHexStringLenient("0xDEADBEEF").toHexString(), Address.ECREC.toString(), - emptyList()); + emptyList(), null); var resp = resp( @@ -492,7 +492,7 @@ public void shouldReturnInvalidIfWithdrawalsIsNotNull_WhenWithdrawalsProhibited( String.valueOf(System.currentTimeMillis()), Bytes32.fromHexStringLenient("0xDEADBEEF").toHexString(), Address.ECREC.toString(), - emptyList()); + emptyList(), null); var resp = resp( @@ -516,7 +516,7 @@ public void shouldReturnValidIfWithdrawalsIsNull_WhenWithdrawalsProhibited() { String.valueOf(System.currentTimeMillis()), Bytes32.fromHexStringLenient("0xDEADBEEF").toHexString(), Address.ECREC.toString(), - null); + null, null); var mockPayloadId = PayloadIdentifier.forPayloadParams( @@ -531,7 +531,7 @@ public void shouldReturnValidIfWithdrawalsIsNull_WhenWithdrawalsProhibited() { payloadParams.getTimestamp(), payloadParams.getPrevRandao(), Address.ECREC, - Optional.empty())) + Optional.empty(), Optional.empty())) .thenReturn(mockPayloadId); assertSuccessWithPayloadForForkchoiceResult( @@ -557,7 +557,7 @@ public void shouldReturnInvalidIfWithdrawalsIsNull_WhenWithdrawalsAllowed() { String.valueOf(System.currentTimeMillis()), Bytes32.fromHexStringLenient("0xDEADBEEF").toHexString(), Address.ECREC.toString(), - null); + null, null); var resp = resp( @@ -592,7 +592,7 @@ public void shouldReturnValidIfWithdrawalsIsNotNull_WhenWithdrawalsAllowed() { String.valueOf(System.currentTimeMillis()), Bytes32.fromHexStringLenient("0xDEADBEEF").toHexString(), Address.ECREC.toString(), - withdrawalParameters); + withdrawalParameters, null); final Optional> withdrawals = Optional.of( @@ -613,7 +613,7 @@ public void shouldReturnValidIfWithdrawalsIsNotNull_WhenWithdrawalsAllowed() { payloadParams.getTimestamp(), payloadParams.getPrevRandao(), Address.ECREC, - withdrawals)) + withdrawals, Optional.empty())) .thenReturn(mockPayloadId); assertSuccessWithPayloadForForkchoiceResult( @@ -638,7 +638,7 @@ public void shouldReturnValidIfProtocolScheduleIsEmpty() { String.valueOf(System.currentTimeMillis()), Bytes32.fromHexStringLenient("0xDEADBEEF").toHexString(), Address.ECREC.toString(), - null); + null, null); var mockPayloadId = PayloadIdentifier.forPayloadParams( @@ -653,7 +653,7 @@ public void shouldReturnValidIfProtocolScheduleIsEmpty() { payloadParams.getTimestamp(), payloadParams.getPrevRandao(), Address.ECREC, - Optional.empty())) + Optional.empty(), Optional.empty())) .thenReturn(mockPayloadId); assertSuccessWithPayloadForForkchoiceResult( diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java index bc78e4d0564..ce4daf88a79 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineExchangeTransitionConfigurationTest.java @@ -252,7 +252,7 @@ private BlockHeader createBlockHeader(final Hash blockHash, final long blockNumb null, null, null, - null, + null, null, new BlockHeaderFunctions() { @Override public Hash hash(final BlockHeader header) { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadAttributesParameterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadAttributesParameterTest.java index 20386bb4345..a9d90721181 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadAttributesParameterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/EnginePayloadAttributesParameterTest.java @@ -99,12 +99,12 @@ public void serialize_WithdrawalsPresent() { private EnginePayloadAttributesParameter parameterWithdrawalsOmitted() { return new EnginePayloadAttributesParameter( - TIMESTAMP, PREV_RANDAO, SUGGESTED_FEE_RECIPIENT_ADDRESS, null); + TIMESTAMP, PREV_RANDAO, SUGGESTED_FEE_RECIPIENT_ADDRESS, null, null); } private EnginePayloadAttributesParameter parameterWithdrawalsPresent() { final List withdrawals = List.of(WITHDRAWAL_PARAM_1, WITHDRAWAL_PARAM_2); return new EnginePayloadAttributesParameter( - TIMESTAMP, PREV_RANDAO, SUGGESTED_FEE_RECIPIENT_ADDRESS, withdrawals); + TIMESTAMP, PREV_RANDAO, SUGGESTED_FEE_RECIPIENT_ADDRESS, withdrawals, null); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesLogCacheTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesLogCacheTest.java index b0e84b9e3ba..7a607ff1444 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesLogCacheTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesLogCacheTest.java @@ -116,7 +116,7 @@ public void setup() { null, null, null, - null, + null, null, new MainnetBlockHeaderFunctions()); testHash = fakeHeader.getHash(); final BlockBody fakeBody = new BlockBody(Collections.emptyList(), Collections.emptyList()); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/cache/TransactionLogBloomCacherTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/cache/TransactionLogBloomCacherTest.java index b88e68a4f0d..b9a6c672c5e 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/cache/TransactionLogBloomCacherTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/cache/TransactionLogBloomCacherTest.java @@ -108,7 +108,7 @@ public void setup() throws IOException { null, null, null, - null, + null, null, new MainnetBlockHeaderFunctions()); testHash = fakeHeader.getHash(); when(blockchain.getBlockHeader(anyLong())).thenReturn(Optional.of(fakeHeader)); @@ -282,7 +282,7 @@ private BlockHeader createBlock(final long number, final Optional messag null, null, null, - null, + null, null, new MainnetBlockHeaderFunctions()); testHash = fakeHeader.getHash(); when(blockchain.getBlockHeader(number)).thenReturn(Optional.of(fakeHeader)); diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java index dead80c5a46..ea3250f5e65 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java @@ -152,23 +152,24 @@ public BlockCreationResult createBlock( final Optional> maybeOmmers, final long timestamp) { return createBlock( - maybeTransactions, maybeOmmers, Optional.empty(), Optional.empty(), timestamp, true); + maybeTransactions, maybeOmmers, Optional.empty(), Optional.empty(), Optional.empty(), timestamp, true); } protected BlockCreationResult createBlock( - final Optional> maybeTransactions, - final Optional> maybeOmmers, - final Optional> maybeWithdrawals, - final Optional maybePrevRandao, - final long timestamp, - boolean rewardCoinbase) { + final Optional> maybeTransactions, + final Optional> maybeOmmers, + final Optional> maybeWithdrawals, + final Optional maybePrevRandao, + final Optional maybeParentBeaconBlockRoot, + final long timestamp, + boolean rewardCoinbase) { try (final MutableWorldState disposableWorldState = duplicateWorldStateAtParent()) { final ProtocolSpec newProtocolSpec = protocolSchedule.getForNextBlockHeader(parentHeader, timestamp); final ProcessableBlockHeader processableBlockHeader = - createPendingBlockHeader(timestamp, maybePrevRandao, newProtocolSpec); + createPendingBlockHeader(timestamp, maybePrevRandao, maybeParentBeaconBlockRoot, newProtocolSpec); final Address miningBeneficiary = miningBeneficiaryCalculator.getMiningBeneficiary(processableBlockHeader.getNumber()); Wei dataGasPrice = @@ -369,9 +370,10 @@ private List selectOmmers() { } private ProcessableBlockHeader createPendingBlockHeader( - final long timestamp, - final Optional maybePrevRandao, - final ProtocolSpec protocolSpec) { + final long timestamp, + final Optional maybePrevRandao, + final Optional maybeParentBeaconBlockRoot, + final ProtocolSpec protocolSpec) { final long newBlockNumber = parentHeader.getNumber() + 1; long gasLimit = protocolSpec @@ -399,6 +401,7 @@ private ProcessableBlockHeader createPendingBlockHeader( .orElse(null); final Bytes32 prevRandao = maybePrevRandao.orElse(null); + final Bytes32 parentBeaconBlockRoot = maybeParentBeaconBlockRoot.orElse(null); return BlockHeaderBuilder.create() .parentHash(parentHeader.getHash()) .coinbase(coinbase) @@ -408,6 +411,7 @@ private ProcessableBlockHeader createPendingBlockHeader( .timestamp(timestamp) .baseFee(baseFee) .prevRandao(prevRandao) + .parentBeaconBlockRoot(parentBeaconBlockRoot) .buildProcessableBlockHeader(); } diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java index b16cc1e9d6c..e94288dc069 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java @@ -146,7 +146,7 @@ void withAllowedDepositsAndContractAddress_DepositsAreParsed() { Optional.empty(), Optional.of(emptyList()), Optional.empty(), - 1L, + Optional.empty(), 1L, false); List deposits = emptyList(); @@ -165,7 +165,7 @@ void withAllowedDepositsAndNoContractAddress_DepositsAreNotParsed() { Optional.empty(), Optional.of(emptyList()), Optional.empty(), - 1L, + Optional.empty(), 1L, false); assertThat(blockCreationResult.getBlock().getHeader().getDepositsRoot()).isEmpty(); @@ -182,7 +182,7 @@ void withProhibitedDeposits_DepositsAreNotParsed() { Optional.empty(), Optional.of(emptyList()), Optional.empty(), - 1L, + Optional.empty(), 1L, false); assertThat(blockCreationResult.getBlock().getHeader().getDepositsRoot()).isEmpty(); @@ -214,7 +214,7 @@ void withProcessorAndEmptyWithdrawals_NoWithdrawalsAreProcessed() { final AbstractBlockCreator blockCreator = blockCreatorWithWithdrawalsProcessor(); final BlockCreationResult blockCreationResult = blockCreator.createBlock( - Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), 1L, false); + Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), 1L, false); verify(withdrawalsProcessor, never()).processWithdrawals(any(), any()); assertThat(blockCreationResult.getBlock().getHeader().getWithdrawalsRoot()).isEmpty(); assertThat(blockCreationResult.getBlock().getBody().getWithdrawals()).isEmpty(); @@ -225,7 +225,7 @@ void withNoProcessorAndEmptyWithdrawals_NoWithdrawalsAreNotProcessed() { final AbstractBlockCreator blockCreator = blockCreatorWithoutWithdrawalsProcessor(); final BlockCreationResult blockCreationResult = blockCreator.createBlock( - Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), 1L, false); + Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), 1L, false); verify(withdrawalsProcessor, never()).processWithdrawals(any(), any()); assertThat(blockCreationResult.getBlock().getHeader().getWithdrawalsRoot()).isEmpty(); assertThat(blockCreationResult.getBlock().getBody().getWithdrawals()).isEmpty(); @@ -242,7 +242,7 @@ void withProcessorAndWithdrawals_WithdrawalsAreProcessed() { Optional.empty(), Optional.of(withdrawals), Optional.empty(), - 1L, + Optional.empty(), 1L, false); final Hash withdrawalsRoot = BodyValidation.withdrawalsRoot(withdrawals); @@ -263,7 +263,7 @@ void withNoProcessorAndWithdrawals_WithdrawalsAreNotProcessed() { Optional.empty(), Optional.of(withdrawals), Optional.empty(), - 1L, + Optional.empty(), 1L, false); verify(withdrawalsProcessor, never()).processWithdrawals(any(), any()); assertThat(blockCreationResult.getBlock().getHeader().getWithdrawalsRoot()).isEmpty(); @@ -295,7 +295,7 @@ public void computesGasUsageFromIncludedTransactions() { Optional.empty(), Optional.empty(), Optional.empty(), - 1L, + Optional.empty(), 1L, false); long dataGasUsage = blockCreationResult.getBlock().getHeader().getGasUsed(); assertThat(dataGasUsage).isNotZero(); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java index eb2e906af70..50cb01f5fa1 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java @@ -45,28 +45,27 @@ public class BlockHeader extends SealableBlockHeader private final Supplier parsedExtraData; public BlockHeader( - final Hash parentHash, - final Hash ommersHash, - final Address coinbase, - final Hash stateRoot, - final Hash transactionsRoot, - final Hash receiptsRoot, - final LogsBloomFilter logsBloom, - final Difficulty difficulty, - final long number, - final long gasLimit, - final long gasUsed, - final long timestamp, - final Bytes extraData, - final Wei baseFee, - final Bytes32 mixHashOrPrevRandao, - final long nonce, - final Hash withdrawalsRoot, - final long dataGasUsed, - final DataGas excessDataGas, - final Hash depositsRoot, - final BlockHeaderFunctions blockHeaderFunctions, - final Optional privateLogsBloom) { + final Hash parentHash, + final Hash ommersHash, + final Address coinbase, + final Hash stateRoot, + final Hash transactionsRoot, + final Hash receiptsRoot, + final LogsBloomFilter logsBloom, + final Difficulty difficulty, + final long number, + final long gasLimit, + final long gasUsed, + final long timestamp, + final Bytes extraData, + final Wei baseFee, + final Bytes32 mixHashOrPrevRandao, + final long nonce, + final Hash withdrawalsRoot, + final Long dataGasUsed, + final DataGas excessDataGas, + final Bytes32 parentBeaconBlockRoot, final Hash depositsRoot, + final BlockHeaderFunctions blockHeaderFunctions) { super( parentHash, ommersHash, @@ -86,54 +85,7 @@ public BlockHeader( withdrawalsRoot, dataGasUsed, excessDataGas, - depositsRoot); - this.nonce = nonce; - this.hash = Suppliers.memoize(() -> blockHeaderFunctions.hash(this)); - this.parsedExtraData = Suppliers.memoize(() -> blockHeaderFunctions.parseExtraData(this)); - } - - public BlockHeader( - final Hash parentHash, - final Hash ommersHash, - final Address coinbase, - final Hash stateRoot, - final Hash transactionsRoot, - final Hash receiptsRoot, - final LogsBloomFilter logsBloom, - final Difficulty difficulty, - final long number, - final long gasLimit, - final long gasUsed, - final long timestamp, - final Bytes extraData, - final Wei baseFee, - final Bytes32 mixHashOrPrevRandao, - final long nonce, - final Hash withdrawalsRoot, - final Long dataGasUsed, - final DataGas excessDataGas, - final Hash depositsRoot, - final BlockHeaderFunctions blockHeaderFunctions) { - super( - parentHash, - ommersHash, - coinbase, - stateRoot, - transactionsRoot, - receiptsRoot, - logsBloom, - difficulty, - number, - gasLimit, - gasUsed, - timestamp, - extraData, - baseFee, - mixHashOrPrevRandao, - withdrawalsRoot, - dataGasUsed, - excessDataGas, - depositsRoot); + parentBeaconBlockRoot, depositsRoot); this.nonce = nonce; this.hash = Suppliers.memoize(() -> blockHeaderFunctions.hash(this)); this.parsedExtraData = Suppliers.memoize(() -> blockHeaderFunctions.parseExtraData(this)); @@ -275,7 +227,7 @@ public static BlockHeader readFrom( withdrawalHashRoot, dataGasUsed, excessDataGas, - depositHashRoot, + null, depositHashRoot, blockHeaderFunctions); } @@ -358,7 +310,7 @@ public static org.hyperledger.besu.ethereum.core.BlockHeader convertPluginBlockH .orElse(null), pluginBlockHeader.getDataGasUsed().map(Long::longValue).orElse(null), pluginBlockHeader.getExcessDataGas().map(DataGas::fromQuantity).orElse(null), - pluginBlockHeader + null, pluginBlockHeader .getDepositsRoot() .map(h -> Hash.fromHexString(h.toHexString())) .orElse(null), diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java index 41536ca964e..52a2d258fd8 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java @@ -75,6 +75,7 @@ public class BlockHeaderBuilder { private Long dataGasUsed = null; private DataGas excessDataGas = null; + private Bytes32 parentBeaconBlockRoot = null; public static BlockHeaderBuilder create() { return new BlockHeaderBuilder(); @@ -122,9 +123,12 @@ public static BlockHeaderBuilder fromHeader(final BlockHeader header) { .withdrawalsRoot(header.getWithdrawalsRoot().orElse(null)) .dataGasUsed(header.getDataGasUsed().orElse(null)) .excessDataGas(header.getExcessDataGas().orElse(null)) + .parentBeaconBlockRoot(header.getParentBeaconBlockRoot().orElse(null)) .depositsRoot(header.getDepositsRoot().orElse(null)); } + + public static BlockHeaderBuilder fromBuilder(final BlockHeaderBuilder fromBuilder) { final BlockHeaderBuilder toBuilder = create() @@ -145,6 +149,7 @@ public static BlockHeaderBuilder fromBuilder(final BlockHeaderBuilder fromBuilde .prevRandao(fromBuilder.mixHashOrPrevRandao) .withdrawalsRoot(fromBuilder.withdrawalsRoot) .excessDataGas(fromBuilder.excessDataGas) + .parentBeaconBlockRoot(fromBuilder.parentBeaconBlockRoot) .depositsRoot(fromBuilder.depositsRoot) .blockHeaderFunctions(fromBuilder.blockHeaderFunctions); toBuilder.nonce = fromBuilder.nonce; @@ -174,7 +179,7 @@ public BlockHeader buildBlockHeader() { withdrawalsRoot, dataGasUsed, excessDataGas, - depositsRoot, + null, depositsRoot, blockHeaderFunctions); } @@ -191,7 +196,7 @@ public ProcessableBlockHeader buildProcessableBlockHeader() { baseFee, mixHashOrPrevRandao, dataGasUsed, - excessDataGas); + excessDataGas, parentBeaconBlockRoot); } public SealableBlockHeader buildSealableBlockHeader() { @@ -216,7 +221,8 @@ public SealableBlockHeader buildSealableBlockHeader() { withdrawalsRoot, dataGasUsed, excessDataGas, - depositsRoot); + parentBeaconBlockRoot, + depositsRoot); } private void validateBlockHeader() { @@ -258,6 +264,7 @@ public BlockHeaderBuilder populateFrom(final ProcessableBlockHeader processableB processableBlockHeader.getPrevRandao().ifPresent(this::prevRandao); processableBlockHeader.getDataGasUsed().ifPresent(this::dataGasUsed); processableBlockHeader.getExcessDataGas().ifPresent(this::excessDataGas); + processableBlockHeader.getParentBeaconBlockRoot().ifPresent(this::parentBeaconBlockRoot); return this; } @@ -281,6 +288,7 @@ public BlockHeaderBuilder populateFrom(final SealableBlockHeader sealableBlockHe withdrawalsRoot(sealableBlockHeader.getWithdrawalsRoot().orElse(null)); sealableBlockHeader.getDataGasUsed().ifPresent(this::dataGasUsed); sealableBlockHeader.getExcessDataGas().ifPresent(this::excessDataGas); + sealableBlockHeader.getParentBeaconBlockRoot().ifPresent(this::parentBeaconBlockRoot); depositsRoot(sealableBlockHeader.getDepositsRoot().orElse(null)); return this; } @@ -411,4 +419,9 @@ public BlockHeaderBuilder dataGasUsed(final Long dataGasUsed) { this.dataGasUsed = dataGasUsed; return this; } + + public BlockHeaderBuilder parentBeaconBlockRoot(final Bytes32 parentBeaconBlockRoot) { + this.parentBeaconBlockRoot = parentBeaconBlockRoot; + return this; + } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ProcessableBlockHeader.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ProcessableBlockHeader.java index 716782c047c..939c49e8698 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ProcessableBlockHeader.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ProcessableBlockHeader.java @@ -48,18 +48,20 @@ public class ProcessableBlockHeader implements BlockValues { protected final Long dataGasUsed; // excessDataGas is included for Cancun protected final DataGas excessDataGas; + private final Bytes32 parentBeaconBlockRoot; protected ProcessableBlockHeader( - final Hash parentHash, - final Address coinbase, - final Difficulty difficulty, - final long number, - final long gasLimit, - final long timestamp, - final Wei baseFee, - final Bytes32 mixHashOrPrevRandao, - final Long dataGasUsed, - final DataGas excessDataGas) { + final Hash parentHash, + final Address coinbase, + final Difficulty difficulty, + final long number, + final long gasLimit, + final long timestamp, + final Wei baseFee, + final Bytes32 mixHashOrPrevRandao, + final Long dataGasUsed, + final DataGas excessDataGas, + final Bytes32 parentBeaconBlockRoot) { this.parentHash = parentHash; this.coinbase = coinbase; this.difficulty = difficulty; @@ -70,6 +72,7 @@ protected ProcessableBlockHeader( this.mixHashOrPrevRandao = mixHashOrPrevRandao; this.dataGasUsed = dataGasUsed; this.excessDataGas = excessDataGas; + this.parentBeaconBlockRoot = parentBeaconBlockRoot; } /** @@ -176,6 +179,10 @@ public Optional getDataGasUsed() { return Optional.ofNullable(dataGasUsed); } + public Optional getParentBeaconBlockRoot() { + return Optional.ofNullable(parentBeaconBlockRoot); + } + public String toLogString() { return getNumber() + " (time: " + getTimestamp() + ")"; } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SealableBlockHeader.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SealableBlockHeader.java index 8b76768eb7e..ac384cd57a0 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SealableBlockHeader.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SealableBlockHeader.java @@ -46,25 +46,26 @@ public class SealableBlockHeader extends ProcessableBlockHeader { protected final Hash depositsRoot; protected SealableBlockHeader( - final Hash parentHash, - final Hash ommersHash, - final Address coinbase, - final Hash stateRoot, - final Hash transactionsRoot, - final Hash receiptsRoot, - final LogsBloomFilter logsBloom, - final Difficulty difficulty, - final long number, - final long gasLimit, - final long gasUsed, - final long timestamp, - final Bytes extraData, - final Wei baseFee, - final Bytes32 mixHashOrPrevRandao, - final Hash withdrawalsRoot, - final Long dataGasUsed, - final DataGas excessDataGas, - final Hash depositsRoot) { + final Hash parentHash, + final Hash ommersHash, + final Address coinbase, + final Hash stateRoot, + final Hash transactionsRoot, + final Hash receiptsRoot, + final LogsBloomFilter logsBloom, + final Difficulty difficulty, + final long number, + final long gasLimit, + final long gasUsed, + final long timestamp, + final Bytes extraData, + final Wei baseFee, + final Bytes32 mixHashOrPrevRandao, + final Hash withdrawalsRoot, + final Long dataGasUsed, + final DataGas excessDataGas, + final Bytes32 parentBeaconBlockRoot, + final Hash depositsRoot) { super( parentHash, coinbase, @@ -75,7 +76,8 @@ protected SealableBlockHeader( baseFee, mixHashOrPrevRandao, dataGasUsed, - excessDataGas); + excessDataGas, + parentBeaconBlockRoot); this.ommersHash = ommersHash; this.stateRoot = stateRoot; this.transactionsRoot = transactionsRoot; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java index 15aca473829..67b28f5d1d0 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java @@ -35,6 +35,8 @@ import org.hyperledger.besu.ethereum.trie.MerkleTrieException; import org.hyperledger.besu.ethereum.vm.BlockHashLookup; import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup; +import org.hyperledger.besu.evm.account.EvmAccount; +import org.hyperledger.besu.evm.precompile.ParentBeaconBlockRootPrecompiledContract; import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.evm.worldstate.WorldUpdater; @@ -104,12 +106,22 @@ public BlockProcessingResult processBlock( final ProtocolSpec protocolSpec = protocolSchedule.getByBlockHeader(blockHeader); + if (blockHeader.getParentBeaconBlockRoot().isPresent()) { + //TODO: Have we checked that we are cancun????? + // TODO: if we have to set the nonce for the contract to one this can happen here as well + final WorldUpdater updater = worldState.updater(); + ParentBeaconBlockRootPrecompiledContract.storeParentBeaconBlockRoot(updater, blockHeader.getTimestamp(), blockHeader.getParentBeaconBlockRoot().get()); + } + for (final Transaction transaction : transactions) { if (!hasAvailableBlockBudget(blockHeader, transaction, currentGasUsed)) { return new BlockProcessingResult(Optional.empty(), "provided gas insufficient"); } final WorldUpdater worldStateUpdater = worldState.updater(); + + + final BlockHashLookup blockHashLookup = new CachingBlockHashLookup(blockHeader, blockchain); final Address miningBeneficiary = miningBeneficiaryCalculator.calculateBeneficiary(blockHeader); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/LogRollingTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/LogRollingTests.java index e3f0ffaa74c..f50d6807abb 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/LogRollingTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/LogRollingTests.java @@ -97,7 +97,7 @@ public class LogRollingTests { null, null, // dataGasUSed null, - null, + null, null, new MainnetBlockHeaderFunctions()); private static final BlockHeader headerTwo = new BlockHeader( @@ -120,7 +120,7 @@ public class LogRollingTests { null, null, // dataGasUsed null, - null, + null, null, new MainnetBlockHeaderFunctions()); @BeforeEach diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/MessageWrapperTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/MessageWrapperTest.java index 921802b5cc3..8804ddd4364 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/MessageWrapperTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/MessageWrapperTest.java @@ -391,7 +391,7 @@ public TestBlockHeader( null, null, null, - null, + null, null, new MainnetBlockHeaderFunctions()); } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ChainForTestCreator.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ChainForTestCreator.java index 406e5950401..850f849d7f8 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ChainForTestCreator.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ChainForTestCreator.java @@ -59,7 +59,7 @@ public static BlockHeader prepareHeader(final long number, final Optional