From a9dc83312e330dea08007495ab91bcd617b05ac2 Mon Sep 17 00:00:00 2001 From: Bhanu Pulluri Date: Thu, 17 Oct 2024 14:43:22 -0400 Subject: [PATCH 1/8] Fix incorrect duration for THREE_MINUTES from 1 minute to 3 minutes Signed-off-by: Bhanu Pulluri --- .../besu/tests/acceptance/bftsoak/BftMiningSoakTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bftsoak/BftMiningSoakTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bftsoak/BftMiningSoakTest.java index 878e503ba39..9098fcbb7de 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bftsoak/BftMiningSoakTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bftsoak/BftMiningSoakTest.java @@ -41,7 +41,7 @@ public class BftMiningSoakTest extends ParameterizedBftTestBase { private static final long ONE_MINUTE = Duration.of(1, ChronoUnit.MINUTES).toMillis(); - private static final long THREE_MINUTES = Duration.of(1, ChronoUnit.MINUTES).toMillis(); + private static final long THREE_MINUTES = Duration.of(3, ChronoUnit.MINUTES).toMillis(); private static final long TEN_SECONDS = Duration.of(10, ChronoUnit.SECONDS).toMillis(); From 1ab15263d47053554814e8c2be3152e1837490ac Mon Sep 17 00:00:00 2001 From: Bhanu Pulluri Date: Thu, 31 Oct 2024 04:41:10 -0400 Subject: [PATCH 2/8] Round change upon f+1 RC messages (experimental option) Signed-off-by: Bhanu Pulluri --- .../org/hyperledger/besu/cli/BesuCommand.java | 4 + .../cli/options/unstable/QBFTOptions.java | 35 ++++++++ .../controller/BesuControllerBuilder.java | 7 ++ .../controller/QbftBesuControllerBuilder.java | 31 ++++--- .../besu/consensus/common/bft/BftHelpers.java | 10 +++ .../besu/consensus/common/bft/RoundTimer.java | 3 +- .../statemachine/QbftBlockHeightManager.java | 89 ++++++++++++++----- .../QbftBlockHeightManagerFactory.java | 34 +++++-- .../qbft/statemachine/RoundChangeManager.java | 47 +++++++++- 9 files changed, 214 insertions(+), 46 deletions(-) create mode 100644 besu/src/main/java/org/hyperledger/besu/cli/options/unstable/QBFTOptions.java 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 b21305c87ad..5c849b6b651 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -68,6 +68,7 @@ import org.hyperledger.besu.cli.options.unstable.NetworkingOptions; import org.hyperledger.besu.cli.options.unstable.P2PTLSConfigOptions; import org.hyperledger.besu.cli.options.unstable.PrivacyPluginOptions; +import org.hyperledger.besu.cli.options.unstable.QBFTOptions; import org.hyperledger.besu.cli.options.unstable.RPCOptions; import org.hyperledger.besu.cli.options.unstable.SynchronizerOptions; import org.hyperledger.besu.cli.presynctasks.PreSynchronizationTaskRunner; @@ -303,6 +304,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable { private final EvmOptions unstableEvmOptions = EvmOptions.create(); private final IpcOptions unstableIpcOptions = IpcOptions.create(); private final ChainPruningOptions unstableChainPruningOptions = ChainPruningOptions.create(); + private final QBFTOptions unstableQbftOptions = QBFTOptions.create(); // stable CLI options final DataStorageOptions dataStorageOptions = DataStorageOptions.create(); @@ -1162,6 +1164,7 @@ private void handleUnstableOptions() { .put("EVM Options", unstableEvmOptions) .put("IPC Options", unstableIpcOptions) .put("Chain Data Pruning Options", unstableChainPruningOptions) + .put("QBFT options", unstableQbftOptions) .build(); UnstableOptionsSubCommand.createUnstableOptions(commandLine, unstableOptions); @@ -1806,6 +1809,7 @@ public BesuControllerBuilder setupControllerBuilder() { .isRevertReasonEnabled(isRevertReasonEnabled) .isParallelTxProcessingEnabled( dataStorageConfiguration.getUnstable().isParallelTxProcessingEnabled()) + .isEarlyRoundChangeEnabled(unstableQbftOptions.isEarlyRoundChangeEnabled()) .storageProvider(storageProvider) .gasLimitCalculator( miningParametersSupplier.get().getTargetGasLimit().isPresent() diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/QBFTOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/QBFTOptions.java new file mode 100644 index 00000000000..3852b8225ef --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/QBFTOptions.java @@ -0,0 +1,35 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.cli.options.unstable; + +import picocli.CommandLine; + +public class QBFTOptions { + + public static QBFTOptions create() { + return new QBFTOptions(); + } + + @CommandLine.Option( + names = {"--Xqbft-enable-early-round-change"}, + description = + "Enable early round change upon receiving f+1 valid future Round Change messages from different validators (experimental)", + hidden = true) + private boolean enableEarlyRoundChange = false; + + public boolean isEarlyRoundChangeEnabled() { + return enableEarlyRoundChange; + } +} diff --git a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java index bded2a38ac7..4850019d3ee 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java @@ -206,6 +206,8 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides /** whether parallel transaction processing is enabled or not */ protected boolean isParallelTxProcessingEnabled; + protected boolean isEarlyRoundChangeEnabled = false; + /** Instantiates a new Besu controller builder. */ protected BesuControllerBuilder() {} @@ -529,6 +531,11 @@ public BesuControllerBuilder isParallelTxProcessingEnabled( return this; } + public BesuControllerBuilder isEarlyRoundChangeEnabled(final boolean isEarlyRoundChangeEnabled) { + this.isEarlyRoundChangeEnabled = isEarlyRoundChangeEnabled; + return this; + } + /** * Build besu controller. * diff --git a/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java index 498435e4afb..504d43075af 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java @@ -249,23 +249,28 @@ protected MiningCoordinator createMiningCoordinator( final MessageFactory messageFactory = new MessageFactory(nodeKey); - final BftEventHandler qbftController = - new QbftController( - blockchain, + QbftBlockHeightManagerFactory qbftBlockHeightManagerFactory = + new QbftBlockHeightManagerFactory( finalState, - new QbftBlockHeightManagerFactory( + new QbftRoundFactory( finalState, - new QbftRoundFactory( - finalState, - protocolContext, - bftProtocolSchedule, - minedBlockObservers, - messageValidatorFactory, - messageFactory, - bftExtraDataCodec().get()), + protocolContext, + bftProtocolSchedule, + minedBlockObservers, messageValidatorFactory, messageFactory, - new ValidatorModeTransitionLogger(qbftForksSchedule)), + bftExtraDataCodec().get()), + messageValidatorFactory, + messageFactory, + new ValidatorModeTransitionLogger(qbftForksSchedule)); + + qbftBlockHeightManagerFactory.isEarlyRoundChangeEnabled(isEarlyRoundChangeEnabled); + + final BftEventHandler qbftController = + new QbftController( + blockchain, + finalState, + qbftBlockHeightManagerFactory, gossiper, duplicateMessageTracker, futureMessageBuffer, diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftHelpers.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftHelpers.java index 318701da7cd..878aebed2e0 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftHelpers.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftHelpers.java @@ -43,6 +43,16 @@ public static int calculateRequiredValidatorQuorum(final int validatorCount) { return Util.fastDivCeiling(2 * validatorCount, 3); } + /** + * Calculate required future RC messages count quorum for a round change. + * + * @param validatorCount the validator count + * @return the int + */ + public static int calculateRequiredFutureRCQuorum(final int validatorCount) { + return validatorCount - Util.fastDivCeiling(2 * validatorCount, 3) + 1; + } + /** * Prepare message count for quorum. * diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/RoundTimer.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/RoundTimer.java index 0302943fc12..78cfedfa98b 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/RoundTimer.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/RoundTimer.java @@ -83,8 +83,7 @@ public synchronized void startTimer(final ConsensusRoundIdentifier round) { // Once we are up to round 2 start logging round expiries if (round.getRoundNumber() >= 2) { LOG.info( - "BFT round {} expired. Moved to round {} which will expire in {} seconds", - round.getRoundNumber() - 1, + "Moved to round {} which will expire in {} seconds", round.getRoundNumber(), (expiryTime / 1000)); } diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManager.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManager.java index 757998b5ca6..5f9326f9b62 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManager.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManager.java @@ -68,6 +68,7 @@ public class QbftBlockHeightManager implements BaseQbftBlockHeightManager { private Optional latestPreparedCertificate = Optional.empty(); private Optional currentRound = Optional.empty(); + private boolean isEarlyRoundChangeEnabled = false; /** * Instantiates a new Qbft block height manager. @@ -213,37 +214,50 @@ private void logValidatorChanges(final QbftRound qbftRound) { @Override public void roundExpired(final RoundExpiry expire) { if (currentRound.isEmpty()) { - LOG.error( + LOG.info( "Received Round timer expiry before round is created timerRound={}", expire.getView()); return; } QbftRound qbftRound = currentRound.get(); if (!expire.getView().equals(qbftRound.getRoundIdentifier())) { - LOG.trace( + LOG.info( "Ignoring Round timer expired which does not match current round. round={}, timerRound={}", qbftRound.getRoundIdentifier(), expire.getView()); return; } + doRoundChange(qbftRound.getRoundIdentifier().getRoundNumber() + 1); + } + + private synchronized void doRoundChange(final int newRoundNumber) { + + if (currentRound.isPresent() + && currentRound.get().getRoundIdentifier().getRoundNumber() >= newRoundNumber) { + return; + } LOG.debug( - "Round has expired, creating PreparedCertificate and notifying peers. round={}", - qbftRound.getRoundIdentifier()); + "Round has expired or changing based on RC quorum, creating PreparedCertificate and notifying peers. round={}", + currentRound.get().getRoundIdentifier()); final Optional preparedCertificate = - qbftRound.constructPreparedCertificate(); + currentRound.get().constructPreparedCertificate(); if (preparedCertificate.isPresent()) { latestPreparedCertificate = preparedCertificate; } - startNewRound(qbftRound.getRoundIdentifier().getRoundNumber() + 1); - qbftRound = currentRound.get(); + startNewRound(newRoundNumber); + if (currentRound.isEmpty()) { + LOG.info("Failed to start round "); + return; + } + QbftRound qbftRoundNew = currentRound.get(); try { final RoundChange localRoundChange = messageFactory.createRoundChange( - qbftRound.getRoundIdentifier(), latestPreparedCertificate); + qbftRoundNew.getRoundIdentifier(), latestPreparedCertificate); // Its possible the locally created RoundChange triggers the transmission of a NewRound // message - so it must be handled accordingly. @@ -252,7 +266,7 @@ public void roundExpired(final RoundExpiry expire) { LOG.warn("Failed to create signed RoundChange message.", e); } - transmitter.multicastRoundChange(qbftRound.getRoundIdentifier(), latestPreparedCertificate); + transmitter.multicastRoundChange(qbftRoundNew.getRoundIdentifier(), latestPreparedCertificate); } @Override @@ -333,24 +347,55 @@ public void handleRoundChangePayload(final RoundChange message) { final Optional> result = roundChangeManager.appendRoundChangeMessage(message); - if (result.isPresent()) { - LOG.debug( - "Received sufficient RoundChange messages to change round to targetRound={}", - targetRound); - if (messageAge == MessageAge.FUTURE_ROUND) { - startNewRound(targetRound.getRoundNumber()); - } + if (!isEarlyRoundChangeEnabled) { + if (result.isPresent()) { + LOG.debug( + "Received sufficient RoundChange messages to change round to targetRound={}", + targetRound); + if (messageAge == MessageAge.FUTURE_ROUND) { + startNewRound(targetRound.getRoundNumber()); + } - final RoundChangeArtifacts roundChangeMetadata = RoundChangeArtifacts.create(result.get()); + final RoundChangeArtifacts roundChangeMetadata = RoundChangeArtifacts.create(result.get()); - if (finalState.isLocalNodeProposerForRound(targetRound)) { - if (currentRound.isEmpty()) { - startNewRound(0); + if (finalState.isLocalNodeProposerForRound(targetRound)) { + if (currentRound.isEmpty()) { + startNewRound(0); + } + currentRound + .get() + .startRoundWith(roundChangeMetadata, TimeUnit.MILLISECONDS.toSeconds(clock.millis())); } + } + } else { + + if (currentRound.isEmpty()) { + startNewRound(0); + } + int currentRoundNumber = currentRound.get().getRoundIdentifier().getRoundNumber(); + // If this node is proposer for the current round, check if quorum is achieved for RC messages + // aiming this round + if (targetRound.getRoundNumber() == currentRoundNumber + && finalState.isLocalNodeProposerForRound(targetRound) + && result.isPresent()) { + + final RoundChangeArtifacts roundChangeMetadata = RoundChangeArtifacts.create(result.get()); + currentRound .get() .startRoundWith(roundChangeMetadata, TimeUnit.MILLISECONDS.toSeconds(clock.millis())); } + + // check if f+1 RC messages for future rounds are received + QbftRound qbftRound = currentRound.get(); + Optional nextHigherRound = + roundChangeManager.futureRCQuorumReceived(qbftRound.getRoundIdentifier()); + if (nextHigherRound.isPresent()) { + LOG.info( + "Received sufficient RoundChange messages to change round to targetRound={}", + nextHigherRound.get()); + doRoundChange(nextHigherRound.get()); + } } } @@ -391,6 +436,10 @@ private MessageAge determineAgeOfPayload(final int messageRoundNumber) { return MessageAge.PRIOR_ROUND; } + public void isEarlyRoundChangeEnabled(final boolean isEarlyRoundChangeEnabled) { + this.isEarlyRoundChangeEnabled = isEarlyRoundChangeEnabled; + } + /** The enum Message age. */ public enum MessageAge { /** Prior round message age. */ diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerFactory.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerFactory.java index 889f83f98a7..ce82722ee7a 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerFactory.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerFactory.java @@ -34,6 +34,7 @@ public class QbftBlockHeightManagerFactory { private final MessageValidatorFactory messageValidatorFactory; private final MessageFactory messageFactory; private final ValidatorModeTransitionLogger validatorModeTransitionLogger; + private boolean isEarlyRoundChangeEnabled = false; /** * Instantiates a new Qbft block height manager factory. @@ -75,22 +76,39 @@ public BaseQbftBlockHeightManager create(final BlockHeader parentHeader) { } } + public void isEarlyRoundChangeEnabled(final boolean isEarlyRoundChangeEnabled) { + this.isEarlyRoundChangeEnabled = isEarlyRoundChangeEnabled; + } + private BaseQbftBlockHeightManager createNoOpBlockHeightManager(final BlockHeader parentHeader) { return new NoOpBlockHeightManager(parentHeader); } private BaseQbftBlockHeightManager createFullBlockHeightManager(final BlockHeader parentHeader) { - return new QbftBlockHeightManager( - parentHeader, - finalState, + + RoundChangeManager roundChangeManager = new RoundChangeManager( BftHelpers.calculateRequiredValidatorQuorum(finalState.getValidators().size()), messageValidatorFactory.createRoundChangeMessageValidator( parentHeader.getNumber() + 1L, parentHeader), - finalState.getLocalAddress()), - roundFactory, - finalState.getClock(), - messageValidatorFactory, - messageFactory); + finalState.getLocalAddress()); + + QbftBlockHeightManager qbftBlockHeightManager = + new QbftBlockHeightManager( + parentHeader, + finalState, + roundChangeManager, + roundFactory, + finalState.getClock(), + messageValidatorFactory, + messageFactory); + + if (isEarlyRoundChangeEnabled) { + roundChangeManager.setRCQuorum( + BftHelpers.calculateRequiredFutureRCQuorum(finalState.getValidators().size())); + qbftBlockHeightManager.isEarlyRoundChangeEnabled(true); + } + + return qbftBlockHeightManager; } } diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/RoundChangeManager.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/RoundChangeManager.java index 89e2888395c..7884c1db6e9 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/RoundChangeManager.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/RoundChangeManager.java @@ -22,6 +22,7 @@ import java.util.Collection; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Maps; @@ -75,7 +76,7 @@ public void addMessage(final RoundChange msg) { * * @return the boolean */ - public boolean roundChangeReady() { + public boolean roundChangeQuorumReceived() { return receivedMessages.size() >= quorum && !actioned; } @@ -85,7 +86,7 @@ public boolean roundChangeReady() { * @return the collection */ public Collection createRoundChangeCertificate() { - if (roundChangeReady()) { + if (roundChangeQuorumReceived()) { actioned = true; return receivedMessages.values(); } else { @@ -104,6 +105,7 @@ public Collection createRoundChangeCertificate() { private final Map roundSummary = Maps.newHashMap(); private final long quorum; + private long rcQuorum; private final RoundChangeMessageValidator roundChangeMessageValidator; private final Address localAddress; @@ -130,6 +132,10 @@ public RoundChangeManager( * @param message the round-change message that has just been received */ public void storeAndLogRoundChangeSummary(final RoundChange message) { + if (!isMessageValid(message)) { + LOG.info("RoundChange message is invalid ."); + return; + } roundSummary.put(message.getAuthor(), message.getRoundIdentifier()); if (roundChangeCache.keySet().stream() .findFirst() @@ -147,6 +153,36 @@ public void storeAndLogRoundChangeSummary(final RoundChange message) { } } + public void setRCQuorum(final long rcQuorum) { + this.rcQuorum = rcQuorum; + } + + public Optional futureRCQuorumReceived( + final ConsensusRoundIdentifier currentRoundIdentifier) { + // Iterate through elements of round summary, identify ones with round number higher than + // current, + // tracking minimum of those and return the next higher round number if quorum is reached + + // Filter out entries with round number greater than current round + // and collect their round numbers + Map higherRounds = + roundSummary.entrySet().stream() + .filter(entry -> isAFutureRound(entry.getValue(), currentRoundIdentifier)) + .collect( + Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getRoundNumber())); + + LOG.debug("Higher rounds size ={} rcquorum = {}", higherRounds.size(), rcQuorum); + + // Check if we have at least f + 1 validators at higher rounds + if (higherRounds.size() >= rcQuorum) { + // Find the minimum round that is greater than the current round + return Optional.of(higherRounds.values().stream().min(Integer::compareTo).orElseThrow()); + } + + // If quorum is not reached, return empty Optional + return Optional.empty(); + } + /** * Adds the round message to this manager and return a certificate if it passes the threshold * @@ -163,7 +199,7 @@ public Optional> appendRoundChangeMessage(final RoundCha final RoundChangeStatus roundChangeStatus = storeRoundChangeMessage(msg); - if (roundChangeStatus.roundChangeReady()) { + if (roundChangeStatus.roundChangeQuorumReceived()) { return Optional.of(roundChangeStatus.createRoundChangeCertificate()); } @@ -198,4 +234,9 @@ private boolean isAnEarlierRound( final ConsensusRoundIdentifier left, final ConsensusRoundIdentifier right) { return left.getRoundNumber() < right.getRoundNumber(); } + + private boolean isAFutureRound( + final ConsensusRoundIdentifier left, final ConsensusRoundIdentifier right) { + return left.getRoundNumber() > right.getRoundNumber(); + } } From 468e19405d56476de0afff9b8a250156b0ce8dd2 Mon Sep 17 00:00:00 2001 From: Bhanu Pulluri <59369753+pullurib@users.noreply.github.com> Date: Tue, 3 Dec 2024 14:58:39 -0500 Subject: [PATCH 3/8] Update besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java Co-authored-by: Matt Whitehead Signed-off-by: Bhanu Pulluri <59369753+pullurib@users.noreply.github.com> --- besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 5c849b6b651..60f203efdd3 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -1164,7 +1164,7 @@ private void handleUnstableOptions() { .put("EVM Options", unstableEvmOptions) .put("IPC Options", unstableIpcOptions) .put("Chain Data Pruning Options", unstableChainPruningOptions) - .put("QBFT options", unstableQbftOptions) + .put("QBFT Options", unstableQbftOptions) .build(); UnstableOptionsSubCommand.createUnstableOptions(commandLine, unstableOptions); From 7eda43f822e1a7187c48652195b1d094d02244ec Mon Sep 17 00:00:00 2001 From: Bhanu Pulluri Date: Tue, 3 Dec 2024 15:43:06 -0500 Subject: [PATCH 4/8] revert an unrelated fix already merged to main Signed-off-by: Bhanu Pulluri --- .../besu/tests/acceptance/bftsoak/BftMiningSoakTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bftsoak/BftMiningSoakTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bftsoak/BftMiningSoakTest.java index 9098fcbb7de..878e503ba39 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bftsoak/BftMiningSoakTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/bftsoak/BftMiningSoakTest.java @@ -41,7 +41,7 @@ public class BftMiningSoakTest extends ParameterizedBftTestBase { private static final long ONE_MINUTE = Duration.of(1, ChronoUnit.MINUTES).toMillis(); - private static final long THREE_MINUTES = Duration.of(3, ChronoUnit.MINUTES).toMillis(); + private static final long THREE_MINUTES = Duration.of(1, ChronoUnit.MINUTES).toMillis(); private static final long TEN_SECONDS = Duration.of(10, ChronoUnit.SECONDS).toMillis(); From bfff0bef6f8e8b384b27d10413da3234a56bab21 Mon Sep 17 00:00:00 2001 From: Bhanu Pulluri Date: Tue, 3 Dec 2024 15:46:41 -0500 Subject: [PATCH 5/8] update return value description Signed-off-by: Bhanu Pulluri --- .../org/hyperledger/besu/consensus/common/bft/BftHelpers.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftHelpers.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftHelpers.java index 878aebed2e0..f900e738d61 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftHelpers.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftHelpers.java @@ -47,7 +47,7 @@ public static int calculateRequiredValidatorQuorum(final int validatorCount) { * Calculate required future RC messages count quorum for a round change. * * @param validatorCount the validator count - * @return the int + * @return Required number of future round change messages to reach quorum for a round change. */ public static int calculateRequiredFutureRCQuorum(final int validatorCount) { return validatorCount - Util.fastDivCeiling(2 * validatorCount, 3) + 1; From d1a2572abaa10f1f79bb024a5505eac340e1136f Mon Sep 17 00:00:00 2001 From: Bhanu Pulluri Date: Tue, 3 Dec 2024 15:52:01 -0500 Subject: [PATCH 6/8] fix logging level for couple of logs Signed-off-by: Bhanu Pulluri --- .../consensus/qbft/statemachine/QbftBlockHeightManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManager.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManager.java index 5f9326f9b62..bd8aa117e2f 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManager.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManager.java @@ -214,14 +214,14 @@ private void logValidatorChanges(final QbftRound qbftRound) { @Override public void roundExpired(final RoundExpiry expire) { if (currentRound.isEmpty()) { - LOG.info( + LOG.error( "Received Round timer expiry before round is created timerRound={}", expire.getView()); return; } QbftRound qbftRound = currentRound.get(); if (!expire.getView().equals(qbftRound.getRoundIdentifier())) { - LOG.info( + LOG.trace( "Ignoring Round timer expired which does not match current round. round={}, timerRound={}", qbftRound.getRoundIdentifier(), expire.getView()); From 6c6743b732eea6f7656dfa19bb305221502be044 Mon Sep 17 00:00:00 2001 From: Bhanu Pulluri Date: Fri, 6 Dec 2024 01:54:08 -0500 Subject: [PATCH 7/8] Review changes , added tests Signed-off-by: Bhanu Pulluri --- .../besu/consensus/common/bft/BftHelpers.java | 2 +- .../consensus/common/bft/BftHelpersTest.java | 35 ++++++++++++ .../statemachine/QbftBlockHeightManager.java | 29 ++++++++-- .../QbftBlockHeightManagerFactory.java | 54 ++++++++++++------- .../qbft/statemachine/RoundChangeManager.java | 21 ++++++-- .../QbftBlockHeightManagerTest.java | 41 +++++++++++++- 6 files changed, 153 insertions(+), 29 deletions(-) diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftHelpers.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftHelpers.java index f900e738d61..6c52dd71914 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftHelpers.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftHelpers.java @@ -50,7 +50,7 @@ public static int calculateRequiredValidatorQuorum(final int validatorCount) { * @return Required number of future round change messages to reach quorum for a round change. */ public static int calculateRequiredFutureRCQuorum(final int validatorCount) { - return validatorCount - Util.fastDivCeiling(2 * validatorCount, 3) + 1; + return (validatorCount - 1) / 3 + 1; } /** diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BftHelpersTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BftHelpersTest.java index 67e7cc283b9..7106d9f5dcb 100644 --- a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BftHelpersTest.java +++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BftHelpersTest.java @@ -63,4 +63,39 @@ public void calculateRequiredValidatorQuorum15Validator() { public void calculateRequiredValidatorQuorum20Validator() { Assertions.assertThat(BftHelpers.calculateRequiredValidatorQuorum(20)).isEqualTo(14); } + + @Test + public void calculateRequiredFutureRCQuorum4Validator() { + Assertions.assertThat(BftHelpers.calculateRequiredFutureRCQuorum(4)).isEqualTo(2); + } + + @Test + public void calculateRequiredFutureRCQuorum6Validator() { + Assertions.assertThat(BftHelpers.calculateRequiredFutureRCQuorum(6)).isEqualTo(2); + } + + @Test + public void calculateRequiredFutureRCQuorum7Validator() { + Assertions.assertThat(BftHelpers.calculateRequiredFutureRCQuorum(7)).isEqualTo(3); + } + + @Test + public void calculateRequiredFutureRCQuorum9Validator() { + Assertions.assertThat(BftHelpers.calculateRequiredFutureRCQuorum(9)).isEqualTo(3); + } + + @Test + public void calculateRequiredFutureRCQuorum10Validator() { + Assertions.assertThat(BftHelpers.calculateRequiredFutureRCQuorum(10)).isEqualTo(4); + } + + @Test + public void calculateRequiredFutureRCQuorum13Validator() { + Assertions.assertThat(BftHelpers.calculateRequiredFutureRCQuorum(13)).isEqualTo(5); + } + + @Test + public void calculateRequiredFutureRCQuorum15Validator() { + Assertions.assertThat(BftHelpers.calculateRequiredFutureRCQuorum(15)).isEqualTo(5); + } } diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManager.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManager.java index bd8aa117e2f..0064902e8c3 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManager.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManager.java @@ -116,6 +116,31 @@ public QbftBlockHeightManager( finalState.getBlockTimer().startTimer(roundIdentifier, parentHeader); } + /** + * Secondary constructor with early round change option + * + * @param isEarlyRoundChangeEnabled enable round change when f+1 RC messages are received + */ + public QbftBlockHeightManager( + final BlockHeader parentHeader, + final BftFinalState finalState, + final RoundChangeManager roundChangeManager, + final QbftRoundFactory qbftRoundFactory, + final Clock clock, + final MessageValidatorFactory messageValidatorFactory, + final MessageFactory messageFactory, + final boolean isEarlyRoundChangeEnabled) { + this( + parentHeader, + finalState, + roundChangeManager, + qbftRoundFactory, + clock, + messageValidatorFactory, + messageFactory); + this.isEarlyRoundChangeEnabled = isEarlyRoundChangeEnabled; + } + @Override public void handleBlockTimerExpiry(final ConsensusRoundIdentifier roundIdentifier) { if (currentRound.isPresent()) { @@ -436,10 +461,6 @@ private MessageAge determineAgeOfPayload(final int messageRoundNumber) { return MessageAge.PRIOR_ROUND; } - public void isEarlyRoundChangeEnabled(final boolean isEarlyRoundChangeEnabled) { - this.isEarlyRoundChangeEnabled = isEarlyRoundChangeEnabled; - } - /** The enum Message age. */ public enum MessageAge { /** Prior round message age. */ diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerFactory.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerFactory.java index ce82722ee7a..b05fe8c45a3 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerFactory.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerFactory.java @@ -86,27 +86,43 @@ private BaseQbftBlockHeightManager createNoOpBlockHeightManager(final BlockHeade private BaseQbftBlockHeightManager createFullBlockHeightManager(final BlockHeader parentHeader) { - RoundChangeManager roundChangeManager = - new RoundChangeManager( - BftHelpers.calculateRequiredValidatorQuorum(finalState.getValidators().size()), - messageValidatorFactory.createRoundChangeMessageValidator( - parentHeader.getNumber() + 1L, parentHeader), - finalState.getLocalAddress()); - - QbftBlockHeightManager qbftBlockHeightManager = - new QbftBlockHeightManager( - parentHeader, - finalState, - roundChangeManager, - roundFactory, - finalState.getClock(), - messageValidatorFactory, - messageFactory); + QbftBlockHeightManager qbftBlockHeightManager; + RoundChangeManager roundChangeManager; if (isEarlyRoundChangeEnabled) { - roundChangeManager.setRCQuorum( - BftHelpers.calculateRequiredFutureRCQuorum(finalState.getValidators().size())); - qbftBlockHeightManager.isEarlyRoundChangeEnabled(true); + roundChangeManager = + new RoundChangeManager( + BftHelpers.calculateRequiredValidatorQuorum(finalState.getValidators().size()), + BftHelpers.calculateRequiredFutureRCQuorum(finalState.getValidators().size()), + messageValidatorFactory.createRoundChangeMessageValidator( + parentHeader.getNumber() + 1L, parentHeader), + finalState.getLocalAddress()); + qbftBlockHeightManager = + new QbftBlockHeightManager( + parentHeader, + finalState, + roundChangeManager, + roundFactory, + finalState.getClock(), + messageValidatorFactory, + messageFactory, + true); + } else { + roundChangeManager = + new RoundChangeManager( + BftHelpers.calculateRequiredValidatorQuorum(finalState.getValidators().size()), + messageValidatorFactory.createRoundChangeMessageValidator( + parentHeader.getNumber() + 1L, parentHeader), + finalState.getLocalAddress()); + qbftBlockHeightManager = + new QbftBlockHeightManager( + parentHeader, + finalState, + roundChangeManager, + roundFactory, + finalState.getClock(), + messageValidatorFactory, + messageFactory); } return qbftBlockHeightManager; diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/RoundChangeManager.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/RoundChangeManager.java index 7884c1db6e9..c260219a6f0 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/RoundChangeManager.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/RoundChangeManager.java @@ -125,6 +125,23 @@ public RoundChangeManager( this.localAddress = localAddress; } + /** + * Instantiates a new Round change manager. + * + * @param quorum the quorum + * @param rcQuorum quorum for round change messages + * @param roundChangeMessageValidator the round change message validator + * @param localAddress this node's address + */ + public RoundChangeManager( + final long quorum, + final long rcQuorum, + final RoundChangeMessageValidator roundChangeMessageValidator, + final Address localAddress) { + this(quorum, roundChangeMessageValidator, localAddress); + this.rcQuorum = rcQuorum; + } + /** * Store the latest round for a node, and if chain is stalled log a summary of which round each * address is on @@ -153,10 +170,6 @@ public void storeAndLogRoundChangeSummary(final RoundChange message) { } } - public void setRCQuorum(final long rcQuorum) { - this.rcQuorum = rcQuorum; - } - public Optional futureRCQuorumReceived( final ConsensusRoundIdentifier currentRoundIdentifier) { // Iterate through elements of round summary, identify ones with round number higher than diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerTest.java index 190c87e020f..31641cce32f 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerTest.java @@ -54,6 +54,7 @@ import org.hyperledger.besu.consensus.qbft.validation.FutureRoundProposalMessageValidator; import org.hyperledger.besu.consensus.qbft.validation.MessageValidator; import org.hyperledger.besu.consensus.qbft.validation.MessageValidatorFactory; +import org.hyperledger.besu.consensus.qbft.validation.RoundChangeMessageValidator; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.cryptoservices.NodeKey; import org.hyperledger.besu.cryptoservices.NodeKeyUtils; @@ -144,7 +145,7 @@ private void buildCreatedBlock() { @BeforeEach public void setup() { - for (int i = 0; i < 3; i++) { + for (int i = 0; i <= 3; i++) { final NodeKey nodeKey = NodeKeyUtils.generate(); validators.add(Util.publicKeyToAddress(nodeKey.getPublicKey())); validatorMessageFactory.add(new MessageFactory(nodeKey)); @@ -603,4 +604,42 @@ public void checkOnlyEmptyBlockPeriodSecondsIsInvokedForBlocksWithNoTransactions verify(blockTimer, times(0)).getEmptyBlockPeriodSeconds(); verify(blockTimer, times(0)).getBlockPeriodSeconds(); } + + @Test + public void roundChangeTriggeredUponReceivingFPlusOneRoundChanges() { + final ConsensusRoundIdentifier futureRoundIdentifier1 = createFrom(roundIdentifier, 0, +2); + final ConsensusRoundIdentifier futureRoundIdentifier2 = createFrom(roundIdentifier, 0, +3); + + final RoundChange roundChange1 = + validatorMessageFactory.get(0).createRoundChange(futureRoundIdentifier1, Optional.empty()); + final RoundChange roundChange2 = + validatorMessageFactory.get(1).createRoundChange(futureRoundIdentifier2, Optional.empty()); + + RoundChangeMessageValidator roundChangeMessageValidator = + mock(RoundChangeMessageValidator.class); + when(roundChangeMessageValidator.validate(any())).thenReturn(true); + + // Instantiate the real RoundChangeManager + final RoundChangeManager roundChangeManager = + new RoundChangeManager(3, 2, roundChangeMessageValidator, validators.get(2)); + + when(finalState.isLocalNodeProposerForRound(any())).thenReturn(false); + + final QbftBlockHeightManager manager = + new QbftBlockHeightManager( + headerTestFixture.buildHeader(), + finalState, + roundChangeManager, + roundFactory, + clock, + messageValidatorFactory, + validatorMessageFactory.get(2), + true); // Enable early round change + + manager.handleRoundChangePayload(roundChange1); + manager.handleRoundChangePayload(roundChange2); + + verify(roundFactory, times(1)) + .createNewRound(any(), eq(futureRoundIdentifier1.getRoundNumber())); + } } From 7138df135c79ce9160e2de55f2ab647e75298545 Mon Sep 17 00:00:00 2001 From: Bhanu Pulluri Date: Fri, 6 Dec 2024 02:52:25 -0500 Subject: [PATCH 8/8] Merge and fix controller builder test context Signed-off-by: Bhanu Pulluri --- .../org/hyperledger/besu/cli/BesuCommand.java | 284 ++++++++++-------- .../besu/cli/CommandTestAbstract.java | 1 + 2 files changed, 157 insertions(+), 128 deletions(-) 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 23839c81f73..961292b437c 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -63,13 +63,13 @@ import org.hyperledger.besu.cli.options.PermissionsOptions; import org.hyperledger.besu.cli.options.PluginsConfigurationOptions; import org.hyperledger.besu.cli.options.PrivacyPluginOptions; -import org.hyperledger.besu.cli.options.unstable.QBFTOptions; import org.hyperledger.besu.cli.options.RPCOptions; import org.hyperledger.besu.cli.options.RpcWebsocketOptions; import org.hyperledger.besu.cli.options.SynchronizerOptions; import org.hyperledger.besu.cli.options.TransactionPoolOptions; import org.hyperledger.besu.cli.options.storage.DataStorageOptions; import org.hyperledger.besu.cli.options.storage.DiffBasedSubStorageOptions; +import org.hyperledger.besu.cli.options.unstable.QBFTOptions; import org.hyperledger.besu.cli.presynctasks.PreSynchronizationTaskRunner; import org.hyperledger.besu.cli.presynctasks.PrivateDatabaseMigrationPreSyncTask; import org.hyperledger.besu.cli.subcommands.PasswordSubCommand; @@ -113,7 +113,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.chain.Blockchain; -import org.hyperledger.besu.ethereum.core.MiningParameters; +import org.hyperledger.besu.ethereum.core.MiningConfiguration; import org.hyperledger.besu.ethereum.core.MiningParametersMetrics; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.VersionMetadata; @@ -127,7 +127,6 @@ import org.hyperledger.besu.ethereum.p2p.peers.EnodeDnsConfiguration; import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl; import org.hyperledger.besu.ethereum.p2p.peers.StaticNodesParser; -import org.hyperledger.besu.ethereum.p2p.rlpx.connections.netty.TLSConfiguration; import org.hyperledger.besu.ethereum.permissioning.LocalPermissioningConfiguration; import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration; import org.hyperledger.besu.ethereum.privacy.storage.keyvalue.PrivacyKeyValueStorageProvider; @@ -136,9 +135,10 @@ import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueSegmentIdentifier; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProvider; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStorageProviderBuilder; -import org.hyperledger.besu.ethereum.transaction.TransactionSimulator; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; +import org.hyperledger.besu.ethereum.worldstate.DiffBasedSubStorageConfiguration; import org.hyperledger.besu.ethereum.worldstate.ImmutableDataStorageConfiguration; +import org.hyperledger.besu.ethereum.worldstate.ImmutableDiffBasedSubStorageConfiguration; import org.hyperledger.besu.evm.precompile.AbstractAltBnPrecompiledContract; import org.hyperledger.besu.evm.precompile.BigIntegerModularExponentiationPrecompiledContract; import org.hyperledger.besu.evm.precompile.KZGPointEvalPrecompiledContract; @@ -166,8 +166,8 @@ import org.hyperledger.besu.plugin.services.TransactionSelectionService; import org.hyperledger.besu.plugin.services.TransactionSimulationService; import org.hyperledger.besu.plugin.services.exception.StorageException; -import org.hyperledger.besu.plugin.services.metrics.MetricCategory; import org.hyperledger.besu.plugin.services.metrics.MetricCategoryRegistry; +import org.hyperledger.besu.plugin.services.mining.MiningService; import org.hyperledger.besu.plugin.services.p2p.P2PService; import org.hyperledger.besu.plugin.services.rlp.RlpConverterService; import org.hyperledger.besu.plugin.services.securitymodule.SecurityModule; @@ -180,6 +180,7 @@ import org.hyperledger.besu.services.BesuEventsImpl; import org.hyperledger.besu.services.BesuPluginContextImpl; import org.hyperledger.besu.services.BlockchainServiceImpl; +import org.hyperledger.besu.services.MiningServiceImpl; import org.hyperledger.besu.services.P2PServiceImpl; import org.hyperledger.besu.services.PermissioningServiceImpl; import org.hyperledger.besu.services.PicoCLIOptionsImpl; @@ -256,7 +257,6 @@ import picocli.CommandLine.Command; import picocli.CommandLine.ExecutionException; import picocli.CommandLine.IExecutionStrategy; -import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; import picocli.CommandLine.ParameterException; @@ -302,6 +302,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable { private final EvmOptions unstableEvmOptions = EvmOptions.create(); private final IpcOptions unstableIpcOptions = IpcOptions.create(); private final ChainPruningOptions unstableChainPruningOptions = ChainPruningOptions.create(); + private final QBFTOptions unstableQbftOptions = QBFTOptions.create(); // stable CLI options final DataStorageOptions dataStorageOptions = DataStorageOptions.create(); @@ -328,7 +329,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable { private final Map environment; private final MetricCategoryRegistryImpl metricCategoryRegistry = new MetricCategoryRegistryImpl(); - private final MetricCategoryConverter metricCategoryConverter = new MetricCategoryConverter(); private final PreSynchronizationTaskRunner preSynchronizationTaskRunner = new PreSynchronizationTaskRunner(); @@ -338,8 +338,10 @@ public class BesuCommand implements DefaultCommandValues, Runnable { Suppliers.memoize(this::readGenesisConfigFile); private final Supplier genesisConfigOptionsSupplier = Suppliers.memoize(this::readGenesisConfigOptions); - private final Supplier miningParametersSupplier = + private final Supplier miningParametersSupplier = Suppliers.memoize(this::getMiningParameters); + private final Supplier apiConfigurationSupplier = + Suppliers.memoize(this::getApiConfiguration); private RocksDBPlugin rocksDBPlugin; @@ -505,77 +507,95 @@ void setUserName(final String userName) { @CommandLine.ArgGroup(validate = false, heading = "@|bold In-Process RPC Options|@%n") InProcessRpcOptions inProcessRpcOptions = InProcessRpcOptions.create(); + private static final String PRIVACY_DEPRECATION_PREFIX = + "Deprecated. Tessera-based privacy is deprecated. See CHANGELOG for alternative options. "; + // Privacy Options Group - @CommandLine.ArgGroup(validate = false, heading = "@|bold Privacy Options|@%n") + @CommandLine.ArgGroup(validate = false, heading = "@|bold (Deprecated) Privacy Options |@%n") PrivacyOptionGroup privacyOptionGroup = new PrivacyOptionGroup(); static class PrivacyOptionGroup { @Option( names = {"--privacy-tls-enabled"}, paramLabel = MANDATORY_FILE_FORMAT_HELP, - description = "Enable TLS for connecting to privacy enclave (default: ${DEFAULT-VALUE})") + description = + PRIVACY_DEPRECATION_PREFIX + + "Enable TLS for connecting to privacy enclave (default: ${DEFAULT-VALUE})") private final Boolean isPrivacyTlsEnabled = false; @Option( names = "--privacy-tls-keystore-file", paramLabel = MANDATORY_FILE_FORMAT_HELP, description = - "Path to a PKCS#12 formatted keystore; used to enable TLS on inbound connections.") + PRIVACY_DEPRECATION_PREFIX + + "Path to a PKCS#12 formatted keystore; used to enable TLS on inbound connections.") private final Path privacyKeyStoreFile = null; @Option( names = "--privacy-tls-keystore-password-file", paramLabel = MANDATORY_FILE_FORMAT_HELP, - description = "Path to a file containing the password used to decrypt the keystore.") + description = + PRIVACY_DEPRECATION_PREFIX + + "Path to a file containing the password used to decrypt the keystore.") private final Path privacyKeyStorePasswordFile = null; @Option( names = "--privacy-tls-known-enclave-file", paramLabel = MANDATORY_FILE_FORMAT_HELP, description = - "Path to a file containing the fingerprints of the authorized privacy enclave.") + PRIVACY_DEPRECATION_PREFIX + + "Path to a file containing the fingerprints of the authorized privacy enclave.") private final Path privacyTlsKnownEnclaveFile = null; @Option( names = {"--privacy-enabled"}, - description = "Enable private transactions (default: ${DEFAULT-VALUE})") + description = + PRIVACY_DEPRECATION_PREFIX + "Enable private transactions (default: ${DEFAULT-VALUE})") private final Boolean isPrivacyEnabled = false; @Option( names = {"--privacy-multi-tenancy-enabled"}, - description = "Enable multi-tenant private transactions (default: ${DEFAULT-VALUE})") + description = + PRIVACY_DEPRECATION_PREFIX + + "Enable multi-tenant private transactions (default: ${DEFAULT-VALUE})") private final Boolean isPrivacyMultiTenancyEnabled = false; @Option( names = {"--privacy-url"}, - description = "The URL on which the enclave is running") + description = PRIVACY_DEPRECATION_PREFIX + "The URL on which the enclave is running") private final URI privacyUrl = PrivacyParameters.DEFAULT_ENCLAVE_URL; @Option( names = {"--privacy-public-key-file"}, - description = "The enclave's public key file") + description = PRIVACY_DEPRECATION_PREFIX + "The enclave's public key file") private final File privacyPublicKeyFile = null; @Option( names = {"--privacy-marker-transaction-signing-key-file"}, description = - "The name of a file containing the private key used to sign privacy marker transactions. If unset, each will be signed with a random key.") + PRIVACY_DEPRECATION_PREFIX + + "The name of a file containing the private key used to sign privacy marker transactions. If unset, each will be signed with a random key.") private final Path privateMarkerTransactionSigningKeyPath = null; @Option( names = {"--privacy-enable-database-migration"}, - description = "Enable private database metadata migration (default: ${DEFAULT-VALUE})") + description = + PRIVACY_DEPRECATION_PREFIX + + "Enable private database metadata migration (default: ${DEFAULT-VALUE})") private final Boolean migratePrivateDatabase = false; @Option( names = {"--privacy-flexible-groups-enabled"}, - description = "Enable flexible privacy groups (default: ${DEFAULT-VALUE})") + description = + PRIVACY_DEPRECATION_PREFIX + + "Enable flexible privacy groups (default: ${DEFAULT-VALUE})") private final Boolean isFlexiblePrivacyGroupsEnabled = false; @Option( names = {"--privacy-nonce-always-increments"}, description = - "Enable private nonce " + PRIVACY_DEPRECATION_PREFIX + + "Enable private nonce " + "incrementation even if the transaction didn't succeeded (default: ${DEFAULT-VALUE})") private final Boolean isPrivateNonceAlwaysIncrementsEnabled = false; } @@ -684,8 +704,6 @@ static class PrivacyOptionGroup { description = "Specifies the number of last blocks to cache (default: ${DEFAULT-VALUE})") private final Integer numberOfblocksToCache = 0; - @Mixin private P2PTLSConfigOptions p2pTLSConfigOptions; - // Plugins Configuration Option Group @CommandLine.ArgGroup(validate = false) PluginsConfigurationOptions pluginsConfigurationOptions = new PluginsConfigurationOptions(); @@ -697,10 +715,8 @@ static class PrivacyOptionGroup { private WebSocketConfiguration webSocketConfiguration; private JsonRpcIpcConfiguration jsonRpcIpcConfiguration; private InProcessRpcConfiguration inProcessRpcConfiguration; - private ApiConfiguration apiConfiguration; private MetricsConfiguration metricsConfiguration; private Optional permissioningConfiguration; - private Optional p2pTLSConfiguration; private DataStorageConfiguration dataStorageConfiguration; private Collection staticNodes; private BesuController besuController; @@ -1104,7 +1120,6 @@ private void addSubCommands(final InputStream in) { PublicKeySubCommand.COMMAND_NAME, new PublicKeySubCommand(commandLine.getOut())); commandLine.addSubcommand( PasswordSubCommand.COMMAND_NAME, new PasswordSubCommand(commandLine.getOut())); - commandLine.addSubcommand(RetestethSubCommand.COMMAND_NAME, new RetestethSubCommand()); commandLine.addSubcommand( RLPSubCommand.COMMAND_NAME, new RLPSubCommand(commandLine.getOut(), in)); commandLine.addSubcommand( @@ -1132,10 +1147,6 @@ private void registerConverters() { commandLine.registerConverter(Hash.class, Hash::fromHexString); commandLine.registerConverter(Optional.class, Optional::of); commandLine.registerConverter(Double.class, Double::parseDouble); - - metricCategoryConverter.addCategories(BesuMetricCategory.class); - metricCategoryConverter.addCategories(StandardMetricCategory.class); - commandLine.registerConverter(MetricCategory.class, metricCategoryConverter); } private void handleStableOptions() { @@ -1161,6 +1172,7 @@ private void handleUnstableOptions() { .put("EVM Options", unstableEvmOptions) .put("IPC Options", unstableIpcOptions) .put("Chain Data Pruning Options", unstableChainPruningOptions) + .put("QBFT Options", unstableQbftOptions) .build(); UnstableOptionsSubCommand.createUnstableOptions(commandLine, unstableOptions); @@ -1170,6 +1182,9 @@ private void preparePlugins() { besuPluginContext.addService(PicoCLIOptions.class, new PicoCLIOptionsImpl(commandLine)); besuPluginContext.addService(SecurityModuleService.class, securityModuleService); besuPluginContext.addService(StorageService.class, storageService); + + metricCategoryRegistry.addCategories(BesuMetricCategory.class); + metricCategoryRegistry.addCategories(StandardMetricCategory.class); besuPluginContext.addService(MetricCategoryRegistry.class, metricCategoryRegistry); besuPluginContext.addService(PermissioningService.class, permissioningService); besuPluginContext.addService(PrivacyPluginService.class, privacyPluginService); @@ -1187,10 +1202,6 @@ private void preparePlugins() { rocksDBPlugin.register(besuPluginContext); new InMemoryStoragePlugin().register(besuPluginContext); - metricCategoryRegistry - .getMetricCategories() - .forEach(metricCategoryConverter::addRegistryCategory); - // register default security module securityModuleService.register( DEFAULT_SECURITY_MODULE, Suppliers.memoize(this::defaultSecurityModule)); @@ -1218,7 +1229,6 @@ private Runner buildRunner() { return synchronize( besuController, p2PDiscoveryConfig.p2pEnabled(), - p2pTLSConfiguration, p2PDiscoveryConfig.peerDiscoveryEnabled(), ethNetworkConfig, p2PDiscoveryConfig.p2pHost(), @@ -1230,7 +1240,7 @@ private Runner buildRunner() { webSocketConfiguration, jsonRpcIpcConfiguration, inProcessRpcConfiguration, - apiConfiguration, + apiConfigurationSupplier.get(), metricsConfiguration, permissioningConfiguration, staticNodes, @@ -1239,14 +1249,10 @@ private Runner buildRunner() { private void startPlugins(final Runner runner) { blockchainServiceImpl.init( - besuController.getProtocolContext(), besuController.getProtocolSchedule()); + besuController.getProtocolContext().getBlockchain(), besuController.getProtocolSchedule()); transactionSimulationServiceImpl.init( besuController.getProtocolContext().getBlockchain(), - new TransactionSimulator( - besuController.getProtocolContext().getBlockchain(), - besuController.getProtocolContext().getWorldStateArchive(), - besuController.getProtocolSchedule(), - apiConfiguration.getGasCap())); + besuController.getTransactionSimulator()); rpcEndpointServiceImpl.init(runner.getInProcessRpcMethods()); besuPluginContext.addService( @@ -1264,6 +1270,7 @@ private void startPlugins(final Runner runner) { besuPluginContext.addService( SynchronizationService.class, new SynchronizationServiceImpl( + besuController.getSynchronizer(), besuController.getProtocolContext(), besuController.getProtocolSchedule(), besuController.getSyncState(), @@ -1289,6 +1296,9 @@ private void startPlugins(final Runner runner) { miningParametersSupplier.get()), besuController.getProtocolSchedule())); + besuPluginContext.addService( + MiningService.class, new MiningServiceImpl(besuController.getMiningCoordinator())); + besuController.getAdditionalPluginServices().appendPluginServices(besuPluginContext); besuPluginContext.startPlugins(); } @@ -1299,6 +1309,8 @@ private void validatePrivacyPluginOptions() { // after start has been called on plugins if (Boolean.TRUE.equals(privacyOptionGroup.isPrivacyEnabled)) { + logger.warn( + "--Xprivacy-plugin-enabled and related options are " + PRIVACY_DEPRECATION_PREFIX); if (privacyOptionGroup.privateMarkerTransactionSigningKeyPath != null && privacyPluginService != null @@ -1338,7 +1350,7 @@ private void validatePrivacyPluginOptions() { private void setReleaseMetrics() { besuComponent .getMetricsSystem() - .createLabelledGauge( + .createLabelledSuppliedGauge( StandardMetricCategory.PROCESS, "release", "Release information", "version") .labels(() -> 1, BesuInfo.version()); } @@ -1420,7 +1432,6 @@ private void configureNativeLibs() { } private void validateOptions() { - validateRequiredOptions(); issueOptionWarnings(); validateP2PInterface(p2PDiscoveryOptions.p2pInterface); validateMiningParams(); @@ -1435,10 +1446,8 @@ private void validateOptions() { validateTransactionPoolOptions(); validateDataStorageOptions(); validateGraphQlOptions(); - validateApiOptions(); validateConsensusSyncCompatibilityOptions(); validatePluginOptions(); - p2pTLSConfigOptions.checkP2PTLSOptionsDependencies(logger, commandLine); } private void validateConsensusSyncCompatibilityOptions() { @@ -1474,19 +1483,6 @@ private void validateDataStorageOptions() { dataStorageOptions.validate(commandLine); } - private void validateRequiredOptions() { - commandLine - .getCommandSpec() - .options() - .forEach( - option -> { - if (option.required() && option.stringValues().isEmpty()) { - throw new ParameterException( - this.commandLine, "Missing required option: " + option.longestName()); - } - }); - } - private void validateMiningParams() { miningOptions.validate( commandLine, genesisConfigOptionsSupplier.get(), isMergeEnabled(), logger); @@ -1642,6 +1638,10 @@ private void issueOptionWarnings() { "--p2p-port", "--remote-connections-max-percentage")); + if (SyncMode.FAST == syncMode) { + logger.warn("FAST sync is deprecated. Recommend using SNAP sync instead."); + } + if (SyncMode.isFullSync(getDefaultSyncModeIfNotSet()) && isOptionSet(commandLine, "--sync-min-peers")) { logger.warn("--sync-min-peers is ignored in FULL sync-mode"); @@ -1656,7 +1656,11 @@ && isOptionSet(commandLine, "--sync-min-peers")) { CommandLineUtils.failIfOptionDoesntMeetRequirement( commandLine, "--Xsnapsync-synchronizer-flat option can only be used when --Xbonsai-full-flat-db-enabled is true", - dataStorageOptions.toDomainObject().getUnstable().getBonsaiFullFlatDbEnabled(), + dataStorageOptions + .toDomainObject() + .getDiffBasedSubStorageConfiguration() + .getUnstable() + .getFullFlatDbEnabled(), asList( "--Xsnapsync-synchronizer-flat-account-healed-count-per-request", "--Xsnapsync-synchronizer-flat-slot-healed-count-per-request")); @@ -1686,7 +1690,6 @@ private void configure() throws Exception { if (isEngineApiEnabled()) { engineJsonRpcConfiguration = createEngineJsonRpcConfiguration(); } - p2pTLSConfiguration = p2pTLSConfigOptions.p2pTLSConfiguration(commandLine); graphQLConfiguration = graphQlOptions.graphQLConfiguration( hostsAllowlist, p2PDiscoveryOptions.p2pHost, unstableRPCOptions.getHttpTimeoutSec()); @@ -1700,7 +1703,6 @@ private void configure() throws Exception { unstableIpcOptions.getIpcPath(), unstableIpcOptions.getRpcIpcApis()); inProcessRpcConfiguration = inProcessRpcOptions.toDomainObject(); - apiConfiguration = apiConfigurationOptions.apiConfiguration(); dataStorageConfiguration = getDataStorageConfiguration(); // hostsWhitelist is a hidden option. If it is specified, add the list to hostAllowlist if (!hostsWhitelist.isEmpty()) { @@ -1788,38 +1790,48 @@ public BesuControllerBuilder setupControllerBuilder() { .withMiningParameters(miningParametersSupplier.get()) .withJsonRpcHttpOptions(jsonRpcHttpOptions); final KeyValueStorageProvider storageProvider = keyValueStorageProvider(keyValueStorageName); - return controllerBuilder - .fromEthNetworkConfig(updateNetworkConfig(network), getDefaultSyncModeIfNotSet()) - .synchronizerConfiguration(buildSyncConfig()) - .ethProtocolConfiguration(unstableEthProtocolOptions.toDomainObject()) - .networkConfiguration(unstableNetworkingOptions.toDomainObject()) - .dataDirectory(dataDir()) - .dataStorageConfiguration(getDataStorageConfiguration()) - .miningParameters(miningParametersSupplier.get()) - .transactionPoolConfiguration(buildTransactionPoolConfiguration()) - .nodeKey(new NodeKey(securityModule())) - .metricsSystem((ObservableMetricsSystem) besuComponent.getMetricsSystem()) - .messagePermissioningProviders(permissioningService.getMessagePermissioningProviders()) - .privacyParameters(privacyParameters()) - .clock(Clock.systemUTC()) - .isRevertReasonEnabled(isRevertReasonEnabled) - .isParallelTxProcessingEnabled( - dataStorageConfiguration.getUnstable().isParallelTxProcessingEnabled()) - .storageProvider(storageProvider) - .gasLimitCalculator( - miningParametersSupplier.get().getTargetGasLimit().isPresent() - ? new FrontierTargetingGasLimitCalculator() - : GasLimitCalculator.constant()) - .requiredBlocks(requiredBlocks) - .reorgLoggingThreshold(reorgLoggingThreshold) - .evmConfiguration(unstableEvmOptions.toDomainObject()) - .maxPeers(p2PDiscoveryOptions.maxPeers) - .maxRemotelyInitiatedPeers(maxRemoteInitiatedPeers) - .randomPeerPriority(p2PDiscoveryOptions.randomPeerPriority) - .chainPruningConfiguration(unstableChainPruningOptions.toDomainObject()) - .cacheLastBlocks(numberOfblocksToCache) - .genesisStateHashCacheEnabled(genesisStateHashCacheEnabled) - .besuComponent(besuComponent); + BesuControllerBuilder besuControllerBuilder = + controllerBuilder + .fromEthNetworkConfig(updateNetworkConfig(network), getDefaultSyncModeIfNotSet()) + .synchronizerConfiguration(buildSyncConfig()) + .ethProtocolConfiguration(unstableEthProtocolOptions.toDomainObject()) + .networkConfiguration(unstableNetworkingOptions.toDomainObject()) + .dataDirectory(dataDir()) + .dataStorageConfiguration(getDataStorageConfiguration()) + .miningParameters(miningParametersSupplier.get()) + .transactionPoolConfiguration(buildTransactionPoolConfiguration()) + .nodeKey(new NodeKey(securityModule())) + .metricsSystem((ObservableMetricsSystem) besuComponent.getMetricsSystem()) + .messagePermissioningProviders(permissioningService.getMessagePermissioningProviders()) + .privacyParameters(privacyParameters()) + .clock(Clock.systemUTC()) + .isRevertReasonEnabled(isRevertReasonEnabled) + .storageProvider(storageProvider) + .isEarlyRoundChangeEnabled(unstableQbftOptions.isEarlyRoundChangeEnabled()) + .gasLimitCalculator( + miningParametersSupplier.get().getTargetGasLimit().isPresent() + ? new FrontierTargetingGasLimitCalculator() + : GasLimitCalculator.constant()) + .requiredBlocks(requiredBlocks) + .reorgLoggingThreshold(reorgLoggingThreshold) + .evmConfiguration(unstableEvmOptions.toDomainObject()) + .maxPeers(p2PDiscoveryOptions.maxPeers) + .maxRemotelyInitiatedPeers(maxRemoteInitiatedPeers) + .randomPeerPriority(p2PDiscoveryOptions.randomPeerPriority) + .chainPruningConfiguration(unstableChainPruningOptions.toDomainObject()) + .cacheLastBlocks(numberOfblocksToCache) + .genesisStateHashCacheEnabled(genesisStateHashCacheEnabled) + .apiConfiguration(apiConfigurationSupplier.get()) + .besuComponent(besuComponent); + if (DataStorageFormat.BONSAI.equals(getDataStorageConfiguration().getDataStorageFormat())) { + final DiffBasedSubStorageConfiguration subStorageConfiguration = + getDataStorageConfiguration().getDiffBasedSubStorageConfiguration(); + if (subStorageConfiguration.getLimitTrieLogsEnabled()) { + besuControllerBuilder.isParallelTxProcessingEnabled( + subStorageConfiguration.getUnstable().isParallelTxProcessingEnabled()); + } + } + return besuControllerBuilder; } private JsonRpcConfiguration createEngineJsonRpcConfiguration() { @@ -1889,6 +1901,10 @@ public MetricsConfiguration metricsConfiguration() { "--metrics-push-interval", "--metrics-push-prometheus-job")); + metricsOptions.setMetricCategoryRegistry(metricCategoryRegistry); + + metricsOptions.validate(commandLine); + final MetricsConfiguration.Builder metricsConfigurationBuilder = metricsOptions.toDomainObject(); metricsConfigurationBuilder @@ -1901,7 +1917,9 @@ public MetricsConfiguration metricsConfiguration() { ? p2PDiscoveryOptions.autoDiscoverDefaultIP().getHostAddress() : metricsOptions.getMetricsPushHost()) .hostsAllowlist(hostsAllowlist); - return metricsConfigurationBuilder.build(); + final var metricsConfiguration = metricsConfigurationBuilder.build(); + metricCategoryRegistry.setMetricsConfiguration(metricsConfiguration); + return metricsConfiguration; } private PrivacyParameters privacyParameters() { @@ -1924,6 +1942,7 @@ private PrivacyParameters privacyParameters() { final PrivacyParameters.Builder privacyParametersBuilder = new PrivacyParameters.Builder(); if (Boolean.TRUE.equals(privacyOptionGroup.isPrivacyEnabled)) { + logger.warn("--privacy-enabled and related options are " + PRIVACY_DEPRECATION_PREFIX); final String errorSuffix = "cannot be enabled with privacy."; if (syncMode == SyncMode.FAST) { throw new ParameterException(commandLine, String.format("%s %s", "Fast sync", errorSuffix)); @@ -2119,7 +2138,7 @@ private TransactionPoolConfiguration buildTransactionPoolConfiguration() { return txPoolConfBuilder.build(); } - private MiningParameters getMiningParameters() { + private MiningConfiguration getMiningParameters() { miningOptions.setTransactionSelectionService(transactionSelectionServiceImpl); final var miningParameters = miningOptions.toDomainObject(); getGenesisBlockPeriodSeconds(genesisConfigOptionsSupplier.get()) @@ -2128,6 +2147,11 @@ private MiningParameters getMiningParameters() { return miningParameters; } + private ApiConfiguration getApiConfiguration() { + validateApiOptions(); + return apiConfigurationOptions.apiConfiguration(); + } + /** * Get the data storage configuration * @@ -2139,35 +2163,40 @@ public DataStorageConfiguration getDataStorageConfiguration() { } if (SyncMode.FULL.equals(getDefaultSyncModeIfNotSet()) - && DataStorageFormat.BONSAI.equals(dataStorageConfiguration.getDataStorageFormat()) - && dataStorageConfiguration.getBonsaiLimitTrieLogsEnabled()) { + && DataStorageFormat.BONSAI.equals(dataStorageConfiguration.getDataStorageFormat())) { + final DiffBasedSubStorageConfiguration diffBasedSubStorageConfiguration = + dataStorageConfiguration.getDiffBasedSubStorageConfiguration(); + if (diffBasedSubStorageConfiguration.getLimitTrieLogsEnabled()) { + if (CommandLineUtils.isOptionSet( + commandLine, DiffBasedSubStorageOptions.LIMIT_TRIE_LOGS_ENABLED)) { + throw new ParameterException( + commandLine, + String.format( + "Cannot enable %s with --sync-mode=%s and --data-storage-format=%s. You must set %s or use a different sync-mode", + DiffBasedSubStorageOptions.LIMIT_TRIE_LOGS_ENABLED, + SyncMode.FULL, + DataStorageFormat.BONSAI, + DiffBasedSubStorageOptions.LIMIT_TRIE_LOGS_ENABLED + "=false")); + } - if (CommandLineUtils.isOptionSet( - commandLine, DataStorageOptions.BONSAI_LIMIT_TRIE_LOGS_ENABLED)) { - throw new ParameterException( - commandLine, - String.format( - "Cannot enable %s with --sync-mode=%s and --data-storage-format=%s. You must set %s or use a different sync-mode", - DataStorageOptions.BONSAI_LIMIT_TRIE_LOGS_ENABLED, - SyncMode.FULL, - DataStorageFormat.BONSAI, - DataStorageOptions.BONSAI_LIMIT_TRIE_LOGS_ENABLED + "=false")); + dataStorageConfiguration = + ImmutableDataStorageConfiguration.copyOf(dataStorageConfiguration) + .withDiffBasedSubStorageConfiguration( + ImmutableDiffBasedSubStorageConfiguration.copyOf( + dataStorageConfiguration.getDiffBasedSubStorageConfiguration()) + .withLimitTrieLogsEnabled(false)); + logger.warn( + "Forcing {}, since it cannot be enabled with --sync-mode={} and --data-storage-format={}.", + DiffBasedSubStorageOptions.LIMIT_TRIE_LOGS_ENABLED + "=false", + SyncMode.FULL, + DataStorageFormat.BONSAI); } - - dataStorageConfiguration = - ImmutableDataStorageConfiguration.copyOf(dataStorageConfiguration) - .withBonsaiLimitTrieLogsEnabled(false); - logger.warn( - "Forcing {}, since it cannot be enabled with --sync-mode={} and --data-storage-format={}.", - DataStorageOptions.BONSAI_LIMIT_TRIE_LOGS_ENABLED + "=false", - SyncMode.FULL, - DataStorageFormat.BONSAI); } return dataStorageConfiguration; } - private void initMiningParametersMetrics(final MiningParameters miningParameters) { - new MiningParametersMetrics(getMetricsSystem(), miningParameters); + private void initMiningParametersMetrics(final MiningConfiguration miningConfiguration) { + new MiningParametersMetrics(getMetricsSystem(), miningConfiguration); } private OptionalInt getGenesisBlockPeriodSeconds( @@ -2191,7 +2220,6 @@ private OptionalInt getGenesisBlockPeriodSeconds( private Runner synchronize( final BesuController controller, final boolean p2pEnabled, - final Optional p2pTLSConfiguration, final boolean peerDiscoveryEnabled, final EthNetworkConfig ethNetworkConfig, final String p2pAdvertisedHost, @@ -2211,8 +2239,6 @@ private Runner synchronize( checkNotNull(runnerBuilder); - p2pTLSConfiguration.ifPresent(runnerBuilder::p2pTLSConfiguration); - final Runner runner = runnerBuilder .vertx(vertx) @@ -2728,12 +2754,14 @@ private String generateConfigurationOverview() { builder.setHighSpecEnabled(); } - if (DataStorageFormat.BONSAI.equals(getDataStorageConfiguration().getDataStorageFormat()) - && getDataStorageConfiguration().getBonsaiLimitTrieLogsEnabled()) { - builder.setLimitTrieLogsEnabled(); - builder.setTrieLogRetentionLimit(getDataStorageConfiguration().getBonsaiMaxLayersToLoad()); - builder.setTrieLogsPruningWindowSize( - getDataStorageConfiguration().getBonsaiTrieLogPruningWindowSize()); + if (DataStorageFormat.BONSAI.equals(getDataStorageConfiguration().getDataStorageFormat())) { + final DiffBasedSubStorageConfiguration subStorageConfiguration = + getDataStorageConfiguration().getDiffBasedSubStorageConfiguration(); + if (subStorageConfiguration.getLimitTrieLogsEnabled()) { + builder.setLimitTrieLogsEnabled(); + builder.setTrieLogRetentionLimit(subStorageConfiguration.getMaxLayersToLoad()); + builder.setTrieLogsPruningWindowSize(subStorageConfiguration.getTrieLogPruningWindowSize()); + } } builder.setSnapServerEnabled(this.unstableSynchronizerOptions.isSnapsyncServerEnabled()); 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 78f782d5e55..ac1de0b5252 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java @@ -279,6 +279,7 @@ public void initMocks() throws Exception { when(mockControllerBuilder.isRevertReasonEnabled(false)).thenReturn(mockControllerBuilder); when(mockControllerBuilder.isParallelTxProcessingEnabled(false)) .thenReturn(mockControllerBuilder); + when(mockControllerBuilder.isEarlyRoundChangeEnabled(false)).thenReturn(mockControllerBuilder); when(mockControllerBuilder.storageProvider(any())).thenReturn(mockControllerBuilder); when(mockControllerBuilder.gasLimitCalculator(any())).thenReturn(mockControllerBuilder); when(mockControllerBuilder.requiredBlocks(any())).thenReturn(mockControllerBuilder);