diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java index 267d6f1f97d..12456d1b152 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java @@ -58,6 +58,7 @@ import java.io.File; import java.nio.file.Path; import java.time.Clock; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -147,8 +148,12 @@ public void startNode(final BesuNode node) { .setBootNodes(bootnodes); node.getConfiguration().getGenesisConfig().ifPresent(networkConfigBuilder::setGenesisConfig); final EthNetworkConfig ethNetworkConfig = networkConfigBuilder.build(); + final SynchronizerConfiguration synchronizerConfiguration = + new SynchronizerConfiguration.Builder().build(); final BesuControllerBuilder builder = - new BesuController.Builder().fromEthNetworkConfig(ethNetworkConfig); + new BesuController.Builder() + .fromEthNetworkConfig( + ethNetworkConfig, Collections.emptyMap(), synchronizerConfiguration.getSyncMode()); final KeyValueStorageProvider storageProvider = new KeyValueStorageProviderBuilder() 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 708e92cf03a..21858bd37bb 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -85,6 +85,7 @@ import org.hyperledger.besu.cli.util.CommandLineUtils; import org.hyperledger.besu.cli.util.ConfigOptionSearchAndRunHandler; import org.hyperledger.besu.cli.util.VersionProvider; +import org.hyperledger.besu.config.CheckpointConfigOptions; import org.hyperledger.besu.config.GenesisConfigFile; import org.hyperledger.besu.config.GenesisConfigOptions; import org.hyperledger.besu.config.GoQuorumOptions; @@ -1780,6 +1781,7 @@ private void validateOptions() { ensureValidPeerBoundParams(); validateRpcOptionsParams(); validateChainDataPruningParams(); + validatePostMergeCheckpointBlockRequirements(); p2pTLSConfigOptions.checkP2PTLSOptionsDependencies(logger, commandLine); pkiBlockCreationOptions.checkPkiBlockCreationOptionsDependencies(logger, commandLine); } @@ -2003,6 +2005,12 @@ private void issueOptionWarnings() { !SyncMode.isFullSync(getDefaultSyncModeIfNotSet(syncMode)), singletonList("--fast-sync-min-peers")); + CommandLineUtils.failIfOptionDoesntMeetRequirement( + commandLine, + "--Xcheckpoint-post-merge-enabled can only be used with X_CHECKPOINT sync-mode", + SyncMode.X_CHECKPOINT.equals(getDefaultSyncModeIfNotSet(syncMode)), + singletonList("--Xcheckpoint-post-merge-enabled")); + if (!securityModuleName.equals(DEFAULT_SECURITY_MODULE) && nodePrivateKeyFileOption.getNodePrivateKeyFile() != null) { logger.warn( @@ -2156,7 +2164,7 @@ public BesuController buildController() { public BesuControllerBuilder getControllerBuilder() { final KeyValueStorageProvider storageProvider = keyValueStorageProvider(keyValueStorageName); return controllerBuilderFactory - .fromEthNetworkConfig(updateNetworkConfig(network), genesisConfigOverrides) + .fromEthNetworkConfig(updateNetworkConfig(network), genesisConfigOverrides, syncMode) .synchronizerConfiguration(buildSyncConfig()) .ethProtocolConfiguration(unstableEthProtocolOptions.toDomainObject()) .dataDirectory(dataDir()) @@ -3344,6 +3352,46 @@ private void setMergeConfigOptions() { .isPresent()); } + private void validatePostMergeCheckpointBlockRequirements() { + final GenesisConfigOptions genesisOptions = + Optional.ofNullable(genesisConfigOptions) + .orElseGet( + () -> + GenesisConfigFile.fromConfig( + genesisConfig(Optional.ofNullable(network).orElse(MAINNET))) + .getConfigOptions(genesisConfigOverrides)); + final SynchronizerConfiguration synchronizerConfiguration = + unstableSynchronizerOptions.toDomainObject().build(); + final Optional terminalTotalDifficulty = genesisOptions.getTerminalTotalDifficulty(); + final CheckpointConfigOptions checkpointConfigOptions = genesisOptions.getCheckpointOptions(); + if (synchronizerConfiguration.isCheckpointPostMergeEnabled()) { + if (!checkpointConfigOptions.isValid()) { + throw new InvalidConfigurationException( + "Near head checkpoint sync requires a checkpoint block configured in the genesis file"); + } + terminalTotalDifficulty.ifPresentOrElse( + ttd -> { + if (UInt256.fromHexString( + genesisOptions.getCheckpointOptions().getTotalDifficulty().get()) + .equals(UInt256.ZERO) + && ttd.equals(UInt256.ZERO)) { + throw new InvalidConfigurationException( + "Post Merge checkpoint sync can't be used with TTD = 0 and checkpoint totalDifficulty = 0"); + } + if (UInt256.fromHexString( + genesisOptions.getCheckpointOptions().getTotalDifficulty().get()) + .lessOrEqualThan(ttd)) { + throw new InvalidConfigurationException( + "Near head checkpoint sync requires a block with total difficulty greater than the TTD"); + } + }, + () -> { + throw new InvalidConfigurationException( + "Near head checkpoint sync requires TTD in the genesis file"); + }); + } + } + private boolean isMergeEnabled() { return MergeConfigOptions.isMergeEnabled(); } diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/SynchronizerOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/SynchronizerOptions.java index 4b125c4c445..0492bd8ba1c 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/SynchronizerOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/SynchronizerOptions.java @@ -72,6 +72,8 @@ public class SynchronizerOptions implements CLIOptions