Skip to content

Commit

Permalink
feat: BlockStreams-Inversion of control (#15325)
Browse files Browse the repository at this point in the history
Signed-off-by: Neeharika-Sompalli <[email protected]>
  • Loading branch information
Neeharika-Sompalli authored Sep 11, 2024
1 parent 2dc454a commit ab8b709
Show file tree
Hide file tree
Showing 11 changed files with 341 additions and 280 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,20 @@

import static com.swirlds.common.io.utility.FileUtils.getAbsolutePath;
import static com.swirlds.common.io.utility.FileUtils.rethrowIO;
import static com.swirlds.common.threading.manager.AdHocThreadManager.getStaticThreadManager;
import static com.swirlds.logging.legacy.LogMarker.EXCEPTION;
import static com.swirlds.platform.builder.PlatformBuildConstants.DEFAULT_CONFIG_FILE_NAME;
import static com.swirlds.platform.builder.PlatformBuildConstants.DEFAULT_SETTINGS_FILE_NAME;
import static com.swirlds.platform.builder.internal.StaticPlatformBuilder.getMetricsProvider;
import static com.swirlds.platform.builder.internal.StaticPlatformBuilder.setupGlobalMetrics;
import static com.swirlds.platform.config.internal.PlatformConfigUtils.checkConfiguration;
import static com.swirlds.platform.crypto.CryptoStatic.initNodeSecurity;
import static com.swirlds.platform.state.signed.StartupStateUtils.getInitialState;
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;
import static com.swirlds.platform.system.address.AddressBookUtils.createRoster;
import static com.swirlds.platform.system.address.AddressBookUtils.initializeAddressBook;
import static com.swirlds.platform.util.BootstrapUtils.checkNodesToRun;
import static com.swirlds.platform.util.BootstrapUtils.getNodesToRun;
import static java.util.Objects.requireNonNull;
Expand All @@ -34,14 +42,21 @@
import com.swirlds.base.time.Time;
import com.swirlds.common.constructable.ConstructableRegistry;
import com.swirlds.common.constructable.RuntimeConstructable;
import com.swirlds.common.context.PlatformContext;
import com.swirlds.common.crypto.CryptographyFactory;
import com.swirlds.common.crypto.CryptographyHolder;
import com.swirlds.common.io.filesystem.FileSystemManager;
import com.swirlds.common.io.utility.FileUtils;
import com.swirlds.common.io.utility.RecycleBin;
import com.swirlds.common.merkle.crypto.MerkleCryptoFactory;
import com.swirlds.common.merkle.crypto.MerkleCryptographyFactory;
import com.swirlds.common.platform.NodeId;
import com.swirlds.config.api.Configuration;
import com.swirlds.config.api.ConfigurationBuilder;
import com.swirlds.config.extensions.sources.SystemEnvironmentConfigSource;
import com.swirlds.config.extensions.sources.SystemPropertiesConfigSource;
import com.swirlds.platform.CommandLineArgs;
import com.swirlds.platform.ParameterProvider;
import com.swirlds.platform.builder.PlatformBuilder;
import com.swirlds.platform.config.legacy.ConfigurationException;
import com.swirlds.platform.config.legacy.LegacyConfigProperties;
Expand Down Expand Up @@ -155,7 +170,7 @@ public static void main(final String... args) throws Exception {

// Determine which node to run locally
// Load config.txt address book file and parse address book
final AddressBook addressBook = loadAddressBook(DEFAULT_CONFIG_FILE_NAME);
final AddressBook bootstrapAddressBook = loadAddressBook(DEFAULT_CONFIG_FILE_NAME);
// parse command line arguments
final CommandLineArgs commandLineArgs = CommandLineArgs.parse(args);

Expand All @@ -170,7 +185,7 @@ public static void main(final String... args) throws Exception {
// get the list of configured nodes from the address book
// for each node in the address book, check if it has a local IP (local to this computer)
// additionally if a command line arg is supplied then limit matching nodes to that node id
final List<NodeId> nodesToRun = getNodesToRun(addressBook, commandLineArgs.localNodesToStart());
final List<NodeId> nodesToRun = getNodesToRun(bootstrapAddressBook, commandLineArgs.localNodesToStart());
// hard exit if no nodes are configured to run
checkNodesToRun(nodesToRun);

Expand All @@ -179,19 +194,58 @@ public static void main(final String... args) throws Exception {
final SoftwareVersion version = hedera.getSoftwareVersion();
logger.info("Starting node {} with version {}", selfId, version);

final PlatformBuilder platformBuilder = PlatformBuilder.create(
Hedera.APP_NAME,
Hedera.SWIRLD_NAME,
final var configuration = buildConfiguration();
final var keysAndCerts =
initNodeSecurity(bootstrapAddressBook, configuration).get(selfId);

setupGlobalMetrics(configuration);
final var metrics = getMetricsProvider().createPlatformMetrics(selfId);
final var time = Time.getCurrent();
final var fileSystemManager = FileSystemManager.create(configuration);
final var recycleBin =
RecycleBin.create(metrics, configuration, getStaticThreadManager(), time, fileSystemManager, selfId);

final var cryptography = CryptographyFactory.create();
CryptographyHolder.set(cryptography);
// the AddressBook is not changed after this point, so we calculate the hash now
cryptography.digestSync(bootstrapAddressBook);

// Initialize the Merkle cryptography
final var merkleCryptography = MerkleCryptographyFactory.create(configuration, cryptography);
MerkleCryptoFactory.set(merkleCryptography);

// Create the platform context
final var platformContext = PlatformContext.create(
configuration,
Time.getCurrent(),
metrics,
cryptography,
FileSystemManager.create(configuration),
recycleBin,
merkleCryptography);
// Create initial state for the platform
final var initialState = getInitialState(
platformContext,
version,
hedera::newMerkleStateRoot,
SignedStateFileUtils::readState,
selfId);
Hedera.APP_NAME,
Hedera.SWIRLD_NAME,
selfId,
bootstrapAddressBook);

// Initialize the address book and set on platform builder
final var addressBook =
initializeAddressBook(selfId, version, initialState, bootstrapAddressBook, platformContext);

// Add additional configuration to the platform
final Configuration configuration = buildConfiguration();
platformBuilder.withConfiguration(configuration);
platformBuilder.withCryptography(CryptographyFactory.create());
platformBuilder.withTime(Time.getCurrent());
// Follow the Inversion of Control pattern by injecting all needed dependencies into the PlatformBuilder.
final var platformBuilder = PlatformBuilder.create(
Hedera.APP_NAME, Hedera.SWIRLD_NAME, version, initialState, selfId)
.withPlatformContext(platformContext)
.withConfiguration(configuration)
.withAddressBook(addressBook)
.withRoster(createRoster(addressBook))
.withKeysAndCerts(keysAndCerts);

// IMPORTANT: A surface-level reading of this method will undersell the centrality
// of the Hedera instance. It is actually omnipresent throughout both the startup
Expand Down Expand Up @@ -234,13 +288,15 @@ private static Configuration buildConfiguration() {
.withSource(SystemPropertiesConfigSource.getInstance());
rethrowIO(() ->
BootstrapUtils.setupConfigBuilder(configurationBuilder, getAbsolutePath(DEFAULT_SETTINGS_FILE_NAME)));
return configurationBuilder.build();
final Configuration configuration = configurationBuilder.build();
checkConfiguration(configuration);
return configuration;
}

/**
* 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 Expand Up @@ -289,6 +345,7 @@ private static AddressBook loadAddressBook(@NonNull final String addressBookPath
try {
final LegacyConfigProperties props =
LegacyConfigPropertiesLoader.loadConfigFile(FileUtils.getAbsolutePath(addressBookPath));
props.appConfig().ifPresent(c -> ParameterProvider.getInstance().setParameters(c.params()));
return props.getAddressBook();
} catch (final Exception e) {
logger.error(EXCEPTION.getMarker(), "Error loading address book", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@
* completely different from each other.
*
* <p>The Services version is the version of the node software itself.
* This will be removed once we stop supporting 0.53.0 and earlier versions.
*/
@Deprecated(forRemoval = true)
public class HederaSoftwareVersion implements SoftwareVersion {

public static final long CLASS_ID = 0x6f2b1bc2df8cbd0cL;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,36 @@
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mock.Strictness.LENIENT;
import static org.mockito.Mockito.mockStatic;

import com.hedera.node.app.version.ServicesSoftwareVersion;
import com.swirlds.common.context.PlatformContext;
import com.swirlds.common.crypto.Cryptography;
import com.swirlds.common.io.filesystem.FileSystemManager;
import com.swirlds.common.io.utility.RecycleBin;
import com.swirlds.common.merkle.crypto.MerkleCryptography;
import com.swirlds.common.metrics.platform.DefaultMetricsProvider;
import com.swirlds.common.platform.NodeId;
import com.swirlds.config.api.Configuration;
import com.swirlds.metrics.api.Metrics;
import com.swirlds.platform.builder.PlatformBuilder;
import com.swirlds.platform.config.legacy.ConfigurationException;
import com.swirlds.platform.config.legacy.LegacyConfigProperties;
import com.swirlds.platform.config.legacy.LegacyConfigPropertiesLoader;
import com.swirlds.platform.state.MerkleStateRoot;
import com.swirlds.platform.state.signed.ReservedSignedState;
import com.swirlds.platform.state.signed.SignedState;
import com.swirlds.platform.system.Platform;
import com.swirlds.platform.system.SystemExitUtils;
import com.swirlds.platform.system.address.AddressBook;
import com.swirlds.platform.util.BootstrapUtils;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import java.util.function.BiFunction;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
Expand All @@ -47,9 +62,48 @@ final class ServicesMainTest {
mockStatic(LegacyConfigPropertiesLoader.class);
private static final MockedStatic<BootstrapUtils> bootstrapUtilsMockedStatic = mockStatic(BootstrapUtils.class);

@Mock
@Mock(strictness = LENIENT)
private LegacyConfigProperties legacyConfigProperties;

@Mock(strictness = LENIENT)
private AddressBook addressBook;

@Mock(strictness = LENIENT)
private DefaultMetricsProvider metricsProvider;

@Mock(strictness = LENIENT)
private Metrics metrics;

@Mock(strictness = LENIENT)
private FileSystemManager fileSystemManager;

@Mock(strictness = LENIENT)
private RecycleBin recycleBin;

@Mock(strictness = LENIENT)
private MerkleCryptography merkleCryptography;

@Mock(strictness = LENIENT)
BiFunction<Configuration, Cryptography, MerkleCryptography> merkleCryptographyFn;

@Mock(strictness = LENIENT)
private PlatformContext platformContext;

@Mock(strictness = LENIENT)
private PlatformBuilder platformBuilder;

@Mock(strictness = LENIENT)
private ReservedSignedState reservedSignedState;

@Mock(strictness = LENIENT)
private SignedState signedState;

@Mock(strictness = LENIENT)
private Platform platform;

@Mock(strictness = LENIENT)
private Hedera hedera;

private final ServicesMain subject = new ServicesMain();

// no local nodes specified but more than one match in address book
Expand Down Expand Up @@ -102,7 +156,7 @@ void returnsSerializableVersion() {
@Test
void noopsAsExpected() {
// expect:
Assertions.assertDoesNotThrow(subject::run);
assertDoesNotThrow(subject::run);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,6 @@ void dualReadAndWrite() throws IOException, ConstructableRegistryException {
final var originalTree = createMerkleHederaState(schemaV1);

MerkleStateRoot copy = originalTree.copy(); // make a copy to make VM flushable
;

forceFlush(originalTree.getReadableStates(FIRST_SERVICE).get(ANIMAL_STATE_KEY));
copy.copy(); // make a fast copy because we can only write to disk an immutable copy
Expand Down
Loading

0 comments on commit ab8b709

Please sign in to comment.