From 99260fae96cf9d6248a6a112298e943ac323e8cb Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 16 Jul 2024 23:50:09 +0200 Subject: [PATCH 01/14] Improve blob size transaction selector (#7312) Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 1 + .../txselection/BlockTransactionSelector.java | 2 + .../BlobSizeTransactionSelector.java | 95 +++++++++ .../BlockSizeTransactionSelector.java | 9 +- .../BlobSizeTransactionSelectorTest.java | 188 ++++++++++++++++++ plugin-api/build.gradle | 2 +- .../data/TransactionSelectionResult.java | 12 ++ 7 files changed, 300 insertions(+), 9 deletions(-) create mode 100644 ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlobSizeTransactionSelector.java create mode 100644 ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlobSizeTransactionSelectorTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index bee462006..e0269472a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - `privacy-nonce-always-increments` option enables private transactions to always increment the nonce, even if the transaction is invalid [#6593](https://github.com/hyperledger/besu/pull/6593) - Add `block-test` subcommand to the evmtool which runs blockchain reference tests [#7310](https://github.com/hyperledger/besu/pull/7310) - Implement gnark-crypto for eip-2537 [#7316](https://github.com/hyperledger/besu/pull/7316) +- Improve blob size transaction selector [#7312](https://github.com/hyperledger/besu/pull/7312) ### Bug fixes - Fix `eth_call` deserialization to correctly ignore unknown fields in the transaction object. [#7323](https://github.com/hyperledger/besu/pull/7323) diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java index ab311c3fb..c106b7aff 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java @@ -23,6 +23,7 @@ import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.GasLimitCalculator; import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.AbstractTransactionSelector; import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.BlobPriceTransactionSelector; +import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.BlobSizeTransactionSelector; import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.BlockSizeTransactionSelector; import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.MinPriorityFeePerGasTransactionSelector; import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.PriceTransactionSelector; @@ -146,6 +147,7 @@ public class BlockTransactionSelector { final BlockSelectionContext context) { return List.of( new BlockSizeTransactionSelector(context), + new BlobSizeTransactionSelector(context), new PriceTransactionSelector(context), new BlobPriceTransactionSelector(context), new MinPriorityFeePerGasTransactionSelector(context), diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlobSizeTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlobSizeTransactionSelector.java new file mode 100644 index 000000000..9df006722 --- /dev/null +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlobSizeTransactionSelector.java @@ -0,0 +1,95 @@ +/* + * 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.blockcreation.txselection.selectors; + +import org.hyperledger.besu.ethereum.blockcreation.txselection.BlockSelectionContext; +import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionEvaluationContext; +import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults; +import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; +import org.hyperledger.besu.plugin.data.TransactionSelectionResult; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class extends AbstractTransactionSelector and provides a specific implementation for + * evaluating transactions based on blobs size. It checks if a transaction supports blobs, and if + * so, checks that there is enough remaining data gas in the block to fit the blobs of the tx. + */ +public class BlobSizeTransactionSelector extends AbstractTransactionSelector { + private static final Logger LOG = LoggerFactory.getLogger(BlobSizeTransactionSelector.class); + + public BlobSizeTransactionSelector(final BlockSelectionContext context) { + super(context); + } + + /** + * Evaluates a transaction considering other transactions in the same block. If the tx does not + * support blobs, no check is performed, and SELECTED is returned, otherwise SELECTED is returned + * only if there is enough remaining blob gas to fit the blobs of the tx, otherwise a specific not + * selected result is returned, depending on the fact that the block already contains the max + * number of blobs or not. + * + * @param evaluationContext The current selection session data. + * @param transactionSelectionResults The results of other transaction evaluations in the same + * block. + * @return The result of the transaction selection. + */ + @Override + public TransactionSelectionResult evaluateTransactionPreProcessing( + final TransactionEvaluationContext evaluationContext, + final TransactionSelectionResults transactionSelectionResults) { + + final var tx = evaluationContext.getTransaction(); + if (tx.getType().supportsBlob()) { + + final var remainingBlobGas = + context.gasLimitCalculator().currentBlobGasLimit() + - transactionSelectionResults.getCumulativeBlobGasUsed(); + + if (remainingBlobGas == 0) { + LOG.atTrace() + .setMessage("The block already contains the max number of allowed blobs") + .addArgument(evaluationContext.getPendingTransaction()::toTraceLog) + .log(); + return TransactionSelectionResult.BLOBS_FULL; + } + + final long requestedBlobGas = context.gasCalculator().blobGasCost(tx.getBlobCount()); + + if (requestedBlobGas > remainingBlobGas) { + LOG.atTrace() + .setMessage( + "There is not enough blob gas available to fit the blobs of the transaction {} in the block." + + " Available {} / Requested {}") + .addArgument(evaluationContext.getPendingTransaction()::toTraceLog) + .addArgument(remainingBlobGas) + .addArgument(requestedBlobGas) + .log(); + return TransactionSelectionResult.TX_TOO_LARGE_FOR_REMAINING_BLOB_GAS; + } + } + return TransactionSelectionResult.SELECTED; + } + + @Override + public TransactionSelectionResult evaluateTransactionPostProcessing( + final TransactionEvaluationContext evaluationContext, + final TransactionSelectionResults blockTransactionResults, + final TransactionProcessingResult processingResult) { + // All necessary checks were done in the pre-processing method, so nothing to do here. + return TransactionSelectionResult.SELECTED; + } +} diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlockSizeTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlockSizeTransactionSelector.java index 7f0b13e8b..793f3e938 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlockSizeTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlockSizeTransactionSelector.java @@ -89,15 +89,8 @@ public class BlockSizeTransactionSelector extends AbstractTransactionSelector { private boolean transactionTooLargeForBlock( final Transaction transaction, final TransactionSelectionResults transactionSelectionResults) { - final long blobGasUsed = context.gasCalculator().blobGasCost(transaction.getBlobCount()); - if (blobGasUsed - > context.gasLimitCalculator().currentBlobGasLimit() - - transactionSelectionResults.getCumulativeBlobGasUsed()) { - return true; - } - - return transaction.getGasLimit() + blobGasUsed + return transaction.getGasLimit() > context.processableBlockHeader().getGasLimit() - transactionSelectionResults.getCumulativeGasUsed(); } diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlobSizeTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlobSizeTransactionSelectorTest.java new file mode 100644 index 000000000..f52a5dfb4 --- /dev/null +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlobSizeTransactionSelectorTest.java @@ -0,0 +1,188 @@ +/* + * 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.blockcreation.txselection.selectors; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; +import static org.mockito.Answers.RETURNS_DEEP_STUBS; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.crypto.KeyPair; +import org.hyperledger.besu.crypto.SignatureAlgorithm; +import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Blob; +import org.hyperledger.besu.datatypes.BlobsWithCommitments; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.KZGCommitment; +import org.hyperledger.besu.datatypes.KZGProof; +import org.hyperledger.besu.datatypes.TransactionType; +import org.hyperledger.besu.datatypes.VersionedHash; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.blockcreation.txselection.BlockSelectionContext; +import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionEvaluationContext; +import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.core.TransactionTestFixture; +import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction; +import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; +import org.hyperledger.besu.plugin.data.TransactionSelectionResult; + +import java.util.Optional; +import java.util.stream.IntStream; + +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes48; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class BlobSizeTransactionSelectorTest { + private static final Supplier SIGNATURE_ALGORITHM = + Suppliers.memoize(SignatureAlgorithmFactory::getInstance); + private static final KeyPair KEYS = SIGNATURE_ALGORITHM.get().generateKeyPair(); + + private static final long BLOB_GAS_PER_BLOB = CancunGasCalculator.BLOB_GAS_PER_BLOB; + private static final int MAX_BLOBS = 6; + private static final long MAX_BLOB_GAS = BLOB_GAS_PER_BLOB * MAX_BLOBS; + + @Mock(answer = RETURNS_DEEP_STUBS) + BlockSelectionContext blockSelectionContext; + + @Mock TransactionSelectionResults selectionResults; + + @Test + void notBlobTransactionsAreSelectedWithoutAnyCheck() { + final var selector = new BlobSizeTransactionSelector(blockSelectionContext); + + final var nonBlobTx = createEIP1559PendingTransaction(); + + final var txEvaluationContext = new TransactionEvaluationContext(nonBlobTx, null, null, null); + + final var result = + selector.evaluateTransactionPreProcessing(txEvaluationContext, selectionResults); + assertThat(result).isEqualTo(TransactionSelectionResult.SELECTED); + verifyNoInteractions(selectionResults); + } + + @Test + void firstBlobTransactionIsSelected() { + when(blockSelectionContext.gasLimitCalculator().currentBlobGasLimit()).thenReturn(MAX_BLOB_GAS); + when(blockSelectionContext.gasCalculator().blobGasCost(anyInt())) + .thenAnswer(iom -> BLOB_GAS_PER_BLOB * iom.getArgument(0, Integer.class)); + + final var selector = new BlobSizeTransactionSelector(blockSelectionContext); + + final var firstBlobTx = createBlobPendingTransaction(MAX_BLOBS); + + final var txEvaluationContext = new TransactionEvaluationContext(firstBlobTx, null, null, null); + + when(selectionResults.getCumulativeBlobGasUsed()).thenReturn(0L); + + final var result = + selector.evaluateTransactionPreProcessing(txEvaluationContext, selectionResults); + assertThat(result).isEqualTo(TransactionSelectionResult.SELECTED); + verify(selectionResults).getCumulativeBlobGasUsed(); + } + + @Test + void returnsBlobsFullWhenMaxNumberOfBlobsAlreadyPresent() { + when(blockSelectionContext.gasLimitCalculator().currentBlobGasLimit()).thenReturn(MAX_BLOB_GAS); + + final var selector = new BlobSizeTransactionSelector(blockSelectionContext); + + final var firstBlobTx = createBlobPendingTransaction(1); + + final var txEvaluationContext = new TransactionEvaluationContext(firstBlobTx, null, null, null); + + when(selectionResults.getCumulativeBlobGasUsed()).thenReturn(MAX_BLOB_GAS); + + final var result = + selector.evaluateTransactionPreProcessing(txEvaluationContext, selectionResults); + assertThat(result).isEqualTo(TransactionSelectionResult.BLOBS_FULL); + verify(selectionResults).getCumulativeBlobGasUsed(); + } + + @Test + void returnsTooLargeForRemainingBlobGas() { + when(blockSelectionContext.gasLimitCalculator().currentBlobGasLimit()).thenReturn(MAX_BLOB_GAS); + when(blockSelectionContext.gasCalculator().blobGasCost(anyInt())) + .thenAnswer(iom -> BLOB_GAS_PER_BLOB * iom.getArgument(0, Integer.class)); + + final var selector = new BlobSizeTransactionSelector(blockSelectionContext); + + final var firstBlobTx = createBlobPendingTransaction(MAX_BLOBS); + + final var txEvaluationContext = new TransactionEvaluationContext(firstBlobTx, null, null, null); + + when(selectionResults.getCumulativeBlobGasUsed()).thenReturn(MAX_BLOB_GAS - 1); + + final var result = + selector.evaluateTransactionPreProcessing(txEvaluationContext, selectionResults); + assertThat(result).isEqualTo(TransactionSelectionResult.TX_TOO_LARGE_FOR_REMAINING_BLOB_GAS); + verify(selectionResults).getCumulativeBlobGasUsed(); + } + + private PendingTransaction createEIP1559PendingTransaction() { + return PendingTransaction.newPendingTransaction( + createTransaction(TransactionType.EIP1559, 0), false, false); + } + + private PendingTransaction createBlobPendingTransaction(final int blobCount) { + return PendingTransaction.newPendingTransaction( + createTransaction(TransactionType.BLOB, blobCount), false, false); + } + + private Transaction createTransaction(final TransactionType type, final int blobCount) { + + var tx = + new TransactionTestFixture() + .to(Optional.of(Address.fromHexString("0x634316eA0EE79c701c6F67C53A4C54cBAfd2316d"))) + .nonce(0) + .type(type); + tx.maxFeePerGas(Optional.of(Wei.of(1000))).maxPriorityFeePerGas(Optional.of(Wei.of(100))); + if (type.supportsBlob()) { + if (blobCount > 0) { + tx.maxFeePerBlobGas(Optional.of(Wei.of(10))); + final var versionHashes = + IntStream.range(0, blobCount) + .mapToObj(i -> new VersionedHash((byte) 1, Hash.ZERO)) + .toList(); + final var kgzCommitments = + IntStream.range(0, blobCount) + .mapToObj(i -> new KZGCommitment(Bytes48.random())) + .toList(); + final var kzgProofs = + IntStream.range(0, blobCount).mapToObj(i -> new KZGProof(Bytes48.random())).toList(); + final var blobs = + IntStream.range(0, blobCount).mapToObj(i -> new Blob(Bytes.random(32 * 4096))).toList(); + tx.versionedHashes(Optional.of(versionHashes)); + final var blobsWithCommitments = + new BlobsWithCommitments(kgzCommitments, blobs, kzgProofs, versionHashes); + tx.blobsWithCommitments(Optional.of(blobsWithCommitments)); + } else { + fail("At least 1 blob is required for blob tx type"); + } + } + return tx.createTransaction(KEYS); + } +} diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index dff6cc909..1ea78e7f3 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 = 'MOOKIka8Q1D64m0lU29Leq+zf1vcgeLoDVukBVQXhnY=' + knownHash = 'vWxI4pduLCvzqU73k5kJsoeK9t7QTqOBC9IxksFuzBs=' } check.dependsOn('checkAPIChanges') diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/TransactionSelectionResult.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/TransactionSelectionResult.java index 839c4120d..b59fb2696 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/TransactionSelectionResult.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/TransactionSelectionResult.java @@ -53,6 +53,7 @@ public class TransactionSelectionResult { private enum BaseStatus implements Status { SELECTED, BLOCK_FULL(true, false), + BLOBS_FULL(false, false), BLOCK_OCCUPANCY_ABOVE_THRESHOLD(true, false), BLOCK_SELECTION_TIMEOUT(true, false), TX_EVALUATION_TOO_LONG(true, true), @@ -96,6 +97,10 @@ public class TransactionSelectionResult { public static final TransactionSelectionResult BLOCK_FULL = new TransactionSelectionResult(BaseStatus.BLOCK_FULL); + /** The block already contains the max number of allowed blobs. */ + public static final TransactionSelectionResult BLOBS_FULL = + new TransactionSelectionResult(BaseStatus.BLOBS_FULL); + /** There was no more time to add transaction to the block */ public static final TransactionSelectionResult BLOCK_SELECTION_TIMEOUT = new TransactionSelectionResult(BaseStatus.BLOCK_SELECTION_TIMEOUT); @@ -118,6 +123,13 @@ public class TransactionSelectionResult { public static final TransactionSelectionResult TX_TOO_LARGE_FOR_REMAINING_GAS = TransactionSelectionResult.invalidTransient("TX_TOO_LARGE_FOR_REMAINING_GAS"); + /** + * The transaction has not been selected since there is not enough remaining blob gas in the block + * to fit the blobs of the tx, but selection should continue. + */ + public static final TransactionSelectionResult TX_TOO_LARGE_FOR_REMAINING_BLOB_GAS = + TransactionSelectionResult.invalidTransient("TX_TOO_LARGE_FOR_REMAINING_BLOB_GAS"); + /** * The transaction has not been selected since its current price is below the configured min * price, but the selection should continue. From d03c5b68c9715aaf46c5675df19e559b012db55d Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Wed, 17 Jul 2024 11:06:49 +1000 Subject: [PATCH 02/14] adjust text so it succeeds on macOS (#7328) Signed-off-by: Sally MacFarlane --- .../java/org/hyperledger/besu/tests/acceptance/LoggingTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/LoggingTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/LoggingTest.java index aab428eee..8a231a775 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/LoggingTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/LoggingTest.java @@ -33,6 +33,6 @@ public class LoggingTest extends AcceptanceTestBase { node.verify(net.awaitPeerCount(0)); - assertThat(cluster.getConsoleContents()).contains("| INFO |"); + assertThat(cluster.getConsoleContents()).contains("INFO"); } } From 76a3df704efa1d597976e20a91cb3b532f0f639f Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Wed, 17 Jul 2024 11:52:43 +1000 Subject: [PATCH 03/14] Refactor - replace uses of QbftContext with BftContext (#7333) * refactor to remove QbftContext Signed-off-by: Sally MacFarlane --------- Signed-off-by: Sally MacFarlane --- .../controller/QbftBesuControllerBuilder.java | 3 +- .../qbft/support/TestContextBuilder.java | 3 +- .../test/round/QbftRoundIntegrationTest.java | 4 +- .../besu/consensus/qbft/QbftContext.java | 38 ------------------- ...ockHeaderValidationRulesetFactoryTest.java | 4 +- .../qbft/QbftProtocolScheduleTest.java | 4 +- .../QbftValidatorsValidationRuleTest.java | 10 ++--- .../QbftBlockHeightManagerTest.java | 4 +- .../qbft/statemachine/QbftRoundTest.java | 4 +- .../ProposalPayloadValidatorTest.java | 4 +- .../validation/ProposalValidatorTest.java | 5 +-- .../RoundChangeMessageValidatorTest.java | 5 +-- 12 files changed, 23 insertions(+), 65 deletions(-) delete mode 100644 consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftContext.java diff --git a/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java index 4a5f592e2..795136ded 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java @@ -44,7 +44,6 @@ import org.hyperledger.besu.consensus.common.bft.statemachine.BftFinalState; import org.hyperledger.besu.consensus.common.bft.statemachine.FutureMessageBuffer; import org.hyperledger.besu.consensus.common.validator.ValidatorProvider; import org.hyperledger.besu.consensus.common.validator.blockbased.BlockValidatorProvider; -import org.hyperledger.besu.consensus.qbft.QbftContext; import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec; import org.hyperledger.besu.consensus.qbft.QbftForksSchedulesFactory; import org.hyperledger.besu.consensus.qbft.QbftGossip; @@ -388,7 +387,7 @@ public class QbftBesuControllerBuilder extends BftBesuControllerBuilder { new ForkingValidatorProvider( blockchain, qbftForksSchedule, blockValidatorProvider, transactionValidatorProvider); - return new QbftContext(validatorProvider, epochManager, bftBlockInterface().get()); + return new BftContext(validatorProvider, epochManager, bftBlockInterface().get()); } private BftValidatorOverrides convertBftForks(final List bftForks) { diff --git a/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java b/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java index 48b6daad0..5cf74f945 100644 --- a/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java +++ b/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java @@ -62,7 +62,6 @@ import org.hyperledger.besu.consensus.common.bft.statemachine.FutureMessageBuffe import org.hyperledger.besu.consensus.common.validator.ValidatorProvider; import org.hyperledger.besu.consensus.common.validator.blockbased.BlockValidatorProvider; import org.hyperledger.besu.consensus.qbft.MutableQbftConfigOptions; -import org.hyperledger.besu.consensus.qbft.QbftContext; import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec; import org.hyperledger.besu.consensus.qbft.QbftForksSchedulesFactory; import org.hyperledger.besu.consensus.qbft.QbftGossip; @@ -458,7 +457,7 @@ public class TestContextBuilder { new ProtocolContext( blockChain, worldStateArchive, - new QbftContext(validatorProvider, epochManager, blockInterface), + new BftContext(validatorProvider, epochManager, blockInterface), new BadBlockManager()); final TransactionPoolConfiguration poolConf = diff --git a/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/test/round/QbftRoundIntegrationTest.java b/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/test/round/QbftRoundIntegrationTest.java index 52cdfa1ed..7d5794265 100644 --- a/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/test/round/QbftRoundIntegrationTest.java +++ b/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/test/round/QbftRoundIntegrationTest.java @@ -23,6 +23,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; +import org.hyperledger.besu.consensus.common.bft.BftContext; import org.hyperledger.besu.consensus.common.bft.BftExtraData; import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec; import org.hyperledger.besu.consensus.common.bft.BftProtocolSchedule; @@ -30,7 +31,6 @@ import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier; import org.hyperledger.besu.consensus.common.bft.RoundTimer; import org.hyperledger.besu.consensus.common.bft.blockcreation.BftBlockCreator; import org.hyperledger.besu.consensus.common.bft.inttest.StubValidatorMulticaster; -import org.hyperledger.besu.consensus.qbft.QbftContext; import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec; import org.hyperledger.besu.consensus.qbft.network.QbftMessageTransmitter; import org.hyperledger.besu.consensus.qbft.payload.MessageFactory; @@ -129,7 +129,7 @@ public class QbftRoundIntegrationTest { blockChain, worldStateArchive, setupContextWithBftExtraDataEncoder( - QbftContext.class, emptyList(), qbftExtraDataEncoder), + BftContext.class, emptyList(), qbftExtraDataEncoder), new BadBlockManager()); } diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftContext.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftContext.java deleted file mode 100644 index 68e8b7f1a..000000000 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftContext.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright ConsenSys AG. - * - * 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.consensus.qbft; - -import org.hyperledger.besu.consensus.common.EpochManager; -import org.hyperledger.besu.consensus.common.bft.BftBlockInterface; -import org.hyperledger.besu.consensus.common.bft.BftContext; -import org.hyperledger.besu.consensus.common.validator.ValidatorProvider; - -/** The Qbft context. */ -public class QbftContext extends BftContext { - - /** - * Instantiates a new Qbft context. - * - * @param validatorProvider the validator provider - * @param epochManager the epoch manager - * @param blockInterface the block interface - */ - public QbftContext( - final ValidatorProvider validatorProvider, - final EpochManager epochManager, - final BftBlockInterface blockInterface) { - super(validatorProvider, epochManager, blockInterface); - } -} diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/QbftBlockHeaderValidationRulesetFactoryTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/QbftBlockHeaderValidationRulesetFactoryTest.java index 3a09295a9..4771cf91c 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/QbftBlockHeaderValidationRulesetFactoryTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/QbftBlockHeaderValidationRulesetFactoryTest.java @@ -19,6 +19,7 @@ import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.hyperledger.besu.consensus.common.bft.BftContextBuilder.setupContextWithBftExtraDataEncoder; +import org.hyperledger.besu.consensus.common.bft.BftContext; import org.hyperledger.besu.cryptoservices.NodeKey; import org.hyperledger.besu.cryptoservices.NodeKeyUtils; import org.hyperledger.besu.datatypes.Address; @@ -45,8 +46,7 @@ public class QbftBlockHeaderValidationRulesetFactoryTest { return new ProtocolContext( null, null, - setupContextWithBftExtraDataEncoder( - QbftContext.class, validators, new QbftExtraDataCodec()), + setupContextWithBftExtraDataEncoder(BftContext.class, validators, new QbftExtraDataCodec()), new BadBlockManager()); } diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleTest.java index bdcea4e69..07b3be34b 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleTest.java @@ -26,6 +26,7 @@ import org.hyperledger.besu.config.JsonUtil; import org.hyperledger.besu.config.QbftConfigOptions; import org.hyperledger.besu.consensus.common.ForkSpec; import org.hyperledger.besu.consensus.common.ForksSchedule; +import org.hyperledger.besu.consensus.common.bft.BftContext; import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec; import org.hyperledger.besu.consensus.common.bft.BftProtocolSchedule; import org.hyperledger.besu.cryptoservices.NodeKey; @@ -58,8 +59,7 @@ public class QbftProtocolScheduleTest { return new ProtocolContext( null, null, - setupContextWithBftExtraDataEncoder( - QbftContext.class, validators, new QbftExtraDataCodec()), + setupContextWithBftExtraDataEncoder(BftContext.class, validators, new QbftExtraDataCodec()), new BadBlockManager()); } diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/QbftValidatorsValidationRuleTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/QbftValidatorsValidationRuleTest.java index 3e325142c..28ec8fc3a 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/QbftValidatorsValidationRuleTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/headervalidationrules/QbftValidatorsValidationRuleTest.java @@ -19,9 +19,9 @@ import static org.hyperledger.besu.consensus.common.bft.BftContextBuilder.setupC import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import org.hyperledger.besu.consensus.common.bft.BftContext; import org.hyperledger.besu.consensus.common.bft.BftExtraData; import org.hyperledger.besu.consensus.common.bft.Vote; -import org.hyperledger.besu.consensus.qbft.QbftContext; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.BadBlockManager; @@ -47,7 +47,7 @@ public class QbftValidatorsValidationRuleTest { new ProtocolContext( null, null, - setupContextWithBftExtraData(QbftContext.class, Collections.emptyList(), bftExtraData), + setupContextWithBftExtraData(BftContext.class, Collections.emptyList(), bftExtraData), new BadBlockManager()); when(bftExtraData.getValidators()).thenReturn(Collections.emptyList()); when(bftExtraData.getVote()).thenReturn(Optional.empty()); @@ -66,7 +66,7 @@ public class QbftValidatorsValidationRuleTest { new ProtocolContext( null, null, - setupContextWithBftExtraData(QbftContext.class, validators, bftExtraData), + setupContextWithBftExtraData(BftContext.class, validators, bftExtraData), new BadBlockManager()); when(bftExtraData.getValidators()).thenReturn(validators); assertThat(qbftValidatorsValidationRule.validate(blockHeader, null, context)).isTrue(); @@ -84,7 +84,7 @@ public class QbftValidatorsValidationRuleTest { new ProtocolContext( null, null, - setupContextWithBftExtraData(QbftContext.class, validators, bftExtraData), + setupContextWithBftExtraData(BftContext.class, validators, bftExtraData), new BadBlockManager()); when(bftExtraData.getValidators()).thenReturn(validators); assertThat(qbftValidatorsValidationRule.validate(blockHeader, null, context)).isFalse(); @@ -98,7 +98,7 @@ public class QbftValidatorsValidationRuleTest { new ProtocolContext( null, null, - setupContextWithBftExtraData(QbftContext.class, Collections.emptyList(), bftExtraData), + setupContextWithBftExtraData(BftContext.class, Collections.emptyList(), bftExtraData), new BadBlockManager()); when(bftExtraData.getValidators()).thenReturn(Collections.emptyList()); when(bftExtraData.getVote()).thenReturn(Optional.of(mock(Vote.class))); diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerTest.java index a04798608..0aa1f7843 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerTest.java @@ -32,6 +32,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.hyperledger.besu.config.StubGenesisConfigOptions; +import org.hyperledger.besu.consensus.common.bft.BftContext; import org.hyperledger.besu.consensus.common.bft.BftExtraData; import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec; import org.hyperledger.besu.consensus.common.bft.BftProtocolSchedule; @@ -42,7 +43,6 @@ import org.hyperledger.besu.consensus.common.bft.blockcreation.BftBlockCreator; import org.hyperledger.besu.consensus.common.bft.events.RoundExpiry; import org.hyperledger.besu.consensus.common.bft.network.ValidatorMulticaster; import org.hyperledger.besu.consensus.common.bft.statemachine.BftFinalState; -import org.hyperledger.besu.consensus.qbft.QbftContext; import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec; import org.hyperledger.besu.consensus.qbft.messagedata.RoundChangeMessageData; import org.hyperledger.besu.consensus.qbft.messagewrappers.Commit; @@ -172,7 +172,7 @@ public class QbftBlockHeightManagerTest { blockchain, null, setupContextWithBftExtraDataEncoder( - QbftContext.class, validators, new QbftExtraDataCodec()), + BftContext.class, validators, new QbftExtraDataCodec()), new BadBlockManager()); final ProtocolScheduleBuilder protocolScheduleBuilder = diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftRoundTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftRoundTest.java index 838ec71e0..92e713147 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftRoundTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftRoundTest.java @@ -30,6 +30,7 @@ import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; import org.hyperledger.besu.consensus.common.bft.BftBlockHashing; +import org.hyperledger.besu.consensus.common.bft.BftContext; import org.hyperledger.besu.consensus.common.bft.BftExtraData; import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec; import org.hyperledger.besu.consensus.common.bft.BftProtocolSchedule; @@ -37,7 +38,6 @@ import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier; import org.hyperledger.besu.consensus.common.bft.RoundTimer; import org.hyperledger.besu.consensus.common.bft.blockcreation.BftBlockCreator; import org.hyperledger.besu.consensus.common.bft.payload.SignedData; -import org.hyperledger.besu.consensus.qbft.QbftContext; import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec; import org.hyperledger.besu.consensus.qbft.messagewrappers.RoundChange; import org.hyperledger.besu.consensus.qbft.network.QbftMessageTransmitter; @@ -123,7 +123,7 @@ public class QbftRoundTest { blockChain, worldStateArchive, setupContextWithBftExtraDataEncoder( - QbftContext.class, emptyList(), new QbftExtraDataCodec()), + BftContext.class, emptyList(), new QbftExtraDataCodec()), new BadBlockManager()); when(messageValidator.validateProposal(any())).thenReturn(true); diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validation/ProposalPayloadValidatorTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validation/ProposalPayloadValidatorTest.java index 9c9422e10..09e9455d8 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validation/ProposalPayloadValidatorTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validation/ProposalPayloadValidatorTest.java @@ -21,10 +21,10 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import org.hyperledger.besu.consensus.common.bft.BftContext; import org.hyperledger.besu.consensus.common.bft.ConsensusRoundHelpers; import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier; import org.hyperledger.besu.consensus.common.bft.ProposedBlockHelpers; -import org.hyperledger.besu.consensus.qbft.QbftContext; import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec; import org.hyperledger.besu.consensus.qbft.messagewrappers.Proposal; import org.hyperledger.besu.consensus.qbft.payload.MessageFactory; @@ -74,7 +74,7 @@ public class ProposalPayloadValidatorTest { new ProtocolContext( blockChain, worldStateArchive, - setupContextWithBftExtraDataEncoder(QbftContext.class, emptyList(), bftExtraDataCodec), + setupContextWithBftExtraDataEncoder(BftContext.class, emptyList(), bftExtraDataCodec), new BadBlockManager()); } diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validation/ProposalValidatorTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validation/ProposalValidatorTest.java index c28588a9d..43afff350 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validation/ProposalValidatorTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validation/ProposalValidatorTest.java @@ -24,13 +24,13 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.when; +import org.hyperledger.besu.consensus.common.bft.BftContext; import org.hyperledger.besu.consensus.common.bft.BftHelpers; import org.hyperledger.besu.consensus.common.bft.BftProtocolSchedule; import org.hyperledger.besu.consensus.common.bft.ConsensusRoundHelpers; import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier; import org.hyperledger.besu.consensus.common.bft.ProposedBlockHelpers; import org.hyperledger.besu.consensus.common.bft.payload.SignedData; -import org.hyperledger.besu.consensus.qbft.QbftContext; import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec; import org.hyperledger.besu.consensus.qbft.messagewrappers.Prepare; import org.hyperledger.besu.consensus.qbft.messagewrappers.Proposal; @@ -102,8 +102,7 @@ public class ProposalValidatorTest { new ProtocolContext( blockChain, worldStateArchive, - setupContextWithBftExtraDataEncoder( - QbftContext.class, emptyList(), bftExtraDataEncoder), + setupContextWithBftExtraDataEncoder(BftContext.class, emptyList(), bftExtraDataEncoder), new BadBlockManager()); // typically tests require the blockValidation to be successful diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validation/RoundChangeMessageValidatorTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validation/RoundChangeMessageValidatorTest.java index b11f2dafc..82e8fb5c7 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validation/RoundChangeMessageValidatorTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validation/RoundChangeMessageValidatorTest.java @@ -24,13 +24,13 @@ import static org.mockito.Mockito.any; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.when; +import org.hyperledger.besu.consensus.common.bft.BftContext; import org.hyperledger.besu.consensus.common.bft.BftHelpers; import org.hyperledger.besu.consensus.common.bft.BftProtocolSchedule; import org.hyperledger.besu.consensus.common.bft.ConsensusRoundHelpers; import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier; import org.hyperledger.besu.consensus.common.bft.ProposedBlockHelpers; import org.hyperledger.besu.consensus.common.bft.payload.SignedData; -import org.hyperledger.besu.consensus.qbft.QbftContext; import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec; import org.hyperledger.besu.consensus.qbft.messagewrappers.RoundChange; import org.hyperledger.besu.consensus.qbft.payload.PreparedRoundMetadata; @@ -84,8 +84,7 @@ public class RoundChangeMessageValidatorTest { new ProtocolContext( blockChain, worldStateArchive, - setupContextWithBftExtraDataEncoder( - QbftContext.class, emptyList(), bftExtraDataEncoder), + setupContextWithBftExtraDataEncoder(BftContext.class, emptyList(), bftExtraDataEncoder), new BadBlockManager()); lenient().when(protocolSchedule.getByBlockHeader(any())).thenReturn(protocolSpec); From 895c17d5d2ae140b0d85a6783c9b9f58275b1309 Mon Sep 17 00:00:00 2001 From: daniellehrner Date: Wed, 17 Jul 2024 21:00:48 +0200 Subject: [PATCH 04/14] EIP 7702 (#7237) * EIP 7702 first draft Signed-off-by: Daniel Lehrner * added CHANGELOG.md entry Signed-off-by: Daniel Lehrner * bug fixes, added first tests Signed-off-by: Daniel Lehrner * container verify GitHub workflow (#7239) Container verification step in release process automated with the container verify GitHub workflow. New workflow is triggered at the end of the release workflow which will check the release container images starts successfully. Verification test only checks container starts and reach the Ethereum main loop Signed-off-by: Chaminda Divitotawela Signed-off-by: Daniel Lehrner * Investigate chain halts when syncing (#7162) Fix some reasons for chain download halts when syncing Signed-off-by: stefan.pingel@consensys.net Signed-off-by: Stefan Pingel <16143240+pinges@users.noreply.github.com> Co-authored-by: Sally MacFarlane Signed-off-by: Daniel Lehrner * Check for EOFCreate subcontainer rules (#7232) Check and test for the unused container rule, and only returncontract targets can have truncated data rule. Also test the other subcontainer rules in unit tests. Signed-off-by: Danno Ferrin Signed-off-by: Daniel Lehrner * Remove deprecation message for `--Xp2p-peer-lower-bound` (#7247) Signed-off-by: Gabriel-Trintinalia Signed-off-by: Daniel Lehrner * less invasive code injection approach Signed-off-by: Daniel Lehrner * added missing java doc & fixed test Signed-off-by: Daniel Lehrner * added (currently non-working) acceptance test, some bug fixes in the transaction validation and tx pool logic Signed-off-by: Daniel Lehrner * fix spotless Signed-off-by: Daniel Lehrner * updated acceptance test, still not working, newPayload request seems to be necessary before final fork choice update Signed-off-by: Daniel Lehrner * use correct world state to inject temporary code, inject code in existing accounts as well Signed-off-by: Daniel Lehrner * renamed test service to prague, because the engine versions used are only available in the prague hard fork Signed-off-by: Daniel Lehrner * fixed acceptance test, some bug fixes if authorized account does not yet exist Signed-off-by: Daniel Lehrner * Add build version option to prefix git hash with custom version property (#7222) * Add build version option to prefix git hash with custom version property * Refactor to make appending the git hash a boolean property. Include a commented-out example of how to use the properties in the gradle file Signed-off-by: Matthew Whitehead Signed-off-by: Daniel Lehrner * Handle invalid snap getTrieNode requests with empty paths gracefully (#7221) Signed-off-by: Jason Frame Co-authored-by: Sally MacFarlane Signed-off-by: Daniel Lehrner * fix typos in CHANGELOG (#7226) Signed-off-by: Ties <71668189+TiesD@users.noreply.github.com> Co-authored-by: Matt Nelson <85905982+non-fungible-nelson@users.noreply.github.com> Co-authored-by: Sally MacFarlane Signed-off-by: Daniel Lehrner * feat: Add network option for LUKSO Mainnet (#7223) * Add option for LUKSO network Signed-off-by: Wolmin * Add tests for LUKSO Signed-off-by: Wolmin * Apply spotless Signed-off-by: Wolmin * Add changelog entry Signed-off-by: Wolmin * Fix duplicate func Signed-off-by: Wolmin * Fix changelog Signed-off-by: Wolmin * Add bootnodes to genesis Signed-off-by: Wolmin --------- Signed-off-by: Wolmin Signed-off-by: Wolmin <44748271+Wolmin@users.noreply.github.com> Signed-off-by: Daniel Lehrner * Update Docker base image to Ubuntu 24.04 (#7251) Signed-off-by: Fabio Di Fabio Signed-off-by: Daniel Lehrner * Reconfigure how Protocol Specs are created WRT EVM condiguration (#7245) Make the max code size and max initcode size a part of the EVM configuration. As part of the change we need to move the tasks CodeFactory once handled as a static class and move it into the EVM. This has a nice follow on effect that we don't need to pass in max EOF versions or max code sizes anymore. Signed-off-by: Danno Ferrin Signed-off-by: Daniel Lehrner * Fix the wrong 'Identifier' and 'Synchronizer' usage (#7252) * fix the synchronizer usage Signed-off-by: Leni * fix Identifier usage Signed-off-by: Leni --------- Signed-off-by: Leni Co-authored-by: Sally MacFarlane Signed-off-by: Daniel Lehrner * Fix flaky SECP256R1 test (#7249) Signed-off-by: Daniel Lehrner Co-authored-by: Sally MacFarlane Signed-off-by: Daniel Lehrner * update to work with the new max retries value (#7253) Signed-off-by: Justin Florentine Co-authored-by: Sally MacFarlane Signed-off-by: Daniel Lehrner * Temporary CancunEOF fork for EOF testing. (#7227) Add Genesis ("CancunEOFTime") and reference test ("CancunEOF") support for a temporary Cancun+EOF fork, in anticipation of potential devnets. Signed-off-by: Danno Ferrin Signed-off-by: Daniel Lehrner * fixed bug introduced through merge of main, made acceptance test easier to understand Signed-off-by: Daniel Lehrner * added missing java docs Signed-off-by: Daniel Lehrner * removed unnecessary tag Signed-off-by: Daniel Lehrner * make encodeSingleSetCode public again Signed-off-by: Daniel Lehrner * Snapserver responses to return at least one response (#7190) Signed-off-by: Jason Frame Signed-off-by: Daniel Lehrner * copy setCodeTransactionPayloads as well Signed-off-by: Daniel Lehrner * fixed bug during tests with forrest db Signed-off-by: Daniel Lehrner * Snapserver GetTrieNodes request to handle short hash for storage (#7264) Signed-off-by: Jason Frame Signed-off-by: Daniel Lehrner * javadoc: Adding javadoc for ethstats module (#7269) * javadoc: Adding javadoc for ethstats module --------- Signed-off-by: Usman Saleem Signed-off-by: Daniel Lehrner * Fix javadoc for ethereum:core top level package (#7270) * javadoc - Apply javadoc to ethereum core top level package --------- Signed-off-by: Usman Saleem Signed-off-by: Daniel Lehrner * Disable Flaky tests - permissioning (#7256) * disable some flaky tests Signed-off-by: Sally MacFarlane * correct name for test Signed-off-by: Sally MacFarlane * formatting Signed-off-by: Sally MacFarlane * disable some flaky tests Signed-off-by: Sally MacFarlane --------- Signed-off-by: Sally MacFarlane Co-authored-by: Usman Saleem Signed-off-by: Daniel Lehrner * Add bootnodes to the maintained peer list (#7257) * Add bootnodes to the maintained peer list Signed-off-by: Matthew Whitehead * Update unit tests Signed-off-by: Matthew Whitehead * Add entry in changelog Signed-off-by: Matthew Whitehead * Tweak unit test Signed-off-by: Matthew Whitehead * Refactor to keep common steps the same for both cases Signed-off-by: Matthew Whitehead * Add debug log, call sanitizePeers() only once Signed-off-by: Matthew Whitehead --------- Signed-off-by: Matthew Whitehead Signed-off-by: Daniel Lehrner * Fix javadoc for ethereum api module, graphql package (#7272) * javadoc - Adding missing javadocs ethereum:api graphql package Signed-off-by: Usman Saleem Signed-off-by: Daniel Lehrner * T8n support for isStateTest and empty accounts (#7275) Update t8n executor to support new isStateTest env flag that will disable extra-transactional processing such as block rewards and beacon root. Also, make sure such extra-transactional commits don't create empty accounts. Signed-off-by: Danno Ferrin Co-authored-by: Usman Saleem Signed-off-by: Daniel Lehrner * Promote storage x-trie-log subcommand to trie-log (#7278) Signed-off-by: Simon Dudley Signed-off-by: Daniel Lehrner * Evm tool readme update (#7274) * update paths to binary. update docker build to use java 21 * updated suggested jdk --------- Signed-off-by: Justin Florentine Signed-off-by: Daniel Lehrner * javadoc - Add missing javadoc for evmtool module (#7277) Signed-off-by: Usman Saleem Signed-off-by: Daniel Lehrner * Rename ValidatorPublicKey to ValidatorPubKey (#7280) Adapt to EIP-7002 name change for validator public key in all places. Signed-off-by: Danno Ferrin Signed-off-by: Daniel Lehrner * Add info-level diagnostic logs to aid with resolving stalled BFT chains (#7271) * Add info-level diagnostic logs to aid with resolving stalled BFT chains Signed-off-by: Matthew Whitehead * Add javadoc Signed-off-by: Matthew Whitehead --------- Signed-off-by: Matthew Whitehead Signed-off-by: Matt Whitehead Signed-off-by: Daniel Lehrner * Update EIP-2935 contract (#7281) Use the updated contract and address for EIP-2539. Signed-off-by: Danno Ferrin Signed-off-by: Daniel Lehrner * add evmtool compability, fixing bugs related to sender recovery of 7702 txs and handling authorizations to empty accounts Signed-off-by: Daniel Lehrner * Deeper tracing of self-destructed accounts (#7284) Consider previously self-destructed accounts when creating accounts. Signed-off-by: Danno Ferrin Signed-off-by: Daniel Lehrner * next release version after 24.7.0 (#7285) Signed-off-by: garyschulte Signed-off-by: Daniel Lehrner * Add experimental `--Xsnapsync-bft-enabled` which enables snap sync for BFT chains (#7140) * Create a BFT-specific pivot block handler Signed-off-by: Matthew Whitehead * Change visibility Signed-off-by: Matthew Whitehead * Refactor sync-peer-count internal variable to match name, add experimental flag to enabled snap + BFT Signed-off-by: Matthew Whitehead * Merge with main Signed-off-by: Matthew Whitehead * Fix uppercase Signed-off-by: Matthew Whitehead * Address synchronization issue with trie pruning. Create BFT-specific account range handler. Add pipeline name and logs Signed-off-by: Matthew Whitehead * Remove debug log Signed-off-by: Matthew Whitehead * fixing snapsync for empty state Signed-off-by: Karim Taam * Don't queue up events we can't handle Signed-off-by: Matthew Whitehead * Fix timing window where a validator with an empty data dir sometimes falls back to full sync if peer status isn't received quickly enough Signed-off-by: Matthew Whitehead * Remove BFT-specific account request class. Not needed Signed-off-by: Matthew Whitehead * Refactor some more 'fast' sync variables that are common to all pivot-based sync types Signed-off-by: Matthew Whitehead * In FULL sync mode, disable bonsai-limit-trie-logs-enabled instead of failing to start Signed-off-by: Matthew Whitehead * Add javadoc comments, clarify overriding bonsai-limit-trie-logs-enabled Signed-off-by: Matthew Whitehead * Add BFT pivot block selector tests Signed-off-by: Matthew Whitehead * Fix failure error message Signed-off-by: Matthew Whitehead * Remove the unnamed Pipe constructor and update tests to set a pipe name Signed-off-by: Matthew Whitehead * Revert some info logs back to debug given the feedback on noise in the logs syncing with holesky Signed-off-by: Matthew Whitehead * Refactor fastSyncPivotDistance to syncPivotDistance Signed-off-by: Matthew Whitehead * Incomplete refactoring Signed-off-by: Matthew Whitehead * Update BFT event queueing tests Signed-off-by: Matthew Whitehead * Event queue test fixes Signed-off-by: Matthew Whitehead * Remove automatic setting of bonsai-limit-trie-logs-enabled to false if sync-mode = FULL (moving to another PR) Signed-off-by: Matthew Whitehead --------- Signed-off-by: Matthew Whitehead Signed-off-by: Karim Taam Signed-off-by: Matt Whitehead Co-authored-by: Karim Taam Signed-off-by: Daniel Lehrner * Turn off CicleCI for Besu (#7291) All the CI jobs run in GitHub actions and Circle CI it no longer needed in Besu project Signed-off-by: Chaminda Divitotawela Signed-off-by: Daniel Lehrner * Check for snap server (#6609) * EthPeer add isServingSnap to be able to make sure that we have enough snap servers connected when we are snap syncing Signed-off-by: stefan.pingel@consensys.net Signed-off-by: Sally MacFarlane Co-authored-by: Sally MacFarlane Signed-off-by: Daniel Lehrner * Implement System Calls (#7263) Signed-off-by: Gabriel-Trintinalia Signed-off-by: Daniel Lehrner * wrap WorldUpdater inside a WorldUpdaterService to inject the authorized code whenever needed Signed-off-by: Daniel Lehrner * Update limit trie logs validation message for sync-mode=FULL (#7279) Signed-off-by: Simon Dudley Co-authored-by: Sally MacFarlane Signed-off-by: Daniel Lehrner * Execute requests before block persist (#7295) Signed-off-by: Gabriel-Trintinalia Signed-off-by: Daniel Lehrner * fixed MainnetTransactionProcessor retrieval of correctn `to` account with injected code, fixed code injection Signed-off-by: Daniel Lehrner * only first authorization is accepted, all the following ones are ignored Signed-off-by: Daniel Lehrner * don't cache account with empty code Signed-off-by: Daniel Lehrner * revert wrapping of world updater, as its `updater()` method creates a type of nesting that is not compatible with wrapping it. Instead a service is injected in the world updater to inject the code into the authorized accounts Signed-off-by: Daniel Lehrner * Fixed outdated tech redirect link. (#7297) * fix wiki link Signed-off-by: Snazzy * fix format Signed-off-by: Snazzy * change knownHash Signed-off-by: Snazzy --------- Signed-off-by: Snazzy Signed-off-by: Daniel Lehrner * Increment private nonce even if transaction failed. (#6593) Increment private nonce even if transaction failed Signed-off-by: George Tebrean Signed-off-by: stefan.pingel@consensys.net Co-authored-by: stefan.pingel@consensys.net Co-authored-by: Stefan Pingel <16143240+pinges@users.noreply.github.com> Signed-off-by: Daniel Lehrner * feat: Enhance --profile to load external profiles (#7292) * feat: --profile can load external profiles * fix external profile name method * fix ProfilesCompletionCandidate * test: Add unit tests * changelog: Update changelog * test: Fix TomlConfigurationDefaultProviderTest * test: Fix BesuCommandTest --------- Signed-off-by: Usman Saleem Signed-off-by: Daniel Lehrner * Fix status badge for documentation (#7304) Documentation has been moved to GitHub pages and no longer use readthedocs. Updated the README status badge for docs with correct link Signed-off-by: Chaminda Divitotawela Signed-off-by: Daniel Lehrner * [MINOR] Fixed some typos (#7299) * typos Signed-off-by: Sally MacFarlane --------- Signed-off-by: Sally MacFarlane Signed-off-by: Daniel Lehrner * refactored to share one AuthorizedAccountService between the different instances of the world updater, renamed some classes Signed-off-by: Daniel Lehrner * spotless Signed-off-by: Daniel Lehrner * load code for authorization at the beginning of the transaction Signed-off-by: Daniel Lehrner * ignore authorization if chain id doesn't match Signed-off-by: Daniel Lehrner * cache authority address, evmtool: do not fail if sender address is wrong Signed-off-by: Daniel Lehrner * Add evmtool block-test subcommand (#7293) * Add evmtool block-test subcommand Add an evmtool subcommand that will run non-hive blockchain tests. Signed-off-by: Danno Ferrin Signed-off-by: Daniel Lehrner * Make the retrying snap tasks switching (#7307) * make snap tasks switching Signed-off-by: stefan.pingel@consensys.net Signed-off-by: Daniel Lehrner * 6612: Remove deprecated sync modes and related helper methods (#7309) * 6612: Remove deprecated sync modes and related helper methods Signed-off-by: Matilda-Clerke Signed-off-by: Daniel Lehrner * EOF Reference Test Fixes (#7306) Fix a number of issues found in reference tests and evmone tests. - Be tolerant of more nulls in json - Support ContainerKind in reference tests - re-order EXTCALL oeprands - correct return value for REVERT in EXT*CALL - re-order EOFCREATE code validation Signed-off-by: Danno Ferrin Signed-off-by: Daniel Lehrner * test template refactor, bump besu-native to 0.9.2 (#7315) Signed-off-by: garyschulte Signed-off-by: Daniel Lehrner * Feature/use gnark-crypto for eip-2537 (#7316) * use gnark-crypto for bls precompiles Signed-off-by: garyschulte Signed-off-by: Daniel Lehrner * 6612 update changelog with removed syncmodes (#7320) * 6612: Update changelog with removal of deprecated sync modes Signed-off-by: Matilda Clerke * 6612: Update changelog with removal of deprecated sync modes Signed-off-by: Matilda Clerke * 6612: Update changelog with removal of deprecated sync modes Signed-off-by: Matilda Clerke --------- Signed-off-by: Matilda Clerke Signed-off-by: Daniel Lehrner * Update datacopy (#7319) Check for OOG earlier in DataCopy. Add unit tests to cover operation branches. Signed-off-by: Danno Ferrin Signed-off-by: Daniel Lehrner * disable flaky test (#7308) * disable flaky test Signed-off-by: Sally MacFarlane * disable flaky test Signed-off-by: Sally MacFarlane --------- Signed-off-by: Sally MacFarlane Signed-off-by: Daniel Lehrner * Update unit test (#7317) * Update parameterized unit tests so the enumerate with --dry-run * Update the prague-withdrawal.json unit test to handle current code Signed-off-by: Danno Ferrin Co-authored-by: Sally MacFarlane Signed-off-by: Daniel Lehrner * persist accounts that have storage updates, but no nonce, balance nor code Signed-off-by: Daniel Lehrner * Revert "persist accounts that have storage updates, but no nonce, balance nor code" This reverts commit 9c9121a115ecb09f1c3add1fff4da3b102f8b429. Signed-off-by: Daniel Lehrner * removed PKI backed QBFT (#7310) * removed PKI backed QBFT Signed-off-by: Sally MacFarlane * changelog Signed-off-by: Sally MacFarlane --------- Signed-off-by: Sally MacFarlane Signed-off-by: Daniel Lehrner * 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 * fix: `eth_call` deserialization to correctly ignore unknown fields in the transaction object (#7323) * fix: Use Builder for JsonCallParameter * changelog * add additional unit tests * fix: Update builder to withGas to match the json eth_call --------- Signed-off-by: Usman Saleem Signed-off-by: Daniel Lehrner * Stop transaction selection on TX_EVALUATION_TOO_LONG (#7330) Signed-off-by: Fabio Di Fabio Signed-off-by: Daniel Lehrner * message frame buider will create AuthorizedCodeService by itsef if it isn't set Signed-off-by: Daniel Lehrner * get correct nonce for authorization Signed-off-by: Daniel Lehrner * nonce only returns a vaid nonce, new method nonceList returns all the nonces Signed-off-by: Daniel Lehrner * plugs leaky abstraction Signed-off-by: Justin Florentine * some renaming, acceptance tests checks for exact balance of tx sponsor at the end. Signed-off-by: Daniel Lehrner * inject the 7702 code into DiffBasedWorldStateUpdateAccumulator.createAccount Signed-off-by: Daniel Lehrner * spotless Signed-off-by: Justin Florentine * spotless fix, removed todos Signed-off-by: Daniel Lehrner * make AuthorityProcessor & chain id for it optional Signed-off-by: Daniel Lehrner --------- Signed-off-by: Daniel Lehrner Signed-off-by: Chaminda Divitotawela Signed-off-by: stefan.pingel@consensys.net Signed-off-by: Stefan Pingel <16143240+pinges@users.noreply.github.com> Signed-off-by: Danno Ferrin Signed-off-by: Gabriel-Trintinalia Signed-off-by: Matthew Whitehead Signed-off-by: Jason Frame Signed-off-by: Ties <71668189+TiesD@users.noreply.github.com> Signed-off-by: Wolmin Signed-off-by: Wolmin <44748271+Wolmin@users.noreply.github.com> Signed-off-by: Fabio Di Fabio Signed-off-by: Leni Signed-off-by: Justin Florentine Signed-off-by: Usman Saleem Signed-off-by: Sally MacFarlane Signed-off-by: Simon Dudley Signed-off-by: Matt Whitehead Signed-off-by: garyschulte Signed-off-by: Karim Taam Signed-off-by: Snazzy Signed-off-by: George Tebrean Signed-off-by: Matilda-Clerke Signed-off-by: Matilda Clerke Co-authored-by: Chaminda Divitotawela Co-authored-by: Stefan Pingel <16143240+pinges@users.noreply.github.com> Co-authored-by: Sally MacFarlane Co-authored-by: Danno Ferrin Co-authored-by: Gabriel-Trintinalia Co-authored-by: Matt Whitehead Co-authored-by: Jason Frame Co-authored-by: Ties <71668189+TiesD@users.noreply.github.com> Co-authored-by: Matt Nelson <85905982+non-fungible-nelson@users.noreply.github.com> Co-authored-by: Wolmin <44748271+Wolmin@users.noreply.github.com> Co-authored-by: Fabio Di Fabio Co-authored-by: leniram159 Co-authored-by: Justin Florentine Co-authored-by: Usman Saleem Co-authored-by: Simon Dudley Co-authored-by: garyschulte Co-authored-by: Karim Taam Co-authored-by: gringsam Co-authored-by: George Tebrean <99179176+gtebrean@users.noreply.github.com> Co-authored-by: stefan.pingel@consensys.net Co-authored-by: Matilda-Clerke --- CHANGELOG.md | 1 + .../ethereum/PragueAcceptanceTestHelper.java | 193 +++++++++++++ .../SetCodeTransactionAcceptanceTest.java | 125 +++++++++ .../src/test/resources/dev/dev_prague.json | 112 ++++++++ .../options/TransactionPoolOptionsTest.java | 2 +- .../besu/datatypes/SetCodeAuthorization.java | 82 ++++++ .../besu/datatypes/Transaction.java | 14 + .../besu/datatypes/TransactionType.java | 18 +- .../engine/EngineForkchoiceUpdatedV3.java | 14 +- .../results/EnginePayloadStatusResult.java | 9 +- .../results/TransactionCompleteResult.java | 14 +- .../ethereum/core/SetCodeAuthorization.java | 260 ++++++++++++++++++ .../besu/ethereum/core/Transaction.java | 89 +++++- .../encoding/SetCodeTransactionDecoder.java | 116 ++++++++ .../encoding/SetCodeTransactionEncoder.java | 89 ++++++ .../core/encoding/TransactionDecoder.java | 4 +- .../core/encoding/TransactionEncoder.java | 4 +- .../ethereum/mainnet/AuthorityProcessor.java | 88 ++++++ .../mainnet/MainnetProtocolSpecs.java | 20 +- .../mainnet/MainnetTransactionProcessor.java | 52 +++- .../mainnet/MainnetTransactionValidator.java | 3 +- .../PrivateMutableWorldStateUpdater.java | 20 +- .../DiffBasedWorldStateUpdateAccumulator.java | 6 +- .../ethereum/core/BlockDataGenerator.java | 1 + .../ethereum/core/TransactionTestFixture.java | 2 + .../SetCodeTransactionDecoderTest.java | 120 ++++++++ .../SetCodeTransactionEncoderTest.java | 122 ++++++++ .../MainnetTransactionProcessorTest.java | 4 +- .../eth/transactions/PendingTransaction.java | 5 + .../layered/BaseTransactionPoolTest.java | 2 +- .../eth/transactions/layered/LayersTest.java | 1 + .../hyperledger/besu/evmtool/T8nExecutor.java | 69 ++++- .../evm/account/AuthorizedCodeAccount.java | 100 +++++++ .../account/MutableAuthorizedCodeAccount.java | 138 ++++++++++ .../besu/evm/fluent/SimpleWorld.java | 23 +- .../besu/evm/frame/MessageFrame.java | 39 ++- .../besu/evm/gascalculator/GasCalculator.java | 10 + .../gascalculator/PragueGasCalculator.java | 7 + .../evm/operation/AbstractCallOperation.java | 1 + .../operation/AbstractCreateOperation.java | 1 + .../operation/AbstractExtCallOperation.java | 1 + .../evm/worldstate/AbstractWorldUpdater.java | 22 +- .../evm/worldstate/AuthorizedCodeService.java | 116 ++++++++ .../besu/evm/worldstate/JournaledUpdater.java | 22 +- .../besu/evm/worldstate/WorldUpdater.java | 8 + .../hyperledger/besu/evm/toy/ToyWorld.java | 22 +- 46 files changed, 2108 insertions(+), 63 deletions(-) create mode 100644 acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/ethereum/PragueAcceptanceTestHelper.java create mode 100644 acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/ethereum/SetCodeTransactionAcceptanceTest.java create mode 100644 acceptance-tests/tests/src/test/resources/dev/dev_prague.json create mode 100644 datatypes/src/main/java/org/hyperledger/besu/datatypes/SetCodeAuthorization.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SetCodeAuthorization.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/SetCodeTransactionDecoder.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/SetCodeTransactionEncoder.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AuthorityProcessor.java create mode 100644 ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/SetCodeTransactionDecoderTest.java create mode 100644 ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/SetCodeTransactionEncoderTest.java create mode 100644 evm/src/main/java/org/hyperledger/besu/evm/account/AuthorizedCodeAccount.java create mode 100644 evm/src/main/java/org/hyperledger/besu/evm/account/MutableAuthorizedCodeAccount.java create mode 100644 evm/src/main/java/org/hyperledger/besu/evm/worldstate/AuthorizedCodeService.java diff --git a/CHANGELOG.md b/CHANGELOG.md index e0269472a..a6b28d0a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - Add `block-test` subcommand to the evmtool which runs blockchain reference tests [#7310](https://github.com/hyperledger/besu/pull/7310) - Implement gnark-crypto for eip-2537 [#7316](https://github.com/hyperledger/besu/pull/7316) - Improve blob size transaction selector [#7312](https://github.com/hyperledger/besu/pull/7312) +- Added EIP-7702 [#7237](https://github.com/hyperledger/besu/pull/7237) ### Bug fixes - Fix `eth_call` deserialization to correctly ignore unknown fields in the transaction object. [#7323](https://github.com/hyperledger/besu/pull/7323) diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/ethereum/PragueAcceptanceTestHelper.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/ethereum/PragueAcceptanceTestHelper.java new file mode 100644 index 000000000..fa190f3de --- /dev/null +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/ethereum/PragueAcceptanceTestHelper.java @@ -0,0 +1,193 @@ +/* + * 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.tests.acceptance.ethereum; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode; +import org.hyperledger.besu.tests.acceptance.dsl.transaction.eth.EthTransactions; + +import java.io.IOException; +import java.util.Optional; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import okhttp3.Call; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import org.web3j.protocol.core.methods.response.EthBlock; + +public class PragueAcceptanceTestHelper { + protected static final MediaType MEDIA_TYPE_JSON = + MediaType.parse("application/json; charset=utf-8"); + + private final OkHttpClient httpClient; + private final ObjectMapper mapper; + private final BesuNode besuNode; + private final EthTransactions ethTransactions; + + private long blockTimeStamp = 0; + + PragueAcceptanceTestHelper(final BesuNode besuNode, final EthTransactions ethTransactions) { + this.besuNode = besuNode; + this.ethTransactions = ethTransactions; + httpClient = new OkHttpClient(); + mapper = new ObjectMapper(); + } + + public void buildNewBlock() throws IOException { + final EthBlock.Block block = besuNode.execute(ethTransactions.block()); + + blockTimeStamp += 1; + final Call buildBlockRequest = + createEngineCall(createForkChoiceRequest(block.getHash(), blockTimeStamp)); + + final String payloadId; + try (final Response buildBlockResponse = buildBlockRequest.execute()) { + payloadId = + mapper + .readTree(buildBlockResponse.body().string()) + .get("result") + .get("payloadId") + .asText(); + + assertThat(payloadId).isNotEmpty(); + } + + waitFor(500); + + final Call getPayloadRequest = createEngineCall(createGetPayloadRequest(payloadId)); + + final ObjectNode executionPayload; + final String newBlockHash; + final String parentBeaconBlockRoot; + try (final Response getPayloadResponse = getPayloadRequest.execute()) { + assertThat(getPayloadResponse.code()).isEqualTo(200); + + executionPayload = + (ObjectNode) + mapper + .readTree(getPayloadResponse.body().string()) + .get("result") + .get("executionPayload"); + + newBlockHash = executionPayload.get("blockHash").asText(); + parentBeaconBlockRoot = executionPayload.remove("parentBeaconBlockRoot").asText(); + + assertThat(newBlockHash).isNotEmpty(); + } + + final Call newPayloadRequest = + createEngineCall( + createNewPayloadRequest(executionPayload.toString(), parentBeaconBlockRoot)); + try (final Response newPayloadResponse = newPayloadRequest.execute()) { + assertThat(newPayloadResponse.code()).isEqualTo(200); + } + + final Call moveChainAheadRequest = createEngineCall(createForkChoiceRequest(newBlockHash)); + + try (final Response moveChainAheadResponse = moveChainAheadRequest.execute()) { + assertThat(moveChainAheadResponse.code()).isEqualTo(200); + } + } + + private Call createEngineCall(final String request) { + return httpClient.newCall( + new Request.Builder() + .url(besuNode.engineRpcUrl().get()) + .post(RequestBody.create(request, MEDIA_TYPE_JSON)) + .build()); + } + + private String createForkChoiceRequest(final String blockHash) { + return createForkChoiceRequest(blockHash, null); + } + + private String createForkChoiceRequest(final String parentBlockHash, final Long timeStamp) { + final Optional maybeTimeStamp = Optional.ofNullable(timeStamp); + + String forkChoiceRequest = + "{" + + " \"jsonrpc\": \"2.0\"," + + " \"method\": \"engine_forkchoiceUpdatedV3\"," + + " \"params\": [" + + " {" + + " \"headBlockHash\": \"" + + parentBlockHash + + "\"," + + " \"safeBlockHash\": \"" + + parentBlockHash + + "\"," + + " \"finalizedBlockHash\": \"" + + parentBlockHash + + "\"" + + " }"; + + if (maybeTimeStamp.isPresent()) { + forkChoiceRequest += + " ,{" + + " \"timestamp\": \"" + + Long.toHexString(maybeTimeStamp.get()) + + "\"," + + " \"prevRandao\": \"0x0000000000000000000000000000000000000000000000000000000000000000\"," + + " \"suggestedFeeRecipient\": \"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\"," + + " \"withdrawals\": []," + + " \"parentBeaconBlockRoot\": \"0x0000000000000000000000000000000000000000000000000000000000000000\"" + + " }"; + } + + forkChoiceRequest += " ]," + " \"id\": 67" + "}"; + + return forkChoiceRequest; + } + + private String createGetPayloadRequest(final String payloadId) { + return "{" + + " \"jsonrpc\": \"2.0\"," + + " \"method\": \"engine_getPayloadV4\"," + + " \"params\": [\"" + + payloadId + + "\"]," + + " \"id\": 67" + + "}"; + } + + private String createNewPayloadRequest( + final String executionPayload, final String parentBeaconBlockRoot) { + return "{" + + " \"jsonrpc\": \"2.0\"," + + " \"method\": \"engine_newPayloadV4\"," + + " \"params\": [" + + executionPayload + + ",[]," + + "\"" + + parentBeaconBlockRoot + + "\"" + + "]," + + " \"id\": 67" + + "}"; + } + + private static void waitFor(final long durationMilliSeconds) { + try { + Thread.sleep(durationMilliSeconds); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } +} diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/ethereum/SetCodeTransactionAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/ethereum/SetCodeTransactionAcceptanceTest.java new file mode 100644 index 000000000..f1b2558a9 --- /dev/null +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/ethereum/SetCodeTransactionAcceptanceTest.java @@ -0,0 +1,125 @@ +/* + * 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.tests.acceptance.ethereum; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.hyperledger.besu.crypto.SECP256K1; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.TransactionType; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.SetCodeAuthorization; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase; +import org.hyperledger.besu.tests.acceptance.dsl.account.Account; +import org.hyperledger.besu.tests.acceptance.dsl.blockchain.Amount; +import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.List; +import java.util.Optional; + +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.web3j.protocol.core.methods.response.TransactionReceipt; + +public class SetCodeTransactionAcceptanceTest extends AcceptanceTestBase { + private static final String GENESIS_FILE = "/dev/dev_prague.json"; + private static final SECP256K1 secp256k1 = new SECP256K1(); + + public static final Address SEND_ALL_ETH_CONTRACT_ADDRESS = + Address.fromHexStringStrict("0000000000000000000000000000000000009999"); + + private final Account authorizer = + accounts.createAccount( + Address.fromHexStringStrict("8da48afC965480220a3dB9244771bd3afcB5d895")); + public static final Bytes AUTHORIZER_PRIVATE_KEY = + Bytes.fromHexString("11f2e7b6a734ab03fa682450e0d4681d18a944f8b83c99bf7b9b4de6c0f35ea1"); + + private final Account transactionSponsor = + accounts.createAccount( + Address.fromHexStringStrict("a05b21E5186Ce93d2a226722b85D6e550Ac7D6E3")); + public static final Bytes TRANSACTION_SPONSOR_PRIVATE_KEY = + Bytes.fromHexString("3a4ff6d22d7502ef2452368165422861c01a0f72f851793b372b87888dc3c453"); + + private BesuNode besuNode; + private PragueAcceptanceTestHelper testHelper; + + @BeforeEach + void setUp() throws IOException { + besuNode = besu.createExecutionEngineGenesisNode("besuNode", GENESIS_FILE); + cluster.start(besuNode); + + testHelper = new PragueAcceptanceTestHelper(besuNode, ethTransactions); + } + + /** + * At the beginning of the test both the authorizer and the transaction sponsor have a balance of + * 90000 ETH. The authorizer creates an authorization for a contract that send all its ETH to any + * given address. The transaction sponsor created a 7702 transaction with it and sends all the ETH + * from the authorizer to itself. The authorizer balance should be 0 and the transaction sponsor + * balance should be 180000 ETH minus the transaction costs. + */ + @Test + public void shouldTransferAllEthOfAuthorizerToSponsor() throws IOException { + + // 7702 transaction + final org.hyperledger.besu.datatypes.SetCodeAuthorization authorization = + SetCodeAuthorization.builder() + .chainId(BigInteger.valueOf(20211)) + .address(SEND_ALL_ETH_CONTRACT_ADDRESS) + .signAndBuild( + secp256k1.createKeyPair( + secp256k1.createPrivateKey(AUTHORIZER_PRIVATE_KEY.toUnsignedBigInteger()))); + + final Transaction tx = + Transaction.builder() + .type(TransactionType.SET_CODE) + .chainId(BigInteger.valueOf(20211)) + .nonce(0) + .maxPriorityFeePerGas(Wei.of(1000000000)) + .maxFeePerGas(Wei.fromHexString("0x02540BE400")) + .gasLimit(1000000) + .to(Address.fromHexStringStrict(authorizer.getAddress())) + .value(Wei.ZERO) + .payload(Bytes32.leftPad(Bytes.fromHexString(transactionSponsor.getAddress()))) + .accessList(List.of()) + .setCodeTransactionPayloads(List.of(authorization)) + .signAndBuild( + secp256k1.createKeyPair( + secp256k1.createPrivateKey( + TRANSACTION_SPONSOR_PRIVATE_KEY.toUnsignedBigInteger()))); + + final String txHash = + besuNode.execute(ethTransactions.sendRawTransaction(tx.encoded().toHexString())); + testHelper.buildNewBlock(); + + Optional maybeTransactionReceipt = + besuNode.execute(ethTransactions.getTransactionReceipt(txHash)); + assertThat(maybeTransactionReceipt).isPresent(); + + cluster.verify(authorizer.balanceEquals(0)); + + final String gasPriceWithout0x = + maybeTransactionReceipt.get().getEffectiveGasPrice().substring(2); + final BigInteger txCost = + maybeTransactionReceipt.get().getGasUsed().multiply(new BigInteger(gasPriceWithout0x, 16)); + BigInteger expectedSponsorBalance = new BigInteger("180000000000000000000000").subtract(txCost); + cluster.verify(transactionSponsor.balanceEquals(Amount.wei(expectedSponsorBalance))); + } +} diff --git a/acceptance-tests/tests/src/test/resources/dev/dev_prague.json b/acceptance-tests/tests/src/test/resources/dev/dev_prague.json new file mode 100644 index 000000000..26e59992d --- /dev/null +++ b/acceptance-tests/tests/src/test/resources/dev/dev_prague.json @@ -0,0 +1,112 @@ +{ + "config": { + "chainId":20211, + "homesteadBlock":0, + "eip150Block":0, + "eip155Block":0, + "eip158Block":0, + "byzantiumBlock":0, + "constantinopleBlock":0, + "petersburgBlock":0, + "istanbulBlock":0, + "muirGlacierBlock":0, + "berlinBlock":0, + "londonBlock":0, + "terminalTotalDifficulty":0, + "cancunTime":0, + "pragueTime":0, + "clique": { + "period": 5, + "epoch": 30000 + }, + "depositContractAddress": "0x4242424242424242424242424242424242424242" + }, + "nonce":"0x42", + "timestamp":"0x0", + "extraData":"0x0000000000000000000000000000000000000000000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "gasLimit":"0x1C9C380", + "difficulty":"0x400000000", + "mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase":"0x0000000000000000000000000000000000000000", + "alloc":{ + "a05b21E5186Ce93d2a226722b85D6e550Ac7D6E3": { + "privateKey": "3a4ff6d22d7502ef2452368165422861c01a0f72f851793b372b87888dc3c453", + "balance": "90000000000000000000000" + }, + "8da48afC965480220a3dB9244771bd3afcB5d895": { + "comment": "This account has signed a authorization for contract 0x0000000000000000000000000000000000009999 to send a 7702 transaction", + "privateKey": "11f2e7b6a734ab03fa682450e0d4681d18a944f8b83c99bf7b9b4de6c0f35ea1", + "balance": "90000000000000000000000" + }, + "0x0000000000000000000000000000000000009999": { + "comment": "Contract sends all its Ether to the address provided as a call data.", + "balance": "0", + "code": "5F5F5F5F475F355AF100", + "codeDecompiled": "PUSH0 PUSH0 PUSH0 PUSH0 SELFBALANCE PUSH0 CALLDATALOAD GAS CALL STOP", + "storage": {} + }, + "0xa4664C40AACeBD82A2Db79f0ea36C06Bc6A19Adb": { + "balance": "1000000000000000000000000000" + }, + "0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f": { + "comment": "This is the account used to sign the transaction that creates a validator exit", + "balance": "1000000000000000000000000000" + }, + "0x00A3ca265EBcb825B45F985A16CEFB49958cE017": { + "comment": "This is the runtime bytecode for the Withdrawal Request Smart Contract. It was created from the deployment transaction in EIP-7002 (https://eips.ethereum.org/EIPS/eip-7002#deployment)", + "balance": "0", + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe146090573615156028575f545f5260205ff35b36603814156101215760115f54600182026001905f5b5f82111560595781019083028483029004916001019190603e565b90939004341061012157600154600101600155600354806003026004013381556001015f3581556001016020359055600101600355005b6003546002548082038060101160a4575060105b5f5b81811460dd5780604c02838201600302600401805490600101805490600101549160601b83528260140152906034015260010160a6565b910180921460ed579060025560f8565b90505f6002555f6003555b5f5460015460028282011161010f5750505f610115565b01600290035b5f555f600155604c025ff35b5f5ffd", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000004": "000000000000000000000000a4664C40AACeBD82A2Db79f0ea36C06Bc6A19Adb", + "0x0000000000000000000000000000000000000000000000000000000000000005": "b10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee9922355", + "0x0000000000000000000000000000000000000000000000000000000000000006": "5d8601f0cb3bcc4ce1af9864779a416e00000000000000000000000000000000" + } + }, + "0x4242424242424242424242424242424242424242": { + "comment": "The deposit contract", + "balance": "0", + "code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107bf565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610859573d6000803e3d6000fd5b5050506040513d602081101561086e57600080fd5b5051905060006002806108846040848a8c6116fe565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108f857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016108bb565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610955573d6000803e3d6000fd5b5050506040513d602081101561096a57600080fd5b5051600261097b896040818d6116fe565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106109f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016109b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610a51573d6000803e3d6000fd5b5050506040513d6020811015610a6657600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610ada57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610a9d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610b37573d6000803e3d6000fd5b5050506040513d6020811015610b4c57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610bd957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610b9c565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610c36573d6000803e3d6000fd5b5050506040513d6020811015610c4b57600080fd5b50516040518651600291889160009188916020918201918291908601908083835b60208310610ca957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c6c565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610d4e57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610d11565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610dab573d6000803e3d6000fd5b5050506040513d6020811015610dc057600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610e3457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610df7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610e91573d6000803e3d6000fd5b5050506040513d6020811015610ea657600080fd5b50519050858114610f02576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260548152602001806117486054913960600191505060405180910390fd5b60205463ffffffff11610f60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806117276021913960400191505060405180910390fd5b602080546001019081905560005b60208110156110a9578160011660011415610fa0578260008260208110610f9157fe5b0155506110ac95505050505050565b600260008260208110610faf57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061102557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610fe8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015611082573d6000803e3d6000fd5b5050506040513d602081101561109757600080fd5b50519250600282049150600101610f6e565b50fe5b50505050505050565b60606110c26020546114ba565b905090565b6020546000908190815b60208110156112f05781600116600114156111e6576002600082602081106110f557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061116b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161112e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156111c8573d6000803e3d6000fd5b5050506040513d60208110156111dd57600080fd5b505192506112e2565b600283602183602081106111f657fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061126b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161122e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156112c8573d6000803e3d6000fd5b5050506040513d60208110156112dd57600080fd5b505192505b6002820491506001016110d1565b506002826112ff6020546114ba565b600060401b6040516020018084815260200183805190602001908083835b6020831061135a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161131d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000095909516920191825250604080518083037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8018152601890920190819052815191955093508392850191508083835b6020831061143f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611402565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa15801561149c573d6000803e3d6000fd5b5050506040513d60208110156114b157600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106114f457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b8260018151811061153757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b8260028151811061157a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b826003815181106115bd57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b8260048151811061160057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b8260058151811061164357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b8260068151811061168657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106116c957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b6000808585111561170d578182fd5b83861115611719578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a26469706673582212201dd26f37a621703009abf16e77e69c93dc50c79db7f6cc37543e3e0e3decdc9764736f6c634300060b0033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000022": "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", + "0x0000000000000000000000000000000000000000000000000000000000000023": "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", + "0x0000000000000000000000000000000000000000000000000000000000000024": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", + "0x0000000000000000000000000000000000000000000000000000000000000025": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", + "0x0000000000000000000000000000000000000000000000000000000000000026": "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30", + "0x0000000000000000000000000000000000000000000000000000000000000027": "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1", + "0x0000000000000000000000000000000000000000000000000000000000000028": "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", + "0x0000000000000000000000000000000000000000000000000000000000000029": "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", + "0x000000000000000000000000000000000000000000000000000000000000002a": "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", + "0x000000000000000000000000000000000000000000000000000000000000002b": "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", + "0x000000000000000000000000000000000000000000000000000000000000002c": "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", + "0x000000000000000000000000000000000000000000000000000000000000002d": "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", + "0x000000000000000000000000000000000000000000000000000000000000002e": "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", + "0x000000000000000000000000000000000000000000000000000000000000002f": "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", + "0x0000000000000000000000000000000000000000000000000000000000000030": "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", + "0x0000000000000000000000000000000000000000000000000000000000000031": "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", + "0x0000000000000000000000000000000000000000000000000000000000000032": "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", + "0x0000000000000000000000000000000000000000000000000000000000000034": "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", + "0x0000000000000000000000000000000000000000000000000000000000000035": "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", + "0x0000000000000000000000000000000000000000000000000000000000000036": "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", + "0x0000000000000000000000000000000000000000000000000000000000000037": "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", + "0x0000000000000000000000000000000000000000000000000000000000000038": "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", + "0x0000000000000000000000000000000000000000000000000000000000000039": "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", + "0x000000000000000000000000000000000000000000000000000000000000003a": "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", + "0x000000000000000000000000000000000000000000000000000000000000003b": "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", + "0x000000000000000000000000000000000000000000000000000000000000003c": "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", + "0x000000000000000000000000000000000000000000000000000000000000003d": "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", + "0x000000000000000000000000000000000000000000000000000000000000003e": "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", + "0x000000000000000000000000000000000000000000000000000000000000003f": "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", + "0x0000000000000000000000000000000000000000000000000000000000000040": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7" + } + } + }, + "number":"0x0", + "gasUsed":"0x0", + "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "baseFeePerGas":"0x7" +} \ No newline at end of file diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/TransactionPoolOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/TransactionPoolOptionsTest.java index c029983a3..4ee34295f 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/options/TransactionPoolOptionsTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/TransactionPoolOptionsTest.java @@ -413,7 +413,7 @@ public class TransactionPoolOptionsTest @Test public void maxPrioritizedTxsPerTypeWrongTxType() { internalTestFailure( - "Invalid value for option '--tx-pool-max-prioritized-by-type' (MAP): expected one of [FRONTIER, ACCESS_LIST, EIP1559, BLOB] (case-insensitive) but was 'WRONG_TYPE'", + "Invalid value for option '--tx-pool-max-prioritized-by-type' (MAP): expected one of [FRONTIER, ACCESS_LIST, EIP1559, BLOB, SET_CODE] (case-insensitive) but was 'WRONG_TYPE'", "--tx-pool-max-prioritized-by-type", "WRONG_TYPE=1"); } diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/SetCodeAuthorization.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/SetCodeAuthorization.java new file mode 100644 index 000000000..b12e65de4 --- /dev/null +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/SetCodeAuthorization.java @@ -0,0 +1,82 @@ +/* + * 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.datatypes; + +import org.hyperledger.besu.crypto.SECPSignature; + +import java.math.BigInteger; +import java.util.Optional; + +/** + * SetCodeAuthorization is a data structure that represents the authorization to set code on a EOA + * account. + */ +public interface SetCodeAuthorization { + /** + * Return the chain id. + * + * @return chain id + */ + BigInteger chainId(); + + /** + * Return the address of the account which code will be used. + * + * @return address + */ + Address address(); + + /** + * Return the signature. + * + * @return signature + */ + SECPSignature signature(); + + /** + * Return the authorizer address. + * + * @return authorizer address of the EOA which will load the code into its account + */ + Optional
authorizer(); + + /** + * Return a valid nonce or empty otherwise. A nonce is valid if the size of the list is exactly 1 + * + * @return all the optional nonce + */ + Optional nonce(); + + /** + * Return the recovery id. + * + * @return byte + */ + byte v(); + + /** + * Return the r value of the signature. + * + * @return r value + */ + BigInteger r(); + + /** + * Return the s value of the signature. + * + * @return s value + */ + BigInteger s(); +} diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Transaction.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Transaction.java index 4a77a898d..d6751852b 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/Transaction.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/Transaction.java @@ -234,4 +234,18 @@ public interface Transaction { * @return the size in bytes of the encoded transaction. */ int getSize(); + + /** + * Returns the set code transaction payload if this transaction is a 7702 transaction. + * + * @return the set code transaction payloads + */ + Optional> getAuthorizationList(); + + /** + * Returns the size of the authorization list. + * + * @return the size of the authorization list + */ + int authorizationListSize(); } diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/TransactionType.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/TransactionType.java index 984a4cc74..df4a07193 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/TransactionType.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/TransactionType.java @@ -27,10 +27,12 @@ public enum TransactionType { /** Eip1559 transaction type. */ EIP1559(0x02), /** Blob transaction type. */ - BLOB(0x03); + BLOB(0x03), + /** Eip7702 transaction type. */ + SET_CODE(0x04); private static final Set ACCESS_LIST_SUPPORTED_TRANSACTION_TYPES = - Set.of(ACCESS_LIST, EIP1559, BLOB); + Set.of(ACCESS_LIST, EIP1559, BLOB, SET_CODE); private static final EnumSet LEGACY_FEE_MARKET_TRANSACTION_TYPES = EnumSet.of(TransactionType.FRONTIER, TransactionType.ACCESS_LIST); @@ -83,7 +85,8 @@ public enum TransactionType { TransactionType.FRONTIER, TransactionType.ACCESS_LIST, TransactionType.EIP1559, - TransactionType.BLOB + TransactionType.BLOB, + TransactionType.SET_CODE }) .filter(transactionType -> transactionType.typeValue == serializedTypeValue) .findFirst() @@ -128,4 +131,13 @@ public enum TransactionType { public boolean supportsBlob() { return this.equals(BLOB); } + + /** + * Does transaction type require code. + * + * @return the boolean + */ + public boolean requiresSetCode() { + return this.equals(SET_CODE); + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV3.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV3.java index 60ba8990a..b5aebf4f5 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV3.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdatedV3.java @@ -33,7 +33,7 @@ import org.slf4j.LoggerFactory; public class EngineForkchoiceUpdatedV3 extends AbstractEngineForkchoiceUpdated { - private final Optional cancun; + private final Optional supportedHardFork; private static final Logger LOG = LoggerFactory.getLogger(EngineForkchoiceUpdatedV3.class); public EngineForkchoiceUpdatedV3( @@ -43,7 +43,11 @@ public class EngineForkchoiceUpdatedV3 extends AbstractEngineForkchoiceUpdated { final MergeMiningCoordinator mergeCoordinator, final EngineCallListener engineCallListener) { super(vertx, protocolSchedule, protocolContext, mergeCoordinator, engineCallListener); - this.cancun = protocolSchedule.hardforkFor(s -> s.fork().name().equalsIgnoreCase("Cancun")); + this.supportedHardFork = + protocolSchedule.hardforkFor( + s -> + s.fork().name().equalsIgnoreCase("Cancun") + || s.fork().name().equalsIgnoreCase("Prague")); } @Override @@ -77,12 +81,12 @@ public class EngineForkchoiceUpdatedV3 extends AbstractEngineForkchoiceUpdated { @Override protected ValidationResult validateForkSupported(final long blockTimestamp) { if (protocolSchedule.isPresent()) { - if (cancun.isPresent() && blockTimestamp >= cancun.get().milestone()) { + if (supportedHardFork.isPresent() && blockTimestamp >= supportedHardFork.get().milestone()) { return ValidationResult.valid(); } else { return ValidationResult.invalid( RpcErrorType.UNSUPPORTED_FORK, - "Cancun configured to start at timestamp: " + cancun.get().milestone()); + "Cancun configured to start at timestamp: " + supportedHardFork.get().milestone()); } } else { return ValidationResult.invalid( @@ -99,7 +103,7 @@ public class EngineForkchoiceUpdatedV3 extends AbstractEngineForkchoiceUpdated { return Optional.of(new JsonRpcErrorResponse(requestId, getInvalidPayloadAttributesError())); } else if (payloadAttributes.getTimestamp().longValue() == 0) { return Optional.of(new JsonRpcErrorResponse(requestId, getInvalidPayloadAttributesError())); - } else if (payloadAttributes.getTimestamp() < cancun.get().milestone()) { + } else if (payloadAttributes.getTimestamp() < supportedHardFork.get().milestone()) { return Optional.of(new JsonRpcErrorResponse(requestId, RpcErrorType.UNSUPPORTED_FORK)); } else { return Optional.empty(); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EnginePayloadStatusResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EnginePayloadStatusResult.java index 4912f81e4..a9b9a1701 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EnginePayloadStatusResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EnginePayloadStatusResult.java @@ -19,7 +19,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngin import java.util.Optional; +import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; @JsonPropertyOrder({"status", "latestValidHash", "validationError"}) @@ -28,10 +30,11 @@ public class EnginePayloadStatusResult { Optional latestValidHash; Optional validationError; + @JsonCreator public EnginePayloadStatusResult( - final EngineStatus status, - final Hash latestValidHash, - final Optional validationError) { + @JsonProperty("status") final EngineStatus status, + @JsonProperty("latestValidHash") final Hash latestValidHash, + @JsonProperty("errorMessage") final Optional validationError) { this.status = status; this.latestValidHash = Optional.ofNullable(latestValidHash); this.validationError = validationError; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionCompleteResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionCompleteResult.java index c8260d090..05b323cac 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionCompleteResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionCompleteResult.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; import org.hyperledger.besu.datatypes.AccessListEntry; +import org.hyperledger.besu.datatypes.SetCodeAuthorization; import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.Wei; @@ -30,6 +31,7 @@ import org.apache.tuweni.bytes.Bytes; @JsonPropertyOrder({ "accessList", + "authorizationList", "blockHash", "blockNumber", "chainId", @@ -91,6 +93,9 @@ public class TransactionCompleteResult implements TransactionResult { @JsonInclude(JsonInclude.Include.NON_NULL) private final List versionedHashes; + @JsonInclude(JsonInclude.Include.NON_NULL) + private final List authorizationList; + public TransactionCompleteResult(final TransactionWithMetadata tx) { final Transaction transaction = tx.getTransaction(); final TransactionType transactionType = transaction.getType(); @@ -125,7 +130,8 @@ public class TransactionCompleteResult implements TransactionResult { this.yParity = Quantity.create(transaction.getYParity()); this.v = (transactionType == TransactionType.ACCESS_LIST - || transactionType == TransactionType.EIP1559) + || transactionType == TransactionType.EIP1559) + || transactionType == TransactionType.SET_CODE ? Quantity.create(transaction.getYParity()) : null; } @@ -133,6 +139,7 @@ public class TransactionCompleteResult implements TransactionResult { this.r = Quantity.create(transaction.getR()); this.s = Quantity.create(transaction.getS()); this.versionedHashes = transaction.getVersionedHashes().orElse(null); + this.authorizationList = transaction.getAuthorizationList().orElse(null); } @JsonGetter(value = "accessList") @@ -246,4 +253,9 @@ public class TransactionCompleteResult implements TransactionResult { public List getVersionedHashes() { return versionedHashes; } + + @JsonGetter(value = "authorizationList") + public List getAuthorizationList() { + return authorizationList; + } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SetCodeAuthorization.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SetCodeAuthorization.java new file mode 100644 index 000000000..ea9cae2fc --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/SetCodeAuthorization.java @@ -0,0 +1,260 @@ +/* + * 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.crypto.KeyPair; +import org.hyperledger.besu.crypto.SECPSignature; +import org.hyperledger.besu.crypto.SignatureAlgorithm; +import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.core.encoding.SetCodeTransactionEncoder; +import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; + +import java.math.BigInteger; +import java.util.List; +import java.util.Optional; +import java.util.function.Supplier; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.base.Suppliers; +import org.apache.tuweni.bytes.Bytes; + +public class SetCodeAuthorization implements org.hyperledger.besu.datatypes.SetCodeAuthorization { + private static final Supplier SIGNATURE_ALGORITHM = + Suppliers.memoize(SignatureAlgorithmFactory::getInstance); + + public static final Bytes MAGIC = Bytes.fromHexString("05"); + + private final BigInteger chainId; + private final Address address; + private final Optional nonce; + private final SECPSignature signature; + private Optional
authorizer = Optional.empty(); + private boolean isAuthorityComputed = false; + + /** + * An access list entry as defined in EIP-7702 + * + * @param chainId can be either the current chain id or zero + * @param address the address from which the code will be set into the EOA account + * @param nonce an optional nonce after which this auth expires + * @param signature the signature of the EOA account which will be used to set the code + */ + public SetCodeAuthorization( + final BigInteger chainId, + final Address address, + final Optional nonce, + final SECPSignature signature) { + this.chainId = chainId; + this.address = address; + this.nonce = nonce; + this.signature = signature; + } + + /** + * Create access list entry. + * + * @param chainId can be either the current chain id or zero + * @param address the address from which the code will be set into the EOA account + * @param nonces the list of nonces + * @param v the recovery id + * @param r the r value of the signature + * @param s the s value of the signature + * @return SetCodeTransactionEntry + */ + @JsonCreator + public static org.hyperledger.besu.datatypes.SetCodeAuthorization createSetCodeAuthorizationEntry( + @JsonProperty("chainId") final BigInteger chainId, + @JsonProperty("address") final Address address, + @JsonProperty("nonce") final List nonces, + @JsonProperty("v") final byte v, + @JsonProperty("r") final BigInteger r, + @JsonProperty("s") final BigInteger s) { + return new SetCodeAuthorization( + chainId, + address, + Optional.ofNullable(nonces.get(0)), + SIGNATURE_ALGORITHM.get().createSignature(r, s, v)); + } + + @JsonProperty("chainId") + @Override + public BigInteger chainId() { + return chainId; + } + + @JsonProperty("address") + @Override + public Address address() { + return address; + } + + @JsonProperty("signature") + @Override + public SECPSignature signature() { + return signature; + } + + @Override + public Optional
authorizer() { + if (!isAuthorityComputed) { + authorizer = computeAuthority(); + isAuthorityComputed = true; + } + + return authorizer; + } + + @Override + public Optional nonce() { + return nonce; + } + + @JsonProperty("v") + @Override + public byte v() { + return signature.getRecId(); + } + + @JsonProperty("r") + @Override + public BigInteger r() { + return signature.getR(); + } + + @JsonProperty("s") + @Override + public BigInteger s() { + return signature.getS(); + } + + private Optional
computeAuthority() { + BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput(); + SetCodeTransactionEncoder.encodeSingleSetCodeWithoutSignature(this, rlpOutput); + + final Hash hash = Hash.hash(Bytes.concatenate(MAGIC, rlpOutput.encoded())); + + return SIGNATURE_ALGORITHM + .get() + .recoverPublicKeyFromSignature(hash, signature) + .map(Address::extract); + } + + /** + * Create set code authorization with a builder. + * + * @return SetCodeAuthorization.Builder + */ + public static Builder builder() { + return new Builder(); + } + + /** Builder for SetCodeAuthorization. */ + public static class Builder { + private BigInteger chainId = BigInteger.ZERO; + private Address address; + private Optional nonce = Optional.empty(); + private SECPSignature signature; + + /** Create a new builder. */ + protected Builder() {} + + /** + * Set the optional chain id. + * + * @param chainId the chain id + * @return this builder + */ + public Builder chainId(final BigInteger chainId) { + this.chainId = chainId; + return this; + } + + /** + * Set the address of the authorized smart contract. + * + * @param address the address + * @return this builder + */ + public Builder address(final Address address) { + this.address = address; + return this; + } + + /** + * Set the optional nonce. + * + * @param nonce the optional nonce. + * @return this builder + */ + public Builder nonces(final Optional nonce) { + this.nonce = nonce; + return this; + } + + /** + * Set the signature of the authorizer account. + * + * @param signature the signature + * @return this builder + */ + public Builder signature(final SECPSignature signature) { + this.signature = signature; + return this; + } + + /** + * Sign the authorization with the given key pair and return the authorization. + * + * @param keyPair the key pair + * @return SetCodeAuthorization + */ + public org.hyperledger.besu.datatypes.SetCodeAuthorization signAndBuild(final KeyPair keyPair) { + final BytesValueRLPOutput output = new BytesValueRLPOutput(); + output.startList(); + output.writeBigIntegerScalar(chainId); + output.writeBytes(address); + output.startList(); + nonce.ifPresent(output::writeLongScalar); + output.endList(); + output.endList(); + + signature( + SIGNATURE_ALGORITHM + .get() + .sign(Hash.hash(Bytes.concatenate(MAGIC, output.encoded())), keyPair)); + return build(); + } + + /** + * Build the authorization. + * + * @return SetCodeAuthorization + */ + public org.hyperledger.besu.datatypes.SetCodeAuthorization build() { + if (address == null) { + throw new IllegalStateException("Address must be set"); + } + + if (signature == null) { + throw new IllegalStateException("Signature must be set"); + } + + return new SetCodeAuthorization(chainId, address, nonce, signature); + } + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java index 7ca349721..513cfb831 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java @@ -31,6 +31,7 @@ import org.hyperledger.besu.datatypes.BlobsWithCommitments; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.KZGCommitment; import org.hyperledger.besu.datatypes.KZGProof; +import org.hyperledger.besu.datatypes.SetCodeAuthorization; import org.hyperledger.besu.datatypes.Sha256Hash; import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.VersionedHash; @@ -38,6 +39,7 @@ import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.encoding.AccessListTransactionEncoder; import org.hyperledger.besu.ethereum.core.encoding.BlobTransactionEncoder; import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; +import org.hyperledger.besu.ethereum.core.encoding.SetCodeTransactionEncoder; import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; @@ -122,6 +124,7 @@ public class Transaction private final Optional> versionedHashes; private final Optional blobsWithCommitments; + private final Optional> maybeAuthorizationList; public static Builder builder() { return new Builder(); @@ -177,7 +180,8 @@ public class Transaction final Address sender, final Optional chainId, final Optional> versionedHashes, - final Optional blobsWithCommitments) { + final Optional blobsWithCommitments, + final Optional> maybeAuthorizationList) { if (!forCopy) { if (transactionType.requiresChainId()) { @@ -213,6 +217,12 @@ public class Transaction checkArgument( maxFeePerBlobGas.isPresent(), "Must specify max fee per blob gas for blob transaction"); } + + if (transactionType.requiresSetCode()) { + checkArgument( + maybeAuthorizationList.isPresent(), + "Must specify set code transaction payload for set code transaction"); + } } this.transactionType = transactionType; @@ -231,6 +241,7 @@ public class Transaction this.chainId = chainId; this.versionedHashes = versionedHashes; this.blobsWithCommitments = blobsWithCommitments; + this.maybeAuthorizationList = maybeAuthorizationList; } /** @@ -462,6 +473,7 @@ public class Transaction payload, maybeAccessList, versionedHashes.orElse(null), + maybeAuthorizationList, chainId); } return hashNoSignature; @@ -668,6 +680,16 @@ public class Transaction return blobsWithCommitments; } + @Override + public Optional> getAuthorizationList() { + return maybeAuthorizationList; + } + + @Override + public int authorizationListSize() { + return maybeAuthorizationList.map(List::size).orElse(0); + } + /** * Return the list of transaction hashes extracted from the collection of Transaction passed as * argument @@ -692,6 +714,7 @@ public class Transaction final Bytes payload, final Optional> accessList, final List versionedHashes, + final Optional> authorizationList, final Optional chainId) { if (transactionType.requiresChainId()) { checkArgument(chainId.isPresent(), "Transaction type %s requires chainId", transactionType); @@ -736,6 +759,21 @@ public class Transaction new IllegalStateException( "Developer error: the transaction should be guaranteed to have an access list here")), chainId); + case SET_CODE -> + setCodePreimage( + nonce, + maxPriorityFeePerGas, + maxFeePerGas, + gasLimit, + to, + value, + payload, + chainId, + accessList, + authorizationList.orElseThrow( + () -> + new IllegalStateException( + "Developer error: the transaction should be guaranteed to have a set code payload here"))); }; return keccak256(preimage); } @@ -873,6 +911,38 @@ public class Transaction return Bytes.concatenate(Bytes.of(TransactionType.ACCESS_LIST.getSerializedType()), encode); } + private static Bytes setCodePreimage( + final long nonce, + final Wei maxPriorityFeePerGas, + final Wei maxFeePerGas, + final long gasLimit, + final Optional
to, + final Wei value, + final Bytes payload, + final Optional chainId, + final Optional> accessList, + final List authorizationList) { + final Bytes encoded = + RLP.encode( + rlpOutput -> { + rlpOutput.startList(); + eip1559PreimageFields( + nonce, + maxPriorityFeePerGas, + maxFeePerGas, + gasLimit, + to, + value, + payload, + chainId, + accessList, + rlpOutput); + SetCodeTransactionEncoder.encodeSetCodeInner(authorizationList, rlpOutput); + rlpOutput.endList(); + }); + return Bytes.concatenate(Bytes.of(TransactionType.SET_CODE.getSerializedType()), encoded); + } + @Override public boolean equals(final Object other) { if (!(other instanceof Transaction that)) { @@ -1040,7 +1110,8 @@ public class Transaction sender, chainId, detachedVersionedHashes, - detachedBlobsWithCommitments); + detachedBlobsWithCommitments, + maybeAuthorizationList); // copy also the computed fields, to avoid to recompute them copiedTx.sender = this.sender; @@ -1108,6 +1179,7 @@ public class Transaction protected Optional v = Optional.empty(); protected List versionedHashes = null; private BlobsWithCommitments blobsWithCommitments; + protected Optional> setCodeTransactionPayloads = Optional.empty(); public Builder copiedFrom(final Transaction toCopy) { this.transactionType = toCopy.transactionType; @@ -1126,6 +1198,7 @@ public class Transaction this.chainId = toCopy.chainId; this.versionedHashes = toCopy.versionedHashes.orElse(null); this.blobsWithCommitments = toCopy.blobsWithCommitments.orElse(null); + this.setCodeTransactionPayloads = toCopy.maybeAuthorizationList; return this; } @@ -1219,6 +1292,8 @@ public class Transaction transactionType = TransactionType.EIP1559; } else if (accessList.isPresent()) { transactionType = TransactionType.ACCESS_LIST; + } else if (setCodeTransactionPayloads.isPresent()) { + transactionType = TransactionType.SET_CODE; } else { transactionType = TransactionType.FRONTIER; } @@ -1248,7 +1323,8 @@ public class Transaction sender, chainId, Optional.ofNullable(versionedHashes), - Optional.ofNullable(blobsWithCommitments)); + Optional.ofNullable(blobsWithCommitments), + setCodeTransactionPayloads); } public Transaction signAndBuild(final KeyPair keys) { @@ -1275,6 +1351,7 @@ public class Transaction payload, accessList, versionedHashes, + setCodeTransactionPayloads, chainId), keys); } @@ -1298,5 +1375,11 @@ public class Transaction this.blobsWithCommitments = blobsWithCommitments; return this; } + + public Builder setCodeTransactionPayloads( + final List setCodeTransactionEntries) { + this.setCodeTransactionPayloads = Optional.ofNullable(setCodeTransactionEntries); + return this; + } } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/SetCodeTransactionDecoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/SetCodeTransactionDecoder.java new file mode 100644 index 000000000..80d59de83 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/SetCodeTransactionDecoder.java @@ -0,0 +1,116 @@ +/* + * 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.crypto.SECPSignature; +import org.hyperledger.besu.crypto.SignatureAlgorithm; +import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; +import org.hyperledger.besu.datatypes.AccessListEntry; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.TransactionType; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.SetCodeAuthorization; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.rlp.RLPInput; + +import java.math.BigInteger; +import java.util.Optional; +import java.util.function.Supplier; + +import com.google.common.base.Suppliers; + +public class SetCodeTransactionDecoder { + private static final Supplier SIGNATURE_ALGORITHM = + Suppliers.memoize(SignatureAlgorithmFactory::getInstance); + + private SetCodeTransactionDecoder() { + // private constructor + } + + public static Transaction decode(final RLPInput input) { + input.enterList(); + final BigInteger chainId = input.readBigIntegerScalar(); + final Transaction.Builder builder = + Transaction.builder() + .type(TransactionType.SET_CODE) + .chainId(chainId) + .nonce(input.readLongScalar()) + .maxPriorityFeePerGas(Wei.of(input.readUInt256Scalar())) + .maxFeePerGas(Wei.of(input.readUInt256Scalar())) + .gasLimit(input.readLongScalar()) + .to(input.readBytes(v -> v.isEmpty() ? null : Address.wrap(v))) + .value(Wei.of(input.readUInt256Scalar())) + .payload(input.readBytes()) + .accessList( + input.readList( + accessListEntryRLPInput -> { + accessListEntryRLPInput.enterList(); + final AccessListEntry accessListEntry = + new AccessListEntry( + Address.wrap(accessListEntryRLPInput.readBytes()), + accessListEntryRLPInput.readList(RLPInput::readBytes32)); + accessListEntryRLPInput.leaveList(); + return accessListEntry; + })) + .setCodeTransactionPayloads( + input.readList( + setCodeTransactionPayloadsRLPInput -> + decodeInnerPayload(setCodeTransactionPayloadsRLPInput))); + + final byte recId = (byte) input.readUnsignedByteScalar(); + final BigInteger r = input.readUInt256Scalar().toUnsignedBigInteger(); + final BigInteger s = input.readUInt256Scalar().toUnsignedBigInteger(); + + input.leaveList(); + + final Transaction transaction = + builder.signature(SIGNATURE_ALGORITHM.get().createSignature(r, s, recId)).build(); + + return transaction; + } + + public static org.hyperledger.besu.datatypes.SetCodeAuthorization decodeInnerPayload( + final RLPInput input) { + input.enterList(); + final BigInteger chainId = input.readBigIntegerScalar(); + final Address address = Address.wrap(input.readBytes()); + + Optional nonce = Optional.empty(); + + if (!input.nextIsList()) { + throw new IllegalArgumentException("Optional nonce must be an list, but isn't"); + } + + final long noncesSize = input.nextSize(); + + input.enterList(); + if (noncesSize == 1) { + nonce = Optional.ofNullable(input.readLongScalar()); + } else if (noncesSize > 1) { + throw new IllegalArgumentException("Nonce list may only have 1 member, if any"); + } + input.leaveList(); + + final byte yParity = (byte) input.readUnsignedByteScalar(); + final BigInteger r = input.readUInt256Scalar().toUnsignedBigInteger(); + final BigInteger s = input.readUInt256Scalar().toUnsignedBigInteger(); + + input.leaveList(); + + final SECPSignature signature = SIGNATURE_ALGORITHM.get().createSignature(r, s, yParity); + + return new SetCodeAuthorization(chainId, address, nonce, signature); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/SetCodeTransactionEncoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/SetCodeTransactionEncoder.java new file mode 100644 index 000000000..05808f312 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/SetCodeTransactionEncoder.java @@ -0,0 +1,89 @@ +/* + * 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.hyperledger.besu.ethereum.core.encoding.AccessListTransactionEncoder.writeAccessList; +import static org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder.writeSignatureAndRecoveryId; + +import org.hyperledger.besu.datatypes.SetCodeAuthorization; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.rlp.RLPOutput; + +import java.util.List; + +import org.apache.tuweni.bytes.Bytes; + +public class SetCodeTransactionEncoder { + + private SetCodeTransactionEncoder() { + // private constructor + } + + public static void encodeSetCodeInner( + final List payloads, final RLPOutput rlpOutput) { + rlpOutput.startList(); + payloads.forEach(payload -> encodeSingleSetCode(payload, rlpOutput)); + rlpOutput.endList(); + } + + public static void encodeSingleSetCodeWithoutSignature( + final SetCodeAuthorization payload, final RLPOutput rlpOutput) { + rlpOutput.startList(); + encodeAuthorizationDetails(payload, rlpOutput); + rlpOutput.endList(); + } + + public static void encodeSingleSetCode( + final SetCodeAuthorization payload, final RLPOutput rlpOutput) { + rlpOutput.startList(); + encodeAuthorizationDetails(payload, rlpOutput); + rlpOutput.writeIntScalar(payload.signature().getRecId()); + rlpOutput.writeBigIntegerScalar(payload.signature().getR()); + rlpOutput.writeBigIntegerScalar(payload.signature().getS()); + rlpOutput.endList(); + } + + private static void encodeAuthorizationDetails( + final SetCodeAuthorization payload, final RLPOutput rlpOutput) { + rlpOutput.writeBigIntegerScalar(payload.chainId()); + rlpOutput.writeBytes(payload.address().copy()); + rlpOutput.startList(); + payload.nonce().ifPresent(rlpOutput::writeLongScalar); + rlpOutput.endList(); + } + + public static void encode(final Transaction transaction, final RLPOutput out) { + out.startList(); + out.writeBigIntegerScalar(transaction.getChainId().orElseThrow()); + out.writeLongScalar(transaction.getNonce()); + out.writeUInt256Scalar(transaction.getMaxPriorityFeePerGas().orElseThrow()); + out.writeUInt256Scalar(transaction.getMaxFeePerGas().orElseThrow()); + out.writeLongScalar(transaction.getGasLimit()); + out.writeBytes(transaction.getTo().map(Bytes::copy).orElse(Bytes.EMPTY)); + out.writeUInt256Scalar(transaction.getValue()); + out.writeBytes(transaction.getPayload()); + writeAccessList(out, transaction.getAccessList()); + encodeSetCodeInner( + transaction + .getAuthorizationList() + .orElseThrow( + () -> + new IllegalStateException( + "Developer error: the transaction should be guaranteed to have a set code payload here")), + out); + writeSignatureAndRecoveryId(transaction, out); + out.endList(); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java index fe6687cdb..2a63d8f24 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java @@ -40,7 +40,9 @@ public class TransactionDecoder { TransactionType.EIP1559, EIP1559TransactionDecoder::decode, TransactionType.BLOB, - BlobTransactionDecoder::decode); + BlobTransactionDecoder::decode, + TransactionType.SET_CODE, + SetCodeTransactionDecoder::decode); private static final ImmutableMap POOLED_TRANSACTION_DECODERS = ImmutableMap.of(TransactionType.BLOB, BlobPooledTransactionDecoder::decode); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java index 20fe75885..499597562 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java @@ -39,7 +39,9 @@ public class TransactionEncoder { TransactionType.EIP1559, EIP1559TransactionEncoder::encode, TransactionType.BLOB, - BlobTransactionEncoder::encode); + BlobTransactionEncoder::encode, + TransactionType.SET_CODE, + SetCodeTransactionEncoder::encode); private static final ImmutableMap POOLED_TRANSACTION_ENCODERS = ImmutableMap.of(TransactionType.BLOB, BlobPooledTransactionEncoder::encode); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AuthorityProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AuthorityProcessor.java new file mode 100644 index 000000000..f79e2c98e --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AuthorityProcessor.java @@ -0,0 +1,88 @@ +/* + * 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 org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.evm.account.Account; +import org.hyperledger.besu.evm.account.AccountState; +import org.hyperledger.besu.evm.account.MutableAccount; +import org.hyperledger.besu.evm.worldstate.AuthorizedCodeService; +import org.hyperledger.besu.evm.worldstate.WorldUpdater; + +import java.math.BigInteger; +import java.util.Optional; + +import org.apache.tuweni.bytes.Bytes; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AuthorityProcessor { + private static final Logger LOG = LoggerFactory.getLogger(AuthorityProcessor.class); + + private final Optional maybeChainId; + + public AuthorityProcessor(final Optional maybeChainId) { + this.maybeChainId = maybeChainId; + } + + public void addContractToAuthority( + final WorldUpdater worldUpdater, + final AuthorizedCodeService authorizedCodeService, + final Transaction transaction) { + + transaction + .getAuthorizationList() + .get() + .forEach( + payload -> + payload + .authorizer() + .ifPresent( + authorityAddress -> { + LOG.trace("Set code authority: {}", authorityAddress); + + if (maybeChainId.isPresent() + && !payload.chainId().equals(BigInteger.ZERO) + && !maybeChainId.get().equals(payload.chainId())) { + return; + } + + final Optional maybeAccount = + Optional.ofNullable(worldUpdater.getAccount(authorityAddress)); + final long accountNonce = + maybeAccount.map(AccountState::getNonce).orElse(0L); + + if (payload.nonce().isPresent() + && !payload.nonce().get().equals(accountNonce)) { + return; + } + + if (authorizedCodeService.hasAuthorizedCode(authorityAddress)) { + return; + } + + Optional codeAccount = + Optional.ofNullable(worldUpdater.get(payload.address())); + final Bytes code; + if (codeAccount.isPresent()) { + code = codeAccount.get().getCode(); + } else { + code = Bytes.EMPTY; + } + + authorizedCodeService.addAuthorizedCode(authorityAddress, code); + })); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java index 4ae30f8de..6f09df923 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java @@ -595,7 +595,8 @@ public abstract class MainnetProtocolSpecs { true, evmConfiguration.evmStackSize(), feeMarket, - CoinbaseFeePriceCalculator.eip1559())) + CoinbaseFeePriceCalculator.eip1559(), + new AuthorityProcessor(chainId))) // change to check for max blob gas per block for EIP-4844 .transactionValidatorFactoryBuilder( (evm, gasLimitCalculator, feeMarket) -> @@ -658,6 +659,23 @@ public abstract class MainnetProtocolSpecs { // EIP-7002 Withdrawals / EIP-6610 Deposits / EIP-7685 Requests .requestProcessorCoordinator(pragueRequestsProcessors(depositContractAddress)) + // change to accept EIP-7702 transactions + .transactionValidatorFactoryBuilder( + (evm, gasLimitCalculator, feeMarket) -> + new TransactionValidatorFactory( + evm.getGasCalculator(), + gasLimitCalculator, + feeMarket, + true, + chainId, + Set.of( + TransactionType.FRONTIER, + TransactionType.ACCESS_LIST, + TransactionType.EIP1559, + TransactionType.BLOB, + TransactionType.SET_CODE), + evm.getEvmVersion().getMaxInitcodeSize())) + // EIP-2935 Blockhash processor .blockHashProcessor(new PragueBlockHashProcessor()) .name("Prague"); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java index 53801d14c..9ad1db7d8 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java @@ -42,6 +42,7 @@ import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.gascalculator.GasCalculator; import org.hyperledger.besu.evm.processor.AbstractMessageProcessor; import org.hyperledger.besu.evm.tracing.OperationTracer; +import org.hyperledger.besu.evm.worldstate.AuthorizedCodeService; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import java.util.Deque; @@ -80,6 +81,8 @@ public class MainnetTransactionProcessor { protected final FeeMarket feeMarket; private final CoinbaseFeePriceCalculator coinbaseFeePriceCalculator; + private final Optional maybeAuthorityProcessor; + public MainnetTransactionProcessor( final GasCalculator gasCalculator, final TransactionValidatorFactory transactionValidatorFactory, @@ -90,6 +93,30 @@ public class MainnetTransactionProcessor { final int maxStackSize, final FeeMarket feeMarket, final CoinbaseFeePriceCalculator coinbaseFeePriceCalculator) { + this( + gasCalculator, + transactionValidatorFactory, + contractCreationProcessor, + messageCallProcessor, + clearEmptyAccounts, + warmCoinbase, + maxStackSize, + feeMarket, + coinbaseFeePriceCalculator, + null); + } + + public MainnetTransactionProcessor( + final GasCalculator gasCalculator, + final TransactionValidatorFactory transactionValidatorFactory, + final AbstractMessageProcessor contractCreationProcessor, + final AbstractMessageProcessor messageCallProcessor, + final boolean clearEmptyAccounts, + final boolean warmCoinbase, + final int maxStackSize, + final FeeMarket feeMarket, + final CoinbaseFeePriceCalculator coinbaseFeePriceCalculator, + final AuthorityProcessor maybeAuthorityProcessor) { this.gasCalculator = gasCalculator; this.transactionValidatorFactory = transactionValidatorFactory; this.contractCreationProcessor = contractCreationProcessor; @@ -99,6 +126,7 @@ public class MainnetTransactionProcessor { this.maxStackSize = maxStackSize; this.feeMarket = feeMarket; this.coinbaseFeePriceCalculator = coinbaseFeePriceCalculator; + this.maybeAuthorityProcessor = Optional.ofNullable(maybeAuthorityProcessor); } /** @@ -259,6 +287,8 @@ public class MainnetTransactionProcessor { final PrivateMetadataUpdater privateMetadataUpdater, final Wei blobGasPrice) { try { + final AuthorizedCodeService authorizedCodeService = new AuthorizedCodeService(); + worldState.setAuthorizedCodeService(authorizedCodeService); final var transactionValidator = transactionValidatorFactory.get(); LOG.trace("Starting execution of {}", transaction); ValidationResult validationResult = @@ -332,15 +362,19 @@ public class MainnetTransactionProcessor { transaction.getPayload(), transaction.isContractCreation()); final long accessListGas = gasCalculator.accessListGasCost(accessListEntries.size(), accessListStorageCount); - final long gasAvailable = transaction.getGasLimit() - intrinsicGas - accessListGas; + final long setCodeGas = gasCalculator.setCodeListGasCost(transaction.authorizationListSize()); + final long gasAvailable = + transaction.getGasLimit() - intrinsicGas - accessListGas - setCodeGas; LOG.trace( - "Gas available for execution {} = {} - {} - {} (limit - intrinsic - accessList)", + "Gas available for execution {} = {} - {} - {} - {} (limit - intrinsic - accessList - setCode)", gasAvailable, transaction.getGasLimit(), intrinsicGas, - accessListGas); + accessListGas, + setCodeGas); final WorldUpdater worldUpdater = worldState.updater(); + worldUpdater.setAuthorizedCodeService(authorizedCodeService); final ImmutableMap.Builder contextVariablesBuilder = ImmutableMap.builder() .put(KEY_IS_PERSISTING_PRIVATE_STATE, isPersistingPrivateState) @@ -374,6 +408,15 @@ public class MainnetTransactionProcessor { if (transaction.getVersionedHashes().isPresent()) { commonMessageFrameBuilder.versionedHashes( Optional.of(transaction.getVersionedHashes().get().stream().toList())); + } else if (transaction.getAuthorizationList().isPresent()) { + if (maybeAuthorityProcessor.isEmpty()) { + throw new RuntimeException("Authority processor is required for 7702 transactions"); + } + + maybeAuthorityProcessor + .get() + .addContractToAuthority(worldUpdater, authorizedCodeService, transaction); + addressList.addAll(authorizedCodeService.getAuthorities()); } else { commonMessageFrameBuilder.versionedHashes(Optional.empty()); } @@ -392,6 +435,7 @@ public class MainnetTransactionProcessor { .contract(contractAddress) .inputData(initCodeBytes.slice(code.getSize())) .code(code) + .authorizedCodeService(authorizedCodeService) .build(); } else { @SuppressWarnings("OptionalGetWithoutIsPresent") // isContractCall tests isPresent @@ -407,6 +451,7 @@ public class MainnetTransactionProcessor { maybeContract .map(c -> messageCallProcessor.getCodeFromEVM(c.getCodeHash(), c.getCode())) .orElse(CodeV0.EMPTY_CODE)) + .authorizedCodeService(authorizedCodeService) .build(); } Deque messageFrameStack = initialFrame.getMessageFrameStack(); @@ -485,6 +530,7 @@ public class MainnetTransactionProcessor { coinbaseCalculator.price(usedGas, transactionGasPrice, blockHeader.getBaseFee()); coinbase.incrementBalance(coinbaseWeiDelta); + authorizedCodeService.resetAuthorities(); operationTracer.traceEndTransaction( worldUpdater, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java index 9d90a409a..481ce70e0 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java @@ -189,7 +189,8 @@ public class MainnetTransactionValidator implements TransactionValidator { final long intrinsicGasCost = gasCalculator.transactionIntrinsicGasCost( transaction.getPayload(), transaction.isContractCreation()) - + (transaction.getAccessList().map(gasCalculator::accessListGasCost).orElse(0L)); + + (transaction.getAccessList().map(gasCalculator::accessListGasCost).orElse(0L)) + + gasCalculator.setCodeListGasCost(transaction.authorizationListSize()); if (Long.compareUnsigned(intrinsicGasCost, transaction.getGasLimit()) > 0) { return ValidationResult.invalid( TransactionInvalidReason.INTRINSIC_GAS_EXCEEDS_GAS_LIMIT, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateMutableWorldStateUpdater.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateMutableWorldStateUpdater.java index fc20db7f8..b4e8e2856 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateMutableWorldStateUpdater.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateMutableWorldStateUpdater.java @@ -18,6 +18,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.account.MutableAccount; +import org.hyperledger.besu.evm.worldstate.AuthorizedCodeService; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import java.util.Collection; @@ -30,35 +31,39 @@ public class PrivateMutableWorldStateUpdater implements WorldUpdater { protected final WorldUpdater publicWorldUpdater; protected final WorldUpdater privateWorldUpdater; + private AuthorizedCodeService authorizedCodeService; public PrivateMutableWorldStateUpdater( final WorldUpdater publicWorldUpdater, final WorldUpdater privateWorldUpdater) { this.publicWorldUpdater = publicWorldUpdater; this.privateWorldUpdater = privateWorldUpdater; + this.authorizedCodeService = new AuthorizedCodeService(); } @Override public MutableAccount createAccount(final Address address, final long nonce, final Wei balance) { - return privateWorldUpdater.createAccount(address, nonce, balance); + return authorizedCodeService.processMutableAccount( + this, privateWorldUpdater.createAccount(address, nonce, balance), address); } @Override public MutableAccount createAccount(final Address address) { - return privateWorldUpdater.createAccount(address); + return authorizedCodeService.processMutableAccount( + this, privateWorldUpdater.createAccount(address), address); } @Override public MutableAccount getAccount(final Address address) { final MutableAccount privateAccount = privateWorldUpdater.getAccount(address); if (privateAccount != null && !privateAccount.isEmpty()) { - return privateAccount; + return authorizedCodeService.processMutableAccount(this, privateAccount, address); } final MutableAccount publicAccount = publicWorldUpdater.getAccount(address); if (publicAccount != null && !publicAccount.isEmpty()) { publicAccount.becomeImmutable(); - return publicAccount; + return authorizedCodeService.processMutableAccount(this, publicAccount, address); } - return privateAccount; + return authorizedCodeService.processMutableAccount(this, privateAccount, address); } @Override @@ -104,4 +109,9 @@ public class PrivateMutableWorldStateUpdater implements WorldUpdater { public Optional parentUpdater() { return privateWorldUpdater.parentUpdater(); } + + @Override + public void setAuthorizedCodeService(final AuthorizedCodeService authorizedCodeService) { + this.authorizedCodeService = authorizedCodeService; + } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/accumulator/DiffBasedWorldStateUpdateAccumulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/accumulator/DiffBasedWorldStateUpdateAccumulator.java index 149cefbe5..b5bae0aed 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/accumulator/DiffBasedWorldStateUpdateAccumulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/accumulator/DiffBasedWorldStateUpdateAccumulator.java @@ -136,7 +136,8 @@ public abstract class DiffBasedWorldStateUpdateAccumulator(diffBasedValue.getUpdated())); + return authorizedCodeService.processMutableAccount( + this, track(new UpdateTrackingAccount<>(diffBasedValue.getUpdated())), address); } else { throw new IllegalStateException("Cannot create an account when one already exists"); } @@ -153,7 +154,8 @@ public abstract class DiffBasedWorldStateUpdateAccumulator(newAccount)); + return authorizedCodeService.processMutableAccount( + this, track(new UpdateTrackingAccount<>(newAccount)), address); } @Override diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java index c5b797403..2709b94e2 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java @@ -376,6 +376,7 @@ public class BlockDataGenerator { case EIP1559 -> eip1559Transaction(payload, to); case ACCESS_LIST -> accessListTransaction(payload, to); case BLOB -> blobTransaction(payload, to); + case SET_CODE -> null; // no default, all types accounted for. }; } diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TransactionTestFixture.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TransactionTestFixture.java index d016b7f4e..3f7049be3 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TransactionTestFixture.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/TransactionTestFixture.java @@ -92,6 +92,8 @@ public class TransactionTestFixture { builder.versionedHashes(versionedHashes.get()); } break; + case SET_CODE: + break; } to.ifPresent(builder::to); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/SetCodeTransactionDecoderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/SetCodeTransactionDecoderTest.java new file mode 100644 index 000000000..610b5906f --- /dev/null +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/SetCodeTransactionDecoderTest.java @@ -0,0 +1,120 @@ +/* + * 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.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.hyperledger.besu.crypto.SECPSignature; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.SetCodeAuthorization; +import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput; + +import java.math.BigInteger; + +import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.Test; + +class SetCodeTransactionDecoderTest { + + @Test + void shouldDecodeInnerPayloadWithNonce() { + // "0xd80194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c105" + + final BytesValueRLPInput input = + new BytesValueRLPInput( + Bytes.fromHexString( + "0xf85b0194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c18080a0840798fa67118e034c1eb7e42fe89e28d7cd5006dc813d5729e5f75b0d1a7ec5a03b1dbace38ceb862a65bf2eac0637693b5c3493bcb2a022dd614c0a74cce0b99"), + true); + final SetCodeAuthorization authorization = SetCodeTransactionDecoder.decodeInnerPayload(input); + + assertThat(authorization.chainId()).isEqualTo(BigInteger.ONE); + assertThat(authorization.address()) + .isEqualTo(Address.fromHexStringStrict("0x633688abc3cCf8B0C03088D2d1C6ae4958c2fA56")); + assertThat(authorization.nonce().get()).isEqualTo(0L); + + final SECPSignature signature = authorization.signature(); + assertThat(signature.getRecId()).isEqualTo((byte) 0); + assertThat(signature.getR().toString(16)) + .isEqualTo("840798fa67118e034c1eb7e42fe89e28d7cd5006dc813d5729e5f75b0d1a7ec5"); + assertThat(signature.getS().toString(16)) + .isEqualTo("3b1dbace38ceb862a65bf2eac0637693b5c3493bcb2a022dd614c0a74cce0b99"); + } + + @Test + void shouldDecodeInnerPayloadWithoutNonce() { + // "0xd70194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c5" + + final BytesValueRLPInput input = + new BytesValueRLPInput( + Bytes.fromHexString( + "0xf85a0194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c001a0dd6b24048be1b7d7fe5bbbb73ffc37eb2ce1997ecb4ae5b6096532ef19363148a025b58a1ff8ad00bddbbfa1d5c2411961cbb6d08dcdc8ae88303db3c6cf983031"), + true); + final SetCodeAuthorization authorization = SetCodeTransactionDecoder.decodeInnerPayload(input); + + assertThat(authorization.chainId()).isEqualTo(BigInteger.ONE); + assertThat(authorization.address()) + .isEqualTo(Address.fromHexStringStrict("0x633688abc3cCf8B0C03088D2d1C6ae4958c2fA56")); + assertThat(authorization.nonce()).isEmpty(); + + final SECPSignature signature = authorization.signature(); + assertThat(signature.getRecId()).isEqualTo((byte) 1); + assertThat(signature.getR().toString(16)) + .isEqualTo("dd6b24048be1b7d7fe5bbbb73ffc37eb2ce1997ecb4ae5b6096532ef19363148"); + assertThat(signature.getS().toString(16)) + .isEqualTo("25b58a1ff8ad00bddbbfa1d5c2411961cbb6d08dcdc8ae88303db3c6cf983031"); + } + + @Test + void shouldThrowInnerPayloadWithMultipleNonces() { + // "d90194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c20107" + + final BytesValueRLPInput input = + new BytesValueRLPInput( + Bytes.fromHexString( + "0xf85c0194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c2010201a0401b5d4ebe88306448115d1a46a30e5ad1136f2818b4ebb0733d9c4efffd135aa0753ff1dbce6db504ecb9635a64d8c4506ff887e2d2a0d2b7175baf94c849eccc"), + true); + + assertThrows( + IllegalArgumentException.class, + () -> { + SetCodeTransactionDecoder.decodeInnerPayload(input); + }); + } + + @Test + void shouldDecodeInnerPayloadWithoutNonceAndChainIdZero() { + // "d70094633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c5" + + final BytesValueRLPInput input = + new BytesValueRLPInput( + Bytes.fromHexString( + "0xf85a0094633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c001a0025c1240d7ffec0daeedb752d3357aff2e3cd58468f0c2d43ee0ee999e02ace2a03c8a25b2becd6e666f69803d1ae3322f2e137b7745c2c7f19da80f993ffde4df"), + true); + final SetCodeAuthorization authorization = SetCodeTransactionDecoder.decodeInnerPayload(input); + + assertThat(authorization.chainId()).isEqualTo(BigInteger.ZERO); + assertThat(authorization.address()) + .isEqualTo(Address.fromHexStringStrict("0x633688abc3cCf8B0C03088D2d1C6ae4958c2fA56")); + assertThat(authorization.nonce().isEmpty()).isTrue(); + + final SECPSignature signature = authorization.signature(); + assertThat(signature.getRecId()).isEqualTo((byte) 1); + assertThat(signature.getR().toString(16)) + .isEqualTo("25c1240d7ffec0daeedb752d3357aff2e3cd58468f0c2d43ee0ee999e02ace2"); + assertThat(signature.getS().toString(16)) + .isEqualTo("3c8a25b2becd6e666f69803d1ae3322f2e137b7745c2c7f19da80f993ffde4df"); + } +} diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/SetCodeTransactionEncoderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/SetCodeTransactionEncoderTest.java new file mode 100644 index 000000000..89211f4ba --- /dev/null +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/SetCodeTransactionEncoderTest.java @@ -0,0 +1,122 @@ +/* + * 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.AssertionsForClassTypes.assertThat; + +import org.hyperledger.besu.crypto.SignatureAlgorithm; +import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.ethereum.core.SetCodeAuthorization; +import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; + +import java.math.BigInteger; +import java.util.Optional; +import java.util.function.Supplier; + +import com.google.common.base.Suppliers; +import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class SetCodeTransactionEncoderTest { + private static final Supplier SIGNATURE_ALGORITHM = + Suppliers.memoize(SignatureAlgorithmFactory::getInstance); + + BytesValueRLPOutput output; + + @BeforeEach + void setUp() { + output = new BytesValueRLPOutput(); + } + + @Test + void shouldEncodeSingleSetCodeWithNonce() { + // "0xd80194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c105" + + final SetCodeAuthorization authorization = + new SetCodeAuthorization( + BigInteger.ONE, + Address.fromHexString("0x633688abc3cCf8B0C03088D2d1C6ae4958c2fA56"), + Optional.of(0L), + SIGNATURE_ALGORITHM + .get() + .createSignature( + new BigInteger( + "840798fa67118e034c1eb7e42fe89e28d7cd5006dc813d5729e5f75b0d1a7ec5", 16), + new BigInteger( + "3b1dbace38ceb862a65bf2eac0637693b5c3493bcb2a022dd614c0a74cce0b99", 16), + (byte) 0)); + + SetCodeTransactionEncoder.encodeSingleSetCode(authorization, output); + + assertThat(output.encoded()) + .isEqualTo( + Bytes.fromHexString( + "0xf85b0194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c18080a0840798fa67118e034c1eb7e42fe89e28d7cd5006dc813d5729e5f75b0d1a7ec5a03b1dbace38ceb862a65bf2eac0637693b5c3493bcb2a022dd614c0a74cce0b99")); + } + + @Test + void shouldEncodeSingleSetCodeWithoutNonce() { + // "0xd70194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c5" + + final SetCodeAuthorization authorization = + new SetCodeAuthorization( + BigInteger.ONE, + Address.fromHexString("0x633688abc3cCf8B0C03088D2d1C6ae4958c2fA56"), + Optional.empty(), + SIGNATURE_ALGORITHM + .get() + .createSignature( + new BigInteger( + "dd6b24048be1b7d7fe5bbbb73ffc37eb2ce1997ecb4ae5b6096532ef19363148", 16), + new BigInteger( + "25b58a1ff8ad00bddbbfa1d5c2411961cbb6d08dcdc8ae88303db3c6cf983031", 16), + (byte) 1)); + + SetCodeTransactionEncoder.encodeSingleSetCode(authorization, output); + + assertThat(output.encoded()) + .isEqualTo( + Bytes.fromHexString( + "0xf85a0194633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c001a0dd6b24048be1b7d7fe5bbbb73ffc37eb2ce1997ecb4ae5b6096532ef19363148a025b58a1ff8ad00bddbbfa1d5c2411961cbb6d08dcdc8ae88303db3c6cf983031")); + } + + @Test + void shouldEncodeSingleSetCodeWithoutNonceAndChainIdZero() { + // "d70094633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c5" + + final SetCodeAuthorization authorization = + new SetCodeAuthorization( + BigInteger.ZERO, + Address.fromHexString("0x633688abc3cCf8B0C03088D2d1C6ae4958c2fA56"), + Optional.empty(), + SIGNATURE_ALGORITHM + .get() + .createSignature( + new BigInteger( + "25c1240d7ffec0daeedb752d3357aff2e3cd58468f0c2d43ee0ee999e02ace2", 16), + new BigInteger( + "3c8a25b2becd6e666f69803d1ae3322f2e137b7745c2c7f19da80f993ffde4df", 16), + (byte) 1)); + + SetCodeTransactionEncoder.encodeSingleSetCode(authorization, output); + + assertThat(output.encoded()) + .isEqualTo( + Bytes.fromHexString( + "0xf85a8094633688abc3ccf8b0c03088d2d1c6ae4958c2fa56c001a0025c1240d7ffec0daeedb752d3357aff2e3cd58468f0c2d43ee0ee999e02ace2a03c8a25b2becd6e666f69803d1ae3322f2e137b7745c2c7f19da80f993ffde4df")); + } +} diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java index d541cbd99..b2f5718da 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java @@ -39,6 +39,7 @@ import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.evm.worldstate.WorldView; +import java.math.BigInteger; import java.util.List; import java.util.Optional; import java.util.Set; @@ -87,7 +88,8 @@ class MainnetTransactionProcessorTest { warmCoinbase, MAX_STACK_SIZE, FeeMarket.legacy(), - CoinbaseFeePriceCalculator.frontier()); + CoinbaseFeePriceCalculator.frontier(), + new AuthorityProcessor(Optional.of(BigInteger.ONE))); } @Test diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransaction.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransaction.java index 79e8c368e..6ce8f47a7 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransaction.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransaction.java @@ -131,6 +131,7 @@ public abstract class PendingTransaction case ACCESS_LIST -> computeAccessListMemorySize(); case EIP1559 -> computeEIP1559MemorySize(); case BLOB -> computeBlobMemorySize(); + case SET_CODE -> computeSetCodeMemorySize(); } + PENDING_TRANSACTION_MEMORY_SIZE; } @@ -164,6 +165,10 @@ public abstract class PendingTransaction + computeBlobWithCommitmentsMemorySize(); } + private int computeSetCodeMemorySize() { + return 0; + } + private int computeBlobWithCommitmentsMemorySize() { final int blobCount = transaction.getBlobCount(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseTransactionPoolTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseTransactionPoolTest.java index e717adbed..bbd4e7322 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseTransactionPoolTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/BaseTransactionPoolTest.java @@ -128,7 +128,7 @@ public class BaseTransactionPoolTest { final TransactionType txType = TransactionType.values()[randomizeTxType.nextInt(4)]; return switch (txType) { - case FRONTIER, ACCESS_LIST, EIP1559 -> + case FRONTIER, ACCESS_LIST, EIP1559, SET_CODE -> createTransaction(txType, nonce, maxGasPrice, payloadSize, keys); case BLOB -> createTransaction( diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayersTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayersTest.java index a56222345..c5c2bdcf9 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayersTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/layered/LayersTest.java @@ -1377,6 +1377,7 @@ public class LayersTest extends BaseTransactionPoolTest { case ACCESS_LIST -> createAccessListPendingTransaction(sender, n); case EIP1559 -> createEIP1559PendingTransaction(sender, n); case BLOB -> createBlobPendingTransaction(sender, n); + case SET_CODE -> throw new UnsupportedOperationException(); }); } 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 ee6c5d5f7..6f222166b 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 @@ -35,6 +35,7 @@ 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; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.WithdrawalRequest; @@ -212,6 +213,69 @@ public class T8nExecutor { builder.accessList(entries); } + if (txNode.has("authorizationList")) { + JsonNode authorizationList = txNode.get("authorizationList"); + + if (!authorizationList.isArray()) { + out.printf( + "TX json node unparseable: expected authorizationList to be an array - %s%n", + txNode); + continue; + } + + List authorizations = + new ArrayList<>(authorizationList.size()); + for (JsonNode entryAsJson : authorizationList) { + final BigInteger authorizationChainId = + Bytes.fromHexStringLenient(entryAsJson.get("chainId").textValue()) + .toUnsignedBigInteger(); + final Address authorizationAddress = + Address.fromHexString(entryAsJson.get("address").textValue()); + + JsonNode nonces = entryAsJson.get("nonce"); + + if (nonces == null) { + out.printf( + "TX json node unparseable: expected nonce field to be provided - %s%n", + txNode); + continue; + } + + List authorizationNonces; + if (nonces.isArray()) { + authorizationNonces = new ArrayList<>(nonces.size()); + for (JsonNode nonceAsJson : nonces) { + authorizationNonces.add( + Bytes.fromHexStringLenient(nonceAsJson.textValue()).toLong()); + } + } else { + authorizationNonces = + List.of(Bytes.fromHexStringLenient(nonces.textValue()).toLong()); + } + + final byte authorizationV = + Bytes.fromHexStringLenient(entryAsJson.get("v").textValue()) + .toUnsignedBigInteger() + .byteValueExact(); + final BigInteger authorizationR = + Bytes.fromHexStringLenient(entryAsJson.get("r").textValue()) + .toUnsignedBigInteger(); + final BigInteger authorizationS = + Bytes.fromHexStringLenient(entryAsJson.get("s").textValue()) + .toUnsignedBigInteger(); + + authorizations.add( + SetCodeAuthorization.createSetCodeAuthorizationEntry( + authorizationChainId, + authorizationAddress, + authorizationNonces, + authorizationV, + authorizationR, + authorizationS)); + } + builder.setCodeTransactionPayloads(authorizations); + } + if (txNode.has("blobVersionedHashes")) { JsonNode blobVersionedHashes = txNode.get("blobVersionedHashes"); if (!blobVersionedHashes.isArray()) { @@ -255,7 +319,10 @@ public class T8nExecutor { Bytes.fromHexStringLenient(txNode.get("s").textValue()) .toUnsignedBigInteger(), v.byteValueExact())); - transactions.add(builder.build()); + + final Transaction tx = builder.build(); + + transactions.add(tx); } } } else { diff --git a/evm/src/main/java/org/hyperledger/besu/evm/account/AuthorizedCodeAccount.java b/evm/src/main/java/org/hyperledger/besu/evm/account/AuthorizedCodeAccount.java new file mode 100644 index 000000000..46acac74f --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/evm/account/AuthorizedCodeAccount.java @@ -0,0 +1,100 @@ +/* + * 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.evm.account; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; + +import java.util.NavigableMap; + +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.apache.tuweni.units.bigints.UInt256; + +/** Wraps an EOA account and includes authorized code to be run on behalf of it. */ +public class AuthorizedCodeAccount implements Account { + private final Account wrappedAccount; + private final Bytes authorizedCode; + + /** The hash of the authorized code. */ + protected Hash codeHash = null; + + /** + * Creates a new AuthorizedCodeAccount. + * + * @param wrappedAccount the account that has authorized code to be loaded into it. + * @param authorizedCode the authorized code. + */ + public AuthorizedCodeAccount(final Account wrappedAccount, final Bytes authorizedCode) { + this.wrappedAccount = wrappedAccount; + this.authorizedCode = authorizedCode; + } + + @Override + public Address getAddress() { + return wrappedAccount.getAddress(); + } + + @Override + public boolean isStorageEmpty() { + return wrappedAccount.isStorageEmpty(); + } + + @Override + public Hash getAddressHash() { + return wrappedAccount.getAddressHash(); + } + + @Override + public long getNonce() { + return wrappedAccount.getNonce(); + } + + @Override + public Wei getBalance() { + return wrappedAccount.getBalance(); + } + + @Override + public Bytes getCode() { + return authorizedCode; + } + + @Override + public Hash getCodeHash() { + if (codeHash == null) { + codeHash = authorizedCode.equals(Bytes.EMPTY) ? Hash.EMPTY : Hash.hash(authorizedCode); + } + + return codeHash; + } + + @Override + public UInt256 getStorageValue(final UInt256 key) { + return wrappedAccount.getStorageValue(key); + } + + @Override + public UInt256 getOriginalStorageValue(final UInt256 key) { + return wrappedAccount.getOriginalStorageValue(key); + } + + @Override + public NavigableMap storageEntriesFrom( + final Bytes32 startKeyHash, final int limit) { + return wrappedAccount.storageEntriesFrom(startKeyHash, limit); + } +} diff --git a/evm/src/main/java/org/hyperledger/besu/evm/account/MutableAuthorizedCodeAccount.java b/evm/src/main/java/org/hyperledger/besu/evm/account/MutableAuthorizedCodeAccount.java new file mode 100644 index 000000000..6d4e30a9c --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/evm/account/MutableAuthorizedCodeAccount.java @@ -0,0 +1,138 @@ +/* + * 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.evm.account; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; + +import java.util.Map; +import java.util.NavigableMap; + +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.apache.tuweni.units.bigints.UInt256; + +/** Wraps a mutable EOA account and includes authorized code to be run on behalf of it. */ +public class MutableAuthorizedCodeAccount implements MutableAccount { + + private final MutableAccount wrappedAccount; + private final Bytes authorizedCode; + + /** The hash of the authorized code. */ + protected Hash codeHash = null; + + /** + * Creates a new MutableAuthorizedCodeAccount. + * + * @param wrappedAccount the account that has authorized code to be loaded into it. + * @param authorizedCode the authorized code. + */ + public MutableAuthorizedCodeAccount( + final MutableAccount wrappedAccount, final Bytes authorizedCode) { + this.wrappedAccount = wrappedAccount; + this.authorizedCode = authorizedCode; + } + + @Override + public Address getAddress() { + return wrappedAccount.getAddress(); + } + + @Override + public boolean isStorageEmpty() { + return wrappedAccount.isStorageEmpty(); + } + + @Override + public Hash getAddressHash() { + return wrappedAccount.getAddressHash(); + } + + @Override + public long getNonce() { + return wrappedAccount.getNonce(); + } + + @Override + public Wei getBalance() { + return wrappedAccount.getBalance(); + } + + @Override + public Bytes getCode() { + return authorizedCode; + } + + @Override + public Hash getCodeHash() { + if (codeHash == null) { + codeHash = authorizedCode.equals(Bytes.EMPTY) ? Hash.EMPTY : Hash.hash(authorizedCode); + } + + return codeHash; + } + + @Override + public UInt256 getStorageValue(final UInt256 key) { + return wrappedAccount.getStorageValue(key); + } + + @Override + public UInt256 getOriginalStorageValue(final UInt256 key) { + return wrappedAccount.getOriginalStorageValue(key); + } + + @Override + public NavigableMap storageEntriesFrom( + final Bytes32 startKeyHash, final int limit) { + return wrappedAccount.storageEntriesFrom(startKeyHash, limit); + } + + @Override + public void setNonce(final long value) { + wrappedAccount.setNonce(value); + } + + @Override + public void setBalance(final Wei value) { + wrappedAccount.setBalance(value); + } + + @Override + public void setCode(final Bytes code) { + throw new RuntimeException("Cannot set code on an AuthorizedCodeAccount"); + } + + @Override + public void setStorageValue(final UInt256 key, final UInt256 value) { + wrappedAccount.setStorageValue(key, value); + } + + @Override + public void clearStorage() { + wrappedAccount.clearStorage(); + } + + @Override + public Map getUpdatedStorage() { + return wrappedAccount.getUpdatedStorage(); + } + + @Override + public void becomeImmutable() { + wrappedAccount.becomeImmutable(); + } +} diff --git a/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleWorld.java b/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleWorld.java index f52e788ba..c64ca3744 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleWorld.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/fluent/SimpleWorld.java @@ -18,6 +18,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.account.MutableAccount; +import org.hyperledger.besu.evm.worldstate.AuthorizedCodeService; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import java.util.Collection; @@ -34,6 +35,8 @@ public class SimpleWorld implements WorldUpdater { /** The Accounts. */ Map accounts = new HashMap<>(); + private AuthorizedCodeService authorizedCodeService; + /** Instantiates a new Simple world. */ public SimpleWorld() { this(null); @@ -46,6 +49,7 @@ public class SimpleWorld implements WorldUpdater { */ public SimpleWorld(final SimpleWorld parent) { this.parent = parent; + this.authorizedCodeService = new AuthorizedCodeService(); } @Override @@ -56,11 +60,11 @@ public class SimpleWorld implements WorldUpdater { @Override public Account get(final Address address) { if (accounts.containsKey(address)) { - return accounts.get(address); + return authorizedCodeService.processAccount(this, accounts.get(address), address); } else if (parent != null) { - return parent.get(address); + return authorizedCodeService.processAccount(this, parent.get(address), address); } else { - return null; + return authorizedCodeService.processAccount(this, null, address); } } @@ -71,14 +75,14 @@ public class SimpleWorld implements WorldUpdater { } SimpleAccount account = new SimpleAccount(address, nonce, balance); accounts.put(address, account); - return account; + return authorizedCodeService.processMutableAccount(this, account, address); } @Override public MutableAccount getAccount(final Address address) { SimpleAccount account = accounts.get(address); if (account != null) { - return account; + return authorizedCodeService.processMutableAccount(this, account, address); } Account parentAccount = parent == null ? null : parent.getAccount(address); if (parentAccount != null) { @@ -90,9 +94,9 @@ public class SimpleWorld implements WorldUpdater { parentAccount.getBalance(), parentAccount.getCode()); accounts.put(address, account); - return account; + return authorizedCodeService.processMutableAccount(this, account, address); } - return null; + return authorizedCodeService.processMutableAccount(this, null, address); } @Override @@ -132,4 +136,9 @@ public class SimpleWorld implements WorldUpdater { public Optional parentUpdater() { return Optional.ofNullable(parent); } + + @Override + public void setAuthorizedCodeService(final AuthorizedCodeService authorizedCodeService) { + this.authorizedCodeService = authorizedCodeService; + } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java b/evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java index e01c91551..cf7761922 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/frame/MessageFrame.java @@ -33,6 +33,7 @@ import org.hyperledger.besu.evm.internal.UnderflowException; import org.hyperledger.besu.evm.log.Log; import org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup; import org.hyperledger.besu.evm.operation.Operation; +import org.hyperledger.besu.evm.worldstate.AuthorizedCodeService; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import java.util.ArrayDeque; @@ -201,6 +202,7 @@ public class MessageFrame { // Global data fields. private final WorldUpdater worldUpdater; + private final AuthorizedCodeService authorizedCodeService; // Metadata fields. private final Type type; @@ -270,7 +272,8 @@ public class MessageFrame { final Consumer completer, final Map contextVariables, final Optional revertReason, - final TxValues txValues) { + final TxValues txValues, + final AuthorizedCodeService authorizedCodeService) { this.txValues = txValues; this.type = type; @@ -290,6 +293,7 @@ public class MessageFrame { this.completer = completer; this.contextVariables = contextVariables; this.revertReason = revertReason; + this.authorizedCodeService = authorizedCodeService; this.undoMark = txValues.transientStorage().mark(); } @@ -423,6 +427,15 @@ public class MessageFrame { return returnData; } + /** + * Return the authorized account service. + * + * @return the authorized account service + */ + public AuthorizedCodeService getAuthorizedCodeService() { + return authorizedCodeService; + } + /** * Set the return data. * @@ -1347,6 +1360,7 @@ public class MessageFrame { private Optional reason = Optional.empty(); private Set
accessListWarmAddresses = emptySet(); private Multimap accessListWarmStorage = HashMultimap.create(); + private AuthorizedCodeService authorizedCodeService; private Optional> versionedHashes = Optional.empty(); @@ -1631,6 +1645,17 @@ public class MessageFrame { return this; } + /** + * Sets authorized account service. + * + * @param authorizedCodeService the authorized account service + * @return the builder + */ + public Builder authorizedCodeService(final AuthorizedCodeService authorizedCodeService) { + this.authorizedCodeService = authorizedCodeService; + return this; + } + private void validate() { if (parentMessageFrame == null) { checkState(worldUpdater != null, "Missing message frame world updater"); @@ -1664,6 +1689,11 @@ public class MessageFrame { WorldUpdater updater; boolean newStatic; TxValues newTxValues; + + if (authorizedCodeService == null) { + authorizedCodeService = new AuthorizedCodeService(); + } + if (parentMessageFrame == null) { newTxValues = new TxValues( @@ -1686,10 +1716,12 @@ public class MessageFrame { newStatic = isStatic; } else { newTxValues = parentMessageFrame.txValues; - updater = parentMessageFrame.worldUpdater.updater(); + updater = parentMessageFrame.getWorldUpdater().updater(); newStatic = isStatic || parentMessageFrame.isStatic; } + updater.setAuthorizedCodeService(authorizedCodeService); + MessageFrame messageFrame = new MessageFrame( type, @@ -1706,7 +1738,8 @@ public class MessageFrame { completer, contextVariables == null ? Map.of() : contextVariables, reason, - newTxValues); + newTxValues, + authorizedCodeService); newTxValues.messageFrameStack().addFirst(messageFrame); messageFrame.warmUpAddress(sender); messageFrame.warmUpAddress(contract); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java index 2e1728b23..0af023851 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java @@ -645,4 +645,14 @@ public interface GasCalculator { default long computeExcessBlobGas(final long parentExcessBlobGas, final long blobGasUsed) { return 0L; } + + /** + * Returns the upfront gas cost for EIP 7702 operation. + * + * @param authorizationListLength The length of the authorization list + * @return the gas cost + */ + default long setCodeListGasCost(final int authorizationListLength) { + return 0L; + } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculator.java index e2789bba3..0c223d780 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculator.java @@ -28,6 +28,8 @@ import static org.hyperledger.besu.datatypes.Address.BLS12_MAP_FP2_TO_G2; */ public class PragueGasCalculator extends CancunGasCalculator { + static final long PER_CONTRACT_CODE_BASE_COST = 2500L; + /** Instantiates a new Prague Gas Calculator. */ public PragueGasCalculator() { this(BLS12_MAP_FP2_TO_G2.toArrayUnsafe()[19]); @@ -41,4 +43,9 @@ public class PragueGasCalculator extends CancunGasCalculator { protected PragueGasCalculator(final int maxPrecompile) { super(maxPrecompile); } + + @Override + public long setCodeListGasCost(final int authorizationListLength) { + return PER_CONTRACT_CODE_BASE_COST * authorizationListLength; + } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCallOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCallOperation.java index 8a8226220..762030bf3 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCallOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCallOperation.java @@ -230,6 +230,7 @@ public abstract class AbstractCallOperation extends AbstractOperation { .code(code) .isStatic(isStatic(frame)) .completer(child -> complete(frame, child)) + .authorizedCodeService(frame.getAuthorizedCodeService()) .build(); // see note in stack depth check about incrementing cost frame.incrementRemainingGas(cost); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java index f20c2914a..16ea218f9 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCreateOperation.java @@ -195,6 +195,7 @@ public abstract class AbstractCreateOperation extends AbstractOperation { .apparentValue(value) .code(code) .completer(child -> complete(parent, child, evm)) + .authorizedCodeService(parent.getAuthorizedCodeService()) .build(); parent.setState(MessageFrame.State.CODE_SUSPENDED); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractExtCallOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractExtCallOperation.java index 43d7e343f..e19b6cd8a 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractExtCallOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractExtCallOperation.java @@ -180,6 +180,7 @@ public abstract class AbstractExtCallOperation extends AbstractCallOperation { .code(code) .isStatic(isStatic(frame)) .completer(child -> complete(frame, child)) + .authorizedCodeService(frame.getAuthorizedCodeService()) .build(); frame.setState(MessageFrame.State.CODE_SUSPENDED); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/worldstate/AbstractWorldUpdater.java b/evm/src/main/java/org/hyperledger/besu/evm/worldstate/AbstractWorldUpdater.java index 9623eaf89..00cd67ddb 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/worldstate/AbstractWorldUpdater.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/worldstate/AbstractWorldUpdater.java @@ -43,6 +43,9 @@ public abstract class AbstractWorldUpdater> updatedAccounts = new ConcurrentHashMap<>(); @@ -59,6 +62,7 @@ public abstract class AbstractWorldUpdater account = new UpdateTrackingAccount<>(address); account.setNonce(nonce); account.setBalance(balance); - return track(account); + return authorizedCodeService.processMutableAccount(this, track(account), address); } @Override @@ -95,12 +99,12 @@ public abstract class AbstractWorldUpdater(origin)); + return authorizedCodeService.processMutableAccount( + this, track(new UpdateTrackingAccount<>(origin)), address); } } @@ -165,6 +170,11 @@ public abstract class AbstractWorldUpdater authorizedCode = new HashMap<>(); + + /** Creates a new AuthorizedCodeService. */ + public AuthorizedCodeService() {} + + /** + * Authorizes to load the code of authorizedCode into the authorizer account. + * + * @param authorizer the address that gives the authorization. + * @param authorizedCode the code which will be loaded. + */ + public void addAuthorizedCode(final Address authorizer, final Bytes authorizedCode) { + this.authorizedCode.put(authorizer, authorizedCode); + } + + /** + * Return all the authorities that have given their authorization to load the code of another + * account. + * + * @return the set of authorities. + */ + public Set
getAuthorities() { + return authorizedCode.keySet(); + } + + /** Resets all the authorized accounts. */ + public void resetAuthorities() { + authorizedCode.clear(); + } + + /** + * Checks if the provided address has set an authorized to load code into an EOA account. + * + * @param authority the address to check. + * @return {@code true} if the address has been authorized, {@code false} otherwise. + */ + public boolean hasAuthorizedCode(final Address authority) { + return authorizedCode.containsKey(authority); + } + + /** + * Processes the provided account, injecting the authorized code if authorized. + * + * @param worldUpdater the world updater to retrieve the code account. + * @param originalAccount the account to process. + * @param address the address of the account in case the provided account is null + * @return the processed account, containing the authorized code if authorized. + */ + public Account processAccount( + final WorldUpdater worldUpdater, final Account originalAccount, final Address address) { + if (!authorizedCode.containsKey(address)) { + return originalAccount; + } + + Account account = originalAccount; + if (account == null) { + account = worldUpdater.createAccount(address); + } + + return new AuthorizedCodeAccount(account, authorizedCode.get(address)); + } + + /** + * Processes the provided mutable account, injecting the authorized code if authorized. + * + * @param worldUpdater the world updater to retrieve the code account. + * @param originalAccount the mutable account to process. + * @param address the address of the account in case the provided account is null + * @return the processed mutable account, containing the authorized code if authorized. + */ + public MutableAccount processMutableAccount( + final WorldUpdater worldUpdater, + final MutableAccount originalAccount, + final Address address) { + if (!authorizedCode.containsKey(address)) { + return originalAccount; + } + + MutableAccount account = originalAccount; + if (account == null) { + account = worldUpdater.createAccount(address); + } + + return new MutableAuthorizedCodeAccount(account, authorizedCode.get(address)); + } +} diff --git a/evm/src/main/java/org/hyperledger/besu/evm/worldstate/JournaledUpdater.java b/evm/src/main/java/org/hyperledger/besu/evm/worldstate/JournaledUpdater.java index 9987a5be7..2497ed348 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/worldstate/JournaledUpdater.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/worldstate/JournaledUpdater.java @@ -41,6 +41,7 @@ public class JournaledUpdater implements WorldUpdater { final UndoMap accounts; final UndoSet
deleted; final long undoMark; + private AuthorizedCodeService authorizedCodeService; /** * Instantiates a new Stacked updater. @@ -66,6 +67,7 @@ public class JournaledUpdater implements WorldUpdater { "WorldUpdater must be a JournaledWorldUpdater or an AbstractWorldUpdater"); } undoMark = accounts.mark(); + this.authorizedCodeService = new AuthorizedCodeService(); } /** @@ -126,12 +128,18 @@ public class JournaledUpdater implements WorldUpdater { accounts.values().forEach(JournaledAccount::markTransactionBoundary); } + @Override + public void setAuthorizedCodeService(final AuthorizedCodeService authorizedCodeService) { + this.authorizedCodeService = authorizedCodeService; + } + @Override public MutableAccount createAccount(final Address address, final long nonce, final Wei balance) { JournaledAccount journaledAccount = new JournaledAccount(rootWorld.createAccount(address, nonce, balance)); accounts.put(address, journaledAccount); - return new JournaledAccount(journaledAccount); + return authorizedCodeService.processMutableAccount( + this, new JournaledAccount(journaledAccount), address); } @Override @@ -139,7 +147,7 @@ public class JournaledUpdater implements WorldUpdater { // We may have updated it already, so check that first. final JournaledAccount existing = accounts.get(address); if (existing != null) { - return existing; + return authorizedCodeService.processMutableAccount(this, existing, address); } if (deleted.contains(address)) { return null; @@ -148,11 +156,11 @@ public class JournaledUpdater implements WorldUpdater { // Otherwise, get it from our wrapped view and create a new update tracker. final MutableAccount origin = rootWorld.getAccount(address); if (origin == null) { - return null; + return authorizedCodeService.processMutableAccount(this, null, address); } else { var newAccount = new JournaledAccount(origin); accounts.put(address, newAccount); - return newAccount; + return authorizedCodeService.processMutableAccount(this, newAccount, address); } } @@ -169,12 +177,12 @@ public class JournaledUpdater implements WorldUpdater { public Account get(final Address address) { final MutableAccount existing = accounts.get(address); if (existing != null) { - return existing; + return authorizedCodeService.processAccount(this, existing, address); } if (deleted.contains(address)) { - return null; + return authorizedCodeService.processAccount(this, null, address); } - return rootWorld.get(address); + return authorizedCodeService.processAccount(this, rootWorld.get(address), address); } @Override diff --git a/evm/src/main/java/org/hyperledger/besu/evm/worldstate/WorldUpdater.java b/evm/src/main/java/org/hyperledger/besu/evm/worldstate/WorldUpdater.java index 4cbda7327..5144176e7 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/worldstate/WorldUpdater.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/worldstate/WorldUpdater.java @@ -179,4 +179,12 @@ public interface WorldUpdater extends MutableWorldView { default void markTransactionBoundary() { // default is to ignore } + + /** + * Sets the {@link AuthorizedCodeService} associated with this {@link WorldUpdater}. + * + * @param authorizedCodeService the {@link AuthorizedCodeService} to associate with this {@link + * WorldUpdater} + */ + void setAuthorizedCodeService(AuthorizedCodeService authorizedCodeService); } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/toy/ToyWorld.java b/evm/src/test/java/org/hyperledger/besu/evm/toy/ToyWorld.java index e1e9c4c3a..479376a8f 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/toy/ToyWorld.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/toy/ToyWorld.java @@ -18,6 +18,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.account.MutableAccount; +import org.hyperledger.besu.evm.worldstate.AuthorizedCodeService; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import java.util.Collection; @@ -32,6 +33,7 @@ public class ToyWorld implements WorldUpdater { ToyWorld parent; Map accounts = new HashMap<>(); + private AuthorizedCodeService authorizedCodeService; public ToyWorld() { this(null); @@ -39,6 +41,7 @@ public class ToyWorld implements WorldUpdater { public ToyWorld(final ToyWorld parent) { this.parent = parent; + this.authorizedCodeService = new AuthorizedCodeService(); } @Override @@ -49,11 +52,11 @@ public class ToyWorld implements WorldUpdater { @Override public Account get(final Address address) { if (accounts.containsKey(address)) { - return accounts.get(address); + return authorizedCodeService.processAccount(this, accounts.get(address), address); } else if (parent != null) { - return parent.get(address); + return authorizedCodeService.processAccount(this, parent.get(address), address); } else { - return null; + return authorizedCodeService.processAccount(this, null, address); } } @@ -70,17 +73,17 @@ public class ToyWorld implements WorldUpdater { final Bytes code) { ToyAccount account = new ToyAccount(parentAccount, address, nonce, balance, code); accounts.put(address, account); - return account; + return authorizedCodeService.processMutableAccount(this, account, address); } @Override public MutableAccount getAccount(final Address address) { if (accounts.containsKey(address)) { - return accounts.get(address); + return authorizedCodeService.processMutableAccount(this, accounts.get(address), address); } else if (parent != null) { Account parentAccount = parent.getAccount(address); if (parentAccount == null) { - return null; + return authorizedCodeService.processMutableAccount(this, null, address); } else { return createAccount( parentAccount, @@ -90,7 +93,7 @@ public class ToyWorld implements WorldUpdater { parentAccount.getCode()); } } else { - return null; + return authorizedCodeService.processMutableAccount(this, null, address); } } @@ -128,4 +131,9 @@ public class ToyWorld implements WorldUpdater { public Optional parentUpdater() { return Optional.empty(); } + + @Override + public void setAuthorizedCodeService(final AuthorizedCodeService authorizedCodeService) { + this.authorizedCodeService = authorizedCodeService; + } } From 8eef2df494ccd9bf3d6a69caf828ebb226acfb88 Mon Sep 17 00:00:00 2001 From: garyschulte Date: Wed, 17 Jul 2024 13:45:40 -0700 Subject: [PATCH 05/14] Feature/use gnark-crypto for eip-196 precompiles (#7262) * squash commit, use gnark-crypto for eip-196 * use besu-native 0.9.3 Signed-off-by: garyschulte --- CHANGELOG.md | 4 +- .../AbstractAltBnPrecompiledContract.java | 23 +++--- .../AltBN128AddPrecompiledContract.java | 4 +- .../AltBN128MulPrecompiledContract.java | 4 +- .../AltBN128PairingPrecompiledContract.java | 4 +- gradle/verification-metadata.xml | 70 +++++++++---------- gradle/versions.gradle | 2 +- 7 files changed, 57 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6b28d0a5..5fb35c2e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,10 +10,12 @@ - `--Xsnapsync-bft-enabled` option enables experimental support for snap sync with IBFT/QBFT permissioned Bonsai-DB chains [#7140](https://github.com/hyperledger/besu/pull/7140) - Add support to load external profiles using `--profile` [#7265](https://github.com/hyperledger/besu/issues/7265) - `privacy-nonce-always-increments` option enables private transactions to always increment the nonce, even if the transaction is invalid [#6593](https://github.com/hyperledger/besu/pull/6593) -- Add `block-test` subcommand to the evmtool which runs blockchain reference tests [#7310](https://github.com/hyperledger/besu/pull/7310) +- Added `block-test` subcommand to the evmtool which runs blockchain reference tests [#7293](https://github.com/hyperledger/besu/pull/7293) +- removed PKI backed QBFT [#7310](https://github.com/hyperledger/besu/pull/7310) - Implement gnark-crypto for eip-2537 [#7316](https://github.com/hyperledger/besu/pull/7316) - Improve blob size transaction selector [#7312](https://github.com/hyperledger/besu/pull/7312) - Added EIP-7702 [#7237](https://github.com/hyperledger/besu/pull/7237) +- implement gnark-crypto for eip-196 [#7262](https://github.com/hyperledger/besu/pull/7262) ### Bug fixes - Fix `eth_call` deserialization to correctly ignore unknown fields in the transaction object. [#7323](https://github.com/hyperledger/besu/pull/7323) diff --git a/evm/src/main/java/org/hyperledger/besu/evm/precompile/AbstractAltBnPrecompiledContract.java b/evm/src/main/java/org/hyperledger/besu/evm/precompile/AbstractAltBnPrecompiledContract.java index 84ce6c6cf..5f8e4b0a8 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/precompile/AbstractAltBnPrecompiledContract.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/precompile/AbstractAltBnPrecompiledContract.java @@ -19,7 +19,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.gascalculator.GasCalculator; -import org.hyperledger.besu.nativelib.bls12_381.LibEthPairings; +import org.hyperledger.besu.nativelib.gnark.LibGnarkEIP196; import java.util.Optional; import javax.annotation.Nonnull; @@ -49,7 +49,7 @@ public abstract class AbstractAltBnPrecompiledContract extends AbstractPrecompil */ public static boolean maybeEnableNative() { try { - useNative = LibEthPairings.ENABLED; + useNative = LibGnarkEIP196.ENABLED; } catch (UnsatisfiedLinkError | NoClassDefFoundError ule) { LOG.info("altbn128 native precompile not available: {}", ule.getMessage()); useNative = false; @@ -72,7 +72,7 @@ public abstract class AbstractAltBnPrecompiledContract extends AbstractPrecompil } private final byte operationId; - private final int inputLen; + private final int inputLimit; /** * Instantiates a new Abstract alt bn precompiled contract. @@ -89,9 +89,9 @@ public abstract class AbstractAltBnPrecompiledContract extends AbstractPrecompil final int inputLen) { super(name, gasCalculator); this.operationId = operationId; - this.inputLen = inputLen + 1; + this.inputLimit = inputLen + 1; - if (!LibEthPairings.ENABLED) { + if (!LibGnarkEIP196.ENABLED) { LOG.info("Native alt bn128 not available"); } } @@ -106,16 +106,16 @@ public abstract class AbstractAltBnPrecompiledContract extends AbstractPrecompil @Nonnull public PrecompileContractResult computeNative( final @Nonnull Bytes input, final MessageFrame messageFrame) { - final byte[] result = new byte[LibEthPairings.EIP196_PREALLOCATE_FOR_RESULT_BYTES]; - final byte[] error = new byte[LibEthPairings.EIP2537_PREALLOCATE_FOR_ERROR_BYTES]; + final byte[] result = new byte[LibGnarkEIP196.EIP196_PREALLOCATE_FOR_RESULT_BYTES]; + final byte[] error = new byte[LibGnarkEIP196.EIP196_PREALLOCATE_FOR_ERROR_BYTES]; final IntByReference o_len = - new IntByReference(LibEthPairings.EIP196_PREALLOCATE_FOR_RESULT_BYTES); + new IntByReference(LibGnarkEIP196.EIP196_PREALLOCATE_FOR_RESULT_BYTES); final IntByReference err_len = - new IntByReference(LibEthPairings.EIP2537_PREALLOCATE_FOR_ERROR_BYTES); - final int inputSize = Math.min(inputLen, input.size()); + new IntByReference(LibGnarkEIP196.EIP196_PREALLOCATE_FOR_ERROR_BYTES); + final int inputSize = Math.min(inputLimit, input.size()); final int errorNo = - LibEthPairings.eip196_perform_operation( + LibGnarkEIP196.eip196_perform_operation( operationId, input.slice(0, inputSize).toArrayUnsafe(), inputSize, @@ -123,6 +123,7 @@ public abstract class AbstractAltBnPrecompiledContract extends AbstractPrecompil o_len, error, err_len); + if (errorNo == 0) { return PrecompileContractResult.success(Bytes.wrap(result, 0, o_len.getValue())); } else { diff --git a/evm/src/main/java/org/hyperledger/besu/evm/precompile/AltBN128AddPrecompiledContract.java b/evm/src/main/java/org/hyperledger/besu/evm/precompile/AltBN128AddPrecompiledContract.java index 026a78c4a..8aaa27658 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/precompile/AltBN128AddPrecompiledContract.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/precompile/AltBN128AddPrecompiledContract.java @@ -19,7 +19,7 @@ import org.hyperledger.besu.crypto.altbn128.Fq; import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.gascalculator.GasCalculator; -import org.hyperledger.besu.nativelib.bls12_381.LibEthPairings; +import org.hyperledger.besu.nativelib.gnark.LibGnarkEIP196; import java.math.BigInteger; import java.util.Arrays; @@ -40,7 +40,7 @@ public class AltBN128AddPrecompiledContract extends AbstractAltBnPrecompiledCont super( "AltBN128Add", gasCalculator, - LibEthPairings.EIP196_ADD_OPERATION_RAW_VALUE, + LibGnarkEIP196.EIP196_ADD_OPERATION_RAW_VALUE, PARAMETER_LENGTH); this.gasCost = gasCost; } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/precompile/AltBN128MulPrecompiledContract.java b/evm/src/main/java/org/hyperledger/besu/evm/precompile/AltBN128MulPrecompiledContract.java index 73b824f76..25399d9e7 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/precompile/AltBN128MulPrecompiledContract.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/precompile/AltBN128MulPrecompiledContract.java @@ -19,7 +19,7 @@ import org.hyperledger.besu.crypto.altbn128.Fq; import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.gascalculator.GasCalculator; -import org.hyperledger.besu.nativelib.bls12_381.LibEthPairings; +import org.hyperledger.besu.nativelib.gnark.LibGnarkEIP196; import java.math.BigInteger; import java.util.Arrays; @@ -44,7 +44,7 @@ public class AltBN128MulPrecompiledContract extends AbstractAltBnPrecompiledCont super( "AltBN128Mul", gasCalculator, - LibEthPairings.EIP196_MUL_OPERATION_RAW_VALUE, + LibGnarkEIP196.EIP196_MUL_OPERATION_RAW_VALUE, PARAMETER_LENGTH); this.gasCost = gasCost; } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/precompile/AltBN128PairingPrecompiledContract.java b/evm/src/main/java/org/hyperledger/besu/evm/precompile/AltBN128PairingPrecompiledContract.java index 82496d4e3..e6cd89223 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/precompile/AltBN128PairingPrecompiledContract.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/precompile/AltBN128PairingPrecompiledContract.java @@ -23,7 +23,7 @@ import org.hyperledger.besu.crypto.altbn128.Fq2; import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.gascalculator.GasCalculator; -import org.hyperledger.besu.nativelib.bls12_381.LibEthPairings; +import org.hyperledger.besu.nativelib.gnark.LibGnarkEIP196; import java.math.BigInteger; import java.util.ArrayList; @@ -56,7 +56,7 @@ public class AltBN128PairingPrecompiledContract extends AbstractAltBnPrecompiled super( "AltBN128Pairing", gasCalculator, - LibEthPairings.EIP196_PAIR_OPERATION_RAW_VALUE, + LibGnarkEIP196.EIP196_PAIR_OPERATION_RAW_VALUE, Integer.MAX_VALUE / PARAMETER_LENGTH * PARAMETER_LENGTH); this.pairingGasCost = pairingGasCost; this.baseGasCost = baseGasCost; diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index bd437c3a4..7cdf7ce08 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -4632,12 +4632,12 @@ - - - + + + - - + + @@ -4648,52 +4648,52 @@ - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + diff --git a/gradle/versions.gradle b/gradle/versions.gradle index 0c2289233..6d176ba7e 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -156,7 +156,7 @@ dependencyManagement { dependency 'org.openjdk.jol:jol-core:0.17' dependency 'tech.pegasys:jc-kzg-4844:1.0.0' - dependencySet(group: 'org.hyperledger.besu', version: '0.9.2') { + dependencySet(group: 'org.hyperledger.besu', version: '0.9.3') { entry 'arithmetic' entry 'ipa-multipoint' entry 'bls12-381' From 3925ee4a80add4e0f4353b47b52f2b9d01442882 Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Thu, 18 Jul 2024 10:04:48 +1000 Subject: [PATCH 06/14] exclude permissioning test from default ATs run on PRs (#7327) * exclude permissioning test from default ATs run on PRs Signed-off-by: Sally MacFarlane --------- Signed-off-by: Sally MacFarlane --- acceptance-tests/tests/build.gradle | 32 ++--------------------------- 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/acceptance-tests/tests/build.gradle b/acceptance-tests/tests/build.gradle index 1bc0e5556..953d1859e 100644 --- a/acceptance-tests/tests/build.gradle +++ b/acceptance-tests/tests/build.gradle @@ -122,39 +122,11 @@ task acceptanceTest(type: Test) { doFirst { mkdir "${buildDir}/jvmErrorLogs" } } -task acceptanceTestMainnet(type: Test) { - inputs.property "integration.date", LocalTime.now() // so it runs at every invocation - exclude '**/bft/**' - exclude '**/clique/**' - exclude '**/permissioning/**' - exclude '**/privacy/**' - - useJUnitPlatform {} - - dependsOn(rootProject.installDist) - setSystemProperties(test.getSystemProperties()) - systemProperty 'acctests.runBesuAsProcess', 'true' - systemProperty 'java.security.properties', "${buildDir}/resources/test/acceptanceTesting.security" - mustRunAfter rootProject.subprojects*.test - description = 'Runs MAINNET Besu acceptance tests (excluding permissioning, privacy and some other stable features).' - group = 'verification' - - jvmArgs "-XX:ErrorFile=${buildDir}/jvmErrorLogs/java_err_pid%p.log" - - testLogging { - exceptionFormat = 'full' - showStackTraces = true - showStandardStreams = Boolean.getBoolean('acctests.showStandardStreams') - showExceptions = true - showCauses = true - } - - doFirst { mkdir "${buildDir}/jvmErrorLogs" } -} task acceptanceTestNotPrivacy(type: Test) { inputs.property "integration.date", LocalTime.now() // so it runs at every invocation exclude '**/privacy/**' + exclude '**/permissioning/**' exclude '**/bftsoak/**' useJUnitPlatform {} @@ -164,7 +136,7 @@ task acceptanceTestNotPrivacy(type: Test) { systemProperty 'acctests.runBesuAsProcess', 'true' systemProperty 'java.security.properties', "${buildDir}/resources/test/acceptanceTesting.security" mustRunAfter rootProject.subprojects*.test - description = 'Runs MAINNET Besu acceptance tests (excluding privacy since they run nightly, and are being refactored).' + description = 'Runs MAINNET Besu acceptance tests (excluding specific non-mainnet suites).' group = 'verification' jvmArgs "-XX:ErrorFile=${buildDir}/jvmErrorLogs/java_err_pid%p.log" From cee973d429e41391927eb611b93b046eeba1c540 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Thu, 18 Jul 2024 10:28:29 +1000 Subject: [PATCH 07/14] [minor] Remove redundant info from plugin summary (#7339) Signed-off-by: Gabriel-Trintinalia --- .../besu/services/BesuPluginContextImpl.java | 18 ++++++++---------- plugin-api/build.gradle | 2 +- .../hyperledger/besu/plugin/BesuPlugin.java | 2 +- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/besu/src/main/java/org/hyperledger/besu/services/BesuPluginContextImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BesuPluginContextImpl.java index 6aa64ac51..ddf694029 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BesuPluginContextImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BesuPluginContextImpl.java @@ -379,22 +379,20 @@ public class BesuPluginContextImpl implements BesuContext, PluginVersionsProvide plugin -> summary.add( String.format( - " - %s (Version: %s)", - plugin.getClass().getSimpleName(), plugin.getVersion()))); + " - %s (%s)", plugin.getClass().getSimpleName(), plugin.getVersion()))); } // Identify and log detected but not registered (skipped) plugins - List skippedPlugins = - detectedPlugins.stream() - .filter(plugin -> !registeredPlugins.contains(plugin)) - .map(plugin -> plugin.getClass().getSimpleName()) - .toList(); + List skippedPlugins = + detectedPlugins.stream().filter(plugin -> !registeredPlugins.contains(plugin)).toList(); if (!skippedPlugins.isEmpty()) { - summary.add("Skipped Plugins:"); + summary.add("Detected but not registered:"); skippedPlugins.forEach( - pluginName -> - summary.add(String.format(" - %s (Detected but not registered)", pluginName))); + plugin -> + summary.add( + String.format( + " - %s (%s)", plugin.getClass().getSimpleName(), plugin.getVersion()))); } summary.add( String.format( diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index 1ea78e7f3..58c241509 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 = 'vWxI4pduLCvzqU73k5kJsoeK9t7QTqOBC9IxksFuzBs=' + knownHash = 'F07ix5Mkvycb2W2luprKmcMyrWcSLB4Xtou5Id10DW0=' } check.dependsOn('checkAPIChanges') diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/BesuPlugin.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/BesuPlugin.java index 952f1fb07..1d7acf3a3 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/BesuPlugin.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/BesuPlugin.java @@ -105,6 +105,6 @@ public interface BesuPlugin { Optional.ofNullable(pluginPackage.getImplementationVersion()) .filter(version -> !version.isBlank()) .orElse(""); - return implTitle + "/v" + implVersion; + return implTitle + "/" + implVersion; } } From 39e276fd10b0c2c28e1893efc6303f4857d40218 Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Thu, 18 Jul 2024 11:29:17 +1000 Subject: [PATCH 08/14] Refactor - eliminate non-constant string concatenation from debug and trace (#7336) * eliminate non-constant string concatenation from debug and trace Signed-off-by: Sally MacFarlane * adjustments Signed-off-by: Sally MacFarlane --------- Signed-off-by: Sally MacFarlane --- besu/src/main/java/org/hyperledger/besu/Runner.java | 2 +- .../besu/ethereum/chain/ChainDataPruner.java | 2 +- .../common/DiffBasedWorldStateProvider.java | 12 ++++++------ .../besu/ethereum/eth/manager/EthPeer.java | 6 +++++- .../besu/ethereum/eth/manager/EthScheduler.java | 7 +++++-- .../eth/manager/snap/SnapProtocolManager.java | 9 +++++---- .../hyperledger/besu/nat/upnp/UpnpNatManager.java | 5 ++++- 7 files changed, 27 insertions(+), 16 deletions(-) diff --git a/besu/src/main/java/org/hyperledger/besu/Runner.java b/besu/src/main/java/org/hyperledger/besu/Runner.java index 4444f7acf..eed35a03a 100644 --- a/besu/src/main/java/org/hyperledger/besu/Runner.java +++ b/besu/src/main/java/org/hyperledger/besu/Runner.java @@ -253,7 +253,7 @@ public class Runner implements AutoCloseable { try { shutdown.await(); } catch (final InterruptedException e) { - LOG.debug("Interrupted while waiting for service " + serviceName + " to stop", e); + LOG.debug("Interrupted while waiting for service {} to stop {}", serviceName, e); Thread.currentThread().interrupt(); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/ChainDataPruner.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/ChainDataPruner.java index 11a1500e4..37025feca 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/ChainDataPruner.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/ChainDataPruner.java @@ -76,7 +76,7 @@ public class ChainDataPruner implements BlockAddedObserver { if (event.isNewCanonicalHead() && blocksToBePruned >= pruningFrequency) { long currentRetainedBlock = blockNumber - currentPruningMark + 1; while (currentRetainedBlock > blocksToRetain) { - LOG.debug("Pruning chain data with block height of " + currentPruningMark); + LOG.debug("Pruning chain data with block height of {}", currentPruningMark); pruneChainDataAtBlock(pruningTransaction, currentPruningMark); currentPruningMark++; currentRetainedBlock = blockNumber - currentPruningMark; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/DiffBasedWorldStateProvider.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/DiffBasedWorldStateProvider.java index 857ec0b07..75b370c1c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/DiffBasedWorldStateProvider.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/DiffBasedWorldStateProvider.java @@ -230,12 +230,12 @@ public abstract class DiffBasedWorldStateProvider implements WorldStateArchive { } catch (final Exception e) { // if we fail we must clean up the updater diffBasedUpdater.reset(); - LOG.debug( - "State rolling failed on " - + mutableState.getWorldStateStorage().getClass().getSimpleName() - + " for block hash " - + blockHash, - e); + LOG.atDebug() + .setMessage("State rolling failed on {} for block hash {}") + .addArgument(mutableState.getWorldStateStorage().getClass().getSimpleName()) + .addArgument(blockHash) + .addArgument(e) + .log(); return Optional.empty(); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeer.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeer.java index 8cc907d68..755283b08 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeer.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthPeer.java @@ -710,7 +710,11 @@ public class EthPeer implements Comparable { } } // Otherwise, keep older connection - LOG.trace("comparing timestamps " + a.getInitiatedAt() + " with " + b.getInitiatedAt()); + LOG.atTrace() + .setMessage("comparing timestamps {} with {}") + .addArgument(a.getInitiatedAt()) + .addArgument(b.getInitiatedAt()) + .log(); return a.getInitiatedAt() < b.getInitiatedAt() ? -1 : 1; } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthScheduler.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthScheduler.java index dcb666966..1e2f3eb6a 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthScheduler.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthScheduler.java @@ -243,7 +243,7 @@ public class EthScheduler { public void stop() { if (stopped.compareAndSet(false, true)) { - LOG.trace("Stopping " + getClass().getSimpleName()); + LOG.atTrace().setMessage("Stopping {}").addArgument(getClass().getSimpleName()).log(); syncWorkerExecutor.shutdownNow(); txWorkerExecutor.shutdownNow(); scheduler.shutdownNow(); @@ -251,7 +251,10 @@ public class EthScheduler { computationExecutor.shutdownNow(); shutdown.countDown(); } else { - LOG.trace("Attempted to stop already stopped " + getClass().getSimpleName()); + LOG.atTrace() + .setMessage("Attempted to stop already stopped {}") + .addArgument(getClass().getSimpleName()) + .log(); } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/SnapProtocolManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/SnapProtocolManager.java index c65a1c6b0..ce639a7a9 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/SnapProtocolManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/snap/SnapProtocolManager.java @@ -97,7 +97,7 @@ public class SnapProtocolManager implements ProtocolManager { final EthPeer ethPeer = ethPeers.peer(message.getConnection()); if (ethPeer == null) { LOG.debug( - "Ignoring message received from unknown peer connection: " + message.getConnection()); + "Ignoring message received from unknown peer connection: {}", message.getConnection()); return; } final EthMessage ethMessage = new EthMessage(ethPeer, messageData); @@ -132,9 +132,10 @@ public class SnapProtocolManager implements ProtocolManager { try { ethPeer.send(responseData, getSupportedProtocol()); } catch (final PeerConnection.PeerNotConnected error) { - // Peer disconnected before we could respond - nothing to do - LOG.trace( - "Peer disconnected before we could respond - nothing to do " + error.getMessage()); + LOG.atTrace() + .setMessage("Peer disconnected before we could respond - nothing to do {}") + .addArgument(error.getMessage()) + .log(); } }); } diff --git a/nat/src/main/java/org/hyperledger/besu/nat/upnp/UpnpNatManager.java b/nat/src/main/java/org/hyperledger/besu/nat/upnp/UpnpNatManager.java index a7386d7f7..292fb0b00 100644 --- a/nat/src/main/java/org/hyperledger/besu/nat/upnp/UpnpNatManager.java +++ b/nat/src/main/java/org/hyperledger/besu/nat/upnp/UpnpNatManager.java @@ -101,7 +101,10 @@ public class UpnpNatManager extends AbstractNatManager { new BesuUpnpRegistryListener() { @Override public void remoteDeviceAdded(final Registry registry, final RemoteDevice device) { - LOG.debug("UPnP Device discovered: " + device.getDetails().getFriendlyName()); + LOG.atDebug() + .setMessage("UPnP Device discovered: {}") + .addArgument(device.getDetails().getFriendlyName()) + .log(); inspectDeviceRecursive(device, recognizedServices.keySet()); } }; From 592acb7b5054a7a30cf460e12335c716e2c6ab81 Mon Sep 17 00:00:00 2001 From: Simon Dudley Date: Thu, 18 Jul 2024 14:09:41 +1000 Subject: [PATCH 09/14] Update release checklist (#7329) Signed-off-by: Simon Dudley --- .github/ISSUE_TEMPLATE/release-checklist.md | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/release-checklist.md b/.github/ISSUE_TEMPLATE/release-checklist.md index f484b7a59..9840a3fa4 100644 --- a/.github/ISSUE_TEMPLATE/release-checklist.md +++ b/.github/ISSUE_TEMPLATE/release-checklist.md @@ -8,8 +8,8 @@ assignees: '' --- - [ ] Confirm anything outstanding for release with other maintainers on #besu-release in Discord +- [ ] Update changelog if necessary, and merge a PR for it to main - [ ] Notify maintainers about updating changelog for in-flight PRs - - [ ] Update changelog if necessary, and merge a PR for it to main - [ ] Optional: for hotfixes, create a release branch and cherry-pick, e.g. `release--hotfix` - [ ] Optional: create a PR into main from the hotfix branch to see the CI checks pass - [ ] On the appropriate branch/commit, create a calver tag for the release candidate, format example: `24.4.0-RC2` @@ -18,18 +18,14 @@ assignees: '' - [ ] Sign off burn-in; convey burn-in results in #besu-release in Discord - [ ] Using the same git sha, create a calver tag for the FULL RELEASE, example format `24.4.0` - [ ] Using the FULL RELEASE tag, create a release in github to trigger the workflows. Once published: - - makes the release "latest" in github - this is now public and notifies subscribed users + - makes the release "latest" in github - publishes artefacts and version-specific docker tags - publishes the docker `latest` tag variants -- [ ] Draft homebrew PR -- [ ] Draft documentation release -- [ ] Ensure binary SHAs are correct on the release page -- [ ] Docker release startup test: - - `docker run hyperledger/besu:` - - `docker run hyperledger/besu:-arm64` - - `docker run --platform linux/amd64 hyperledger/besu:-amd64` - - `docker run --pull=always hyperledger/besu:latest` (check version is ) -- [ ] Merge homebrew PR -- [ ] Publish Docs Release +- [ ] Check binary SHAs are correct on the release page +- [ ] Check "Container Verify" GitHub workflow has run successfully +- [ ] Create homebrew release - run https://github.com/hyperledger/homebrew-besu/actions/workflows/update-version.yml +- [ ] Create besu-docs release - https://github.com/hyperledger/besu-docs/releases/new + - Copy release notes from besu + - If publishing the release in github doesn't automatically trigger this workflow, then manually run https://github.com/hyperledger/besu-docs/actions/workflows/update-version.yml - [ ] Social announcements From 7a905f8b0a4266809c6789060490df538e350d5c Mon Sep 17 00:00:00 2001 From: Simon Dudley Date: Fri, 19 Jul 2024 03:21:08 +1000 Subject: [PATCH 10/14] Add metrics for trie log pruner (#7352) --------- Signed-off-by: Simon Dudley --- CHANGELOG.md | 9 ++++- .../controller/BesuControllerBuilder.java | 3 +- .../common/trielog/TrieLogPruner.java | 23 ++++++++++++- .../bonsai/trielog/TrieLogPrunerTest.java | 34 +++++++++++++++---- 4 files changed, 60 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fb35c2e0..7710f8e7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Next release +### Upcoming Breaking Changes +- Receipt compaction will be enabled by default in a future version of Besu. After this change it will not be possible to downgrade to the previous Besu version. +- --Xbonsai-limit-trie-logs-enabled is deprecated, use --bonsai-limit-trie-logs-enabled instead +- --Xbonsai-trie-logs-pruning-window-size is deprecated, use --bonsai-trie-logs-pruning-window-size instead +- `besu storage x-trie-log` subcommand is deprecated, use `besu storage trie-log` instead + ### Breaking Changes - Remove deprecated sync modes (X_SNAP and X_CHECKPOINT). Use SNAP and CHECKPOINT instead [#7309](https://github.com/hyperledger/besu/pull/7309) - Remove PKI-backed QBFT (deprecated in 24.5.1) Other forms of QBFT remain unchanged. [#7293](https://github.com/hyperledger/besu/pull/7293) @@ -15,7 +21,8 @@ - Implement gnark-crypto for eip-2537 [#7316](https://github.com/hyperledger/besu/pull/7316) - Improve blob size transaction selector [#7312](https://github.com/hyperledger/besu/pull/7312) - Added EIP-7702 [#7237](https://github.com/hyperledger/besu/pull/7237) -- implement gnark-crypto for eip-196 [#7262](https://github.com/hyperledger/besu/pull/7262) +- Implement gnark-crypto for eip-196 [#7262](https://github.com/hyperledger/besu/pull/7262) +- Add trie log pruner metrics [#7352](https://github.com/hyperledger/besu/pull/7352) ### Bug fixes - Fix `eth_call` deserialization to correctly ignore unknown fields in the transaction object. [#7323](https://github.com/hyperledger/besu/pull/7323) diff --git a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java index 8f26909a5..20f3ca8ef 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java @@ -793,7 +793,8 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides scheduler::executeServiceTask, dataStorageConfiguration.getBonsaiMaxLayersToLoad(), dataStorageConfiguration.getBonsaiTrieLogPruningWindowSize(), - isProofOfStake); + isProofOfStake, + metricsSystem); trieLogPruner.initialize(); return trieLogPruner; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/trielog/TrieLogPruner.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/trielog/TrieLogPruner.java index 6f347be03..cea5c1a32 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/trielog/TrieLogPruner.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/trielog/TrieLogPruner.java @@ -19,6 +19,9 @@ import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.trie.diffbased.common.storage.DiffBasedWorldStateKeyValueStorage; +import org.hyperledger.besu.metrics.BesuMetricCategory; +import org.hyperledger.besu.plugin.services.MetricsSystem; +import org.hyperledger.besu.plugin.services.metrics.Counter; import org.hyperledger.besu.plugin.services.trielogs.TrieLogEvent; import java.util.Comparator; @@ -45,6 +48,9 @@ public class TrieLogPruner implements TrieLogEvent.TrieLogObserver { private final Consumer executeAsync; private final long numBlocksToRetain; private final boolean requireFinalizedBlock; + private final Counter addedToPruneQueueCounter; + private final Counter prunedFromQueueCounter; + private final Counter prunedOrphanCounter; private final Multimap trieLogBlocksAndForksByDescendingBlockNumber = TreeMultimap.create(Comparator.reverseOrder(), Comparator.naturalOrder()); @@ -55,7 +61,8 @@ public class TrieLogPruner implements TrieLogEvent.TrieLogObserver { final Consumer executeAsync, final long numBlocksToRetain, final int pruningLimit, - final boolean requireFinalizedBlock) { + final boolean requireFinalizedBlock, + final MetricsSystem metricsSystem) { this.rootWorldStateStorage = rootWorldStateStorage; this.blockchain = blockchain; this.executeAsync = executeAsync; @@ -63,6 +70,17 @@ public class TrieLogPruner implements TrieLogEvent.TrieLogObserver { this.pruningLimit = pruningLimit; this.loadingLimit = pruningLimit; // same as pruningLimit for now this.requireFinalizedBlock = requireFinalizedBlock; + this.addedToPruneQueueCounter = + metricsSystem.createCounter( + BesuMetricCategory.PRUNER, + "trie_log_added_to_prune_queue", + "trie log added to prune queue"); + this.prunedFromQueueCounter = + metricsSystem.createCounter( + BesuMetricCategory.PRUNER, "trie_log_pruned_from_queue", "trie log pruned from queue"); + this.prunedOrphanCounter = + metricsSystem.createCounter( + BesuMetricCategory.PRUNER, "trie_log_pruned_orphan", "trie log pruned orphan"); } public int initialize() { @@ -88,6 +106,7 @@ public class TrieLogPruner implements TrieLogEvent.TrieLogObserver { // prune orphaned blocks (sometimes created during block production) rootWorldStateStorage.pruneTrieLog(blockHash); orphansPruned.getAndIncrement(); + prunedOrphanCounter.inc(); } }); LOG.atDebug().log("Pruned {} orphaned trie logs from database...", orphansPruned.intValue()); @@ -106,6 +125,7 @@ public class TrieLogPruner implements TrieLogEvent.TrieLogObserver { .addArgument(blockHash) .log(); trieLogBlocksAndForksByDescendingBlockNumber.put(blockNumber, blockHash); + addedToPruneQueueCounter.inc(); } public synchronized int pruneFromQueue() { @@ -155,6 +175,7 @@ public class TrieLogPruner implements TrieLogEvent.TrieLogObserver { }); wasPruned.keySet().forEach(trieLogBlocksAndForksByDescendingBlockNumber::removeAll); + prunedFromQueueCounter.inc(wasPruned.size()); LOG.atTrace() .setMessage("pruned {} trie logs for blocks {}") diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/trielog/TrieLogPrunerTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/trielog/TrieLogPrunerTest.java index bca954a49..621e73711 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/trielog/TrieLogPrunerTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/trielog/TrieLogPrunerTest.java @@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldSt import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogAddedEvent; import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogLayer; import org.hyperledger.besu.ethereum.trie.diffbased.common.trielog.TrieLogPruner; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.util.Optional; import java.util.function.Consumer; @@ -72,7 +73,8 @@ public class TrieLogPrunerTest { // When TrieLogPruner trieLogPruner = - new TrieLogPruner(worldState, blockchain, executeAsync, 3, loadingLimit, false); + new TrieLogPruner( + worldState, blockchain, executeAsync, 3, loadingLimit, false, new NoOpMetricsSystem()); trieLogPruner.initialize(); // Then @@ -92,7 +94,13 @@ public class TrieLogPrunerTest { // requireFinalizedBlock = false means this is not a PoS chain TrieLogPruner trieLogPruner = new TrieLogPruner( - worldState, blockchain, executeAsync, blocksToRetain, pruningWindowSize, false); + worldState, + blockchain, + executeAsync, + blocksToRetain, + pruningWindowSize, + false, + new NoOpMetricsSystem()); trieLogPruner.addToPruneQueue(0, key(0)); // older block outside prune window trieLogPruner.addToPruneQueue(1, key(1)); // block inside the prune window @@ -201,7 +209,13 @@ public class TrieLogPrunerTest { when(blockchain.getChainHeadBlockNumber()).thenReturn(chainHeight); TrieLogPruner trieLogPruner = new TrieLogPruner( - worldState, blockchain, executeAsync, blocksToRetain, pruningWindowSize, true); + worldState, + blockchain, + executeAsync, + blocksToRetain, + pruningWindowSize, + true, + new NoOpMetricsSystem()); trieLogPruner.addToPruneQueue(1, key(1)); trieLogPruner.addToPruneQueue(2, key(2)); @@ -240,7 +254,8 @@ public class TrieLogPrunerTest { // Given final TriggerableConsumer triggerableConsumer = new TriggerableConsumer(); TrieLogPruner trieLogPruner = - new TrieLogPruner(worldState, blockchain, triggerableConsumer, 0, 1, false); + new TrieLogPruner( + worldState, blockchain, triggerableConsumer, 0, 1, false, new NoOpMetricsSystem()); assertThat(trieLogPruner.pruneFromQueue()).isEqualTo(0); final TrieLogLayer layer = new TrieLogLayer(); @@ -261,7 +276,8 @@ public class TrieLogPrunerTest { public void onTrieLogAdded_should_not_prune_when_no_blockNumber() { // Given TrieLogPruner trieLogPruner = - new TrieLogPruner(worldState, blockchain, executeAsync, 0, 1, false); + new TrieLogPruner( + worldState, blockchain, executeAsync, 0, 1, false, new NoOpMetricsSystem()); assertThat(trieLogPruner.pruneFromQueue()).isEqualTo(0); final TrieLogLayer layer = new TrieLogLayer(); @@ -289,7 +305,13 @@ public class TrieLogPrunerTest { when(blockchain.getChainHeadBlockNumber()).thenReturn(chainHeight); TrieLogPruner trieLogPruner = new TrieLogPruner( - worldState, blockchain, executeAsync, blocksToRetain, pruningWindowSize, true); + worldState, + blockchain, + executeAsync, + blocksToRetain, + pruningWindowSize, + true, + new NoOpMetricsSystem()); trieLogPruner.addToPruneQueue(1, key(1)); trieLogPruner.addToPruneQueue(2, key(2)); From 30c96c7a1d6e379854d91f3f43914b5d564f3381 Mon Sep 17 00:00:00 2001 From: Karim Taam Date: Fri, 19 Jul 2024 18:11:30 +0200 Subject: [PATCH 11/14] Optimistic parallelization of transactions to improve performance (#7296) Optimistic transaction parallelization execution during block processing to improve the performances. This feature can enabled with a flag --Xbonsai-parallel-tx-processing-enabled=true Signed-off-by: Karim Taam Co-authored-by: Ameziane H Co-authored-by: garyschulte --- CHANGELOG.md | 1 + .../org/hyperledger/besu/cli/BesuCommand.java | 2 + .../options/stable/DataStorageOptions.java | 81 +++-- .../controller/BesuControllerBuilder.java | 17 + .../CliqueBesuControllerBuilder.java | 4 +- ...onsensusScheduleBesuControllerBuilder.java | 9 + .../controller/IbftBesuControllerBuilder.java | 4 +- .../MainnetBesuControllerBuilder.java | 4 +- .../MergeBesuControllerBuilder.java | 4 +- .../controller/QbftBesuControllerBuilder.java | 4 +- .../TransitionBesuControllerBuilder.java | 7 + .../besu/ForkIdsNetworkConfigTest.java | 14 +- .../besu/cli/CommandTestAbstract.java | 2 + .../clique/CliqueProtocolSchedule.java | 23 +- .../clique/CliqueProtocolScheduleTest.java | 21 +- .../blockcreation/CliqueBlockCreatorTest.java | 4 +- .../CliqueMinerExecutorTest.java | 4 +- .../bft/BaseBftProtocolScheduleBuilder.java | 12 +- .../CombinedProtocolScheduleFactoryTest.java | 5 +- .../BaseBftProtocolScheduleBuilderTest.java | 5 +- .../ibft/support/TestContextBuilder.java | 4 +- .../ibft/IbftProtocolScheduleBuilder.java | 23 +- .../ibft/IbftProtocolScheduleTest.java | 5 +- .../blockcreation/BftBlockCreatorTest.java | 4 +- .../IbftBlockHeightManagerTest.java | 5 +- .../merge/MergeProtocolSchedule.java | 19 +- .../merge/TransitionProtocolSchedule.java | 20 +- .../merge/MergeProtocolScheduleTest.java | 33 +- .../MergeGenesisConfigHelper.java | 5 +- .../qbft/support/TestContextBuilder.java | 4 +- .../qbft/QbftProtocolScheduleBuilder.java | 34 +- .../qbft/QbftProtocolScheduleTest.java | 5 +- .../QbftBlockHeightManagerTest.java | 5 +- .../besu/crypto/Blake2bfMessageDigest.java | 30 +- .../crypto/Blake2bfMessageDigestTest.java | 50 +++ .../besu/datatypes/StorageSlotKey.java | 2 +- .../api/jsonrpc/BlockchainImporter.java | 5 +- .../JsonRpcHttpServiceHostAllowlistTest.java | 4 +- .../jsonrpc/JsonRpcHttpServiceLoginTest.java | 6 +- .../jsonrpc/JsonRpcHttpServiceTestBase.java | 4 +- .../JsonRpcHttpServiceTlsClientAuthTest.java | 4 +- ...RpcHttpServiceTlsMisconfigurationTest.java | 4 +- .../jsonrpc/JsonRpcHttpServiceTlsTest.java | 4 +- .../websocket/WebSocketServiceLoginTest.java | 4 +- .../AbstractBlockCreatorTest.java | 4 +- .../AbstractBlockTransactionSelectorTest.java | 4 +- ...FeeMarketBlockTransactionSelectorTest.java | 5 +- ...FeeMarketBlockTransactionSelectorTest.java | 5 +- .../blockcreation/PoWBlockCreatorTest.java | 24 +- .../FixedDifficultyProtocolSchedule.java | 25 +- .../mainnet/AbstractBlockProcessor.java | 121 +++++--- .../mainnet/ClassicProtocolSpecs.java | 125 ++++++-- .../mainnet/MainnetProtocolSchedule.java | 42 ++- .../mainnet/MainnetProtocolSpecFactory.java | 209 +++++++++++-- .../mainnet/MainnetProtocolSpecs.java | 268 ++++++++++++---- .../mainnet/MainnetTransactionProcessor.java | 4 +- .../mainnet/ProtocolScheduleBuilder.java | 32 +- .../ethereum/mainnet/ProtocolSpecBuilder.java | 3 + .../MainnetParallelBlockProcessor.java | 199 ++++++++++++ ...lelizedConcurrentTransactionProcessor.java | 268 ++++++++++++++++ .../ParallelizedTransactionContext.java | 133 ++++++++ .../TransactionCollisionDetector.java | 114 +++++++ .../NoopBonsaiCachedMerkleTrieLoader.java | 44 +++ .../bonsai/worldview/BonsaiWorldState.java | 12 + .../DiffBasedWorldStateUpdateAccumulator.java | 126 +++++++- .../worldstate/DataStorageConfiguration.java | 7 + .../ethereum/core/BlockchainSetupUtil.java | 4 +- .../core/ExecutionContextTestFixture.java | 4 +- .../core/ProtocolScheduleFixture.java | 5 +- .../BlockImportExceptionHandlingTest.java | 6 + .../fixed/FixedProtocolScheduleTest.java | 5 +- .../mainnet/DefaultProtocolScheduleTest.java | 5 +- .../mainnet/MainnetProtocolScheduleTest.java | 13 +- .../mainnet/ProtocolScheduleBuilderTest.java | 9 +- ...zedConcurrentTransactionProcessorTest.java | 213 +++++++++++++ .../TransactionCollisionDetectorTest.java | 290 ++++++++++++++++++ .../bonsai/AbstractIsolationTests.java | 4 +- .../eth/messages/BlockBodiesMessageTest.java | 5 +- .../eth/messages/BlockHeadersMessageTest.java | 5 +- .../eth/sync/ChainHeadTrackerTest.java | 4 +- .../backwardsync/BackwardSyncContextTest.java | 7 +- .../backwardsync/BackwardSyncStepTest.java | 7 +- .../backwardsync/ForwardSyncStepTest.java | 7 +- .../AbstractTransactionPoolTest.java | 4 +- .../ethereum/eth/transactions/TestNode.java | 4 +- .../TransactionPoolFactoryTest.java | 4 +- .../evmtool/MainnetGenesisFileModule.java | 12 +- ethereum/referencetests/build.gradle | 1 + .../ReferenceTestProtocolSchedules.java | 5 +- .../mainnet/DifficultyCalculatorTests.java | 30 +- .../ethereum/retesteth/RetestethContext.java | 7 +- .../besu/evm/tracing/OperationTracer.java | 12 + .../besu/metrics/BesuMetricCategory.java | 4 +- 93 files changed, 2630 insertions(+), 330 deletions(-) create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/MainnetParallelBlockProcessor.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/ParallelizedConcurrentTransactionProcessor.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/ParallelizedTransactionContext.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/TransactionCollisionDetector.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/cache/NoopBonsaiCachedMerkleTrieLoader.java create mode 100644 ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/parallelization/ParallelizedConcurrentTransactionProcessorTest.java create mode 100644 ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/parallelization/TransactionCollisionDetectorTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 7710f8e7b..9c6cb373b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ - Added EIP-7702 [#7237](https://github.com/hyperledger/besu/pull/7237) - Implement gnark-crypto for eip-196 [#7262](https://github.com/hyperledger/besu/pull/7262) - Add trie log pruner metrics [#7352](https://github.com/hyperledger/besu/pull/7352) +- `--Xbonsai-parallel-tx-processing-enabled` option enables executing transactions in parallel during block processing for Bonsai nodes ### Bug fixes - Fix `eth_call` deserialization to correctly ignore unknown fields in the transaction object. [#7323](https://github.com/hyperledger/besu/pull/7323) diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index 7216d9ebd..198c26fe2 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -1901,6 +1901,8 @@ public class BesuCommand implements DefaultCommandValues, Runnable { .privacyParameters(privacyParameters()) .clock(Clock.systemUTC()) .isRevertReasonEnabled(isRevertReasonEnabled) + .isParallelTxProcessingEnabled( + dataStorageConfiguration.getUnstable().isParallelTxProcessingEnabled()) .storageProvider(storageProvider) .gasLimitCalculator( miningParametersSupplier.get().getTargetGasLimit().isPresent() diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/DataStorageOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/DataStorageOptions.java index 69cf819cb..fc92a7e5d 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/DataStorageOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/DataStorageOptions.java @@ -122,6 +122,14 @@ public class DataStorageOptions implements CLIOptions "Enables code storage using code hash instead of by account hash. (default: ${DEFAULT-VALUE})") private boolean bonsaiCodeUsingCodeHashEnabled = DEFAULT_BONSAI_CODE_USING_CODE_HASH_ENABLED; + @CommandLine.Option( + hidden = true, + names = {"--Xbonsai-parallel-tx-processing-enabled"}, + arity = "1", + description = + "Enables parallelization of transactions to optimize processing speed by concurrently loading and executing necessary data in advance. (default: ${DEFAULT-VALUE})") + private Boolean isParallelTxProcessingEnabled = false; + /** Default Constructor. */ Unstable() {} } @@ -142,40 +150,48 @@ public class DataStorageOptions implements CLIOptions * @param syncMode the sync mode */ public void validate(final CommandLine commandLine, final SyncMode syncMode) { - if (DataStorageFormat.BONSAI == dataStorageFormat && bonsaiLimitTrieLogsEnabled) { - if (SyncMode.FULL == syncMode) { - throw new CommandLine.ParameterException( - commandLine, - String.format( - "Cannot enable %s with sync-mode %s. You must set %s or use a different sync-mode", - BONSAI_LIMIT_TRIE_LOGS_ENABLED, - SyncMode.FULL, - BONSAI_LIMIT_TRIE_LOGS_ENABLED + "=false")); + if (DataStorageFormat.BONSAI == dataStorageFormat) { + if (bonsaiLimitTrieLogsEnabled) { + if (SyncMode.FULL == syncMode) { + throw new CommandLine.ParameterException( + commandLine, + String.format( + "Cannot enable %s with sync-mode %s. You must set %s or use a different sync-mode", + BONSAI_LIMIT_TRIE_LOGS_ENABLED, + SyncMode.FULL, + BONSAI_LIMIT_TRIE_LOGS_ENABLED + "=false")); + } + if (bonsaiMaxLayersToLoad < MINIMUM_BONSAI_TRIE_LOG_RETENTION_LIMIT) { + throw new CommandLine.ParameterException( + commandLine, + String.format( + BONSAI_STORAGE_FORMAT_MAX_LAYERS_TO_LOAD + " minimum value is %d", + MINIMUM_BONSAI_TRIE_LOG_RETENTION_LIMIT)); + } + if (bonsaiTrieLogPruningWindowSize <= 0) { + throw new CommandLine.ParameterException( + commandLine, + String.format( + BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE + "=%d must be greater than 0", + bonsaiTrieLogPruningWindowSize)); + } + if (bonsaiTrieLogPruningWindowSize <= bonsaiMaxLayersToLoad) { + throw new CommandLine.ParameterException( + commandLine, + String.format( + BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE + + "=%d must be greater than " + + BONSAI_STORAGE_FORMAT_MAX_LAYERS_TO_LOAD + + "=%d", + bonsaiTrieLogPruningWindowSize, + bonsaiMaxLayersToLoad)); + } } - if (bonsaiMaxLayersToLoad < MINIMUM_BONSAI_TRIE_LOG_RETENTION_LIMIT) { + } else { + if (unstableOptions.isParallelTxProcessingEnabled) { throw new CommandLine.ParameterException( commandLine, - String.format( - BONSAI_STORAGE_FORMAT_MAX_LAYERS_TO_LOAD + " minimum value is %d", - MINIMUM_BONSAI_TRIE_LOG_RETENTION_LIMIT)); - } - if (bonsaiTrieLogPruningWindowSize <= 0) { - throw new CommandLine.ParameterException( - commandLine, - String.format( - BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE + "=%d must be greater than 0", - bonsaiTrieLogPruningWindowSize)); - } - if (bonsaiTrieLogPruningWindowSize <= bonsaiMaxLayersToLoad) { - throw new CommandLine.ParameterException( - commandLine, - String.format( - BONSAI_TRIE_LOG_PRUNING_WINDOW_SIZE - + "=%d must be greater than " - + BONSAI_STORAGE_FORMAT_MAX_LAYERS_TO_LOAD - + "=%d", - bonsaiTrieLogPruningWindowSize, - bonsaiMaxLayersToLoad)); + "Transaction parallelization is not supported unless operating in a 'diffbased' mode, such as Bonsai."); } } } @@ -198,6 +214,8 @@ public class DataStorageOptions implements CLIOptions domainObject.getUnstable().getBonsaiFullFlatDbEnabled(); dataStorageOptions.unstableOptions.bonsaiCodeUsingCodeHashEnabled = domainObject.getUnstable().getBonsaiCodeStoredByCodeHashEnabled(); + dataStorageOptions.unstableOptions.isParallelTxProcessingEnabled = + domainObject.getUnstable().isParallelTxProcessingEnabled(); return dataStorageOptions; } @@ -214,6 +232,7 @@ public class DataStorageOptions implements CLIOptions ImmutableDataStorageConfiguration.Unstable.builder() .bonsaiFullFlatDbEnabled(unstableOptions.bonsaiFullFlatDbEnabled) .bonsaiCodeStoredByCodeHashEnabled(unstableOptions.bonsaiCodeUsingCodeHashEnabled) + .isParallelTxProcessingEnabled(unstableOptions.isParallelTxProcessingEnabled) .build()) .build(); } diff --git a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java index 20f3ca8ef..ddb75fcde 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java @@ -203,6 +203,9 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides private int numberOfBlocksToCache = 0; + /** whether parallel transaction processing is enabled or not */ + protected boolean isParallelTxProcessingEnabled; + /** Instantiates a new Besu controller builder. */ protected BesuControllerBuilder() {} @@ -512,6 +515,20 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides return this; } + /** + * Sets whether parallel transaction processing is enabled. When parallel transaction processing + * is enabled, transactions within a block can be processed in parallel and potentially improving + * performance + * + * @param isParallelTxProcessingEnabled true to enable parallel transaction + * @return the besu controller + */ + public BesuControllerBuilder isParallelTxProcessingEnabled( + final boolean isParallelTxProcessingEnabled) { + this.isParallelTxProcessingEnabled = isParallelTxProcessingEnabled; + return this; + } + /** * Build besu controller. * diff --git a/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java index c12742406..b4ada6054 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java @@ -136,7 +136,9 @@ public class CliqueBesuControllerBuilder extends BesuControllerBuilder { isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } @Override diff --git a/besu/src/main/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilder.java index f66933220..0d0f8d2fd 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilder.java @@ -358,6 +358,15 @@ public class ConsensusScheduleBesuControllerBuilder extends BesuControllerBuilde return super.isRevertReasonEnabled(isRevertReasonEnabled); } + @Override + public BesuControllerBuilder isParallelTxProcessingEnabled( + final boolean isParallelTxProcessingEnabled) { + besuControllerBuilderSchedule + .values() + .forEach(b -> b.isParallelTxProcessingEnabled(isParallelTxProcessingEnabled)); + return super.isParallelTxProcessingEnabled(isParallelTxProcessingEnabled); + } + @Override public BesuControllerBuilder gasLimitCalculator(final GasLimitCalculator gasLimitCalculator) { besuControllerBuilderSchedule.values().forEach(b -> b.gasLimitCalculator(gasLimitCalculator)); diff --git a/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java index 473549e0b..b8d4d2645 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java @@ -291,7 +291,9 @@ public class IbftBesuControllerBuilder extends BftBesuControllerBuilder { bftExtraDataCodec().get(), evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } @Override diff --git a/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java index 27570483c..e0fbed608 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java @@ -99,7 +99,9 @@ public class MainnetBesuControllerBuilder extends BesuControllerBuilder { isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } @Override diff --git a/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java index cdd46ea5b..f5fc75959 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java @@ -177,7 +177,9 @@ public class MergeBesuControllerBuilder extends BesuControllerBuilder { privacyParameters, isRevertReasonEnabled, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } @Override diff --git a/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java index 795136ded..ab2dbce3f 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java @@ -329,7 +329,9 @@ public class QbftBesuControllerBuilder extends BftBesuControllerBuilder { bftExtraDataCodec().get(), evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } @Override diff --git a/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java index cdf5413ff..d7b701b4c 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java @@ -374,6 +374,13 @@ public class TransitionBesuControllerBuilder extends BesuControllerBuilder { return propagateConfig(z -> z.isRevertReasonEnabled(isRevertReasonEnabled)); } + @Override + public BesuControllerBuilder isParallelTxProcessingEnabled( + final boolean isParallelTxProcessingEnabled) { + super.isParallelTxProcessingEnabled(isParallelTxProcessingEnabled); + return propagateConfig(z -> z.isParallelTxProcessingEnabled(isParallelTxProcessingEnabled)); + } + @Override public BesuControllerBuilder gasLimitCalculator(final GasLimitCalculator gasLimitCalculator) { super.gasLimitCalculator(gasLimitCalculator); diff --git a/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java b/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java index fe5077acc..28d4c7703 100644 --- a/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java +++ b/besu/src/test/java/org/hyperledger/besu/ForkIdsNetworkConfigTest.java @@ -35,6 +35,7 @@ import org.hyperledger.besu.ethereum.forkid.ForkId; import org.hyperledger.besu.ethereum.forkid.ForkIdManager; import org.hyperledger.besu.ethereum.mainnet.DefaultProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.util.Collection; import java.util.List; @@ -177,12 +178,21 @@ public class ForkIdsNetworkConfigTest { new MilestoneStreamingProtocolSchedule( (DefaultProtocolSchedule) MainnetProtocolSchedule.fromConfig( - configOptions, MiningParameters.MINING_DISABLED, new BadBlockManager())); + configOptions, + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem())); MilestoneStreamingProtocolSchedule postMergeProtocolSchedule = new MilestoneStreamingProtocolSchedule( (DefaultProtocolSchedule) MergeProtocolSchedule.create( - configOptions, false, MiningParameters.MINING_DISABLED, new BadBlockManager())); + configOptions, + false, + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem())); final MilestoneStreamingTransitionProtocolSchedule schedule = new MilestoneStreamingTransitionProtocolSchedule( preMergeProtocolSchedule, postMergeProtocolSchedule); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java index c92a3a5bd..8a6a57811 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java @@ -276,6 +276,8 @@ public abstract class CommandTestAbstract { when(mockControllerBuilder.privacyParameters(any())).thenReturn(mockControllerBuilder); when(mockControllerBuilder.clock(any())).thenReturn(mockControllerBuilder); when(mockControllerBuilder.isRevertReasonEnabled(false)).thenReturn(mockControllerBuilder); + when(mockControllerBuilder.isParallelTxProcessingEnabled(false)) + .thenReturn(mockControllerBuilder); when(mockControllerBuilder.storageProvider(any())).thenReturn(mockControllerBuilder); when(mockControllerBuilder.gasLimitCalculator(any())).thenReturn(mockControllerBuilder); when(mockControllerBuilder.requiredBlocks(any())).thenReturn(mockControllerBuilder); diff --git a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/CliqueProtocolSchedule.java b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/CliqueProtocolSchedule.java index 91013ab97..cd1975563 100644 --- a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/CliqueProtocolSchedule.java +++ b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/CliqueProtocolSchedule.java @@ -36,6 +36,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecBuilder; import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.plugin.services.MetricsSystem; import java.math.BigInteger; import java.util.HashMap; @@ -64,6 +65,9 @@ public class CliqueProtocolSchedule { * @param evmConfiguration the evm configuration * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled + * @param metricsSystem A metricSystem instance to be able to expose metrics in the underlying + * calls * @return the protocol schedule */ public static ProtocolSchedule create( @@ -74,7 +78,9 @@ public class CliqueProtocolSchedule { final boolean isRevertReasonEnabled, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { final CliqueConfigOptions cliqueConfig = config.getCliqueConfigOptions(); @@ -110,7 +116,9 @@ public class CliqueProtocolSchedule { isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager) + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem) .createProtocolSchedule(); } @@ -124,6 +132,9 @@ public class CliqueProtocolSchedule { * @param evmConfiguration the evm configuration * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled + * @param metricsSystem A metricSystem instance to be able to expose metrics in the underlying + * calls * @return the protocol schedule */ @VisibleForTesting @@ -134,7 +145,9 @@ public class CliqueProtocolSchedule { final boolean isRevertReasonEnabled, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return create( config, forksSchedule, @@ -143,7 +156,9 @@ public class CliqueProtocolSchedule { isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } private static ProtocolSpecBuilder applyCliqueSpecificModifications( diff --git a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/CliqueProtocolScheduleTest.java b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/CliqueProtocolScheduleTest.java index 35f959e45..5cbdbb6d0 100644 --- a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/CliqueProtocolScheduleTest.java +++ b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/CliqueProtocolScheduleTest.java @@ -37,6 +37,7 @@ import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.time.Instant; import java.util.List; @@ -68,7 +69,9 @@ public class CliqueProtocolScheduleTest { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); final ProtocolSpec homesteadSpec = protocolSchedule.getByBlockHeader(blockHeader(1)); final ProtocolSpec tangerineWhistleSpec = protocolSchedule.getByBlockHeader(blockHeader(2)); @@ -92,7 +95,9 @@ public class CliqueProtocolScheduleTest { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()) + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .getByBlockHeader(blockHeader(0)); assertThat(homestead.getName()).isEqualTo("Frontier"); @@ -116,7 +121,9 @@ public class CliqueProtocolScheduleTest { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager())) + new BadBlockManager(), + false, + new NoOpMetricsSystem())) .isInstanceOf(IllegalArgumentException.class) .hasMessage("Epoch length in config must be greater than zero"); } @@ -136,7 +143,9 @@ public class CliqueProtocolScheduleTest { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager())) + new BadBlockManager(), + false, + new NoOpMetricsSystem())) .isInstanceOf(IllegalArgumentException.class) .hasMessage("Epoch length in config must be greater than zero"); } @@ -160,7 +169,9 @@ public class CliqueProtocolScheduleTest { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); BlockHeader emptyFrontierParent = headerBuilder diff --git a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreatorTest.java b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreatorTest.java index 485b2aff7..ec10630df 100644 --- a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreatorTest.java +++ b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreatorTest.java @@ -106,7 +106,9 @@ public class CliqueBlockCreatorTest { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); final Address otherAddress = Util.publicKeyToAddress(otherKeyPair.getPublicKey()); validatorList.add(otherAddress); diff --git a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java index bb69aaff4..9502d00a1 100644 --- a/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java +++ b/consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java @@ -105,7 +105,9 @@ public class CliqueMinerExecutorTest { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); cliqueEthContext = mock(EthContext.class, RETURNS_DEEP_STUBS); blockHeaderBuilder = new BlockHeaderTestFixture(); } diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BaseBftProtocolScheduleBuilder.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BaseBftProtocolScheduleBuilder.java index da81ce80b..311bf30fa 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BaseBftProtocolScheduleBuilder.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BaseBftProtocolScheduleBuilder.java @@ -33,6 +33,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecBuilder; import org.hyperledger.besu.ethereum.mainnet.WithdrawalsValidator; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.plugin.services.MetricsSystem; import java.math.BigInteger; import java.util.HashMap; @@ -58,6 +59,9 @@ public abstract class BaseBftProtocolScheduleBuilder { * @param evmConfiguration the evm configuration * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled. + * @param metricsSystem metricsSystem A metricSystem instance to be able to expose metrics in the + * underlying calls * @return the protocol schedule */ public BftProtocolSchedule createProtocolSchedule( @@ -68,7 +72,9 @@ public abstract class BaseBftProtocolScheduleBuilder { final BftExtraDataCodec bftExtraDataCodec, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { final Map> specMap = new HashMap<>(); forksSchedule @@ -90,7 +96,9 @@ public abstract class BaseBftProtocolScheduleBuilder { isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager) + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem) .createProtocolSchedule(); return new BftProtocolSchedule((DefaultProtocolSchedule) protocolSchedule); } diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/CombinedProtocolScheduleFactoryTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/CombinedProtocolScheduleFactoryTest.java index 4e3cab78e..02689d52a 100644 --- a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/CombinedProtocolScheduleFactoryTest.java +++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/CombinedProtocolScheduleFactoryTest.java @@ -28,6 +28,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.math.BigInteger; import java.util.List; @@ -177,7 +178,9 @@ public class CombinedProtocolScheduleFactoryTest { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); return new BftProtocolSchedule( (DefaultProtocolSchedule) protocolScheduleBuilder.createProtocolSchedule()); diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BaseBftProtocolScheduleBuilderTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BaseBftProtocolScheduleBuilderTest.java index 9b05bd7a3..e23664fd8 100644 --- a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BaseBftProtocolScheduleBuilderTest.java +++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BaseBftProtocolScheduleBuilderTest.java @@ -39,6 +39,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.math.BigInteger; import java.util.List; @@ -245,7 +246,9 @@ public class BaseBftProtocolScheduleBuilderTest { bftExtraDataCodec, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); } private BftConfigOptions createBftConfig(final BigInteger blockReward) { diff --git a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java index 55a2f3551..2d620c563 100644 --- a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java +++ b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java @@ -333,7 +333,9 @@ public class TestContextBuilder { IBFT_EXTRA_DATA_ENCODER, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); ///////////////////////////////////////////////////////////////////////////////////// // From here down is BASICALLY taken from IbftBesuController diff --git a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleBuilder.java b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleBuilder.java index 5cad697c5..0789f2e89 100644 --- a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleBuilder.java +++ b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleBuilder.java @@ -27,6 +27,7 @@ import org.hyperledger.besu.ethereum.mainnet.BlockHeaderValidator; import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.plugin.services.MetricsSystem; import java.util.Optional; @@ -46,6 +47,9 @@ public class IbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder * @param evmConfiguration the evm configuration * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled + * @param metricsSystem A metricSystem instance to be able to expose metrics in the underlying + * calls * @return the protocol schedule */ public static BftProtocolSchedule create( @@ -56,7 +60,9 @@ public class IbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder final BftExtraDataCodec bftExtraDataCodec, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return new IbftProtocolScheduleBuilder() .createProtocolSchedule( config, @@ -66,7 +72,9 @@ public class IbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder bftExtraDataCodec, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } /** @@ -78,6 +86,9 @@ public class IbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder * @param evmConfiguration the evm configuration * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled. + * @param metricsSystem A metricSystem instance to be able to expose metrics in the underlying + * calls * @return the protocol schedule */ public static BftProtocolSchedule create( @@ -86,7 +97,9 @@ public class IbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder final BftExtraDataCodec bftExtraDataCodec, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return create( config, forksSchedule, @@ -95,7 +108,9 @@ public class IbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder bftExtraDataCodec, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } @Override diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleTest.java index 611399fd5..e5551ff3f 100644 --- a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleTest.java +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleTest.java @@ -45,6 +45,7 @@ import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.Util; import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.math.BigInteger; import java.util.Collection; @@ -103,7 +104,9 @@ public class IbftProtocolScheduleTest { bftExtraDataCodec, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); } private boolean validateHeader( diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/BftBlockCreatorTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/BftBlockCreatorTest.java index 25c5c1d10..1b86896f3 100644 --- a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/BftBlockCreatorTest.java +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/BftBlockCreatorTest.java @@ -121,7 +121,9 @@ public class BftBlockCreatorTest { bftExtraDataEncoder, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); final ProtocolContext protContext = new ProtocolContext( blockchain, diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManagerTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManagerTest.java index 68e0ee5ef..b388b80a3 100644 --- a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManagerTest.java +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManagerTest.java @@ -79,6 +79,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.util.Subscribers; import java.math.BigInteger; @@ -184,7 +185,9 @@ public class IbftBlockHeightManagerTest { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); ProtocolSchedule protocolSchedule = new BftProtocolSchedule( diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeProtocolSchedule.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeProtocolSchedule.java index ff92319ae..abbc3b130 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeProtocolSchedule.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeProtocolSchedule.java @@ -27,6 +27,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecBuilder; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.evm.MainnetEVMs; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.plugin.services.MetricsSystem; import java.math.BigInteger; import java.util.HashMap; @@ -49,19 +50,24 @@ public class MergeProtocolSchedule { * @param isRevertReasonEnabled the is revert reason enabled * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled. * @return the protocol schedule */ public static ProtocolSchedule create( final GenesisConfigOptions config, final boolean isRevertReasonEnabled, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return create( config, PrivacyParameters.DEFAULT, isRevertReasonEnabled, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } /** @@ -72,6 +78,7 @@ public class MergeProtocolSchedule { * @param isRevertReasonEnabled the is revert reason enabled * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled. * @return the protocol schedule */ public static ProtocolSchedule create( @@ -79,7 +86,9 @@ public class MergeProtocolSchedule { final PrivacyParameters privacyParameters, final boolean isRevertReasonEnabled, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { Map> postMergeModifications = new HashMap<>(); @@ -98,7 +107,9 @@ public class MergeProtocolSchedule { isRevertReasonEnabled, EvmConfiguration.DEFAULT, miningParameters, - badBlockManager) + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem) .createProtocolSchedule(); } diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java index faab15dac..8600344ce 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java @@ -27,6 +27,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import org.hyperledger.besu.plugin.services.MetricsSystem; import java.math.BigInteger; import java.util.Optional; @@ -65,17 +66,30 @@ public class TransitionProtocolSchedule implements ProtocolSchedule { * milestone starting points * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled. * @return an initialised TransitionProtocolSchedule using post-merge defaults */ public static TransitionProtocolSchedule fromConfig( final GenesisConfigOptions genesisConfigOptions, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { ProtocolSchedule preMergeProtocolSchedule = - MainnetProtocolSchedule.fromConfig(genesisConfigOptions, miningParameters, badBlockManager); + MainnetProtocolSchedule.fromConfig( + genesisConfigOptions, + miningParameters, + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); ProtocolSchedule postMergeProtocolSchedule = MergeProtocolSchedule.create( - genesisConfigOptions, false, miningParameters, badBlockManager); + genesisConfigOptions, + false, + miningParameters, + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); return new TransitionProtocolSchedule( preMergeProtocolSchedule, postMergeProtocolSchedule, PostMergeContext.get()); } diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/MergeProtocolScheduleTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/MergeProtocolScheduleTest.java index b1f7414e4..0d4aede3a 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/MergeProtocolScheduleTest.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/MergeProtocolScheduleTest.java @@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.evm.operation.InvalidOperation; import org.hyperledger.besu.evm.operation.PrevRanDaoOperation; import org.hyperledger.besu.evm.operation.Push0Operation; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.math.BigInteger; @@ -48,7 +49,12 @@ public class MergeProtocolScheduleTest { final GenesisConfigOptions config = GenesisConfigFile.fromConfig(jsonInput).getConfigOptions(); final ProtocolSchedule protocolSchedule = MergeProtocolSchedule.create( - config, false, MiningParameters.MINING_DISABLED, new BadBlockManager()); + config, + false, + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()); final ProtocolSpec homesteadSpec = protocolSchedule.getByBlockHeader(blockHeader(1)); final ProtocolSpec londonSpec = protocolSchedule.getByBlockHeader(blockHeader(1559)); @@ -64,7 +70,12 @@ public class MergeProtocolScheduleTest { final GenesisConfigOptions config = GenesisConfigFile.mainnet().getConfigOptions(); final ProtocolSchedule protocolSchedule = MergeProtocolSchedule.create( - config, false, MiningParameters.MINING_DISABLED, new BadBlockManager()); + config, + false, + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()); final long lastParisBlockNumber = 17034869L; final ProtocolSpec parisSpec = @@ -100,7 +111,12 @@ public class MergeProtocolScheduleTest { final GenesisConfigOptions config = GenesisConfigFile.fromConfig(jsonInput).getConfigOptions(); final ProtocolSchedule protocolSchedule = MergeProtocolSchedule.create( - config, false, MiningParameters.MINING_DISABLED, new BadBlockManager()); + config, + false, + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()); final ProtocolSpec parisSpec = protocolSchedule.getByBlockHeader( @@ -128,7 +144,12 @@ public class MergeProtocolScheduleTest { final GenesisConfigOptions config = GenesisConfigFile.mainnet().getConfigOptions(); final ProtocolSchedule protocolSchedule = MergeProtocolSchedule.create( - config, false, MiningParameters.MINING_DISABLED, new BadBlockManager()); + config, + false, + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()); final long lastParisBlockNumber = 17034869L; final ProtocolSpec parisSpec = @@ -160,7 +181,9 @@ public class MergeProtocolScheduleTest { GenesisConfigFile.DEFAULT.getConfigOptions(), false, MiningParameters.MINING_DISABLED, - new BadBlockManager()) + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .getByBlockHeader(blockHeader(0)); assertThat(london.getName()).isEqualTo("Paris"); diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeGenesisConfigHelper.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeGenesisConfigHelper.java index 54099f868..dcfe5f98e 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeGenesisConfigHelper.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeGenesisConfigHelper.java @@ -21,6 +21,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.ethereum.chain.BadBlockManager; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.io.IOException; import java.net.URI; @@ -56,6 +57,8 @@ public interface MergeGenesisConfigHelper { getPosGenesisConfigFile().getConfigOptions(), false, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); } } diff --git a/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java b/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java index 5cf74f945..3467dce9f 100644 --- a/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java +++ b/consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java @@ -437,7 +437,9 @@ public class TestContextBuilder { BFT_EXTRA_DATA_ENCODER, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); final BftValidatorOverrides validatorOverrides = convertBftForks(qbftForks); final TransactionSimulator transactionSimulator = diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleBuilder.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleBuilder.java index 58a50efa2..44c7ddfba 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleBuilder.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleBuilder.java @@ -31,6 +31,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.plugin.services.MetricsSystem; import java.util.Optional; @@ -50,6 +51,9 @@ public class QbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder * @param evmConfiguration the evm configuration * @param miningParameters The mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled. + * @param metricsSystem A metricSystem instance to be able to expose metrics in the underlying + * calls * @return the protocol schedule */ public static BftProtocolSchedule create( @@ -60,7 +64,9 @@ public class QbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder final BftExtraDataCodec bftExtraDataCodec, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return new QbftProtocolScheduleBuilder() .createProtocolSchedule( config, @@ -70,7 +76,9 @@ public class QbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder bftExtraDataCodec, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } /** @@ -82,6 +90,9 @@ public class QbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder * @param evmConfiguration the evm configuration * @param miningParameters The mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled. + * @param metricsSystem A metricSystem instance to be able to expose metrics in the underlying + * calls * @return the protocol schedule */ public static BftProtocolSchedule create( @@ -90,7 +101,9 @@ public class QbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder final BftExtraDataCodec bftExtraDataCodec, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return create( config, qbftForksSchedule, @@ -99,7 +112,9 @@ public class QbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder bftExtraDataCodec, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } /** @@ -111,6 +126,9 @@ public class QbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder * @param bftExtraDataCodec the bft extra data codec * @param miningParameters The mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled. + * @param metricsSystem A metricSystem instance to be able to expose metrics in the underlying + * calls * @return the protocol schedule */ public static ProtocolSchedule create( @@ -119,7 +137,9 @@ public class QbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder final boolean isRevertReasonEnabled, final BftExtraDataCodec bftExtraDataCodec, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return create( config, qbftForksSchedule, @@ -128,7 +148,9 @@ public class QbftProtocolScheduleBuilder extends BaseBftProtocolScheduleBuilder bftExtraDataCodec, EvmConfiguration.DEFAULT, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } @Override diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleTest.java index 07b3be34b..020d6e0e5 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/QbftProtocolScheduleTest.java @@ -41,6 +41,7 @@ import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.Util; import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.math.BigInteger; import java.util.Collection; @@ -138,7 +139,9 @@ public class QbftProtocolScheduleTest { bftExtraDataCodec, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); } private boolean validateHeader( diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerTest.java index 0aa1f7843..71ea4131a 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerTest.java @@ -78,6 +78,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.util.Subscribers; import java.math.BigInteger; @@ -184,7 +185,9 @@ public class QbftBlockHeightManagerTest { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); ProtocolSchedule protocolSchedule = new BftProtocolSchedule( diff --git a/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/Blake2bfMessageDigest.java b/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/Blake2bfMessageDigest.java index 63449d74b..ad4fe7ddb 100644 --- a/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/Blake2bfMessageDigest.java +++ b/crypto/algorithms/src/main/java/org/hyperledger/besu/crypto/Blake2bfMessageDigest.java @@ -34,6 +34,13 @@ public class Blake2bfMessageDigest extends BCMessageDigest implements Cloneable super(new Blake2bfDigest()); } + @Override + public Blake2bfMessageDigest clone() throws CloneNotSupportedException { + Blake2bfMessageDigest cloned = (Blake2bfMessageDigest) super.clone(); + cloned.digest = ((Blake2bfDigest) this.digest).clone(); + return cloned; + } + /** * Implementation of the `F` compression function of the Blake2b cryptographic hash function. * @@ -43,7 +50,7 @@ public class Blake2bfMessageDigest extends BCMessageDigest implements Cloneable * *

Optimized for 64-bit platforms */ - public static class Blake2bfDigest implements Digest { + public static class Blake2bfDigest implements Digest, Cloneable { /** The constant MESSAGE_LENGTH_BYTES. */ public static final int MESSAGE_LENGTH_BYTES = 213; @@ -71,18 +78,18 @@ public class Blake2bfMessageDigest extends BCMessageDigest implements Cloneable // buffer which holds serialized input for this compression function // [ 4 bytes for rounds ][ 64 bytes for h ][ 128 bytes for m ] // [ 8 bytes for t_0 ][ 8 bytes for t_1 ][ 1 byte for f ] - private final byte[] buffer; + private byte[] buffer; private int bufferPos; // deserialized inputs for f compression - private final long[] h; - private final long[] m; - private final long[] t; + private long[] h; + private long[] m; + private long[] t; private boolean f; private long rounds; // unsigned integer represented as long - private final long[] v; + private long[] v; private static boolean useNative; static { @@ -112,6 +119,17 @@ public class Blake2bfMessageDigest extends BCMessageDigest implements Cloneable v = new long[16]; } + @Override + public Blake2bfDigest clone() throws CloneNotSupportedException { + Blake2bfDigest cloned = (Blake2bfDigest) super.clone(); + cloned.buffer = this.buffer.clone(); + cloned.h = this.h.clone(); + cloned.m = this.m.clone(); + cloned.t = this.t.clone(); + cloned.v = this.v.clone(); + return cloned; + } + /** Disable native. */ public static void disableNative() { useNative = false; diff --git a/crypto/algorithms/src/test/java/org/hyperledger/besu/crypto/Blake2bfMessageDigestTest.java b/crypto/algorithms/src/test/java/org/hyperledger/besu/crypto/Blake2bfMessageDigestTest.java index bd00dc7da..390d7d414 100644 --- a/crypto/algorithms/src/test/java/org/hyperledger/besu/crypto/Blake2bfMessageDigestTest.java +++ b/crypto/algorithms/src/test/java/org/hyperledger/besu/crypto/Blake2bfMessageDigestTest.java @@ -17,6 +17,13 @@ package org.hyperledger.besu.crypto; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.stream.IntStream; + import org.bouncycastle.util.Pack; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -29,6 +36,16 @@ import org.junit.jupiter.params.provider.CsvFileSource; */ public class Blake2bfMessageDigestTest { + private static final SecureRandom SECURE_RANDOM; + + static { + try { + SECURE_RANDOM = SecureRandom.getInstanceStrong(); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + private Blake2bfMessageDigest messageDigest; // output when input is all 0 @@ -124,6 +141,39 @@ public class Blake2bfMessageDigestTest { .isInstanceOf(IllegalArgumentException.class); } + @SuppressWarnings("unchecked") + @Test + public void testDigestThreadSafety() throws ExecutionException, InterruptedException { + final byte[] input = new byte[213]; + ; + SECURE_RANDOM.nextBytes(input); + int numberOfHashes = 10; + + CompletableFuture[] futures = + IntStream.range(0, numberOfHashes) + .mapToObj( + i -> + CompletableFuture.supplyAsync( + () -> { + try { + MessageDigest clonedDigest = messageDigest.clone(); + clonedDigest.update(input); + byte[] digest = clonedDigest.digest(); + return digest; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + })) + .toArray(CompletableFuture[]::new); + + CompletableFuture.allOf(futures).get(); + + byte[] expectedHash = futures[0].get(); + for (CompletableFuture future : futures) { + assertThat(expectedHash).isEqualTo(future.get()); + } + } + @ParameterizedTest @CsvFileSource(resources = "eip152TestCases.csv", numLinesToSkip = 1) public void eip152TestCases(final String hexIn, final String hexExpected) { diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/StorageSlotKey.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/StorageSlotKey.java index a8bf7c9af..8404453cf 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/StorageSlotKey.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/StorageSlotKey.java @@ -94,7 +94,7 @@ public class StorageSlotKey implements Comparable { @Override public int hashCode() { - return Objects.hash(slotHash.hashCode()); + return slotHash.hashCode(); } @Override diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/BlockchainImporter.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/BlockchainImporter.java index 2a62331d3..3e261abf6 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/BlockchainImporter.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/BlockchainImporter.java @@ -24,6 +24,7 @@ import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions; import org.hyperledger.besu.ethereum.util.RawBlockIterator; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.net.URL; import java.nio.file.Paths; @@ -46,7 +47,9 @@ public class BlockchainImporter { MainnetProtocolSchedule.fromConfig( GenesisConfigFile.fromConfig(genesisJson).getConfigOptions(), MiningParameters.newDefault(), - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); final BlockHeaderFunctions blockHeaderFunctions = ScheduleBasedBlockHeaderFunctions.create(protocolSchedule); blocks = new ArrayList<>(); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java index af5228dc0..80626ef2f 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java @@ -109,7 +109,9 @@ public class JsonRpcHttpServiceHostAllowlistTest { MainnetProtocolSchedule.fromConfig( new StubGenesisConfigOptions().constantinopleBlock(0).chainId(CHAIN_ID), MiningParameters.MINING_DISABLED, - new BadBlockManager()), + new BadBlockManager(), + false, + new NoOpMetricsSystem()), mock(ProtocolContext.class), mock(FilterManager.class), mock(TransactionPool.class), diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java index 6ae5d37a0..0fb55fdf3 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java @@ -138,7 +138,11 @@ public class JsonRpcHttpServiceLoginTest { blockchainQueries, synchronizer, MainnetProtocolSchedule.fromConfig( - genesisConfigOptions, MiningParameters.MINING_DISABLED, new BadBlockManager()), + genesisConfigOptions, + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()), mock(ProtocolContext.class), mock(FilterManager.class), mock(TransactionPool.class), diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java index f8c9dbc18..a2a856333 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java @@ -118,7 +118,9 @@ public class JsonRpcHttpServiceTestBase { new StubGenesisConfigOptions().constantinopleBlock(0).chainId(CHAIN_ID), EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()), + new BadBlockManager(), + false, + new NoOpMetricsSystem()), mock(ProtocolContext.class), mock(FilterManager.class), mock(TransactionPool.class), diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java index 2f62e490b..1d3a3a087 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java @@ -123,7 +123,9 @@ public class JsonRpcHttpServiceTlsClientAuthTest { MainnetProtocolSchedule.fromConfig( new StubGenesisConfigOptions().constantinopleBlock(0).chainId(CHAIN_ID), MiningParameters.MINING_DISABLED, - new BadBlockManager()), + new BadBlockManager(), + false, + new NoOpMetricsSystem()), mock(ProtocolContext.class), mock(FilterManager.class), mock(TransactionPool.class), diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java index 2ff0833bc..684f843d2 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java @@ -111,7 +111,9 @@ class JsonRpcHttpServiceTlsMisconfigurationTest { MainnetProtocolSchedule.fromConfig( new StubGenesisConfigOptions().constantinopleBlock(0).chainId(CHAIN_ID), MiningParameters.MINING_DISABLED, - new BadBlockManager()), + new BadBlockManager(), + false, + new NoOpMetricsSystem()), mock(ProtocolContext.class), mock(FilterManager.class), mock(TransactionPool.class), diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java index e650f9d49..b6d7fa67f 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java @@ -112,7 +112,9 @@ public class JsonRpcHttpServiceTlsTest { MainnetProtocolSchedule.fromConfig( new StubGenesisConfigOptions().constantinopleBlock(0).chainId(CHAIN_ID), MiningParameters.MINING_DISABLED, - new BadBlockManager()), + new BadBlockManager(), + false, + new NoOpMetricsSystem()), mock(ProtocolContext.class), mock(FilterManager.class), mock(TransactionPool.class), diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java index 5fa137e31..75927c451 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java @@ -176,7 +176,9 @@ public class WebSocketServiceLoginTest { MainnetProtocolSchedule.fromConfig( genesisConfigOptions, MiningParameters.MINING_DISABLED, - new BadBlockManager()), + new BadBlockManager(), + false, + new NoOpMetricsSystem()), mock(ProtocolContext.class), mock(FilterManager.class), mock(TransactionPool.class), 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 2444d9db7..946d4ab09 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 @@ -395,7 +395,9 @@ abstract class AbstractBlockCreatorTest { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()) + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .createProtocolSchedule()) .build(); diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java index d70589ae8..c6ee45424 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java @@ -223,7 +223,9 @@ public abstract class AbstractBlockTransactionSelectorTest { GenesisConfigFile.fromResource("/dev.json").getConfigOptions(), EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); final MainnetTransactionProcessor mainnetTransactionProcessor = protocolSchedule.getByBlockHeader(blockHeader(0)).getTransactionProcessor(); diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java index 620638453..416e5fd23 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java @@ -36,6 +36,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.testutil.TestClock; import org.hyperledger.besu.util.number.Fraction; @@ -60,7 +61,9 @@ public class LegacyFeeMarketBlockTransactionSelectorTest false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()) + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .createProtocolSchedule(); } diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java index e9bfcfb76..a59841d4f 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java @@ -43,6 +43,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.data.TransactionSelectionResult; import org.hyperledger.besu.testutil.TestClock; import org.hyperledger.besu.util.number.Fraction; @@ -71,7 +72,9 @@ public class LondonFeeMarketBlockTransactionSelectorTest false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()) + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .createProtocolSchedule(); } diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java index 2cd5bc5e9..7e3c01200 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java @@ -97,8 +97,10 @@ class PoWBlockCreatorTest extends AbstractBlockCreatorTest { PrivacyParameters.DEFAULT, false, EvmConfiguration.DEFAULT, - miningParameters, - new BadBlockManager()) + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .createProtocolSchedule()) .build(); @@ -158,8 +160,10 @@ class PoWBlockCreatorTest extends AbstractBlockCreatorTest { PrivacyParameters.DEFAULT, false, EvmConfiguration.DEFAULT, - miningParameters, - new BadBlockManager()) + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .createProtocolSchedule()) .build(); @@ -209,8 +213,10 @@ class PoWBlockCreatorTest extends AbstractBlockCreatorTest { PrivacyParameters.DEFAULT, false, EvmConfiguration.DEFAULT, - miningParameters, - new BadBlockManager()) + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .createProtocolSchedule(); final ExecutionContextTestFixture executionContextTestFixture = ExecutionContextTestFixture.builder(genesisConfigFile) @@ -285,8 +291,10 @@ class PoWBlockCreatorTest extends AbstractBlockCreatorTest { PrivacyParameters.DEFAULT, false, EvmConfiguration.DEFAULT, - miningParameters, - new BadBlockManager()) + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .createProtocolSchedule(); final ExecutionContextTestFixture executionContextTestFixture = ExecutionContextTestFixture.builder(genesisConfigFile) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/difficulty/fixed/FixedDifficultyProtocolSchedule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/difficulty/fixed/FixedDifficultyProtocolSchedule.java index b7f8395d9..b86b2b0de 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/difficulty/fixed/FixedDifficultyProtocolSchedule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/difficulty/fixed/FixedDifficultyProtocolSchedule.java @@ -22,6 +22,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.plugin.services.MetricsSystem; /** A ProtocolSchedule which behaves similarly to MainNet, but with a much reduced difficulty. */ public class FixedDifficultyProtocolSchedule { @@ -32,7 +33,9 @@ public class FixedDifficultyProtocolSchedule { final boolean isRevertReasonEnabled, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return new ProtocolScheduleBuilder( config, ProtocolSpecAdapters.create( @@ -43,7 +46,9 @@ public class FixedDifficultyProtocolSchedule { isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager) + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem) .createProtocolSchedule(); } @@ -52,27 +57,35 @@ public class FixedDifficultyProtocolSchedule { final boolean isRevertReasonEnabled, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return create( config, PrivacyParameters.DEFAULT, isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } public static ProtocolSchedule create( final GenesisConfigOptions config, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return create( config, PrivacyParameters.DEFAULT, false, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } } 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 8ecfa453d..480a1d8d7 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 @@ -38,6 +38,7 @@ import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorld import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldStateUpdateAccumulator; import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup; import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; +import org.hyperledger.besu.evm.operation.BlockHashOperation; import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.evm.worldstate.WorldUpdater; @@ -110,57 +111,67 @@ public abstract class AbstractBlockProcessor implements BlockProcessor { protocolSpec.getBlockHashProcessor().processBlockHashes(blockchain, worldState, blockHeader); final BlockHashLookup blockHashLookup = new CachingBlockHashLookup(blockHeader, blockchain); - for (final Transaction transaction : transactions) { + final Address miningBeneficiary = miningBeneficiaryCalculator.calculateBeneficiary(blockHeader); + + Optional maybeParentHeader = + blockchain.getBlockHeader(blockHeader.getParentHash()); + + Wei blobGasPrice = + maybeParentHeader + .map( + parentHeader -> + protocolSpec + .getFeeMarket() + .blobGasPricePerGas( + calculateExcessBlobGasForParent(protocolSpec, parentHeader))) + .orElse(Wei.ZERO); + + final Optional preProcessingContext = + runBlockPreProcessing( + worldState, + privateMetadataUpdater, + blockHeader, + transactions, + miningBeneficiary, + blockHashLookup, + blobGasPrice); + + for (int i = 0; i < transactions.size(); i++) { + final Transaction transaction = transactions.get(i); if (!hasAvailableBlockBudget(blockHeader, transaction, currentGasUsed)) { return new BlockProcessingResult(Optional.empty(), "provided gas insufficient"); } + final WorldUpdater blockUpdater = worldState.updater(); - final WorldUpdater worldStateUpdater = worldState.updater(); - - final Address miningBeneficiary = - miningBeneficiaryCalculator.calculateBeneficiary(blockHeader); - - Optional maybeParentHeader = - blockchain.getBlockHeader(blockHeader.getParentHash()); - - Wei blobGasPrice = - maybeParentHeader - .map( - parentHeader -> - protocolSpec - .getFeeMarket() - .blobGasPricePerGas( - calculateExcessBlobGasForParent(protocolSpec, parentHeader))) - .orElse(Wei.ZERO); - - final TransactionProcessingResult result = - transactionProcessor.processTransaction( - worldStateUpdater, - blockHeader, - transaction, - miningBeneficiary, - OperationTracer.NO_TRACING, - blockHashLookup, - true, - TransactionValidationParams.processingBlock(), + TransactionProcessingResult transactionProcessingResult = + getTransactionProcessingResult( + preProcessingContext, + worldState, + blockUpdater, privateMetadataUpdater, - blobGasPrice); - if (result.isInvalid()) { + blockHeader, + blobGasPrice, + miningBeneficiary, + transaction, + i, + blockHashLookup); + if (transactionProcessingResult.isInvalid()) { String errorMessage = MessageFormat.format( "Block processing error: transaction invalid {0}. Block {1} Transaction {2}", - result.getValidationResult().getErrorMessage(), + transactionProcessingResult.getValidationResult().getErrorMessage(), blockHeader.getHash().toHexString(), transaction.getHash().toHexString()); LOG.info(errorMessage); if (worldState instanceof BonsaiWorldState) { - ((BonsaiWorldStateUpdateAccumulator) worldStateUpdater).reset(); + ((BonsaiWorldStateUpdateAccumulator) blockUpdater).reset(); } return new BlockProcessingResult(Optional.empty(), errorMessage); } - worldStateUpdater.commit(); - currentGasUsed += transaction.getGasLimit() - result.getGasRemaining(); + blockUpdater.commit(); + + currentGasUsed += transaction.getGasLimit() - transactionProcessingResult.getGasRemaining(); if (transaction.getVersionedHashes().isPresent()) { currentBlobGasUsed += (transaction.getVersionedHashes().get().size() * CancunGasCalculator.BLOB_GAS_PER_BLOB); @@ -168,7 +179,7 @@ public abstract class AbstractBlockProcessor implements BlockProcessor { final TransactionReceipt transactionReceipt = transactionReceiptFactory.create( - transaction.getType(), result, worldState, currentGasUsed); + transaction.getType(), transactionProcessingResult, worldState, currentGasUsed); receipts.add(transactionReceipt); } if (blockHeader.getBlobGasUsed().isPresent() @@ -235,6 +246,41 @@ public abstract class AbstractBlockProcessor implements BlockProcessor { Optional.of(new BlockProcessingOutputs(worldState, receipts, maybeRequests))); } + protected Optional runBlockPreProcessing( + final MutableWorldState worldState, + final PrivateMetadataUpdater privateMetadataUpdater, + final BlockHeader blockHeader, + final List transactions, + final Address miningBeneficiary, + final BlockHashOperation.BlockHashLookup blockHashLookup, + final Wei blobGasPrice) { + return Optional.empty(); + } + + protected TransactionProcessingResult getTransactionProcessingResult( + final Optional preProcessingContext, + final MutableWorldState worldState, + final WorldUpdater blockUpdater, + final PrivateMetadataUpdater privateMetadataUpdater, + final BlockHeader blockHeader, + final Wei blobGasPrice, + final Address miningBeneficiary, + final Transaction transaction, + final int location, + final BlockHashLookup blockHashLookup) { + return transactionProcessor.processTransaction( + blockUpdater, + blockHeader, + transaction, + miningBeneficiary, + OperationTracer.NO_TRACING, + blockHashLookup, + true, + TransactionValidationParams.processingBlock(), + privateMetadataUpdater, + blobGasPrice); + } + protected boolean hasAvailableBlockBudget( final BlockHeader blockHeader, final Transaction transaction, final long currentGasUsed) { final long remainingGasBudget = blockHeader.getGasLimit() - currentGasUsed; @@ -261,4 +307,7 @@ public abstract class AbstractBlockProcessor implements BlockProcessor { final BlockHeader header, final List ommers, final boolean skipZeroBlockRewards); + + public interface PreprocessingContext {} + ; } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java index aec844894..47c1747dc 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java @@ -38,6 +38,7 @@ import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.processor.ContractCreationProcessor; import org.hyperledger.besu.evm.processor.MessageCallProcessor; import org.hyperledger.besu.evm.worldstate.WorldState; +import org.hyperledger.besu.plugin.services.MetricsSystem; import java.math.BigInteger; import java.util.Collections; @@ -54,16 +55,23 @@ public class ClassicProtocolSpecs { } public static ProtocolSpecBuilder classicRecoveryInitDefinition( - final EvmConfiguration evmConfiguration) { - return MainnetProtocolSpecs.homesteadDefinition(evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return MainnetProtocolSpecs.homesteadDefinition( + evmConfiguration, isParallelTxProcessingEnabled, metricsSystem) .blockHeaderValidatorBuilder( feeMarket -> MainnetBlockHeaderValidator.createClassicValidator()) .name("ClassicRecoveryInit"); } public static ProtocolSpecBuilder tangerineWhistleDefinition( - final Optional chainId, final EvmConfiguration evmConfiguration) { - return MainnetProtocolSpecs.homesteadDefinition(evmConfiguration) + final Optional chainId, + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return MainnetProtocolSpecs.homesteadDefinition( + evmConfiguration, isParallelTxProcessingEnabled, metricsSystem) .isReplayProtectionSupported(true) .gasCalculator(TangerineWhistleGasCalculator::new) .transactionValidatorFactoryBuilder( @@ -74,8 +82,12 @@ public class ClassicProtocolSpecs { } public static ProtocolSpecBuilder dieHardDefinition( - final Optional chainId, final EvmConfiguration evmConfiguration) { - return tangerineWhistleDefinition(chainId, evmConfiguration) + final Optional chainId, + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return tangerineWhistleDefinition( + chainId, evmConfiguration, isParallelTxProcessingEnabled, metricsSystem) .gasCalculator(DieHardGasCalculator::new) .difficultyCalculator(ClassicDifficultyCalculators.DIFFICULTY_BOMB_PAUSED) .name("DieHard"); @@ -84,8 +96,11 @@ public class ClassicProtocolSpecs { public static ProtocolSpecBuilder gothamDefinition( final Optional chainId, final OptionalLong ecip1017EraRounds, - final EvmConfiguration evmConfiguration) { - return dieHardDefinition(chainId, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return dieHardDefinition( + chainId, evmConfiguration, isParallelTxProcessingEnabled, metricsSystem) .blockReward(MAX_BLOCK_REWARD) .difficultyCalculator(ClassicDifficultyCalculators.DIFFICULTY_BOMB_DELAYED) .blockProcessorBuilder( @@ -109,8 +124,15 @@ public class ClassicProtocolSpecs { public static ProtocolSpecBuilder defuseDifficultyBombDefinition( final Optional chainId, final OptionalLong ecip1017EraRounds, - final EvmConfiguration evmConfiguration) { - return gothamDefinition(chainId, ecip1017EraRounds, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return gothamDefinition( + chainId, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .difficultyCalculator(ClassicDifficultyCalculators.DIFFICULTY_BOMB_REMOVED) .transactionValidatorFactoryBuilder( (evm, gasLimitCalculator, feeMarket) -> @@ -123,8 +145,15 @@ public class ClassicProtocolSpecs { final Optional chainId, final boolean enableRevertReason, final OptionalLong ecip1017EraRounds, - final EvmConfiguration evmConfiguration) { - return gothamDefinition(chainId, ecip1017EraRounds, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return gothamDefinition( + chainId, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .evmBuilder(MainnetEVMs::byzantium) .evmConfiguration(evmConfiguration) .gasCalculator(SpuriousDragonGasCalculator::new) @@ -163,8 +192,16 @@ public class ClassicProtocolSpecs { final Optional chainId, final boolean enableRevertReason, final OptionalLong ecip1017EraRounds, - final EvmConfiguration evmConfiguration) { - return atlantisDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return atlantisDefinition( + chainId, + enableRevertReason, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .evmBuilder(MainnetEVMs::constantinople) .gasCalculator(PetersburgGasCalculator::new) .evmBuilder(MainnetEVMs::constantinople) @@ -176,8 +213,16 @@ public class ClassicProtocolSpecs { final Optional chainId, final boolean enableRevertReason, final OptionalLong ecip1017EraRounds, - final EvmConfiguration evmConfiguration) { - return aghartaDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return aghartaDefinition( + chainId, + enableRevertReason, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .gasCalculator(IstanbulGasCalculator::new) .evmBuilder( (gasCalculator, evmConfig) -> @@ -191,8 +236,16 @@ public class ClassicProtocolSpecs { final Optional chainId, final boolean enableRevertReason, final OptionalLong ecip1017EraRounds, - final EvmConfiguration evmConfiguration) { - return phoenixDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return phoenixDefinition( + chainId, + enableRevertReason, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .blockHeaderValidatorBuilder( feeMarket -> MainnetBlockHeaderValidator.createPgaBlockHeaderValidator( @@ -228,8 +281,16 @@ public class ClassicProtocolSpecs { final Optional chainId, final boolean enableRevertReason, final OptionalLong ecip1017EraRounds, - final EvmConfiguration evmConfiguration) { - return thanosDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return thanosDefinition( + chainId, + enableRevertReason, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .gasCalculator(BerlinGasCalculator::new) .transactionValidatorFactoryBuilder( (evm, gasLimitCalculator, feeMarket) -> @@ -250,8 +311,16 @@ public class ClassicProtocolSpecs { final Optional chainId, final boolean enableRevertReason, final OptionalLong ecip1017EraRounds, - final EvmConfiguration evmConfiguration) { - return magnetoDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return magnetoDefinition( + chainId, + enableRevertReason, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .gasCalculator(LondonGasCalculator::new) .contractCreationProcessorBuilder( evm -> @@ -264,8 +333,16 @@ public class ClassicProtocolSpecs { final Optional chainId, final boolean enableRevertReason, final OptionalLong ecip1017EraRounds, - final EvmConfiguration evmConfiguration) { - return mystiqueDefinition(chainId, enableRevertReason, ecip1017EraRounds, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return mystiqueDefinition( + chainId, + enableRevertReason, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) // EIP-3860 .gasCalculator(ShanghaiGasCalculator::new) // EIP-3855 diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSchedule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSchedule.java index 794f96cfb..88b6a5ae1 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSchedule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSchedule.java @@ -21,6 +21,7 @@ import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.difficulty.fixed.FixedDifficultyCalculators; import org.hyperledger.besu.ethereum.difficulty.fixed.FixedDifficultyProtocolSchedule; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.plugin.services.MetricsSystem; import java.math.BigInteger; import java.util.function.Function; @@ -40,6 +41,8 @@ public class MainnetProtocolSchedule { * @param evmConfiguration how to configure the EVMs jumpdest cache * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled + * @param metricsSystem A metricSystem instance to expose metrics in the underlying calls * @return A configured mainnet protocol schedule */ public static ProtocolSchedule fromConfig( @@ -48,7 +51,9 @@ public class MainnetProtocolSchedule { final boolean isRevertReasonEnabled, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { if (FixedDifficultyCalculators.isFixedDifficultyInConfig(config)) { return FixedDifficultyProtocolSchedule.create( config, @@ -56,7 +61,9 @@ public class MainnetProtocolSchedule { isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } return new ProtocolScheduleBuilder( config, @@ -66,7 +73,9 @@ public class MainnetProtocolSchedule { isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager) + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem) .createProtocolSchedule(); } @@ -79,6 +88,7 @@ public class MainnetProtocolSchedule { * @param evmConfiguration how to configure the EVMs jumpdest cache * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled. * @return A configured mainnet protocol schedule */ public static ProtocolSchedule fromConfig( @@ -86,14 +96,18 @@ public class MainnetProtocolSchedule { final boolean isRevertReasonEnabled, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return fromConfig( config, PrivacyParameters.DEFAULT, isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } /** @@ -104,20 +118,25 @@ public class MainnetProtocolSchedule { * @param evmConfiguration size of * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled. * @return A configured mainnet protocol schedule */ public static ProtocolSchedule fromConfig( final GenesisConfigOptions config, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return fromConfig( config, PrivacyParameters.DEFAULT, false, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } /** @@ -127,18 +146,23 @@ public class MainnetProtocolSchedule { * starting points * @param miningParameters the mining parameters * @param badBlockManager the cache to use to keep invalid blocks + * @param isParallelTxProcessingEnabled indicates whether parallel transaction is enabled. * @return A configured mainnet protocol schedule */ public static ProtocolSchedule fromConfig( final GenesisConfigOptions config, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return fromConfig( config, PrivacyParameters.DEFAULT, false, EvmConfiguration.DEFAULT, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecFactory.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecFactory.java index aa9bae6c7..55bfb363b 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecFactory.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecFactory.java @@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.mainnet; import org.hyperledger.besu.config.GenesisConfigOptions; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.plugin.services.MetricsSystem; import java.math.BigInteger; import java.util.Optional; @@ -29,118 +30,209 @@ public class MainnetProtocolSpecFactory { private final OptionalLong ecip1017EraRounds; private final EvmConfiguration evmConfiguration; private final MiningParameters miningParameters; + private final boolean isParallelTxProcessingEnabled; + private final MetricsSystem metricsSystem; public MainnetProtocolSpecFactory( final Optional chainId, final boolean isRevertReasonEnabled, final OptionalLong ecip1017EraRounds, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { this.chainId = chainId; this.isRevertReasonEnabled = isRevertReasonEnabled; this.ecip1017EraRounds = ecip1017EraRounds; this.evmConfiguration = evmConfiguration; this.miningParameters = miningParameters; + this.isParallelTxProcessingEnabled = isParallelTxProcessingEnabled; + this.metricsSystem = metricsSystem; } public ProtocolSpecBuilder frontierDefinition() { - return MainnetProtocolSpecs.frontierDefinition(evmConfiguration); + return MainnetProtocolSpecs.frontierDefinition( + evmConfiguration, isParallelTxProcessingEnabled, metricsSystem); } public ProtocolSpecBuilder homesteadDefinition() { - return MainnetProtocolSpecs.homesteadDefinition(evmConfiguration); + return MainnetProtocolSpecs.homesteadDefinition( + evmConfiguration, isParallelTxProcessingEnabled, metricsSystem); } public ProtocolSpecBuilder daoRecoveryInitDefinition() { - return MainnetProtocolSpecs.daoRecoveryInitDefinition(evmConfiguration); + return MainnetProtocolSpecs.daoRecoveryInitDefinition( + evmConfiguration, isParallelTxProcessingEnabled, metricsSystem); } public ProtocolSpecBuilder daoRecoveryTransitionDefinition() { - return MainnetProtocolSpecs.daoRecoveryTransitionDefinition(evmConfiguration); + return MainnetProtocolSpecs.daoRecoveryTransitionDefinition( + evmConfiguration, isParallelTxProcessingEnabled, metricsSystem); } public ProtocolSpecBuilder tangerineWhistleDefinition() { - return MainnetProtocolSpecs.tangerineWhistleDefinition(evmConfiguration); + return MainnetProtocolSpecs.tangerineWhistleDefinition( + evmConfiguration, isParallelTxProcessingEnabled, metricsSystem); } public ProtocolSpecBuilder spuriousDragonDefinition() { - return MainnetProtocolSpecs.spuriousDragonDefinition(chainId, evmConfiguration); + return MainnetProtocolSpecs.spuriousDragonDefinition( + chainId, evmConfiguration, isParallelTxProcessingEnabled, metricsSystem); } public ProtocolSpecBuilder byzantiumDefinition() { return MainnetProtocolSpecs.byzantiumDefinition( - chainId, isRevertReasonEnabled, evmConfiguration); + chainId, + isRevertReasonEnabled, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder constantinopleDefinition() { return MainnetProtocolSpecs.constantinopleDefinition( - chainId, isRevertReasonEnabled, evmConfiguration); + chainId, + isRevertReasonEnabled, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder petersburgDefinition() { return MainnetProtocolSpecs.petersburgDefinition( - chainId, isRevertReasonEnabled, evmConfiguration); + chainId, + isRevertReasonEnabled, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder istanbulDefinition() { return MainnetProtocolSpecs.istanbulDefinition( - chainId, isRevertReasonEnabled, evmConfiguration); + chainId, + isRevertReasonEnabled, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder muirGlacierDefinition() { return MainnetProtocolSpecs.muirGlacierDefinition( - chainId, isRevertReasonEnabled, evmConfiguration); + chainId, + isRevertReasonEnabled, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder berlinDefinition() { - return MainnetProtocolSpecs.berlinDefinition(chainId, isRevertReasonEnabled, evmConfiguration); + return MainnetProtocolSpecs.berlinDefinition( + chainId, + isRevertReasonEnabled, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder londonDefinition(final GenesisConfigOptions genesisConfigOptions) { return MainnetProtocolSpecs.londonDefinition( - chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + isRevertReasonEnabled, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder arrowGlacierDefinition( final GenesisConfigOptions genesisConfigOptions) { return MainnetProtocolSpecs.arrowGlacierDefinition( - chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + isRevertReasonEnabled, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder grayGlacierDefinition( final GenesisConfigOptions genesisConfigOptions) { return MainnetProtocolSpecs.grayGlacierDefinition( - chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + isRevertReasonEnabled, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder parisDefinition(final GenesisConfigOptions genesisConfigOptions) { return MainnetProtocolSpecs.parisDefinition( - chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + isRevertReasonEnabled, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder shanghaiDefinition(final GenesisConfigOptions genesisConfigOptions) { return MainnetProtocolSpecs.shanghaiDefinition( - chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + isRevertReasonEnabled, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder cancunDefinition(final GenesisConfigOptions genesisConfigOptions) { return MainnetProtocolSpecs.cancunDefinition( - chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + isRevertReasonEnabled, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder cancunEOFDefinition(final GenesisConfigOptions genesisConfigOptions) { return MainnetProtocolSpecs.cancunEOFDefinition( - chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + isRevertReasonEnabled, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder pragueDefinition(final GenesisConfigOptions genesisConfigOptions) { return MainnetProtocolSpecs.pragueDefinition( - chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + isRevertReasonEnabled, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder pragueEOFDefinition(final GenesisConfigOptions genesisConfigOptions) { return MainnetProtocolSpecs.pragueEOFDefinition( - chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + isRevertReasonEnabled, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); } /** @@ -156,7 +248,13 @@ public class MainnetProtocolSpecFactory { */ public ProtocolSpecBuilder futureEipsDefinition(final GenesisConfigOptions genesisConfigOptions) { return MainnetProtocolSpecs.futureEipsDefinition( - chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + isRevertReasonEnabled, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); } /** @@ -172,57 +270,100 @@ public class MainnetProtocolSpecFactory { public ProtocolSpecBuilder experimentalEipsDefinition( final GenesisConfigOptions genesisConfigOptions) { return MainnetProtocolSpecs.experimentalEipsDefinition( - chainId, isRevertReasonEnabled, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + isRevertReasonEnabled, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); } //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// // Classic Protocol Specs public ProtocolSpecBuilder dieHardDefinition() { - return ClassicProtocolSpecs.dieHardDefinition(chainId, evmConfiguration); + return ClassicProtocolSpecs.dieHardDefinition( + chainId, evmConfiguration, isParallelTxProcessingEnabled, metricsSystem); } public ProtocolSpecBuilder gothamDefinition() { - return ClassicProtocolSpecs.gothamDefinition(chainId, ecip1017EraRounds, evmConfiguration); + return ClassicProtocolSpecs.gothamDefinition( + chainId, ecip1017EraRounds, evmConfiguration, isParallelTxProcessingEnabled, metricsSystem); } public ProtocolSpecBuilder defuseDifficultyBombDefinition() { return ClassicProtocolSpecs.defuseDifficultyBombDefinition( - chainId, ecip1017EraRounds, evmConfiguration); + chainId, ecip1017EraRounds, evmConfiguration, isParallelTxProcessingEnabled, metricsSystem); } public ProtocolSpecBuilder atlantisDefinition() { return ClassicProtocolSpecs.atlantisDefinition( - chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration); + chainId, + isRevertReasonEnabled, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder aghartaDefinition() { return ClassicProtocolSpecs.aghartaDefinition( - chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration); + chainId, + isRevertReasonEnabled, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder phoenixDefinition() { return ClassicProtocolSpecs.phoenixDefinition( - chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration); + chainId, + isRevertReasonEnabled, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder thanosDefinition() { return ClassicProtocolSpecs.thanosDefinition( - chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration); + chainId, + isRevertReasonEnabled, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder magnetoDefinition() { return ClassicProtocolSpecs.magnetoDefinition( - chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration); + chainId, + isRevertReasonEnabled, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder mystiqueDefinition() { return ClassicProtocolSpecs.mystiqueDefinition( - chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration); + chainId, + isRevertReasonEnabled, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolSpecBuilder spiralDefinition() { return ClassicProtocolSpecs.spiralDefinition( - chainId, isRevertReasonEnabled, ecip1017EraRounds, evmConfiguration); + chainId, + isRevertReasonEnabled, + ecip1017EraRounds, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java index 6f09df923..36d8257ff 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java @@ -39,6 +39,7 @@ import org.hyperledger.besu.ethereum.mainnet.blockhash.FrontierBlockHashProcesso import org.hyperledger.besu.ethereum.mainnet.blockhash.PragueBlockHashProcessor; import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; +import org.hyperledger.besu.ethereum.mainnet.parallelization.MainnetParallelBlockProcessor; import org.hyperledger.besu.ethereum.privacy.PrivateTransactionProcessor; import org.hyperledger.besu.ethereum.privacy.PrivateTransactionValidator; import org.hyperledger.besu.ethereum.privacy.storage.PrivateMetadataUpdater; @@ -67,6 +68,7 @@ import org.hyperledger.besu.evm.processor.ContractCreationProcessor; import org.hyperledger.besu.evm.processor.MessageCallProcessor; import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.evm.worldstate.WorldUpdater; +import org.hyperledger.besu.plugin.services.MetricsSystem; import java.io.IOException; import java.math.BigInteger; @@ -101,7 +103,10 @@ public abstract class MainnetProtocolSpecs { private MainnetProtocolSpecs() {} - public static ProtocolSpecBuilder frontierDefinition(final EvmConfiguration evmConfiguration) { + public static ProtocolSpecBuilder frontierDefinition( + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return new ProtocolSpecBuilder() .gasCalculator(FrontierGasCalculator::new) .gasLimitCalculatorBuilder(feeMarket -> new FrontierTargetingGasLimitCalculator()) @@ -152,7 +157,10 @@ public abstract class MainnetProtocolSpecs { .transactionReceiptFactory(MainnetProtocolSpecs::frontierTransactionReceiptFactory) .blockReward(FRONTIER_BLOCK_REWARD) .skipZeroBlockRewards(false) - .blockProcessorBuilder(MainnetBlockProcessor::new) + .blockProcessorBuilder( + isParallelTxProcessingEnabled + ? new MainnetParallelBlockProcessor.ParallelBlockProcessorBuilder(metricsSystem) + : MainnetBlockProcessor::new) .blockValidatorBuilder(MainnetProtocolSpecs.blockValidatorBuilder()) .blockImporterBuilder(MainnetBlockImporter::new) .blockHeaderFunctions(new MainnetBlockHeaderFunctions()) @@ -173,8 +181,11 @@ public abstract class MainnetProtocolSpecs { return MainnetBlockValidator::new; } - public static ProtocolSpecBuilder homesteadDefinition(final EvmConfiguration evmConfiguration) { - return frontierDefinition(evmConfiguration) + public static ProtocolSpecBuilder homesteadDefinition( + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return frontierDefinition(evmConfiguration, isParallelTxProcessingEnabled, metricsSystem) .gasCalculator(HomesteadGasCalculator::new) .evmBuilder(MainnetEVMs::homestead) .contractCreationProcessorBuilder( @@ -190,8 +201,10 @@ public abstract class MainnetProtocolSpecs { } public static ProtocolSpecBuilder daoRecoveryInitDefinition( - final EvmConfiguration evmConfiguration) { - return homesteadDefinition(evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return homesteadDefinition(evmConfiguration, isParallelTxProcessingEnabled, metricsSystem) .blockHeaderValidatorBuilder(feeMarket -> MainnetBlockHeaderValidator.createDaoValidator()) .blockProcessorBuilder( (transactionProcessor, @@ -201,33 +214,53 @@ public abstract class MainnetProtocolSpecs { skipZeroBlockRewards, protocolSchedule) -> new DaoBlockProcessor( - new MainnetBlockProcessor( - transactionProcessor, - transactionReceiptFactory, - blockReward, - miningBeneficiaryCalculator, - skipZeroBlockRewards, - protocolSchedule))) + isParallelTxProcessingEnabled + ? new MainnetParallelBlockProcessor( + transactionProcessor, + transactionReceiptFactory, + blockReward, + miningBeneficiaryCalculator, + skipZeroBlockRewards, + protocolSchedule, + metricsSystem) + : new MainnetBlockProcessor( + transactionProcessor, + transactionReceiptFactory, + blockReward, + miningBeneficiaryCalculator, + skipZeroBlockRewards, + protocolSchedule))) .name("DaoRecoveryInit"); } public static ProtocolSpecBuilder daoRecoveryTransitionDefinition( - final EvmConfiguration evmConfiguration) { - return daoRecoveryInitDefinition(evmConfiguration) - .blockProcessorBuilder(MainnetBlockProcessor::new) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return daoRecoveryInitDefinition(evmConfiguration, isParallelTxProcessingEnabled, metricsSystem) + .blockProcessorBuilder( + isParallelTxProcessingEnabled + ? new MainnetParallelBlockProcessor.ParallelBlockProcessorBuilder(metricsSystem) + : MainnetBlockProcessor::new) .name("DaoRecoveryTransition"); } public static ProtocolSpecBuilder tangerineWhistleDefinition( - final EvmConfiguration evmConfiguration) { - return homesteadDefinition(evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return homesteadDefinition(evmConfiguration, isParallelTxProcessingEnabled, metricsSystem) .gasCalculator(TangerineWhistleGasCalculator::new) .name("TangerineWhistle"); } public static ProtocolSpecBuilder spuriousDragonDefinition( - final Optional chainId, final EvmConfiguration evmConfiguration) { - return tangerineWhistleDefinition(evmConfiguration) + final Optional chainId, + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return tangerineWhistleDefinition( + evmConfiguration, isParallelTxProcessingEnabled, metricsSystem) .isReplayProtectionSupported(true) .gasCalculator(SpuriousDragonGasCalculator::new) .skipZeroBlockRewards(true) @@ -271,8 +304,11 @@ public abstract class MainnetProtocolSpecs { public static ProtocolSpecBuilder byzantiumDefinition( final Optional chainId, final boolean enableRevertReason, - final EvmConfiguration evmConfiguration) { - return spuriousDragonDefinition(chainId, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return spuriousDragonDefinition( + chainId, evmConfiguration, isParallelTxProcessingEnabled, metricsSystem) .gasCalculator(ByzantiumGasCalculator::new) .evmBuilder(MainnetEVMs::byzantium) .precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::byzantium) @@ -301,8 +337,15 @@ public abstract class MainnetProtocolSpecs { public static ProtocolSpecBuilder constantinopleDefinition( final Optional chainId, final boolean enableRevertReason, - final EvmConfiguration evmConfiguration) { - return byzantiumDefinition(chainId, enableRevertReason, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return byzantiumDefinition( + chainId, + enableRevertReason, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .difficultyCalculator(MainnetDifficultyCalculators.CONSTANTINOPLE) .gasCalculator(ConstantinopleGasCalculator::new) .evmBuilder(MainnetEVMs::constantinople) @@ -313,8 +356,15 @@ public abstract class MainnetProtocolSpecs { public static ProtocolSpecBuilder petersburgDefinition( final Optional chainId, final boolean enableRevertReason, - final EvmConfiguration evmConfiguration) { - return constantinopleDefinition(chainId, enableRevertReason, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return constantinopleDefinition( + chainId, + enableRevertReason, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .gasCalculator(PetersburgGasCalculator::new) .name("Petersburg"); } @@ -322,8 +372,15 @@ public abstract class MainnetProtocolSpecs { public static ProtocolSpecBuilder istanbulDefinition( final Optional chainId, final boolean enableRevertReason, - final EvmConfiguration evmConfiguration) { - return petersburgDefinition(chainId, enableRevertReason, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return petersburgDefinition( + chainId, + enableRevertReason, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .gasCalculator(IstanbulGasCalculator::new) .evmBuilder( (gasCalculator, jdCacheConfig) -> @@ -344,8 +401,15 @@ public abstract class MainnetProtocolSpecs { static ProtocolSpecBuilder muirGlacierDefinition( final Optional chainId, final boolean enableRevertReason, - final EvmConfiguration evmConfiguration) { - return istanbulDefinition(chainId, enableRevertReason, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return istanbulDefinition( + chainId, + enableRevertReason, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .difficultyCalculator(MainnetDifficultyCalculators.MUIR_GLACIER) .name("MuirGlacier"); } @@ -353,8 +417,15 @@ public abstract class MainnetProtocolSpecs { static ProtocolSpecBuilder berlinDefinition( final Optional chainId, final boolean enableRevertReason, - final EvmConfiguration evmConfiguration) { - return muirGlacierDefinition(chainId, enableRevertReason, evmConfiguration) + final EvmConfiguration evmConfiguration, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { + return muirGlacierDefinition( + chainId, + enableRevertReason, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .gasCalculator(BerlinGasCalculator::new) .transactionValidatorFactoryBuilder( (evm, gasLimitCalculator, feeMarket) -> @@ -376,7 +447,9 @@ public abstract class MainnetProtocolSpecs { final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { final long londonForkBlockNumber = genesisConfigOptions.getLondonBlockNumber().orElse(Long.MAX_VALUE); final BaseFeeMarket londonFeeMarket; @@ -390,7 +463,12 @@ public abstract class MainnetProtocolSpecs { londonFeeMarket = FeeMarket.london(londonForkBlockNumber, genesisConfigOptions.getBaseFeePerGas()); } - return berlinDefinition(chainId, enableRevertReason, evmConfiguration) + return berlinDefinition( + chainId, + enableRevertReason, + evmConfiguration, + isParallelTxProcessingEnabled, + metricsSystem) .feeMarket(londonFeeMarket) .gasCalculator(LondonGasCalculator::new) .gasLimitCalculatorBuilder( @@ -455,9 +533,17 @@ public abstract class MainnetProtocolSpecs { final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return londonDefinition( - chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters) + chainId, + enableRevertReason, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem) .difficultyCalculator(MainnetDifficultyCalculators.ARROW_GLACIER) .name("ArrowGlacier"); } @@ -467,9 +553,17 @@ public abstract class MainnetProtocolSpecs { final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return arrowGlacierDefinition( - chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters) + chainId, + enableRevertReason, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem) .difficultyCalculator(MainnetDifficultyCalculators.GRAY_GLACIER) .name("GrayGlacier"); } @@ -479,10 +573,18 @@ public abstract class MainnetProtocolSpecs { final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return grayGlacierDefinition( - chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters) + chainId, + enableRevertReason, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem) .evmBuilder( (gasCalculator, jdCacheConfig) -> MainnetEVMs.paris(gasCalculator, chainId.orElse(BigInteger.ZERO), evmConfiguration)) @@ -499,9 +601,17 @@ public abstract class MainnetProtocolSpecs { final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return parisDefinition( - chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters) + chainId, + enableRevertReason, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem) // gas calculator has new code to support EIP-3860 limit and meter initcode .gasCalculator(ShanghaiGasCalculator::new) // EVM has a new operation for EIP-3855 PUSH0 instruction @@ -550,7 +660,9 @@ public abstract class MainnetProtocolSpecs { final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { final long londonForkBlockNumber = genesisConfigOptions.getLondonBlockNumber().orElse(0L); final BaseFeeMarket cancunFeeMarket; if (genesisConfigOptions.isZeroBaseFee()) { @@ -565,7 +677,13 @@ public abstract class MainnetProtocolSpecs { } return shanghaiDefinition( - chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters) + chainId, + enableRevertReason, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem) .feeMarket(cancunFeeMarket) // gas calculator for EIP-4844 blob gas .gasCalculator(CancunGasCalculator::new) @@ -623,11 +741,19 @@ public abstract class MainnetProtocolSpecs { final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { ProtocolSpecBuilder protocolSpecBuilder = cancunDefinition( - chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + enableRevertReason, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); return addEOF(chainId, evmConfiguration, protocolSpecBuilder).name("CancunEOF"); } @@ -636,14 +762,22 @@ public abstract class MainnetProtocolSpecs { final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { final Address depositContractAddress = genesisConfigOptions.getDepositContractAddress().orElse(DEFAULT_DEPOSIT_CONTRACT_ADDRESS); return cancunDefinition( - chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters) - // EIP-3074 AUTH and AUTHCALL gas + chainId, + enableRevertReason, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem) + // EIP-3074 AUTH and AUTCALL gas .gasCalculator(PragueGasCalculator::new) // EIP-3074 AUTH and AUTHCALL .evmBuilder( @@ -686,11 +820,19 @@ public abstract class MainnetProtocolSpecs { final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { ProtocolSpecBuilder protocolSpecBuilder = pragueDefinition( - chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters); + chainId, + enableRevertReason, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); return addEOF(chainId, evmConfiguration, protocolSpecBuilder).name("PragueEOF"); } @@ -722,9 +864,17 @@ public abstract class MainnetProtocolSpecs { final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return pragueEOFDefinition( - chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters) + chainId, + enableRevertReason, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem) // Use Future EIP configured EVM .evmBuilder( (gasCalculator, jdCacheConfig) -> @@ -749,10 +899,18 @@ public abstract class MainnetProtocolSpecs { final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters) { + final MiningParameters miningParameters, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { return futureEipsDefinition( - chainId, enableRevertReason, genesisConfigOptions, evmConfiguration, miningParameters) + chainId, + enableRevertReason, + genesisConfigOptions, + evmConfiguration, + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem) .evmBuilder( (gasCalculator, jdCacheConfig) -> MainnetEVMs.experimentalEips( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java index 9ad1db7d8..5fa2b119f 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java @@ -507,7 +507,6 @@ public class MainnetTransactionProcessor { final long gasUsedByTransaction = transaction.getGasLimit() - initialFrame.getRemainingGas(); // update the coinbase - final var coinbase = worldState.getOrCreate(miningBeneficiary); final long usedGas = transaction.getGasLimit() - refundedGas; final CoinbaseFeePriceCalculator coinbaseCalculator; if (blockHeader.getBaseFee().isPresent()) { @@ -529,6 +528,9 @@ public class MainnetTransactionProcessor { final Wei coinbaseWeiDelta = coinbaseCalculator.price(usedGas, transactionGasPrice, blockHeader.getBaseFee()); + operationTracer.traceBeforeRewardTransaction(worldUpdater, transaction, coinbaseWeiDelta); + + final var coinbase = worldState.getOrCreate(miningBeneficiary); coinbase.incrementBalance(coinbaseWeiDelta); authorizedCodeService.resetAuthorities(); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java index 649442f88..1cb3a5cb3 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java @@ -20,6 +20,7 @@ import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.privacy.PrivateTransactionValidator; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.plugin.services.MetricsSystem; import java.math.BigInteger; import java.util.NavigableMap; @@ -45,6 +46,8 @@ public class ProtocolScheduleBuilder { private final EvmConfiguration evmConfiguration; private final MiningParameters miningParameters; private final BadBlockManager badBlockManager; + private final boolean isParallelTxProcessingEnabled; + private final MetricsSystem metricsSystem; public ProtocolScheduleBuilder( final GenesisConfigOptions config, @@ -54,7 +57,9 @@ public class ProtocolScheduleBuilder { final boolean isRevertReasonEnabled, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { this( config, Optional.of(defaultChainId), @@ -63,7 +68,9 @@ public class ProtocolScheduleBuilder { isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } public ProtocolScheduleBuilder( @@ -73,7 +80,9 @@ public class ProtocolScheduleBuilder { final boolean isRevertReasonEnabled, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { this( config, Optional.empty(), @@ -82,7 +91,9 @@ public class ProtocolScheduleBuilder { isRevertReasonEnabled, evmConfiguration, miningParameters, - badBlockManager); + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); } private ProtocolScheduleBuilder( @@ -93,7 +104,9 @@ public class ProtocolScheduleBuilder { final boolean isRevertReasonEnabled, final EvmConfiguration evmConfiguration, final MiningParameters miningParameters, - final BadBlockManager badBlockManager) { + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem) { this.config = config; this.protocolSpecAdapters = protocolSpecAdapters; this.privacyParameters = privacyParameters; @@ -102,6 +115,8 @@ public class ProtocolScheduleBuilder { this.defaultChainId = defaultChainId; this.miningParameters = miningParameters; this.badBlockManager = badBlockManager; + this.isParallelTxProcessingEnabled = isParallelTxProcessingEnabled; + this.metricsSystem = metricsSystem; } public ProtocolSchedule createProtocolSchedule() { @@ -121,7 +136,9 @@ public class ProtocolScheduleBuilder { config.getEcip1017EraRounds(), evmConfiguration.overrides( config.getContractSizeLimit(), OptionalInt.empty(), config.getEvmStackSize()), - miningParameters); + miningParameters, + isParallelTxProcessingEnabled, + metricsSystem); validateForkOrdering(); @@ -203,7 +220,8 @@ public class ProtocolScheduleBuilder { protocolSchedule, BuilderMapEntry.MilestoneType.BLOCK_NUMBER, classicBlockNumber, - ClassicProtocolSpecs.classicRecoveryInitDefinition(evmConfiguration), + ClassicProtocolSpecs.classicRecoveryInitDefinition( + evmConfiguration, isParallelTxProcessingEnabled, metricsSystem), Function.identity()); protocolSchedule.putBlockNumberMilestone( classicBlockNumber + 1, originalProtocolSpec); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java index cd886b6c8..0d792b787 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java @@ -51,6 +51,7 @@ public class ProtocolSpecBuilder { private Function gasLimitCalculatorBuilder; private Wei blockReward; private boolean skipZeroBlockRewards; + private BlockHeaderFunctions blockHeaderFunctions; private AbstractBlockProcessor.TransactionReceiptFactory transactionReceiptFactory; private DifficultyCalculator difficultyCalculator; @@ -66,9 +67,11 @@ public class ProtocolSpecBuilder { private BiFunction messageCallProcessorBuilder; private TransactionProcessorBuilder transactionProcessorBuilder; + private BlockProcessorBuilder blockProcessorBuilder; private BlockValidatorBuilder blockValidatorBuilder; private BlockImporterBuilder blockImporterBuilder; + private String name; private MiningBeneficiaryCalculator miningBeneficiaryCalculator; private PrivacyParameters privacyParameters; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/MainnetParallelBlockProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/MainnetParallelBlockProcessor.java new file mode 100644 index 000000000..d1f0d9c51 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/MainnetParallelBlockProcessor.java @@ -0,0 +1,199 @@ +/* + * 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.parallelization; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.MutableWorldState; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.mainnet.BlockProcessor; +import org.hyperledger.besu.ethereum.mainnet.MainnetBlockProcessor; +import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor; +import org.hyperledger.besu.ethereum.mainnet.MiningBeneficiaryCalculator; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecBuilder; +import org.hyperledger.besu.ethereum.privacy.storage.PrivateMetadataUpdater; +import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; +import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldState; +import org.hyperledger.besu.evm.operation.BlockHashOperation; +import org.hyperledger.besu.evm.worldstate.WorldUpdater; +import org.hyperledger.besu.metrics.BesuMetricCategory; +import org.hyperledger.besu.plugin.services.MetricsSystem; +import org.hyperledger.besu.plugin.services.metrics.Counter; + +import java.util.List; +import java.util.Optional; + +public class MainnetParallelBlockProcessor extends MainnetBlockProcessor { + + private final Optional metricsSystem; + private final Optional confirmedParallelizedTransactionCounter; + private final Optional conflictingButCachedTransactionCounter; + + public MainnetParallelBlockProcessor( + final MainnetTransactionProcessor transactionProcessor, + final TransactionReceiptFactory transactionReceiptFactory, + final Wei blockReward, + final MiningBeneficiaryCalculator miningBeneficiaryCalculator, + final boolean skipZeroBlockRewards, + final ProtocolSchedule protocolSchedule, + final MetricsSystem metricsSystem) { + super( + transactionProcessor, + transactionReceiptFactory, + blockReward, + miningBeneficiaryCalculator, + skipZeroBlockRewards, + protocolSchedule); + this.metricsSystem = Optional.of(metricsSystem); + this.confirmedParallelizedTransactionCounter = + Optional.of( + this.metricsSystem + .get() + .createCounter( + BesuMetricCategory.BLOCK_PROCESSING, + "parallelized_transactions_counter", + "Counter for the number of parallelized transactions during block processing")); + + this.conflictingButCachedTransactionCounter = + Optional.of( + this.metricsSystem + .get() + .createCounter( + BesuMetricCategory.BLOCK_PROCESSING, + "conflicted_transactions_counter", + "Counter for the number of conflicted transactions during block processing")); + } + + @Override + protected Optional runBlockPreProcessing( + final MutableWorldState worldState, + final PrivateMetadataUpdater privateMetadataUpdater, + final BlockHeader blockHeader, + final List transactions, + final Address miningBeneficiary, + final BlockHashOperation.BlockHashLookup blockHashLookup, + final Wei blobGasPrice) { + if ((worldState instanceof DiffBasedWorldState)) { + ParallelizedConcurrentTransactionProcessor parallelizedConcurrentTransactionProcessor = + new ParallelizedConcurrentTransactionProcessor(transactionProcessor); + // runAsyncBlock, if activated, facilitates the non-blocking parallel execution of + // transactions in the background through an optimistic strategy. + parallelizedConcurrentTransactionProcessor.runAsyncBlock( + worldState, + blockHeader, + transactions, + miningBeneficiary, + blockHashLookup, + blobGasPrice, + privateMetadataUpdater); + return Optional.of( + new ParallelizedPreProcessingContext(parallelizedConcurrentTransactionProcessor)); + } + return Optional.empty(); + } + + @Override + protected TransactionProcessingResult getTransactionProcessingResult( + final Optional preProcessingContext, + final MutableWorldState worldState, + final WorldUpdater blockUpdater, + final PrivateMetadataUpdater privateMetadataUpdater, + final BlockHeader blockHeader, + final Wei blobGasPrice, + final Address miningBeneficiary, + final Transaction transaction, + final int location, + final BlockHashOperation.BlockHashLookup blockHashLookup) { + + TransactionProcessingResult transactionProcessingResult = null; + + if (preProcessingContext.isPresent()) { + final ParallelizedPreProcessingContext parallelizedPreProcessingContext = + (ParallelizedPreProcessingContext) preProcessingContext.get(); + transactionProcessingResult = + parallelizedPreProcessingContext + .getParallelizedConcurrentTransactionProcessor() + .applyParallelizedTransactionResult( + worldState, + miningBeneficiary, + transaction, + location, + confirmedParallelizedTransactionCounter, + conflictingButCachedTransactionCounter) + .orElse(null); + } + + if (transactionProcessingResult == null) { + return super.getTransactionProcessingResult( + preProcessingContext, + worldState, + blockUpdater, + privateMetadataUpdater, + blockHeader, + blobGasPrice, + miningBeneficiary, + transaction, + location, + blockHashLookup); + } else { + return transactionProcessingResult; + } + } + + static class ParallelizedPreProcessingContext implements PreprocessingContext { + final ParallelizedConcurrentTransactionProcessor parallelizedConcurrentTransactionProcessor; + + public ParallelizedPreProcessingContext( + final ParallelizedConcurrentTransactionProcessor + parallelizedConcurrentTransactionProcessor) { + this.parallelizedConcurrentTransactionProcessor = parallelizedConcurrentTransactionProcessor; + } + + public ParallelizedConcurrentTransactionProcessor + getParallelizedConcurrentTransactionProcessor() { + return parallelizedConcurrentTransactionProcessor; + } + } + + public static class ParallelBlockProcessorBuilder + implements ProtocolSpecBuilder.BlockProcessorBuilder { + + final MetricsSystem metricsSystem; + + public ParallelBlockProcessorBuilder(final MetricsSystem metricsSystem) { + this.metricsSystem = metricsSystem; + } + + @Override + public BlockProcessor apply( + final MainnetTransactionProcessor transactionProcessor, + final TransactionReceiptFactory transactionReceiptFactory, + final Wei blockReward, + final MiningBeneficiaryCalculator miningBeneficiaryCalculator, + final boolean skipZeroBlockRewards, + final ProtocolSchedule protocolSchedule) { + return new MainnetParallelBlockProcessor( + transactionProcessor, + transactionReceiptFactory, + blockReward, + miningBeneficiaryCalculator, + skipZeroBlockRewards, + protocolSchedule, + metricsSystem); + } + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/ParallelizedConcurrentTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/ParallelizedConcurrentTransactionProcessor.java new file mode 100644 index 000000000..c6beaa2f4 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/ParallelizedConcurrentTransactionProcessor.java @@ -0,0 +1,268 @@ +/* + * 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.parallelization; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.MutableWorldState; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor; +import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams; +import org.hyperledger.besu.ethereum.privacy.storage.PrivateMetadataUpdater; +import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; +import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.NoopBonsaiCachedMerkleTrieLoader; +import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldState; +import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.DiffBasedWorldState; +import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.DiffBasedWorldStateUpdateAccumulator; +import org.hyperledger.besu.evm.operation.BlockHashOperation; +import org.hyperledger.besu.evm.tracing.OperationTracer; +import org.hyperledger.besu.evm.worldstate.WorldView; +import org.hyperledger.besu.plugin.services.metrics.Counter; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +import com.google.common.annotations.VisibleForTesting; + +/** + * Optimizes transaction processing by executing transactions in parallel within a given block. + * Transactions are executed optimistically in a non-blocking manner. After execution, the class + * checks for potential conflicts among transactions to ensure data integrity before applying the + * results to the world state. + */ +@SuppressWarnings({"unchecked", "rawtypes"}) +public class ParallelizedConcurrentTransactionProcessor { + + private static final int NCPU = Runtime.getRuntime().availableProcessors(); + private static final Executor executor = Executors.newFixedThreadPool(NCPU); + + private final MainnetTransactionProcessor transactionProcessor; + + private final TransactionCollisionDetector transactionCollisionDetector; + + private final Map + parallelizedTransactionContextByLocation = new ConcurrentHashMap<>(); + + /** + * Constructs a PreloadConcurrentTransactionProcessor with a specified transaction processor. This + * processor is responsible for the individual processing of transactions. + * + * @param transactionProcessor The transaction processor for processing individual transactions. + */ + public ParallelizedConcurrentTransactionProcessor( + final MainnetTransactionProcessor transactionProcessor) { + this.transactionProcessor = transactionProcessor; + this.transactionCollisionDetector = new TransactionCollisionDetector(); + } + + @VisibleForTesting + public ParallelizedConcurrentTransactionProcessor( + final MainnetTransactionProcessor transactionProcessor, + final TransactionCollisionDetector transactionCollisionDetector) { + this.transactionProcessor = transactionProcessor; + this.transactionCollisionDetector = transactionCollisionDetector; + } + + /** + * Initiates the parallel and optimistic execution of transactions within a block by creating a + * copy of the world state for each transaction. This method processes transactions in a + * non-blocking manner. Transactions are executed against their respective copies of the world + * state, ensuring that the original world state passed as a parameter remains unmodified during + * this process. + * + * @param worldState Mutable world state intended for applying transaction results. This world + * state is not modified directly; instead, copies are made for transaction execution. + * @param blockHeader Header of the current block containing the transactions. + * @param transactions List of transactions to be processed. + * @param miningBeneficiary Address of the beneficiary to receive mining rewards. + * @param blockHashLookup Function for block hash lookup. + * @param blobGasPrice Gas price for blob transactions. + * @param privateMetadataUpdater Updater for private transaction metadata. + */ + public void runAsyncBlock( + final MutableWorldState worldState, + final BlockHeader blockHeader, + final List transactions, + final Address miningBeneficiary, + final BlockHashOperation.BlockHashLookup blockHashLookup, + final Wei blobGasPrice, + final PrivateMetadataUpdater privateMetadataUpdater) { + for (int i = 0; i < transactions.size(); i++) { + final Transaction transaction = transactions.get(i); + final int transactionLocation = i; + /* + * All transactions are executed in the background by copying the world state of the block on which the transactions need to be executed, ensuring that each one has its own accumulator. + */ + CompletableFuture.runAsync( + () -> + runTransaction( + worldState, + blockHeader, + transactionLocation, + transaction, + miningBeneficiary, + blockHashLookup, + blobGasPrice, + privateMetadataUpdater), + executor); + } + } + + @VisibleForTesting + public void runTransaction( + final MutableWorldState worldState, + final BlockHeader blockHeader, + final int transactionLocation, + final Transaction transaction, + final Address miningBeneficiary, + final BlockHashOperation.BlockHashLookup blockHashLookup, + final Wei blobGasPrice, + final PrivateMetadataUpdater privateMetadataUpdater) { + try (final DiffBasedWorldState roundWorldState = + new BonsaiWorldState( + (BonsaiWorldState) worldState, new NoopBonsaiCachedMerkleTrieLoader())) { + roundWorldState.freeze(); // make the clone frozen + final ParallelizedTransactionContext.Builder contextBuilder = + new ParallelizedTransactionContext.Builder(); + final DiffBasedWorldStateUpdateAccumulator roundWorldStateUpdater = + (DiffBasedWorldStateUpdateAccumulator) roundWorldState.updater(); + final TransactionProcessingResult result = + transactionProcessor.processTransaction( + roundWorldStateUpdater, + blockHeader, + transaction, + miningBeneficiary, + new OperationTracer() { + @Override + public void traceBeforeRewardTransaction( + final WorldView worldView, + final org.hyperledger.besu.datatypes.Transaction tx, + final Wei miningReward) { + /* + * This part checks if the mining beneficiary's account was accessed before increasing its balance for rewards. + * Indeed, if the transaction has interacted with the address to read or modify it, + * it means that the value is necessary for the proper execution of the transaction and will therefore be considered in collision detection. + * If this is not the case, we can ignore this address during conflict detection. + */ + if (transactionCollisionDetector + .getAddressesTouchedByTransaction( + transaction, Optional.of(roundWorldStateUpdater)) + .contains(miningBeneficiary)) { + contextBuilder.isMiningBeneficiaryTouchedPreRewardByTransaction(true); + } + contextBuilder.miningBeneficiaryReward(miningReward); + } + }, + blockHashLookup, + true, + TransactionValidationParams.processingBlock(), + privateMetadataUpdater, + blobGasPrice); + + // commit the accumulator in order to apply all the modifications + roundWorldState.getAccumulator().commit(); + + contextBuilder + .transactionAccumulator(roundWorldState.getAccumulator()) + .transactionProcessingResult(result); + + final ParallelizedTransactionContext parallelizedTransactionContext = contextBuilder.build(); + if (!parallelizedTransactionContext.isMiningBeneficiaryTouchedPreRewardByTransaction()) { + /* + * If the address of the mining beneficiary has been touched only for adding rewards, + * we remove it from the accumulator to avoid a false positive collision. + * The balance will be increased during the sequential processing. + */ + roundWorldStateUpdater.getAccountsToUpdate().remove(miningBeneficiary); + } + parallelizedTransactionContextByLocation.put( + transactionLocation, parallelizedTransactionContext); + } + } + + /** + * Applies the results of parallelized transactions to the world state after checking for + * conflicts. + * + *

If a transaction was executed optimistically without any detected conflicts, its result is + * directly applied to the world state. If there is a conflict, this method does not apply the + * transaction's modifications directly to the world state. Instead, it caches the data read from + * the database during the transaction's execution. This cached data is then used to optimize the + * replay of the transaction by reducing the need for additional reads from the disk, thereby + * making the replay process faster. This approach ensures that the integrity of the world state + * is maintained while optimizing the performance of transaction processing. + * + * @param worldState Mutable world state intended for applying transaction results. + * @param miningBeneficiary Address of the beneficiary for mining rewards. + * @param transaction Transaction for which the result is to be applied. + * @param transactionLocation Index of the transaction within the block. + * @param confirmedParallelizedTransactionCounter Metric counter for confirmed parallelized + * transactions + * @param conflictingButCachedTransactionCounter Metric counter for conflicting but cached + * transactions + * @return Optional containing the transaction processing result if applied, or empty if the + * transaction needs to be replayed due to a conflict. + */ + public Optional applyParallelizedTransactionResult( + final MutableWorldState worldState, + final Address miningBeneficiary, + final Transaction transaction, + final int transactionLocation, + final Optional confirmedParallelizedTransactionCounter, + final Optional conflictingButCachedTransactionCounter) { + final DiffBasedWorldState diffBasedWorldState = (DiffBasedWorldState) worldState; + final DiffBasedWorldStateUpdateAccumulator blockAccumulator = + (DiffBasedWorldStateUpdateAccumulator) diffBasedWorldState.updater(); + final ParallelizedTransactionContext parallelizedTransactionContext = + parallelizedTransactionContextByLocation.remove(transactionLocation); + /* + * If `parallelizedTransactionContext` is not null, it means that the transaction had time to complete in the background. + */ + if (parallelizedTransactionContext != null) { + final DiffBasedWorldStateUpdateAccumulator transactionAccumulator = + parallelizedTransactionContext.transactionAccumulator(); + final TransactionProcessingResult transactionProcessingResult = + parallelizedTransactionContext.transactionProcessingResult(); + final boolean hasCollision = + transactionCollisionDetector.hasCollision( + transaction, miningBeneficiary, parallelizedTransactionContext, blockAccumulator); + if (transactionProcessingResult.isSuccessful() && !hasCollision) { + blockAccumulator + .getOrCreate(miningBeneficiary) + .incrementBalance(parallelizedTransactionContext.miningBeneficiaryReward()); + + blockAccumulator.importStateChangesFromSource(transactionAccumulator); + + if (confirmedParallelizedTransactionCounter.isPresent()) + confirmedParallelizedTransactionCounter.get().inc(); + return Optional.of(transactionProcessingResult); + } else { + blockAccumulator.importPriorStateFromSource(transactionAccumulator); + if (conflictingButCachedTransactionCounter.isPresent()) + conflictingButCachedTransactionCounter.get().inc(); + // If there is a conflict, we return an empty result to signal the block processor to + // re-execute the transaction. + return Optional.empty(); + } + } + return Optional.empty(); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/ParallelizedTransactionContext.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/ParallelizedTransactionContext.java new file mode 100644 index 000000000..30305ce00 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/ParallelizedTransactionContext.java @@ -0,0 +1,133 @@ +/* + * 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.parallelization; + +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; +import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.DiffBasedWorldStateUpdateAccumulator; + +import java.util.Objects; + +public final class ParallelizedTransactionContext { + private final DiffBasedWorldStateUpdateAccumulator transactionAccumulator; + private final TransactionProcessingResult transactionProcessingResult; + private final boolean isMiningBeneficiaryTouchedPreRewardByTransaction; + private final Wei miningBeneficiaryReward; + + public ParallelizedTransactionContext( + final DiffBasedWorldStateUpdateAccumulator transactionAccumulator, + final TransactionProcessingResult transactionProcessingResult, + final boolean isMiningBeneficiaryTouchedPreRewardByTransaction, + final Wei miningBeneficiaryReward) { + this.transactionAccumulator = transactionAccumulator; + this.transactionProcessingResult = transactionProcessingResult; + this.isMiningBeneficiaryTouchedPreRewardByTransaction = + isMiningBeneficiaryTouchedPreRewardByTransaction; + this.miningBeneficiaryReward = miningBeneficiaryReward; + } + + public DiffBasedWorldStateUpdateAccumulator transactionAccumulator() { + return transactionAccumulator; + } + + public TransactionProcessingResult transactionProcessingResult() { + return transactionProcessingResult; + } + + public boolean isMiningBeneficiaryTouchedPreRewardByTransaction() { + return isMiningBeneficiaryTouchedPreRewardByTransaction; + } + + public Wei miningBeneficiaryReward() { + return miningBeneficiaryReward; + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) return true; + if (obj == null || obj.getClass() != this.getClass()) return false; + var that = (ParallelizedTransactionContext) obj; + return Objects.equals(this.transactionAccumulator, that.transactionAccumulator) + && Objects.equals(this.transactionProcessingResult, that.transactionProcessingResult) + && this.isMiningBeneficiaryTouchedPreRewardByTransaction + == that.isMiningBeneficiaryTouchedPreRewardByTransaction + && Objects.equals(this.miningBeneficiaryReward, that.miningBeneficiaryReward); + } + + @Override + public int hashCode() { + return Objects.hash( + transactionAccumulator, + transactionProcessingResult, + isMiningBeneficiaryTouchedPreRewardByTransaction, + miningBeneficiaryReward); + } + + @Override + public String toString() { + return "ParallelizedTransactionContext[" + + "transactionAccumulator=" + + transactionAccumulator + + ", " + + "transactionProcessingResult=" + + transactionProcessingResult + + ", " + + "isMiningBeneficiaryTouchedPreRewardByTransaction=" + + isMiningBeneficiaryTouchedPreRewardByTransaction + + ", " + + "miningBeneficiaryReward=" + + miningBeneficiaryReward + + ']'; + } + + public static class Builder { + private DiffBasedWorldStateUpdateAccumulator transactionAccumulator; + private TransactionProcessingResult transactionProcessingResult; + private boolean isMiningBeneficiaryTouchedPreRewardByTransaction; + private Wei miningBeneficiaryReward = Wei.ZERO; + + public Builder transactionAccumulator( + final DiffBasedWorldStateUpdateAccumulator transactionAccumulator) { + this.transactionAccumulator = transactionAccumulator; + return this; + } + + public Builder transactionProcessingResult( + final TransactionProcessingResult transactionProcessingResult) { + this.transactionProcessingResult = transactionProcessingResult; + return this; + } + + public Builder isMiningBeneficiaryTouchedPreRewardByTransaction( + final boolean isMiningBeneficiaryTouchedPreRewardByTransaction) { + this.isMiningBeneficiaryTouchedPreRewardByTransaction = + isMiningBeneficiaryTouchedPreRewardByTransaction; + return this; + } + + public Builder miningBeneficiaryReward(final Wei miningBeneficiaryReward) { + this.miningBeneficiaryReward = miningBeneficiaryReward; + return this; + } + + public ParallelizedTransactionContext build() { + return new ParallelizedTransactionContext( + transactionAccumulator, + transactionProcessingResult, + isMiningBeneficiaryTouchedPreRewardByTransaction, + miningBeneficiaryReward); + } + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/TransactionCollisionDetector.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/TransactionCollisionDetector.java new file mode 100644 index 000000000..4120c0edb --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/parallelization/TransactionCollisionDetector.java @@ -0,0 +1,114 @@ +/* + * 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.parallelization; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.trie.diffbased.common.worldview.accumulator.DiffBasedWorldStateUpdateAccumulator; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Optional; +import java.util.Set; + +public class TransactionCollisionDetector { + + /** + * Determines if a transaction has a collision based on the addresses it touches. A collision + * occurs if the transaction touches the mining beneficiary address or if there are common + * addresses touched by both the transaction and other transactions within the same block. + * + * @param transaction The transaction to check for collisions. + * @param miningBeneficiary The address of the mining beneficiary. + * @param parallelizedTransactionContext The context containing the accumulator for the + * transaction. + * @param blockAccumulator The accumulator for the block. + * @return true if there is a collision; false otherwise. + */ + public boolean hasCollision( + final Transaction transaction, + final Address miningBeneficiary, + final ParallelizedTransactionContext parallelizedTransactionContext, + final DiffBasedWorldStateUpdateAccumulator blockAccumulator) { + final Set

addressesTouchedByTransaction = + getAddressesTouchedByTransaction( + transaction, Optional.of(parallelizedTransactionContext.transactionAccumulator())); + if (addressesTouchedByTransaction.contains(miningBeneficiary)) { + return true; + } + final Set
addressesTouchedByBlock = + getAddressesTouchedByBlock(Optional.of(blockAccumulator)); + final Iterator
it = addressesTouchedByTransaction.iterator(); + boolean commonAddressFound = false; + while (it.hasNext() && !commonAddressFound) { + if (addressesTouchedByBlock.contains(it.next())) { + commonAddressFound = true; + } + } + return commonAddressFound; + } + + /** + * Retrieves the set of addresses that were touched by a transaction. This includes the sender and + * recipient of the transaction, as well as any addresses that were read from or written to by the + * transaction's execution. + * + * @param transaction The transaction to analyze. + * @param accumulator An optional accumulator containing state changes made by the transaction. + * @return A set of addresses touched by the transaction. + */ + public Set
getAddressesTouchedByTransaction( + final Transaction transaction, + final Optional> accumulator) { + HashSet
addresses = new HashSet<>(); + addresses.add(transaction.getSender()); + if (transaction.getTo().isPresent()) { + addresses.add(transaction.getTo().get()); + } + accumulator.ifPresent( + diffBasedWorldStateUpdateAccumulator -> { + diffBasedWorldStateUpdateAccumulator + .getAccountsToUpdate() + .forEach((address, diffBasedValue) -> addresses.add(address)); + addresses.addAll(diffBasedWorldStateUpdateAccumulator.getDeletedAccountAddresses()); + }); + return addresses; + } + + /** + * Retrieves the set of addresses that were touched by all transactions within a block. This + * method filters out addresses that were only read and not modified. + * + * @param accumulator An optional accumulator containing state changes made by the block. + * @return A set of addresses that were modified by the block's transactions. + */ + private Set
getAddressesTouchedByBlock( + final Optional> accumulator) { + HashSet
addresses = new HashSet<>(); + accumulator.ifPresent( + diffBasedWorldStateUpdateAccumulator -> { + diffBasedWorldStateUpdateAccumulator + .getAccountsToUpdate() + .forEach( + (address, diffBasedValue) -> { + if (!diffBasedValue.isUnchanged()) { + addresses.add(address); + } + }); + addresses.addAll(diffBasedWorldStateUpdateAccumulator.getDeletedAccountAddresses()); + }); + return addresses; + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/cache/NoopBonsaiCachedMerkleTrieLoader.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/cache/NoopBonsaiCachedMerkleTrieLoader.java new file mode 100644 index 000000000..8f58e697f --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/cache/NoopBonsaiCachedMerkleTrieLoader.java @@ -0,0 +1,44 @@ +/* + * 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.trie.diffbased.bonsai.cache; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.StorageSlotKey; +import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; + +public class NoopBonsaiCachedMerkleTrieLoader extends BonsaiCachedMerkleTrieLoader { + + public NoopBonsaiCachedMerkleTrieLoader() { + super(new NoOpMetricsSystem()); + } + + @Override + public void preLoadAccount( + final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage, + final Hash worldStateRootHash, + final Address account) { + // noop + } + + @Override + public void preLoadStorageSlot( + final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage, + final Address account, + final StorageSlotKey slotKey) { + // noop + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/worldview/BonsaiWorldState.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/worldview/BonsaiWorldState.java index ad838aa52..b62805c1f 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/worldview/BonsaiWorldState.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/worldview/BonsaiWorldState.java @@ -76,6 +76,18 @@ public class BonsaiWorldState extends DiffBasedWorldState { diffBasedWorldStateConfig); } + public BonsaiWorldState( + final BonsaiWorldState worldState, + final BonsaiCachedMerkleTrieLoader cachedMerkleTrieLoader) { + this( + new BonsaiWorldStateLayerStorage(worldState.getWorldStateStorage()), + cachedMerkleTrieLoader, + worldState.cachedWorldStorageManager, + worldState.trieLogManager, + worldState.accumulator.getEvmConfiguration(), + new DiffBasedWorldStateConfig(worldState.worldStateConfig)); + } + public BonsaiWorldState( final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage, final BonsaiCachedMerkleTrieLoader bonsaiCachedMerkleTrieLoader, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/accumulator/DiffBasedWorldStateUpdateAccumulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/accumulator/DiffBasedWorldStateUpdateAccumulator.java index b5bae0aed..0799ed3db 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/accumulator/DiffBasedWorldStateUpdateAccumulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/trie/diffbased/common/worldview/accumulator/DiffBasedWorldStateUpdateAccumulator.java @@ -90,7 +90,7 @@ public abstract class DiffBasedWorldStateUpdateAccumulator source) { + public void cloneFromUpdater(final DiffBasedWorldStateUpdateAccumulator source) { accountsToUpdate.putAll(source.getAccountsToUpdate()); codeToUpdate.putAll(source.codeToUpdate); storageToClear.addAll(source.storageToClear); @@ -100,6 +100,120 @@ public abstract class DiffBasedWorldStateUpdateAccumulator source) { + source + .getAccountsToUpdate() + .forEach( + (address, diffBasedValue) -> { + ACCOUNT copyPrior = + diffBasedValue.getPrior() != null + ? copyAccount(diffBasedValue.getPrior(), this, false) + : null; + ACCOUNT copyUpdated = + diffBasedValue.getUpdated() != null + ? copyAccount(diffBasedValue.getUpdated(), this, true) + : null; + accountsToUpdate.put(address, new DiffBasedValue<>(copyPrior, copyUpdated)); + }); + source + .getCodeToUpdate() + .forEach( + (address, diffBasedValue) -> { + codeToUpdate.put( + address, + new DiffBasedValue<>(diffBasedValue.getPrior(), diffBasedValue.getUpdated())); + }); + source + .getStorageToUpdate() + .forEach( + (address, slots) -> { + StorageConsumingMap> storageConsumingMap = + storageToUpdate.computeIfAbsent( + address, + k -> + new StorageConsumingMap<>( + address, new ConcurrentHashMap<>(), storagePreloader)); + slots.forEach( + (storageSlotKey, uInt256DiffBasedValue) -> { + storageConsumingMap.put( + storageSlotKey, + new DiffBasedValue<>( + uInt256DiffBasedValue.getPrior(), uInt256DiffBasedValue.getUpdated())); + }); + }); + storageToClear.addAll(source.storageToClear); + + this.isAccumulatorStateChanged = true; + } + + /** + * Imports unchanged state data from an external source into the current state. This method + * focuses on integrating state data from the specified source that has been read but not + * modified. + * + *

The method ensures that only new, unmodified data from the source is added to the current + * state. If a state data has already been read or modified in the current state, it will not be + * added again to avoid overwriting any existing modifications. + * + * @param source The source accumulator + */ + public void importPriorStateFromSource( + final DiffBasedWorldStateUpdateAccumulator source) { + + source + .getAccountsToUpdate() + .forEach( + (address, diffBasedValue) -> { + ACCOUNT copyPrior = + diffBasedValue.getPrior() != null + ? copyAccount(diffBasedValue.getPrior(), this, false) + : null; + ACCOUNT copyUpdated = + diffBasedValue.getPrior() != null + ? copyAccount(diffBasedValue.getPrior(), this, true) + : null; + accountsToUpdate.putIfAbsent(address, new DiffBasedValue<>(copyPrior, copyUpdated)); + }); + source + .getCodeToUpdate() + .forEach( + (address, diffBasedValue) -> { + codeToUpdate.putIfAbsent( + address, + new DiffBasedValue<>(diffBasedValue.getPrior(), diffBasedValue.getPrior())); + }); + source + .getStorageToUpdate() + .forEach( + (address, slots) -> { + StorageConsumingMap> storageConsumingMap = + storageToUpdate.computeIfAbsent( + address, + k -> + new StorageConsumingMap<>( + address, new ConcurrentHashMap<>(), storagePreloader)); + slots.forEach( + (storageSlotKey, uInt256DiffBasedValue) -> { + storageConsumingMap.putIfAbsent( + storageSlotKey, + new DiffBasedValue<>( + uInt256DiffBasedValue.getPrior(), uInt256DiffBasedValue.getPrior())); + }); + }); + this.isAccumulatorStateChanged = true; + } + protected Consumer> getAccountPreloader() { return accountPreloader; } @@ -108,7 +222,7 @@ public abstract class DiffBasedWorldStateUpdateAccumulator accountValue = accountsToUpdate.computeIfAbsent( @@ -305,7 +420,6 @@ public abstract class DiffBasedWorldStateUpdateAccumulator updatedAccountValue = accountsToUpdate.get(updatedAddress); - final Map> pendingStorageUpdates = storageToUpdate.computeIfAbsent( updatedAddress, @@ -359,12 +473,6 @@ public abstract class DiffBasedWorldStateUpdateAccumulator Hash.EMPTY, + blobGasPrice, + privateMetadataUpdater); + + verify(transactionProcessor, times(1)) + .processTransaction( + any(DiffBasedWorldStateUpdateAccumulator.class), + eq(blockHeader), + eq(transaction), + eq(miningBeneficiary), + any(OperationTracer.class), + any(BlockHashOperation.BlockHashLookup.class), + eq(true), + eq(TransactionValidationParams.processingBlock()), + eq(privateMetadataUpdater), + eq(blobGasPrice)); + + assertTrue( + processor + .applyParallelizedTransactionResult( + worldState, miningBeneficiary, transaction, 0, Optional.empty(), Optional.empty()) + .isPresent(), + "Expected the transaction context to be stored"); + } + + @Test + void testRunTransactionWithFailure() { + Address miningBeneficiary = Address.fromHexString("0x1"); + Wei blobGasPrice = Wei.ZERO; + + when(transactionProcessor.processTransaction( + any(), any(), any(), any(), any(), any(), anyBoolean(), any(), any(), any())) + .thenReturn( + TransactionProcessingResult.failed( + 0, + 0, + ValidationResult.invalid( + TransactionInvalidReason.BLOB_GAS_PRICE_BELOW_CURRENT_BLOB_BASE_FEE), + Optional.of(Bytes.EMPTY))); + + processor.runTransaction( + worldState, + blockHeader, + 0, + transaction, + miningBeneficiary, + (blockNumber) -> Hash.EMPTY, + blobGasPrice, + privateMetadataUpdater); + + Optional result = + processor.applyParallelizedTransactionResult( + worldState, miningBeneficiary, transaction, 0, Optional.empty(), Optional.empty()); + assertTrue(result.isEmpty(), "Expected the transaction result to indicate a failure"); + } + + @Test + void testRunTransactionWithConflict() { + + Address miningBeneficiary = Address.fromHexString("0x1"); + Wei blobGasPrice = Wei.ZERO; + + Mockito.when( + transactionProcessor.processTransaction( + any(), any(), any(), any(), any(), any(), anyBoolean(), any(), any(), any())) + .thenReturn( + TransactionProcessingResult.successful( + Collections.emptyList(), 0, 0, Bytes.EMPTY, ValidationResult.valid())); + + processor.runTransaction( + worldState, + blockHeader, + 0, + transaction, + miningBeneficiary, + (blockNumber) -> Hash.EMPTY, + blobGasPrice, + privateMetadataUpdater); + + verify(transactionProcessor, times(1)) + .processTransaction( + any(DiffBasedWorldStateUpdateAccumulator.class), + eq(blockHeader), + eq(transaction), + eq(miningBeneficiary), + any(OperationTracer.class), + any(BlockHashOperation.BlockHashLookup.class), + eq(true), + eq(TransactionValidationParams.processingBlock()), + eq(privateMetadataUpdater), + eq(blobGasPrice)); + + // simulate a conflict + when(transactionCollisionDetector.hasCollision(any(), any(), any(), any())).thenReturn(true); + + Optional result = + processor.applyParallelizedTransactionResult( + worldState, miningBeneficiary, transaction, 0, Optional.empty(), Optional.empty()); + assertTrue(result.isEmpty(), "Expected no transaction result to be applied due to conflict"); + } +} diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/parallelization/TransactionCollisionDetectorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/parallelization/TransactionCollisionDetectorTest.java new file mode 100644 index 000000000..0cd1bad3c --- /dev/null +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/parallelization/TransactionCollisionDetectorTest.java @@ -0,0 +1,290 @@ +/* + * 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.parallelization; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.BonsaiAccount; +import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldState; +import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldStateUpdateAccumulator; +import org.hyperledger.besu.ethereum.trie.diffbased.common.DiffBasedValue; +import org.hyperledger.besu.evm.internal.EvmConfiguration; + +import java.math.BigInteger; + +import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class TransactionCollisionDetectorTest { + + private TransactionCollisionDetector collisionDetector; + @Mock BonsaiWorldState worldState; + BonsaiWorldStateUpdateAccumulator bonsaiUpdater; + BonsaiWorldStateUpdateAccumulator trxUpdater; + + @BeforeEach + public void setUp() { + collisionDetector = new TransactionCollisionDetector(); + bonsaiUpdater = + new BonsaiWorldStateUpdateAccumulator( + worldState, (__, ___) -> {}, (__, ___) -> {}, EvmConfiguration.DEFAULT); + trxUpdater = + new BonsaiWorldStateUpdateAccumulator( + worldState, (__, ___) -> {}, (__, ___) -> {}, EvmConfiguration.DEFAULT); + } + + private Transaction createTransaction(final Address sender, final Address to) { + return new Transaction.Builder() + .nonce(1) + .gasPrice(Wei.of(1)) + .gasLimit(21000) + .to(to) + .value(Wei.ZERO) + .payload(Bytes.EMPTY) + .chainId(BigInteger.ONE) + .sender(sender) + .build(); + } + + private BonsaiAccount createAccount(final Address address) { + return new BonsaiAccount( + worldState, + address, + Hash.hash(Address.ZERO), + 0, + Wei.ONE, + Hash.EMPTY_TRIE_HASH, + Hash.EMPTY, + false); + } + + @Test + void testCollisionWithModifiedBalance() { + final Address address = Address.fromHexString("0x1"); + final BonsaiAccount priorAccountValue = createAccount(address); + final BonsaiAccount nextAccountValue = new BonsaiAccount(priorAccountValue, worldState, true); + nextAccountValue.setBalance(Wei.MAX_WEI); + + // Simulate that the address was already modified in the block + bonsaiUpdater + .getAccountsToUpdate() + .put(address, new DiffBasedValue<>(priorAccountValue, nextAccountValue)); + + final Transaction transaction = createTransaction(address, address); + + // Simulate that the address is read in the next transaction + trxUpdater + .getAccountsToUpdate() + .put(address, new DiffBasedValue<>(priorAccountValue, priorAccountValue)); + + boolean hasCollision = + collisionDetector.hasCollision( + transaction, + Address.ZERO, + new ParallelizedTransactionContext(trxUpdater, null, false, Wei.ZERO), + bonsaiUpdater); + + assertTrue(hasCollision, "Expected a collision with the modified address"); + } + + @Test + void testCollisionWithModifiedNonce() { + final Address address = Address.fromHexString("0x1"); + final BonsaiAccount priorAccountValue = createAccount(address); + final BonsaiAccount nextAccountValue = new BonsaiAccount(priorAccountValue, worldState, true); + nextAccountValue.setNonce(1); + + // Simulate that the address was already modified in the block + bonsaiUpdater + .getAccountsToUpdate() + .put(address, new DiffBasedValue<>(priorAccountValue, nextAccountValue)); + + final Transaction transaction = createTransaction(address, address); + + // Simulate that the address is read in the next transaction + trxUpdater + .getAccountsToUpdate() + .put(address, new DiffBasedValue<>(priorAccountValue, priorAccountValue)); + + boolean hasCollision = + collisionDetector.hasCollision( + transaction, + Address.ZERO, + new ParallelizedTransactionContext(trxUpdater, null, false, Wei.ZERO), + bonsaiUpdater); + + assertTrue(hasCollision, "Expected a collision with the modified address"); + } + + @Test + void testCollisionWithModifiedCode() { + final Address address = Address.fromHexString("0x1"); + final BonsaiAccount priorAccountValue = createAccount(address); + final BonsaiAccount nextAccountValue = new BonsaiAccount(priorAccountValue, worldState, true); + nextAccountValue.setCode(Bytes.repeat((byte) 0x01, 10)); + + // Simulate that the address was already modified in the block + bonsaiUpdater + .getAccountsToUpdate() + .put(address, new DiffBasedValue<>(priorAccountValue, nextAccountValue)); + + final Transaction transaction = createTransaction(address, address); + + // Simulate that the address is read in the next transaction + trxUpdater + .getAccountsToUpdate() + .put(address, new DiffBasedValue<>(priorAccountValue, priorAccountValue)); + + boolean hasCollision = + collisionDetector.hasCollision( + transaction, + Address.ZERO, + new ParallelizedTransactionContext(trxUpdater, null, false, Wei.ZERO), + bonsaiUpdater); + + assertTrue(hasCollision, "Expected a collision with the modified address"); + } + + @Test + void testCollisionWithModifiedStorageRoot() { + final Address address = Address.fromHexString("0x1"); + final BonsaiAccount priorAccountValue = createAccount(address); + final BonsaiAccount nextAccountValue = new BonsaiAccount(priorAccountValue, worldState, true); + nextAccountValue.setStorageRoot(Hash.EMPTY); + + // Simulate that the address was already modified in the block + bonsaiUpdater + .getAccountsToUpdate() + .put(address, new DiffBasedValue<>(priorAccountValue, nextAccountValue)); + + final Transaction transaction = createTransaction(address, address); + + // Simulate that the address is read in the next transaction + trxUpdater + .getAccountsToUpdate() + .put(address, new DiffBasedValue<>(priorAccountValue, priorAccountValue)); + + boolean hasCollision = + collisionDetector.hasCollision( + transaction, + Address.ZERO, + new ParallelizedTransactionContext(trxUpdater, null, false, Wei.ZERO), + bonsaiUpdater); + + assertTrue(hasCollision, "Expected a collision with the modified address"); + } + + @Test + void testCollisionWithMiningBeneficiaryAddress() { + final Address miningBeneficiary = Address.ZERO; + final Address address = Address.fromHexString("0x1"); + + final Transaction transaction = createTransaction(miningBeneficiary, address); + + boolean hasCollision = + collisionDetector.hasCollision( + transaction, + miningBeneficiary, + new ParallelizedTransactionContext(trxUpdater, null, false, Wei.ZERO), + bonsaiUpdater); + + assertTrue(hasCollision, "Expected collision with the mining beneficiary address as sender"); + } + + @Test + void testCollisionWithAnotherMiningBeneficiaryAddress() { + final Address miningBeneficiary = Address.ZERO; + final Address address = Address.fromHexString("0x1"); + final BonsaiAccount miningBeneficiaryValue = createAccount(address); + + final Transaction transaction = createTransaction(address, address); + + // Simulate that the mining beneficiary is read in the next transaction + trxUpdater + .getAccountsToUpdate() + .put( + miningBeneficiary, + new DiffBasedValue<>(miningBeneficiaryValue, miningBeneficiaryValue)); + + boolean hasCollision = + collisionDetector.hasCollision( + transaction, + miningBeneficiary, + new ParallelizedTransactionContext(trxUpdater, null, true, Wei.ZERO), + bonsaiUpdater); + + assertTrue(hasCollision, "Expected collision with the read mining beneficiary address"); + } + + @Test + void testCollisionWithDeletedAddress() { + final Address address = Address.fromHexString("0x1"); + final BonsaiAccount accountValue = createAccount(address); + + // Simulate that the address was deleted in the block + bonsaiUpdater.getDeletedAccountAddresses().add(address); + + final Transaction transaction = createTransaction(address, address); + + // Simulate that the deleted address is read in the next transaction + trxUpdater.getAccountsToUpdate().put(address, new DiffBasedValue<>(accountValue, accountValue)); + + boolean hasCollision = + collisionDetector.hasCollision( + transaction, + Address.ZERO, + new ParallelizedTransactionContext(trxUpdater, null, false, Wei.ZERO), + bonsaiUpdater); + + assertTrue(hasCollision, "Expected a collision with the deleted address"); + } + + @Test + void testCollisionWithNoModifiedAddress() { + final Address address = Address.fromHexString("0x1"); + final BonsaiAccount priorAccountValue = createAccount(address); + + // Simulate that the address was already read in the block + bonsaiUpdater + .getAccountsToUpdate() + .put(address, new DiffBasedValue<>(priorAccountValue, priorAccountValue)); + + final Transaction transaction = createTransaction(address, address); + + // Simulate that the address is read in the next transaction + trxUpdater + .getAccountsToUpdate() + .put(address, new DiffBasedValue<>(priorAccountValue, priorAccountValue)); + + boolean hasCollision = + collisionDetector.hasCollision( + transaction, + Address.ZERO, + new ParallelizedTransactionContext(trxUpdater, null, false, Wei.ZERO), + bonsaiUpdater); + + assertFalse(hasCollision, "Expected no collision with the read address"); + } +} diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/AbstractIsolationTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/AbstractIsolationTests.java index 845b859ef..388a11269 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/AbstractIsolationTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/trie/diffbased/bonsai/AbstractIsolationTests.java @@ -105,7 +105,9 @@ public abstract class AbstractIsolationTests { MainnetProtocolSchedule.fromConfig( GenesisConfigFile.fromResource("/dev.json").getConfigOptions(), MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); protected final GenesisState genesisState = GenesisState.fromConfig(GenesisConfigFile.fromResource("/dev.json"), protocolSchedule); protected final MutableBlockchain blockchain = createInMemoryBlockchain(genesisState.getBlock()); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockBodiesMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockBodiesMessageTest.java index ac3b8f2fc..b11afeb4c 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockBodiesMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockBodiesMessageTest.java @@ -34,6 +34,7 @@ import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.rlp.RLPException; import org.hyperledger.besu.ethereum.rlp.RLPInput; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.io.IOException; import java.nio.ByteBuffer; @@ -60,7 +61,9 @@ public final class BlockBodiesMessageTest { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); } @Test diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockHeadersMessageTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockHeadersMessageTest.java index 2b9105ed4..72f089a53 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockHeadersMessageTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/messages/BlockHeadersMessageTest.java @@ -26,6 +26,7 @@ import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput; import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.rlp.RLPInput; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.io.IOException; import java.nio.ByteBuffer; @@ -67,7 +68,9 @@ public final class BlockHeadersMessageTest { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager())); + new BadBlockManager(), + false, + new NoOpMetricsSystem())); for (int i = 0; i < 50; ++i) { Assertions.assertThat(readHeaders.get(i)).isEqualTo(headers.get(i)); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/ChainHeadTrackerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/ChainHeadTrackerTest.java index 4bad73ebb..5f7baaff4 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/ChainHeadTrackerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/ChainHeadTrackerTest.java @@ -59,7 +59,9 @@ public class ChainHeadTrackerTest { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); private final TrailingPeerLimiter trailingPeerLimiter = mock(TrailingPeerLimiter.class); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java index 9afba66ad..cfc9f9dc1 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncContextTest.java @@ -48,6 +48,7 @@ import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.referencetests.ForestReferenceTestWorldState; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; @@ -93,7 +94,11 @@ public class BackwardSyncContextTest { @Spy private ProtocolSchedule protocolSchedule = MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions(), MiningParameters.MINING_DISABLED, new BadBlockManager()); + new StubGenesisConfigOptions(), + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()); @Spy private ProtocolSpec protocolSpec = diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncStepTest.java index ecb72881e..6dc69ea27 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncStepTest.java @@ -39,6 +39,7 @@ import org.hyperledger.besu.ethereum.eth.manager.exceptions.MaxRetriesReachedExc import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import org.hyperledger.besu.testutil.DeterministicEthScheduler; @@ -70,7 +71,11 @@ public class BackwardSyncStepTest { private final ProtocolSchedule protocolSchedule = MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions(), MiningParameters.MINING_DISABLED, new BadBlockManager()); + new StubGenesisConfigOptions(), + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()); private final DeterministicEthScheduler ethScheduler = new DeterministicEthScheduler(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ForwardSyncStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ForwardSyncStepTest.java index 5fb47a557..a5d2cf610 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ForwardSyncStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/ForwardSyncStepTest.java @@ -38,6 +38,7 @@ import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.referencetests.ForestReferenceTestWorldState; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; import java.nio.charset.StandardCharsets; @@ -73,7 +74,11 @@ public class ForwardSyncStepTest { private final ProtocolSchedule protocolSchedule = MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions(), MiningParameters.MINING_DISABLED, new BadBlockManager()); + new StubGenesisConfigOptions(), + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()); private MutableBlockchain localBlockchain; GenericKeyValueStorageFacade headersStorage; GenericKeyValueStorageFacade blocksStorage; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java index 23eb9d02b..cd780c2dc 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java @@ -201,7 +201,9 @@ public abstract class AbstractTransactionPoolTest { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()) + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .createProtocolSchedule(); final ExecutionContextTestFixture executionContextTestFixture = ExecutionContextTestFixture.builder(genesisConfigFile) diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java index 8e9bda89c..c679183b0 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TestNode.java @@ -123,7 +123,9 @@ public class TestNode implements Closeable { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()); + new BadBlockManager(), + false, + new NoOpMetricsSystem()); final GenesisState genesisState = GenesisState.fromConfig(genesisConfigFile, protocolSchedule); final BlockHeaderFunctions blockHeaderFunctions = diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java index ef8d07017..5742637c3 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java @@ -379,7 +379,9 @@ public class TransactionPoolFactoryTest { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()) + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .createProtocolSchedule(); protocolContext = mock(ProtocolContext.class); diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java index db70ccf41..4f1065027 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java @@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; import org.hyperledger.besu.evm.EvmSpecVersion; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.math.BigInteger; import java.util.Locale; @@ -80,7 +81,12 @@ class MainnetGenesisFileModule extends GenesisFileModule { } return MainnetProtocolSchedule.fromConfig( - configOptions, evmConfiguration, MiningParameters.newDefault(), new BadBlockManager()); + configOptions, + evmConfiguration, + MiningParameters.newDefault(), + new BadBlockManager(), + false, + new NoOpMetricsSystem()); } public static Map> createSchedules() { @@ -145,7 +151,9 @@ class MainnetGenesisFileModule extends GenesisFileModule { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()) + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .createProtocolSchedule(); } } diff --git a/ethereum/referencetests/build.gradle b/ethereum/referencetests/build.gradle index 11db6b8ee..3c073136a 100644 --- a/ethereum/referencetests/build.gradle +++ b/ethereum/referencetests/build.gradle @@ -194,6 +194,7 @@ dependencies { referenceTestImplementation project(path: ':config') referenceTestImplementation project(path: ':datatypes') referenceTestImplementation project(path: ':ethereum:core') + referenceTestImplementation project(path: ':metrics:core') referenceTestImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts') referenceTestImplementation project(path: ':ethereum:rlp') referenceTestImplementation project(path: ':ethereum:rlp', configuration: 'testSupportArtifacts') diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java index 8ac419f7a..5dfb12f1d 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java @@ -27,6 +27,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.precompile.KZGPointEvalPrecompiledContract; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.math.BigInteger; import java.util.Arrays; @@ -130,7 +131,9 @@ public class ReferenceTestProtocolSchedules { false, EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, - new BadBlockManager()) + new BadBlockManager(), + false, + new NoOpMetricsSystem()) .createProtocolSchedule(); } diff --git a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/mainnet/DifficultyCalculatorTests.java b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/mainnet/DifficultyCalculatorTests.java index 6377b1ae3..00733de1f 100644 --- a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/mainnet/DifficultyCalculatorTests.java +++ b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/mainnet/DifficultyCalculatorTests.java @@ -18,6 +18,7 @@ package org.hyperledger.besu.ethereum.mainnet; import static org.assertj.core.api.Assertions.assertThat; +import org.checkerframework.checker.units.qual.N; import org.hyperledger.besu.config.GenesisConfigFile; import org.hyperledger.besu.config.JsonUtil; import org.hyperledger.besu.config.StubGenesisConfigOptions; @@ -43,6 +44,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.io.Resources; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -59,64 +61,64 @@ public class DifficultyCalculatorTests { MainnetProtocolSchedule.fromConfig( GenesisConfigFile.mainnet() .getConfigOptions(postMergeOverrides), - EvmConfiguration.DEFAULT, MiningParameters.newDefault(), new BadBlockManager())), + EvmConfiguration.DEFAULT, MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem())), Arguments.of( "/DifficultyTests/dfGrayGlacier/difficultyGrayGlacierForkBlock.json", MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions().grayGlacierBlock(15050000), MiningParameters.newDefault(), new BadBlockManager()) + new StubGenesisConfigOptions().grayGlacierBlock(15050000), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfGrayGlacier/difficultyGrayGlacierTimeDiff1.json", MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions().grayGlacierBlock(15050000), MiningParameters.newDefault(), new BadBlockManager()) + new StubGenesisConfigOptions().grayGlacierBlock(15050000), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfGrayGlacier/difficultyGrayGlacierTimeDiff2.json", MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions().grayGlacierBlock(15050000), MiningParameters.newDefault(), new BadBlockManager()) + new StubGenesisConfigOptions().grayGlacierBlock(15050000), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfArrowGlacier/difficultyArrowGlacierForkBlock.json", MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions().arrowGlacierBlock(13773000), MiningParameters.newDefault(), new BadBlockManager()) + new StubGenesisConfigOptions().arrowGlacierBlock(13773000), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfArrowGlacier/difficultyArrowGlacierTimeDiff1.json", MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions().arrowGlacierBlock(13773000), MiningParameters.newDefault(), new BadBlockManager()) + new StubGenesisConfigOptions().arrowGlacierBlock(13773000), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfArrowGlacier/difficultyArrowGlacierTimeDiff2.json", MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions().arrowGlacierBlock(13773000), MiningParameters.newDefault(), new BadBlockManager()) + new StubGenesisConfigOptions().arrowGlacierBlock(13773000), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfByzantium/difficultyByzantium.json", - MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().byzantiumBlock(0), MiningParameters.newDefault(), new BadBlockManager()) + MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().byzantiumBlock(0), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfConstantinople/difficultyConstantinople.json", - MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().constantinopleBlock(0), MiningParameters.newDefault(), new BadBlockManager()) + MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().constantinopleBlock(0), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfEIP2384/difficultyEIP2384.json", - MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().muirGlacierBlock(0), MiningParameters.newDefault(), new BadBlockManager()) + MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().muirGlacierBlock(0), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfEIP2384/difficultyEIP2384_random.json", - MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().muirGlacierBlock(0), MiningParameters.newDefault(), new BadBlockManager()) + MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().muirGlacierBlock(0), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfEIP2384/difficultyEIP2384_random_to20M.json", - MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().muirGlacierBlock(0), MiningParameters.newDefault(), new BadBlockManager()) + MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().muirGlacierBlock(0), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfFrontier/difficultyFrontier.json", - MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions(), MiningParameters.newDefault(), new BadBlockManager()) + MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions(), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfHomestead/difficultyHomestead.json", - MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().homesteadBlock(0), MiningParameters.newDefault(), new BadBlockManager()) + MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().homesteadBlock(0), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) )); } diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java index fd39ef7f4..32d4e0bab 100644 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java +++ b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java @@ -161,7 +161,12 @@ public class RetestethContext { JsonUtil.getObjectNode(genesisConfig, "config").get()); protocolSchedule = MainnetProtocolSchedule.fromConfig( - jsonGenesisConfigOptions, EvmConfiguration.DEFAULT, miningParameters, badBlockManager); + jsonGenesisConfigOptions, + EvmConfiguration.DEFAULT, + miningParameters, + badBlockManager, + false, + new NoOpMetricsSystem()); if ("NoReward".equalsIgnoreCase(sealEngine)) { protocolSchedule = new NoRewardProtocolScheduleWrapper(protocolSchedule, badBlockManager); } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/tracing/OperationTracer.java b/evm/src/main/java/org/hyperledger/besu/evm/tracing/OperationTracer.java index 34e28bbb3..f13938611 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/tracing/OperationTracer.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/tracing/OperationTracer.java @@ -16,6 +16,7 @@ package org.hyperledger.besu.evm.tracing; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Transaction; +import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.log.Log; @@ -85,6 +86,17 @@ public interface OperationTracer { */ default void traceStartTransaction(final WorldView worldView, final Transaction transaction) {} + /** + * Trace the end of a transaction just before mining reward. + * + * @param worldView an immutable view of the execution context + * @param tx the transaction that just concluded + * @param miningReward the reward that the mining beneficiary will receive. + */ + default void traceBeforeRewardTransaction( + final WorldView worldView, final Transaction tx, final Wei miningReward) {} + ; + /** * Trace the end of a transaction. * diff --git a/metrics/core/src/main/java/org/hyperledger/besu/metrics/BesuMetricCategory.java b/metrics/core/src/main/java/org/hyperledger/besu/metrics/BesuMetricCategory.java index d419a6ac7..415132017 100644 --- a/metrics/core/src/main/java/org/hyperledger/besu/metrics/BesuMetricCategory.java +++ b/metrics/core/src/main/java/org/hyperledger/besu/metrics/BesuMetricCategory.java @@ -53,7 +53,9 @@ public enum BesuMetricCategory implements MetricCategory { /** Transaction pool besu metric category. */ TRANSACTION_POOL("transaction_pool"), /** Stratum besu metric category. */ - STRATUM("stratum"); + STRATUM("stratum"), + /** Block processing besu metric category. */ + BLOCK_PROCESSING("block_processing"); private static final Optional BESU_PREFIX = Optional.of("besu_"); From 0269d83f39f39d1022848c24ce8c126913c51f08 Mon Sep 17 00:00:00 2001 From: Matilda-Clerke Date: Mon, 22 Jul 2024 09:22:33 +1000 Subject: [PATCH 12/14] 7732: Remove datagas related stuff in favour of blobgas (#7353) * 7732: Remove datagas related stuff in favour of blobgas Signed-off-by: Matilda Clerke --------- Signed-off-by: Matilda Clerke --- .../selectors/BlobSizeTransactionSelector.java | 2 +- .../BlockchainReferenceTestCaseSpec.java | 12 ++---------- .../StateTestVersionedTransaction.java | 5 +---- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlobSizeTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlobSizeTransactionSelector.java index 9df006722..9a4c83e96 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlobSizeTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlobSizeTransactionSelector.java @@ -26,7 +26,7 @@ import org.slf4j.LoggerFactory; /** * This class extends AbstractTransactionSelector and provides a specific implementation for * evaluating transactions based on blobs size. It checks if a transaction supports blobs, and if - * so, checks that there is enough remaining data gas in the block to fit the blobs of the tx. + * so, checks that there is enough remaining blob gas in the block to fit the blobs of the tx. */ public class BlobSizeTransactionSelector extends AbstractTransactionSelector { private static final Logger LOG = LoggerFactory.getLogger(BlobSizeTransactionSelector.class); diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BlockchainReferenceTestCaseSpec.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BlockchainReferenceTestCaseSpec.java index 1048f6238..4645abdfc 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BlockchainReferenceTestCaseSpec.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BlockchainReferenceTestCaseSpec.java @@ -165,10 +165,6 @@ public class BlockchainReferenceTestCaseSpec { @JsonProperty("nonce") final String nonce, @JsonProperty("withdrawalsRoot") final String withdrawalsRoot, @JsonProperty("requestsRoot") final String requestsRoot, - @JsonProperty("dataGasUsed") - final String dataGasUsed, // TODO: remove once reference tests have been updated - @JsonProperty("excessDataGas") - final String excessDataGas, // TODO: remove once reference tests have been updated @JsonProperty("blobGasUsed") final String blobGasUsed, @JsonProperty("excessBlobGas") final String excessBlobGas, @JsonProperty("parentBeaconBlockRoot") final String parentBeaconBlockRoot, @@ -195,12 +191,8 @@ public class BlockchainReferenceTestCaseSpec { Hash.fromHexString(mixHash), // mixHash Bytes.fromHexStringLenient(nonce).toLong(), withdrawalsRoot != null ? Hash.fromHexString(withdrawalsRoot) : null, - dataGasUsed != null - ? Long.decode(dataGasUsed) - : blobGasUsed != null ? Long.decode(blobGasUsed) : 0, - excessDataGas != null - ? BlobGas.fromHexString(excessDataGas) - : excessBlobGas != null ? BlobGas.fromHexString(excessBlobGas) : null, + blobGasUsed != null ? Long.decode(blobGasUsed) : 0, + excessBlobGas != null ? BlobGas.fromHexString(excessBlobGas) : null, parentBeaconBlockRoot != null ? Bytes32.fromHexString(parentBeaconBlockRoot) : null, requestsRoot != null ? Hash.fromHexString(requestsRoot) : null, new BlockHeaderFunctions() { diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/StateTestVersionedTransaction.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/StateTestVersionedTransaction.java index 9748d2aa0..a36d38043 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/StateTestVersionedTransaction.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/StateTestVersionedTransaction.java @@ -103,7 +103,6 @@ public class StateTestVersionedTransaction { @JsonDeserialize(using = StateTestAccessListDeserializer.class) @JsonProperty("accessLists") final List> maybeAccessLists, @JsonProperty("maxFeePerBlobGas") final String maxFeePerBlobGas, - @JsonProperty("maxFeePerDataGas") final String maxFeePerDataGas, @JsonProperty("blobVersionedHashes") final List blobVersionedHashes) { this.nonce = Bytes.fromHexStringLenient(nonce).toLong(); @@ -123,9 +122,7 @@ public class StateTestVersionedTransaction { this.payloads = parseArray(data, Bytes::fromHexString); this.maybeAccessLists = Optional.ofNullable(maybeAccessLists); this.maxFeePerBlobGas = - Optional.ofNullable(maxFeePerBlobGas == null ? maxFeePerDataGas : maxFeePerBlobGas) - .map(Wei::fromHexString) - .orElse(null); + Optional.ofNullable(maxFeePerBlobGas).map(Wei::fromHexString).orElse(null); this.blobVersionedHashes = blobVersionedHashes; } From bcbfec0c27eb2bca9b0f3f56b9cf6522e8673e16 Mon Sep 17 00:00:00 2001 From: Stefan Pingel <16143240+pinges@users.noreply.github.com> Date: Mon, 22 Jul 2024 12:43:06 +1000 Subject: [PATCH 13/14] Fix NPE for legacy ForkId with no forks (#7349) Fix NPE for legacy ForkId with no forks Signed-off-by: stefan.pingel@consensys.net --- .../besu/ethereum/forkid/ForkIdManager.java | 5 ++--- .../forkid/ForkIdBackwardCompatibilityTest.java | 17 ++++++++++++----- .../ethereum/forkid/LegacyForkIdManager.java | 15 ++++++++------- .../eth/manager/EthProtocolManagerTest.java | 12 ++++++++++-- 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/forkid/ForkIdManager.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/forkid/ForkIdManager.java index 859fb918a..407e5149d 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/forkid/ForkIdManager.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/forkid/ForkIdManager.java @@ -79,8 +79,7 @@ public class ForkIdManager { .sorted() .collect(Collectors.toUnmodifiableList()); final List allForkNumbers = - Stream.concat(blockNumberForks.stream(), timestampForks.stream()) - .collect(Collectors.toList()); + Stream.concat(blockNumberForks.stream(), timestampForks.stream()).toList(); this.forkNext = createForkIds(); this.allForkIds = Stream.concat(blockNumbersForkIds.stream(), timestampsForkIds.stream()) @@ -93,7 +92,7 @@ public class ForkIdManager { public ForkId getForkIdForChainHead() { if (legacyEth64) { return blockNumbersForkIds.isEmpty() - ? null + ? new ForkId(genesisHashCrc, 0) : blockNumbersForkIds.get(blockNumbersForkIds.size() - 1); } final BlockHeader header = chainHeadSupplier.get(); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdBackwardCompatibilityTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdBackwardCompatibilityTest.java index 84c24bc9a..df97386e9 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdBackwardCompatibilityTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/ForkIdBackwardCompatibilityTest.java @@ -18,6 +18,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.hyperledger.besu.ethereum.forkid.ForkIdTestUtil.GenesisHash; import static org.hyperledger.besu.ethereum.forkid.ForkIdTestUtil.mockBlockchain; +import org.hyperledger.besu.ethereum.chain.Blockchain; + import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -77,6 +79,13 @@ public class ForkIdBackwardCompatibilityTest { 8L, Arrays.asList(0L, 0L, 4L, 5L, 6L), true, + null), + Arguments.of( + "no forks and legacyEth64=true", + GenesisHash.PRIVATE, + 8L, + Collections.emptyList(), + true, null)); } @@ -90,13 +99,11 @@ public class ForkIdBackwardCompatibilityTest { final boolean legacyEth64, final ForkId wantForkId) { LOG.info("Running test case {}", name); + final Blockchain blockchain = mockBlockchain(genesisHash, head, 0); final ForkIdManager forkIdManager = - new ForkIdManager( - mockBlockchain(genesisHash, head, 0), forks, Collections.emptyList(), legacyEth64); + new ForkIdManager(blockchain, forks, Collections.emptyList(), legacyEth64); final ForkId legacyForkId = - legacyEth64 - ? new LegacyForkIdManager(mockBlockchain(genesisHash, head, 0), forks).getLatestForkId() - : null; + legacyEth64 ? new LegacyForkIdManager(blockchain, forks).getLatestForkId() : null; assertThat(forkIdManager.getForkIdForChainHead()) .isEqualTo(legacyEth64 ? legacyForkId : wantForkId); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/LegacyForkIdManager.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/LegacyForkIdManager.java index 325fd41c8..bc9196e6d 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/LegacyForkIdManager.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/forkid/LegacyForkIdManager.java @@ -20,7 +20,6 @@ import org.hyperledger.besu.ethereum.rlp.RLPInput; import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; import java.util.zip.CRC32; import org.apache.tuweni.bytes.Bytes; @@ -30,12 +29,13 @@ public class LegacyForkIdManager { private final Hash genesisHash; private final List forks; private List forkAndHashList; + private CRC32 crc; + private Bytes genesisHashCrc; public LegacyForkIdManager(final Blockchain blockchain, final List forks) { this.genesisHash = blockchain.getGenesisBlock().getHash(); // de-dupe and sanitize forks - this.forks = - forks.stream().filter(fork -> fork > 0).distinct().collect(Collectors.toUnmodifiableList()); + this.forks = forks.stream().filter(fork -> fork > 0).distinct().toList(); createForkIds(); } @@ -44,10 +44,10 @@ public class LegacyForkIdManager { } public ForkId getLatestForkId() { - if (forkAndHashList.size() > 0) { - return forkAndHashList.get(forkAndHashList.size() - 1); + if (!forkAndHashList.isEmpty()) { + return forkAndHashList.getLast(); } - return null; + return new ForkId(genesisHashCrc, 0); } public static ForkId readFrom(final RLPInput in) { @@ -59,8 +59,9 @@ public class LegacyForkIdManager { } private void createForkIds() { - final CRC32 crc = new CRC32(); + crc = new CRC32(); crc.update(genesisHash.toArray()); + genesisHashCrc = getCurrentCrcHash(crc); final List forkHashes = new ArrayList<>(List.of(getCurrentCrcHash(crc))); for (final Long fork : forks) { updateCrc(crc, fork); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java index 93a80be2f..3a3331b56 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManagerTest.java @@ -64,6 +64,7 @@ import org.hyperledger.besu.ethereum.eth.transactions.BlobCache; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolFactory; +import org.hyperledger.besu.ethereum.forkid.ForkId; import org.hyperledger.besu.ethereum.forkid.ForkIdManager; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.p2p.rlpx.connections.PeerConnection; @@ -93,6 +94,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import java.util.zip.CRC32; import com.google.common.collect.Lists; import org.apache.tuweni.bytes.Bytes; @@ -1136,7 +1138,7 @@ public final class EthProtocolManagerTest { } @Test - public void forkIdForChainHeadMayBeNull() { + public void forkIdForChainHeadLegacyNoForksNotEmpty() { final EthScheduler ethScheduler = mock(EthScheduler.class); try (final EthProtocolManager ethManager = EthProtocolManagerTestUtil.create( @@ -1149,7 +1151,13 @@ public final class EthProtocolManagerTest { new ForkIdManager( blockchain, Collections.emptyList(), Collections.emptyList(), true))) { - assertThat(ethManager.getForkIdAsBytesList()).isEmpty(); + assertThat(ethManager.getForkIdAsBytesList()).isNotEmpty(); + final CRC32 genesisHashCRC = new CRC32(); + genesisHashCRC.update(blockchain.getGenesisBlock().getHash().toArray()); + assertThat(ethManager.getForkIdAsBytesList()) + .isEqualTo( + new ForkId(Bytes.ofUnsignedInt(genesisHashCRC.getValue()), 0L) + .getForkIdAsBytesList()); } } From 7e4a25a9ba980f142d47d7efec859ff0e90c1394 Mon Sep 17 00:00:00 2001 From: Matt Whitehead Date: Tue, 23 Jul 2024 10:25:07 +0100 Subject: [PATCH 14/14] Add new PoA network option to use bootnodes during any peer table refresh, not just the first one (#7314) * Add new config option to use bootnodes during any peer table refresh, not just the first one Signed-off-by: Matthew Whitehead * Update everything-config list Signed-off-by: Matthew Whitehead * Revert debug setting Signed-off-by: Matthew Whitehead * Update ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryController.java Co-authored-by: Stefan Pingel <16143240+pinges@users.noreply.github.com> Signed-off-by: Matt Whitehead --------- Signed-off-by: Matthew Whitehead Signed-off-by: Matt Whitehead Co-authored-by: Stefan Pingel <16143240+pinges@users.noreply.github.com> --- CHANGELOG.md | 2 ++ .../org/hyperledger/besu/RunnerBuilder.java | 15 ++++++++++++ .../org/hyperledger/besu/cli/BesuCommand.java | 14 +++++++++++ .../hyperledger/besu/cli/BesuCommandTest.java | 22 +++++++++++++++++ .../besu/cli/CommandTestAbstract.java | 1 + besu/src/test/resources/complete_config.toml | 1 + .../src/test/resources/everything_config.toml | 1 + .../p2p/config/DiscoveryConfiguration.java | 11 +++++++++ .../p2p/discovery/PeerDiscoveryAgent.java | 1 + .../internal/PeerDiscoveryController.java | 24 +++++++++++++++++-- 10 files changed, 90 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c6cb373b..d0e62bc5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,8 @@ - Add trie log pruner metrics [#7352](https://github.com/hyperledger/besu/pull/7352) - `--Xbonsai-parallel-tx-processing-enabled` option enables executing transactions in parallel during block processing for Bonsai nodes +- Add option `--poa-discovery-retry-bootnodes` for PoA networks to always use bootnodes during peer refresh, not just on first start [#7314](https://github.com/hyperledger/besu/pull/7314) + ### Bug fixes - Fix `eth_call` deserialization to correctly ignore unknown fields in the transaction object. [#7323](https://github.com/hyperledger/besu/pull/7323) diff --git a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java index 7ed627cfc..dfd09165b 100644 --- a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java @@ -195,6 +195,7 @@ public class RunnerBuilder { private boolean legacyForkIdEnabled; private Optional enodeDnsConfiguration; private List allowedSubnets = new ArrayList<>(); + private boolean poaDiscoveryRetryBootnodes = true; /** Instantiates a new Runner builder. */ public RunnerBuilder() {} @@ -603,6 +604,17 @@ public class RunnerBuilder { return this; } + /** + * Flag to indicate if peer table refreshes should always query bootnodes + * + * @param poaDiscoveryRetryBootnodes whether to always query bootnodes + * @return the runner builder + */ + public RunnerBuilder poaDiscoveryRetryBootnodes(final boolean poaDiscoveryRetryBootnodes) { + this.poaDiscoveryRetryBootnodes = poaDiscoveryRetryBootnodes; + return this; + } + /** * Build Runner instance. * @@ -625,6 +637,8 @@ public class RunnerBuilder { bootstrap = ethNetworkConfig.bootNodes(); } discoveryConfiguration.setBootnodes(bootstrap); + discoveryConfiguration.setIncludeBootnodesOnPeerRefresh( + besuController.getGenesisConfigOptions().isPoa() && poaDiscoveryRetryBootnodes); LOG.info("Resolved {} bootnodes.", bootstrap.size()); LOG.debug("Bootnodes = {}", bootstrap); discoveryConfiguration.setDnsDiscoveryURL(ethNetworkConfig.dnsDiscoveryUrl()); @@ -694,6 +708,7 @@ public class RunnerBuilder { final boolean fallbackEnabled = natMethod == NatMethod.AUTO || natMethodFallbackEnabled; final NatService natService = new NatService(buildNatManager(natMethod), fallbackEnabled); final NetworkBuilder inactiveNetwork = caps -> new NoopP2PNetwork(); + final NetworkBuilder activeNetwork = caps -> { return DefaultP2PNetwork.builder() diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index 198c26fe2..2607f6e59 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -513,6 +513,19 @@ public class BesuCommand implements DefaultCommandValues, Runnable { } } + // Boolean option to set that in a PoA network the bootnodes should always be queried during + // peer table refresh. If this flag is disabled bootnodes are only sent FINDN requests on first + // startup, meaning that an offline bootnode or network outage at the client can prevent it + // discovering any peers without a restart. + @Option( + names = {"--poa-discovery-retry-bootnodes"}, + description = + "Always use of bootnodes for discovery in PoA networks. Disabling this reverts " + + " to the same behaviour as non-PoA networks, where neighbours are only discovered from bootnodes on first startup." + + "(default: ${DEFAULT-VALUE})", + arity = "1") + private final Boolean poaDiscoveryRetryBootnodes = true; + private Collection bannedNodeIds = new ArrayList<>(); // Used to discover the default IP of the client. @@ -2324,6 +2337,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable { .rpcEndpointService(rpcEndpointServiceImpl) .enodeDnsConfiguration(getEnodeDnsConfiguration()) .allowedSubnets(p2PDiscoveryOptionGroup.allowedSubnets) + .poaDiscoveryRetryBootnodes(p2PDiscoveryOptionGroup.poaDiscoveryRetryBootnodes) .build(); addShutdownHook(runner); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index efeff412d..c892ffe7f 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -804,6 +804,28 @@ public class BesuCommandTest extends CommandTestAbstract { assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); } + @Test + public void poaDiscoveryRetryBootnodesValueTrueMustBeUsed() { + parseCommand("--poa-discovery-retry-bootnodes", "true"); + + verify(mockRunnerBuilder).poaDiscoveryRetryBootnodes(eq(true)); + verify(mockRunnerBuilder).build(); + + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + } + + @Test + public void poaDiscoveryRetryBootnodesValueFalseMustBeUsed() { + parseCommand("--poa-discovery-retry-bootnodes", "false"); + + verify(mockRunnerBuilder).poaDiscoveryRetryBootnodes(eq(false)); + verify(mockRunnerBuilder).build(); + + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + } + @Test public void callingWithBootnodesOptionButNoValueMustPassEmptyBootnodeList() { parseCommand("--bootnodes"); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java index 8a6a57811..c77ced5c6 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java @@ -350,6 +350,7 @@ public abstract class CommandTestAbstract { when(mockRunnerBuilder.apiConfiguration(any())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.enodeDnsConfiguration(any())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.allowedSubnets(any())).thenReturn(mockRunnerBuilder); + when(mockRunnerBuilder.poaDiscoveryRetryBootnodes(anyBoolean())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.build()).thenReturn(mockRunner); final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithmFactory.getInstance(); diff --git a/besu/src/test/resources/complete_config.toml b/besu/src/test/resources/complete_config.toml index 3243b0561..8ae2105ef 100644 --- a/besu/src/test/resources/complete_config.toml +++ b/besu/src/test/resources/complete_config.toml @@ -6,6 +6,7 @@ data-path="/opt/besu" # Path # network discovery-enabled=false +poa-discovery-retry-bootnodes=true bootnodes=[ "enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.1:4567", "enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.1:4567", diff --git a/besu/src/test/resources/everything_config.toml b/besu/src/test/resources/everything_config.toml index a5e03bd59..27ea5c164 100644 --- a/besu/src/test/resources/everything_config.toml +++ b/besu/src/test/resources/everything_config.toml @@ -29,6 +29,7 @@ nat-method="NONE" Xnat-kube-service-name="besu" Xnat-method-fallback-enabled=true discovery-enabled=false +poa-discovery-retry-bootnodes=true bootnodes=[ "enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.1:4567", "enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.1:4567", diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/config/DiscoveryConfiguration.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/config/DiscoveryConfiguration.java index 86bb079a2..3f59abf2f 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/config/DiscoveryConfiguration.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/config/DiscoveryConfiguration.java @@ -33,6 +33,7 @@ public class DiscoveryConfiguration { private String dnsDiscoveryURL; private boolean discoveryV5Enabled = false; private boolean filterOnEnrForkId = NetworkingConfiguration.DEFAULT_FILTER_ON_ENR_FORK_ID; + private boolean includeBootnodesOnPeerRefresh = true; public static DiscoveryConfiguration create() { return new DiscoveryConfiguration(); @@ -88,6 +89,16 @@ public class DiscoveryConfiguration { return this; } + public boolean getIncludeBootnodesOnPeerRefresh() { + return includeBootnodesOnPeerRefresh; + } + + public DiscoveryConfiguration setIncludeBootnodesOnPeerRefresh( + final boolean includeBootnodesOnPeerRefresh) { + this.includeBootnodesOnPeerRefresh = includeBootnodesOnPeerRefresh; + return this; + } + public String getAdvertisedHost() { return advertisedHost; } diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryAgent.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryAgent.java index d1f17b530..7efc50750 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryAgent.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryAgent.java @@ -274,6 +274,7 @@ public abstract class PeerDiscoveryAgent { .filterOnEnrForkId((config.isFilterOnEnrForkIdEnabled())) .rlpxAgent(rlpxAgent) .peerTable(peerTable) + .includeBootnodesOnPeerRefresh(config.getIncludeBootnodesOnPeerRefresh()) .build(); } diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryController.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryController.java index 5d0fee184..11b5216a8 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryController.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerDiscoveryController.java @@ -143,6 +143,7 @@ public class PeerDiscoveryController { private final AtomicBoolean peerTableIsDirty = new AtomicBoolean(false); private OptionalLong cleanTableTimerId = OptionalLong.empty(); private RecursivePeerRefreshState recursivePeerRefreshState; + private final boolean includeBootnodesOnPeerRefresh; private PeerDiscoveryController( final NodeKey nodeKey, @@ -159,7 +160,8 @@ public class PeerDiscoveryController { final MetricsSystem metricsSystem, final Optional> maybeCacheForEnrRequests, final boolean filterOnEnrForkId, - final RlpxAgent rlpxAgent) { + final RlpxAgent rlpxAgent, + final boolean includeBootnodesOnPeerRefresh) { this.timerUtil = timerUtil; this.nodeKey = nodeKey; this.localPeer = localPeer; @@ -173,6 +175,7 @@ public class PeerDiscoveryController { this.discoveryProtocolLogger = new DiscoveryProtocolLogger(metricsSystem); this.peerPermissions = new PeerDiscoveryPermissions(localPeer, peerPermissions); this.rlpxAgent = rlpxAgent; + this.includeBootnodesOnPeerRefresh = includeBootnodesOnPeerRefresh; metricsSystem.createIntegerGauge( BesuMetricCategory.NETWORK, @@ -483,7 +486,17 @@ public class PeerDiscoveryController { */ private void refreshTable() { final Bytes target = Peer.randomId(); + final List initialPeers = peerTable.nearestBondedPeers(Peer.randomId(), 16); + if (includeBootnodesOnPeerRefresh) { + bootstrapNodes.stream() + .filter(p -> p.getStatus() != PeerDiscoveryStatus.BONDED) + .forEach(p -> p.setStatus(PeerDiscoveryStatus.KNOWN)); + + // If configured to retry bootnodes during peer table refresh, include them + // in the initial peers list. + initialPeers.addAll(bootstrapNodes); + } recursivePeerRefreshState.start(initialPeers, target); lastRefreshTime = System.currentTimeMillis(); } @@ -816,6 +829,7 @@ public class PeerDiscoveryController { private long cleanPeerTableIntervalMs = MILLISECONDS.convert(1, TimeUnit.MINUTES); private final List bootstrapNodes = new ArrayList<>(); private PeerTable peerTable; + private boolean includeBootnodesOnPeerRefresh = true; // Required dependencies private NodeKey nodeKey; @@ -849,7 +863,8 @@ public class PeerDiscoveryController { metricsSystem, Optional.of(cachedEnrRequests), filterOnEnrForkId, - rlpxAgent); + rlpxAgent, + includeBootnodesOnPeerRefresh); } private void validate() { @@ -953,5 +968,10 @@ public class PeerDiscoveryController { this.rlpxAgent = rlpxAgent; return this; } + + public Builder includeBootnodesOnPeerRefresh(final boolean includeBootnodesOnPeerRefresh) { + this.includeBootnodesOnPeerRefresh = includeBootnodesOnPeerRefresh; + return this; + } } }