From c839a3b02298c6b00ba0867cc0155d760fe7f43a Mon Sep 17 00:00:00 2001 From: matkt Date: Tue, 24 Oct 2023 04:09:38 +0200 Subject: [PATCH 1/2] add retry logic on sync pipeline for rocksdb issue (#6004) * add retry logic for sync pipeline with rocksdb issue Signed-off-by: Karim TAAM --- ethereum/eth/build.gradle | 1 + .../eth/sync/StorageExceptionManager.java | 64 +++++++++++++++ .../fastsync/worldstate/PersistDataStep.java | 63 ++++++++++----- .../eth/sync/snapsync/LoadLocalDataStep.java | 50 +++++++++--- .../eth/sync/snapsync/PersistDataStep.java | 80 ++++++++++++------- .../SnapWorldStateDownloadProcess.java | 16 ++++ .../ethereum/eth/sync/snapsync/StackTrie.java | 15 +++- .../request/AccountRangeDataRequest.java | 6 ++ .../snapsync/request/BytecodeRequest.java | 5 ++ .../request/StorageRangeDataRequest.java | 6 ++ .../request/heal/TrieNodeHealingRequest.java | 5 ++ 11 files changed, 251 insertions(+), 60 deletions(-) create mode 100644 ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/StorageExceptionManager.java diff --git a/ethereum/eth/build.gradle b/ethereum/eth/build.gradle index a40b49afffb..1919efdd4f2 100644 --- a/ethereum/eth/build.gradle +++ b/ethereum/eth/build.gradle @@ -58,6 +58,7 @@ dependencies { implementation 'io.tmio:tuweni-bytes' implementation 'io.tmio:tuweni-units' implementation 'io.tmio:tuweni-rlp' + implementation 'org.rocksdb:rocksdbjni' annotationProcessor "org.immutables:value" implementation "org.immutables:value-annotations" diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/StorageExceptionManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/StorageExceptionManager.java new file mode 100644 index 00000000000..97d1506cf3e --- /dev/null +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/StorageExceptionManager.java @@ -0,0 +1,64 @@ +/* + * 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.ethereum.eth.sync; + +import org.hyperledger.besu.plugin.services.exception.StorageException; + +import java.util.EnumSet; +import java.util.Optional; + +import org.rocksdb.RocksDBException; +import org.rocksdb.Status; + +public final class StorageExceptionManager { + + private static final EnumSet RETRYABLE_STATUS_CODES = + EnumSet.of(Status.Code.TimedOut, Status.Code.TryAgain, Status.Code.Busy); + + private static final long ERROR_THRESHOLD = 1000; + + private static long retryableErrorCounter; + /** + * Determines if an operation can be retried based on the error received. This method checks if + * the cause of the StorageException is a RocksDBException. If it is, it retrieves the status code + * of the RocksDBException and checks if it is contained in the list of retryable {@link + * StorageExceptionManager.RETRYABLE_STATUS_CODES} status codes. + * + * @param e the StorageException to check + * @return true if the operation can be retried, false otherwise + */ + public static boolean canRetryOnError(final StorageException e) { + return Optional.of(e.getCause()) + .filter(z -> z instanceof RocksDBException) + .map(RocksDBException.class::cast) + .map(RocksDBException::getStatus) + .map(Status::getCode) + .map(RETRYABLE_STATUS_CODES::contains) + .map( + result -> { + retryableErrorCounter++; + return result; + }) + .orElse(false); + } + + public static long getRetryableErrorCounter() { + return retryableErrorCounter; + } + + public static boolean errorCountAtThreshold() { + return retryableErrorCounter % ERROR_THRESHOLD == 1; + } +} diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStep.java index 94592b98d81..1ab202ee6ce 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/PersistDataStep.java @@ -14,15 +14,26 @@ */ package org.hyperledger.besu.ethereum.eth.sync.fastsync.worldstate; +import static org.hyperledger.besu.ethereum.eth.sync.StorageExceptionManager.canRetryOnError; +import static org.hyperledger.besu.ethereum.eth.sync.StorageExceptionManager.errorCountAtThreshold; +import static org.hyperledger.besu.ethereum.eth.sync.StorageExceptionManager.getRetryableErrorCounter; + import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.eth.sync.worldstate.WorldDownloadState; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage.Updater; +import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.services.tasks.Task; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class PersistDataStep { + + private static final Logger LOG = LoggerFactory.getLogger(PersistDataStep.class); + private final WorldStateStorage worldStateStorage; public PersistDataStep(final WorldStateStorage worldStateStorage) { @@ -33,24 +44,40 @@ public List> persist( final List> tasks, final BlockHeader blockHeader, final WorldDownloadState downloadState) { - final Updater updater = worldStateStorage.updater(); - tasks.stream() - .map( - task -> { - enqueueChildren(task, downloadState); - return task; - }) - .map(Task::getData) - .filter(request -> request.getData() != null) - .forEach( - request -> { - if (isRootState(blockHeader, request)) { - downloadState.setRootNodeData(request.getData()); - } else { - request.persist(updater); - } - }); - updater.commit(); + try { + final Updater updater = worldStateStorage.updater(); + tasks.stream() + .map( + task -> { + enqueueChildren(task, downloadState); + return task; + }) + .map(Task::getData) + .filter(request -> request.getData() != null) + .forEach( + request -> { + if (isRootState(blockHeader, request)) { + downloadState.setRootNodeData(request.getData()); + } else { + request.persist(updater); + } + }); + updater.commit(); + } catch (StorageException storageException) { + if (canRetryOnError(storageException)) { + // We reset the task by setting it to null. This way, it is considered as failed by the + // pipeline, and it will attempt to execute it again later. + if (errorCountAtThreshold()) { + LOG.info( + "Encountered {} retryable RocksDB errors, latest error message {}", + getRetryableErrorCounter(), + storageException.getMessage()); + } + tasks.forEach(nodeDataRequestTask -> nodeDataRequestTask.getData().setData(null)); + } else { + throw storageException; + } + } return tasks; } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/LoadLocalDataStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/LoadLocalDataStep.java index 5264eac2b50..c24dbf6037d 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/LoadLocalDataStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/LoadLocalDataStep.java @@ -14,11 +14,16 @@ */ package org.hyperledger.besu.ethereum.eth.sync.snapsync; +import static org.hyperledger.besu.ethereum.eth.sync.StorageExceptionManager.canRetryOnError; +import static org.hyperledger.besu.ethereum.eth.sync.StorageExceptionManager.errorCountAtThreshold; +import static org.hyperledger.besu.ethereum.eth.sync.StorageExceptionManager.getRetryableErrorCounter; + import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest; import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.heal.TrieNodeHealingRequest; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; import org.hyperledger.besu.metrics.BesuMetricCategory; import org.hyperledger.besu.plugin.services.MetricsSystem; +import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.metrics.Counter; import org.hyperledger.besu.services.pipeline.Pipe; import org.hyperledger.besu.services.tasks.Task; @@ -27,9 +32,12 @@ import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class LoadLocalDataStep { + private static final Logger LOG = LoggerFactory.getLogger(LoadLocalDataStep.class); private final WorldStateStorage worldStateStorage; private final SnapWorldDownloadState downloadState; private final SnapSyncProcessState snapSyncState; @@ -58,19 +66,35 @@ public Stream> loadLocalDataTrieNode( final Task task, final Pipe> completedTasks) { final TrieNodeHealingRequest request = (TrieNodeHealingRequest) task.getData(); // check if node is already stored in the worldstate - if (snapSyncState.hasPivotBlockHeader()) { - Optional existingData = request.getExistingData(downloadState, worldStateStorage); - if (existingData.isPresent()) { - existingNodeCounter.inc(); - request.setData(existingData.get()); - request.setRequiresPersisting(false); - final WorldStateStorage.Updater updater = worldStateStorage.updater(); - request.persist( - worldStateStorage, updater, downloadState, snapSyncState, snapSyncConfiguration); - updater.commit(); - downloadState.enqueueRequests(request.getRootStorageRequests(worldStateStorage)); - completedTasks.put(task); - return Stream.empty(); + try { + if (snapSyncState.hasPivotBlockHeader()) { + Optional existingData = request.getExistingData(downloadState, worldStateStorage); + if (existingData.isPresent()) { + existingNodeCounter.inc(); + request.setData(existingData.get()); + request.setRequiresPersisting(false); + final WorldStateStorage.Updater updater = worldStateStorage.updater(); + request.persist( + worldStateStorage, updater, downloadState, snapSyncState, snapSyncConfiguration); + updater.commit(); + downloadState.enqueueRequests(request.getRootStorageRequests(worldStateStorage)); + completedTasks.put(task); + return Stream.empty(); + } + } + } catch (StorageException storageException) { + if (canRetryOnError(storageException)) { + // We reset the task by setting it to null. This way, it is considered as failed by the + // pipeline, and it will attempt to execute it again later. + if (errorCountAtThreshold()) { + LOG.info( + "Encountered {} retryable RocksDB errors, latest error message {}", + getRetryableErrorCounter(), + storageException.getMessage()); + } + task.getData().clear(); + } else { + throw storageException; } } return Stream.of(task); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStep.java index 6a39f648716..df3696ccdf7 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStep.java @@ -14,16 +14,25 @@ */ package org.hyperledger.besu.ethereum.eth.sync.snapsync; +import static org.hyperledger.besu.ethereum.eth.sync.StorageExceptionManager.canRetryOnError; +import static org.hyperledger.besu.ethereum.eth.sync.StorageExceptionManager.errorCountAtThreshold; +import static org.hyperledger.besu.ethereum.eth.sync.StorageExceptionManager.getRetryableErrorCounter; + import org.hyperledger.besu.ethereum.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest; import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.heal.TrieNodeHealingRequest; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorage; +import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.services.tasks.Task; import java.util.List; import java.util.stream.Stream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class PersistDataStep { + private static final Logger LOG = LoggerFactory.getLogger(PersistDataStep.class); private final SnapSyncProcessState snapSyncState; private final WorldStateStorage worldStateStorage; @@ -43,41 +52,58 @@ public PersistDataStep( } public List> persist(final List> tasks) { - final WorldStateStorage.Updater updater = worldStateStorage.updater(); - for (Task task : tasks) { - if (task.getData().isResponseReceived()) { - // enqueue child requests - final Stream childRequests = - task.getData().getChildRequests(downloadState, worldStateStorage, snapSyncState); - if (!(task.getData() instanceof TrieNodeHealingRequest)) { - enqueueChildren(childRequests); - } else { - if (!task.getData().isExpired(snapSyncState)) { + try { + final WorldStateStorage.Updater updater = worldStateStorage.updater(); + for (Task task : tasks) { + if (task.getData().isResponseReceived()) { + // enqueue child requests + final Stream childRequests = + task.getData().getChildRequests(downloadState, worldStateStorage, snapSyncState); + if (!(task.getData() instanceof TrieNodeHealingRequest)) { enqueueChildren(childRequests); } else { - continue; + if (!task.getData().isExpired(snapSyncState)) { + enqueueChildren(childRequests); + } else { + continue; + } } - } - // persist nodes - final int persistedNodes = - task.getData() - .persist( - worldStateStorage, - updater, - downloadState, - snapSyncState, - snapSyncConfiguration); - if (persistedNodes > 0) { - if (task.getData() instanceof TrieNodeHealingRequest) { - downloadState.getMetricsManager().notifyTrieNodesHealed(persistedNodes); - } else { - downloadState.getMetricsManager().notifyNodesGenerated(persistedNodes); + // persist nodes + final int persistedNodes = + task.getData() + .persist( + worldStateStorage, + updater, + downloadState, + snapSyncState, + snapSyncConfiguration); + if (persistedNodes > 0) { + if (task.getData() instanceof TrieNodeHealingRequest) { + downloadState.getMetricsManager().notifyTrieNodesHealed(persistedNodes); + } else { + downloadState.getMetricsManager().notifyNodesGenerated(persistedNodes); + } } } } + updater.commit(); + } catch (StorageException storageException) { + if (canRetryOnError(storageException)) { + // We reset the task by setting it to null. This way, it is considered as failed by the + // pipeline, and it will attempt to execute it again later. not display all the retryable + // issues + if (errorCountAtThreshold()) { + LOG.info( + "Encountered {} retryable RocksDB errors, latest error message {}", + getRetryableErrorCounter(), + storageException.getMessage()); + } + tasks.forEach(task -> task.getData().clear()); + } else { + throw storageException; + } } - updater.commit(); return tasks; } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldStateDownloadProcess.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldStateDownloadProcess.java index c8afc582b72..c19ae6facc7 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldStateDownloadProcess.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapWorldStateDownloadProcess.java @@ -231,6 +231,22 @@ public SnapWorldStateDownloadProcess build() { "step", "action"); + /* + The logic and intercommunication of different pipelines can be summarized as follows: + + 1. Account Data Pipeline (fetchAccountDataPipeline): This process starts with downloading the leaves of the account tree in ranges, with multiple ranges being processed simultaneously. + If the downloaded accounts are smart contracts, tasks are created in the storage pipeline to download the storage tree of the smart contract, and in the code download pipeline for the smart contract. + + 2. Storage Data Pipeline (fetchStorageDataPipeline): Running parallel to the account data pipeline, this pipeline downloads the storage of smart contracts. + If all slots cannot be downloaded at once, tasks are created in the fetchLargeStorageDataPipeline to download the storage by range, allowing parallelization of large account downloads. + + 3. Code Data Pipeline (fetchCodePipeline): This pipeline, running concurrently with the account and storage data pipelines, is responsible for downloading the code of the smart contracts. + + 4. Large Storage Data Pipeline (fetchLargeStorageDataPipeline): This pipeline is used when the storage data for a smart contract is too large to be downloaded at once. + It enables the storage data to be downloaded in ranges, similar to the account data. + + 5. Healing Phase: Initiated after all other pipelines have completed their tasks, this phase ensures the integrity and completeness of the downloaded data. + */ final Pipeline> completionPipeline = PipelineBuilder.>createPipeline( "requestDataAvailable", bufferCapacity, outputCounter, true, "node_data_request") diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/StackTrie.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/StackTrie.java index fd6acde3754..01f17eb79b4 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/StackTrie.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/StackTrie.java @@ -51,8 +51,8 @@ public class StackTrie { private final AtomicInteger nbSegments; private final int maxSegments; private final Bytes32 startKeyHash; - private final Map elements; - private final AtomicLong elementsCount; + private Map elements; + private AtomicLong elementsCount; public StackTrie(final Hash rootHash, final Bytes32 startKeyHash) { this(rootHash, 1, 1, startKeyHash); @@ -78,6 +78,12 @@ public void addElement( taskIdentifier, ImmutableTaskElement.builder().proofs(proofs).keys(keys).build()); } + public void removeElement(final Bytes32 taskIdentifier) { + if (this.elements.containsKey(taskIdentifier)) { + this.elementsCount.addAndGet(-this.elements.remove(taskIdentifier).keys().size()); + } + } + public TaskElement getElement(final Bytes32 taskIdentifier) { return this.elements.get(taskIdentifier); } @@ -142,6 +148,11 @@ public void maybeStoreNode(final Bytes location, final Node node) { } } + public void clear() { + this.elements = new LinkedHashMap<>(); + this.elementsCount = new AtomicLong(); + } + public boolean addSegment() { if (nbSegments.get() > maxSegments) { return false; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/AccountRangeDataRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/AccountRangeDataRequest.java index a1a6bc63da4..06181fd09f1 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/AccountRangeDataRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/AccountRangeDataRequest.java @@ -216,6 +216,12 @@ public TreeMap getAccounts() { return stackTrie.getElement(startKeyHash).keys(); } + @Override + public void clear() { + stackTrie.clear(); + isProofValid = Optional.of(false); + } + public Bytes serialize() { return RLP.encode( out -> { diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/BytecodeRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/BytecodeRequest.java index 96673d6f874..5db5ec0211e 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/BytecodeRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/BytecodeRequest.java @@ -88,6 +88,11 @@ public Bytes32 getAccountHash() { return accountHash; } + @Override + public void clear() { + setCode(Bytes.EMPTY); + } + public Bytes32 getCodeHash() { return codeHash; } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/StorageRangeDataRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/StorageRangeDataRequest.java index c18d063d74d..14839f0ad6f 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/StorageRangeDataRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/StorageRangeDataRequest.java @@ -205,6 +205,12 @@ public Bytes32 getEndKeyHash() { return endKeyHash; } + @Override + public void clear() { + this.isProofValid = Optional.of(false); + this.stackTrie.removeElement(startKeyHash); + } + @VisibleForTesting public void setProofValid(final boolean isProofValid) { this.isProofValid = Optional.of(isProofValid); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/TrieNodeHealingRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/TrieNodeHealingRequest.java index c04066141d8..ef7191a0167 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/TrieNodeHealingRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/TrieNodeHealingRequest.java @@ -123,6 +123,11 @@ public boolean isResponseReceived() { return !data.isEmpty() && Hash.hash(data).equals(getNodeHash()); } + @Override + public void clear() { + setData(Bytes.EMPTY); + } + @Override public boolean isExpired(final SnapSyncProcessState snapSyncState) { return snapSyncState.isExpired(this); From 20a82d45482194129e68133973533c290be8eb1c Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 24 Oct 2023 11:38:05 +0200 Subject: [PATCH 2/2] Mining options refactor (#6027) Signed-off-by: Fabio Di Fabio Co-authored-by: Sally MacFarlane --- .../dsl/node/ProcessBesuNodeRunner.java | 6 +- .../BesuNodeConfigurationBuilder.java | 18 +- .../node/configuration/BesuNodeFactory.java | 13 +- .../bft/BftMiningAcceptanceTest.java | 13 +- .../org/hyperledger/besu/RunnerBuilder.java | 2 +- .../org/hyperledger/besu/cli/BesuCommand.java | 169 +----- .../besu/cli/DefaultCommandValues.java | 8 - .../besu/cli/options/MiningOptions.java | 303 +++++++++++ .../cli/options/unstable/MiningOptions.java | 151 ------ .../subcommands/blocks/BlocksSubCommand.java | 35 +- .../besu/cli/util/CommandLineUtils.java | 3 +- .../CliqueBesuControllerBuilder.java | 2 +- .../MainnetBesuControllerBuilder.java | 8 +- .../TransitionBesuControllerBuilder.java | 2 +- .../hyperledger/besu/PrivacyReorgTest.java | 6 +- .../org/hyperledger/besu/PrivacyTest.java | 2 +- .../java/org/hyperledger/besu/RunnerTest.java | 2 +- .../chainexport/RlpBlockExporterTest.java | 2 +- .../chainimport/JsonBlockImporterTest.java | 12 +- .../chainimport/RlpBlockImporterTest.java | 6 +- .../hyperledger/besu/cli/BesuCommandTest.java | 389 +------------- .../besu/cli/CommandTestAbstract.java | 39 ++ .../cli/options/AbstractCLIOptionsTest.java | 29 ++ .../besu/cli/options/MiningOptionsTest.java | 340 +++++++++++++ .../blocks/BlocksSubCommandTest.java | 3 +- .../controller/BesuControllerBuilderTest.java | 3 +- .../MergeBesuControllerBuilderTest.java | 7 +- .../TransitionControllerBuilderTest.java | 9 +- .../besu/services/BesuEventsImplTest.java | 8 +- .../blockcreation/CliqueBlockCreator.java | 19 +- .../blockcreation/CliqueMinerExecutor.java | 12 +- .../blockcreation/CliqueBlockCreatorTest.java | 39 +- .../CliqueMinerExecutorTest.java | 40 +- .../bft/blockcreation/BftBlockCreator.java | 16 +- .../blockcreation/BftBlockCreatorFactory.java | 33 +- .../ibft/support/TestContextBuilder.java | 15 +- .../blockcreation/BftBlockCreatorTest.java | 23 +- .../blockcreation/MergeBlockCreator.java | 28 +- .../merge/blockcreation/MergeCoordinator.java | 82 +-- .../blockcreation/MergeCoordinatorTest.java | 31 +- .../merge/blockcreation/MergeReorgTest.java | 7 +- .../qbft/support/TestContextBuilder.java | 15 +- .../QbftBlockCreatorFactory.java | 3 +- .../QbftBlockCreatorFactoryTest.java | 13 +- .../EthGetFilterChangesIntegrationTest.java | 2 +- .../EthGetFilterChangesIntegrationTest.java | 2 +- .../besu/ethereum/api/ApiConfiguration.java | 6 +- .../ethereum/api/query/BlockchainQueries.java | 2 +- .../AbstractEthGraphQLHttpServiceTest.java | 2 +- .../internal/methods/EthGasPriceTest.java | 2 +- .../blockcreation/AbstractBlockCreator.java | 25 +- .../blockcreation/AbstractMinerExecutor.java | 22 +- .../blockcreation/PoWBlockCreator.java | 16 +- .../blockcreation/PoWMinerExecutor.java | 35 +- .../txselection/BlockSelectionContext.java | 4 +- .../txselection/BlockTransactionSelector.java | 8 +- .../BlockSizeTransactionSelector.java | 4 +- .../selectors/PriceTransactionSelector.java | 8 +- .../AbstractBlockCreatorTest.java | 29 +- .../AbstractBlockTransactionSelectorTest.java | 25 +- .../blockcreation/PoWBlockCreatorTest.java | 67 +-- .../blockcreation/PoWMinerExecutorTest.java | 14 +- .../PoWMiningCoordinatorTest.java | 4 +- .../besu/ethereum/core/MiningParameters.java | 481 +++++++----------- .../besu/ethereum/mainnet/PoWSolver.java | 26 +- .../bonsai/AbstractIsolationTests.java | 31 +- .../besu/ethereum/mainnet/PoWSolverTest.java | 77 ++- .../eth/manager/EthProtocolManagerTest.java | 3 +- .../ethtaskutils/AbstractMessageTaskTest.java | 3 +- ...GetPooledTransactionsFromPeerTaskTest.java | 2 +- .../AbstractTransactionPoolTest.java | 5 +- .../ethereum/eth/transactions/TestNode.java | 3 +- .../TransactionPoolFactoryTest.java | 5 +- .../ethereum/retesteth/RetestethContext.java | 42 +- .../retesteth/methods/TestMineBlocks.java | 12 +- 75 files changed, 1445 insertions(+), 1488 deletions(-) create mode 100644 besu/src/main/java/org/hyperledger/besu/cli/options/MiningOptions.java delete mode 100644 besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MiningOptions.java create mode 100644 besu/src/test/java/org/hyperledger/besu/cli/options/MiningOptionsTest.java diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ProcessBesuNodeRunner.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ProcessBesuNodeRunner.java index 048e40553ba..f01c58549bc 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ProcessBesuNodeRunner.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ProcessBesuNodeRunner.java @@ -110,9 +110,11 @@ public void startNode(final BesuNode node) { params.add( Integer.toString(node.getMiningParameters().getMinTransactionGasPrice().intValue())); params.add("--Xminer-remote-sealers-limit"); - params.add(Integer.toString(node.getMiningParameters().getRemoteSealersLimit())); + params.add( + Integer.toString(node.getMiningParameters().getUnstable().getRemoteSealersLimit())); params.add("--Xminer-remote-sealers-hashrate-ttl"); - params.add(Long.toString(node.getMiningParameters().getRemoteSealersTimeToLive())); + params.add( + Long.toString(node.getMiningParameters().getUnstable().getRemoteSealersTimeToLive())); } if (node.getMiningParameters().isStratumMiningEnabled()) { params.add("--miner-stratum-enabled"); diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfigurationBuilder.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfigurationBuilder.java index 4943aaf60eb..fea87c35088 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfigurationBuilder.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfigurationBuilder.java @@ -22,7 +22,6 @@ import org.hyperledger.besu.cli.config.NetworkName; import org.hyperledger.besu.crypto.KeyPair; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis; import org.hyperledger.besu.ethereum.api.jsonrpc.authentication.JwtAlgorithm; @@ -30,6 +29,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration; import org.hyperledger.besu.ethereum.api.tls.FileBasedPasswordProvider; import org.hyperledger.besu.ethereum.core.AddressHelpers; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration; @@ -56,11 +57,11 @@ public class BesuNodeConfigurationBuilder { private String name; private Optional dataPath = Optional.empty(); private MiningParameters miningParameters = - new MiningParameters.Builder() - .miningEnabled(false) - .coinbase(AddressHelpers.ofValue(1)) - .minTransactionGasPrice(Wei.of(1000)) + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder().coinbase(AddressHelpers.ofValue(1)).build()) .build(); + private JsonRpcConfiguration jsonRpcConfiguration = JsonRpcConfiguration.createDefault(); private JsonRpcConfiguration engineRpcConfiguration = JsonRpcConfiguration.createEngineDefault(); private WebSocketConfiguration webSocketConfiguration = WebSocketConfiguration.createDefault(); @@ -113,12 +114,7 @@ public BesuNodeConfigurationBuilder miningEnabled() { } public BesuNodeConfigurationBuilder miningEnabled(final boolean enabled) { - this.miningParameters = - new MiningParameters.Builder() - .miningEnabled(enabled) - .minTransactionGasPrice(Wei.of(1000)) - .coinbase(AddressHelpers.ofValue(1)) - .build(); + this.miningParameters = miningParameters.setMiningEnabled(enabled); this.jsonRpcConfiguration.addRpcApi(RpcApis.MINER.name()); return this; } diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java index bd635c6bfcf..9e35d09f2fc 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java @@ -26,6 +26,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration; import org.hyperledger.besu.ethereum.core.AddressHelpers; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.InMemoryPrivacyStorageProvider; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; @@ -303,10 +305,13 @@ public BesuNode createNodeWithMultiTenantedPrivacy( .build(); final MiningParameters miningParameters = - new MiningParameters.Builder() - .minTransactionGasPrice(Wei.ZERO) - .coinbase(AddressHelpers.ofValue(1)) - .miningEnabled(true) + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .isMiningEnabled(true) + .minTransactionGasPrice(Wei.ZERO) + .coinbase(AddressHelpers.ofValue(1)) + .build()) .build(); return create( diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bft/BftMiningAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bft/BftMiningAcceptanceTest.java index e529268cb59..a109a3b8567 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bft/BftMiningAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bft/BftMiningAcceptanceTest.java @@ -17,6 +17,8 @@ import org.hyperledger.besu.config.JsonUtil; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.AddressHelpers; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.tests.acceptance.dsl.account.Account; import org.hyperledger.besu.tests.acceptance.dsl.blockchain.Amount; @@ -59,10 +61,13 @@ public void shouldMineOnSingleNodeWithPaidGas_Berlin() throws Exception { public void shouldMineOnSingleNodeWithFreeGas_Berlin() throws Exception { final BesuNode minerNode = nodeFactory.createNode(besu, "miner1"); final MiningParameters zeroGasMiningParams = - new MiningParameters.Builder() - .miningEnabled(true) - .minTransactionGasPrice(Wei.ZERO) - .coinbase(AddressHelpers.ofValue(1)) + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .isMiningEnabled(true) + .minTransactionGasPrice(Wei.ZERO) + .coinbase(AddressHelpers.ofValue(1)) + .build()) .build(); minerNode.setMiningParameters(zeroGasMiningParams); diff --git a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java index 857fd4e093e..4dc137fe3c7 100644 --- a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java @@ -768,7 +768,7 @@ public Runner build() { powMiningCoordinator, miningParameters.getStratumPort(), miningParameters.getStratumNetworkInterface(), - miningParameters.getStratumExtranonce(), + miningParameters.getUnstable().getStratumExtranonce(), metricsSystem)); miningCoordinator.addEthHashObserver(stratumServer.get()); LOG.debug("added ethash observer: {}", stratumServer.get()); 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 d7ce4dfa539..6d6bed2bfcf 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -53,6 +53,7 @@ import org.hyperledger.besu.cli.custom.RpcAuthFileValidator; import org.hyperledger.besu.cli.error.BesuExecutionExceptionHandler; import org.hyperledger.besu.cli.error.BesuParameterExceptionHandler; +import org.hyperledger.besu.cli.options.MiningOptions; import org.hyperledger.besu.cli.options.stable.DataStorageOptions; import org.hyperledger.besu.cli.options.stable.EthstatsOptions; import org.hyperledger.besu.cli.options.stable.LoggingLevelOption; @@ -65,7 +66,6 @@ import org.hyperledger.besu.cli.options.unstable.EvmOptions; import org.hyperledger.besu.cli.options.unstable.IpcOptions; import org.hyperledger.besu.cli.options.unstable.MetricsCLIOptions; -import org.hyperledger.besu.cli.options.unstable.MiningOptions; import org.hyperledger.besu.cli.options.unstable.NatOptions; import org.hyperledger.besu.cli.options.unstable.NativeLibraryOptions; import org.hyperledger.besu.cli.options.unstable.NetworkingOptions; @@ -287,7 +287,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable { unstableTransactionPoolOptions = org.hyperledger.besu.cli.options.unstable.TransactionPoolOptions.create(); private final DnsOptions unstableDnsOptions = DnsOptions.create(); - private final MiningOptions unstableMiningOptions = MiningOptions.create(); private final NatOptions unstableNatOptions = NatOptions.create(); private final NativeLibraryOptions unstableNativeLibraryOptions = NativeLibraryOptions.create(); private final RPCOptions unstableRPCOptions = RPCOptions.create(); @@ -307,6 +306,9 @@ public class BesuCommand implements DefaultCommandValues, Runnable { final org.hyperledger.besu.cli.options.stable.TransactionPoolOptions stableTransactionPoolOptions = TransactionPoolOptions.create(); + @CommandLine.ArgGroup(validate = false, heading = "@|bold Block Builder Options|@%n") + final MiningOptions miningOptions = MiningOptions.create(); + private final RunnerBuilder runnerBuilder; private final BesuController.Builder controllerBuilderFactory; private final BesuPluginContextImpl besuPluginContext; @@ -1068,63 +1070,6 @@ static class MetricsOptionGroup { "How deep a chain reorganization must be in order for it to be logged (default: ${DEFAULT-VALUE})") private final Long reorgLoggingThreshold = 6L; - // Miner options group - @CommandLine.ArgGroup(validate = false, heading = "@|bold Miner Options|@%n") - MinerOptionGroup minerOptionGroup = new MinerOptionGroup(); - - static class MinerOptionGroup { - @Option( - names = {"--miner-enabled"}, - description = "Set if node will perform mining (default: ${DEFAULT-VALUE})") - private final Boolean isMiningEnabled = false; - - @Option( - names = {"--miner-stratum-enabled"}, - description = "Set if node will perform Stratum mining (default: ${DEFAULT-VALUE})") - private final Boolean iStratumMiningEnabled = false; - - @SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings. - @Option( - names = {"--miner-stratum-host"}, - description = "Host for Stratum network mining service (default: ${DEFAULT-VALUE})") - private String stratumNetworkInterface = "0.0.0.0"; - - @Option( - names = {"--miner-stratum-port"}, - description = "Stratum port binding (default: ${DEFAULT-VALUE})") - private final Integer stratumPort = 8008; - - @Option( - names = {"--miner-coinbase"}, - description = - "Account to which mining rewards are paid. You must specify a valid coinbase if " - + "mining is enabled using --miner-enabled option", - arity = "1") - private final Address coinbase = null; - - @Option( - names = {"--miner-extra-data"}, - description = - "A hex string representing the (32) bytes to be included in the extra data " - + "field of a mined block (default: ${DEFAULT-VALUE})", - arity = "1") - private final Bytes extraData = DEFAULT_EXTRA_DATA; - } - - @Option( - names = {"--min-gas-price"}, - description = - "Minimum price (in Wei) offered by a transaction for it to be included in a mined " - + "block (default: ${DEFAULT-VALUE})", - arity = "1") - private final Wei minTransactionGasPrice = DEFAULT_MIN_TRANSACTION_GAS_PRICE; - - @Option( - names = {"--min-block-occupancy-ratio"}, - description = "Minimum occupancy ratio for a mined block (default: ${DEFAULT-VALUE})", - arity = "1") - private final Double minBlockOccupancyRatio = DEFAULT_MIN_BLOCK_OCCUPANCY_RATIO; - @Option( names = {"--pruning-enabled"}, description = @@ -1204,12 +1149,6 @@ static class PermissionsOptionGroup { split = ",") private final Map requiredBlocks = new HashMap<>(); - @Option( - names = {"--target-gas-limit"}, - description = - "Sets target gas limit per block. If set, each block's gas limit will approach this setting over time if the current gas limit is different.") - private final Long targetGasLimit = null; - @SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings. @Option( names = {"--key-value-storage"}, @@ -1316,6 +1255,7 @@ static class PermissionsOptionGroup { private Collection staticNodes; private BesuController besuController; private BesuConfiguration pluginCommonConfiguration; + private MiningParameters miningParameters; private BesuComponent besuComponent; private final Supplier metricsSystem = @@ -1586,7 +1526,6 @@ private void handleUnstableOptions() { .put("Privacy Plugin Configuration", unstablePrivacyPluginOptions) .put("Synchronizer", unstableSynchronizerOptions) .put("TransactionPool", unstableTransactionPoolOptions) - .put("Mining", unstableMiningOptions) .put("Native Library", unstableNativeLibraryOptions) .put("EVM Options", unstableEvmOptions) .put("IPC Options", unstableIpcOptions) @@ -1728,7 +1667,7 @@ private void validatePluginOptions() { "--privacy-marker-transaction-signing-key-file can not be used in conjunction with a plugin that specifies a PrivateMarkerTransactionFactory"); } - if (Wei.ZERO.compareTo(minTransactionGasPrice) < 0 + if (Wei.ZERO.compareTo(getMiningParameters().getMinTransactionGasPrice()) < 0 && (privacyOptionGroup.privateMarkerTransactionSigningKeyPath == null && (privacyPluginService == null || privacyPluginService.getPrivateMarkerTransactionFactory() == null))) { @@ -1871,35 +1810,9 @@ private void validateRequiredOptions() { }); } - @SuppressWarnings("ConstantConditions") private void validateMiningParams() { - if (Boolean.TRUE.equals(minerOptionGroup.isMiningEnabled) - && minerOptionGroup.coinbase == null) { - throw new ParameterException( - this.commandLine, - "Unable to mine without a valid coinbase. Either disable mining (remove --miner-enabled) " - + "or specify the beneficiary of mining (via --miner-coinbase
)"); - } - if (Boolean.FALSE.equals(minerOptionGroup.isMiningEnabled) - && Boolean.TRUE.equals(minerOptionGroup.iStratumMiningEnabled)) { - throw new ParameterException( - this.commandLine, - "Unable to mine with Stratum if mining is disabled. Either disable Stratum mining (remove --miner-stratum-enabled) " - + "or specify mining is enabled (--miner-enabled)"); - } - if (unstableMiningOptions.getPosBlockCreationMaxTime() <= 0 - || unstableMiningOptions.getPosBlockCreationMaxTime() - > MiningParameters.DEFAULT_POS_BLOCK_CREATION_MAX_TIME) { - throw new ParameterException( - this.commandLine, "--Xpos-block-creation-max-time must be positive and ≤ 12000"); - } - - if (unstableMiningOptions.getPosBlockCreationRepetitionMinDuration() <= 0 - || unstableMiningOptions.getPosBlockCreationRepetitionMinDuration() > 2000) { - throw new ParameterException( - this.commandLine, - "--Xpos-block-creation-repetition-min-duration must be positive and ≤ 2000"); - } + miningOptions.validate( + commandLine, logger, isMergeEnabled(), getActualGenesisConfigOptions().isEthHash()); } /** @@ -2072,31 +1985,6 @@ private void issueOptionWarnings() { "--p2p-port", "--remote-connections-max-percentage")); - // Check that block producer options work - if (!isMergeEnabled() && getActualGenesisConfigOptions().isEthHash()) { - CommandLineUtils.checkOptionDependencies( - logger, - commandLine, - "--miner-enabled", - !minerOptionGroup.isMiningEnabled, - asList( - "--miner-coinbase", - "--min-gas-price", - "--min-block-occupancy-ratio", - "--miner-extra-data")); - - // Check that mining options are able to work - CommandLineUtils.checkOptionDependencies( - logger, - commandLine, - "--miner-enabled", - !minerOptionGroup.isMiningEnabled, - asList( - "--miner-stratum-enabled", - "--Xminer-remote-sealers-limit", - "--Xminer-remote-sealers-hashrate-ttl")); - } - CommandLineUtils.failIfOptionDoesntMeetRequirement( commandLine, "--fast-sync-min-peers can't be used with FULL sync-mode", @@ -2250,26 +2138,7 @@ public BesuControllerBuilder getControllerBuilder() { .transactionSelectorFactory(getTransactionSelectorFactory()) .pluginTransactionValidatorFactory(getPluginTransactionValidatorFactory()) .dataDirectory(dataDir()) - .miningParameters( - new MiningParameters.Builder() - .coinbase(minerOptionGroup.coinbase) - .targetGasLimit(targetGasLimit) - .minTransactionGasPrice(minTransactionGasPrice) - .extraData(minerOptionGroup.extraData) - .miningEnabled(minerOptionGroup.isMiningEnabled) - .stratumMiningEnabled(minerOptionGroup.iStratumMiningEnabled) - .stratumNetworkInterface(minerOptionGroup.stratumNetworkInterface) - .stratumPort(minerOptionGroup.stratumPort) - .stratumExtranonce(unstableMiningOptions.getStratumExtranonce()) - .minBlockOccupancyRatio(minBlockOccupancyRatio) - .remoteSealersLimit(unstableMiningOptions.getRemoteSealersLimit()) - .remoteSealersTimeToLive(unstableMiningOptions.getRemoteSealersTimeToLive()) - .powJobTimeToLive(unstableMiningOptions.getPowJobTimeToLive()) - .maxOmmerDepth(unstableMiningOptions.getMaxOmmersDepth()) - .posBlockCreationMaxTime(unstableMiningOptions.getPosBlockCreationMaxTime()) - .posBlockCreationRepetitionMinDuration( - unstableMiningOptions.getPosBlockCreationRepetitionMinDuration()) - .build()) + .miningParameters(getMiningParameters()) .transactionPoolConfiguration(buildTransactionPoolConfiguration()) .nodeKey(new NodeKey(securityModule())) .metricsSystem(metricsSystem.get()) @@ -2284,9 +2153,9 @@ public BesuControllerBuilder getControllerBuilder() { new PrunerConfiguration(pruningBlockConfirmations, pruningBlocksRetained)) .genesisConfigOverrides(genesisConfigOverrides) .gasLimitCalculator( - Optional.ofNullable(targetGasLimit) - .map(z -> new FrontierTargetingGasLimitCalculator()) - .orElse(GasLimitCalculator.constant())) + getMiningParameters().getTargetGasLimit().isPresent() + ? new FrontierTargetingGasLimitCalculator() + : GasLimitCalculator.constant()) .requiredBlocks(requiredBlocks) .reorgLoggingThreshold(reorgLoggingThreshold) .evmConfiguration(unstableEvmOptions.toDomainObject()) @@ -2613,7 +2482,8 @@ private ApiConfiguration apiConfiguration() { return ImmutableApiConfiguration.builder() .gasPriceBlocks(apiGasPriceBlocks) .gasPricePercentile(apiGasPricePercentile) - .gasPriceMin(minTransactionGasPrice.toLong()) + .gasPriceMinSupplier( + getMiningParameters().getMinTransactionGasPrice().getAsBigInteger()::longValueExact) .gasPriceMax(apiGasPriceMax) .build(); } @@ -2949,6 +2819,13 @@ private TransactionPoolConfiguration buildTransactionPoolConfiguration() { .build(); } + private MiningParameters getMiningParameters() { + if (miningParameters == null) { + miningParameters = miningOptions.toDomainObject(); + } + return miningParameters; + } + private boolean isPruningEnabled() { return pruningEnabled; } @@ -3344,7 +3221,9 @@ private List getEffectivePorts() { addPortIfEnabled( effectivePorts, metricsOptionGroup.metricsPort, metricsOptionGroup.isMetricsEnabled); addPortIfEnabled( - effectivePorts, minerOptionGroup.stratumPort, minerOptionGroup.iStratumMiningEnabled); + effectivePorts, + getMiningParameters().getStratumPort(), + getMiningParameters().isStratumMiningEnabled()); return effectivePorts; } diff --git a/besu/src/main/java/org/hyperledger/besu/cli/DefaultCommandValues.java b/besu/src/main/java/org/hyperledger/besu/cli/DefaultCommandValues.java index 8b837268327..b7d603b8caa 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/DefaultCommandValues.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/DefaultCommandValues.java @@ -14,7 +14,6 @@ */ package org.hyperledger.besu.cli; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.jsonrpc.authentication.JwtAlgorithm; import org.hyperledger.besu.ethereum.p2p.config.RlpxConfiguration; import org.hyperledger.besu.nat.NatMethod; @@ -28,7 +27,6 @@ import java.nio.file.Paths; import java.util.List; -import org.apache.tuweni.bytes.Bytes; import picocli.CommandLine; /** The interface Default command values. */ @@ -58,12 +56,6 @@ public interface DefaultCommandValues { String MANDATORY_NETWORK_FORMAT_HELP = ""; /** The constant MANDATORY_NODE_ID_FORMAT_HELP. */ String MANDATORY_NODE_ID_FORMAT_HELP = ""; - /** The constant DEFAULT_MIN_TRANSACTION_GAS_PRICE. */ - Wei DEFAULT_MIN_TRANSACTION_GAS_PRICE = Wei.of(1000); - /** The constant DEFAULT_MIN_BLOCK_OCCUPANCY_RATIO. */ - Double DEFAULT_MIN_BLOCK_OCCUPANCY_RATIO = 0.8; - /** The constant DEFAULT_EXTRA_DATA. */ - Bytes DEFAULT_EXTRA_DATA = Bytes.EMPTY; /** The constant PERMISSIONING_CONFIG_LOCATION. */ String PERMISSIONING_CONFIG_LOCATION = "permissions_config.toml"; /** The constant MANDATORY_HOST_FORMAT_HELP. */ diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/MiningOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/MiningOptions.java new file mode 100644 index 00000000000..af4e423b416 --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/MiningOptions.java @@ -0,0 +1,303 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * 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.cli.options; + +import static java.util.Arrays.asList; +import static org.hyperledger.besu.ethereum.core.MiningParameters.MutableInitValues.DEFAULT_EXTRA_DATA; +import static org.hyperledger.besu.ethereum.core.MiningParameters.MutableInitValues.DEFAULT_MIN_BLOCK_OCCUPANCY_RATIO; +import static org.hyperledger.besu.ethereum.core.MiningParameters.MutableInitValues.DEFAULT_MIN_TRANSACTION_GAS_PRICE; +import static org.hyperledger.besu.ethereum.core.MiningParameters.Unstable.DEFAULT_MAX_OMMERS_DEPTH; +import static org.hyperledger.besu.ethereum.core.MiningParameters.Unstable.DEFAULT_POS_BLOCK_CREATION_MAX_TIME; +import static org.hyperledger.besu.ethereum.core.MiningParameters.Unstable.DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION; +import static org.hyperledger.besu.ethereum.core.MiningParameters.Unstable.DEFAULT_POW_JOB_TTL; +import static org.hyperledger.besu.ethereum.core.MiningParameters.Unstable.DEFAULT_REMOTE_SEALERS_LIMIT; +import static org.hyperledger.besu.ethereum.core.MiningParameters.Unstable.DEFAULT_REMOTE_SEALERS_TTL; + +import org.hyperledger.besu.cli.util.CommandLineUtils; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; +import org.hyperledger.besu.ethereum.core.MiningParameters; + +import java.util.List; + +import org.apache.tuweni.bytes.Bytes; +import org.slf4j.Logger; +import picocli.CommandLine; +import picocli.CommandLine.Option; +import picocli.CommandLine.ParameterException; + +/** The Mining CLI options. */ +public class MiningOptions implements CLIOptions { + + @Option( + names = {"--miner-enabled"}, + description = "Set if node will perform mining (default: ${DEFAULT-VALUE})") + private Boolean isMiningEnabled = false; + + @Option( + names = {"--miner-stratum-enabled"}, + description = "Set if node will perform Stratum mining (default: ${DEFAULT-VALUE})") + private Boolean iStratumMiningEnabled = false; + + @Option( + names = {"--miner-stratum-host"}, + description = "Host for Stratum network mining service (default: ${DEFAULT-VALUE})") + private String stratumNetworkInterface = "0.0.0.0"; + + @Option( + names = {"--miner-stratum-port"}, + description = "Stratum port binding (default: ${DEFAULT-VALUE})") + private Integer stratumPort = 8008; + + @Option( + names = {"--miner-coinbase"}, + description = + "Account to which mining rewards are paid. You must specify a valid coinbase if " + + "mining is enabled using --miner-enabled option", + arity = "1") + private Address coinbase = null; + + @Option( + names = {"--miner-extra-data"}, + description = + "A hex string representing the (32) bytes to be included in the extra data " + + "field of a mined block (default: ${DEFAULT-VALUE})", + arity = "1") + private Bytes extraData = DEFAULT_EXTRA_DATA; + + @Option( + names = {"--min-block-occupancy-ratio"}, + description = "Minimum occupancy ratio for a mined block (default: ${DEFAULT-VALUE})", + arity = "1") + private Double minBlockOccupancyRatio = DEFAULT_MIN_BLOCK_OCCUPANCY_RATIO; + + @Option( + names = {"--min-gas-price"}, + description = + "Minimum price (in Wei) offered by a transaction for it to be included in a mined " + + "block (default: ${DEFAULT-VALUE})", + arity = "1") + private Wei minTransactionGasPrice = DEFAULT_MIN_TRANSACTION_GAS_PRICE; + + @Option( + names = {"--target-gas-limit"}, + description = + "Sets target gas limit per block. If set, each block's gas limit will approach this setting over time if the current gas limit is different.") + private Long targetGasLimit = null; + + @CommandLine.ArgGroup(validate = false) + private final Unstable unstableOptions = new Unstable(); + + static class Unstable { + @CommandLine.Option( + hidden = true, + names = {"--Xminer-remote-sealers-limit"}, + description = + "Limits the number of remote sealers that can submit their hashrates (default: ${DEFAULT-VALUE})") + private Integer remoteSealersLimit = DEFAULT_REMOTE_SEALERS_LIMIT; + + @CommandLine.Option( + hidden = true, + names = {"--Xminer-remote-sealers-hashrate-ttl"}, + description = + "Specifies the lifetime of each entry in the cache. An entry will be automatically deleted if no update has been received before the deadline (default: ${DEFAULT-VALUE} minutes)") + private Long remoteSealersTimeToLive = DEFAULT_REMOTE_SEALERS_TTL; + + @CommandLine.Option( + hidden = true, + names = {"--Xminer-pow-job-ttl"}, + description = + "Specifies the time PoW jobs are kept in cache and will accept a solution from miners (default: ${DEFAULT-VALUE} milliseconds)") + private Long powJobTimeToLive = DEFAULT_POW_JOB_TTL; + + @CommandLine.Option( + hidden = true, + names = {"--Xmax-ommers-depth"}, + description = + "Specifies the depth of ommer blocks to accept when receiving solutions (default: ${DEFAULT-VALUE})") + private Integer maxOmmersDepth = DEFAULT_MAX_OMMERS_DEPTH; + + @CommandLine.Option( + hidden = true, + names = {"--Xminer-stratum-extranonce"}, + description = "Extranonce for Stratum network miners (default: ${DEFAULT-VALUE})") + private String stratumExtranonce = "080c"; + + @CommandLine.Option( + hidden = true, + names = {"--Xpos-block-creation-max-time"}, + description = + "Specifies the maximum time, in milliseconds, a PoS block creation jobs is allowed to run. Must be positive and ≤ 12000 (default: ${DEFAULT-VALUE} milliseconds)") + private Long posBlockCreationMaxTime = DEFAULT_POS_BLOCK_CREATION_MAX_TIME; + + @CommandLine.Option( + hidden = true, + names = {"--Xpos-block-creation-repetition-min-duration"}, + description = + "If a PoS block creation repetition takes less than this duration, in milliseconds," + + " then it waits before next repetition. Must be positive and ≤ 2000 (default: ${DEFAULT-VALUE} milliseconds)") + private Long posBlockCreationRepetitionMinDuration = + DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION; + } + + private MiningOptions() {} + + /** + * Create mining options. + * + * @return the mining options + */ + public static MiningOptions create() { + return new MiningOptions(); + } + + /** + * Validate that there are no inconsistencies in the specified options. For example that the + * options are valid for the selected implementation. + * + * @param commandLine the full commandLine to check all the options specified by the user + * @param logger the logger + * @param isMergeEnabled is the Merge enabled? + * @param isEthHash is EthHash? + */ + public void validate( + final CommandLine commandLine, + final Logger logger, + final boolean isMergeEnabled, + final boolean isEthHash) { + if (Boolean.TRUE.equals(isMiningEnabled) && coinbase == null) { + throw new ParameterException( + commandLine, + "Unable to mine without a valid coinbase. Either disable mining (remove --miner-enabled) " + + "or specify the beneficiary of mining (via --miner-coinbase
)"); + } + if (Boolean.FALSE.equals(isMiningEnabled) && Boolean.TRUE.equals(iStratumMiningEnabled)) { + throw new ParameterException( + commandLine, + "Unable to mine with Stratum if mining is disabled. Either disable Stratum mining (remove --miner-stratum-enabled) " + + "or specify mining is enabled (--miner-enabled)"); + } + + // Check that block producer options work + if (!isMergeEnabled && isEthHash) { + CommandLineUtils.checkOptionDependencies( + logger, + commandLine, + "--miner-enabled", + !isMiningEnabled, + asList( + "--miner-coinbase", + "--min-gas-price", + "--min-block-occupancy-ratio", + "--miner-extra-data")); + + // Check that mining options are able to work + CommandLineUtils.checkOptionDependencies( + logger, + commandLine, + "--miner-enabled", + !isMiningEnabled, + asList( + "--miner-stratum-enabled", + "--Xminer-remote-sealers-limit", + "--Xminer-remote-sealers-hashrate-ttl")); + } + + if (unstableOptions.posBlockCreationMaxTime <= 0 + || unstableOptions.posBlockCreationMaxTime > DEFAULT_POS_BLOCK_CREATION_MAX_TIME) { + throw new ParameterException( + commandLine, "--Xpos-block-creation-max-time must be positive and ≤ 12000"); + } + + if (unstableOptions.posBlockCreationRepetitionMinDuration <= 0 + || unstableOptions.posBlockCreationRepetitionMinDuration > 2000) { + throw new ParameterException( + commandLine, "--Xpos-block-creation-repetition-min-duration must be positive and ≤ 2000"); + } + } + + static MiningOptions fromConfig(final MiningParameters miningParameters) { + final MiningOptions miningOptions = MiningOptions.create(); + miningOptions.isMiningEnabled = miningParameters.isMiningEnabled(); + miningOptions.iStratumMiningEnabled = miningParameters.isStratumMiningEnabled(); + miningOptions.stratumNetworkInterface = miningParameters.getStratumNetworkInterface(); + miningOptions.stratumPort = miningParameters.getStratumPort(); + miningOptions.extraData = miningParameters.getExtraData(); + miningOptions.minTransactionGasPrice = miningParameters.getMinTransactionGasPrice(); + miningOptions.minBlockOccupancyRatio = miningParameters.getMinBlockOccupancyRatio(); + miningOptions.unstableOptions.remoteSealersLimit = + miningParameters.getUnstable().getRemoteSealersLimit(); + miningOptions.unstableOptions.remoteSealersTimeToLive = + miningParameters.getUnstable().getRemoteSealersTimeToLive(); + miningOptions.unstableOptions.powJobTimeToLive = + miningParameters.getUnstable().getPowJobTimeToLive(); + miningOptions.unstableOptions.maxOmmersDepth = + miningParameters.getUnstable().getMaxOmmerDepth(); + miningOptions.unstableOptions.stratumExtranonce = + miningParameters.getUnstable().getStratumExtranonce(); + miningOptions.unstableOptions.posBlockCreationMaxTime = + miningParameters.getUnstable().getPosBlockCreationMaxTime(); + miningOptions.unstableOptions.posBlockCreationRepetitionMinDuration = + miningParameters.getUnstable().getPosBlockCreationRepetitionMinDuration(); + + miningParameters.getCoinbase().ifPresent(coinbase -> miningOptions.coinbase = coinbase); + miningParameters.getTargetGasLimit().ifPresent(tgl -> miningOptions.targetGasLimit = tgl); + return miningOptions; + } + + @Override + public MiningParameters toDomainObject() { + final var updatableInitValuesBuilder = + MutableInitValues.builder() + .isMiningEnabled(isMiningEnabled) + .extraData(extraData) + .minTransactionGasPrice(minTransactionGasPrice) + .minBlockOccupancyRatio(minBlockOccupancyRatio); + + if (targetGasLimit != null) { + updatableInitValuesBuilder.targetGasLimit(targetGasLimit); + } + if (coinbase != null) { + updatableInitValuesBuilder.coinbase(coinbase); + } + + final var miningParametersBuilder = + ImmutableMiningParameters.builder() + .mutableInitValues(updatableInitValuesBuilder.build()) + .isStratumMiningEnabled(iStratumMiningEnabled) + .stratumNetworkInterface(stratumNetworkInterface) + .stratumPort(stratumPort) + .unstable( + ImmutableMiningParameters.Unstable.builder() + .remoteSealersLimit(unstableOptions.remoteSealersLimit) + .remoteSealersTimeToLive(unstableOptions.remoteSealersTimeToLive) + .powJobTimeToLive(unstableOptions.powJobTimeToLive) + .maxOmmerDepth(unstableOptions.maxOmmersDepth) + .stratumExtranonce(unstableOptions.stratumExtranonce) + .posBlockCreationMaxTime(unstableOptions.posBlockCreationMaxTime) + .posBlockCreationRepetitionMinDuration( + unstableOptions.posBlockCreationRepetitionMinDuration) + .build()); + + return miningParametersBuilder.build(); + } + + @Override + public List getCLIOptions() { + return CommandLineUtils.getCLIOptions(this, new MiningOptions()); + } +} diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MiningOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MiningOptions.java deleted file mode 100644 index 232554722e2..00000000000 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MiningOptions.java +++ /dev/null @@ -1,151 +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.cli.options.unstable; - -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_MAX_OMMERS_DEPTH; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_POS_BLOCK_CREATION_MAX_TIME; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_POW_JOB_TTL; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_REMOTE_SEALERS_LIMIT; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_REMOTE_SEALERS_TTL; - -import picocli.CommandLine; - -/** The Mining CLI options. */ -public class MiningOptions { - - @CommandLine.Option( - hidden = true, - names = {"--Xminer-remote-sealers-limit"}, - description = - "Limits the number of remote sealers that can submit their hashrates (default: ${DEFAULT-VALUE})") - private final Integer remoteSealersLimit = DEFAULT_REMOTE_SEALERS_LIMIT; - - @CommandLine.Option( - hidden = true, - names = {"--Xminer-remote-sealers-hashrate-ttl"}, - description = - "Specifies the lifetime of each entry in the cache. An entry will be automatically deleted if no update has been received before the deadline (default: ${DEFAULT-VALUE} minutes)") - private final Long remoteSealersTimeToLive = DEFAULT_REMOTE_SEALERS_TTL; - - @CommandLine.Option( - hidden = true, - names = {"--Xminer-pow-job-ttl"}, - description = - "Specifies the time PoW jobs are kept in cache and will accept a solution from miners (default: ${DEFAULT-VALUE} milliseconds)") - private final Long powJobTimeToLive = DEFAULT_POW_JOB_TTL; - - @CommandLine.Option( - hidden = true, - names = {"--Xmax-ommers-depth"}, - description = - "Specifies the depth of ommer blocks to accept when receiving solutions (default: ${DEFAULT-VALUE})") - private final Integer maxOmmersDepth = DEFAULT_MAX_OMMERS_DEPTH; - - @SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings. - @CommandLine.Option( - hidden = true, - names = {"--Xminer-stratum-extranonce"}, - description = "Extranonce for Stratum network miners (default: ${DEFAULT-VALUE})") - private String stratumExtranonce = "080c"; - - @CommandLine.Option( - hidden = true, - names = {"--Xpos-block-creation-max-time"}, - description = - "Specifies the maximum time, in milliseconds, a PoS block creation jobs is allowed to run. Must be positive and ≤ 12000 (default: ${DEFAULT-VALUE} milliseconds)") - private final Long posBlockCreationMaxTime = DEFAULT_POS_BLOCK_CREATION_MAX_TIME; - - @CommandLine.Option( - hidden = true, - names = {"--Xpos-block-creation-repetition-min-duration"}, - description = - "If a PoS block creation repetition takes less than this duration, in milliseconds," - + " then it waits before next repetition. Must be positive and ≤ 2000 (default: ${DEFAULT-VALUE} milliseconds)") - private final Long posBlockCreationRepetitionMinDuration = - DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION; - - /** - * Create mining options. - * - * @return the mining options - */ - public static MiningOptions create() { - return new MiningOptions(); - } - - /** - * Gets remote sealers limit. - * - * @return the remote sealers limit - */ - public Integer getRemoteSealersLimit() { - return remoteSealersLimit; - } - - /** - * Gets remote sealers time to live. - * - * @return the remote sealers time to live - */ - public Long getRemoteSealersTimeToLive() { - return remoteSealersTimeToLive; - } - - /** - * Gets stratum extra nonce. - * - * @return the stratum extra nonce - */ - public String getStratumExtranonce() { - return stratumExtranonce; - } - - /** - * Gets pow job time to live. - * - * @return the pow job time to live - */ - public Long getPowJobTimeToLive() { - return powJobTimeToLive; - } - - /** - * Gets max ommers depth. - * - * @return the max ommers depth - */ - public int getMaxOmmersDepth() { - return maxOmmersDepth; - } - - /** - * Gets pos block creation max time. - * - * @return the pos block creation max time - */ - public Long getPosBlockCreationMaxTime() { - return posBlockCreationMaxTime; - } - - /** - * Gets pos block creation repetition min duration. - * - * @return the pos block creation repetition min duration. - */ - public Long getPosBlockCreationRepetitionMinDuration() { - return posBlockCreationRepetitionMinDuration; - } -} diff --git a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommand.java index 9417aad8f55..ea8bfab8d14 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommand.java @@ -16,10 +16,6 @@ import static com.google.common.base.Preconditions.checkNotNull; import static org.hyperledger.besu.cli.subcommands.blocks.BlocksSubCommand.COMMAND_NAME; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_MAX_OMMERS_DEPTH; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_POW_JOB_TTL; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_REMOTE_SEALERS_LIMIT; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_REMOTE_SEALERS_TTL; import org.hyperledger.besu.chainexport.RlpBlockExporter; import org.hyperledger.besu.chainimport.JsonBlockImporter; @@ -35,6 +31,8 @@ import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.blockcreation.IncrementingNonceGenerator; import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.metrics.MetricsService; import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration; @@ -271,21 +269,14 @@ private MiningParameters getMiningParameters() { // Extradata and coinbase can be configured on a per-block level via the json file final Address coinbase = Address.ZERO; final Bytes extraData = Bytes.EMPTY; - return new MiningParameters.Builder() - .coinbase(coinbase) - .minTransactionGasPrice(minTransactionGasPrice) - .extraData(extraData) - .miningEnabled(false) - .stratumMiningEnabled(false) - .stratumNetworkInterface("0.0.0.0") - .stratumPort(8008) - .stratumExtranonce("080c") - .maybeNonceGenerator(new IncrementingNonceGenerator(0)) - .minBlockOccupancyRatio(0.0) - .remoteSealersLimit(DEFAULT_REMOTE_SEALERS_LIMIT) - .remoteSealersTimeToLive(DEFAULT_REMOTE_SEALERS_TTL) - .powJobTimeToLive(DEFAULT_POW_JOB_TTL) - .maxOmmerDepth(DEFAULT_MAX_OMMERS_DEPTH) + return ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .nonceGenerator(new IncrementingNonceGenerator(0)) + .extraData(extraData) + .minTransactionGasPrice(minTransactionGasPrice) + .coinbase(coinbase) + .build()) .build(); } @@ -381,7 +372,11 @@ public void run() { } private BesuController createBesuController() { - return parentCommand.parentCommand.buildController(); + return parentCommand + .parentCommand + .getControllerBuilder() + .miningParameters(MiningParameters.newDefault()) + .build(); } private void exportRlpFormat(final BesuController controller) throws IOException { diff --git a/besu/src/main/java/org/hyperledger/besu/cli/util/CommandLineUtils.java b/besu/src/main/java/org/hyperledger/besu/cli/util/CommandLineUtils.java index a44e616bd3d..33b531b5903 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/util/CommandLineUtils.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/util/CommandLineUtils.java @@ -178,9 +178,8 @@ public static List getCLIOptions(final Object currOptions, final Object var optVal = field.get(currOptions); if (!Objects.equals(optVal, field.get(defaults))) { var optAnn = CommandLine.Option.class.cast(ann); - cliOpts.add(optAnn.names()[0]); final var optConverter = optAnn.converter(); - cliOpts.add(formatValue(optConverter, optVal)); + cliOpts.add(optAnn.names()[0] + "=" + formatValue(optConverter, optVal)); } } catch (IllegalAccessException e) { throw new RuntimeException(e); 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 1e894e0d9c5..baad246a76b 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java @@ -148,6 +148,6 @@ protected CliqueContext createConsensusContext( @Override public MiningParameters getMiningParameterOverrides(final MiningParameters fromCli) { // Clique mines by default, reflect that with in the mining parameters: - return new MiningParameters.Builder(fromCli).miningEnabled(true).build(); + return fromCli.setMiningEnabled(true); } } 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 0fce7f484ce..6f034e6f759 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java @@ -55,17 +55,15 @@ protected MiningCoordinator createMiningCoordinator( MainnetBlockHeaderValidator.MINIMUM_SECONDS_SINCE_PARENT, MainnetBlockHeaderValidator.TIMESTAMP_TOLERANCE_S, clock), - epochCalculator, - miningParameters.getPowJobTimeToLive(), - miningParameters.getMaxOmmerDepth()); + epochCalculator); final PoWMiningCoordinator miningCoordinator = new PoWMiningCoordinator( protocolContext.getBlockchain(), executor, syncState, - miningParameters.getRemoteSealersLimit(), - miningParameters.getRemoteSealersTimeToLive()); + miningParameters.getUnstable().getRemoteSealersLimit(), + miningParameters.getUnstable().getRemoteSealersTimeToLive()); miningCoordinator.addMinedBlockObserver(ethProtocolManager); miningCoordinator.setStratumMiningEnabled(miningParameters.isStratumMiningEnabled()); if (miningParameters.isMiningEnabled()) { 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 6db71ef81ca..d4541d91b9c 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java @@ -134,7 +134,7 @@ protected MiningCoordinator createMiningCoordinator( transitionProtocolSchedule.getPreMergeSchedule(), protocolContext, transactionPool, - new MiningParameters.Builder(miningParameters).miningEnabled(false).build(), + MiningParameters.MINING_DISABLED, syncState, ethProtocolManager), mergeBesuControllerBuilder.createTransitionMiningCoordinator( diff --git a/besu/src/test/java/org/hyperledger/besu/PrivacyReorgTest.java b/besu/src/test/java/org/hyperledger/besu/PrivacyReorgTest.java index f831e1ecd59..276740fbfed 100644 --- a/besu/src/test/java/org/hyperledger/besu/PrivacyReorgTest.java +++ b/besu/src/test/java/org/hyperledger/besu/PrivacyReorgTest.java @@ -187,11 +187,7 @@ public void setUp() throws IOException { .ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig()) .storageProvider(new InMemoryKeyValueStorageProvider()) .networkId(BigInteger.ONE) - .miningParameters( - new MiningParameters.Builder() - .minTransactionGasPrice(Wei.of(1000)) - .miningEnabled(false) - .build()) + .miningParameters(MiningParameters.newDefault()) .nodeKey(NodeKeyUtils.generate()) .metricsSystem(new NoOpMetricsSystem()) .dataDirectory(folder) diff --git a/besu/src/test/java/org/hyperledger/besu/PrivacyTest.java b/besu/src/test/java/org/hyperledger/besu/PrivacyTest.java index bfdd71b3d2a..c71d44284fb 100644 --- a/besu/src/test/java/org/hyperledger/besu/PrivacyTest.java +++ b/besu/src/test/java/org/hyperledger/besu/PrivacyTest.java @@ -111,7 +111,7 @@ private BesuController setUpControllerWithPrivacyEnabled(final boolean flexibleE .ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig()) .storageProvider(new InMemoryKeyValueStorageProvider()) .networkId(BigInteger.ONE) - .miningParameters(new MiningParameters.Builder().miningEnabled(false).build()) + .miningParameters(MiningParameters.newDefault()) .nodeKey(NodeKeyUtils.generate()) .metricsSystem(new NoOpMetricsSystem()) .dataDirectory(dataDir) diff --git a/besu/src/test/java/org/hyperledger/besu/RunnerTest.java b/besu/src/test/java/org/hyperledger/besu/RunnerTest.java index 93207b1d11a..43a4d2cd963 100644 --- a/besu/src/test/java/org/hyperledger/besu/RunnerTest.java +++ b/besu/src/test/java/org/hyperledger/besu/RunnerTest.java @@ -448,7 +448,7 @@ private BesuController getController( .ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig()) .dataDirectory(dataDir) .networkId(NETWORK_ID) - .miningParameters(new MiningParameters.Builder().miningEnabled(false).build()) + .miningParameters(MiningParameters.newDefault()) .nodeKey(nodeKey) .storageProvider(storageProvider) .metricsSystem(metricsSystem) diff --git a/besu/src/test/java/org/hyperledger/besu/chainexport/RlpBlockExporterTest.java b/besu/src/test/java/org/hyperledger/besu/chainexport/RlpBlockExporterTest.java index e6b60dad197..89e1b255479 100644 --- a/besu/src/test/java/org/hyperledger/besu/chainexport/RlpBlockExporterTest.java +++ b/besu/src/test/java/org/hyperledger/besu/chainexport/RlpBlockExporterTest.java @@ -91,7 +91,7 @@ private static BesuController createController() throws IOException { .ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig()) .storageProvider(new InMemoryKeyValueStorageProvider()) .networkId(BigInteger.ONE) - .miningParameters(new MiningParameters.Builder().miningEnabled(false).build()) + .miningParameters(MiningParameters.newDefault()) .nodeKey(NodeKeyUtils.generate()) .metricsSystem(new NoOpMetricsSystem()) .privacyParameters(PrivacyParameters.DEFAULT) diff --git a/besu/src/test/java/org/hyperledger/besu/chainimport/JsonBlockImporterTest.java b/besu/src/test/java/org/hyperledger/besu/chainimport/JsonBlockImporterTest.java index 00c86133ea6..00ebc610823 100644 --- a/besu/src/test/java/org/hyperledger/besu/chainimport/JsonBlockImporterTest.java +++ b/besu/src/test/java/org/hyperledger/besu/chainimport/JsonBlockImporterTest.java @@ -29,8 +29,9 @@ import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; -import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; @@ -421,9 +422,12 @@ protected BesuController createController(final GenesisConfigFile genesisConfigF .storageProvider(new InMemoryKeyValueStorageProvider()) .networkId(BigInteger.valueOf(10)) .miningParameters( - new MiningParameters.Builder() - .minTransactionGasPrice(Wei.ZERO) - .miningEnabled(true) + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .isMiningEnabled(true) + .minTransactionGasPrice(Wei.ZERO) + .build()) .build()) .nodeKey(NodeKeyUtils.generate()) .metricsSystem(new NoOpMetricsSystem()) diff --git a/besu/src/test/java/org/hyperledger/besu/chainimport/RlpBlockImporterTest.java b/besu/src/test/java/org/hyperledger/besu/chainimport/RlpBlockImporterTest.java index 3260b8ee55b..f9d543aca9f 100644 --- a/besu/src/test/java/org/hyperledger/besu/chainimport/RlpBlockImporterTest.java +++ b/besu/src/test/java/org/hyperledger/besu/chainimport/RlpBlockImporterTest.java @@ -67,7 +67,7 @@ public void blockImport() throws IOException { .ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig()) .storageProvider(new InMemoryKeyValueStorageProvider()) .networkId(BigInteger.ONE) - .miningParameters(new MiningParameters.Builder().miningEnabled(false).build()) + .miningParameters(MiningParameters.newDefault()) .nodeKey(NodeKeyUtils.generate()) .metricsSystem(new NoOpMetricsSystem()) .privacyParameters(PrivacyParameters.DEFAULT) @@ -100,7 +100,7 @@ public void blockImportRejectsBadPow() throws IOException { .ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig()) .storageProvider(new InMemoryKeyValueStorageProvider()) .networkId(BigInteger.ONE) - .miningParameters(new MiningParameters.Builder().miningEnabled(false).build()) + .miningParameters(MiningParameters.newDefault()) .nodeKey(NodeKeyUtils.generate()) .metricsSystem(new NoOpMetricsSystem()) .privacyParameters(PrivacyParameters.DEFAULT) @@ -130,7 +130,7 @@ public void blockImportCanSkipPow() throws IOException { .ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig()) .storageProvider(new InMemoryKeyValueStorageProvider()) .networkId(BigInteger.ONE) - .miningParameters(new MiningParameters.Builder().miningEnabled(false).build()) + .miningParameters(MiningParameters.newDefault()) .nodeKey(NodeKeyUtils.generate()) .metricsSystem(new NoOpMetricsSystem()) .privacyParameters(PrivacyParameters.DEFAULT) 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 af28e7ba7c2..91a203ff576 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -35,7 +35,6 @@ import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis.NET; import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis.PERM; import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis.WEB3; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_POS_BLOCK_CREATION_MAX_TIME; import static org.hyperledger.besu.ethereum.p2p.config.DefaultDiscoveryConfiguration.GOERLI_BOOTSTRAP_NODES; import static org.hyperledger.besu.ethereum.p2p.config.DefaultDiscoveryConfiguration.GOERLI_DISCOVERY_URL; import static org.hyperledger.besu.ethereum.p2p.config.DefaultDiscoveryConfiguration.MAINNET_BOOTSTRAP_NODES; @@ -48,7 +47,6 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNotNull; import static org.mockito.Mockito.atLeast; -import static org.mockito.Mockito.atMost; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -72,6 +70,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.authentication.JwtAlgorithm; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration; import org.hyperledger.besu.ethereum.api.tls.TlsConfiguration; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.eth.sync.SyncMode; @@ -161,20 +161,6 @@ public class BesuCommandTest extends CommandTestAbstract { (new JsonObject()).put("config", new JsonObject().put("ecCurve", "secp256k1")); private static final String ENCLAVE_PUBLIC_KEY_PATH = BesuCommand.class.getResource("/orion_publickey.pub").getPath(); - private static final JsonObject VALID_GENESIS_QBFT_POST_LONDON = - (new JsonObject()) - .put( - "config", - new JsonObject() - .put("londonBlock", 0) - .put("qbft", new JsonObject().put("blockperiodseconds", 5))); - private static final JsonObject VALID_GENESIS_IBFT2_POST_LONDON = - (new JsonObject()) - .put( - "config", - new JsonObject() - .put("londonBlock", 0) - .put("ibft2", new JsonObject().put("blockperiodseconds", 5))); private static final String[] VALID_ENODE_STRINGS = { "enode://" + VALID_NODE_ID + "@192.168.0.1:4567", @@ -916,11 +902,11 @@ public void envVariableOverridesValueFromConfigFile() { verify(mockControllerBuilder) .miningParameters( - new MiningParameters.Builder() - .coinbase(Address.fromHexString(expectedCoinbase)) - .minTransactionGasPrice(DefaultCommandValues.DEFAULT_MIN_TRANSACTION_GAS_PRICE) - .extraData(DefaultCommandValues.DEFAULT_EXTRA_DATA) - .miningEnabled(false) + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .coinbase(Address.fromHexString(expectedCoinbase)) + .build()) .build()); } @@ -933,11 +919,11 @@ public void cliOptionOverridesEnvVariableAndConfig() { verify(mockControllerBuilder) .miningParameters( - new MiningParameters.Builder() - .coinbase(Address.fromHexString(expectedCoinbase)) - .minTransactionGasPrice(DefaultCommandValues.DEFAULT_MIN_TRANSACTION_GAS_PRICE) - .extraData(DefaultCommandValues.DEFAULT_EXTRA_DATA) - .miningEnabled(false) + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .coinbase(Address.fromHexString(expectedCoinbase)) + .build()) .build()); } @@ -3652,261 +3638,6 @@ public void metricsAndMetricsPushMustNotBeUsedTogether() { .startsWith("--metrics-enabled option and --metrics-push-enabled option can't be used"); } - @Test - public void besuDoesNotStartInMiningModeIfCoinbaseNotSet() { - parseCommand("--miner-enabled"); - - Mockito.verifyNoInteractions(mockControllerBuilder); - } - - @Test - public void miningIsEnabledWhenSpecified() throws Exception { - final String coinbaseStr = String.format("%040x", 1); - parseCommand("--miner-enabled", "--miner-coinbase=" + coinbaseStr); - - final ArgumentCaptor miningArg = - ArgumentCaptor.forClass(MiningParameters.class); - - verify(mockControllerBuilder).miningParameters(miningArg.capture()); - verify(mockControllerBuilder).build(); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - assertThat(miningArg.getValue().isMiningEnabled()).isTrue(); - assertThat(miningArg.getValue().getCoinbase()) - .isEqualTo(Optional.of(Address.fromHexString(coinbaseStr))); - } - - @Test - public void stratumMiningIsEnabledWhenSpecified() throws Exception { - final String coinbaseStr = String.format("%040x", 1); - parseCommand("--miner-enabled", "--miner-coinbase=" + coinbaseStr, "--miner-stratum-enabled"); - - final ArgumentCaptor miningArg = - ArgumentCaptor.forClass(MiningParameters.class); - - verify(mockControllerBuilder).miningParameters(miningArg.capture()); - verify(mockControllerBuilder).build(); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - assertThat(miningArg.getValue().isMiningEnabled()).isTrue(); - assertThat(miningArg.getValue().getCoinbase()) - .isEqualTo(Optional.of(Address.fromHexString(coinbaseStr))); - assertThat(miningArg.getValue().isStratumMiningEnabled()).isTrue(); - } - - @Test - public void stratumMiningOptionsRequiresServiceToBeEnabled() { - - parseCommand("--network", "dev", "--miner-stratum-enabled"); - - verifyOptionsConstraintLoggerCall("--miner-enabled", "--miner-stratum-enabled"); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)) - .startsWith( - "Unable to mine with Stratum if mining is disabled. Either disable Stratum mining (remove --miner-stratum-enabled) or specify mining is enabled (--miner-enabled)"); - } - - @Test - public void stratumMiningOptionsRequiresServiceToBeEnabledToml() throws IOException { - final Path toml = createTempFile("toml", "miner-stratum-enabled=true\n"); - - parseCommand("--network", "dev", "--config-file", toml.toString()); - - verifyOptionsConstraintLoggerCall("--miner-enabled", "--miner-stratum-enabled"); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)) - .startsWith( - "Unable to mine with Stratum if mining is disabled. Either disable Stratum mining (remove --miner-stratum-enabled) or specify mining is enabled (--miner-enabled)"); - } - - @Test - public void blockProducingOptionsWarnsMinerShouldBeEnabled() { - - final Address requestedCoinbase = Address.fromHexString("0000011111222223333344444"); - parseCommand( - "--network", - "dev", - "--miner-coinbase", - requestedCoinbase.toString(), - "--min-gas-price", - "42", - "--miner-extra-data", - "0x1122334455667788990011223344556677889900112233445566778899001122"); - - verifyOptionsConstraintLoggerCall( - "--miner-enabled", "--miner-coinbase", "--min-gas-price", "--miner-extra-data"); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void blockProducingOptionsWarnsMinerShouldBeEnabledToml() throws IOException { - - final Address requestedCoinbase = Address.fromHexString("0000011111222223333344444"); - - final Path toml = - createTempFile( - "toml", - "network=\"dev\"\n" - + "miner-coinbase=\"" - + requestedCoinbase - + "\"\n" - + "min-gas-price=42\n" - + "miner-extra-data=\"0x1122334455667788990011223344556677889900112233445566778899001122\"\n"); - - parseCommand("--config-file", toml.toString()); - - verifyOptionsConstraintLoggerCall( - "--miner-enabled", "--miner-coinbase", "--min-gas-price", "--miner-extra-data"); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void blockProducingOptionsDoNotWarnWhenPoA() throws IOException { - - final Path genesisFileQBFT = createFakeGenesisFile(VALID_GENESIS_QBFT_POST_LONDON); - parseCommand( - "--genesis-file", - genesisFileQBFT.toString(), - "--min-gas-price", - "42", - "--miner-extra-data", - "0x1122334455667788990011223344556677889900112233445566778899001122"); - - verify(mockLogger, atMost(0)) - .warn( - stringArgumentCaptor.capture(), - stringArgumentCaptor.capture(), - stringArgumentCaptor.capture()); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - - final Path genesisFileIBFT2 = createFakeGenesisFile(VALID_GENESIS_IBFT2_POST_LONDON); - parseCommand( - "--genesis-file", - genesisFileIBFT2.toString(), - "--min-gas-price", - "42", - "--miner-extra-data", - "0x1122334455667788990011223344556677889900112233445566778899001122"); - - verify(mockLogger, atMost(0)) - .warn( - stringArgumentCaptor.capture(), - stringArgumentCaptor.capture(), - stringArgumentCaptor.capture()); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void blockProducingOptionsDoNotWarnWhenMergeEnabled() { - - final Address requestedCoinbase = Address.fromHexString("0000011111222223333344444"); - // TODO: once we have mainnet TTD, we can remove the TTD override parameter here - // https://github.com/hyperledger/besu/issues/3874 - parseCommand( - "--override-genesis-config", - "terminalTotalDifficulty=1337", - "--miner-coinbase", - requestedCoinbase.toString(), - "--min-gas-price", - "42", - "--miner-extra-data", - "0x1122334455667788990011223344556677889900112233445566778899001122"); - - verify(mockLogger, atMost(0)) - .warn( - stringArgumentCaptor.capture(), - stringArgumentCaptor.capture(), - stringArgumentCaptor.capture()); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void minGasPriceRequiresMainOption() { - parseCommand("--min-gas-price", "0", "--network", "dev"); - - verifyOptionsConstraintLoggerCall("--miner-enabled", "--min-gas-price"); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void minGasPriceRequiresMainOptionToml() throws IOException { - final Path toml = createTempFile("toml", "min-gas-price=0\nnetwork=\"dev\"\n"); - - parseCommand("--config-file", toml.toString()); - - verifyOptionsConstraintLoggerCall("--miner-enabled", "--min-gas-price"); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void minGasPriceDoesNotRequireMainOptionWhenPoA() throws IOException { - final Path genesisFileQBFT = createFakeGenesisFile(VALID_GENESIS_QBFT_POST_LONDON); - parseCommand("--genesis-file", genesisFileQBFT.toString(), "--min-gas-price", "0"); - - verify(mockLogger, atMost(0)) - .warn( - stringArgumentCaptor.capture(), - stringArgumentCaptor.capture(), - stringArgumentCaptor.capture()); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - - final Path genesisFileIBFT2 = createFakeGenesisFile(VALID_GENESIS_IBFT2_POST_LONDON); - parseCommand("--genesis-file", genesisFileIBFT2.toString(), "--min-gas-price", "0"); - - verify(mockLogger, atMost(0)) - .warn( - stringArgumentCaptor.capture(), - stringArgumentCaptor.capture(), - stringArgumentCaptor.capture()); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - - @Test - public void miningParametersAreCaptured() { - final Address requestedCoinbase = Address.fromHexString("0000011111222223333344444"); - final String extraDataString = - "0x1122334455667788990011223344556677889900112233445566778899001122"; - parseCommand( - "--miner-enabled", - "--miner-coinbase=" + requestedCoinbase.toString(), - "--min-gas-price=15", - "--miner-extra-data=" + extraDataString); - - final ArgumentCaptor miningArg = - ArgumentCaptor.forClass(MiningParameters.class); - - verify(mockControllerBuilder).miningParameters(miningArg.capture()); - verify(mockControllerBuilder).build(); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - assertThat(miningArg.getValue().getCoinbase()).isEqualTo(Optional.of(requestedCoinbase)); - assertThat(miningArg.getValue().getMinTransactionGasPrice()).isEqualTo(Wei.of(15)); - assertThat(miningArg.getValue().getExtraData()).isEqualTo(Bytes.fromHexString(extraDataString)); - } - @Test public void colorCanBeEnabledOrDisabledExplicitly() { Stream.of(true, false) @@ -4471,31 +4202,6 @@ public void canNotUseFlexiblePrivacyWhenPrivacyPluginEnabled() { "No Payload Provider has been provided. You must register one when enabling privacy plugin!"); } - private Path createFakeGenesisFile(final JsonObject jsonGenesis) throws IOException { - final Path genesisFile = Files.createTempFile("genesisFile", ""); - Files.write(genesisFile, encodeJsonGenesis(jsonGenesis).getBytes(UTF_8)); - genesisFile.toFile().deleteOnExit(); - return genesisFile; - } - - private Path createTempFile(final String filename, final String contents) throws IOException { - final Path file = Files.createTempFile(filename, ""); - Files.write(file, contents.getBytes(UTF_8)); - file.toFile().deleteOnExit(); - return file; - } - - private Path createTempFile(final String filename, final byte[] contents) throws IOException { - final Path file = Files.createTempFile(filename, ""); - Files.write(file, contents); - file.toFile().deleteOnExit(); - return file; - } - - private String encodeJsonGenesis(final JsonObject jsonGenesis) { - return jsonGenesis.encodePrettily(); - } - private static String escapeTomlString(final String s) { return StringEscapeUtils.escapeJava(s); } @@ -4619,42 +4325,6 @@ public void tomlThatHasInvalidOptions() throws IOException { .contains("Unknown options in TOML configuration file: invalid_option, invalid_option2"); } - @Test - public void targetGasLimitIsEnabledWhenSpecified() { - parseCommand("--target-gas-limit=10000000"); - - @SuppressWarnings("unchecked") - final ArgumentCaptor miningParametersArgumentCaptor = - ArgumentCaptor.forClass(MiningParameters.class); - - verify(mockControllerBuilder).miningParameters(miningParametersArgumentCaptor.capture()); - verify(mockControllerBuilder).build(); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - - assertThat(miningParametersArgumentCaptor.getValue().getTargetGasLimit().get().longValue()) - .isEqualTo(10_000_000L); - } - - @Test - public void targetGasLimitIsDisabledWhenNotSpecified() { - parseCommand(); - - @SuppressWarnings("unchecked") - final ArgumentCaptor gasLimitCalculatorArgumentCaptor = - ArgumentCaptor.forClass(GasLimitCalculator.class); - - verify(mockControllerBuilder).gasLimitCalculator(gasLimitCalculatorArgumentCaptor.capture()); - verify(mockControllerBuilder).build(); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - - assertThat(gasLimitCalculatorArgumentCaptor.getValue()) - .isEqualTo(GasLimitCalculator.constant()); - } - @Test public void requiredBlocksSetWhenSpecified() { final long blockNumber = 8675309L; @@ -5069,11 +4739,7 @@ public void assertThatCheckPortClashRejectsAsExpected() throws Exception { public void assertThatCheckPortClashRejectsAsExpectedForEngineApi() throws Exception { // use WS port for HTTP final int port = 8545; - // TODO: once we have mainnet TTD, we can remove the TTD override parameter here - // https://github.com/hyperledger/besu/issues/3874 parseCommand( - "--override-genesis-config", - "terminalTotalDifficulty=1337", "--rpc-http-enabled", "--rpc-http-port", String.valueOf(port), @@ -5275,37 +4941,6 @@ public void logWarnIfFastSyncMinPeersUsedWithFullSync() { .contains("--fast-sync-min-peers can't be used with FULL sync-mode"); } - @Test - public void posBlockCreationMaxTimeDefaultValue() { - parseCommand(); - assertThat(getPosBlockCreationMaxTimeValue()).isEqualTo(DEFAULT_POS_BLOCK_CREATION_MAX_TIME); - } - - @Test - public void posBlockCreationMaxTimeOption() { - parseCommand("--Xpos-block-creation-max-time", "7000"); - assertThat(getPosBlockCreationMaxTimeValue()).isEqualTo(7000L); - } - - private long getPosBlockCreationMaxTimeValue() { - final ArgumentCaptor miningArg = - ArgumentCaptor.forClass(MiningParameters.class); - - verify(mockControllerBuilder).miningParameters(miningArg.capture()); - verify(mockControllerBuilder).build(); - - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - return miningArg.getValue().getPosBlockCreationMaxTime(); - } - - @Test - public void posBlockCreationMaxTimeOutOfAllowedRange() { - parseCommand("--Xpos-block-creation-max-time", "17000"); - assertThat(commandErrorOutput.toString(UTF_8)) - .contains("--Xpos-block-creation-max-time must be positive and ≤ 12000"); - } - @Test public void portInUseReportsError() throws IOException { final ServerSocket serverSocket = new ServerSocket(8545); 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 1c991d64935..bccf28c4522 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java @@ -31,6 +31,7 @@ import org.hyperledger.besu.chainimport.JsonBlockImporter; import org.hyperledger.besu.chainimport.RlpBlockImporter; import org.hyperledger.besu.cli.config.EthNetworkConfig; +import org.hyperledger.besu.cli.options.MiningOptions; import org.hyperledger.besu.cli.options.stable.EthstatsOptions; import org.hyperledger.besu.cli.options.unstable.EthProtocolOptions; import org.hyperledger.besu.cli.options.unstable.MetricsCLIOptions; @@ -105,6 +106,7 @@ import io.opentelemetry.api.GlobalOpenTelemetry; import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; +import io.vertx.core.json.JsonObject; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.awaitility.Awaitility; @@ -126,6 +128,20 @@ @RunWith(MockitoJUnitRunner.class) public abstract class CommandTestAbstract { private static final Logger TEST_LOGGER = LoggerFactory.getLogger(CommandTestAbstract.class); + protected static final JsonObject VALID_GENESIS_QBFT_POST_LONDON = + (new JsonObject()) + .put( + "config", + new JsonObject() + .put("londonBlock", 0) + .put("qbft", new JsonObject().put("blockperiodseconds", 5))); + protected static final JsonObject VALID_GENESIS_IBFT2_POST_LONDON = + (new JsonObject()) + .put( + "config", + new JsonObject() + .put("londonBlock", 0) + .put("ibft2", new JsonObject().put("blockperiodseconds", 5))); protected final PrintStream originalOut = System.out; protected final PrintStream originalErr = System.err; protected final ByteArrayOutputStream commandOutput = new ByteArrayOutputStream(); @@ -460,6 +476,25 @@ private TestBesuCommand getTestBesuCommand(final TestType testType) { } } + protected Path createTempFile(final String filename, final byte[] contents) throws IOException { + final Path file = Files.createTempFile(filename, ""); + Files.write(file, contents); + file.toFile().deleteOnExit(); + return file; + } + + protected Path createFakeGenesisFile(final JsonObject jsonGenesis) throws IOException { + return createTempFile("genesisFile", encodeJsonGenesis(jsonGenesis).getBytes(UTF_8)); + } + + protected String encodeJsonGenesis(final JsonObject jsonGenesis) { + return jsonGenesis.encodePrettily(); + } + + protected Path createTempFile(final String filename, final String contents) throws IOException { + return createTempFile(filename, contents.getBytes(UTF_8)); + } + @CommandLine.Command public static class TestBesuCommand extends BesuCommand { @@ -530,6 +565,10 @@ public EthProtocolOptions getEthProtocolOptions() { return stableTransactionPoolOptions; } + public MiningOptions getMiningOptions() { + return miningOptions; + } + public TransactionPoolOptions getUnstableTransactionPoolOptions() { return unstableTransactionPoolOptions; } diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/AbstractCLIOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/AbstractCLIOptionsTest.java index ef7da0c7669..09b4e3b1365 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/options/AbstractCLIOptionsTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/AbstractCLIOptionsTest.java @@ -16,6 +16,9 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.cli.util.CommandLineUtils.DEPENDENCY_WARNING_MSG; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.verify; import org.hyperledger.besu.cli.CommandTestAbstract; @@ -113,6 +116,7 @@ protected void internalTestSuccess(final Consumer assertion, final String... assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + verify(mockControllerBuilder).build(); } protected void internalTestFailure(final String errorMsg, final String... args) { @@ -121,4 +125,29 @@ protected void internalTestFailure(final String errorMsg, final String... args) assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)).contains(errorMsg); } + + /** + * Check logger calls + * + *

Here we check the calls to logger and not the result of the log line as we don't test the + * logger itself but the fact that we call it. + * + * @param dependentOptions the string representing the list of dependent options names + * @param mainOption the main option name + */ + protected void verifyOptionsConstraintLoggerCall( + final String mainOption, final String... dependentOptions) { + verify(mockLogger, atLeast(1)) + .warn( + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture()); + assertThat(stringArgumentCaptor.getAllValues().get(0)).isEqualTo(DEPENDENCY_WARNING_MSG); + + for (final String option : dependentOptions) { + assertThat(stringArgumentCaptor.getAllValues().get(1)).contains(option); + } + + assertThat(stringArgumentCaptor.getAllValues().get(2)).isEqualTo(mainOption); + } } diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/MiningOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/MiningOptionsTest.java new file mode 100644 index 00000000000..7d6d3cfe06e --- /dev/null +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/MiningOptionsTest.java @@ -0,0 +1,340 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * 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.cli.options; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.ethereum.core.MiningParameters.Unstable.DEFAULT_POS_BLOCK_CREATION_MAX_TIME; +import static org.mockito.Mockito.atMost; +import static org.mockito.Mockito.verify; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.GasLimitCalculator; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.Unstable; +import org.hyperledger.besu.ethereum.core.MiningParameters; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Optional; + +import org.apache.tuweni.bytes.Bytes; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class MiningOptionsTest extends AbstractCLIOptionsTest { + + @Test + public void besuDoesNotStartInMiningModeIfCoinbaseNotSet() { + internalTestFailure( + "Unable to mine without a valid coinbase. Either disable mining (remove --miner-enabled) or specify the beneficiary of mining (via --miner-coinbase

)", + "--miner-enabled"); + } + + @Test + public void miningIsEnabledWhenSpecified() { + final String coinbaseStr = String.format("%040x", 1); + internalTestSuccess( + miningOpts -> { + assertThat(miningOpts.isMiningEnabled()).isTrue(); + assertThat(miningOpts.getCoinbase()) + .isEqualTo(Optional.of(Address.fromHexString(coinbaseStr))); + }, + "--miner-enabled", + "--miner-coinbase=" + coinbaseStr); + } + + @Test + public void stratumMiningIsEnabledWhenSpecified() { + final String coinbaseStr = String.format("%040x", 1); + internalTestSuccess( + miningOpts -> { + assertThat(miningOpts.isMiningEnabled()).isTrue(); + assertThat(miningOpts.getCoinbase()) + .isEqualTo(Optional.of(Address.fromHexString(coinbaseStr))); + assertThat(miningOpts.isStratumMiningEnabled()).isTrue(); + }, + "--miner-enabled", + "--miner-coinbase=" + coinbaseStr, + "--miner-stratum-enabled"); + } + + @Test + public void stratumMiningOptionsRequiresServiceToBeEnabled() { + internalTestFailure( + "Unable to mine with Stratum if mining is disabled. Either disable Stratum mining (remove --miner-stratum-enabled) or specify mining is enabled (--miner-enabled)", + "--network", + "dev", + "--miner-stratum-enabled"); + } + + @Test + public void stratumMiningOptionsRequiresServiceToBeEnabledToml() throws IOException { + final Path toml = createTempFile("toml", "miner-stratum-enabled=true\n"); + internalTestFailure( + "Unable to mine with Stratum if mining is disabled. Either disable Stratum mining (remove --miner-stratum-enabled) or specify mining is enabled (--miner-enabled)", + "--network", + "dev", + "--config-file", + toml.toString()); + } + + @Test + public void blockProducingOptionsWarnsMinerShouldBeEnabled() { + final Address requestedCoinbase = Address.fromHexString("0000011111222223333344444"); + internalTestSuccess( + miningOpts -> + verifyOptionsConstraintLoggerCall( + "--miner-enabled", "--miner-coinbase", "--min-gas-price", "--miner-extra-data"), + "--network", + "dev", + "--miner-coinbase", + requestedCoinbase.toString(), + "--min-gas-price", + "42", + "--miner-extra-data", + "0x1122334455667788990011223344556677889900112233445566778899001122"); + } + + @Test + public void blockProducingOptionsWarnsMinerShouldBeEnabledToml() throws IOException { + + final Address requestedCoinbase = Address.fromHexString("0000011111222223333344444"); + + final Path toml = + createTempFile( + "toml", + "network=\"dev\"\n" + + "miner-coinbase=\"" + + requestedCoinbase + + "\"\n" + + "min-gas-price=42\n" + + "miner-extra-data=\"0x1122334455667788990011223344556677889900112233445566778899001122\"\n"); + + internalTestSuccess( + miningOpts -> + verifyOptionsConstraintLoggerCall( + "--miner-enabled", "--miner-coinbase", "--min-gas-price", "--miner-extra-data"), + "--config-file", + toml.toString()); + } + + @Test + public void blockProducingOptionsDoNotWarnWhenPoAQBFT() throws IOException { + + final Path genesisFileQBFT = createFakeGenesisFile(VALID_GENESIS_QBFT_POST_LONDON); + internalTestSuccess( + miningOpts -> + verify(mockLogger, atMost(0)) + .warn( + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture()), + "--genesis-file", + genesisFileQBFT.toString(), + "--min-gas-price", + "42", + "--miner-extra-data", + "0x1122334455667788990011223344556677889900112233445566778899001122"); + } + + @Test + public void blockProducingOptionsDoNotWarnWhenPoAIBFT2() throws IOException { + + final Path genesisFileIBFT2 = createFakeGenesisFile(VALID_GENESIS_IBFT2_POST_LONDON); + internalTestSuccess( + miningOpts -> + verify(mockLogger, atMost(0)) + .warn( + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture()), + "--genesis-file", + genesisFileIBFT2.toString(), + "--min-gas-price", + "42", + "--miner-extra-data", + "0x1122334455667788990011223344556677889900112233445566778899001122"); + } + + @Test + public void blockProducingOptionsDoNotWarnWhenMergeEnabled() { + + final Address requestedCoinbase = Address.fromHexString("0000011111222223333344444"); + internalTestSuccess( + miningOpt -> + verify(mockLogger, atMost(0)) + .warn( + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture()), + "--miner-coinbase", + requestedCoinbase.toString(), + "--min-gas-price", + "42", + "--miner-extra-data", + "0x1122334455667788990011223344556677889900112233445566778899001122"); + } + + @Test + public void minGasPriceRequiresMainOption() { + internalTestSuccess( + miningOpt -> verifyOptionsConstraintLoggerCall("--miner-enabled", "--min-gas-price"), + "--min-gas-price", + "0", + "--network", + "dev"); + } + + @Test + public void minGasPriceRequiresMainOptionToml() throws IOException { + final Path toml = createTempFile("toml", "min-gas-price=0\nnetwork=\"dev\"\n"); + internalTestSuccess( + miningOpt -> verifyOptionsConstraintLoggerCall("--miner-enabled", "--min-gas-price"), + "--config-file", + toml.toString()); + } + + @Test + public void minGasPriceDoesNotRequireMainOptionWhenPoAQBFT() throws IOException { + final Path genesisFileQBFT = createFakeGenesisFile(VALID_GENESIS_QBFT_POST_LONDON); + internalTestSuccess( + miningOpt -> + verify(mockLogger, atMost(0)) + .warn( + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture()), + "--genesis-file", + genesisFileQBFT.toString(), + "--min-gas-price", + "0"); + } + + @Test + public void minGasPriceDoesNotRequireMainOptionWhenPoAIBFT2() throws IOException { + final Path genesisFileIBFT2 = createFakeGenesisFile(VALID_GENESIS_IBFT2_POST_LONDON); + + internalTestSuccess( + miningOpt -> + verify(mockLogger, atMost(0)) + .warn( + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture(), + stringArgumentCaptor.capture()), + "--genesis-file", + genesisFileIBFT2.toString(), + "--min-gas-price", + "0"); + } + + @Test + public void miningParametersAreCaptured() { + final Address requestedCoinbase = Address.fromHexString("0000011111222223333344444"); + final String extraDataString = + "0x1122334455667788990011223344556677889900112233445566778899001122"; + internalTestSuccess( + miningParams -> { + assertThat(miningParams.getCoinbase()).isEqualTo(Optional.of(requestedCoinbase)); + assertThat(miningParams.getMinTransactionGasPrice()).isEqualTo(Wei.of(15)); + assertThat(miningParams.getExtraData()).isEqualTo(Bytes.fromHexString(extraDataString)); + }, + "--miner-enabled", + "--miner-coinbase=" + requestedCoinbase.toString(), + "--min-gas-price=15", + "--miner-extra-data=" + extraDataString); + } + + @Test + public void targetGasLimitIsEnabledWhenSpecified() { + internalTestSuccess( + miningParams -> + assertThat(miningParams.getTargetGasLimit().getAsLong()).isEqualTo(10_000_000L), + "--target-gas-limit=10000000"); + } + + @Test + public void targetGasLimitIsDisabledWhenNotSpecified() { + internalTestSuccess( + miningParams -> { + final ArgumentCaptor gasLimitCalculatorArgumentCaptor = + ArgumentCaptor.forClass(GasLimitCalculator.class); + + verify(mockControllerBuilder) + .gasLimitCalculator(gasLimitCalculatorArgumentCaptor.capture()); + assertThat(gasLimitCalculatorArgumentCaptor.getValue()) + .isEqualTo(GasLimitCalculator.constant()); + }); + } + + @Test + public void posBlockCreationMaxTimeDefaultValue() { + internalTestSuccess( + miningParams -> + assertThat(miningParams.getUnstable().getPosBlockCreationMaxTime()) + .isEqualTo(DEFAULT_POS_BLOCK_CREATION_MAX_TIME)); + } + + @Test + public void posBlockCreationMaxTimeOption() { + internalTestSuccess( + miningParams -> + assertThat(miningParams.getUnstable().getPosBlockCreationMaxTime()).isEqualTo(7000L), + "--Xpos-block-creation-max-time", + "7000"); + } + + @Test + public void posBlockCreationMaxTimeOutOfAllowedRange() { + internalTestFailure( + "--Xpos-block-creation-max-time must be positive and ≤ 12000", + "--Xpos-block-creation-max-time", + "17000"); + } + + @Override + protected MiningParameters createDefaultDomainObject() { + return MiningParameters.newDefault(); + } + + @Override + protected MiningParameters createCustomizedDomainObject() { + return ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .isMiningEnabled(true) + .extraData(Bytes.fromHexString("0xabc321")) + .minBlockOccupancyRatio(0.5) + .coinbase(Address.ZERO) + .build()) + .isStratumMiningEnabled(true) + .unstable(Unstable.builder().posBlockCreationMaxTime(1000).build()) + .build(); + } + + @Override + protected MiningOptions optionsFromDomainObject(final MiningParameters domainObject) { + return MiningOptions.fromConfig(domainObject); + } + + @Override + protected MiningOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) { + return besuCommand.getMiningOptions(); + } +} diff --git a/besu/src/test/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommandTest.java index 6a0b5592d27..5c62076e692 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommandTest.java @@ -174,7 +174,8 @@ public void callingBlockImportSubCommandWithJSONAndSkipPOWFails() { @Test public void callingBlockImportSubCommandHelpMustDisplayUsage() { parseCommand(BLOCK_SUBCOMMAND_NAME, BLOCK_IMPORT_SUBCOMMAND_NAME, "--help"); - assertThat(commandOutput.toString(UTF_8)).isEqualTo(EXPECTED_BLOCK_IMPORT_USAGE); + assertThat(commandOutput.toString(UTF_8)) + .isEqualToNormalizingNewlines(EXPECTED_BLOCK_IMPORT_USAGE); assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); } diff --git a/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java index c7c6466e602..a24479e8617 100644 --- a/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/controller/BesuControllerBuilderTest.java @@ -84,7 +84,6 @@ public class BesuControllerBuilderTest { @Mock CheckpointConfigOptions checkpointConfigOptions; @Mock SynchronizerConfiguration synchronizerConfiguration; @Mock EthProtocolConfiguration ethProtocolConfiguration; - @Mock MiningParameters miningParameters; @Mock PrivacyParameters privacyParameters; @Mock Clock clock; @Mock StorageProvider storageProvider; @@ -95,6 +94,8 @@ public class BesuControllerBuilderTest { @Mock WorldStatePreimageStorage worldStatePreimageStorage; private final TransactionPoolConfiguration poolConfiguration = TransactionPoolConfiguration.DEFAULT; + private final MiningParameters miningParameters = MiningParameters.newDefault(); + private final ObservableMetricsSystem observableMetricsSystem = new NoOpMetricsSystem(); BigInteger networkId = BigInteger.ONE; diff --git a/besu/src/test/java/org/hyperledger/besu/controller/MergeBesuControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/MergeBesuControllerBuilderTest.java index b1f59554af3..33a539f8bc2 100644 --- a/besu/src/test/java/org/hyperledger/besu/controller/MergeBesuControllerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/controller/MergeBesuControllerBuilderTest.java @@ -75,6 +75,7 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; +import org.mockito.Answers; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @@ -89,7 +90,10 @@ public class MergeBesuControllerBuilderTest { @Mock SynchronizerConfiguration synchronizerConfiguration; @Mock EthProtocolConfiguration ethProtocolConfiguration; @Mock CheckpointConfigOptions checkpointConfigOptions; - @Mock MiningParameters miningParameters; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + MiningParameters miningParameters; + @Mock PrivacyParameters privacyParameters; @Mock Clock clock; @Mock StorageProvider storageProvider; @@ -143,6 +147,7 @@ public void setup() { when(worldStatePreimageStorage.updater()) .thenReturn(mock(WorldStatePreimageStorage.Updater.class)); when(worldStateStorage.updater()).thenReturn(mock(WorldStateStorage.Updater.class)); + when(miningParameters.getTargetGasLimit()).thenReturn(OptionalLong.empty()); besuControllerBuilder = visitWithMockConfigs(new MergeBesuControllerBuilder()); } diff --git a/besu/src/test/java/org/hyperledger/besu/controller/TransitionControllerBuilderTest.java b/besu/src/test/java/org/hyperledger/besu/controller/TransitionControllerBuilderTest.java index 9fc337095f2..0b1a98a210f 100644 --- a/besu/src/test/java/org/hyperledger/besu/controller/TransitionControllerBuilderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/controller/TransitionControllerBuilderTest.java @@ -34,6 +34,8 @@ import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; @@ -99,7 +101,7 @@ public void setup() { .thenReturn(mock(CliqueContext.class)); when(protocolContext.getConsensusContext(PostMergeContext.class)).thenReturn(mergeContext); when(protocolContext.getConsensusContext(MergeContext.class)).thenReturn(mergeContext); - miningParameters = new MiningParameters.Builder().miningEnabled(false).build(); + miningParameters = MiningParameters.newDefault(); } @Test @@ -118,7 +120,10 @@ public void assertPoWIsNotMiningPreMerge() { @Test public void assertPowMiningPreMerge() { - miningParameters = new MiningParameters.Builder().miningEnabled(true).build(); + miningParameters = + ImmutableMiningParameters.builder() + .mutableInitValues(MutableInitValues.builder().isMiningEnabled(true).build()) + .build(); var transCoordinator = buildTransitionCoordinator(powBuilder, postMergeBuilder); assertThat(transCoordinator.isMiningBeforeMerge()).isTrue(); } diff --git a/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java index 8b6b10f5493..921d4e7fbe6 100644 --- a/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java +++ b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java @@ -33,7 +33,8 @@ import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Difficulty; -import org.hyperledger.besu.ethereum.core.MiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; @@ -155,7 +156,10 @@ public void setUp() { TestClock.system(ZoneId.systemDefault()), new NoOpMetricsSystem(), syncState, - new MiningParameters.Builder().minTransactionGasPrice(Wei.ZERO).build(), + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder().minTransactionGasPrice(Wei.ZERO).build()) + .build(), txPoolConfig, null); diff --git a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreator.java b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreator.java index 30bf9b6476d..d991fb9db4c 100644 --- a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreator.java +++ b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreator.java @@ -23,14 +23,13 @@ import org.hyperledger.besu.consensus.common.EpochManager; import org.hyperledger.besu.consensus.common.validator.ValidatorVote; import org.hyperledger.besu.cryptoservices.NodeKey; -import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.blockcreation.AbstractBlockCreator; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.SealableBlockHeader; import org.hyperledger.besu.ethereum.core.Util; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; @@ -38,7 +37,6 @@ import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions; import java.util.Optional; -import java.util.function.Supplier; /** The Clique block creator. */ public class CliqueBlockCreator extends AbstractBlockCreator { @@ -49,40 +47,31 @@ public class CliqueBlockCreator extends AbstractBlockCreator { /** * Instantiates a new Clique block creator. * - * @param coinbase the coinbase - * @param targetGasLimitSupplier the target gas limit supplier + * @param miningParameters the mining parameters * @param extraDataCalculator the extra data calculator * @param transactionPool the pending transactions * @param protocolContext the protocol context * @param protocolSchedule the protocol schedule * @param nodeKey the node key - * @param minTransactionGasPrice the min transaction gas price - * @param minBlockOccupancyRatio the min block occupancy ratio * @param parentHeader the parent header * @param epochManager the epoch manager */ public CliqueBlockCreator( - final Address coinbase, - final Supplier> targetGasLimitSupplier, + final MiningParameters miningParameters, final ExtraDataCalculator extraDataCalculator, final TransactionPool transactionPool, final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, final NodeKey nodeKey, - final Wei minTransactionGasPrice, - final Double minBlockOccupancyRatio, final BlockHeader parentHeader, final EpochManager epochManager) { super( - coinbase, + miningParameters, __ -> Util.publicKeyToAddress(nodeKey.getPublicKey()), - targetGasLimitSupplier, extraDataCalculator, transactionPool, protocolContext, protocolSchedule, - minTransactionGasPrice, - minBlockOccupancyRatio, parentHeader, Optional.empty()); this.nodeKey = nodeKey; diff --git a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java index 9f2be2e1e76..81b754b267c 100644 --- a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java +++ b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java @@ -35,7 +35,6 @@ import java.util.Collection; import java.util.List; import java.util.Optional; -import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; import com.google.common.annotations.VisibleForTesting; @@ -72,6 +71,7 @@ public CliqueMinerExecutor( this.nodeKey = nodeKey; this.localAddress = Util.publicKeyToAddress(nodeKey.getPublicKey()); this.epochManager = epochManager; + miningParams.setCoinbase(localAddress); } @Override @@ -82,15 +82,12 @@ public CliqueBlockMiner createMiner( final Function blockCreator = (header) -> new CliqueBlockCreator( - localAddress, // TOOD(tmm): This can be removed (used for voting not coinbase). - () -> targetGasLimit.map(AtomicLong::longValue), + miningParameters, this::calculateExtraData, transactionPool, protocolContext, protocolSchedule, nodeKey, - minTransactionGasPrice, - minBlockOccupancyRatio, header, epochManager); @@ -106,7 +103,7 @@ public CliqueBlockMiner createMiner( @Override public Optional
getCoinbase() { - return Optional.of(localAddress); + return miningParameters.getCoinbase(); } /** @@ -120,7 +117,8 @@ Bytes calculateExtraData(final BlockHeader parentHeader) { final List
validators = Lists.newArrayList(); final Bytes vanityDataToInsert = - ConsensusHelpers.zeroLeftPad(extraData, CliqueExtraData.EXTRA_VANITY_LENGTH); + ConsensusHelpers.zeroLeftPad( + miningParameters.getExtraData(), CliqueExtraData.EXTRA_VANITY_LENGTH); // Building ON TOP of canonical head, if the next block is epoch, include validators. if (epochManager.isEpochBlock(parentHeader.getNumber() + 1)) { 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 0b0210d4ef3..3ddfdb1149d 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 @@ -47,6 +47,8 @@ import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.Util; import org.hyperledger.besu.ethereum.eth.manager.EthContext; @@ -134,17 +136,17 @@ public void proposerAddressCanBeExtractFromAConstructedBlock() { CliqueExtraData.createWithoutProposerSeal(Bytes.wrap(new byte[32]), validatorList); final Address coinbase = AddressHelpers.ofValue(1); + + final MiningParameters miningParameters = createMiningParameters(extraData, coinbase); + final CliqueBlockCreator blockCreator = new CliqueBlockCreator( - coinbase, - () -> Optional.of(10_000_000L), + miningParameters, parent -> extraData, createTransactionPool(), protocolContext, protocolSchedule, proposerNodeKey, - Wei.ZERO, - 0.8, blockchain.getChainHeadHeader(), epochManager); @@ -163,17 +165,16 @@ public void insertsValidVoteIntoConstructedBlock() { when(voteProvider.getVoteAfterBlock(any(), any())) .thenReturn(Optional.of(new ValidatorVote(VoteType.ADD, coinbase, a1))); + final MiningParameters miningParameters = createMiningParameters(extraData, coinbase); + final CliqueBlockCreator blockCreator = new CliqueBlockCreator( - coinbase, - () -> Optional.of(10_000_000L), + miningParameters, parent -> extraData, createTransactionPool(), protocolContext, protocolSchedule, proposerNodeKey, - Wei.ZERO, - 0.8, blockchain.getChainHeadHeader(), epochManager); @@ -197,17 +198,16 @@ public void insertsNoVoteWhenAtEpoch() { when(mockVoteProvider.getVoteAfterBlock(any(), any())) .thenReturn(Optional.of(new ValidatorVote(VoteType.ADD, coinbase, a1))); + final MiningParameters miningParameters = createMiningParameters(extraData, coinbase); + final CliqueBlockCreator blockCreator = new CliqueBlockCreator( - coinbase, - () -> Optional.of(10_000_000L), + miningParameters, parent -> extraData, createTransactionPool(), protocolContext, protocolSchedule, proposerNodeKey, - Wei.ZERO, - 0.8, blockchain.getChainHeadHeader(), epochManager); @@ -240,4 +240,19 @@ private TransactionPool createTransactionPool() { transactionPool.setEnabled(); return transactionPool; } + + private static MiningParameters createMiningParameters( + final Bytes extraData, final Address coinbase) { + final MiningParameters miningParameters = + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .extraData(extraData) + .targetGasLimit(10_000_000L) + .minTransactionGasPrice(Wei.ZERO) + .coinbase(coinbase) + .build()) + .build(); + return miningParameters; + } } 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 4a3bf5424d7..7a089f2ef37 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 @@ -37,6 +37,8 @@ import org.hyperledger.besu.ethereum.core.AddressHelpers; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.Util; import org.hyperledger.besu.ethereum.eth.manager.EthContext; @@ -101,18 +103,15 @@ public void setup() { public void extraDataCreatedOnEpochBlocksContainsValidators() { final Bytes vanityData = generateRandomVanityData(); + final MiningParameters miningParameters = createMiningParameters(vanityData); + final CliqueMinerExecutor executor = new CliqueMinerExecutor( cliqueProtocolContext, cliqueProtocolSchedule, createTransactionPool(), proposerNodeKey, - new MiningParameters.Builder() - .coinbase(AddressHelpers.ofValue(1)) - .minTransactionGasPrice(Wei.ZERO) - .extraData(vanityData) - .miningEnabled(false) - .build(), + miningParameters, mock(CliqueBlockScheduler.class), new EpochManager(EPOCH_LENGTH)); @@ -138,18 +137,15 @@ public void extraDataCreatedOnEpochBlocksContainsValidators() { public void extraDataForNonEpochBlocksDoesNotContainValidaors() { final Bytes vanityData = generateRandomVanityData(); + final MiningParameters miningParameters = createMiningParameters(vanityData); + final CliqueMinerExecutor executor = new CliqueMinerExecutor( cliqueProtocolContext, cliqueProtocolSchedule, createTransactionPool(), proposerNodeKey, - new MiningParameters.Builder() - .coinbase(AddressHelpers.ofValue(1)) - .minTransactionGasPrice(Wei.ZERO) - .extraData(vanityData) - .miningEnabled(false) - .build(), + miningParameters, mock(CliqueBlockScheduler.class), new EpochManager(EPOCH_LENGTH)); @@ -175,18 +171,15 @@ public void shouldUseLatestVanityData() { final Bytes initialVanityData = generateRandomVanityData(); final Bytes modifiedVanityData = generateRandomVanityData(); + final MiningParameters miningParameters = createMiningParameters(initialVanityData); + final CliqueMinerExecutor executor = new CliqueMinerExecutor( cliqueProtocolContext, cliqueProtocolSchedule, createTransactionPool(), proposerNodeKey, - new MiningParameters.Builder() - .coinbase(AddressHelpers.ofValue(1)) - .minTransactionGasPrice(Wei.ZERO) - .extraData(initialVanityData) - .miningEnabled(false) - .build(), + miningParameters, mock(CliqueBlockScheduler.class), new EpochManager(EPOCH_LENGTH)); @@ -240,4 +233,15 @@ private Bytes generateRandomVanityData() { random.nextBytes(vanityData); return Bytes.wrap(vanityData); } + + private static MiningParameters createMiningParameters(final Bytes vanityData) { + return ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .extraData(vanityData) + .minTransactionGasPrice(Wei.ZERO) + .coinbase(AddressHelpers.ofValue(1)) + .build()) + .build(); + } } diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreator.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreator.java index 4e5a39f335f..4c5e773966f 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreator.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreator.java @@ -20,17 +20,16 @@ import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec; import org.hyperledger.besu.consensus.common.bft.BftHelpers; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.blockcreation.AbstractBlockCreator; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.SealableBlockHeader; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import java.util.Optional; -import java.util.function.Supplier; /** The Bft block creator. */ // This class is responsible for creating a block without committer seals (basically it was just @@ -42,40 +41,33 @@ public class BftBlockCreator extends AbstractBlockCreator { /** * Instantiates a new Bft block creator. * + * @param miningParameters the mining parameters * @param forksSchedule the forks schedule * @param localAddress the local address - * @param targetGasLimitSupplier the target gas limit supplier * @param extraDataCalculator the extra data calculator * @param transactionPool the pending transactions * @param protocolContext the protocol context * @param protocolSchedule the protocol schedule - * @param minTransactionGasPrice the min transaction gas price - * @param minBlockOccupancyRatio the min block occupancy ratio * @param parentHeader the parent header * @param bftExtraDataCodec the bft extra data codec */ public BftBlockCreator( + final MiningParameters miningParameters, final ForksSchedule forksSchedule, final Address localAddress, - final Supplier> targetGasLimitSupplier, final ExtraDataCalculator extraDataCalculator, final TransactionPool transactionPool, final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, - final Wei minTransactionGasPrice, - final Double minBlockOccupancyRatio, final BlockHeader parentHeader, final BftExtraDataCodec bftExtraDataCodec) { super( - localAddress, + miningParameters.setCoinbase(localAddress), miningBeneficiaryCalculator(localAddress, forksSchedule), - targetGasLimitSupplier, extraDataCalculator, transactionPool, protocolContext, protocolSchedule, - minTransactionGasPrice, - minBlockOccupancyRatio, parentHeader, Optional.empty()); this.bftExtraDataCodec = bftExtraDataCodec; diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java index 35c6a33c94e..fab04b1a770 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java @@ -40,7 +40,6 @@ import java.util.Collections; import java.util.List; import java.util.Optional; -import java.util.concurrent.atomic.AtomicLong; import org.apache.tuweni.bytes.Bytes; @@ -52,6 +51,8 @@ public class BftBlockCreatorFactory { /** The Forks schedule. */ protected final ForksSchedule forksSchedule; + /** The Mining parameters */ + protected final MiningParameters miningParameters; private final TransactionPool transactionPool; /** The Protocol context. */ @@ -63,13 +64,6 @@ public class BftBlockCreatorFactory { private final Address localAddress; - /** The Vanity data. */ - protected volatile Bytes vanityData; - - private volatile Wei minTransactionGasPrice; - private volatile Double minBlockOccupancyRatio; - private volatile Optional targetGasLimit; - /** * Instantiates a new Bft block creator factory. * @@ -94,11 +88,8 @@ public BftBlockCreatorFactory( this.protocolSchedule = protocolSchedule; this.forksSchedule = forksSchedule; this.localAddress = localAddress; - this.minTransactionGasPrice = miningParams.getMinTransactionGasPrice(); - this.minBlockOccupancyRatio = miningParams.getMinBlockOccupancyRatio(); - this.vanityData = miningParams.getExtraData(); + this.miningParameters = miningParams; this.bftExtraDataCodec = bftExtraDataCodec; - this.targetGasLimit = miningParams.getTargetGasLimit(); } /** @@ -110,15 +101,13 @@ public BftBlockCreatorFactory( */ public BlockCreator create(final BlockHeader parentHeader, final int round) { return new BftBlockCreator( + miningParameters, forksSchedule, localAddress, - () -> targetGasLimit.map(AtomicLong::longValue), ph -> createExtraData(round, ph), transactionPool, protocolContext, protocolSchedule, - minTransactionGasPrice, - minBlockOccupancyRatio, parentHeader, bftExtraDataCodec); } @@ -129,7 +118,8 @@ public BlockCreator create(final BlockHeader parentHeader, final int round) { * @param extraData the extra data */ public void setExtraData(final Bytes extraData) { - this.vanityData = extraData.copy(); + + miningParameters.setExtraData(extraData.copy()); } /** @@ -138,7 +128,7 @@ public void setExtraData(final Bytes extraData) { * @param minTransactionGasPrice the min transaction gas price */ public void setMinTransactionGasPrice(final Wei minTransactionGasPrice) { - this.minTransactionGasPrice = minTransactionGasPrice; + miningParameters.setMinTransactionGasPrice(minTransactionGasPrice); } /** @@ -147,7 +137,7 @@ public void setMinTransactionGasPrice(final Wei minTransactionGasPrice) { * @return the min transaction gas price */ public Wei getMinTransactionGasPrice() { - return minTransactionGasPrice; + return miningParameters.getMinTransactionGasPrice(); } /** @@ -171,7 +161,8 @@ public Bytes createExtraData(final int round, final BlockHeader parentHeader) { final BftExtraData extraData = new BftExtraData( - ConsensusHelpers.zeroLeftPad(vanityData, BftExtraDataCodec.EXTRA_VANITY_LENGTH), + ConsensusHelpers.zeroLeftPad( + miningParameters.getExtraData(), BftExtraDataCodec.EXTRA_VANITY_LENGTH), Collections.emptyList(), toVote(proposal), round, @@ -187,9 +178,7 @@ public Bytes createExtraData(final int round, final BlockHeader parentHeader) { */ public void changeTargetGasLimit(final Long newTargetGasLimit) { if (AbstractGasLimitSpecification.isValidTargetGasLimit(newTargetGasLimit)) { - this.targetGasLimit.ifPresentOrElse( - existing -> existing.set(newTargetGasLimit), - () -> this.targetGasLimit = Optional.of(new AtomicLong(newTargetGasLimit))); + miningParameters.setTargetGasLimit(newTargetGasLimit); } else { throw new UnsupportedOperationException("Specified target gas limit is invalid"); } 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 42d68250821..9b0d9f65ad9 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 @@ -77,6 +77,8 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.Util; import org.hyperledger.besu.ethereum.eth.manager.EthContext; @@ -304,11 +306,14 @@ private static ControllerAndState createControllerAndFinalState( final WorldStateArchive worldStateArchive = createInMemoryWorldStateArchive(); final MiningParameters miningParams = - new MiningParameters.Builder() - .coinbase(AddressHelpers.ofValue(1)) - .minTransactionGasPrice(Wei.ZERO) - .extraData(Bytes.wrap("Ibft Int tests".getBytes(UTF_8))) - .miningEnabled(true) + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .isMiningEnabled(true) + .minTransactionGasPrice(Wei.ZERO) + .extraData(Bytes.wrap("Ibft Int tests".getBytes(UTF_8))) + .coinbase(AddressHelpers.ofValue(1)) + .build()) .build(); final StubGenesisConfigOptions genesisConfigOptions = new StubGenesisConfigOptions(); 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 1039b3579c1..6065c269be7 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 @@ -41,6 +41,8 @@ import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.eth.manager.EthContext; @@ -150,11 +152,28 @@ public BlockHeaderValidator.Builder createBlockHeaderRuleset( transactionPool.setEnabled(); + final MiningParameters miningParameters = + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .extraData( + bftExtraDataEncoder.encode( + new BftExtraData( + Bytes.wrap(new byte[32]), + Collections.emptyList(), + Optional.empty(), + 0, + initialValidatorList))) + .minTransactionGasPrice(Wei.ZERO) + .coinbase(AddressHelpers.ofValue(1)) + .build()) + .build(); + final BftBlockCreator blockCreator = new BftBlockCreator( + miningParameters, forksSchedule, initialValidatorList.get(0), - () -> Optional.of(10_000_000L), parent -> bftExtraDataEncoder.encode( new BftExtraData( @@ -166,8 +185,6 @@ public BlockHeaderValidator.Builder createBlockHeaderRuleset( transactionPool, protContext, protocolSchedule, - Wei.ZERO, - 0.8, parentHeader, bftExtraDataEncoder); diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeBlockCreator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeBlockCreator.java index dd8adae7e9b..b81a941816a 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeBlockCreator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeBlockCreator.java @@ -15,12 +15,12 @@ package org.hyperledger.besu.consensus.merge.blockcreation; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.blockcreation.AbstractBlockCreator; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.SealableBlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Withdrawal; @@ -30,55 +30,37 @@ import java.util.Collections; import java.util.List; import java.util.Optional; -import java.util.function.Supplier; import org.apache.tuweni.bytes.Bytes32; /** The Merge block creator. */ class MergeBlockCreator extends AbstractBlockCreator { - /** - * On PoS you do not need to compete with other nodes for block production, since you have an - * allocated slot for that, so in this case make sense to always try to fill the block, if there - * are enough pending transactions, until the remaining gas is less than the minimum needed for - * the smaller transaction. So for PoS the min-block-occupancy-ratio option is set to always try - * to fill 100% of the block. - */ - private static final double TRY_FILL_BLOCK = 1.0; /** * Instantiates a new Merge block creator. * - * @param coinbase the coinbase - * @param targetGasLimitSupplier the target gas limit supplier + * @param miningParameters the mining parameters * @param extraDataCalculator the extra data calculator * @param transactionPool the pending transactions * @param protocolContext the protocol context * @param protocolSchedule the protocol schedule - * @param minTransactionGasPrice the min transaction gas price - * @param miningBeneficiary the mining beneficiary * @param parentHeader the parent header */ public MergeBlockCreator( - final Address coinbase, - final Supplier> targetGasLimitSupplier, + final MiningParameters miningParameters, final ExtraDataCalculator extraDataCalculator, final TransactionPool transactionPool, final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, - final Wei minTransactionGasPrice, - final Address miningBeneficiary, final BlockHeader parentHeader, final Optional
depositContractAddress) { super( - miningBeneficiary, - __ -> miningBeneficiary, - targetGasLimitSupplier, + miningParameters, + __ -> miningParameters.getCoinbase().orElseThrow(), extraDataCalculator, transactionPool, protocolContext, protocolSchedule, - minTransactionGasPrice, - TRY_FILL_BLOCK, parentHeader, depositContractAddress); } diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java index ffd57c4b27e..9a5d26f1c63 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java @@ -56,8 +56,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; import com.google.common.annotations.VisibleForTesting; @@ -69,18 +67,20 @@ /** The Merge coordinator. */ public class MergeCoordinator implements MergeMiningCoordinator, BadChainListener { private static final Logger LOG = LoggerFactory.getLogger(MergeCoordinator.class); + /** + * On PoS you do not need to compete with other nodes for block production, since you have an + * allocated slot for that, so in this case make sense to always try to fill the block, if there + * are enough pending transactions, until the remaining gas is less than the minimum needed for + * the smaller transaction. So for PoS the min-block-occupancy-ratio option is set to always try + * to fill 100% of the block. + */ + private static final double TRY_FILL_BLOCK = 1.0; - /** The Target gas limit. */ - protected final AtomicLong targetGasLimit; + private static final long DEFAULT_TARGET_GAS_LIMIT = 30000000L; /** The Mining parameters. */ protected final MiningParameters miningParameters; /** The Merge block creator factory. */ protected final MergeBlockCreatorFactory mergeBlockCreatorFactory; - /** The Extra data. */ - protected final AtomicReference extraData = - new AtomicReference<>(Bytes.fromHexString("0x")); - /** The Latest descends from terminal. */ - protected final AtomicReference latestDescendsFromTerminal = new AtomicReference<>(); /** The Merge context. */ protected final MergeContext mergeContext; /** The Protocol context. */ @@ -118,28 +118,30 @@ public MergeCoordinator( this.protocolSchedule = protocolSchedule; this.blockBuilderExecutor = blockBuilderExecutor; this.mergeContext = protocolContext.getConsensusContext(MergeContext.class); - this.miningParameters = miningParams; this.backwardSyncContext = backwardSyncContext; - this.targetGasLimit = - miningParameters - .getTargetGasLimit() - // TODO: revisit default target gas limit - .orElse(new AtomicLong(30000000L)); - this.extraData.set(miningParams.getExtraData()); + + if (miningParams.getCoinbase().isEmpty()) { + miningParams.setCoinbase(Address.ZERO); + } + if (miningParams.getTargetGasLimit().isEmpty()) { + miningParams.setTargetGasLimit(DEFAULT_TARGET_GAS_LIMIT); + } + miningParams.setMinBlockOccupancyRatio(TRY_FILL_BLOCK); + + this.miningParameters = miningParams; this.mergeBlockCreatorFactory = - (parentHeader, address) -> - new MergeBlockCreator( - address.or(miningParameters::getCoinbase).orElse(Address.ZERO), - () -> Optional.of(targetGasLimit.longValue()), - parent -> extraData.get(), - transactionPool, - protocolContext, - protocolSchedule, - this.miningParameters.getMinTransactionGasPrice(), - address.or(miningParameters::getCoinbase).orElse(Address.ZERO), - parentHeader, - depositContractAddress); + (parentHeader, address) -> { + address.ifPresent(miningParams::setCoinbase); + return new MergeBlockCreator( + miningParameters, + parent -> miningParameters.getExtraData(), + transactionPool, + protocolContext, + protocolSchedule, + parentHeader, + depositContractAddress); + }; this.backwardSyncContext.subscribeBadChainListener(this); } @@ -166,13 +168,12 @@ public MergeCoordinator( this.protocolSchedule = protocolSchedule; this.blockBuilderExecutor = blockBuilderExecutor; this.mergeContext = protocolContext.getConsensusContext(MergeContext.class); - this.miningParameters = miningParams; this.backwardSyncContext = backwardSyncContext; - this.targetGasLimit = - miningParameters - .getTargetGasLimit() - // TODO: revisit default target gas limit - .orElse(new AtomicLong(30000000L)); + if (miningParams.getTargetGasLimit().isEmpty()) { + miningParams.setTargetGasLimit(DEFAULT_TARGET_GAS_LIMIT); + } + miningParams.setMinBlockOccupancyRatio(TRY_FILL_BLOCK); + this.miningParameters = miningParams; this.mergeBlockCreatorFactory = mergeBlockCreatorFactory; @@ -210,7 +211,7 @@ public Wei getMinTransactionGasPrice() { @Override public void setExtraData(final Bytes extraData) { - this.extraData.set(extraData); + this.miningParameters.setExtraData(extraData); } @Override @@ -234,7 +235,7 @@ public Optional createBlock(final BlockHeader parentHeader, final long ti @Override public void changeTargetGasLimit(final Long newTargetGasLimit) { if (AbstractGasLimitSpecification.isValidTargetGasLimit(newTargetGasLimit)) { - this.targetGasLimit.set(newTargetGasLimit); + this.miningParameters.setTargetGasLimit(newTargetGasLimit); } else { throw new IllegalArgumentException("Specified target gas limit is invalid"); } @@ -363,11 +364,12 @@ private void tryToBuildBetterBlock( LOG.debug( "Block creation started for payload id {}, remaining time is {}ms", payloadIdentifier, - miningParameters.getPosBlockCreationMaxTime()); + miningParameters.getUnstable().getPosBlockCreationMaxTime()); blockBuilderExecutor .buildProposal(() -> retryBlockCreationUntilUseful(payloadIdentifier, blockCreator)) - .orTimeout(miningParameters.getPosBlockCreationMaxTime(), TimeUnit.MILLISECONDS) + .orTimeout( + miningParameters.getUnstable().getPosBlockCreationMaxTime(), TimeUnit.MILLISECONDS) .whenComplete( (unused, throwable) -> { if (throwable != null) { @@ -393,7 +395,9 @@ private Void retryBlockCreationUntilUseful( final long lastDuration = System.currentTimeMillis() - lastStartAt; final long waitBeforeRepetition = Math.max( - 100, miningParameters.getPosBlockCreationRepetitionMinDuration() - lastDuration); + 100, + miningParameters.getUnstable().getPosBlockCreationRepetitionMinDuration() + - lastDuration); LOG.debug("Waiting {}ms before repeating block creation", waitBeforeRepetition); Thread.sleep(waitBeforeRepetition); } catch (final CancellationException | InterruptedException ce) { diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java index bc7e424133d..7c54b9260f9 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java @@ -25,7 +25,6 @@ import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doCallRealMethod; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -57,6 +56,9 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.Unstable; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.ethereum.eth.manager.EthContext; @@ -98,7 +100,6 @@ import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; @@ -132,11 +133,13 @@ public class MergeCoordinatorTest implements MergeGenesisConfigHelper { @Mock ProposalBuilderExecutor proposalBuilderExecutor; private final Address coinbase = genesisAllocations(getPosGenesisConfigFile()).findFirst().get(); - @Spy MiningParameters miningParameters = - new MiningParameters.Builder() - .coinbase(coinbase) - .posBlockCreationRepetitionMinDuration(REPETITION_MIN_DURATION) + ImmutableMiningParameters.builder() + .mutableInitValues(MutableInitValues.builder().coinbase(coinbase).build()) + .unstable( + Unstable.builder() + .posBlockCreationRepetitionMinDuration(REPETITION_MIN_DURATION) + .build()) .build(); private MergeCoordinator coordinator; @@ -278,14 +281,11 @@ public void exceptionDuringBuildingBlockShouldNotBeInvalid() MergeBlockCreator beingSpiedOn = spy( new MergeBlockCreator( - address.or(miningParameters::getCoinbase).orElse(Address.ZERO), - () -> Optional.of(30000000L), + miningParameters, parent -> Bytes.EMPTY, transactionPool, protocolContext, protocolSchedule, - this.miningParameters.getMinTransactionGasPrice(), - address.or(miningParameters::getCoinbase).orElse(Address.ZERO), parentHeader, Optional.empty())); @@ -548,7 +548,11 @@ public void shouldRetryBlockCreationOnRecoverableError() @Test public void shouldStopRetryBlockCreationIfTimeExpired() throws InterruptedException { final AtomicLong retries = new AtomicLong(0); - doReturn(100L).when(miningParameters).getPosBlockCreationMaxTime(); + miningParameters = + ImmutableMiningParameters.builder() + .from(miningParameters) + .unstable(Unstable.builder().posBlockCreationMaxTime(100).build()) + .build(); doAnswer( invocation -> { retries.incrementAndGet(); @@ -738,7 +742,10 @@ public void shouldCancelPreviousBlockCreationJobIfCalledAgainWithNewPayloadId() public void shouldUseExtraDataFromMiningParameters() { final Bytes extraData = Bytes.fromHexString("0x1234"); - miningParameters = new MiningParameters.Builder().extraData(extraData).build(); + miningParameters = + ImmutableMiningParameters.builder() + .mutableInitValues(MutableInitValues.builder().extraData(extraData).build()) + .build(); this.coordinator = new MergeCoordinator( diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java index d5dbd139c6c..cd96d9cbdbb 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeReorgTest.java @@ -33,7 +33,8 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Difficulty; -import org.hyperledger.besu.ethereum.core.MiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.eth.sync.backwardsync.BackwardSyncContext; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.BlockHeaderValidator; @@ -93,7 +94,9 @@ public void setUp() { mockProtocolSchedule, CompletableFuture::runAsync, mockTransactionPool, - new MiningParameters.Builder().coinbase(coinbase).build(), + ImmutableMiningParameters.builder() + .mutableInitValues(MutableInitValues.builder().coinbase(coinbase).build()) + .build(), mock(BackwardSyncContext.class), Optional.empty()); mergeContext.setIsPostMerge(genesisState.getBlock().getHeader().getDifficulty()); 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 ac824df6c0f..2b0386d9066 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 @@ -90,6 +90,8 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.ProtocolScheduleFixture; import org.hyperledger.besu.ethereum.core.Util; @@ -365,11 +367,14 @@ private static ControllerAndState createControllerAndFinalState( final List qbftForks) { final MiningParameters miningParams = - new MiningParameters.Builder() - .coinbase(AddressHelpers.ofValue(1)) - .minTransactionGasPrice(Wei.ZERO) - .extraData(Bytes.wrap("Qbft Int tests".getBytes(UTF_8))) - .miningEnabled(true) + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .isMiningEnabled(true) + .minTransactionGasPrice(Wei.ZERO) + .extraData(Bytes.wrap("Qbft Int tests".getBytes(UTF_8))) + .coinbase(AddressHelpers.ofValue(1)) + .build()) .build(); final StubGenesisConfigOptions genesisConfigOptions = new StubGenesisConfigOptions(); diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactory.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactory.java index c2007ededf7..2f993c4d1bb 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactory.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactory.java @@ -83,7 +83,8 @@ public Bytes createExtraData(final int round, final BlockHeader parentHeader) { // vote and validators will come from contract instead of block final BftExtraData extraData = new BftExtraData( - ConsensusHelpers.zeroLeftPad(vanityData, BftExtraDataCodec.EXTRA_VANITY_LENGTH), + ConsensusHelpers.zeroLeftPad( + miningParameters.getExtraData(), BftExtraDataCodec.EXTRA_VANITY_LENGTH), Collections.emptyList(), Optional.empty(), round, diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactoryTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactoryTest.java index fa2e8158530..d7b63bc215c 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactoryTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactoryTest.java @@ -30,6 +30,8 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; @@ -46,9 +48,14 @@ public class QbftBlockCreatorFactoryTest { @BeforeEach @SuppressWarnings("unchecked") - public void setUp() throws Exception { - final MiningParameters miningParams = mock(MiningParameters.class); - when(miningParams.getExtraData()).thenReturn(Bytes.wrap("Qbft tests".getBytes(UTF_8))); + public void setUp() { + final MiningParameters miningParams = + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .extraData(Bytes.wrap("Qbft tests".getBytes(UTF_8))) + .build()) + .build(); final MutableQbftConfigOptions qbftConfigOptions = new MutableQbftConfigOptions(JsonQbftConfigOptions.DEFAULT); diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetFilterChangesIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetFilterChangesIntegrationTest.java index 555146ca7cb..116c2d75181 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetFilterChangesIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthGetFilterChangesIntegrationTest.java @@ -119,7 +119,7 @@ public void setUp() { protocolContext, batchAddedListener, ethContext, - new MiningParameters.Builder().minTransactionGasPrice(Wei.ZERO).build(), + MiningParameters.newDefault(), new TransactionPoolMetrics(metricsSystem), TransactionPoolConfiguration.DEFAULT, null); diff --git a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthGetFilterChangesIntegrationTest.java b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthGetFilterChangesIntegrationTest.java index 873956d34b1..70025eeef07 100644 --- a/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthGetFilterChangesIntegrationTest.java +++ b/ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthGetFilterChangesIntegrationTest.java @@ -119,7 +119,7 @@ public void setUp() { protocolContext, batchAddedListener, ethContext, - new MiningParameters.Builder().minTransactionGasPrice(Wei.ZERO).build(), + MiningParameters.newDefault(), new TransactionPoolMetrics(metricsSystem), TransactionPoolConfiguration.DEFAULT, null); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/ApiConfiguration.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/ApiConfiguration.java index f8b52054d57..6652682fc4f 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/ApiConfiguration.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/ApiConfiguration.java @@ -16,6 +16,8 @@ package org.hyperledger.besu.ethereum.api; +import java.util.function.LongSupplier; + import org.immutables.value.Value; @Value.Immutable @@ -33,8 +35,8 @@ public double getGasPricePercentile() { } @Value.Default - public long getGasPriceMin() { - return 1_000_000_000L; // 1 GWei + public LongSupplier getGasPriceMinSupplier() { + return () -> 1_000_000_000L; // 1 GWei } @Value.Default diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java index 04bfdd9727a..eede84fb82b 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java @@ -969,7 +969,7 @@ public Optional gasPrice() { ? Optional.empty() : Optional.of( Math.max( - apiConfig.getGasPriceMin(), + apiConfig.getGasPriceMinSupplier().getAsLong(), Math.min( apiConfig.getGasPriceMax(), gasCollection[ diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java index bba69967d52..9a03f782e5b 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java @@ -118,7 +118,7 @@ public void setupTest() throws Exception { context.getWorldStateArchive(), Optional.empty(), Optional.empty(), - ImmutableApiConfiguration.builder().gasPriceMin(0).build()); + ImmutableApiConfiguration.builder().gasPriceMinSupplier(() -> 0).build()); final Set supportedCapabilities = new HashSet<>(); supportedCapabilities.add(EthProtocol.ETH62); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java index eef2b4422e8..27462501010 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGasPriceTest.java @@ -67,7 +67,7 @@ public void setUp() { null, Optional.empty(), Optional.empty(), - ImmutableApiConfiguration.builder().gasPriceMin(100).build()), + ImmutableApiConfiguration.builder().gasPriceMinSupplier(() -> 100).build()), miningCoordinator); } diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java index 3fa80f1dd0a..a8bb17e93cd 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java @@ -31,6 +31,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions; import org.hyperledger.besu.ethereum.core.Deposit; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.core.SealableBlockHeader; @@ -61,7 +62,6 @@ import java.util.Optional; import java.util.concurrent.CancellationException; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Supplier; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; @@ -79,43 +79,33 @@ public interface ExtraDataCalculator { private static final Logger LOG = LoggerFactory.getLogger(AbstractBlockCreator.class); - protected final Address coinbase; private final MiningBeneficiaryCalculator miningBeneficiaryCalculator; - protected final Supplier> targetGasLimitSupplier; - private final ExtraDataCalculator extraDataCalculator; private final TransactionPool transactionPool; + protected final MiningParameters miningParameters; protected final ProtocolContext protocolContext; protected final ProtocolSchedule protocolSchedule; protected final BlockHeaderFunctions blockHeaderFunctions; - private final Wei minTransactionGasPrice; - private final Double minBlockOccupancyRatio; protected final BlockHeader parentHeader; private final Optional
depositContractAddress; private final AtomicBoolean isCancelled = new AtomicBoolean(false); protected AbstractBlockCreator( - final Address coinbase, + final MiningParameters miningParameters, final MiningBeneficiaryCalculator miningBeneficiaryCalculator, - final Supplier> targetGasLimitSupplier, final ExtraDataCalculator extraDataCalculator, final TransactionPool transactionPool, final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, - final Wei minTransactionGasPrice, - final Double minBlockOccupancyRatio, final BlockHeader parentHeader, final Optional
depositContractAddress) { - this.coinbase = coinbase; + this.miningParameters = miningParameters; this.miningBeneficiaryCalculator = miningBeneficiaryCalculator; - this.targetGasLimitSupplier = targetGasLimitSupplier; this.extraDataCalculator = extraDataCalculator; this.transactionPool = transactionPool; this.protocolContext = protocolContext; this.protocolSchedule = protocolSchedule; - this.minTransactionGasPrice = minTransactionGasPrice; - this.minBlockOccupancyRatio = minBlockOccupancyRatio; this.parentHeader = parentHeader; this.depositContractAddress = depositContractAddress; blockHeaderFunctions = ScheduleBasedBlockHeaderFunctions.create(protocolSchedule); @@ -341,14 +331,13 @@ private TransactionSelectionResults selectTransactions( final BlockTransactionSelector selector = new BlockTransactionSelector( + miningParameters, transactionProcessor, protocolContext.getBlockchain(), disposableWorldState, transactionPool, processableBlockHeader, transactionReceiptFactory, - minTransactionGasPrice, - minBlockOccupancyRatio, isCancelled::get, miningBeneficiary, blobGasPrice, @@ -395,7 +384,7 @@ private ProcessableBlockHeader createPendingBlockHeader( .getGasLimitCalculator() .nextGasLimit( parentHeader.getGasLimit(), - targetGasLimitSupplier.get().orElse(parentHeader.getGasLimit()), + miningParameters.getTargetGasLimit().orElse(parentHeader.getGasLimit()), newBlockNumber); final DifficultyCalculator difficultyCalculator = protocolSpec.getDifficultyCalculator(); @@ -419,7 +408,7 @@ private ProcessableBlockHeader createPendingBlockHeader( final Bytes32 parentBeaconBlockRoot = maybeParentBeaconBlockRoot.orElse(null); return BlockHeaderBuilder.create() .parentHash(parentHeader.getHash()) - .coinbase(coinbase) + .coinbase(miningParameters.getCoinbase().orElseThrow()) .difficulty(Difficulty.of(difficulty)) .number(newBlockNumber) .gasLimit(gasLimit) diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java index 3434c6f1b26..1432afb34a7 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java @@ -32,7 +32,6 @@ import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; import org.apache.tuweni.bytes.Bytes; import org.slf4j.Logger; @@ -47,12 +46,7 @@ public abstract class AbstractMinerExecutor targetGasLimit; - + protected final MiningParameters miningParameters; private final AtomicBoolean stopped = new AtomicBoolean(false); protected AbstractMinerExecutor( @@ -64,11 +58,8 @@ protected AbstractMinerExecutor( this.protocolContext = protocolContext; this.protocolSchedule = protocolSchedule; this.transactionPool = transactionPool; - this.extraData = miningParams.getExtraData(); - this.minTransactionGasPrice = miningParams.getMinTransactionGasPrice(); this.blockScheduler = blockScheduler; - this.minBlockOccupancyRatio = miningParams.getMinBlockOccupancyRatio(); - this.targetGasLimit = miningParams.getTargetGasLimit(); + this.miningParameters = miningParams; } public Optional startAsyncMining( @@ -103,24 +94,21 @@ public abstract M createMiner( final BlockHeader parentHeader); public void setExtraData(final Bytes extraData) { - this.extraData = extraData.copy(); + miningParameters.setExtraData(extraData.copy()); } public void setMinTransactionGasPrice(final Wei minTransactionGasPrice) { - this.minTransactionGasPrice = minTransactionGasPrice; + miningParameters.setMinTransactionGasPrice(minTransactionGasPrice); } public Wei getMinTransactionGasPrice() { - return minTransactionGasPrice; + return miningParameters.getMinTransactionGasPrice(); } public abstract Optional
getCoinbase(); public void changeTargetGasLimit(final Long newTargetGasLimit) { if (AbstractGasLimitSpecification.isValidTargetGasLimit(newTargetGasLimit)) { - this.targetGasLimit.ifPresentOrElse( - existing -> existing.set(newTargetGasLimit), - () -> this.targetGasLimit = Optional.of(new AtomicLong(newTargetGasLimit))); } else { throw new UnsupportedOperationException("Specified target gas limit is invalid"); } diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreator.java index 46eb9d5c5ff..66c57379ccb 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreator.java @@ -14,11 +14,10 @@ */ package org.hyperledger.besu.ethereum.blockcreation; -import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.SealableBlockHeader; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.EthHash; @@ -31,7 +30,6 @@ import java.util.Optional; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; -import java.util.function.Supplier; import org.apache.tuweni.units.bigints.UInt256; @@ -40,26 +38,20 @@ public class PoWBlockCreator extends AbstractBlockCreator { private final PoWSolver nonceSolver; public PoWBlockCreator( - final Address coinbase, - final Supplier> targetGasLimitSupplier, + final MiningParameters miningParameters, final ExtraDataCalculator extraDataCalculator, final TransactionPool transactionPool, final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, final PoWSolver nonceSolver, - final Wei minTransactionGasPrice, - final Double minBlockOccupancyRatio, final BlockHeader parentHeader) { super( - coinbase, - __ -> coinbase, - targetGasLimitSupplier, + miningParameters, + __ -> miningParameters.getCoinbase().orElseThrow(), extraDataCalculator, transactionPool, protocolContext, protocolSchedule, - minTransactionGasPrice, - minBlockOccupancyRatio, parentHeader, Optional.empty()); diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java index 49f7e702c23..cd44318e960 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java @@ -28,17 +28,12 @@ import org.hyperledger.besu.util.Subscribers; import java.util.Optional; -import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; public class PoWMinerExecutor extends AbstractMinerExecutor { - protected volatile Optional
coinbase; protected boolean stratumMiningEnabled; - protected final Iterable nonceGenerator; protected final EpochCalculator epochCalculator; - protected final long powJobTimeToLive; - protected final int maxOmmerDepth; public PoWMinerExecutor( final ProtocolContext protocolContext, @@ -46,15 +41,12 @@ public PoWMinerExecutor( final TransactionPool transactionPool, final MiningParameters miningParams, final AbstractBlockScheduler blockScheduler, - final EpochCalculator epochCalculator, - final long powJobTimeToLive, - final int maxOmmerDepth) { + final EpochCalculator epochCalculator) { super(protocolContext, protocolSchedule, transactionPool, miningParams, blockScheduler); - this.coinbase = miningParams.getCoinbase(); - this.nonceGenerator = miningParams.getNonceGenerator().orElse(new RandomNonceGenerator()); + if (miningParams.getNonceGenerator().isEmpty()) { + miningParams.setNonceGenerator(new RandomNonceGenerator()); + } this.epochCalculator = epochCalculator; - this.powJobTimeToLive = powJobTimeToLive; - this.maxOmmerDepth = maxOmmerDepth; } @Override @@ -62,7 +54,7 @@ public Optional startAsyncMining( final Subscribers observers, final Subscribers ethHashObservers, final BlockHeader parentHeader) { - if (coinbase.isEmpty()) { + if (miningParameters.getCoinbase().isEmpty()) { throw new CoinbaseNotSetException("Unable to start mining without a coinbase."); } return super.startAsyncMining(observers, ethHashObservers, parentHeader); @@ -79,25 +71,20 @@ public PoWBlockMiner createMiner( protocolSchedule.getForNextBlockHeader(parentHeader, 0); final PoWSolver solver = new PoWSolver( - nonceGenerator, + miningParameters, nextBlockProtocolSpec.getPoWHasher().get(), stratumMiningEnabled, ethHashObservers, - epochCalculator, - powJobTimeToLive, - maxOmmerDepth); + epochCalculator); final Function blockCreator = (header) -> new PoWBlockCreator( - coinbase.orElse(Address.ZERO), - () -> targetGasLimit.map(AtomicLong::longValue), - parent -> extraData, + miningParameters, + parent -> miningParameters.getExtraData(), transactionPool, protocolContext, protocolSchedule, solver, - minTransactionGasPrice, - minBlockOccupancyRatio, parentHeader); return new PoWBlockMiner( @@ -108,7 +95,7 @@ public void setCoinbase(final Address coinbase) { if (coinbase == null) { throw new IllegalArgumentException("Coinbase cannot be unset."); } else { - this.coinbase = Optional.of(Address.wrap(coinbase.copy())); + miningParameters.setCoinbase(Address.wrap(coinbase.copy())); } } @@ -118,7 +105,7 @@ void setStratumMiningEnabled(final boolean stratumMiningEnabled) { @Override public Optional
getCoinbase() { - return coinbase; + return miningParameters.getCoinbase(); } public EpochCalculator getEpochCalculator() { diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockSelectionContext.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockSelectionContext.java index 0292f0bf67c..8204b3d9e43 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockSelectionContext.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockSelectionContext.java @@ -17,16 +17,16 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.GasLimitCalculator; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.evm.gascalculator.GasCalculator; public record BlockSelectionContext( + MiningParameters miningParameters, GasCalculator gasCalculator, GasLimitCalculator gasLimitCalculator, - Wei minTransactionGasPrice, - Double minBlockOccupancyRatio, ProcessableBlockHeader processableBlockHeader, FeeMarket feeMarket, Wei blobGasPrice, 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 03c6ef28951..2c4382234dc 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 @@ -24,6 +24,7 @@ import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.PriceTransactionSelector; import org.hyperledger.besu.ethereum.blockcreation.txselection.selectors.ProcessingResultTransactionSelector; import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; @@ -75,7 +76,6 @@ */ public class BlockTransactionSelector { private static final Logger LOG = LoggerFactory.getLogger(BlockTransactionSelector.class); - private final Supplier isCancelled; private final MainnetTransactionProcessor transactionProcessor; private final Blockchain blockchain; @@ -89,14 +89,13 @@ public class BlockTransactionSelector { private final OperationTracer pluginOperationTracer; public BlockTransactionSelector( + final MiningParameters miningParameters, final MainnetTransactionProcessor transactionProcessor, final Blockchain blockchain, final MutableWorldState worldState, final TransactionPool transactionPool, final ProcessableBlockHeader processableBlockHeader, final AbstractBlockProcessor.TransactionReceiptFactory transactionReceiptFactory, - final Wei minTransactionGasPrice, - final Double minBlockOccupancyRatio, final Supplier isCancelled, final Address miningBeneficiary, final Wei blobGasPrice, @@ -111,10 +110,9 @@ public BlockTransactionSelector( this.isCancelled = isCancelled; this.blockSelectionContext = new BlockSelectionContext( + miningParameters, gasCalculator, gasLimitCalculator, - minTransactionGasPrice, - minBlockOccupancyRatio, processableBlockHeader, feeMarket, blobGasPrice, 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 5d60ef8fc62..96f357546f3 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 @@ -118,13 +118,13 @@ private boolean blockOccupancyAboveThreshold( LOG.trace( "Min block occupancy ratio {}, gas used {}, available {}, remaining {}, used/available {}", - context.minBlockOccupancyRatio(), + context.miningParameters().getMinBlockOccupancyRatio(), gasUsed, gasAvailable, gasRemaining, occupancyRatio); - return occupancyRatio >= context.minBlockOccupancyRatio(); + return occupancyRatio >= context.miningParameters().getMinBlockOccupancyRatio(); } /** diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/PriceTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/PriceTransactionSelector.java index 9828650b41b..dee4316245c 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/PriceTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/PriceTransactionSelector.java @@ -86,11 +86,15 @@ private boolean transactionCurrentPriceBelowMin(final PendingTransaction pending .feeMarket() .getTransactionPriceCalculator() .price(transaction, context.processableBlockHeader().getBaseFee()); - if (context.minTransactionGasPrice().compareTo(currentMinTransactionGasPriceInBlock) > 0) { + if (context + .miningParameters() + .getMinTransactionGasPrice() + .compareTo(currentMinTransactionGasPriceInBlock) + > 0) { LOG.trace( "Current gas fee of {} is lower than configured minimum {}, skipping", pendingTransaction, - context.minTransactionGasPrice()); + context.miningParameters().getMinTransactionGasPrice()); return true; } } 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 b5ad06d8248..413f9bb9ce6 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 @@ -49,6 +49,8 @@ import org.hyperledger.besu.ethereum.core.Deposit; import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.SealableBlockHeader; @@ -81,7 +83,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.function.Supplier; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; @@ -385,16 +386,24 @@ private AbstractBlockCreator createBlockCreator( null); transactionPool.setEnabled(); + final MiningParameters miningParameters = + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .extraData(Bytes.fromHexString("deadbeef")) + .minTransactionGasPrice(Wei.ONE) + .minBlockOccupancyRatio(0d) + .coinbase(Address.ZERO) + .build()) + .build(); + return new TestBlockCreator( - Address.ZERO, + miningParameters, __ -> Address.ZERO, - () -> Optional.of(30_000_000L), __ -> Bytes.fromHexString("deadbeef"), transactionPool, executionContextTestFixture.getProtocolContext(), executionContextTestFixture.getProtocolSchedule(), - Wei.of(1L), - 0d, blockchain.getChainHeadHeader(), depositContractAddress); } @@ -402,27 +411,21 @@ private AbstractBlockCreator createBlockCreator( static class TestBlockCreator extends AbstractBlockCreator { protected TestBlockCreator( - final Address coinbase, + final MiningParameters miningParameters, final MiningBeneficiaryCalculator miningBeneficiaryCalculator, - final Supplier> targetGasLimitSupplier, final ExtraDataCalculator extraDataCalculator, final TransactionPool transactionPool, final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, - final Wei minTransactionGasPrice, - final Double minBlockOccupancyRatio, final BlockHeader parentHeader, final Optional
depositContractAddress) { super( - coinbase, + miningParameters, miningBeneficiaryCalculator, - targetGasLimitSupplier, extraDataCalculator, transactionPool, protocolContext, protocolSchedule, - minTransactionGasPrice, - minBlockOccupancyRatio, parentHeader, depositContractAddress); } 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 863d164df43..1ddcd264ea0 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 @@ -46,6 +46,8 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.MutableWorldState; @@ -111,12 +113,12 @@ public abstract class AbstractBlockTransactionSelectorTest { protected TransactionPool transactionPool; protected MutableWorldState worldState; protected ProtocolSchedule protocolSchedule; + protected MiningParameters miningParameters; @Mock(answer = Answers.RETURNS_DEEP_STUBS) protected ProtocolContext protocolContext; @Mock protected MainnetTransactionProcessor transactionProcessor; - @Mock protected MiningParameters miningParameters; @Mock(answer = Answers.RETURNS_DEEP_STUBS) protected EthContext ethContext; @@ -148,7 +150,10 @@ public void setup() { when(protocolContext.getWorldStateArchive().getMutable(any(), anyBoolean())) .thenReturn(Optional.of(worldState)); when(ethContext.getEthPeers().subscribeConnect(any())).thenReturn(1L); - when(miningParameters.getMinTransactionGasPrice()).thenReturn(Wei.ONE); + miningParameters = + ImmutableMiningParameters.builder() + .mutableInitValues(MutableInitValues.builder().minTransactionGasPrice(Wei.ONE).build()) + .build(); transactionPool = createTransactionPool(); } @@ -584,10 +589,8 @@ public TransactionSelectionResult evaluateTransactionPostProcessing( createBlockSelectorWithTxSelPlugin( transactionProcessor, blockHeader, - Wei.ZERO, miningBeneficiary, Wei.ZERO, - MIN_OCCUPANCY_80_PERCENT, transactionSelectorFactory); transactionPool.addRemoteTransactions( @@ -648,10 +651,8 @@ public TransactionSelectionResult evaluateTransactionPostProcessing( createBlockSelectorWithTxSelPlugin( transactionProcessor, blockHeader, - Wei.ZERO, miningBeneficiary, Wei.ZERO, - MIN_OCCUPANCY_80_PERCENT, transactionSelectorFactory); transactionPool.addRemoteTransactions(List.of(selected, notSelected, selected3)); @@ -682,10 +683,8 @@ public void transactionSelectionPluginShouldBeNotifiedWhenTransactionSelectionCo createBlockSelectorWithTxSelPlugin( transactionProcessor, createBlock(300_000), - Wei.ZERO, AddressHelpers.ofValue(1), Wei.ZERO, - MIN_OCCUPANCY_80_PERCENT, transactionSelectorFactory) .buildTransactionListForBlock(); @@ -747,14 +746,15 @@ protected BlockTransactionSelector createBlockSelector( final double minBlockOccupancyRatio) { final BlockTransactionSelector selector = new BlockTransactionSelector( + miningParameters + .setMinTransactionGasPrice(minGasPrice) + .setMinBlockOccupancyRatio(minBlockOccupancyRatio), transactionProcessor, blockchain, worldState, transactionPool, blockHeader, this::createReceipt, - minGasPrice, - minBlockOccupancyRatio, this::isCancelled, miningBeneficiary, blobGasPrice, @@ -769,21 +769,18 @@ protected BlockTransactionSelector createBlockSelector( protected BlockTransactionSelector createBlockSelectorWithTxSelPlugin( final MainnetTransactionProcessor transactionProcessor, final ProcessableBlockHeader blockHeader, - final Wei minGasPrice, final Address miningBeneficiary, final Wei blobGasPrice, - final double minBlockOccupancyRatio, final PluginTransactionSelectorFactory transactionSelectorFactory) { final BlockTransactionSelector selector = new BlockTransactionSelector( + miningParameters, transactionProcessor, blockchain, worldState, transactionPool, blockHeader, this::createReceipt, - minGasPrice, - minBlockOccupancyRatio, this::isCancelled, miningBeneficiary, blobGasPrice, 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 818210f88a4..80c0a3d4426 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 @@ -31,6 +31,8 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.PrivacyParameters; @@ -58,7 +60,6 @@ import java.io.IOException; import java.math.BigInteger; import java.util.Collections; -import java.util.Optional; import java.util.function.Function; import com.google.common.collect.Lists; @@ -94,29 +95,26 @@ void createMainnetBlock1() throws IOException { .createProtocolSchedule()) .build(); + final MiningParameters miningParameters = createMiningParameters(); + final PoWSolver solver = new PoWSolver( - Lists.newArrayList(BLOCK_1_NONCE), + miningParameters, PoWHasher.ETHASH_LIGHT, false, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); final TransactionPool transactionPool = createTransactionPool(executionContextTestFixture); final PoWBlockCreator blockCreator = new PoWBlockCreator( - BLOCK_1_COINBASE, - Optional::empty, + miningParameters, parent -> BLOCK_1_EXTRA_DATA, transactionPool, executionContextTestFixture.getProtocolContext(), executionContextTestFixture.getProtocolSchedule(), solver, - Wei.ZERO, - 0.8, executionContextTestFixture.getBlockchain().getChainHeadHeader()); // A Hashrate should not exist in the block creator prior to creating a block @@ -150,29 +148,26 @@ void createMainnetBlock1_fixedDifficulty1() { .createProtocolSchedule()) .build(); + final MiningParameters miningParameters = createMiningParameters(); + final PoWSolver solver = new PoWSolver( - Lists.newArrayList(BLOCK_1_NONCE), + miningParameters, PoWHasher.ETHASH_LIGHT, false, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); final TransactionPool transactionPool = createTransactionPool(executionContextTestFixture); final PoWBlockCreator blockCreator = new PoWBlockCreator( - BLOCK_1_COINBASE, - Optional::empty, + miningParameters, parent -> BLOCK_1_EXTRA_DATA, transactionPool, executionContextTestFixture.getProtocolContext(), executionContextTestFixture.getProtocolSchedule(), solver, - Wei.ZERO, - 0.8, executionContextTestFixture.getBlockchain().getChainHeadHeader()); assertThat(blockCreator.createBlock(BLOCK_1_TIMESTAMP)).isNotNull(); @@ -197,29 +192,26 @@ void rewardBeneficiary_zeroReward_skipZeroRewardsFalse() { final ExecutionContextTestFixture executionContextTestFixture = ExecutionContextTestFixture.builder().protocolSchedule(protocolSchedule).build(); + final MiningParameters miningParameters = createMiningParameters(); + final PoWSolver solver = new PoWSolver( - Lists.newArrayList(BLOCK_1_NONCE), + miningParameters, PoWHasher.ETHASH_LIGHT, false, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); final TransactionPool transactionPool = createTransactionPool(executionContextTestFixture); final PoWBlockCreator blockCreator = new PoWBlockCreator( - BLOCK_1_COINBASE, - () -> Optional.of(10_000_000L), + miningParameters, parent -> BLOCK_1_EXTRA_DATA, transactionPool, executionContextTestFixture.getProtocolContext(), executionContextTestFixture.getProtocolSchedule(), solver, - Wei.ZERO, - 0.8, executionContextTestFixture.getBlockchain().getChainHeadHeader()); final MutableWorldState mutableWorldState = @@ -266,29 +258,26 @@ void rewardBeneficiary_zeroReward_skipZeroRewardsTrue() { final ExecutionContextTestFixture executionContextTestFixture = ExecutionContextTestFixture.builder().protocolSchedule(protocolSchedule).build(); + final MiningParameters miningParameters = createMiningParameters(); + final PoWSolver solver = new PoWSolver( - Lists.newArrayList(BLOCK_1_NONCE), + miningParameters, PoWHasher.ETHASH_LIGHT, false, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); final TransactionPool transactionPool = createTransactionPool(executionContextTestFixture); final PoWBlockCreator blockCreator = new PoWBlockCreator( - BLOCK_1_COINBASE, - () -> Optional.of(10_000_000L), + miningParameters, parent -> BLOCK_1_EXTRA_DATA, transactionPool, executionContextTestFixture.getProtocolContext(), executionContextTestFixture.getProtocolSchedule(), solver, - Wei.ZERO, - 0.8, executionContextTestFixture.getBlockchain().getChainHeadHeader()); final MutableWorldState mutableWorldState = @@ -347,4 +336,16 @@ private TransactionPool createTransactionPool( return transactionPool; } + + private MiningParameters createMiningParameters() { + return ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .nonceGenerator(Lists.newArrayList(BLOCK_1_NONCE)) + .extraData(BLOCK_1_EXTRA_DATA) + .minTransactionGasPrice(Wei.ONE) + .coinbase(BLOCK_1_COINBASE) + .build()) + .build(); + } } diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutorTest.java index b3ab4ff0688..b074e2146a8 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutorTest.java @@ -20,7 +20,6 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.MiningParameters; @@ -48,8 +47,7 @@ public class PoWMinerExecutorTest { @Test public void startingMiningWithoutCoinbaseThrowsException() { - final MiningParameters miningParameters = - new MiningParameters.Builder().coinbase(null).minTransactionGasPrice(Wei.of(1000)).build(); + final MiningParameters miningParameters = MiningParameters.newDefault(); final TransactionPool transactionPool = createTransactionPool(miningParameters); @@ -60,9 +58,7 @@ public void startingMiningWithoutCoinbaseThrowsException() { transactionPool, miningParameters, new DefaultBlockScheduler(1, 10, TestClock.fixed()), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); assertThatExceptionOfType(CoinbaseNotSetException.class) .isThrownBy(() -> executor.startAsyncMining(Subscribers.create(), Subscribers.none(), null)) @@ -71,7 +67,7 @@ public void startingMiningWithoutCoinbaseThrowsException() { @Test public void settingCoinbaseToNullThrowsException() { - final MiningParameters miningParameters = new MiningParameters.Builder().build(); + final MiningParameters miningParameters = MiningParameters.newDefault(); final TransactionPool transactionPool = createTransactionPool(miningParameters); @@ -82,9 +78,7 @@ public void settingCoinbaseToNullThrowsException() { transactionPool, miningParameters, new DefaultBlockScheduler(1, 10, TestClock.fixed()), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); assertThatExceptionOfType(IllegalArgumentException.class) .isThrownBy(() -> executor.setCoinbase(null)) diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMiningCoordinatorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMiningCoordinatorTest.java index b60b1f2cd43..6efd63fbaed 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMiningCoordinatorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWMiningCoordinatorTest.java @@ -15,8 +15,8 @@ package org.hyperledger.besu.ethereum.blockcreation; import static org.assertj.core.api.Assertions.assertThat; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_REMOTE_SEALERS_LIMIT; -import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_REMOTE_SEALERS_TTL; +import static org.hyperledger.besu.ethereum.core.MiningParameters.Unstable.DEFAULT_REMOTE_SEALERS_LIMIT; +import static org.hyperledger.besu.ethereum.core.MiningParameters.Unstable.DEFAULT_REMOTE_SEALERS_TTL; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/MiningParameters.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/MiningParameters.java index e90efaba5b9..014c0c2ae8a 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/MiningParameters.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/MiningParameters.java @@ -20,385 +20,262 @@ import java.time.Duration; import java.util.Objects; import java.util.Optional; -import java.util.concurrent.atomic.AtomicLong; +import java.util.OptionalLong; import org.apache.tuweni.bytes.Bytes; - -public class MiningParameters { - - public static final int DEFAULT_REMOTE_SEALERS_LIMIT = 1000; - - public static final long DEFAULT_REMOTE_SEALERS_TTL = Duration.ofMinutes(10).toMinutes(); - - public static final long DEFAULT_POW_JOB_TTL = Duration.ofMinutes(5).toMillis(); - - public static final int DEFAULT_MAX_OMMERS_DEPTH = 8; - - public static final long DEFAULT_POS_BLOCK_CREATION_MAX_TIME = Duration.ofSeconds(12).toMillis(); - - public static final long DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION = - Duration.ofMillis(500).toMillis(); - - private final Optional
coinbase; - private final Optional targetGasLimit; - private final Wei minTransactionGasPrice; - private final Bytes extraData; - private final boolean miningEnabled; - private final boolean stratumMiningEnabled; - private final String stratumNetworkInterface; - private final int stratumPort; - private final String stratumExtranonce; - private final Optional> maybeNonceGenerator; - private final Double minBlockOccupancyRatio; - private final int remoteSealersLimit; - private final long remoteSealersTimeToLive; - private final long powJobTimeToLive; - private final int maxOmmerDepth; - private final long posBlockCreationMaxTime; - private final long posBlockCreationRepetitionMinDuration; - - private MiningParameters( - final Address coinbase, - final Long targetGasLimit, - final Wei minTransactionGasPrice, - final Bytes extraData, - final boolean miningEnabled, - final boolean stratumMiningEnabled, - final String stratumNetworkInterface, - final int stratumPort, - final String stratumExtranonce, - final Optional> maybeNonceGenerator, - final Double minBlockOccupancyRatio, - final int remoteSealersLimit, - final long remoteSealersTimeToLive, - final long powJobTimeToLive, - final int maxOmmerDepth, - final long posBlockCreationMaxTime, - final long posBlockCreationRepetitionMinDuration) { - this.coinbase = Optional.ofNullable(coinbase); - this.targetGasLimit = Optional.ofNullable(targetGasLimit).map(AtomicLong::new); - this.minTransactionGasPrice = minTransactionGasPrice; - this.extraData = extraData; - this.miningEnabled = miningEnabled; - this.stratumMiningEnabled = stratumMiningEnabled; - this.stratumNetworkInterface = stratumNetworkInterface; - this.stratumPort = stratumPort; - this.stratumExtranonce = stratumExtranonce; - this.maybeNonceGenerator = maybeNonceGenerator; - this.minBlockOccupancyRatio = minBlockOccupancyRatio; - this.remoteSealersLimit = remoteSealersLimit; - this.remoteSealersTimeToLive = remoteSealersTimeToLive; - this.powJobTimeToLive = powJobTimeToLive; - this.maxOmmerDepth = maxOmmerDepth; - this.posBlockCreationMaxTime = posBlockCreationMaxTime; - this.posBlockCreationRepetitionMinDuration = posBlockCreationRepetitionMinDuration; +import org.immutables.value.Value; + +@Value.Immutable +@Value.Enclosing +public abstract class MiningParameters { + public static final MiningParameters MINING_DISABLED = + ImmutableMiningParameters.builder() + .mutableInitValues( + ImmutableMiningParameters.MutableInitValues.builder().isMiningEnabled(false).build()) + .build(); + + public static final MiningParameters newDefault() { + return ImmutableMiningParameters.builder().build(); } - public Optional
getCoinbase() { - return coinbase; + public boolean isMiningEnabled() { + return getMutableRuntimeValues().miningEnabled; } - public Optional getTargetGasLimit() { - return targetGasLimit; + public MiningParameters setMiningEnabled(final boolean miningEnabled) { + getMutableRuntimeValues().miningEnabled = miningEnabled; + return this; } - public Wei getMinTransactionGasPrice() { - return minTransactionGasPrice; + public Bytes getExtraData() { + return getMutableRuntimeValues().extraData; } - public Bytes getExtraData() { - return extraData; + public MiningParameters setExtraData(final Bytes extraData) { + getMutableRuntimeValues().extraData = extraData; + return this; } - public boolean isMiningEnabled() { - return miningEnabled; + public Wei getMinTransactionGasPrice() { + return getMutableRuntimeValues().minTransactionGasPrice; } - public boolean isStratumMiningEnabled() { - return stratumMiningEnabled; + public MiningParameters setMinTransactionGasPrice(final Wei minTransactionGasPrice) { + getMutableRuntimeValues().minTransactionGasPrice = minTransactionGasPrice; + return this; } - public String getStratumNetworkInterface() { - return stratumNetworkInterface; + public Optional
getCoinbase() { + return getMutableRuntimeValues().coinbase; } - public int getStratumPort() { - return stratumPort; + public MiningParameters setCoinbase(final Address coinbase) { + getMutableRuntimeValues().coinbase = Optional.of(coinbase); + return this; } - public String getStratumExtranonce() { - return stratumExtranonce; + public OptionalLong getTargetGasLimit() { + return getMutableRuntimeValues().targetGasLimit; } - public Optional> getNonceGenerator() { - return maybeNonceGenerator; + public MiningParameters setTargetGasLimit(final long targetGasLimit) { + getMutableRuntimeValues().targetGasLimit = OptionalLong.of(targetGasLimit); + return this; } - public Double getMinBlockOccupancyRatio() { - return minBlockOccupancyRatio; + public double getMinBlockOccupancyRatio() { + return getMutableRuntimeValues().minBlockOccupancyRatio; } - public int getRemoteSealersLimit() { - return remoteSealersLimit; + public MiningParameters setMinBlockOccupancyRatio(final double minBlockOccupancyRatio) { + getMutableRuntimeValues().minBlockOccupancyRatio = minBlockOccupancyRatio; + return this; } - public long getRemoteSealersTimeToLive() { - return remoteSealersTimeToLive; + public Optional> getNonceGenerator() { + return getMutableRuntimeValues().nonceGenerator; } - public long getPowJobTimeToLive() { - return powJobTimeToLive; + public MiningParameters setNonceGenerator(final Iterable nonceGenerator) { + getMutableRuntimeValues().nonceGenerator = Optional.of(nonceGenerator); + return this; } - public int getMaxOmmerDepth() { - return maxOmmerDepth; + @Value.Default + public boolean isStratumMiningEnabled() { + return false; } - public long getPosBlockCreationMaxTime() { - return posBlockCreationMaxTime; + @Value.Default + public String getStratumNetworkInterface() { + return "0.0.0.0"; } - public long getPosBlockCreationRepetitionMinDuration() { - return posBlockCreationRepetitionMinDuration; + @Value.Default + public int getStratumPort() { + return 8008; } - @Override - public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - MiningParameters that = (MiningParameters) o; - return stratumPort == that.stratumPort - && Objects.equals(coinbase, that.coinbase) - && Objects.equals(targetGasLimit, that.targetGasLimit) - && Objects.equals(minTransactionGasPrice, that.minTransactionGasPrice) - && Objects.equals(extraData, that.extraData) - && miningEnabled == that.miningEnabled - && stratumMiningEnabled == that.stratumMiningEnabled - && Objects.equals(stratumNetworkInterface, that.stratumNetworkInterface) - && Objects.equals(stratumExtranonce, that.stratumExtranonce) - && Objects.equals(minBlockOccupancyRatio, that.minBlockOccupancyRatio) - && remoteSealersTimeToLive == that.remoteSealersTimeToLive - && remoteSealersLimit == that.remoteSealersLimit - && powJobTimeToLive == that.powJobTimeToLive - && posBlockCreationMaxTime == that.posBlockCreationMaxTime - && posBlockCreationRepetitionMinDuration == that.posBlockCreationRepetitionMinDuration; + @Value.Default + protected MutableRuntimeValues getMutableRuntimeValues() { + return new MutableRuntimeValues(getMutableInitValues()); } - @Override - public int hashCode() { - return Objects.hash( - coinbase, - targetGasLimit, - minTransactionGasPrice, - extraData, - miningEnabled, - stratumMiningEnabled, - stratumNetworkInterface, - stratumPort, - stratumExtranonce, - minBlockOccupancyRatio, - remoteSealersLimit, - remoteSealersTimeToLive, - powJobTimeToLive, - posBlockCreationMaxTime, - posBlockCreationRepetitionMinDuration); + @Value.Default + public Unstable getUnstable() { + return Unstable.DEFAULT; } - @Override - public String toString() { - return "MiningParameters{" - + "coinbase=" - + coinbase - + ", targetGasLimit=" - + targetGasLimit.map(Object::toString).orElse("null") - + ", minTransactionGasPrice=" - + minTransactionGasPrice - + ", extraData=" - + extraData - + ", miningEnabled=" - + miningEnabled - + ", stratumMiningEnabled=" - + stratumMiningEnabled - + ", stratumNetworkInterface='" - + stratumNetworkInterface - + '\'' - + ", stratumPort=" - + stratumPort - + ", stratumExtranonce='" - + stratumExtranonce - + '\'' - + ", maybeNonceGenerator=" - + maybeNonceGenerator - + ", minBlockOccupancyRatio=" - + minBlockOccupancyRatio - + ", remoteSealersLimit=" - + remoteSealersLimit - + ", remoteSealersTimeToLive=" - + remoteSealersTimeToLive - + ", powJobTimeToLive=" - + powJobTimeToLive - + ", posBlockCreationMaxTime=" - + posBlockCreationMaxTime - + ", posBlockCreationRepetitionMinDuration=" - + posBlockCreationRepetitionMinDuration - + '}'; + @Value.Default + public MutableInitValues getMutableInitValues() { + return MutableInitValues.DEFAULT; } - public static class Builder { - - private Address coinbase = null; - private Long targetGasLimit = null; - private Wei minTransactionGasPrice = Wei.ZERO; - private Bytes extraData = Bytes.EMPTY; - private boolean miningEnabled = false; - private boolean stratumMiningEnabled = false; - private String stratumNetworkInterface = "0.0.0.0"; - private int stratumPort = 8008; - private String stratumExtranonce = "080c"; - private Iterable maybeNonceGenerator; - private Double minBlockOccupancyRatio = 0.8; - private int remoteSealersLimit = DEFAULT_REMOTE_SEALERS_LIMIT; - private long remoteSealersTimeToLive = DEFAULT_REMOTE_SEALERS_TTL; - private long powJobTimeToLive = DEFAULT_POW_JOB_TTL; - private int maxOmmerDepth = DEFAULT_MAX_OMMERS_DEPTH; - private long posBlockCreationMaxTime = DEFAULT_POS_BLOCK_CREATION_MAX_TIME; - - private long posBlockCreationRepetitionMinDuration = - DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION; - - public Builder() { - // zero arg - } + @Value.Immutable + public interface MutableInitValues { + Bytes DEFAULT_EXTRA_DATA = Bytes.EMPTY; + Wei DEFAULT_MIN_TRANSACTION_GAS_PRICE = Wei.of(1000); + double DEFAULT_MIN_BLOCK_OCCUPANCY_RATIO = 0.8; - public Builder(final MiningParameters existing) { - existing.getCoinbase().ifPresent(cb -> this.coinbase = cb); - existing - .getTargetGasLimit() - .map(AtomicLong::longValue) - .ifPresent(gasLimit -> this.targetGasLimit = gasLimit); - this.minTransactionGasPrice = existing.getMinTransactionGasPrice(); - this.extraData = existing.getExtraData(); - this.miningEnabled = existing.isMiningEnabled(); - this.stratumMiningEnabled = existing.isStratumMiningEnabled(); - this.stratumNetworkInterface = existing.getStratumNetworkInterface(); - this.stratumPort = existing.getStratumPort(); - this.stratumExtranonce = existing.getStratumExtranonce(); - existing.getNonceGenerator().ifPresent(ng -> this.maybeNonceGenerator = ng); - this.minBlockOccupancyRatio = existing.getMinBlockOccupancyRatio(); - this.remoteSealersLimit = existing.getRemoteSealersLimit(); - this.remoteSealersTimeToLive = existing.getRemoteSealersTimeToLive(); - this.powJobTimeToLive = existing.getPowJobTimeToLive(); - this.maxOmmerDepth = existing.getMaxOmmerDepth(); - this.posBlockCreationMaxTime = existing.getPosBlockCreationMaxTime(); - this.posBlockCreationRepetitionMinDuration = - existing.getPosBlockCreationRepetitionMinDuration(); - } + MutableInitValues DEFAULT = ImmutableMiningParameters.MutableInitValues.builder().build(); - public Builder coinbase(final Address address) { - this.coinbase = address; - return this; + @Value.Default + default boolean isMiningEnabled() { + return false; } - public Builder targetGasLimit(final Long targetGasLimit) { - this.targetGasLimit = targetGasLimit; - return this; + @Value.Default + default Bytes getExtraData() { + return DEFAULT_EXTRA_DATA; } - public Builder minTransactionGasPrice(final Wei minTransactionGasPrice) { - this.minTransactionGasPrice = minTransactionGasPrice; - return this; + @Value.Default + default Wei getMinTransactionGasPrice() { + return DEFAULT_MIN_TRANSACTION_GAS_PRICE; } - public Builder extraData(final Bytes extraData) { - this.extraData = extraData; - return this; + @Value.Default + default double getMinBlockOccupancyRatio() { + return DEFAULT_MIN_BLOCK_OCCUPANCY_RATIO; } - public Builder miningEnabled(final boolean miningEnabled) { - this.miningEnabled = miningEnabled; - return this; - } + Optional
getCoinbase(); - public Builder stratumMiningEnabled(final boolean stratumMiningEnabled) { - this.stratumMiningEnabled = stratumMiningEnabled; - return this; - } + OptionalLong getTargetGasLimit(); - public Builder stratumNetworkInterface(final String stratumNetworkInterface) { - this.stratumNetworkInterface = stratumNetworkInterface; - return this; - } + Optional> nonceGenerator(); + } - public Builder stratumPort(final int stratumPort) { - this.stratumPort = stratumPort; - return this; + static class MutableRuntimeValues { + private volatile boolean miningEnabled; + private volatile Bytes extraData; + private volatile Wei minTransactionGasPrice; + private volatile double minBlockOccupancyRatio; + private volatile Optional
coinbase; + private volatile OptionalLong targetGasLimit; + private volatile Optional> nonceGenerator; + + private MutableRuntimeValues(final MutableInitValues initValues) { + miningEnabled = initValues.isMiningEnabled(); + extraData = initValues.getExtraData(); + minTransactionGasPrice = initValues.getMinTransactionGasPrice(); + minBlockOccupancyRatio = initValues.getMinBlockOccupancyRatio(); + coinbase = initValues.getCoinbase(); + targetGasLimit = initValues.getTargetGasLimit(); + nonceGenerator = initValues.nonceGenerator(); } - public Builder stratumExtranonce(final String stratumExtranonce) { - this.stratumExtranonce = stratumExtranonce; - return this; + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final MutableRuntimeValues that = (MutableRuntimeValues) o; + return miningEnabled == that.miningEnabled + && Double.compare(minBlockOccupancyRatio, that.minBlockOccupancyRatio) == 0 + && Objects.equals(extraData, that.extraData) + && Objects.equals(minTransactionGasPrice, that.minTransactionGasPrice) + && Objects.equals(coinbase, that.coinbase) + && Objects.equals(targetGasLimit, that.targetGasLimit) + && Objects.equals(nonceGenerator, that.nonceGenerator); } - public Builder maybeNonceGenerator(final Iterable maybeNonceGenerator) { - this.maybeNonceGenerator = maybeNonceGenerator; - return this; + @Override + public int hashCode() { + return Objects.hash( + miningEnabled, + extraData, + minTransactionGasPrice, + minBlockOccupancyRatio, + coinbase, + targetGasLimit, + nonceGenerator); } - public Builder minBlockOccupancyRatio(final Double minBlockOccupancyRatio) { - this.minBlockOccupancyRatio = minBlockOccupancyRatio; - return this; + @Override + public String toString() { + return "UpdatableRuntimeValues{" + + "miningEnabled=" + + miningEnabled + + ", extraData=" + + extraData + + ", minTransactionGasPrice=" + + minTransactionGasPrice + + ", minBlockOccupancyRatio=" + + minBlockOccupancyRatio + + ", coinbase=" + + coinbase + + ", targetGasLimit=" + + targetGasLimit + + ", nonceGenerator=" + + nonceGenerator + + '}'; } + } + + @Value.Immutable + public interface Unstable { + int DEFAULT_REMOTE_SEALERS_LIMIT = 1000; + long DEFAULT_REMOTE_SEALERS_TTL = Duration.ofMinutes(10).toMinutes(); + long DEFAULT_POW_JOB_TTL = Duration.ofMinutes(5).toMillis(); + int DEFAULT_MAX_OMMERS_DEPTH = 8; + long DEFAULT_POS_BLOCK_CREATION_MAX_TIME = Duration.ofSeconds(12).toMillis(); + long DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION = Duration.ofMillis(500).toMillis(); + + MiningParameters.Unstable DEFAULT = ImmutableMiningParameters.Unstable.builder().build(); - public Builder remoteSealersLimit(final int remoteSealersLimit) { - this.remoteSealersLimit = remoteSealersLimit; - return this; + @Value.Default + default int getRemoteSealersLimit() { + return DEFAULT_REMOTE_SEALERS_LIMIT; } - public Builder remoteSealersTimeToLive(final long remoteSealersTimeToLive) { - this.remoteSealersTimeToLive = remoteSealersTimeToLive; - return this; + @Value.Default + default long getRemoteSealersTimeToLive() { + return DEFAULT_REMOTE_SEALERS_TTL; } - public Builder powJobTimeToLive(final long powJobTimeToLive) { - this.powJobTimeToLive = powJobTimeToLive; - return this; + @Value.Default + default long getPowJobTimeToLive() { + return DEFAULT_POW_JOB_TTL; } - public Builder maxOmmerDepth(final int maxOmmerDepth) { - this.maxOmmerDepth = maxOmmerDepth; - return this; + @Value.Default + default int getMaxOmmerDepth() { + return DEFAULT_MAX_OMMERS_DEPTH; } - public Builder posBlockCreationMaxTime(final long posBlockCreationMaxTime) { - this.posBlockCreationMaxTime = posBlockCreationMaxTime; - return this; + @Value.Default + default long getPosBlockCreationMaxTime() { + return DEFAULT_POS_BLOCK_CREATION_MAX_TIME; } - public Builder posBlockCreationRepetitionMinDuration( - final long posBlockCreationRepetitionMinDuration) { - this.posBlockCreationRepetitionMinDuration = posBlockCreationRepetitionMinDuration; - return this; + @Value.Default + default long getPosBlockCreationRepetitionMinDuration() { + return DEFAULT_POS_BLOCK_CREATION_REPETITION_MIN_DURATION; } - public MiningParameters build() { - return new MiningParameters( - coinbase, - targetGasLimit, - minTransactionGasPrice, - extraData, - miningEnabled, - stratumMiningEnabled, - stratumNetworkInterface, - stratumPort, - stratumExtranonce, - Optional.ofNullable(maybeNonceGenerator), - minBlockOccupancyRatio, - remoteSealersLimit, - remoteSealersTimeToLive, - powJobTimeToLive, - maxOmmerDepth, - posBlockCreationMaxTime, - posBlockCreationRepetitionMinDuration); + @Value.Default + default String getStratumExtranonce() { + return "080c"; } } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/PoWSolver.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/PoWSolver.java index 3248f304100..3161490478e 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/PoWSolver.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/PoWSolver.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.mainnet; import org.hyperledger.besu.ethereum.chain.PoWObserver; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.util.Subscribers; import java.util.Optional; @@ -31,9 +32,9 @@ public class PoWSolver { - private final int maxOmmerDepth; private static final Logger LOG = LoggerFactory.getLogger(PoWSolver.class); - private final long powJobTimeToLive; + + private final MiningParameters miningParameters; public static class PoWSolverJob { @@ -76,7 +77,6 @@ PoWSolution getSolution() throws InterruptedException, ExecutionException { private final long NO_MINING_CONDUCTED = -1; - private final Iterable nonceGenerator; private final PoWHasher poWHasher; private volatile long hashesPerSecond = NO_MINING_CONDUCTED; private final Boolean stratumMiningEnabled; @@ -86,28 +86,26 @@ PoWSolution getSolution() throws InterruptedException, ExecutionException { private final ExpiringMap currentJobs = new ExpiringMap<>(); public PoWSolver( - final Iterable nonceGenerator, + final MiningParameters miningParameters, final PoWHasher poWHasher, final Boolean stratumMiningEnabled, final Subscribers ethHashObservers, - final EpochCalculator epochCalculator, - final long powJobTimeToLive, - final int maxOmmerDepth) { - this.nonceGenerator = nonceGenerator; + final EpochCalculator epochCalculator) { + this.miningParameters = miningParameters; this.poWHasher = poWHasher; this.stratumMiningEnabled = stratumMiningEnabled; this.ethHashObservers = ethHashObservers; ethHashObservers.forEach(observer -> observer.setSubmitWorkCallback(this::submitSolution)); this.epochCalculator = epochCalculator; - this.powJobTimeToLive = powJobTimeToLive; - this.maxOmmerDepth = maxOmmerDepth; } public PoWSolution solveFor(final PoWSolverJob job) throws InterruptedException, ExecutionException { currentJob = Optional.of(job); currentJobs.put( - job.getInputs().getPrePowHash(), job, System.currentTimeMillis() + powJobTimeToLive); + job.getInputs().getPrePowHash(), + job, + System.currentTimeMillis() + miningParameters.getUnstable().getPowJobTimeToLive()); if (stratumMiningEnabled) { LOG.debug( "solving with stratum miner for {} observers", ethHashObservers.getSubscriberCount()); @@ -123,7 +121,7 @@ private void findValidNonce() { final Stopwatch operationTimer = Stopwatch.createStarted(); final PoWSolverJob job = currentJob.get(); long hashesExecuted = 0; - for (final Long n : nonceGenerator) { + for (final Long n : miningParameters.getNonceGenerator().get()) { if (job.isDone()) { return; @@ -183,7 +181,7 @@ public boolean submitSolution(final PoWSolution solution) { solution.getPowHash(), ommerCandidate.getInputs().getBlockNumber(), distanceToHead); - if (distanceToHead <= maxOmmerDepth) { + if (distanceToHead <= miningParameters.getUnstable().getMaxOmmerDepth()) { jobToTestWith = ommerCandidate; } else { LOG.debug("Discarded ommer solution as too far from head {}", distanceToHead); @@ -213,6 +211,6 @@ public boolean submitSolution(final PoWSolution solution) { } public Iterable getNonceGenerator() { - return nonceGenerator; + return miningParameters.getNonceGenerator().get(); } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/AbstractIsolationTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/AbstractIsolationTests.java index da12289afa8..a6441f970fb 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/AbstractIsolationTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/AbstractIsolationTests.java @@ -41,6 +41,8 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.SealableBlockHeader; @@ -77,7 +79,6 @@ import java.util.Optional; import java.util.function.BiFunction; import java.util.function.Function; -import java.util.function.Supplier; import java.util.stream.Collectors; import org.apache.tuweni.bytes.Bytes; @@ -205,26 +206,20 @@ public int getDatabaseVersion() { static class TestBlockCreator extends AbstractBlockCreator { private TestBlockCreator( - final Address coinbase, + final MiningParameters miningParameters, final MiningBeneficiaryCalculator miningBeneficiaryCalculator, - final Supplier> targetGasLimitSupplier, final ExtraDataCalculator extraDataCalculator, final TransactionPool transactionPool, final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, - final Wei minTransactionGasPrice, - final Double minBlockOccupancyRatio, final BlockHeader parentHeader) { super( - coinbase, + miningParameters, miningBeneficiaryCalculator, - targetGasLimitSupplier, extraDataCalculator, transactionPool, protocolContext, protocolSchedule, - minTransactionGasPrice, - minBlockOccupancyRatio, parentHeader, Optional.empty()); } @@ -234,16 +229,26 @@ static TestBlockCreator forHeader( final ProtocolContext protocolContext, final ProtocolSchedule protocolSchedule, final TransactionPool transactionPool) { + + final MiningParameters miningParameters = + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .extraData(Bytes.fromHexString("deadbeef")) + .targetGasLimit(30_000_000L) + .minTransactionGasPrice(Wei.ONE) + .minBlockOccupancyRatio(0d) + .coinbase(Address.ZERO) + .build()) + .build(); + return new TestBlockCreator( - Address.ZERO, + miningParameters, __ -> Address.ZERO, - () -> Optional.of(30_000_000L), __ -> Bytes.fromHexString("deadbeef"), transactionPool, protocolContext, protocolSchedule, - Wei.of(1L), - 0d, parentHeader); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PoWSolverTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PoWSolverTest.java index 92cdce6eb0e..91553afed33 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PoWSolverTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PoWSolverTest.java @@ -21,6 +21,9 @@ import static org.mockito.Mockito.mock; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.util.Subscribers; import java.util.Arrays; @@ -48,13 +51,11 @@ public void emptyHashRateAndWorkDefinitionIsReportedPriorToSolverStarting() { final List noncesToTry = Arrays.asList(1L, 1L, 1L, 1L, 1L, 1L, 0L); final PoWSolver solver = new PoWSolver( - noncesToTry, + createMiningParameters(noncesToTry, 1000, 8), PoWHasher.ETHASH_LIGHT, false, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); assertThat(solver.hashesPerSecond()).isEqualTo(Optional.empty()); assertThat(solver.getWorkDefinition()).isEqualTo(Optional.empty()); @@ -83,13 +84,11 @@ public void hashRateIsProducedSuccessfully() throws InterruptedException, Execut final PoWSolver solver = new PoWSolver( - noncesToTry, + createMiningParameters(noncesToTry, 1000, 8), hasher, false, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); final Stopwatch operationTimer = Stopwatch.createStarted(); final PoWSolverInputs inputs = new PoWSolverInputs(UInt256.ONE, Bytes.EMPTY, 5); @@ -150,13 +149,15 @@ public void ifInvokedTwiceProducesCorrectAnswerForSecondInvocation() // Nonces need to have a 0L inserted, as it is a "wasted" nonce in the solver. final PoWSolver solver = new PoWSolver( - Lists.newArrayList(expectedFirstOutput.getNonce(), 0L, expectedSecondOutput.getNonce()), + createMiningParameters( + Lists.newArrayList( + expectedFirstOutput.getNonce(), 0L, expectedSecondOutput.getNonce()), + 1000, + 8), PoWHasher.ETHASH_LIGHT, false, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); PoWSolution soln = solver.solveFor(PoWSolver.PoWSolverJob.createFromInputs(firstInputs)); assertThat(soln.getMixHash()).isEqualTo(expectedFirstOutput.getMixHash()); @@ -210,13 +211,15 @@ public void canAcceptSolutionsSerially() // Nonces need to have a 0L inserted, as it is a "wasted" nonce in the solver. final PoWSolver solver = new PoWSolver( - Lists.newArrayList(expectedFirstOutput.getNonce(), 0L, expectedSecondOutput.getNonce()), + createMiningParameters( + Lists.newArrayList( + expectedFirstOutput.getNonce(), 0L, expectedSecondOutput.getNonce()), + 1000, + 8), PoWHasher.ETHASH_LIGHT, true, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); CompletableFuture soln1 = new CompletableFuture<>(); CompletableFuture soln2 = new CompletableFuture<>(); @@ -291,13 +294,15 @@ public void canAcceptSolutionsForMultipleJobs() // Nonces need to have a 0L inserted, as it is a "wasted" nonce in the solver. final PoWSolver solver = new PoWSolver( - Lists.newArrayList(expectedFirstOutput.getNonce(), 0L, expectedSecondOutput.getNonce()), + createMiningParameters( + Lists.newArrayList( + expectedFirstOutput.getNonce(), 0L, expectedSecondOutput.getNonce()), + 10000, + 8), PoWHasher.ETHASH_LIGHT, true, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 10000, - 8); + new EpochCalculator.DefaultEpochCalculator()); CompletableFuture soln1 = new CompletableFuture<>(); CompletableFuture soln2 = new CompletableFuture<>(); @@ -382,13 +387,15 @@ public void canAcceptAtMostOneSolution() // Nonces need to have a 0L inserted, as it is a "wasted" nonce in the solver. final PoWSolver solver = new PoWSolver( - Lists.newArrayList(expectedFirstOutput.getNonce(), 0L, expectedSecondOutput.getNonce()), + createMiningParameters( + Lists.newArrayList( + expectedFirstOutput.getNonce(), 0L, expectedSecondOutput.getNonce()), + 1000, + 8), PoWHasher.ETHASH_LIGHT, true, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); CompletableFuture soln1 = new CompletableFuture<>(); CompletableFuture soln2 = new CompletableFuture<>(); @@ -475,13 +482,15 @@ public void rejectsSolutionsForOldBlocks() // Nonces need to have a 0L inserted, as it is a "wasted" nonce in the solver. final PoWSolver solver = new PoWSolver( - Lists.newArrayList(expectedFirstOutput.getNonce(), 0L, expectedSecondOutput.getNonce()), + createMiningParameters( + Lists.newArrayList( + expectedFirstOutput.getNonce(), 0L, expectedSecondOutput.getNonce()), + 1000, + 8), PoWHasher.ETHASH_LIGHT, true, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); CompletableFuture soln1 = new CompletableFuture<>(); CompletableFuture soln2 = new CompletableFuture<>(); @@ -520,4 +529,16 @@ public void rejectsSolutionsForOldBlocks() assertThat(result2.getMixHash()).isEqualTo(expectedSecondOutput.getMixHash()); powThread1.interrupt(); } + + private MiningParameters createMiningParameters( + final List nonceToTry, final int powJobTimeToLive, final int maxOmmerDepth) { + return ImmutableMiningParameters.builder() + .mutableInitValues(MutableInitValues.builder().nonceGenerator(nonceToTry).build()) + .unstable( + ImmutableMiningParameters.Unstable.builder() + .maxOmmerDepth(maxOmmerDepth) + .powJobTimeToLive(powJobTimeToLive) + .build()) + .build(); + } } 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 60574c92152..8884eefdd6e 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 @@ -27,7 +27,6 @@ import org.hyperledger.besu.consensus.merge.ForkchoiceEvent; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; @@ -1116,7 +1115,7 @@ public void transactionMessagesGoToTheCorrectExecutor() { TestClock.system(ZoneId.systemDefault()), metricsSystem, new SyncState(blockchain, ethManager.ethContext().getEthPeers()), - new MiningParameters.Builder().minTransactionGasPrice(Wei.ZERO).build(), + MiningParameters.newDefault(), TransactionPoolConfiguration.DEFAULT, null) .setEnabled(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java index dc410937341..88f5457a121 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java @@ -22,7 +22,6 @@ import org.hyperledger.besu.crypto.SECPPublicKey; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; @@ -136,7 +135,7 @@ public void setupTest() { TestClock.system(ZoneId.systemDefault()), metricsSystem, syncState, - new MiningParameters.Builder().minTransactionGasPrice(Wei.ONE).build(), + MiningParameters.newDefault(), TransactionPoolConfiguration.DEFAULT, null); transactionPool.setEnabled(); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetPooledTransactionsFromPeerTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetPooledTransactionsFromPeerTaskTest.java index f50237515e4..4c7d521a16b 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetPooledTransactionsFromPeerTaskTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/task/GetPooledTransactionsFromPeerTaskTest.java @@ -43,7 +43,7 @@ protected List generateDataToBeRequested() { Transaction tx = new TransactionTestFixture() .nonce(genesisAccountNonce + i) - .gasPrice(Wei.ONE) + .gasPrice(Wei.of(2000)) .gasLimit(100000) .chainId(Optional.empty()) .createTransaction(genesisAccountKeyPair); 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 d9c98f3a92b..ee3b6da2425 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 @@ -132,7 +132,10 @@ public abstract class AbstractTransactionPoolTest { protected TransactionValidatorFactory transactionValidatorFactory; @Mock protected PendingTransactionAddedListener listener; - @Mock protected MiningParameters miningParameters; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + protected MiningParameters miningParameters; + @Mock protected TransactionsMessageSender transactionsMessageSender; @Mock protected NewPooledTransactionHashesMessageSender newPooledTransactionHashesMessageSender; @Mock protected ProtocolSpec protocolSpec; 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 6d3eb668f8f..90f77a783f3 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 @@ -26,7 +26,6 @@ import org.hyperledger.besu.crypto.KeyPair; import org.hyperledger.besu.cryptoservices.NodeKey; import org.hyperledger.besu.cryptoservices.NodeKeyUtils; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.GenesisState; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; @@ -163,7 +162,7 @@ public boolean isMessagePermitted(final EnodeURL destinationEnode, final int cod TestClock.system(ZoneId.systemDefault()), metricsSystem, syncState, - new MiningParameters.Builder().minTransactionGasPrice(Wei.ZERO).build(), + MiningParameters.newDefault(), TransactionPoolConfiguration.DEFAULT, null); 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 3da9bb9c66d..e902c2c1dd8 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 @@ -27,7 +27,6 @@ import org.hyperledger.besu.config.StubGenesisConfigOptions; import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.BlockAddedObserver; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; @@ -241,7 +240,7 @@ private void setupInitialSyncPhase(final boolean hasInitialSyncPhase) { TestClock.fixed(), new TransactionPoolMetrics(new NoOpMetricsSystem()), syncState, - new MiningParameters.Builder().minTransactionGasPrice(Wei.ONE).build(), + MiningParameters.newDefault(), ImmutableTransactionPoolConfiguration.builder() .txPoolMaxSize(1) .pendingTxRetentionPeriod(1) @@ -350,7 +349,7 @@ private TransactionPool createTransactionPool( TestClock.fixed(), new NoOpMetricsSystem(), syncState, - new MiningParameters.Builder().minTransactionGasPrice(Wei.ONE).build(), + MiningParameters.newDefault(), ImmutableTransactionPoolConfiguration.builder() .txPoolImplementation(implementation) .txPoolMaxSize(1) 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 4d29bfd213e..bed7652c6d7 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 @@ -24,7 +24,6 @@ import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockReplay; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; -import org.hyperledger.besu.ethereum.blockcreation.IncrementingNonceGenerator; import org.hyperledger.besu.ethereum.chain.DefaultBlockchain; import org.hyperledger.besu.ethereum.chain.GenesisState; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; @@ -32,6 +31,9 @@ import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.Unstable; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; @@ -99,7 +101,7 @@ public class RetestethContext { private HeaderValidationMode headerValidationMode; private BlockReplay blockReplay; private RetestethClock retestethClock; - + private MiningParameters miningParameters; private TransactionPool transactionPool; private EthScheduler ethScheduler; private PoWSolver poWSolver; @@ -180,25 +182,33 @@ private boolean buildContext( ? HeaderValidationMode.LIGHT : HeaderValidationMode.FULL; - final Iterable nonceGenerator = new IncrementingNonceGenerator(0); + miningParameters = + ImmutableMiningParameters.builder() + .mutableInitValues( + MutableInitValues.builder() + .coinbase(coinbase) + .extraData(extraData) + .targetGasLimit(blockchain.getChainHeadHeader().getGasLimit()) + .minBlockOccupancyRatio(0.0) + .minTransactionGasPrice(Wei.ZERO) + .build()) + .unstable(Unstable.builder().powJobTimeToLive(1000).maxOmmerDepth(8).build()) + .build(); + miningParameters.setMinTransactionGasPrice(Wei.ZERO); poWSolver = ("NoProof".equals(sealengine) || "NoReward".equals(sealEngine)) ? new PoWSolver( - nonceGenerator, + miningParameters, NO_WORK_HASHER, false, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8) + new EpochCalculator.DefaultEpochCalculator()) : new PoWSolver( - nonceGenerator, + miningParameters, PoWHasher.ETHASH_LIGHT, false, Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator(), - 1000, - 8); + new EpochCalculator.DefaultEpochCalculator()); blockReplay = new BlockReplay(protocolSchedule, blockchainQueries.getBlockchain()); @@ -239,7 +249,7 @@ private boolean buildContext( retestethClock, metricsSystem, syncState, - new MiningParameters.Builder().minTransactionGasPrice(Wei.ZERO).build(), + miningParameters, transactionPoolConfiguration, null); @@ -307,12 +317,8 @@ public TransactionPool getTransactionPool() { return transactionPool; } - public Address getCoinbase() { - return coinbase; - } - - public Bytes getExtraData() { - return extraData; + public MiningParameters getMiningParameters() { + return miningParameters; } public MutableBlockchain getBlockchain() { diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestMineBlocks.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestMineBlocks.java index f802ee73e4b..6c3fddae1c7 100644 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestMineBlocks.java +++ b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestMineBlocks.java @@ -14,7 +14,6 @@ */ package org.hyperledger.besu.ethereum.retesteth.methods; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; @@ -24,14 +23,13 @@ import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockImporter; +import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.mainnet.BlockImportResult; import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.retesteth.RetestethClock; import org.hyperledger.besu.ethereum.retesteth.RetestethContext; -import java.util.Optional; - public class TestMineBlocks implements JsonRpcMethod { private final RetestethContext context; @@ -62,17 +60,15 @@ private boolean mineNewBlock() { final ProtocolContext protocolContext = context.getProtocolContext(); final MutableBlockchain blockchain = context.getBlockchain(); final HeaderValidationMode headerValidationMode = context.getHeaderValidationMode(); + final MiningParameters miningParameters = context.getMiningParameters(); final PoWBlockCreator blockCreator = new PoWBlockCreator( - context.getCoinbase(), - () -> Optional.of(blockchain.getChainHeadHeader().getGasLimit()), - header -> context.getExtraData(), + miningParameters, + header -> miningParameters.getExtraData(), context.getTransactionPool(), protocolContext, protocolSchedule, context.getEthHashSolver(), - Wei.ZERO, - 0.0, blockchain.getChainHeadHeader()); final Block block = blockCreator.createBlock(retesethClock.instant().getEpochSecond()).getBlock();