Skip to content

Commit

Permalink
feat: build context first (#12379)
Browse files Browse the repository at this point in the history
Signed-off-by: Cody Littley <[email protected]>
  • Loading branch information
cody-littley authored Mar 28, 2024
1 parent 2eb6a79 commit 5e00e1f
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@

package com.hedera.node.app;

import static com.swirlds.common.io.utility.FileUtils.getAbsolutePath;
import static com.swirlds.logging.legacy.LogMarker.EXCEPTION;
import static com.swirlds.platform.PlatformBuilder.DEFAULT_SETTINGS_FILE_NAME;
import static com.swirlds.platform.PlatformBuilder.buildPlatformContext;
import static com.swirlds.platform.system.SystemExitCode.CONFIGURATION_ERROR;
import static com.swirlds.platform.system.SystemExitCode.NODE_ADDRESS_MISMATCH;
import static com.swirlds.platform.system.SystemExitUtils.exitSystem;
Expand All @@ -27,6 +30,7 @@
import com.hedera.node.app.config.ConfigProviderImpl;
import com.hedera.node.config.data.HederaConfig;
import com.swirlds.common.constructable.ConstructableRegistry;
import com.swirlds.common.context.PlatformContext;
import com.swirlds.common.io.utility.FileUtils;
import com.swirlds.common.platform.NodeId;
import com.swirlds.config.api.ConfigurationBuilder;
Expand Down Expand Up @@ -151,10 +155,15 @@ public static void main(final String... args) throws Exception {

SoftwareVersion version = hedera.getSoftwareVersion();
logger.info("Starting node {} with version {}", selfId, version);
final PlatformBuilder builder = new PlatformBuilder(
Hedera.APP_NAME, Hedera.SWIRLD_NAME, version, hedera::newState, selfId)
.withPreviousSoftwareVersionClassId(0x6f2b1bc2df8cbd0bL /* SerializableSemVers.CLASS_ID */)
.withConfigurationBuilder(config);

final PlatformContext platformContext =
buildPlatformContext(config, getAbsolutePath(DEFAULT_SETTINGS_FILE_NAME), selfId);

final PlatformBuilder builder =
new PlatformBuilder(Hedera.APP_NAME, Hedera.SWIRLD_NAME, version, hedera::newState, selfId);

builder.withPreviousSoftwareVersionClassId(0x6f2b1bc2df8cbd0bL /* SerializableSemVers.CLASS_ID */);
builder.withPlatformContext(platformContext);

final Platform platform = builder.build();
hedera.init(platform, selfId);
Expand All @@ -165,7 +174,7 @@ public static void main(final String... args) throws Exception {
/**
* Selects the node to run locally from either the command line arguments or the address book.
*
* @param nodesToRun the list of nodes configured to run based on the address book.
* @param nodesToRun the list of nodes configured to run based on the address book.
* @param localNodesToStart the node ids specified on the command line.
* @return the node which should be run locally.
* @throws ConfigurationException if more than one node would be started or the requested node is not configured.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import static com.swirlds.platform.StaticPlatformBuilder.doStaticSetup;
import static com.swirlds.platform.StaticPlatformBuilder.getGlobalMetrics;
import static com.swirlds.platform.StaticPlatformBuilder.getMetricsProvider;
import static com.swirlds.platform.StaticPlatformBuilder.setupGlobalMetrics;
import static com.swirlds.platform.crypto.CryptoStatic.initNodeSecurity;
import static com.swirlds.platform.gui.internal.BrowserWindowManager.getPlatforms;
import static com.swirlds.platform.state.signed.StartupStateUtils.getInitialState;
Expand All @@ -41,6 +42,7 @@
import com.swirlds.common.platform.NodeId;
import com.swirlds.config.api.Configuration;
import com.swirlds.config.api.ConfigurationBuilder;
import com.swirlds.metrics.api.Metrics;
import com.swirlds.platform.config.BasicConfig;
import com.swirlds.platform.config.StateConfig;
import com.swirlds.platform.config.internal.PlatformConfigUtils;
Expand Down Expand Up @@ -83,6 +85,7 @@ public final class PlatformBuilder {
private final NodeId selfId;
private final String swirldName;

private PlatformContext platformContext;
private ConfigurationBuilder configurationBuilder;

private static final String SWIRLDS_PACKAGE = "com.swirlds";
Expand All @@ -98,7 +101,7 @@ public final class PlatformBuilder {
/**
* The path to the settings file (i.e. the path used to instantiate {@link Configuration}).
*/
private Path settingsPath = getAbsolutePath(DEFAULT_SETTINGS_FILE_NAME);
private Path settingsPath;

private Consumer<GossipEvent> preconsensusEventConsumer;
private Consumer<ConsensusSnapshot> snapshotOverrideConsumer;
Expand Down Expand Up @@ -129,15 +132,44 @@ public PlatformBuilder(
StaticSoftwareVersion.setSoftwareVersion(softwareVersion);
}

/**
* Set the platform context to use. If not provided then one is generated when the platform is built.
*
* @param platformContext the platform context to use
* @return this
* @throws IllegalStateException if {@link #withConfigurationBuilder(ConfigurationBuilder)} has been called or if
* {@link #withSettingsPath(Path)} has been called
*/
@NonNull
public PlatformBuilder withPlatformContext(@NonNull final PlatformContext platformContext) {
if (configurationBuilder != null) {
throw new IllegalStateException("Cannot set the platform context after the config builder has been set. "
+ "This method should not be called if withConfigurationBuilder() has been called.");
}
if (settingsPath != null) {
throw new IllegalStateException("Cannot set the platform context after the settings path has been set. "
+ "This method should not be called if withSettingsPath() has been called.");
}
this.platformContext = Objects.requireNonNull(platformContext);

return this;
}

/**
* Set the configuration builder to use. If not provided then one is generated when the platform is built.
*
* @param configurationBuilder the configuration builder to use
* @return this
* @throws IllegalStateException if {@link #withPlatformContext(PlatformContext)} has been called
*/
@NonNull
public PlatformBuilder withConfigurationBuilder(@Nullable final ConfigurationBuilder configurationBuilder) {
this.configurationBuilder = configurationBuilder;
if (platformContext != null) {
throw new IllegalStateException("Cannot set the config builder after the platform context has been "
+ "created. This method should not be called if withPlatformContext() has been called.");
}
this.configurationBuilder = Objects.requireNonNull(configurationBuilder);

return this;
}

Expand All @@ -147,11 +179,16 @@ public PlatformBuilder withConfigurationBuilder(@Nullable final ConfigurationBui
*
* @param path the path to the settings file
* @return this
* @throws IllegalStateException if {@link #withPlatformContext(PlatformContext)} has been called
*/
@NonNull
public PlatformBuilder withSettingsPath(@NonNull final Path path) {
Objects.requireNonNull(path);
this.settingsPath = getAbsolutePath(path);
if (platformContext != null) {
throw new IllegalStateException("Cannot set the settings path after the platform context has been created. "
+ "This method should not be called if withPlatformContext() has been called.");
}

this.settingsPath = getAbsolutePath(Objects.requireNonNull(path));
return this;
}

Expand Down Expand Up @@ -235,13 +272,16 @@ public PlatformBuilder withConsensusSnapshotOverrideCallback(
/**
* Build the configuration for the node.
*
* @param configurationBuilder used to build configuration
* @param settingsPath the path to the settings file
* @return the configuration
*/
@NonNull
private Configuration buildConfiguration() {
if (configurationBuilder == null) {
configurationBuilder = ConfigurationBuilder.create();
}
private static Configuration buildConfiguration(
@NonNull final ConfigurationBuilder configurationBuilder, @NonNull final Path settingsPath) {

Objects.requireNonNull(configurationBuilder);
Objects.requireNonNull(settingsPath);

rethrowIO(() -> BootstrapUtils.setupConfigBuilder(configurationBuilder, settingsPath));

Expand All @@ -264,13 +304,21 @@ private AddressBook loadConfigAddressBook() {
}

/**
* Build a platform. Platform is not started.
* Build a platform context that is compatible with the platform.
*
* @return a new platform instance
* @param configurationBuilder used to build configuration, can be pre-configured for application specific
* configuration needs
* @param settingsPath the path to the settings file
* @param selfId the ID of this node
* @return a new platform context
*/
@NonNull
public Platform build() {
final Configuration configuration = buildConfiguration();
public static PlatformContext buildPlatformContext(
@NonNull final ConfigurationBuilder configurationBuilder,
@NonNull final Path settingsPath,
@NonNull final NodeId selfId) {

final Configuration configuration = buildConfiguration(configurationBuilder, settingsPath);

final Cryptography cryptography = CryptographyFactory.create(configuration);
final MerkleCryptography merkleCryptography = MerkleCryptographyFactory.create(configuration, cryptography);
Expand All @@ -279,15 +327,39 @@ public Platform build() {
CryptographyHolder.set(cryptography);
MerkleCryptoFactory.set(merkleCryptography);

setupGlobalMetrics(configuration);
final Metrics metrics = getMetricsProvider().createPlatformMetrics(selfId);

return new DefaultPlatformContext(configuration, metrics, cryptography, Time.getCurrent());
}

/**
* Build a platform. Platform is not started.
*
* @return a new platform instance
*/
@NonNull
public Platform build() {

if (platformContext == null) {
if (configurationBuilder == null) {
configurationBuilder = ConfigurationBuilder.create();
}
if (settingsPath == null) {
settingsPath = getAbsolutePath(DEFAULT_SETTINGS_FILE_NAME);
}
platformContext = buildPlatformContext(configurationBuilder, settingsPath, selfId);
}

final Configuration configuration = platformContext.getConfiguration();

final boolean firstTimeSetup = doStaticSetup(configuration, configPath);

final AddressBook configAddressBook = loadConfigAddressBook();

checkNodesToRun(List.of(selfId));

final Map<NodeId, KeysAndCerts> keysAndCerts = initNodeSecurity(configAddressBook, configuration);
final PlatformContext platformContext = new DefaultPlatformContext(
configuration, getMetricsProvider().createPlatformMetrics(selfId), cryptography, Time.getCurrent());

// the AddressBook is not changed after this point, so we calculate the hash now
platformContext.getCryptography().digestSync(configAddressBook);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,19 @@ final class StaticPlatformBuilder {

private StaticPlatformBuilder() {}

/**
* Setup global metrics.
*
* @param configuration the configuration for this node
*/
static void setupGlobalMetrics(@NonNull final Configuration configuration) {
if (metricsProvider == null) {
metricsProvider = new DefaultMetricsProvider(configuration);
globalMetrics = metricsProvider.createGlobalMetrics();
CryptoMetrics.registerMetrics(globalMetrics);
}
}

/**
* Setup static utilities. If running multiple platforms in the same JVM and this method is called more than once
* then this method becomes a no-op.
Expand Down Expand Up @@ -100,10 +113,6 @@ static boolean doStaticSetup(@NonNull final Configuration configuration, @Nullab
BootstrapUtils.performHealthChecks(configPath, configuration);
writeSettingsUsed(configuration);

metricsProvider = new DefaultMetricsProvider(configuration);
globalMetrics = metricsProvider.createGlobalMetrics();
CryptoMetrics.registerMetrics(globalMetrics);

// Initialize the thread dump generator, if enabled via settings
startThreadDumpGenerator(configuration);

Expand Down

0 comments on commit 5e00e1f

Please sign in to comment.