From 7d5988d4b5aa9db12827f2256fb575ddd3ea6246 Mon Sep 17 00:00:00 2001 From: Gabriel Fukushima Date: Wed, 21 Dec 2022 15:04:08 +1100 Subject: [PATCH] PoS checkpoint sync (#4844) Signed-off-by: Gabriel Fukushima --- .../dsl/node/ThreadBesuNodeRunner.java | 7 +- .../org/hyperledger/besu/cli/BesuCommand.java | 50 ++++++- .../options/unstable/SynchronizerOptions.java | 11 ++ .../besu/controller/BesuController.java | 48 +++++-- .../MergeBesuControllerBuilder.java | 10 +- .../hyperledger/besu/PrivacyReorgTest.java | 3 +- .../org/hyperledger/besu/PrivacyTest.java | 3 +- .../chainexport/RlpBlockExporterTest.java | 3 +- .../chainimport/JsonBlockImporterTest.java | 3 +- .../chainimport/RlpBlockImporterTest.java | 9 +- .../hyperledger/besu/cli/BesuCommandTest.java | 133 ++++++++++++++---- .../besu/cli/CommandTestAbstract.java | 2 +- .../besu/controller/BesuControllerTest.java | 68 ++++++++- ...eckpoint_total_difficulty_same_as_TTD.json | 56 ++++++++ .../invalid_post_merge_merge_at_genesis.json | 56 ++++++++ ...valid_post_merge_near_head_checkpoint.json | 55 ++++++++ ...valid_post_merge_near_head_checkpoint.json | 56 ++++++++ .../besu/consensus/merge/MergeContext.java | 2 + .../consensus/merge/PostMergeContext.java | 16 ++- .../consensus/merge/TransitionContext.java | 5 + .../consensus/merge/PostMergeContextTest.java | 26 ++++ .../engine/EngineForkchoiceUpdated.java | 3 +- .../methods/engine/EngineNewPayload.java | 3 +- .../besu/ethereum/eth/sync/SyncMode.java | 4 + .../eth/sync/SynchronizerConfiguration.java | 22 ++- 25 files changed, 592 insertions(+), 62 deletions(-) create mode 100644 besu/src/test/resources/invalid_post_merge_checkpoint_total_difficulty_same_as_TTD.json create mode 100644 besu/src/test/resources/invalid_post_merge_merge_at_genesis.json create mode 100644 besu/src/test/resources/invalid_post_merge_near_head_checkpoint.json create mode 100644 besu/src/test/resources/valid_post_merge_near_head_checkpoint.json 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 267d6f1f97..12456d1b15 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 org.hyperledger.besu.services.StorageServiceImpl; 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 class ThreadBesuNodeRunner implements BesuNodeRunner { .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 708e92cf03..21858bd37b 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.BesuCommandCustomFactory; 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 @@ public class BesuCommand implements DefaultCommandValues, Runnable { ensureValidPeerBoundParams(); validateRpcOptionsParams(); validateChainDataPruningParams(); + validatePostMergeCheckpointBlockRequirements(); p2pTLSConfigOptions.checkP2PTLSOptionsDependencies(logger, commandLine); pkiBlockCreationOptions.checkPkiBlockCreationOptionsDependencies(logger, commandLine); } @@ -2003,6 +2005,12 @@ public class BesuCommand implements DefaultCommandValues, Runnable { !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 class BesuCommand implements DefaultCommandValues, Runnable { 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 @@ public class BesuCommand implements DefaultCommandValues, Runnable { .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 4b125c4c44..0492bd8ba1 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