PoS checkpoint sync (#4844)

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>
pull/4854/head
Gabriel Fukushima 2 years ago committed by GitHub
parent d3b6b32fdd
commit 7d5988d4b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java
  2. 50
      besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
  3. 11
      besu/src/main/java/org/hyperledger/besu/cli/options/unstable/SynchronizerOptions.java
  4. 38
      besu/src/main/java/org/hyperledger/besu/controller/BesuController.java
  5. 10
      besu/src/main/java/org/hyperledger/besu/controller/MergeBesuControllerBuilder.java
  6. 3
      besu/src/test/java/org/hyperledger/besu/PrivacyReorgTest.java
  7. 3
      besu/src/test/java/org/hyperledger/besu/PrivacyTest.java
  8. 3
      besu/src/test/java/org/hyperledger/besu/chainexport/RlpBlockExporterTest.java
  9. 3
      besu/src/test/java/org/hyperledger/besu/chainimport/JsonBlockImporterTest.java
  10. 9
      besu/src/test/java/org/hyperledger/besu/chainimport/RlpBlockImporterTest.java
  11. 133
      besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java
  12. 2
      besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java
  13. 68
      besu/src/test/java/org/hyperledger/besu/controller/BesuControllerTest.java
  14. 56
      besu/src/test/resources/invalid_post_merge_checkpoint_total_difficulty_same_as_TTD.json
  15. 56
      besu/src/test/resources/invalid_post_merge_merge_at_genesis.json
  16. 55
      besu/src/test/resources/invalid_post_merge_near_head_checkpoint.json
  17. 56
      besu/src/test/resources/valid_post_merge_near_head_checkpoint.json
  18. 2
      consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeContext.java
  19. 16
      consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/PostMergeContext.java
  20. 5
      consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionContext.java
  21. 26
      consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/PostMergeContextTest.java
  22. 3
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineForkchoiceUpdated.java
  23. 3
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayload.java
  24. 4
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/SyncMode.java
  25. 22
      ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/SynchronizerConfiguration.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()

@ -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<UInt256> 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();
}

@ -72,6 +72,8 @@ public class SynchronizerOptions implements CLIOptions<SynchronizerConfiguration
private static final String SNAP_TRIENODE_COUNT_PER_REQUEST_FLAG =
"--Xsnapsync-synchronizer-trienode-count-per-request";
private static final String CHECKPOINT_POST_MERGE_FLAG = "--Xcheckpoint-post-merge-enabled";
@CommandLine.Option(
names = BLOCK_PROPAGATION_RANGE_FLAG,
hidden = true,
@ -272,6 +274,13 @@ public class SynchronizerOptions implements CLIOptions<SynchronizerConfiguration
private int snapsyncTrieNodeCountPerRequest =
SnapSyncConfiguration.DEFAULT_TRIENODE_COUNT_PER_REQUEST;
@CommandLine.Option(
names = {CHECKPOINT_POST_MERGE_FLAG},
hidden = true,
description = "Enable the sync to start from a post-merge block.")
private Boolean checkpointPostMergeSyncEnabled =
SynchronizerConfiguration.DEFAULT_CHECKPOINT_POST_MERGE_ENABLED;
private SynchronizerOptions() {}
public static SynchronizerOptions create() {
@ -308,6 +317,7 @@ public class SynchronizerOptions implements CLIOptions<SynchronizerConfiguration
config.getSnapSyncConfiguration().getBytecodeCountPerRequest();
options.snapsyncTrieNodeCountPerRequest =
config.getSnapSyncConfiguration().getTrienodeCountPerRequest();
options.checkpointPostMergeSyncEnabled = config.isCheckpointPostMergeEnabled();
return options;
}
@ -338,6 +348,7 @@ public class SynchronizerOptions implements CLIOptions<SynchronizerConfiguration
.bytecodeCountPerRequest(snapsyncBytecodeCountPerRequest)
.trienodeCountPerRequest(snapsyncTrieNodeCountPerRequest)
.build());
builder.checkpointPostMergeEnabled(checkpointPostMergeSyncEnabled);
return builder;
}

@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.controller;
import static org.hyperledger.besu.ethereum.eth.sync.SyncMode.isCheckpointSync;
import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.config.GenesisConfigOptions;
@ -28,6 +30,7 @@ import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.core.Synchronizer;
import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager;
import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
import org.hyperledger.besu.ethereum.eth.sync.state.SyncState;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
@ -41,6 +44,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.tuweni.units.bigints.UInt256;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -171,24 +175,26 @@ public class BesuController implements java.io.Closeable {
public static class Builder {
public BesuControllerBuilder fromEthNetworkConfig(final EthNetworkConfig ethNetworkConfig) {
return fromEthNetworkConfig(ethNetworkConfig, Collections.emptyMap());
}
public BesuControllerBuilder fromEthNetworkConfig(
final EthNetworkConfig ethNetworkConfig, final Map<String, String> genesisConfigOverrides) {
final EthNetworkConfig ethNetworkConfig,
final Map<String, String> genesisConfigOverrides,
final SyncMode syncMode) {
return fromGenesisConfig(
GenesisConfigFile.fromConfig(ethNetworkConfig.getGenesisConfig()),
genesisConfigOverrides)
genesisConfigOverrides,
syncMode)
.networkId(ethNetworkConfig.getNetworkId());
}
public BesuControllerBuilder fromGenesisConfig(final GenesisConfigFile genesisConfig) {
return fromGenesisConfig(genesisConfig, Collections.emptyMap());
public BesuControllerBuilder fromGenesisConfig(
final GenesisConfigFile genesisConfig, final SyncMode syncMode) {
return fromGenesisConfig(genesisConfig, Collections.emptyMap(), syncMode);
}
BesuControllerBuilder fromGenesisConfig(
final GenesisConfigFile genesisConfig, final Map<String, String> genesisConfigOverrides) {
final GenesisConfigFile genesisConfig,
final Map<String, String> genesisConfigOverrides,
final SyncMode syncMode) {
final GenesisConfigOptions configOptions =
genesisConfig.getConfigOptions(genesisConfigOverrides);
final BesuControllerBuilder builder;
@ -213,11 +219,17 @@ public class BesuController implements java.io.Closeable {
// wrap with TransitionBesuControllerBuilder if we have a terminal total difficulty:
if (configOptions.getTerminalTotalDifficulty().isPresent()) {
// Enable start with vanilla MergeBesuControllerBuilder for PoS checkpoint block
if (isCheckpointSync(syncMode) && isCheckpointPoSBlock(configOptions)) {
return new MergeBesuControllerBuilder().genesisConfigFile(genesisConfig);
} else {
// TODO this should be changed to vanilla MergeBesuControllerBuilder and the Transition*
// series of classes removed after we successfully transition to PoS
// https://github.com/hyperledger/besu/issues/2897
return new TransitionBesuControllerBuilder(builder, new MergeBesuControllerBuilder())
.genesisConfigFile(genesisConfig);
}
} else return builder.genesisConfigFile(genesisConfig);
}
@ -258,5 +270,13 @@ public class BesuController implements java.io.Closeable {
return startBlock;
}
private boolean isCheckpointPoSBlock(final GenesisConfigOptions configOptions) {
final UInt256 terminalTotalDifficulty = configOptions.getTerminalTotalDifficulty().get();
return configOptions.getCheckpointOptions().isValid()
&& (UInt256.fromHexString(configOptions.getCheckpointOptions().getTotalDifficulty().get())
.greaterThan(terminalTotalDifficulty));
}
}
}

@ -184,7 +184,8 @@ public class MergeBesuControllerBuilder extends BesuControllerBuilder {
.get()
.getTerminalTotalDifficulty()
.map(Difficulty::of)
.orElse(Difficulty.ZERO));
.orElse(Difficulty.ZERO))
.setCheckpointPostMergeSync(syncConfig.isCheckpointPostMergeEnabled());
blockchain
.getFinalized()
@ -235,6 +236,13 @@ public class MergeBesuControllerBuilder extends BesuControllerBuilder {
return retval;
}
@Override
public BesuController build() {
final BesuController controller = super.build();
PostMergeContext.get().setSyncState(controller.getSyncState());
return controller;
}
public TimestampSchedule createTimestampProtocolSchedule() {
return MergeProtocolSchedule.createTimestamp(
configOptionsSupplier.get(), privacyParameters, isRevertReasonEnabled);

@ -45,6 +45,7 @@ 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;
import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode;
@ -188,7 +189,7 @@ public class PrivacyReorgTest {
besuController =
new BesuController.Builder()
.fromGenesisConfig(GenesisConfigFile.development())
.fromGenesisConfig(GenesisConfigFile.development(), SyncMode.FULL)
.synchronizerConfiguration(SynchronizerConfiguration.builder().build())
.ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig())
.storageProvider(new InMemoryKeyValueStorageProvider())

@ -33,6 +33,7 @@ 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.eth.EthProtocolConfiguration;
import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.privacy.storage.PrivacyStorageProvider;
@ -107,7 +108,7 @@ public class PrivacyTest {
.setFlexiblePrivacyGroupsEnabled(flexibleEnabled)
.build();
return new BesuController.Builder()
.fromGenesisConfig(GenesisConfigFile.mainnet())
.fromGenesisConfig(GenesisConfigFile.mainnet(), SyncMode.FULL)
.synchronizerConfiguration(SynchronizerConfiguration.builder().build())
.ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig())
.storageProvider(new InMemoryKeyValueStorageProvider())

@ -30,6 +30,7 @@ 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.eth.EthProtocolConfiguration;
import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
@ -83,7 +84,7 @@ public final class RlpBlockExporterTest {
private static BesuController createController() throws IOException {
final Path dataDir = folder.newFolder().toPath();
return new BesuController.Builder()
.fromGenesisConfig(GenesisConfigFile.mainnet())
.fromGenesisConfig(GenesisConfigFile.mainnet(), SyncMode.FAST)
.synchronizerConfiguration(SynchronizerConfiguration.builder().build())
.ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig())
.storageProvider(new InMemoryKeyValueStorageProvider())

@ -34,6 +34,7 @@ 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;
import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
@ -413,7 +414,7 @@ public abstract class JsonBlockImporterTest {
throws IOException {
final Path dataDir = folder.newFolder().toPath();
return new BesuController.Builder()
.fromGenesisConfig(genesisConfigFile)
.fromGenesisConfig(genesisConfigFile, SyncMode.FAST)
.synchronizerConfiguration(SynchronizerConfiguration.builder().build())
.ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig())
.storageProvider(new InMemoryKeyValueStorageProvider())

@ -27,6 +27,7 @@ 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.eth.EthProtocolConfiguration;
import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
@ -64,7 +65,7 @@ public final class RlpBlockImporterTest {
BlockTestUtil.write1000Blocks(source);
final BesuController targetController =
new BesuController.Builder()
.fromGenesisConfig(GenesisConfigFile.mainnet())
.fromGenesisConfig(GenesisConfigFile.mainnet(), SyncMode.FAST)
.synchronizerConfiguration(SynchronizerConfiguration.builder().build())
.ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig())
.storageProvider(new InMemoryKeyValueStorageProvider())
@ -96,7 +97,7 @@ public final class RlpBlockImporterTest {
BlockTestUtil.writeBadPowBlocks(source);
final BesuController targetController =
new BesuController.Builder()
.fromGenesisConfig(GenesisConfigFile.mainnet())
.fromGenesisConfig(GenesisConfigFile.mainnet(), SyncMode.FAST)
.synchronizerConfiguration(SynchronizerConfiguration.builder().build())
.ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig())
.storageProvider(new InMemoryKeyValueStorageProvider())
@ -125,7 +126,7 @@ public final class RlpBlockImporterTest {
BlockTestUtil.writeBadPowBlocks(source);
final BesuController targetController =
new BesuController.Builder()
.fromGenesisConfig(GenesisConfigFile.mainnet())
.fromGenesisConfig(GenesisConfigFile.mainnet(), SyncMode.FAST)
.synchronizerConfiguration(SynchronizerConfiguration.builder().build())
.ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig())
.storageProvider(new InMemoryKeyValueStorageProvider())
@ -166,7 +167,7 @@ public final class RlpBlockImporterTest {
final BesuController controller =
new BesuController.Builder()
.fromGenesisConfig(GenesisConfigFile.fromConfig(config))
.fromGenesisConfig(GenesisConfigFile.fromConfig(config), SyncMode.FULL)
.synchronizerConfiguration(SynchronizerConfiguration.builder().build())
.ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig())
.storageProvider(new InMemoryKeyValueStorageProvider())

@ -105,6 +105,7 @@ import java.math.BigInteger;
import java.net.ServerSocket;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@ -258,7 +259,8 @@ public class BesuCommandTest extends CommandTestAbstract {
verify(mockRunnerBuilder).rpcMaxLogsRange(eq(1000L));
verify(mockRunnerBuilder).build();
verify(mockControllerBuilderFactory).fromEthNetworkConfig(ethNetworkArg.capture(), any());
verify(mockControllerBuilderFactory)
.fromEthNetworkConfig(ethNetworkArg.capture(), any(), any());
final ArgumentCaptor<MiningParameters> miningArg =
ArgumentCaptor.forClass(MiningParameters.class);
verify(mockControllerBuilder).synchronizerConfiguration(syncConfigurationCaptor.capture());
@ -420,7 +422,7 @@ public class BesuCommandTest extends CommandTestAbstract {
.setDnsDiscoveryUrl(null)
.build();
verify(mockControllerBuilder).dataDirectory(eq(dataFolder.toPath()));
verify(mockControllerBuilderFactory).fromEthNetworkConfig(eq(networkConfig), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(eq(networkConfig), any(), any());
verify(mockControllerBuilder).synchronizerConfiguration(syncConfigurationCaptor.capture());
assertThat(syncConfigurationCaptor.getValue().getSyncMode()).isEqualTo(SyncMode.FAST);
@ -966,7 +968,7 @@ public class BesuCommandTest extends CommandTestAbstract {
parseCommand("--genesis-file", genesisFile.toString());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
assertThat(networkArg.getValue().getGenesisConfig())
@ -985,7 +987,7 @@ public class BesuCommandTest extends CommandTestAbstract {
parseCommand("--genesis-file", genesisFile.toString());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
final EthNetworkConfig config = networkArg.getValue();
@ -1001,7 +1003,7 @@ public class BesuCommandTest extends CommandTestAbstract {
parseCommand("--network", "mainnet");
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
final EthNetworkConfig config = networkArg.getValue();
@ -1019,7 +1021,7 @@ public class BesuCommandTest extends CommandTestAbstract {
parseCommand("--network", "goerli");
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
final EthNetworkConfig config = networkArg.getValue();
@ -1035,7 +1037,7 @@ public class BesuCommandTest extends CommandTestAbstract {
parseCommand("--network", "rinkeby");
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
final EthNetworkConfig config = networkArg.getValue();
@ -1051,7 +1053,7 @@ public class BesuCommandTest extends CommandTestAbstract {
parseCommand("--network", "shandong");
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
final EthNetworkConfig config = networkArg.getValue();
@ -1094,7 +1096,7 @@ public class BesuCommandTest extends CommandTestAbstract {
"--discovery-dns-url",
"enrtree://AM5FCQLWIZX2QFPNJAP7VUERCCRNGRHWZG3YYHIUV7BVDQ5FDPRT2@nodes.example.org");
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
final EthNetworkConfig config = networkArg.getValue();
@ -1114,7 +1116,7 @@ public class BesuCommandTest extends CommandTestAbstract {
"--discovery-dns-url",
"enrtree://AM5FCQLWIZX2QFPNJAP7VUERCCRNGRHWZG3YYHIUV7BVDQ5FDPRT2@nodes.example.org");
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
final EthNetworkConfig config = networkArg.getValue();
@ -1132,7 +1134,7 @@ public class BesuCommandTest extends CommandTestAbstract {
final ArgumentCaptor<EthNetworkConfig> networkArg =
ArgumentCaptor.forClass(EthNetworkConfig.class);
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
assertThat(networkArg.getValue().getGenesisConfig())
@ -1153,7 +1155,7 @@ public class BesuCommandTest extends CommandTestAbstract {
final ArgumentCaptor<EthNetworkConfig> networkArg =
ArgumentCaptor.forClass(EthNetworkConfig.class);
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
assertThat(networkArg.getValue().getGenesisConfig())
@ -1309,7 +1311,7 @@ public class BesuCommandTest extends CommandTestAbstract {
final ArgumentCaptor<EthNetworkConfig> networkArg =
ArgumentCaptor.forClass(EthNetworkConfig.class);
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
final EthNetworkConfig config = networkArg.getValue();
@ -1331,7 +1333,7 @@ public class BesuCommandTest extends CommandTestAbstract {
final ArgumentCaptor<EthNetworkConfig> networkArg =
ArgumentCaptor.forClass(EthNetworkConfig.class);
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
final EthNetworkConfig config = networkArg.getValue();
@ -1350,7 +1352,7 @@ public class BesuCommandTest extends CommandTestAbstract {
final ArgumentCaptor<EthNetworkConfig> networkArg =
ArgumentCaptor.forClass(EthNetworkConfig.class);
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
final EthNetworkConfig config = networkArg.getValue();
@ -3910,7 +3912,7 @@ public class BesuCommandTest extends CommandTestAbstract {
final ArgumentCaptor<EthNetworkConfig> networkArg =
ArgumentCaptor.forClass(EthNetworkConfig.class);
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
assertThat(networkArg.getValue()).isEqualTo(EthNetworkConfig.getNetworkConfig(DEV));
@ -3926,7 +3928,7 @@ public class BesuCommandTest extends CommandTestAbstract {
final ArgumentCaptor<EthNetworkConfig> networkArg =
ArgumentCaptor.forClass(EthNetworkConfig.class);
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
assertThat(networkArg.getValue()).isEqualTo(EthNetworkConfig.getNetworkConfig(RINKEBY));
@ -3944,7 +3946,7 @@ public class BesuCommandTest extends CommandTestAbstract {
final ArgumentCaptor<EthNetworkConfig> networkArg =
ArgumentCaptor.forClass(EthNetworkConfig.class);
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
assertThat(networkArg.getValue()).isEqualTo(EthNetworkConfig.getNetworkConfig(ROPSTEN));
@ -3962,7 +3964,7 @@ public class BesuCommandTest extends CommandTestAbstract {
final ArgumentCaptor<EthNetworkConfig> networkArg =
ArgumentCaptor.forClass(EthNetworkConfig.class);
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
assertThat(networkArg.getValue()).isEqualTo(EthNetworkConfig.getNetworkConfig(KILN));
@ -3980,7 +3982,7 @@ public class BesuCommandTest extends CommandTestAbstract {
final ArgumentCaptor<EthNetworkConfig> networkArg =
ArgumentCaptor.forClass(EthNetworkConfig.class);
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
assertThat(networkArg.getValue()).isEqualTo(EthNetworkConfig.getNetworkConfig(GOERLI));
@ -3998,7 +4000,7 @@ public class BesuCommandTest extends CommandTestAbstract {
final ArgumentCaptor<EthNetworkConfig> networkArg =
ArgumentCaptor.forClass(EthNetworkConfig.class);
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
assertThat(networkArg.getValue()).isEqualTo(EthNetworkConfig.getNetworkConfig(SEPOLIA));
@ -4016,7 +4018,7 @@ public class BesuCommandTest extends CommandTestAbstract {
final ArgumentCaptor<EthNetworkConfig> networkArg =
ArgumentCaptor.forClass(EthNetworkConfig.class);
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
assertThat(networkArg.getValue()).isEqualTo(EthNetworkConfig.getNetworkConfig(SHANDONG));
@ -4034,7 +4036,7 @@ public class BesuCommandTest extends CommandTestAbstract {
final ArgumentCaptor<EthNetworkConfig> networkArg =
ArgumentCaptor.forClass(EthNetworkConfig.class);
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
assertThat(networkArg.getValue()).isEqualTo(EthNetworkConfig.getNetworkConfig(CLASSIC));
@ -4050,7 +4052,7 @@ public class BesuCommandTest extends CommandTestAbstract {
final ArgumentCaptor<EthNetworkConfig> networkArg =
ArgumentCaptor.forClass(EthNetworkConfig.class);
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
assertThat(networkArg.getValue()).isEqualTo(EthNetworkConfig.getNetworkConfig(KOTTI));
@ -4066,7 +4068,7 @@ public class BesuCommandTest extends CommandTestAbstract {
final ArgumentCaptor<EthNetworkConfig> networkArg =
ArgumentCaptor.forClass(EthNetworkConfig.class);
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
assertThat(networkArg.getValue()).isEqualTo(EthNetworkConfig.getNetworkConfig(MORDOR));
@ -4126,7 +4128,7 @@ public class BesuCommandTest extends CommandTestAbstract {
final ArgumentCaptor<EthNetworkConfig> networkArg =
ArgumentCaptor.forClass(EthNetworkConfig.class);
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any());
verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any(), any());
verify(mockControllerBuilder).build();
assertThat(networkArg.getValue().getBootNodes())
@ -5476,4 +5478,83 @@ public class BesuCommandTest extends CommandTestAbstract {
.startsWith(
"Missing required option: '--accept-terms-and-conditions=<acceptTermsAndConditions>'");
}
@Test
public void checkpointPostMergeShouldFailWhenGenesisHasNoTTD() throws IOException {
final String configText =
Resources.toString(
Resources.getResource("invalid_post_merge_near_head_checkpoint.json"),
StandardCharsets.UTF_8);
final Path genesisFile = createFakeGenesisFile(new JsonObject(configText));
parseCommand(
"--genesis-file",
genesisFile.toString(),
"--sync-mode",
"X_CHECKPOINT",
"--Xcheckpoint-post-merge-enabled");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8))
.contains("Near head checkpoint sync requires TTD in the genesis file");
}
@Test
public void checkpointPostMergeShouldFailWhenGenesisUsesCheckpointFromPreMerge() {
// using the default genesis which has a checkpoint sync block prior to the merge
parseCommand("--sync-mode", "X_CHECKPOINT", "--Xcheckpoint-post-merge-enabled");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8))
.contains(
"Near head checkpoint sync requires a block with total difficulty greater than the TTD");
}
@Test
public void checkpointPostMergeShouldFailWhenSyncModeIsNotCheckpoint() {
parseCommand("--sync-mode", "X_SNAP", "--Xcheckpoint-post-merge-enabled");
assertThat(commandErrorOutput.toString(UTF_8))
.contains("--Xcheckpoint-post-merge-enabled can only be used with X_CHECKPOINT sync-mode");
}
@Test
public void checkpointPostMergeWithPostMergeBlockSucceeds() throws IOException {
final String configText =
Resources.toString(
Resources.getResource("valid_post_merge_near_head_checkpoint.json"),
StandardCharsets.UTF_8);
final Path genesisFile = createFakeGenesisFile(new JsonObject(configText));
parseCommand(
"--genesis-file",
genesisFile.toString(),
"--sync-mode",
"X_CHECKPOINT",
"--Xcheckpoint-post-merge-enabled");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void checkpointMergeAtGenesisWithGenesisBlockDifficultyZeroFails() throws IOException {
final String configText =
Resources.toString(
Resources.getResource("invalid_post_merge_merge_at_genesis.json"),
StandardCharsets.UTF_8);
final Path genesisFile = createFakeGenesisFile(new JsonObject(configText));
parseCommand(
"--genesis-file",
genesisFile.toString(),
"--sync-mode",
"X_CHECKPOINT",
"--Xcheckpoint-post-merge-enabled");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8))
.contains(
"Post Merge checkpoint sync can't be used with TTD = 0 and checkpoint totalDifficulty = 0");
}
}

@ -200,7 +200,7 @@ public abstract class CommandTestAbstract {
// doReturn used because of generic BesuController
doReturn(mockControllerBuilder)
.when(mockControllerBuilderFactory)
.fromEthNetworkConfig(any(), any());
.fromEthNetworkConfig(any(), any(), any());
when(mockControllerBuilder.synchronizerConfiguration(any())).thenReturn(mockControllerBuilder);
when(mockControllerBuilder.ethProtocolConfiguration(any())).thenReturn(mockControllerBuilder);
when(mockControllerBuilder.transactionPoolConfiguration(any()))

@ -27,11 +27,16 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.config.GenesisConfigOptions;
import org.hyperledger.besu.config.QbftConfigOptions;
import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import java.util.OptionalLong;
import com.google.common.io.Resources;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@ -48,7 +53,8 @@ public class BesuControllerTest {
@Test
public void missingQbftStartBlock() {
mockGenesisConfigForMigration("ibft2", OptionalLong.empty());
assertThatThrownBy(() -> new BesuController.Builder().fromGenesisConfig(genesisConfigFile))
assertThatThrownBy(
() -> new BesuController.Builder().fromGenesisConfig(genesisConfigFile, SyncMode.FULL))
.isInstanceOf(IllegalStateException.class)
.hasMessage("Missing QBFT startBlock config in genesis file");
}
@ -56,7 +62,8 @@ public class BesuControllerTest {
@Test
public void invalidQbftStartBlock() {
mockGenesisConfigForMigration("ibft2", OptionalLong.of(-1L));
assertThatThrownBy(() -> new BesuController.Builder().fromGenesisConfig(genesisConfigFile))
assertThatThrownBy(
() -> new BesuController.Builder().fromGenesisConfig(genesisConfigFile, SyncMode.FULL))
.isInstanceOf(IllegalStateException.class)
.hasMessage("Invalid QBFT startBlock config in genesis file");
}
@ -67,7 +74,8 @@ public class BesuControllerTest {
when(genesisConfigOptions.isConsensusMigration()).thenReturn(true);
// explicitly not setting isIbftLegacy() or isIbft2() for genesisConfigOptions
assertThatThrownBy(() -> new BesuController.Builder().fromGenesisConfig(genesisConfigFile))
assertThatThrownBy(
() -> new BesuController.Builder().fromGenesisConfig(genesisConfigFile, SyncMode.FULL))
.isInstanceOf(IllegalStateException.class)
.hasMessage(
"Invalid genesis migration config. Migration is supported from IBFT (legacy) or IBFT2 to QBFT)");
@ -79,7 +87,7 @@ public class BesuControllerTest {
mockGenesisConfigForMigration("ibft2", OptionalLong.of(qbftStartBlock));
final BesuControllerBuilder besuControllerBuilder =
new BesuController.Builder().fromGenesisConfig(genesisConfigFile);
new BesuController.Builder().fromGenesisConfig(genesisConfigFile, SyncMode.FULL);
assertThat(besuControllerBuilder).isInstanceOf(ConsensusScheduleBesuControllerBuilder.class);
@ -99,7 +107,7 @@ public class BesuControllerTest {
mockGenesisConfigForMigration("ibftLegacy", OptionalLong.of(qbftStartBlock));
final BesuControllerBuilder besuControllerBuilder =
new BesuController.Builder().fromGenesisConfig(genesisConfigFile);
new BesuController.Builder().fromGenesisConfig(genesisConfigFile, SyncMode.FULL);
assertThat(besuControllerBuilder).isInstanceOf(ConsensusScheduleBesuControllerBuilder.class);
@ -137,4 +145,54 @@ public class BesuControllerTest {
when(genesisConfigOptions.getQbftConfigOptions()).thenReturn(qbftConfigOptions);
when(qbftConfigOptions.getStartBlock()).thenReturn(startBlock);
}
@Test
public void postMergeCheckpointSyncUsesMergeControllerBuilder() throws IOException {
final GenesisConfigFile postMergeGenesisFile =
GenesisConfigFile.fromConfig(
Resources.toString(
Resources.getResource("valid_post_merge_near_head_checkpoint.json"),
StandardCharsets.UTF_8));
final BesuControllerBuilder besuControllerBuilder =
new BesuController.Builder()
.fromGenesisConfig(postMergeGenesisFile, Collections.emptyMap(), SyncMode.X_CHECKPOINT);
assertThat(besuControllerBuilder).isInstanceOf(MergeBesuControllerBuilder.class);
}
@Test
public void postMergeCheckpointSyncWithTotalDifficultyEqualsTTDUsesTransitionControllerBuilder()
throws IOException {
final GenesisConfigFile mergeAtGenesisFile =
GenesisConfigFile.fromConfig(
Resources.toString(
Resources.getResource(
"invalid_post_merge_checkpoint_total_difficulty_same_as_TTD.json"),
StandardCharsets.UTF_8));
final BesuControllerBuilder besuControllerBuilder =
new BesuController.Builder()
.fromGenesisConfig(mergeAtGenesisFile, Collections.emptyMap(), SyncMode.X_CHECKPOINT);
assertThat(besuControllerBuilder).isInstanceOf(TransitionBesuControllerBuilder.class);
}
@Test
public void preMergeCheckpointSyncUsesTransitionControllerBuilder() {
final BesuControllerBuilder besuControllerBuilder =
new BesuController.Builder()
.fromGenesisConfig(genesisConfigFile, Collections.emptyMap(), SyncMode.X_CHECKPOINT);
assertThat(besuControllerBuilder).isInstanceOf(TransitionBesuControllerBuilder.class);
}
@Test
public void nonCheckpointSyncUsesTransitionControllerBuild() {
final BesuControllerBuilder besuControllerBuilder =
new BesuController.Builder()
.fromGenesisConfig(genesisConfigFile, Collections.emptyMap(), SyncMode.X_SNAP);
assertThat(besuControllerBuilder).isInstanceOf(TransitionBesuControllerBuilder.class);
}
}

@ -0,0 +1,56 @@
{
"config": {
"chainId": 1,
"homesteadBlock": 1150000,
"daoForkBlock": 1920000,
"eip150Block": 2463000,
"eip158Block": 2675000,
"byzantiumBlock": 4370000,
"petersburgBlock": 7280000,
"istanbulBlock": 9069000,
"muirGlacierBlock": 9200000,
"berlinBlock": 12244000,
"londonBlock": 12965000,
"arrowGlacierBlock": 13773000,
"grayGlacierBlock": 15050000,
"terminalTotalDifficulty": 58750000000000000000000,
"ethash": {
},
"discovery": {
"dns": "enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@all.mainnet.ethdisco.net",
"bootnodes": [
"enode://d860a01f9722d78051619d1e2351aba3f43f943f6f00718d1b9baa4101932a1f5011f16bb2b1bb35db20d6fe28fa0bf09636d26a87d31de9ec6203eeedb1f666@18.138.108.67:30303",
"enode://22a8232c3abc76a16ae9d6c3b164f98775fe226f0917b0ca871128a74a8e9630b458460865bab457221f1d448dd9791d24c4e5d88786180ac185df813a68d4de@3.209.45.79:30303",
"enode://8499da03c47d637b20eee24eec3c356c9a2e6148d6fe25ca195c7949ab8ec2c03e3556126b0d7ed644675e78c4318b08691b7b57de10e5f0d40d05b09238fa0a@52.187.207.27:30303",
"enode://103858bdb88756c71f15e9b5e09b56dc1be52f0a5021d46301dbbfb7e130029cc9d0d6f73f693bc29b665770fff7da4d34f3c6379fe12721b5d7a0bcb5ca1fc1@191.234.162.198:30303",
"enode://715171f50508aba88aecd1250af392a45a330af91d7b90701c436b618c86aaa1589c9184561907bebbb56439b8f8787bc01f49a7c77276c58c1b09822d75e8e8@52.231.165.108:30303",
"enode://5d6d7cd20d6da4bb83a1d28cadb5d409b64edf314c0335df658c1a54e32c7c4a7ab7823d57c39b6a757556e68ff1df17c748b698544a55cb488b52479a92b60f@104.42.217.25:30303",
"enode://2b252ab6a1d0f971d9722cb839a42cb81db019ba44c08754628ab4a823487071b5695317c8ccd085219c3a03af063495b2f1da8d18218da2d6a82981b45e6ffc@65.108.70.101:30303",
"enode://4aeb4ab6c14b23e2c4cfdce879c04b0748a20d8e9b59e25ded2a08143e265c6c25936e74cbc8e641e3312ca288673d91f2f93f8e277de3cfa444ecdaaf982052@157.90.35.166:30303",
"enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303",
"enode://3f1d12044546b76342d59d4a05532c14b85aa669704bfe1f864fe079415aa2c02d743e03218e57a33fb94523adb54032871a6c51b2cc5514cb7c7e35b3ed0a99@13.93.211.84:30303",
"enode://78de8a0916848093c73790ead81d1928bec737d565119932b98c6b100d944b7a95e94f847f689fc723399d2e31129d182f7ef3863f2b4c820abbf3ab2722344d@191.235.84.50:30303",
"enode://158f8aab45f6d19c6cbf4a089c2670541a8da11978a2f90dbf6a502a4a3bab80d288afdbeb7ec0ef6d92de563767f3b1ea9e8e334ca711e9f8e2df5a0385e8e6@13.75.154.138:30303",
"enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303",
"enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303"
]
},
"checkpoint": {
"hash": "0x186642d6084eb7799cb01c7eb69c1a7f3b2c32cd141e62d309f30081a1ea3c91",
"number": 16015954,
"totalDifficulty": "0xC70D808A128D7380000"
}
},
"nonce": "0x42",
"timestamp": "0x0",
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"gasLimit": "0x1388",
"difficulty": "0x400000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"alloc": {
"000d836201318ec6899a67540690382780743280": {
"balance": "0xad78ebc5ac6200000"
}
}
}

@ -0,0 +1,56 @@
{
"config": {
"chainId": 1,
"homesteadBlock": 0,
"daoForkBlock": 0,
"eip150Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0,
"muirGlacierBlock": 0,
"berlinBlock": 0,
"londonBlock": 0,
"arrowGlacierBlock": 0,
"grayGlacierBlock": 0,
"terminalTotalDifficulty": 0,
"ethash": {
},
"discovery": {
"dns": "enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@all.mainnet.ethdisco.net",
"bootnodes": [
"enode://d860a01f9722d78051619d1e2351aba3f43f943f6f00718d1b9baa4101932a1f5011f16bb2b1bb35db20d6fe28fa0bf09636d26a87d31de9ec6203eeedb1f666@18.138.108.67:30303",
"enode://22a8232c3abc76a16ae9d6c3b164f98775fe226f0917b0ca871128a74a8e9630b458460865bab457221f1d448dd9791d24c4e5d88786180ac185df813a68d4de@3.209.45.79:30303",
"enode://8499da03c47d637b20eee24eec3c356c9a2e6148d6fe25ca195c7949ab8ec2c03e3556126b0d7ed644675e78c4318b08691b7b57de10e5f0d40d05b09238fa0a@52.187.207.27:30303",
"enode://103858bdb88756c71f15e9b5e09b56dc1be52f0a5021d46301dbbfb7e130029cc9d0d6f73f693bc29b665770fff7da4d34f3c6379fe12721b5d7a0bcb5ca1fc1@191.234.162.198:30303",
"enode://715171f50508aba88aecd1250af392a45a330af91d7b90701c436b618c86aaa1589c9184561907bebbb56439b8f8787bc01f49a7c77276c58c1b09822d75e8e8@52.231.165.108:30303",
"enode://5d6d7cd20d6da4bb83a1d28cadb5d409b64edf314c0335df658c1a54e32c7c4a7ab7823d57c39b6a757556e68ff1df17c748b698544a55cb488b52479a92b60f@104.42.217.25:30303",
"enode://2b252ab6a1d0f971d9722cb839a42cb81db019ba44c08754628ab4a823487071b5695317c8ccd085219c3a03af063495b2f1da8d18218da2d6a82981b45e6ffc@65.108.70.101:30303",
"enode://4aeb4ab6c14b23e2c4cfdce879c04b0748a20d8e9b59e25ded2a08143e265c6c25936e74cbc8e641e3312ca288673d91f2f93f8e277de3cfa444ecdaaf982052@157.90.35.166:30303",
"enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303",
"enode://3f1d12044546b76342d59d4a05532c14b85aa669704bfe1f864fe079415aa2c02d743e03218e57a33fb94523adb54032871a6c51b2cc5514cb7c7e35b3ed0a99@13.93.211.84:30303",
"enode://78de8a0916848093c73790ead81d1928bec737d565119932b98c6b100d944b7a95e94f847f689fc723399d2e31129d182f7ef3863f2b4c820abbf3ab2722344d@191.235.84.50:30303",
"enode://158f8aab45f6d19c6cbf4a089c2670541a8da11978a2f90dbf6a502a4a3bab80d288afdbeb7ec0ef6d92de563767f3b1ea9e8e334ca711e9f8e2df5a0385e8e6@13.75.154.138:30303",
"enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303",
"enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303"
]
},
"checkpoint": {
"hash": "0x186642d6084eb7799cb01c7eb69c1a7f3b2c32cd141e62d309f30081a1ea3c91",
"number": 1,
"totalDifficulty": "0x0"
}
},
"nonce": "0x42",
"timestamp": "0x0",
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"gasLimit": "0x1388",
"difficulty": "0x0",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"alloc": {
"000d836201318ec6899a67540690382780743280": {
"balance": "0xad78ebc5ac6200000"
}
}
}

@ -0,0 +1,55 @@
{
"config": {
"chainId": 1,
"homesteadBlock": 1150000,
"daoForkBlock": 1920000,
"eip150Block": 2463000,
"eip158Block": 2675000,
"byzantiumBlock": 4370000,
"petersburgBlock": 7280000,
"istanbulBlock": 9069000,
"muirGlacierBlock": 9200000,
"berlinBlock": 12244000,
"londonBlock": 12965000,
"arrowGlacierBlock": 13773000,
"grayGlacierBlock": 15050000,
"ethash": {
},
"discovery": {
"dns": "enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@all.mainnet.ethdisco.net",
"bootnodes": [
"enode://d860a01f9722d78051619d1e2351aba3f43f943f6f00718d1b9baa4101932a1f5011f16bb2b1bb35db20d6fe28fa0bf09636d26a87d31de9ec6203eeedb1f666@18.138.108.67:30303",
"enode://22a8232c3abc76a16ae9d6c3b164f98775fe226f0917b0ca871128a74a8e9630b458460865bab457221f1d448dd9791d24c4e5d88786180ac185df813a68d4de@3.209.45.79:30303",
"enode://8499da03c47d637b20eee24eec3c356c9a2e6148d6fe25ca195c7949ab8ec2c03e3556126b0d7ed644675e78c4318b08691b7b57de10e5f0d40d05b09238fa0a@52.187.207.27:30303",
"enode://103858bdb88756c71f15e9b5e09b56dc1be52f0a5021d46301dbbfb7e130029cc9d0d6f73f693bc29b665770fff7da4d34f3c6379fe12721b5d7a0bcb5ca1fc1@191.234.162.198:30303",
"enode://715171f50508aba88aecd1250af392a45a330af91d7b90701c436b618c86aaa1589c9184561907bebbb56439b8f8787bc01f49a7c77276c58c1b09822d75e8e8@52.231.165.108:30303",
"enode://5d6d7cd20d6da4bb83a1d28cadb5d409b64edf314c0335df658c1a54e32c7c4a7ab7823d57c39b6a757556e68ff1df17c748b698544a55cb488b52479a92b60f@104.42.217.25:30303",
"enode://2b252ab6a1d0f971d9722cb839a42cb81db019ba44c08754628ab4a823487071b5695317c8ccd085219c3a03af063495b2f1da8d18218da2d6a82981b45e6ffc@65.108.70.101:30303",
"enode://4aeb4ab6c14b23e2c4cfdce879c04b0748a20d8e9b59e25ded2a08143e265c6c25936e74cbc8e641e3312ca288673d91f2f93f8e277de3cfa444ecdaaf982052@157.90.35.166:30303",
"enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303",
"enode://3f1d12044546b76342d59d4a05532c14b85aa669704bfe1f864fe079415aa2c02d743e03218e57a33fb94523adb54032871a6c51b2cc5514cb7c7e35b3ed0a99@13.93.211.84:30303",
"enode://78de8a0916848093c73790ead81d1928bec737d565119932b98c6b100d944b7a95e94f847f689fc723399d2e31129d182f7ef3863f2b4c820abbf3ab2722344d@191.235.84.50:30303",
"enode://158f8aab45f6d19c6cbf4a089c2670541a8da11978a2f90dbf6a502a4a3bab80d288afdbeb7ec0ef6d92de563767f3b1ea9e8e334ca711e9f8e2df5a0385e8e6@13.75.154.138:30303",
"enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303",
"enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303"
]
},
"checkpoint": {
"hash": "0x186642d6084eb7799cb01c7eb69c1a7f3b2c32cd141e62d309f30081a1ea3c91",
"number": 16015954,
"totalDifficulty": "0xC70D815D562D3CFA955"
}
},
"nonce": "0x42",
"timestamp": "0x0",
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"gasLimit": "0x1388",
"difficulty": "0x400000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"alloc": {
"000d836201318ec6899a67540690382780743280": {
"balance": "0xad78ebc5ac6200000"
}
}
}

@ -0,0 +1,56 @@
{
"config": {
"chainId": 1,
"homesteadBlock": 1150000,
"daoForkBlock": 1920000,
"eip150Block": 2463000,
"eip158Block": 2675000,
"byzantiumBlock": 4370000,
"petersburgBlock": 7280000,
"istanbulBlock": 9069000,
"muirGlacierBlock": 9200000,
"berlinBlock": 12244000,
"londonBlock": 12965000,
"arrowGlacierBlock": 13773000,
"grayGlacierBlock": 15050000,
"terminalTotalDifficulty": 58750000000000000000000,
"ethash": {
},
"discovery": {
"dns": "enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@all.mainnet.ethdisco.net",
"bootnodes": [
"enode://d860a01f9722d78051619d1e2351aba3f43f943f6f00718d1b9baa4101932a1f5011f16bb2b1bb35db20d6fe28fa0bf09636d26a87d31de9ec6203eeedb1f666@18.138.108.67:30303",
"enode://22a8232c3abc76a16ae9d6c3b164f98775fe226f0917b0ca871128a74a8e9630b458460865bab457221f1d448dd9791d24c4e5d88786180ac185df813a68d4de@3.209.45.79:30303",
"enode://8499da03c47d637b20eee24eec3c356c9a2e6148d6fe25ca195c7949ab8ec2c03e3556126b0d7ed644675e78c4318b08691b7b57de10e5f0d40d05b09238fa0a@52.187.207.27:30303",
"enode://103858bdb88756c71f15e9b5e09b56dc1be52f0a5021d46301dbbfb7e130029cc9d0d6f73f693bc29b665770fff7da4d34f3c6379fe12721b5d7a0bcb5ca1fc1@191.234.162.198:30303",
"enode://715171f50508aba88aecd1250af392a45a330af91d7b90701c436b618c86aaa1589c9184561907bebbb56439b8f8787bc01f49a7c77276c58c1b09822d75e8e8@52.231.165.108:30303",
"enode://5d6d7cd20d6da4bb83a1d28cadb5d409b64edf314c0335df658c1a54e32c7c4a7ab7823d57c39b6a757556e68ff1df17c748b698544a55cb488b52479a92b60f@104.42.217.25:30303",
"enode://2b252ab6a1d0f971d9722cb839a42cb81db019ba44c08754628ab4a823487071b5695317c8ccd085219c3a03af063495b2f1da8d18218da2d6a82981b45e6ffc@65.108.70.101:30303",
"enode://4aeb4ab6c14b23e2c4cfdce879c04b0748a20d8e9b59e25ded2a08143e265c6c25936e74cbc8e641e3312ca288673d91f2f93f8e277de3cfa444ecdaaf982052@157.90.35.166:30303",
"enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303",
"enode://3f1d12044546b76342d59d4a05532c14b85aa669704bfe1f864fe079415aa2c02d743e03218e57a33fb94523adb54032871a6c51b2cc5514cb7c7e35b3ed0a99@13.93.211.84:30303",
"enode://78de8a0916848093c73790ead81d1928bec737d565119932b98c6b100d944b7a95e94f847f689fc723399d2e31129d182f7ef3863f2b4c820abbf3ab2722344d@191.235.84.50:30303",
"enode://158f8aab45f6d19c6cbf4a089c2670541a8da11978a2f90dbf6a502a4a3bab80d288afdbeb7ec0ef6d92de563767f3b1ea9e8e334ca711e9f8e2df5a0385e8e6@13.75.154.138:30303",
"enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303",
"enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303"
]
},
"checkpoint": {
"hash": "0x186642d6084eb7799cb01c7eb69c1a7f3b2c32cd141e62d309f30081a1ea3c91",
"number": 16015954,
"totalDifficulty": "0xC70D815D562D3CFA955"
}
},
"nonce": "0x42",
"timestamp": "0x0",
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"gasLimit": "0x1388",
"difficulty": "0x400000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"alloc": {
"000d836201318ec6899a67540690382780743280": {
"balance": "0xad78ebc5ac6200000"
}
}
}

@ -71,4 +71,6 @@ public interface MergeContext extends ConsensusContext {
default boolean isChainPruningEnabled() {
return false;
}
boolean isCheckpointPostMergeSync();
}

@ -63,6 +63,7 @@ public class PostMergeContext implements MergeContext {
private final AtomicReference<BlockHeader> lastSafeBlock = new AtomicReference<>();
private final AtomicReference<Optional<BlockHeader>> terminalPoWBlock =
new AtomicReference<>(Optional.empty());
private boolean isCheckpointPostMergeSync;
// TODO: cleanup - isChainPruningEnabled will not be required after
// https://github.com/hyperledger/besu/pull/4703 is merged.
@ -77,6 +78,7 @@ public class PostMergeContext implements MergeContext {
PostMergeContext(final Difficulty difficulty) {
this.terminalTotalDifficulty = new AtomicReference<>(difficulty);
this.syncState = new AtomicReference<>();
this.isCheckpointPostMergeSync = false;
}
public static PostMergeContext get() {
@ -139,7 +141,9 @@ public class PostMergeContext implements MergeContext {
return Optional.ofNullable(syncState.get()).map(s -> !s.isInSync()).orElse(Boolean.TRUE)
// this is necessary for when we do not have a sync target yet, like at startup.
// not being stopped at ttd implies we are syncing.
&& !syncState.get().hasReachedTerminalDifficulty().orElse(Boolean.FALSE);
&& Optional.ofNullable(syncState.get())
.map(s -> !(s.hasReachedTerminalDifficulty().orElse(Boolean.FALSE)))
.orElse(Boolean.TRUE);
}
@Override
@ -279,4 +283,14 @@ public class PostMergeContext implements MergeContext {
public boolean isChainPruningEnabled() {
return isChainPruningEnabled;
}
public PostMergeContext setCheckpointPostMergeSync(final boolean isCheckpointPostMergeSync) {
this.isCheckpointPostMergeSync = isCheckpointPostMergeSync;
return this;
}
@Override
public boolean isCheckpointPostMergeSync() {
return this.isCheckpointPostMergeSync;
}
}

@ -139,4 +139,9 @@ public class TransitionContext implements MergeContext {
public Optional<Block> retrieveBlockById(final PayloadIdentifier payloadId) {
return postMergeContext.retrieveBlockById(payloadId);
}
@Override
public boolean isCheckpointPostMergeSync() {
return false;
}
}

@ -202,6 +202,32 @@ public class PostMergeContextTest {
assertThat(postMergeContext.retrieveBlockById(evictedPayloadId)).isEmpty();
}
@Test
public void syncStateNullShouldNotThrowWhenIsSyncingIsCalled() {
// simulate a possible syncState null when we still have got a syncState set yet.
postMergeContext.setSyncState(null);
assertThat(postMergeContext.isSyncing()).isTrue();
// after setting a syncState things should progress as expected.
postMergeContext.setSyncState(mockSyncState);
// Assuming we're not in sync
when(mockSyncState.isInSync()).thenReturn(Boolean.FALSE);
when(mockSyncState.hasReachedTerminalDifficulty()).thenReturn(Optional.empty());
assertThat(postMergeContext.isSyncing()).isTrue();
when(mockSyncState.hasReachedTerminalDifficulty()).thenReturn(Optional.of(Boolean.FALSE));
assertThat(postMergeContext.isSyncing()).isTrue();
when(mockSyncState.hasReachedTerminalDifficulty()).thenReturn(Optional.of(Boolean.TRUE));
assertThat(postMergeContext.isSyncing()).isFalse();
// if we're in sync reached ttd does not matter anymore
when(mockSyncState.isInSync()).thenReturn(Boolean.TRUE);
assertThat(postMergeContext.isSyncing()).isFalse();
}
private static class MergeStateChangeCollector implements MergeStateHandler {
final List<Boolean> stateChanges = new ArrayList<>();

@ -119,7 +119,8 @@ public class EngineForkchoiceUpdated extends ExecutionEngineJsonRpcMethod {
}
// TODO: post-merge cleanup, this should be unnecessary after merge
if (!mergeCoordinator.latestValidAncestorDescendsFromTerminal(newHead)
if (!mergeContext.get().isCheckpointPostMergeSync()
&& !mergeCoordinator.latestValidAncestorDescendsFromTerminal(newHead)
&& !mergeContext.get().isChainPruningEnabled()) {
logForkchoiceUpdatedCall(INVALID, forkChoice);
return new JsonRpcSuccessResponse(

@ -196,7 +196,8 @@ public class EngineNewPayload extends ExecutionEngineJsonRpcMethod {
}
// TODO: post-merge cleanup
if (!mergeCoordinator.latestValidAncestorDescendsFromTerminal(newBlockHeader)
if (!mergeContext.get().isCheckpointPostMergeSync()
&& !mergeCoordinator.latestValidAncestorDescendsFromTerminal(newBlockHeader)
&& !mergeContext.get().isChainPruningEnabled()) {
mergeCoordinator.addBadBlock(block, Optional.empty());
return respondWithInvalid(

@ -40,4 +40,8 @@ public enum SyncMode {
public static boolean isFullSync(final SyncMode syncMode) {
return !EnumSet.of(SyncMode.FAST, SyncMode.X_SNAP, SyncMode.X_CHECKPOINT).contains(syncMode);
}
public static boolean isCheckpointSync(final SyncMode syncMode) {
return syncMode.equals(X_CHECKPOINT);
}
}

@ -50,6 +50,8 @@ public class SynchronizerConfiguration {
public static final long DEFAULT_PROPAGATION_MANAGER_GET_BLOCK_TIMEOUT_MILLIS =
TimeUnit.SECONDS.toMillis(60);
public static final boolean DEFAULT_CHECKPOINT_POST_MERGE_ENABLED = false;
// Fast sync config
private final int fastSyncPivotDistance;
private final float fastSyncFullValidationRate;
@ -68,6 +70,9 @@ public class SynchronizerConfiguration {
// General config
private final SyncMode syncMode;
// Near head Checkpoint sync
private final boolean checkpointPostMergeEnabled;
// Downloader config
private final long downloaderChangeTargetThresholdByHeight;
private final UInt256 downloaderChangeTargetThresholdByTd;
@ -102,7 +107,8 @@ public class SynchronizerConfiguration {
final int transactionsParallelism,
final int computationParallelism,
final int maxTrailingPeers,
final long propagationManagerGetBlockTimeoutMillis) {
final long propagationManagerGetBlockTimeoutMillis,
final boolean checkpointPostMergeEnabled) {
this.fastSyncPivotDistance = fastSyncPivotDistance;
this.fastSyncFullValidationRate = fastSyncFullValidationRate;
this.fastSyncMinimumPeerCount = fastSyncMinimumPeerCount;
@ -124,6 +130,7 @@ public class SynchronizerConfiguration {
this.computationParallelism = computationParallelism;
this.maxTrailingPeers = maxTrailingPeers;
this.propagationManagerGetBlockTimeoutMillis = propagationManagerGetBlockTimeoutMillis;
this.checkpointPostMergeEnabled = checkpointPostMergeEnabled;
}
public static Builder builder() {
@ -139,6 +146,10 @@ public class SynchronizerConfiguration {
return syncMode;
}
public boolean isCheckpointPostMergeEnabled() {
return checkpointPostMergeEnabled;
}
/**
* All the configuration related to snapsync
*
@ -271,6 +282,7 @@ public class SynchronizerConfiguration {
private long propagationManagerGetBlockTimeoutMillis =
DEFAULT_PROPAGATION_MANAGER_GET_BLOCK_TIMEOUT_MILLIS;
private boolean checkpointPostMergeEnabled = DEFAULT_CHECKPOINT_POST_MERGE_ENABLED;
public Builder fastSyncPivotDistance(final int distance) {
fastSyncPivotDistance = distance;
@ -389,6 +401,11 @@ public class SynchronizerConfiguration {
return this;
}
public Builder checkpointPostMergeEnabled(final boolean checkpointPostMergeEnabled) {
this.checkpointPostMergeEnabled = checkpointPostMergeEnabled;
return this;
}
public SynchronizerConfiguration build() {
return new SynchronizerConfiguration(
fastSyncPivotDistance,
@ -411,7 +428,8 @@ public class SynchronizerConfiguration {
transactionsParallelism,
computationParallelism,
maxTrailingPeers,
propagationManagerGetBlockTimeoutMillis);
propagationManagerGetBlockTimeoutMillis,
checkpointPostMergeEnabled);
}
}
}

Loading…
Cancel
Save