diff --git a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/state/merkle/MerkleSchemaRegistry.java b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/state/merkle/MerkleSchemaRegistry.java index bc6461b3c283..680a45d34053 100644 --- a/hedera-node/hedera-app/src/main/java/com/hedera/node/app/state/merkle/MerkleSchemaRegistry.java +++ b/hedera-node/hedera-app/src/main/java/com/hedera/node/app/state/merkle/MerkleSchemaRegistry.java @@ -22,6 +22,7 @@ import static com.hedera.node.app.state.merkle.VersionUtils.alreadyIncludesStateDefs; import static com.hedera.node.app.state.merkle.VersionUtils.isSoOrdered; import static com.hedera.node.app.workflows.handle.metric.UnavailableMetrics.UNAVAILABLE_METRICS; +import static com.swirlds.state.merkle.StateUtils.registerWithSystem; import static java.util.Objects.requireNonNull; import com.hedera.hapi.node.base.SemanticVersion; @@ -31,9 +32,7 @@ import com.hedera.node.app.services.MigrationStateChanges; import com.hedera.node.app.spi.state.FilteredReadableStates; import com.hedera.node.app.spi.state.FilteredWritableStates; -import com.swirlds.common.constructable.ClassConstructorPair; import com.swirlds.common.constructable.ConstructableRegistry; -import com.swirlds.common.constructable.ConstructableRegistryException; import com.swirlds.common.crypto.DigestType; import com.swirlds.config.api.Configuration; import com.swirlds.merkle.map.MerkleMap; @@ -51,16 +50,10 @@ import com.swirlds.state.lifecycle.info.NetworkInfo; import com.swirlds.state.merkle.StateMetadata; import com.swirlds.state.merkle.StateUtils; -import com.swirlds.state.merkle.disk.OnDiskKey; import com.swirlds.state.merkle.disk.OnDiskKeySerializer; -import com.swirlds.state.merkle.disk.OnDiskValue; import com.swirlds.state.merkle.disk.OnDiskValueSerializer; -import com.swirlds.state.merkle.memory.InMemoryValue; -import com.swirlds.state.merkle.memory.InMemoryWritableKVState; import com.swirlds.state.merkle.queue.QueueNode; import com.swirlds.state.merkle.singleton.SingletonNode; -import com.swirlds.state.merkle.singleton.StringLeaf; -import com.swirlds.state.merkle.singleton.ValueLeaf; import com.swirlds.state.spi.WritableStates; import com.swirlds.virtualmap.VirtualMap; import edu.umd.cs.findbugs.annotations.NonNull; @@ -151,7 +144,7 @@ public SchemaRegistry register(@NonNull Schema schema) { schema.statesToCreate(bootstrapConfig).forEach(def -> { //noinspection rawtypes,unchecked final var md = new StateMetadata<>(serviceName, schema, def); - registerWithSystem(md); + registerWithSystem(md, constructableRegistry); }); return this; @@ -380,81 +373,4 @@ private RedefinedWritableStates applyStateDefinitions( final var newStates = new FilteredWritableStates(writableStates, remainingStates); return new RedefinedWritableStates(writableStates, newStates); } - - /** - * Registers with the {@link ConstructableRegistry} system a class ID and a class. While this - * will only be used for in-memory states, it is safe to register for on-disk ones as well. - * - *

The implementation will take the service name and the state key and compute a hash for it. - * It will then convert the hash to a long, and use that as the class ID. It will then register - * an {@link InMemoryWritableKVState}'s value merkle type to be deserialized, answering with the - * generated class ID. - * - * @param md The state metadata - */ - @SuppressWarnings({"rawtypes", "unchecked"}) - private void registerWithSystem(@NonNull final StateMetadata md) { - // Register with the system the uniqueId as the "classId" of an InMemoryValue. There can be - // multiple id's associated with InMemoryValue. The secret is that the supplier captures the - // various delegate writers and parsers, and so can parse/write different types of data - // based on the id. - try { - constructableRegistry.registerConstructable(new ClassConstructorPair( - InMemoryValue.class, - () -> new InMemoryValue( - md.inMemoryValueClassId(), - md.stateDefinition().keyCodec(), - md.stateDefinition().valueCodec()))); - constructableRegistry.registerConstructable(new ClassConstructorPair( - OnDiskKey.class, - () -> new OnDiskKey<>( - md.onDiskKeyClassId(), md.stateDefinition().keyCodec()))); - constructableRegistry.registerConstructable(new ClassConstructorPair( - OnDiskKeySerializer.class, - () -> new OnDiskKeySerializer<>( - md.onDiskKeySerializerClassId(), - md.onDiskKeyClassId(), - md.stateDefinition().keyCodec()))); - constructableRegistry.registerConstructable(new ClassConstructorPair( - OnDiskValue.class, - () -> new OnDiskValue<>( - md.onDiskValueClassId(), md.stateDefinition().valueCodec()))); - constructableRegistry.registerConstructable(new ClassConstructorPair( - OnDiskValueSerializer.class, - () -> new OnDiskValueSerializer<>( - md.onDiskValueSerializerClassId(), - md.onDiskValueClassId(), - md.stateDefinition().valueCodec()))); - constructableRegistry.registerConstructable(new ClassConstructorPair( - SingletonNode.class, - () -> new SingletonNode<>( - md.serviceName(), - md.stateDefinition().stateKey(), - md.singletonClassId(), - md.stateDefinition().valueCodec(), - null))); - constructableRegistry.registerConstructable(new ClassConstructorPair( - QueueNode.class, - () -> new QueueNode<>( - md.serviceName(), - md.stateDefinition().stateKey(), - md.queueNodeClassId(), - md.singletonClassId(), - md.stateDefinition().valueCodec()))); - constructableRegistry.registerConstructable(new ClassConstructorPair(StringLeaf.class, StringLeaf::new)); - constructableRegistry.registerConstructable(new ClassConstructorPair( - ValueLeaf.class, - () -> new ValueLeaf<>( - md.singletonClassId(), md.stateDefinition().valueCodec()))); - } catch (ConstructableRegistryException e) { - // This is a fatal error. - throw new IllegalStateException( - "Failed to register with the system '" - + serviceName - + ":" - + md.stateDefinition().stateKey() - + "'", - e); - } - } } diff --git a/platform-sdk/platform-apps/demos/CryptocurrencyDemo/src/main/java/com/swirlds/demo/crypto/CryptocurrencyDemoMain.java b/platform-sdk/platform-apps/demos/CryptocurrencyDemo/src/main/java/com/swirlds/demo/crypto/CryptocurrencyDemoMain.java index 28e21828fb5b..d6de55759f65 100644 --- a/platform-sdk/platform-apps/demos/CryptocurrencyDemo/src/main/java/com/swirlds/demo/crypto/CryptocurrencyDemoMain.java +++ b/platform-sdk/platform-apps/demos/CryptocurrencyDemo/src/main/java/com/swirlds/demo/crypto/CryptocurrencyDemoMain.java @@ -36,11 +36,11 @@ import com.swirlds.common.utility.AutoCloseableWrapper; import com.swirlds.metrics.api.Metrics; import com.swirlds.platform.Browser; -import com.swirlds.platform.state.MerkleRoot; -import com.swirlds.platform.state.State; +import com.swirlds.platform.state.MerkleStateRoot; import com.swirlds.platform.system.BasicSoftwareVersion; import com.swirlds.platform.system.Platform; import com.swirlds.platform.system.SwirldMain; +import com.swirlds.platform.util.NoOpMerkleStateLifecycles; import edu.umd.cs.findbugs.annotations.NonNull; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; @@ -182,9 +182,11 @@ public void run() { @Override @NonNull - public MerkleRoot newMerkleStateRoot() { - final State state = new State(); - state.setSwirldState(new CryptocurrencyDemoState()); + public MerkleStateRoot newMerkleStateRoot() { + final MerkleStateRoot state = new CryptocurrencyDemoState( + NoOpMerkleStateLifecycles.NO_OP_MERKLE_STATE_LIFECYCLES, + version -> new BasicSoftwareVersion(softwareVersion.getSoftwareVersion())); + NoOpMerkleStateLifecycles.NO_OP_MERKLE_STATE_LIFECYCLES.initPlatformState(state); return state; } diff --git a/platform-sdk/platform-apps/demos/CryptocurrencyDemo/src/main/java/com/swirlds/demo/crypto/CryptocurrencyDemoState.java b/platform-sdk/platform-apps/demos/CryptocurrencyDemo/src/main/java/com/swirlds/demo/crypto/CryptocurrencyDemoState.java index d08785a13640..8225e5ba318f 100644 --- a/platform-sdk/platform-apps/demos/CryptocurrencyDemo/src/main/java/com/swirlds/demo/crypto/CryptocurrencyDemoState.java +++ b/platform-sdk/platform-apps/demos/CryptocurrencyDemo/src/main/java/com/swirlds/demo/crypto/CryptocurrencyDemoState.java @@ -26,25 +26,23 @@ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. */ +import com.hedera.hapi.node.base.SemanticVersion; import com.hedera.pbj.runtime.io.buffer.Bytes; -import com.swirlds.common.io.streams.SerializableDataInputStream; -import com.swirlds.common.io.streams.SerializableDataOutputStream; -import com.swirlds.common.merkle.MerkleLeaf; -import com.swirlds.common.merkle.impl.PartialMerkleLeaf; +import com.swirlds.common.constructable.ConstructableIgnored; import com.swirlds.common.platform.NodeId; import com.swirlds.platform.SwirldsPlatform; +import com.swirlds.platform.state.MerkleStateLifecycles; +import com.swirlds.platform.state.MerkleStateRoot; import com.swirlds.platform.state.PlatformStateModifier; import com.swirlds.platform.system.InitTrigger; import com.swirlds.platform.system.Platform; import com.swirlds.platform.system.Round; import com.swirlds.platform.system.SoftwareVersion; -import com.swirlds.platform.system.SwirldState; import com.swirlds.platform.system.address.Address; import com.swirlds.platform.system.address.AddressBook; import com.swirlds.platform.system.transaction.Transaction; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; -import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -52,6 +50,7 @@ import java.util.Objects; import java.util.Random; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Function; /** * This holds the current state of a swirld representing both a cryptocurrency and a stock market. @@ -62,7 +61,8 @@ * entirely new cryptocurrency is created every time all the computers start the program over again, so * these cryptocurrencies won't have any actual value. */ -public class CryptocurrencyDemoState extends PartialMerkleLeaf implements SwirldState, MerkleLeaf { +@ConstructableIgnored +public class CryptocurrencyDemoState extends MerkleStateRoot { /** * The version history of this class. @@ -134,7 +134,11 @@ public static enum TransType { //////////////////////////////////////////////////// - public CryptocurrencyDemoState() {} + public CryptocurrencyDemoState( + @NonNull final MerkleStateLifecycles lifecycles, + @NonNull final Function versionFactory) { + super(lifecycles, versionFactory); + } private CryptocurrencyDemoState(final CryptocurrencyDemoState sourceState) { super(sourceState); @@ -196,6 +200,7 @@ public synchronized long getNumTrades() { @Override public synchronized CryptocurrencyDemoState copy() { throwIfImmutable(); + setImmutable(true); return new CryptocurrencyDemoState(this); } @@ -380,76 +385,14 @@ public void init( @NonNull final Platform platform, @NonNull final InitTrigger trigger, @Nullable final SoftwareVersion previousSoftwareVersion) { - this.platform = (SwirldsPlatform) platform; + super.init(platform, trigger, previousSoftwareVersion); + this.platform = (SwirldsPlatform) platform; if (trigger == InitTrigger.GENESIS) { genesisInit(); } } - @Override - public void serialize(final SerializableDataOutputStream out) throws IOException { - out.writeStringArray(tickerSymbol); - - out.writeInt(wallet.size()); - for (Map.Entry entry : wallet.entrySet()) { - out.writeSerializable(entry.getKey(), false); - out.writeLong(entry.getValue().get()); - } - - out.writeInt(shares.size()); - for (Map.Entry> entry : shares.entrySet()) { - out.writeSerializable(entry.getKey(), false); - out.writeInt(entry.getValue().size()); - for (int i = 0; i < entry.getValue().size(); i++) { - out.writeLong(entry.getValue().get(i).get()); - } - } - - out.writeStringArray(trades); - out.writeInt(numTradesStored); - out.writeInt(lastTradeIndex); - out.writeLong(numTrades); - out.writeByteArray(ask); - out.writeByteArray(bid); - out.writeSerializableArray(askId, false, true); - out.writeSerializableArray(bidId, false, true); - out.writeByteArray(price); - } - - @Override - public void deserialize(final SerializableDataInputStream in, final int version) throws IOException { - tickerSymbol = in.readStringArray(DEFAULT_MAX_ARRAY_SIZE, DEFAULT_MAX_STRING_SIZE); - - int walletSize = in.readInt(); - for (int i = 0; i < walletSize; i++) { - final NodeId id = in.readSerializable(false, NodeId::new); - final AtomicLong amount = new AtomicLong(in.readLong()); - wallet.put(id, amount); - } - - final int sharesSize = in.readInt(); - for (int i = 0; i < sharesSize; i++) { - final NodeId id = in.readSerializable(false, NodeId::new); - final int numShares = in.readInt(); - final List sharesForID = new ArrayList<>(numShares); - for (int j = 0; j < numShares; j++) { - sharesForID.add(new AtomicLong(in.readLong())); - } - shares.put(id, sharesForID); - } - - trades = in.readStringArray(DEFAULT_MAX_ARRAY_SIZE, DEFAULT_MAX_STRING_SIZE); - numTradesStored = in.readInt(); - lastTradeIndex = in.readInt(); - numTrades = in.readLong(); - ask = in.readByteArray(DEFAULT_MAX_ARRAY_SIZE); - bid = in.readByteArray(DEFAULT_MAX_ARRAY_SIZE); - askId = in.readSerializableArray(NodeId[]::new, DEFAULT_MAX_ARRAY_SIZE, false, NodeId::new); - bidId = in.readSerializableArray(NodeId[]::new, DEFAULT_MAX_ARRAY_SIZE, false, NodeId::new); - price = in.readByteArray(DEFAULT_MAX_ARRAY_SIZE); - } - @Override public long getClassId() { return CLASS_ID; diff --git a/platform-sdk/platform-apps/demos/CryptocurrencyDemo/src/main/java/module-info.java b/platform-sdk/platform-apps/demos/CryptocurrencyDemo/src/main/java/module-info.java index b42efa99b26b..769d0e16696f 100644 --- a/platform-sdk/platform-apps/demos/CryptocurrencyDemo/src/main/java/module-info.java +++ b/platform-sdk/platform-apps/demos/CryptocurrencyDemo/src/main/java/module-info.java @@ -1,7 +1,9 @@ module com.swirlds.demo.crypto { + requires com.hedera.node.hapi; requires com.swirlds.common; requires com.swirlds.metrics.api; requires com.swirlds.platform.core; + requires com.swirlds.state.api; requires com.hedera.pbj.runtime; requires java.desktop; requires static com.github.spotbugs.annotations; diff --git a/platform-sdk/platform-apps/demos/HelloSwirldDemo/src/main/java/com/swirlds/demo/hello/HelloSwirldDemoMain.java b/platform-sdk/platform-apps/demos/HelloSwirldDemo/src/main/java/com/swirlds/demo/hello/HelloSwirldDemoMain.java index 04dfe21cdf2a..236de5ca7703 100644 --- a/platform-sdk/platform-apps/demos/HelloSwirldDemo/src/main/java/com/swirlds/demo/hello/HelloSwirldDemoMain.java +++ b/platform-sdk/platform-apps/demos/HelloSwirldDemo/src/main/java/com/swirlds/demo/hello/HelloSwirldDemoMain.java @@ -35,12 +35,12 @@ import com.swirlds.platform.SwirldsPlatform; import com.swirlds.platform.listeners.PlatformStatusChangeListener; import com.swirlds.platform.listeners.PlatformStatusChangeNotification; -import com.swirlds.platform.state.MerkleRoot; -import com.swirlds.platform.state.State; +import com.swirlds.platform.state.MerkleStateRoot; import com.swirlds.platform.system.BasicSoftwareVersion; import com.swirlds.platform.system.Platform; import com.swirlds.platform.system.SwirldMain; import com.swirlds.platform.system.status.PlatformStatus; +import com.swirlds.platform.util.NoOpMerkleStateLifecycles; import edu.umd.cs.findbugs.annotations.NonNull; import java.nio.charset.StandardCharsets; @@ -109,9 +109,11 @@ public void run() { @NonNull @Override - public MerkleRoot newMerkleStateRoot() { - final State state = new State(); - state.setSwirldState(new HelloSwirldDemoState()); + public MerkleStateRoot newMerkleStateRoot() { + final MerkleStateRoot state = new HelloSwirldDemoState( + NoOpMerkleStateLifecycles.NO_OP_MERKLE_STATE_LIFECYCLES, + version -> new BasicSoftwareVersion(softwareVersion.getSoftwareVersion())); + NoOpMerkleStateLifecycles.NO_OP_MERKLE_STATE_LIFECYCLES.initPlatformState(state); return state; } diff --git a/platform-sdk/platform-apps/demos/HelloSwirldDemo/src/main/java/com/swirlds/demo/hello/HelloSwirldDemoState.java b/platform-sdk/platform-apps/demos/HelloSwirldDemo/src/main/java/com/swirlds/demo/hello/HelloSwirldDemoState.java index 7d36ec7950cd..9ac33b259c35 100644 --- a/platform-sdk/platform-apps/demos/HelloSwirldDemo/src/main/java/com/swirlds/demo/hello/HelloSwirldDemoState.java +++ b/platform-sdk/platform-apps/demos/HelloSwirldDemo/src/main/java/com/swirlds/demo/hello/HelloSwirldDemoState.java @@ -26,25 +26,27 @@ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. */ -import com.swirlds.common.io.streams.SerializableDataInputStream; -import com.swirlds.common.io.streams.SerializableDataOutputStream; -import com.swirlds.common.merkle.MerkleLeaf; -import com.swirlds.common.merkle.impl.PartialMerkleLeaf; +import com.hedera.hapi.node.base.SemanticVersion; +import com.swirlds.common.constructable.ConstructableIgnored; +import com.swirlds.platform.state.MerkleStateLifecycles; +import com.swirlds.platform.state.MerkleStateRoot; import com.swirlds.platform.state.PlatformStateModifier; import com.swirlds.platform.system.Round; -import com.swirlds.platform.system.SwirldState; +import com.swirlds.platform.system.SoftwareVersion; import com.swirlds.platform.system.transaction.Transaction; -import java.io.IOException; +import edu.umd.cs.findbugs.annotations.NonNull; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import java.util.function.Function; /** * This holds the current state of the swirld. For this simple "hello swirld" code, each transaction is just * a string, and the state is just a list of the strings in all the transactions handled so far, in the * order that they were handled. */ -public class HelloSwirldDemoState extends PartialMerkleLeaf implements SwirldState, MerkleLeaf { +@ConstructableIgnored +public class HelloSwirldDemoState extends MerkleStateRoot { /** * The version history of this class. @@ -91,7 +93,11 @@ public synchronized String toString() { // /////////////////////////////////////////////////////////////////// - public HelloSwirldDemoState() {} + public HelloSwirldDemoState( + @NonNull final MerkleStateLifecycles lifecycles, + @NonNull final Function versionFactory) { + super(lifecycles, versionFactory); + } private HelloSwirldDemoState(final HelloSwirldDemoState sourceState) { super(sourceState); @@ -107,6 +113,7 @@ public synchronized void handleConsensusRound(final Round round, final PlatformS @Override public synchronized HelloSwirldDemoState copy() { throwIfImmutable(); + setImmutable(true); return new HelloSwirldDemoState(this); } @@ -117,16 +124,6 @@ private void handleTransaction(final Transaction transaction) { strings.add(new String(transaction.getApplicationTransaction().toByteArray(), StandardCharsets.UTF_8)); } - @Override - public void serialize(final SerializableDataOutputStream out) throws IOException { - out.writeStringList(strings); - } - - @Override - public void deserialize(final SerializableDataInputStream in, final int version) throws IOException { - strings = in.readStringList(DEFAULT_MAX_ARRAY_SIZE, DEFAULT_MAX_STRING_SIZE); - } - @Override public long getClassId() { return CLASS_ID; diff --git a/platform-sdk/platform-apps/demos/HelloSwirldDemo/src/main/java/module-info.java b/platform-sdk/platform-apps/demos/HelloSwirldDemo/src/main/java/module-info.java index cfd02e9373bc..76f2cb141a2c 100644 --- a/platform-sdk/platform-apps/demos/HelloSwirldDemo/src/main/java/module-info.java +++ b/platform-sdk/platform-apps/demos/HelloSwirldDemo/src/main/java/module-info.java @@ -1,6 +1,8 @@ module com.swirlds.demo.hello { + requires com.hedera.node.hapi; requires com.swirlds.common; requires com.swirlds.platform.core; + requires com.swirlds.state.api; requires com.hedera.pbj.runtime; requires java.desktop; requires static com.github.spotbugs.annotations; diff --git a/platform-sdk/platform-apps/demos/StatsDemo/src/main/java/com/swirlds/demo/stats/StatsDemoMain.java b/platform-sdk/platform-apps/demos/StatsDemo/src/main/java/com/swirlds/demo/stats/StatsDemoMain.java index 794f67e901c1..27a7cb63063b 100644 --- a/platform-sdk/platform-apps/demos/StatsDemo/src/main/java/com/swirlds/demo/stats/StatsDemoMain.java +++ b/platform-sdk/platform-apps/demos/StatsDemo/src/main/java/com/swirlds/demo/stats/StatsDemoMain.java @@ -39,11 +39,11 @@ import com.swirlds.metrics.api.Metrics; import com.swirlds.platform.Browser; import com.swirlds.platform.ParameterProvider; -import com.swirlds.platform.state.MerkleRoot; -import com.swirlds.platform.state.State; +import com.swirlds.platform.state.MerkleStateRoot; import com.swirlds.platform.system.BasicSoftwareVersion; import com.swirlds.platform.system.Platform; import com.swirlds.platform.system.SwirldMain; +import com.swirlds.platform.util.NoOpMerkleStateLifecycles; import edu.umd.cs.findbugs.annotations.NonNull; import java.io.BufferedWriter; import java.io.File; @@ -297,9 +297,11 @@ private String valueAsString(final Metric metric) { @NonNull @Override - public MerkleRoot newMerkleStateRoot() { - final State state = new State(); - state.setSwirldState(new StatsDemoState()); + public MerkleStateRoot newMerkleStateRoot() { + final MerkleStateRoot state = new StatsDemoState( + NoOpMerkleStateLifecycles.NO_OP_MERKLE_STATE_LIFECYCLES, + version -> new BasicSoftwareVersion(softwareVersion.getSoftwareVersion())); + NoOpMerkleStateLifecycles.NO_OP_MERKLE_STATE_LIFECYCLES.initPlatformState(state); return state; } diff --git a/platform-sdk/platform-apps/demos/StatsDemo/src/main/java/com/swirlds/demo/stats/StatsDemoState.java b/platform-sdk/platform-apps/demos/StatsDemo/src/main/java/com/swirlds/demo/stats/StatsDemoState.java index 68d018b2c2a3..dc4662f77807 100644 --- a/platform-sdk/platform-apps/demos/StatsDemo/src/main/java/com/swirlds/demo/stats/StatsDemoState.java +++ b/platform-sdk/platform-apps/demos/StatsDemo/src/main/java/com/swirlds/demo/stats/StatsDemoState.java @@ -26,13 +26,15 @@ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. */ -import com.swirlds.common.io.streams.SerializableDataInputStream; -import com.swirlds.common.io.streams.SerializableDataOutputStream; -import com.swirlds.common.merkle.MerkleLeaf; -import com.swirlds.common.merkle.impl.PartialMerkleLeaf; +import com.hedera.hapi.node.base.SemanticVersion; +import com.swirlds.common.constructable.ConstructableIgnored; +import com.swirlds.platform.state.MerkleStateLifecycles; +import com.swirlds.platform.state.MerkleStateRoot; import com.swirlds.platform.state.PlatformStateModifier; import com.swirlds.platform.system.Round; -import com.swirlds.platform.system.SwirldState; +import com.swirlds.platform.system.SoftwareVersion; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.function.Function; /** * This demo collects statistics on the running of the network and consensus systems. It writes them to the @@ -41,7 +43,8 @@ * is 100 random bytes. So StatsDemoState.handleTransaction doesn't actually do anything, other than the * optional sequence number check. */ -public class StatsDemoState extends PartialMerkleLeaf implements SwirldState, MerkleLeaf { +@ConstructableIgnored +public class StatsDemoState extends MerkleStateRoot { /** * The version history of this class. @@ -62,7 +65,11 @@ private static class ClassVersion { private static final long CLASS_ID = 0xc550a1cd94e91ca3L; - public StatsDemoState() {} + public StatsDemoState( + @NonNull final MerkleStateLifecycles lifecycles, + @NonNull final Function versionFactory) { + super(lifecycles, versionFactory); + } private StatsDemoState(final StatsDemoState sourceState) { super(sourceState); @@ -77,21 +84,10 @@ public void handleConsensusRound(final Round round, final PlatformStateModifier @Override public synchronized StatsDemoState copy() { throwIfImmutable(); + setImmutable(true); return new StatsDemoState(this); } - /** - * {@inheritDoc} - */ - @Override - public void serialize(final SerializableDataOutputStream out) {} - - /** - * {@inheritDoc} - */ - @Override - public void deserialize(final SerializableDataInputStream in, final int version) {} - /** * {@inheritDoc} */ diff --git a/platform-sdk/platform-apps/demos/StatsDemo/src/main/java/module-info.java b/platform-sdk/platform-apps/demos/StatsDemo/src/main/java/module-info.java index e0830b328858..5387a8dc5903 100644 --- a/platform-sdk/platform-apps/demos/StatsDemo/src/main/java/module-info.java +++ b/platform-sdk/platform-apps/demos/StatsDemo/src/main/java/module-info.java @@ -1,8 +1,10 @@ module com.swirlds.demo.stats { + requires com.hedera.node.hapi; requires com.swirlds.base; requires com.swirlds.common; requires com.swirlds.metrics.api; requires com.swirlds.platform.core; + requires com.swirlds.state.api; requires java.desktop; requires static com.github.spotbugs.annotations; } diff --git a/platform-sdk/platform-apps/tests/AddressBookTestingTool/src/main/java/com/swirlds/demo/addressbook/AddressBookTestingToolMain.java b/platform-sdk/platform-apps/tests/AddressBookTestingTool/src/main/java/com/swirlds/demo/addressbook/AddressBookTestingToolMain.java index 8fef0db4e50a..eff2c97441d2 100644 --- a/platform-sdk/platform-apps/tests/AddressBookTestingTool/src/main/java/com/swirlds/demo/addressbook/AddressBookTestingToolMain.java +++ b/platform-sdk/platform-apps/tests/AddressBookTestingTool/src/main/java/com/swirlds/demo/addressbook/AddressBookTestingToolMain.java @@ -23,11 +23,11 @@ import com.swirlds.config.api.Configuration; import com.swirlds.config.api.ConfigurationBuilder; import com.swirlds.platform.config.DefaultConfiguration; -import com.swirlds.platform.state.MerkleRoot; -import com.swirlds.platform.state.State; +import com.swirlds.platform.state.MerkleStateRoot; import com.swirlds.platform.system.BasicSoftwareVersion; import com.swirlds.platform.system.Platform; import com.swirlds.platform.system.SwirldMain; +import com.swirlds.platform.util.NoOpMerkleStateLifecycles; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.io.IOException; @@ -105,9 +105,11 @@ public void run() { */ @Override @NonNull - public MerkleRoot newMerkleStateRoot() { - final State state = new State(); - state.setSwirldState(new AddressBookTestingToolState()); + public MerkleStateRoot newMerkleStateRoot() { + final MerkleStateRoot state = new AddressBookTestingToolState( + NoOpMerkleStateLifecycles.NO_OP_MERKLE_STATE_LIFECYCLES, + version -> new BasicSoftwareVersion(softwareVersion.getSoftwareVersion())); + NoOpMerkleStateLifecycles.NO_OP_MERKLE_STATE_LIFECYCLES.initPlatformState(state); return state; } diff --git a/platform-sdk/platform-apps/tests/AddressBookTestingTool/src/main/java/com/swirlds/demo/addressbook/AddressBookTestingToolState.java b/platform-sdk/platform-apps/tests/AddressBookTestingTool/src/main/java/com/swirlds/demo/addressbook/AddressBookTestingToolState.java index 29a02aa8a2e2..f10d931a37ea 100644 --- a/platform-sdk/platform-apps/tests/AddressBookTestingTool/src/main/java/com/swirlds/demo/addressbook/AddressBookTestingToolState.java +++ b/platform-sdk/platform-apps/tests/AddressBookTestingTool/src/main/java/com/swirlds/demo/addressbook/AddressBookTestingToolState.java @@ -35,25 +35,23 @@ import static com.swirlds.platform.state.address.AddressBookInitializer.STATE_ADDRESS_BOOK_USED; import static com.swirlds.platform.state.address.AddressBookInitializer.USED_ADDRESS_BOOK_HEADER; +import com.hedera.hapi.node.base.SemanticVersion; import com.hedera.hapi.node.state.roster.Roster; import com.hedera.pbj.runtime.io.buffer.Bytes; +import com.swirlds.common.constructable.ConstructableIgnored; import com.swirlds.common.context.PlatformContext; -import com.swirlds.common.io.streams.SerializableDataInputStream; -import com.swirlds.common.io.streams.SerializableDataOutputStream; -import com.swirlds.common.merkle.MerkleLeaf; -import com.swirlds.common.merkle.impl.PartialMerkleLeaf; import com.swirlds.common.platform.NodeId; import com.swirlds.common.utility.ByteUtils; import com.swirlds.common.utility.StackTrace; import com.swirlds.platform.config.AddressBookConfig; import com.swirlds.platform.roster.RosterRetriever; -import com.swirlds.platform.state.PlatformStateAccessor; +import com.swirlds.platform.state.MerkleStateLifecycles; +import com.swirlds.platform.state.MerkleStateRoot; import com.swirlds.platform.state.PlatformStateModifier; import com.swirlds.platform.system.InitTrigger; import com.swirlds.platform.system.Platform; import com.swirlds.platform.system.Round; import com.swirlds.platform.system.SoftwareVersion; -import com.swirlds.platform.system.SwirldState; import com.swirlds.platform.system.address.Address; import com.swirlds.platform.system.address.AddressBook; import com.swirlds.platform.system.address.AddressBookUtils; @@ -71,13 +69,15 @@ import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; /** * State for the AddressBookTestingTool. */ -public class AddressBookTestingToolState extends PartialMerkleLeaf implements SwirldState, MerkleLeaf { +@ConstructableIgnored +public class AddressBookTestingToolState extends MerkleStateRoot { private static final Logger logger = LogManager.getLogger(AddressBookTestingToolState.class); @@ -113,8 +113,8 @@ private static class ClassVersion { /** * The number of rounds handled by this app. Is incremented each time - * {@link #handleConsensusRound(Round, PlatformStateAccessor)} is called. Note that this may not actually equal the round - * number, since we don't call {@link #handleConsensusRound(Round, PlatformStateAccessor)} for rounds with no events. + * {@link #handleConsensusRound(Round, PlatformStateModifier)} is called. Note that this may not actually equal the round + * number, since we don't call {@link #handleConsensusRound(Round, PlatformStateModifier)} for rounds with no events. * *

* Affects the hash of this node. @@ -129,7 +129,10 @@ private static class ClassVersion { */ private Duration freezeAfterGenesis = null; - public AddressBookTestingToolState() { + public AddressBookTestingToolState( + @NonNull final MerkleStateLifecycles lifecycles, + @NonNull final Function versionFactory) { + super(lifecycles, versionFactory); logger.info(STARTUP.getMarker(), "New State Constructed."); } @@ -156,6 +159,7 @@ private AddressBookTestingToolState(@NonNull final AddressBookTestingToolState t @Override public synchronized AddressBookTestingToolState copy() { throwIfImmutable(); + setImmutable(true); return new AddressBookTestingToolState(this); } @@ -233,26 +237,6 @@ private void handleTransaction(@NonNull final ConsensusTransaction transaction) runningSum += delta; } - /** - * {@inheritDoc} - */ - @Override - public void serialize(@NonNull final SerializableDataOutputStream out) throws IOException { - Objects.requireNonNull(out, "the serializable data output stream cannot be null"); - out.writeLong(runningSum); - out.writeLong(roundsHandled); - } - - /** - * {@inheritDoc} - */ - @Override - public void deserialize(@NonNull final SerializableDataInputStream in, final int version) throws IOException { - Objects.requireNonNull(in, "the serializable data input stream cannot be null"); - runningSum = in.readLong(); - roundsHandled = in.readLong(); - } - /** * {@inheritDoc} */ diff --git a/platform-sdk/platform-apps/tests/AddressBookTestingTool/src/main/java/module-info.java b/platform-sdk/platform-apps/tests/AddressBookTestingTool/src/main/java/module-info.java index 814c35531ef9..dc767113b793 100644 --- a/platform-sdk/platform-apps/tests/AddressBookTestingTool/src/main/java/module-info.java +++ b/platform-sdk/platform-apps/tests/AddressBookTestingTool/src/main/java/module-info.java @@ -5,6 +5,7 @@ requires com.swirlds.config.api; requires com.swirlds.logging; requires com.swirlds.platform.core; + requires com.swirlds.state.api; requires com.hedera.pbj.runtime; requires org.apache.logging.log4j; requires static com.github.spotbugs.annotations; diff --git a/platform-sdk/platform-apps/tests/ConsistencyTestingTool/build.gradle.kts b/platform-sdk/platform-apps/tests/ConsistencyTestingTool/build.gradle.kts index 75324db7df15..0cb0449462f1 100644 --- a/platform-sdk/platform-apps/tests/ConsistencyTestingTool/build.gradle.kts +++ b/platform-sdk/platform-apps/tests/ConsistencyTestingTool/build.gradle.kts @@ -21,7 +21,6 @@ application.mainClass.set("com.swirlds.demo.consistency.ConsistencyTestingToolMa mainModuleInfo { annotationProcessor("com.swirlds.config.processor") } testModuleInfo { - requires("com.hedera.node.hapi") requires("com.swirlds.common.test.fixtures") requires("com.swirlds.platform.core.test.fixtures") requires("org.junit.jupiter.api") diff --git a/platform-sdk/platform-apps/tests/ConsistencyTestingTool/src/main/java/com/swirlds/demo/consistency/ConsistencyTestingToolMain.java b/platform-sdk/platform-apps/tests/ConsistencyTestingTool/src/main/java/com/swirlds/demo/consistency/ConsistencyTestingToolMain.java index 1f197fc14865..4ba378f469f9 100644 --- a/platform-sdk/platform-apps/tests/ConsistencyTestingTool/src/main/java/com/swirlds/demo/consistency/ConsistencyTestingToolMain.java +++ b/platform-sdk/platform-apps/tests/ConsistencyTestingTool/src/main/java/com/swirlds/demo/consistency/ConsistencyTestingToolMain.java @@ -17,14 +17,22 @@ package com.swirlds.demo.consistency; import static com.swirlds.logging.legacy.LogMarker.STARTUP; +import static com.swirlds.platform.util.NoOpMerkleStateLifecycles.NO_OP_MERKLE_STATE_LIFECYCLES; +import static com.swirlds.state.merkle.StateUtils.registerWithSystem; +import com.swirlds.common.constructable.ClassConstructorPair; +import com.swirlds.common.constructable.ConstructableRegistry; +import com.swirlds.common.constructable.ConstructableRegistryException; import com.swirlds.common.platform.NodeId; -import com.swirlds.platform.state.MerkleRoot; -import com.swirlds.platform.state.State; +import com.swirlds.platform.state.MerkleStateRoot; +import com.swirlds.platform.state.service.PlatformStateService; +import com.swirlds.platform.state.service.schemas.V0540PlatformStateSchema; import com.swirlds.platform.system.BasicSoftwareVersion; import com.swirlds.platform.system.Platform; import com.swirlds.platform.system.SoftwareVersion; import com.swirlds.platform.system.SwirldMain; +import com.swirlds.state.lifecycle.StateDefinition; +import com.swirlds.state.merkle.StateMetadata; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.security.SecureRandom; @@ -45,6 +53,31 @@ public class ConsistencyTestingToolMain implements SwirldMain { */ private static final SoftwareVersion softwareVersion = new BasicSoftwareVersion(1); + static { + try { + logger.info(STARTUP.getMarker(), "Registering ConsistencyTestingToolState with ConstructableRegistry"); + ConstructableRegistry constructableRegistry = ConstructableRegistry.getInstance(); + constructableRegistry.registerConstructable(new ClassConstructorPair( + ConsistencyTestingToolState.class, + () -> new ConsistencyTestingToolState( + NO_OP_MERKLE_STATE_LIFECYCLES, version -> new BasicSoftwareVersion(version.major())))); + logger.info(STARTUP.getMarker(), "ConsistencyTestingToolState is registered with ConstructableRegistry"); + registerPlatformClasses(constructableRegistry); + + } catch (ConstructableRegistryException e) { + logger.error(STARTUP.getMarker(), "Failed to register ConsistencyTestingToolState", e); + throw new RuntimeException(e); + } + } + + private static void registerPlatformClasses(ConstructableRegistry constructableRegistry) { + logger.info(STARTUP.getMarker(), "Registering PlatformState classes with ConstructableRegistry"); + final var schema = new V0540PlatformStateSchema(); + final StateDefinition def = schema.statesToCreate().iterator().next(); + final var md = new StateMetadata<>(PlatformStateService.NAME, schema, def); + registerWithSystem(md, constructableRegistry); + } + /** * The platform instance */ @@ -88,9 +121,12 @@ public void run() { */ @Override @NonNull - public MerkleRoot newMerkleStateRoot() { - final State state = new State(); - state.setSwirldState(new ConsistencyTestingToolState()); + public MerkleStateRoot newMerkleStateRoot() { + final MerkleStateRoot state = new ConsistencyTestingToolState( + NO_OP_MERKLE_STATE_LIFECYCLES, version -> new BasicSoftwareVersion(softwareVersion.getVersion())); + NO_OP_MERKLE_STATE_LIFECYCLES.initPlatformState(state); + registerPlatformClasses(ConstructableRegistry.INSTANCE); + return state; } diff --git a/platform-sdk/platform-apps/tests/ConsistencyTestingTool/src/main/java/com/swirlds/demo/consistency/ConsistencyTestingToolRound.java b/platform-sdk/platform-apps/tests/ConsistencyTestingTool/src/main/java/com/swirlds/demo/consistency/ConsistencyTestingToolRound.java index f1df5c5a342a..e3ff72b2257f 100644 --- a/platform-sdk/platform-apps/tests/ConsistencyTestingTool/src/main/java/com/swirlds/demo/consistency/ConsistencyTestingToolRound.java +++ b/platform-sdk/platform-apps/tests/ConsistencyTestingTool/src/main/java/com/swirlds/demo/consistency/ConsistencyTestingToolRound.java @@ -25,6 +25,8 @@ import java.util.Arrays; import java.util.List; import java.util.Objects; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; /** * Represents a round in the ConsistencyTestingTool @@ -36,6 +38,8 @@ public record ConsistencyTestingToolRound(long roundNumber, long currentState, @NonNull List transactionsContents) implements Comparable { + private static final Logger logger = LogManager.getLogger(ConsistencyTestingToolRound.class); + private static final String ROUND_NUMBER_STRING = "Round Number: "; private static final String CURRENT_STATE_STRING = "Current State: "; private static final String TRANSACTIONS_STRING = "Transactions: "; diff --git a/platform-sdk/platform-apps/tests/ConsistencyTestingTool/src/main/java/com/swirlds/demo/consistency/ConsistencyTestingToolState.java b/platform-sdk/platform-apps/tests/ConsistencyTestingTool/src/main/java/com/swirlds/demo/consistency/ConsistencyTestingToolState.java index 4cbd7b6c7b7b..23704fbcbc29 100644 --- a/platform-sdk/platform-apps/tests/ConsistencyTestingTool/src/main/java/com/swirlds/demo/consistency/ConsistencyTestingToolState.java +++ b/platform-sdk/platform-apps/tests/ConsistencyTestingTool/src/main/java/com/swirlds/demo/consistency/ConsistencyTestingToolState.java @@ -19,22 +19,22 @@ import static com.swirlds.common.utility.ByteUtils.byteArrayToLong; import static com.swirlds.logging.legacy.LogMarker.EXCEPTION; import static com.swirlds.logging.legacy.LogMarker.STARTUP; +import static com.swirlds.platform.util.NoOpMerkleStateLifecycles.NO_OP_MERKLE_STATE_LIFECYCLES; +import com.hedera.hapi.node.base.SemanticVersion; import com.swirlds.common.config.StateCommonConfig; -import com.swirlds.common.io.streams.SerializableDataInputStream; -import com.swirlds.common.io.streams.SerializableDataOutputStream; -import com.swirlds.common.merkle.MerkleLeaf; -import com.swirlds.common.merkle.impl.PartialMerkleLeaf; +import com.swirlds.common.constructable.ConstructableIgnored; import com.swirlds.common.utility.NonCryptographicHashing; -import com.swirlds.platform.state.PlatformStateAccessor; +import com.swirlds.platform.state.MerkleStateLifecycles; +import com.swirlds.platform.state.MerkleStateRoot; import com.swirlds.platform.state.PlatformStateModifier; import com.swirlds.platform.system.InitTrigger; import com.swirlds.platform.system.Platform; import com.swirlds.platform.system.Round; import com.swirlds.platform.system.SoftwareVersion; -import com.swirlds.platform.system.SwirldState; import com.swirlds.platform.system.events.Event; import com.swirlds.platform.system.transaction.ConsensusTransaction; +import com.swirlds.state.merkle.singleton.StringLeaf; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.io.IOException; @@ -45,13 +45,15 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; /** * State for the Consistency Testing Tool */ -public class ConsistencyTestingToolState extends PartialMerkleLeaf implements SwirldState, MerkleLeaf { +@ConstructableIgnored +public class ConsistencyTestingToolState extends MerkleStateRoot { private static final Logger logger = LogManager.getLogger(ConsistencyTestingToolState.class); private static final long CLASS_ID = 0xda03bb07eb897d82L; @@ -59,6 +61,9 @@ private static class ClassVersion { public static final int ORIGINAL = 1; } + private static final int STATE_LONG_INDEX = 1; + private static final int ROUND_HANDLED_INDEX = 2; + /** * The history of transactions that have been handled by this app. *

@@ -70,14 +75,14 @@ private static class ClassVersion { /** * The true "state" of this app. This long value is updated with every transaction, and with every round. *

- * Effects the hash of this node. + * Affects the hash of this node. */ private long stateLong = 0; /** * The number of rounds handled by this app. Is incremented each time - * {@link #handleConsensusRound(Round, PlatformStateAccessor)} is called. Note that this may not actually equal the round - * number, since we don't call {@link #handleConsensusRound(Round, PlatformStateAccessor)} for rounds with no events. + * {@link #handleConsensusRound(Round, PlatformStateModifier)} is called. Note that this may not actually equal the round + * number, since we don't call {@link #handleConsensusRound(Round, PlatformStateModifier)} for rounds with no events. * *

* Affects the hash of this node. @@ -104,7 +109,10 @@ private static class ClassVersion { /** * Constructor */ - public ConsistencyTestingToolState() { + public ConsistencyTestingToolState( + @NonNull final MerkleStateLifecycles lifecycles, + @NonNull final Function versionFactory) { + super(lifecycles, versionFactory); logger.info(STARTUP.getMarker(), "New State Constructed."); this.transactionHandlingHistory = new TransactionHandlingHistory(); @@ -155,7 +163,19 @@ public void init( this.freezeAfterGenesis = testingToolConfig.freezeAfterGenesis(); + final StringLeaf stateLongLeaf = getChild(STATE_LONG_INDEX); + if (stateLongLeaf != null && stateLongLeaf.getLabel() != null) { + this.stateLong = Long.parseLong(stateLongLeaf.getLabel()); + logger.info(STARTUP.getMarker(), "State initialized with state long {}.", stateLong); + } + final StringLeaf roundsHandledLeaf = getChild(ROUND_HANDLED_INDEX); + if (roundsHandledLeaf != null && roundsHandledLeaf.getLabel() != null) { + this.roundsHandled = Long.parseLong(roundsHandledLeaf.getLabel()); + logger.info(STARTUP.getMarker(), "State initialized with {} rounds handled.", roundsHandled); + } + transactionHandlingHistory.init(logFilePath); + NO_OP_MERKLE_STATE_LIFECYCLES.initPlatformState(this); } /** @@ -170,26 +190,15 @@ public long getClassId() { * {@inheritDoc} */ @Override - public void serialize(final @NonNull SerializableDataOutputStream out) throws IOException { - Objects.requireNonNull(out); - out.writeLong(stateLong); - out.writeLong(roundsHandled); - } - - /** - * {@inheritDoc} - */ - @Override - public void deserialize(final @NonNull SerializableDataInputStream in, final int version) throws IOException { - stateLong = Objects.requireNonNull(in).readLong(); - roundsHandled = in.readLong(); + public int getVersion() { + return ClassVersion.ORIGINAL; } /** * {@inheritDoc} */ @Override - public int getVersion() { + public int getMinimumSupportedVersion() { return ClassVersion.ORIGINAL; } @@ -200,6 +209,7 @@ public int getVersion() { @NonNull public synchronized ConsistencyTestingToolState copy() { throwIfImmutable(); + setImmutable(true); return new ConsistencyTestingToolState(this); } @@ -269,5 +279,8 @@ public void handleConsensusRound(final @NonNull Round round, final @NonNull Plat stateLong = NonCryptographicHashing.hash64(stateLong, round.getRoundNum()); transactionHandlingHistory.processRound(ConsistencyTestingToolRound.fromRound(round, stateLong)); + + setChild(ROUND_HANDLED_INDEX, new StringLeaf(Long.toString(roundsHandled))); + setChild(STATE_LONG_INDEX, new StringLeaf(Long.toString(stateLong))); } } diff --git a/platform-sdk/platform-apps/tests/ConsistencyTestingTool/src/main/java/module-info.java b/platform-sdk/platform-apps/tests/ConsistencyTestingTool/src/main/java/module-info.java index be312e2cff34..c525c555dc08 100644 --- a/platform-sdk/platform-apps/tests/ConsistencyTestingTool/src/main/java/module-info.java +++ b/platform-sdk/platform-apps/tests/ConsistencyTestingTool/src/main/java/module-info.java @@ -1,9 +1,12 @@ module com.swirlds.demo.consistency { + requires com.hedera.node.hapi; requires com.swirlds.base; requires com.swirlds.common; requires com.swirlds.config.api; requires com.swirlds.logging; requires com.swirlds.platform.core; + requires com.swirlds.state.api; + requires com.swirlds.state.impl; requires com.hedera.pbj.runtime; requires org.apache.logging.log4j; requires static com.github.spotbugs.annotations; diff --git a/platform-sdk/platform-apps/tests/ISSTestingTool/src/main/java/com/swirlds/demo/iss/ISSTestingToolMain.java b/platform-sdk/platform-apps/tests/ISSTestingTool/src/main/java/com/swirlds/demo/iss/ISSTestingToolMain.java index 1bd1ca3e790e..dcbe18542c62 100644 --- a/platform-sdk/platform-apps/tests/ISSTestingTool/src/main/java/com/swirlds/demo/iss/ISSTestingToolMain.java +++ b/platform-sdk/platform-apps/tests/ISSTestingTool/src/main/java/com/swirlds/demo/iss/ISSTestingToolMain.java @@ -19,13 +19,13 @@ import static com.swirlds.logging.legacy.LogMarker.STARTUP; import com.swirlds.common.platform.NodeId; -import com.swirlds.platform.state.MerkleRoot; -import com.swirlds.platform.state.State; +import com.swirlds.platform.state.MerkleStateRoot; import com.swirlds.platform.system.BasicSoftwareVersion; import com.swirlds.platform.system.Platform; import com.swirlds.platform.system.SwirldMain; import com.swirlds.platform.system.state.notifications.IssListener; import com.swirlds.platform.system.state.notifications.IssNotification; +import com.swirlds.platform.util.NoOpMerkleStateLifecycles; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.util.List; @@ -89,9 +89,11 @@ public void run() { */ @Override @NonNull - public MerkleRoot newMerkleStateRoot() { - final State state = new State(); - state.setSwirldState(new ISSTestingToolState()); + public MerkleStateRoot newMerkleStateRoot() { + final MerkleStateRoot state = new ISSTestingToolState( + NoOpMerkleStateLifecycles.NO_OP_MERKLE_STATE_LIFECYCLES, + version -> new BasicSoftwareVersion(softwareVersion.getSoftwareVersion())); + NoOpMerkleStateLifecycles.NO_OP_MERKLE_STATE_LIFECYCLES.initPlatformState(state); return state; } diff --git a/platform-sdk/platform-apps/tests/ISSTestingTool/src/main/java/com/swirlds/demo/iss/ISSTestingToolState.java b/platform-sdk/platform-apps/tests/ISSTestingTool/src/main/java/com/swirlds/demo/iss/ISSTestingToolState.java index 8c15be311f34..1e4e19e87a8f 100644 --- a/platform-sdk/platform-apps/tests/ISSTestingTool/src/main/java/com/swirlds/demo/iss/ISSTestingToolState.java +++ b/platform-sdk/platform-apps/tests/ISSTestingTool/src/main/java/com/swirlds/demo/iss/ISSTestingToolState.java @@ -32,27 +32,25 @@ import static com.swirlds.logging.legacy.LogMarker.EXCEPTION; import static com.swirlds.logging.legacy.LogMarker.STARTUP; +import com.hedera.hapi.node.base.SemanticVersion; import com.hedera.hapi.node.state.roster.Roster; import com.hedera.hapi.node.state.roster.RosterEntry; -import com.swirlds.common.io.streams.SerializableDataInputStream; -import com.swirlds.common.io.streams.SerializableDataOutputStream; -import com.swirlds.common.merkle.MerkleLeaf; -import com.swirlds.common.merkle.impl.PartialMerkleLeaf; +import com.swirlds.common.constructable.ConstructableIgnored; import com.swirlds.common.merkle.utility.SerializableLong; import com.swirlds.common.platform.NodeId; import com.swirlds.common.utility.ByteUtils; import com.swirlds.platform.scratchpad.Scratchpad; +import com.swirlds.platform.state.MerkleStateLifecycles; +import com.swirlds.platform.state.MerkleStateRoot; import com.swirlds.platform.state.PlatformStateModifier; import com.swirlds.platform.system.InitTrigger; import com.swirlds.platform.system.Platform; import com.swirlds.platform.system.Round; import com.swirlds.platform.system.SoftwareVersion; -import com.swirlds.platform.system.SwirldState; import com.swirlds.platform.system.events.ConsensusEvent; import com.swirlds.platform.system.transaction.ConsensusTransaction; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; -import java.io.IOException; import java.time.Duration; import java.time.Instant; import java.util.HashMap; @@ -62,13 +60,15 @@ import java.util.Map; import java.util.Objects; import java.util.Random; +import java.util.function.Function; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; /** * State for the ISSTestingTool. */ -public class ISSTestingToolState extends PartialMerkleLeaf implements SwirldState, MerkleLeaf { +@ConstructableIgnored +public class ISSTestingToolState extends MerkleStateRoot { private static final Logger logger = LogManager.getLogger(ISSTestingToolState.class); @@ -110,7 +110,11 @@ private static class ClassVersion { private Scratchpad scratchPad; - public ISSTestingToolState() {} + public ISSTestingToolState( + @NonNull final MerkleStateLifecycles lifecycles, + @NonNull final Function versionFactory) { + super(lifecycles, versionFactory); + } /** * Copy constructor. @@ -140,6 +144,7 @@ public boolean isImmutable() { @Override public synchronized ISSTestingToolState copy() { throwIfImmutable(); + setImmutable(true); return new ISSTestingToolState(this); } @@ -151,6 +156,7 @@ public void init( @NonNull final Platform platform, @NonNull final InitTrigger trigger, @Nullable final SoftwareVersion previousSoftwareVersion) { + super.init(platform, trigger, previousSoftwareVersion); throwIfImmutable(); @@ -391,28 +397,6 @@ private void triggerLogError( elapsedSinceGenesis); } - /** - * {@inheritDoc} - */ - @Override - public void serialize(final SerializableDataOutputStream out) throws IOException { - out.writeLong(runningSum); - out.writeInstant(genesisTimestamp); - out.writeSerializableList(plannedIssList, false, true); - out.writeSerializableList(plannedLogErrorList, false, true); - } - - /** - * {@inheritDoc} - */ - @Override - public void deserialize(final SerializableDataInputStream in, final int version) throws IOException { - runningSum = in.readLong(); - genesisTimestamp = in.readInstant(); - plannedIssList = in.readSerializableList(1024, false, PlannedIss::new); - plannedLogErrorList = in.readSerializableList(1024, false, PlannedLogError::new); - } - /** * {@inheritDoc} */ diff --git a/platform-sdk/platform-apps/tests/ISSTestingTool/src/main/java/module-info.java b/platform-sdk/platform-apps/tests/ISSTestingTool/src/main/java/module-info.java index 4ddb608720bd..b621bdaab105 100644 --- a/platform-sdk/platform-apps/tests/ISSTestingTool/src/main/java/module-info.java +++ b/platform-sdk/platform-apps/tests/ISSTestingTool/src/main/java/module-info.java @@ -5,6 +5,7 @@ requires com.swirlds.config.api; requires com.swirlds.logging; requires com.swirlds.platform.core; + requires com.swirlds.state.api; requires com.hedera.pbj.runtime; requires org.apache.logging.log4j; requires static com.github.spotbugs.annotations; diff --git a/platform-sdk/platform-apps/tests/MigrationTestingTool/src/main/java/com/swirlds/demo/migration/MigrationTestingToolMain.java b/platform-sdk/platform-apps/tests/MigrationTestingTool/src/main/java/com/swirlds/demo/migration/MigrationTestingToolMain.java index 8ac8ecb4e3d5..78959e527143 100644 --- a/platform-sdk/platform-apps/tests/MigrationTestingTool/src/main/java/com/swirlds/demo/migration/MigrationTestingToolMain.java +++ b/platform-sdk/platform-apps/tests/MigrationTestingTool/src/main/java/com/swirlds/demo/migration/MigrationTestingToolMain.java @@ -24,11 +24,11 @@ import com.swirlds.logging.legacy.payload.ApplicationFinishedPayload; import com.swirlds.merkle.map.MerkleMapMetrics; import com.swirlds.platform.ParameterProvider; -import com.swirlds.platform.state.MerkleRoot; -import com.swirlds.platform.state.State; +import com.swirlds.platform.state.MerkleStateRoot; import com.swirlds.platform.system.BasicSoftwareVersion; import com.swirlds.platform.system.Platform; import com.swirlds.platform.system.SwirldMain; +import com.swirlds.platform.util.NoOpMerkleStateLifecycles; import edu.umd.cs.findbugs.annotations.NonNull; import java.security.SignatureException; import org.apache.logging.log4j.LogManager; @@ -166,9 +166,11 @@ private void throttleTransactionCreation() throws InterruptedException { */ @NonNull @Override - public MerkleRoot newMerkleStateRoot() { - final State state = new State(); - state.setSwirldState(new MigrationTestingToolState()); + public MerkleStateRoot newMerkleStateRoot() { + final MerkleStateRoot state = new MigrationTestingToolState( + NoOpMerkleStateLifecycles.NO_OP_MERKLE_STATE_LIFECYCLES, + version -> new BasicSoftwareVersion(softwareVersion.getSoftwareVersion())); + NoOpMerkleStateLifecycles.NO_OP_MERKLE_STATE_LIFECYCLES.initPlatformState(state); return state; } diff --git a/platform-sdk/platform-apps/tests/MigrationTestingTool/src/main/java/com/swirlds/demo/migration/MigrationTestingToolState.java b/platform-sdk/platform-apps/tests/MigrationTestingTool/src/main/java/com/swirlds/demo/migration/MigrationTestingToolState.java index da3a96b4f48b..af4b8cb98093 100644 --- a/platform-sdk/platform-apps/tests/MigrationTestingTool/src/main/java/com/swirlds/demo/migration/MigrationTestingToolState.java +++ b/platform-sdk/platform-apps/tests/MigrationTestingTool/src/main/java/com/swirlds/demo/migration/MigrationTestingToolState.java @@ -19,10 +19,10 @@ import static com.swirlds.demo.migration.MigrationTestingToolMain.PREVIOUS_SOFTWARE_VERSION; import static com.swirlds.logging.legacy.LogMarker.STARTUP; +import com.hedera.hapi.node.base.SemanticVersion; +import com.swirlds.common.constructable.ConstructableIgnored; import com.swirlds.common.crypto.DigestType; -import com.swirlds.common.merkle.MerkleInternal; import com.swirlds.common.merkle.MerkleNode; -import com.swirlds.common.merkle.impl.PartialNaryMerkleInternal; import com.swirlds.common.platform.NodeId; import com.swirlds.config.api.Configuration; import com.swirlds.config.api.ConfigurationBuilder; @@ -35,12 +35,13 @@ import com.swirlds.merkledb.MerkleDbDataSourceBuilder; import com.swirlds.merkledb.MerkleDbTableConfig; import com.swirlds.merkledb.config.MerkleDbConfig; +import com.swirlds.platform.state.MerkleStateLifecycles; +import com.swirlds.platform.state.MerkleStateRoot; import com.swirlds.platform.state.PlatformStateModifier; import com.swirlds.platform.system.InitTrigger; import com.swirlds.platform.system.Platform; import com.swirlds.platform.system.Round; import com.swirlds.platform.system.SoftwareVersion; -import com.swirlds.platform.system.SwirldState; import com.swirlds.platform.system.address.AddressBook; import com.swirlds.platform.system.events.ConsensusEvent; import com.swirlds.platform.system.transaction.ConsensusTransaction; @@ -50,10 +51,12 @@ import edu.umd.cs.findbugs.annotations.Nullable; import java.util.Iterator; import java.util.List; +import java.util.function.Function; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -public class MigrationTestingToolState extends PartialNaryMerkleInternal implements MerkleInternal, SwirldState { +@ConstructableIgnored +public class MigrationTestingToolState extends MerkleStateRoot { private static final Logger logger = LogManager.getLogger(MigrationTestingToolState.class); /** @@ -95,8 +98,11 @@ private static class ChildIndices { public NodeId selfId; - public MigrationTestingToolState() { - super(ChildIndices.CHILD_COUNT); + public MigrationTestingToolState( + @NonNull final MerkleStateLifecycles lifecycles, + @NonNull final Function versionFactory) { + super(lifecycles, versionFactory); + allocateSpaceForChild(ChildIndices.CHILD_COUNT); } private MigrationTestingToolState(final MigrationTestingToolState that) { @@ -231,6 +237,8 @@ public void init( @NonNull final Platform platform, @NonNull final InitTrigger trigger, @Nullable final SoftwareVersion previousSoftwareVersion) { + super.init(platform, trigger, previousSoftwareVersion); + final MerkleMap merkleMap = getMerkleMap(); if (merkleMap != null) { logger.info(STARTUP.getMarker(), "MerkleMap initialized with {} values", merkleMap.size()); @@ -286,6 +294,7 @@ public void handleConsensusRound(final Round round, final PlatformStateModifier @Override public MigrationTestingToolState copy() { throwIfImmutable(); + setImmutable(true); return new MigrationTestingToolState(this); } diff --git a/platform-sdk/platform-apps/tests/MigrationTestingTool/src/main/java/module-info.java b/platform-sdk/platform-apps/tests/MigrationTestingTool/src/main/java/module-info.java index 51a47b50d856..167e8678b2f6 100644 --- a/platform-sdk/platform-apps/tests/MigrationTestingTool/src/main/java/module-info.java +++ b/platform-sdk/platform-apps/tests/MigrationTestingTool/src/main/java/module-info.java @@ -1,4 +1,5 @@ module com.swirlds.demo.migration { + requires com.hedera.node.hapi; requires com.swirlds.base; requires com.swirlds.common; requires com.swirlds.config.api; @@ -8,6 +9,7 @@ requires com.swirlds.merkledb; requires com.swirlds.metrics.api; requires com.swirlds.platform.core; + requires com.swirlds.state.api; requires com.swirlds.virtualmap; requires com.hedera.pbj.runtime; requires java.logging; diff --git a/platform-sdk/platform-apps/tests/PlatformTestingTool/build.gradle.kts b/platform-sdk/platform-apps/tests/PlatformTestingTool/build.gradle.kts index 5eddb4203445..e84c41fe4b1d 100644 --- a/platform-sdk/platform-apps/tests/PlatformTestingTool/build.gradle.kts +++ b/platform-sdk/platform-apps/tests/PlatformTestingTool/build.gradle.kts @@ -44,6 +44,7 @@ timingSensitiveModuleInfo { requires("com.swirlds.merkle") requires("com.swirlds.merkle.test.fixtures") requires("com.swirlds.platform.core") + requires("com.hedera.node.hapi") requires("org.junit.jupiter.api") requires("org.junit.jupiter.params") requires("org.mockito") diff --git a/platform-sdk/platform-apps/tests/PlatformTestingTool/src/main/java/com/swirlds/demo/platform/PayloadCfgSimple.java b/platform-sdk/platform-apps/tests/PlatformTestingTool/src/main/java/com/swirlds/demo/platform/PayloadCfgSimple.java index 759054d4549f..4a45c94775a2 100644 --- a/platform-sdk/platform-apps/tests/PlatformTestingTool/src/main/java/com/swirlds/demo/platform/PayloadCfgSimple.java +++ b/platform-sdk/platform-apps/tests/PlatformTestingTool/src/main/java/com/swirlds/demo/platform/PayloadCfgSimple.java @@ -23,9 +23,16 @@ import com.swirlds.common.merkle.MerkleLeaf; import com.swirlds.common.merkle.impl.PartialMerkleLeaf; import java.io.IOException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.MarkerManager; public class PayloadCfgSimple extends PartialMerkleLeaf implements MerkleLeaf { + private static final Logger logger = LogManager.getLogger(PayloadCfgSimple.class); + private static final Marker LOGM_DEMO_INFO = MarkerManager.getMarker("DEMO_INFO"); + /** * The version history of this class. * Versions that have been released must NEVER be given a different value. @@ -160,10 +167,21 @@ private static class ClassVersion { */ private float ratioOfFCMTransaction; - public PayloadCfgSimple() {} + public PayloadCfgSimple() { + // logger.info( + // LOGM_DEMO_INFO, + // "PayloadCfgSimple., immutable: {}, StackTrace: {}", + // isImmutable(), + // StackTrace.getStackTrace()); + } private PayloadCfgSimple(final PayloadCfgSimple sourcePayload) { super(sourcePayload); + // logger.info( + // LOGM_DEMO_INFO, + // "PayloadCfgSimple.(COPY), immutable: {}, StackTrace: {}", + // isImmutable(), + // StackTrace.getStackTrace()); setAppendSig(sourcePayload.appendSig); setInvalidSigRatio(sourcePayload.invalidSigRatio); setInsertSeq(sourcePayload.insertSeq); @@ -381,6 +399,11 @@ public void setRatioOfFCMTransaction(final float ratioOfFCMTransaction) { */ @Override public PayloadCfgSimple copy() { + // logger.info( + // LOGM_DEMO_INFO, + // "PayloadCfgSimple.copy(), immutable: {}, StackTrace: {}", + // isImmutable(), + // StackTrace.getStackTrace()); throwIfImmutable(); return new PayloadCfgSimple(this); } diff --git a/platform-sdk/platform-apps/tests/PlatformTestingTool/src/main/java/com/swirlds/demo/platform/PlatformTestingToolMain.java b/platform-sdk/platform-apps/tests/PlatformTestingTool/src/main/java/com/swirlds/demo/platform/PlatformTestingToolMain.java index e1847a320e8a..0f72ff44f8c6 100644 --- a/platform-sdk/platform-apps/tests/PlatformTestingTool/src/main/java/com/swirlds/demo/platform/PlatformTestingToolMain.java +++ b/platform-sdk/platform-apps/tests/PlatformTestingTool/src/main/java/com/swirlds/demo/platform/PlatformTestingToolMain.java @@ -30,12 +30,14 @@ import static com.swirlds.common.threading.manager.AdHocThreadManager.getStaticThreadManager; import static com.swirlds.logging.legacy.LogMarker.DEMO_INFO; import static com.swirlds.logging.legacy.LogMarker.EXCEPTION; +import static com.swirlds.logging.legacy.LogMarker.STARTUP; import static com.swirlds.merkle.test.fixtures.map.lifecycle.EntityType.Crypto; import static com.swirlds.merkle.test.fixtures.map.lifecycle.SaveExpectedMapHandler.STORAGE_DIRECTORY; import static com.swirlds.merkle.test.fixtures.map.lifecycle.SaveExpectedMapHandler.createExpectedMapName; import static com.swirlds.merkle.test.fixtures.map.lifecycle.SaveExpectedMapHandler.serialize; import static com.swirlds.metrics.api.FloatFormats.FORMAT_6_2; import static com.swirlds.metrics.api.FloatFormats.FORMAT_9_6; +import static com.swirlds.state.merkle.StateUtils.registerWithSystem; import static java.lang.System.exit; import com.fasterxml.jackson.core.JsonParser; @@ -43,6 +45,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.swirlds.base.units.UnitConstants; import com.swirlds.base.utility.Pair; +import com.swirlds.common.constructable.ClassConstructorPair; +import com.swirlds.common.constructable.ConstructableRegistry; +import com.swirlds.common.constructable.ConstructableRegistryException; +import com.swirlds.common.constructable.NoArgsConstructor; import com.swirlds.common.merkle.iterators.MerkleIterator; import com.swirlds.common.metrics.RunningAverageMetric; import com.swirlds.common.metrics.SpeedometerMetric; @@ -79,8 +85,9 @@ import com.swirlds.platform.listeners.PlatformStatusChangeNotification; import com.swirlds.platform.listeners.ReconnectCompleteListener; import com.swirlds.platform.listeners.StateWriteToDiskCompleteListener; -import com.swirlds.platform.state.MerkleRoot; -import com.swirlds.platform.state.State; +import com.swirlds.platform.state.MerkleStateRoot; +import com.swirlds.platform.state.service.PlatformStateService; +import com.swirlds.platform.state.service.schemas.V0540PlatformStateSchema; import com.swirlds.platform.system.BasicSoftwareVersion; import com.swirlds.platform.system.Platform; import com.swirlds.platform.system.SwirldMain; @@ -88,6 +95,9 @@ import com.swirlds.platform.system.SystemExitUtils; import com.swirlds.platform.system.state.notifications.NewSignedStateListener; import com.swirlds.platform.system.status.PlatformStatus; +import com.swirlds.platform.util.NoOpMerkleStateLifecycles; +import com.swirlds.state.lifecycle.StateDefinition; +import com.swirlds.state.merkle.StateMetadata; import com.swirlds.virtualmap.internal.merkle.VirtualLeafNode; import edu.umd.cs.findbugs.annotations.NonNull; import java.io.File; @@ -136,6 +146,39 @@ public class PlatformTestingToolMain implements SwirldMain { private static final String FCM_CATEGORY = "FCM"; private static final String VM_CATEGORY = "VM"; + + static { + try { + logger.info(STARTUP.getMarker(), "Registering PlatformTestingToolState with ConstructableRegistry"); + ConstructableRegistry.getInstance() + .registerConstructable(new ClassConstructorPair( + PlatformTestingToolState.class, + () -> new PlatformTestingToolState( + NoOpMerkleStateLifecycles.NO_OP_MERKLE_STATE_LIFECYCLES, + version -> new BasicSoftwareVersion(version.major())))); + logger.info( + STARTUP.getMarker(), + "PlatformTestingToolState is registered with ConstructableRegistry: {}", + ConstructableRegistry.getInstance() + .getRegistry(NoArgsConstructor.class) + .getConstructor(PlatformTestingToolState.CLASS_ID) + .get() + .getClassId()); + registerPlatformClasses(ConstructableRegistry.getInstance()); + } catch (ConstructableRegistryException e) { + logger.error(STARTUP.getMarker(), "Failed to register PlatformTestingToolState", e); + throw new RuntimeException(e); + } + } + + private static void registerPlatformClasses(ConstructableRegistry constructableRegistry) { + logger.info(STARTUP.getMarker(), "Registering PlatformState classes with ConstructableRegistry"); + final var schema = new V0540PlatformStateSchema(); + final StateDefinition def = schema.statesToCreate().iterator().next(); + final var md = new StateMetadata<>(PlatformStateService.NAME, schema, def); + registerWithSystem(md, constructableRegistry); + } + /** * save internal file logs and expected map to file while freezing; * for restart test we should set `saveExpectedMapAtFreeze` to be true, so that @@ -836,9 +879,12 @@ public void run() { @Override @NonNull - public MerkleRoot newMerkleStateRoot() { - final State state = new State(); - state.setSwirldState(new PlatformTestingToolState()); + public MerkleStateRoot newMerkleStateRoot() { + final MerkleStateRoot state = new PlatformTestingToolState( + NoOpMerkleStateLifecycles.NO_OP_MERKLE_STATE_LIFECYCLES, + version -> new BasicSoftwareVersion(softwareVersion.getSoftwareVersion())); + // logger.info(LOGM_STARTUP, "Initializing platform state..."); + NoOpMerkleStateLifecycles.NO_OP_MERKLE_STATE_LIFECYCLES.initPlatformState(state); return state; } diff --git a/platform-sdk/platform-apps/tests/PlatformTestingTool/src/main/java/com/swirlds/demo/platform/PlatformTestingToolState.java b/platform-sdk/platform-apps/tests/PlatformTestingTool/src/main/java/com/swirlds/demo/platform/PlatformTestingToolState.java index 0681177a515e..3741efab2648 100644 --- a/platform-sdk/platform-apps/tests/PlatformTestingTool/src/main/java/com/swirlds/demo/platform/PlatformTestingToolState.java +++ b/platform-sdk/platform-apps/tests/PlatformTestingTool/src/main/java/com/swirlds/demo/platform/PlatformTestingToolState.java @@ -31,13 +31,13 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.google.protobuf.InvalidProtocolBufferException; +import com.hedera.hapi.node.base.SemanticVersion; +import com.swirlds.common.constructable.*; import com.swirlds.common.crypto.CryptographyHolder; import com.swirlds.common.crypto.SignatureType; import com.swirlds.common.crypto.TransactionSignature; import com.swirlds.common.crypto.VerificationStatus; -import com.swirlds.common.merkle.MerkleInternal; import com.swirlds.common.merkle.MerkleNode; -import com.swirlds.common.merkle.impl.PartialNaryMerkleInternal; import com.swirlds.common.metrics.RunningAverageMetric; import com.swirlds.common.platform.NodeId; import com.swirlds.common.utility.ThresholdLimitingHandler; @@ -83,12 +83,10 @@ import com.swirlds.merkle.test.fixtures.map.pta.MapKey; import com.swirlds.platform.ParameterProvider; import com.swirlds.platform.Utilities; +import com.swirlds.platform.state.MerkleStateLifecycles; +import com.swirlds.platform.state.MerkleStateRoot; import com.swirlds.platform.state.PlatformStateModifier; -import com.swirlds.platform.system.InitTrigger; -import com.swirlds.platform.system.Platform; -import com.swirlds.platform.system.Round; -import com.swirlds.platform.system.SoftwareVersion; -import com.swirlds.platform.system.SwirldState; +import com.swirlds.platform.system.*; import com.swirlds.platform.system.address.AddressBook; import com.swirlds.platform.system.events.ConsensusEvent; import com.swirlds.platform.system.events.Event; @@ -116,6 +114,7 @@ import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Function; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Marker; @@ -126,9 +125,10 @@ * writes them to the screen, and also saves them to disk in a comma separated value (.csv) file. Each transaction * consists of an optional sequence number and random bytes. */ -public class PlatformTestingToolState extends PartialNaryMerkleInternal implements MerkleInternal, SwirldState { +@ConstructableIgnored +public class PlatformTestingToolState extends MerkleStateRoot { - private static final long CLASS_ID = 0xc0900cfa7a24db76L; + static final long CLASS_ID = 0xc0900cfa7a24db76L; private static final Logger logger = LogManager.getLogger(PlatformTestingToolState.class); private static final Marker LOGM_DEMO_INFO = MarkerManager.getMarker("DEMO_INFO"); private static final Marker LOGM_EXCEPTION = MarkerManager.getMarker("EXCEPTION"); @@ -243,8 +243,16 @@ public class PlatformTestingToolState extends PartialNaryMerkleInternal implemen private long transactionsIgnoredByExpectedMap = 0; - public PlatformTestingToolState() { - super(ChildIndices.CHILD_COUNT); + public PlatformTestingToolState( + @NonNull final MerkleStateLifecycles lifecycles, + @NonNull final Function versionFactory) { + super(lifecycles, versionFactory); + + // logger.info( + // LOGM_DEMO_INFO, + // "PlatformTestingToolState., immutable: {}, StackTrace: {}", + // isImmutable(), + // StackTrace.getStackTrace()); expectedFCMFamily = new ExpectedFCMFamilyImpl(); @@ -254,36 +262,43 @@ public PlatformTestingToolState() { protected PlatformTestingToolState(final PlatformTestingToolState sourceState) { super(sourceState); + // logger.info( + // LOGM_DEMO_INFO, + // "PlatformTestingToolState.(COPY), immutable: {}, StackTrace: {}", + // isImmutable(), + // StackTrace.getStackTrace()); + this.initialized.set(sourceState.initialized.get()); this.platform = sourceState.platform; - if (sourceState.getConfig() != null) { - setConfig(sourceState.getConfig().copy()); - } - - if (sourceState.getNextSeqCons() != null) { - setNextSeqCons(new NextSeqConsList(sourceState.getNextSeqCons())); - } - - if (sourceState.getFcmFamily() != null) { - setFcmFamily(sourceState.getFcmFamily().copy()); - } else { - setFcmFamily(new FCMFamily(true)); - } - - if (sourceState.getVirtualMap() != null) { - setVirtualMap(sourceState.getVirtualMap().copy()); - } - - if (sourceState.getVirtualMapForSmartContracts() != null) { - setVirtualMapForSmartContracts( - sourceState.getVirtualMapForSmartContracts().copy()); - } - - if (sourceState.getVirtualMapForSmartContractsByteCode() != null) { - setVirtualMapForSmartContractsByteCode( - sourceState.getVirtualMapForSmartContractsByteCode().copy()); - } + // commented because copying happens in super + // if (sourceState.getConfig() != null) { + // setConfig(sourceState.getConfig().copy()); + // } + // + // if (sourceState.getNextSeqCons() != null) { + // setNextSeqCons(new NextSeqConsList(sourceState.getNextSeqCons())); + // } + // + // if (sourceState.getFcmFamily() != null) { + // setFcmFamily(sourceState.getFcmFamily().copy()); + // } else { + // setFcmFamily(new FCMFamily(true)); + // } + // + // if (sourceState.getVirtualMap() != null) { + // setVirtualMap(sourceState.getVirtualMap().copy()); + // } + // + // if (sourceState.getVirtualMapForSmartContracts() != null) { + // setVirtualMapForSmartContracts( + // sourceState.getVirtualMapForSmartContracts().copy()); + // } + // + // if (sourceState.getVirtualMapForSmartContractsByteCode() != null) { + // setVirtualMapForSmartContractsByteCode( + // sourceState.getVirtualMapForSmartContractsByteCode().copy()); + // } this.lastFileTranFinishTimeStamp = sourceState.lastFileTranFinishTimeStamp; this.lastTranTimeStamp = sourceState.lastTranTimeStamp; @@ -315,21 +330,21 @@ protected PlatformTestingToolState(final PlatformTestingToolState sourceState) { } } - if (sourceState.getIssLeaf() != null) { - setIssLeaf(sourceState.getIssLeaf().copy()); - } + // if (sourceState.getIssLeaf() != null) { + // setIssLeaf(sourceState.getIssLeaf().copy()); + // } - if (sourceState.getNftLedger() != null) { - setNftLedger(sourceState.getNftLedger().copy()); - } + // if (sourceState.getNftLedger() != null) { + // setNftLedger(sourceState.getNftLedger().copy()); + // } // set the current value of QuorumResult from source state - if (sourceState.getQuorumResult() != null) { - setQuorumResult(sourceState.getQuorumResult().copy()); - } - if (controlQuorum != null) { - controlQuorum.setQuorumResult(getQuorumResult().copy()); - } + // if (sourceState.getQuorumResult() != null) { + // setQuorumResult(sourceState.getQuorumResult().copy()); + // } + // if (controlQuorum != null) { + // controlQuorum.setQuorumResult(getQuorumResult().copy()); + // } setImmutable(false); sourceState.setImmutable(true); @@ -409,14 +424,6 @@ private static void getCurrentTransactionStat() { static AtomicLong totalTransactionSignatureCount = new AtomicLong(0); static AtomicLong expectedInvalidSignatureCount = new AtomicLong(0); - /** - * {@inheritDoc} - */ - @Override - public int getNumberOfChildren() { - return ChildIndices.CHILD_COUNT; - } - /** * {@inheritDoc} */ @@ -438,10 +445,18 @@ public int getMaximumChildCount() { */ @Override public boolean childHasExpectedType(final int index, final long childClassId) { + // logger.info( + // DEMO_INFO.getMarker(), + // "Checking if childHasExpectedType for index: {}, childClassId: {}, StackTrace: {}", + // index, + // childClassId, + // StackTrace.getStackTrace()); + switch (index) { case ChildIndices.UNUSED: // We used to use this for an address book, but now we don't use this index. // Ignore whatever is found at this index. + // platform should be here, so check for singleton if all will be ok return true; case ChildIndices.CONFIG: return childClassId == PayloadCfgSimple.CLASS_ID; @@ -650,7 +665,14 @@ public synchronized ExpectedFCMFamily getStateExpectedMap() { */ @Override public synchronized PlatformTestingToolState copy() { + // logger.info( + // LOGM_DEMO_INFO, + // "PlatformTestingToolState.copy() immutable: {}, StackTrace: {}", + // isImmutable(), + // StackTrace.getStackTrace()); + throwIfImmutable(); + // setImmutable(true); roundCounter++; if (transactionsIgnoredByExpectedMap > 0) { @@ -1305,6 +1327,7 @@ public void init( @NonNull final Platform platform, @NonNull final InitTrigger trigger, @Nullable final SoftwareVersion previousSoftwareVersion) { + // super.init(platform, trigger, previousSoftwareVersion); if (trigger == InitTrigger.RESTART) { rebuildExpectedMapFromState(Instant.EPOCH, true); @@ -1646,7 +1669,7 @@ private static class ClassVersion { } private static class ChildIndices { - public static final int UNUSED = 0; + public static final int UNUSED = 0; // should be platform and singleton public static final int CONFIG = 1; /** * last sequence by each member for consensus events diff --git a/platform-sdk/platform-apps/tests/PlatformTestingTool/src/main/java/com/swirlds/demo/platform/TransactionCounter.java b/platform-sdk/platform-apps/tests/PlatformTestingTool/src/main/java/com/swirlds/demo/platform/TransactionCounter.java index caa21f720524..6e6cc87b9e37 100644 --- a/platform-sdk/platform-apps/tests/PlatformTestingTool/src/main/java/com/swirlds/demo/platform/TransactionCounter.java +++ b/platform-sdk/platform-apps/tests/PlatformTestingTool/src/main/java/com/swirlds/demo/platform/TransactionCounter.java @@ -31,6 +31,8 @@ */ public class TransactionCounter implements Cloneable, FastCopyable, SelfSerializable { + // private static final Marker LOGM_DEMO_INFO = MarkerManager.getMarker("DEMO_INFO"); + /** * The version history of this class. * Versions that have been released must NEVER be given a different value. @@ -102,6 +104,12 @@ public TransactionCounter(int nodeId) { public TransactionCounter() {} private TransactionCounter(final TransactionCounter sourceTransactionCounter) { + // logger.info( + // LOGM_DEMO_INFO, + // "TransactionCounter.(COPY), immutable: {}, StackTrace: {}", + // isImmutable(), + // StackTrace.getStackTrace()); + this.fcmCreateAmount = sourceTransactionCounter.fcmCreateAmount; this.fcmUpdateAmount = sourceTransactionCounter.fcmUpdateAmount; this.fcmDeleteAmount = sourceTransactionCounter.fcmDeleteAmount; @@ -129,7 +137,12 @@ private TransactionCounter(final TransactionCounter sourceTransactionCounter) { @Override public TransactionCounter copy() { - throwIfImmutable(); + // logger.info( + // LOGM_DEMO_INFO, + // "TransactionCounter.copy(), immutable: {}, StackTrace: {}", + // isImmutable(), + // StackTrace.getStackTrace()); + // throwIfImmutable(); return new TransactionCounter(this); } diff --git a/platform-sdk/platform-apps/tests/PlatformTestingTool/src/main/java/module-info.java b/platform-sdk/platform-apps/tests/PlatformTestingTool/src/main/java/module-info.java index d0009266a88a..818a3bcb6ce0 100644 --- a/platform-sdk/platform-apps/tests/PlatformTestingTool/src/main/java/module-info.java +++ b/platform-sdk/platform-apps/tests/PlatformTestingTool/src/main/java/module-info.java @@ -23,6 +23,8 @@ exports com.swirlds.demo.virtualmerkle.config to com.fasterxml.jackson.databind; + // requires com.swirlds.state.impl; + requires com.hedera.node.hapi; requires com.swirlds.base; requires com.swirlds.common.test.fixtures; requires com.swirlds.common; @@ -35,6 +37,8 @@ requires com.swirlds.merkledb; requires com.swirlds.metrics.api; requires com.swirlds.platform.core; + requires com.swirlds.state.api; + requires com.swirlds.state.impl; requires com.swirlds.virtualmap; requires com.fasterxml.jackson.annotation; requires com.fasterxml.jackson.core; diff --git a/platform-sdk/platform-apps/tests/PlatformTestingTool/src/timingSensitive/java/com/swirlds/demo/platform/PttTransactionPoolTest.java b/platform-sdk/platform-apps/tests/PlatformTestingTool/src/timingSensitive/java/com/swirlds/demo/platform/PttTransactionPoolTest.java index 1ff76d7aeb62..5f0fc9b30014 100644 --- a/platform-sdk/platform-apps/tests/PlatformTestingTool/src/timingSensitive/java/com/swirlds/demo/platform/PttTransactionPoolTest.java +++ b/platform-sdk/platform-apps/tests/PlatformTestingTool/src/timingSensitive/java/com/swirlds/demo/platform/PttTransactionPoolTest.java @@ -43,7 +43,9 @@ import com.swirlds.merkle.test.fixtures.map.lifecycle.LifecycleStatus; import com.swirlds.merkle.test.fixtures.map.lifecycle.TransactionState; import com.swirlds.merkle.test.fixtures.map.pta.MapKey; +import com.swirlds.platform.system.BasicSoftwareVersion; import com.swirlds.platform.system.Platform; +import com.swirlds.platform.util.NoOpMerkleStateLifecycles; import java.io.IOException; import java.time.Instant; import java.util.Random; @@ -180,7 +182,8 @@ public void fcqDeleteTest() { .setOriginNode(otherID) .build(); try { - final PlatformTestingToolState state = new PlatformTestingToolState(); + final PlatformTestingToolState state = new PlatformTestingToolState( + NoOpMerkleStateLifecycles.NO_OP_MERKLE_STATE_LIFECYCLES, version -> new BasicSoftwareVersion(1)); state.setFcmFamily(fCMFamily); handler.performOperation( trans, @@ -237,7 +240,8 @@ public void fcqDeleteNodeTest() { .setOriginNode(otherID) .build(); try { - final PlatformTestingToolState state = new PlatformTestingToolState(); + final PlatformTestingToolState state = new PlatformTestingToolState( + NoOpMerkleStateLifecycles.NO_OP_MERKLE_STATE_LIFECYCLES, version -> new BasicSoftwareVersion(1)); state.setFcmFamily(fCMFamily); handler.performOperation( trans, diff --git a/platform-sdk/platform-apps/tests/StatsSigningTestingTool/src/main/java/com/swirlds/demo/stats/signing/StatsSigningTestingToolMain.java b/platform-sdk/platform-apps/tests/StatsSigningTestingTool/src/main/java/com/swirlds/demo/stats/signing/StatsSigningTestingToolMain.java index a6db42b89082..325a995ee4f8 100644 --- a/platform-sdk/platform-apps/tests/StatsSigningTestingTool/src/main/java/com/swirlds/demo/stats/signing/StatsSigningTestingToolMain.java +++ b/platform-sdk/platform-apps/tests/StatsSigningTestingTool/src/main/java/com/swirlds/demo/stats/signing/StatsSigningTestingToolMain.java @@ -42,11 +42,11 @@ import com.swirlds.metrics.api.Metrics; import com.swirlds.platform.Browser; import com.swirlds.platform.ParameterProvider; -import com.swirlds.platform.state.MerkleRoot; -import com.swirlds.platform.state.State; +import com.swirlds.platform.state.MerkleStateRoot; import com.swirlds.platform.system.BasicSoftwareVersion; import com.swirlds.platform.system.Platform; import com.swirlds.platform.system.SwirldMain; +import com.swirlds.platform.util.NoOpMerkleStateLifecycles; import edu.umd.cs.findbugs.annotations.NonNull; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -272,9 +272,12 @@ private synchronized void generateTransactions() { @Override @NonNull - public MerkleRoot newMerkleStateRoot() { - final State state = new State(); - state.setSwirldState(new StatsSigningTestingToolState(() -> sttTransactionPool)); + public MerkleStateRoot newMerkleStateRoot() { + final MerkleStateRoot state = new StatsSigningTestingToolState( + NoOpMerkleStateLifecycles.NO_OP_MERKLE_STATE_LIFECYCLES, + version -> new BasicSoftwareVersion(softwareVersion.getSoftwareVersion()), + () -> sttTransactionPool); + NoOpMerkleStateLifecycles.NO_OP_MERKLE_STATE_LIFECYCLES.initPlatformState(state); return state; } diff --git a/platform-sdk/platform-apps/tests/StatsSigningTestingTool/src/main/java/com/swirlds/demo/stats/signing/StatsSigningTestingToolState.java b/platform-sdk/platform-apps/tests/StatsSigningTestingTool/src/main/java/com/swirlds/demo/stats/signing/StatsSigningTestingToolState.java index 22c71f3f071d..cd78c30a16cf 100644 --- a/platform-sdk/platform-apps/tests/StatsSigningTestingTool/src/main/java/com/swirlds/demo/stats/signing/StatsSigningTestingToolState.java +++ b/platform-sdk/platform-apps/tests/StatsSigningTestingTool/src/main/java/com/swirlds/demo/stats/signing/StatsSigningTestingToolState.java @@ -30,26 +30,26 @@ import static com.swirlds.logging.legacy.LogMarker.EXCEPTION; import static com.swirlds.logging.legacy.LogMarker.TESTING_EXCEPTIONS_ACCEPTABLE_RECONNECT; +import com.hedera.hapi.node.base.SemanticVersion; +import com.swirlds.common.constructable.ConstructableIgnored; import com.swirlds.common.crypto.CryptographyHolder; import com.swirlds.common.crypto.TransactionSignature; import com.swirlds.common.crypto.VerificationStatus; -import com.swirlds.common.io.streams.SerializableDataInputStream; -import com.swirlds.common.io.streams.SerializableDataOutputStream; -import com.swirlds.common.merkle.MerkleLeaf; -import com.swirlds.common.merkle.impl.PartialMerkleLeaf; +import com.swirlds.platform.state.MerkleStateLifecycles; +import com.swirlds.platform.state.MerkleStateRoot; import com.swirlds.platform.state.PlatformStateModifier; import com.swirlds.platform.system.Round; -import com.swirlds.platform.system.SwirldState; +import com.swirlds.platform.system.SoftwareVersion; import com.swirlds.platform.system.events.Event; import com.swirlds.platform.system.transaction.ConsensusTransaction; import com.swirlds.platform.system.transaction.Transaction; import edu.umd.cs.findbugs.annotations.NonNull; -import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +import java.util.function.Function; import java.util.function.Supplier; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -61,7 +61,8 @@ * is 100 random bytes. So StatsSigningDemoState.handleTransaction doesn't actually do anything, other than the * optional sequence number check. */ -public class StatsSigningTestingToolState extends PartialMerkleLeaf implements SwirldState, MerkleLeaf { +@ConstructableIgnored +public class StatsSigningTestingToolState extends MerkleStateRoot { private static final long CLASS_ID = 0x79900efa3127b6eL; /** @@ -80,11 +81,11 @@ public class StatsSigningTestingToolState extends PartialMerkleLeaf implements S /** the number of microseconds to wait before returning from the handle method */ private static final int HANDLE_MICROS = 100; - public StatsSigningTestingToolState() { - this(() -> null); - } - - public StatsSigningTestingToolState(@NonNull final Supplier transactionPoolSupplier) { + public StatsSigningTestingToolState( + @NonNull final MerkleStateLifecycles lifecycles, + @NonNull final Function versionFactory, + @NonNull final Supplier transactionPoolSupplier) { + super(lifecycles, versionFactory); this.transactionPoolSupplier = Objects.requireNonNull(transactionPoolSupplier); } @@ -101,6 +102,7 @@ private StatsSigningTestingToolState(@NonNull final StatsSigningTestingToolState @Override public synchronized StatsSigningTestingToolState copy() { throwIfImmutable(); + setImmutable(true); return new StatsSigningTestingToolState(this); } @@ -195,31 +197,6 @@ private boolean validateSignature(final TransactionSignature signature, final Tr return false; } - /** - * {@inheritDoc} - */ - @Override - public void serialize(final SerializableDataOutputStream out) throws IOException { - if (getVersion() >= ClassVersion.KEEP_STATE) { - out.writeLong(runningSum); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void deserialize(final SerializableDataInputStream in, final int version) throws IOException { - if (version < ClassVersion.KEEP_STATE) { - // In this version we serialized an address book - in.readSerializable(); - } - - if (getVersion() >= ClassVersion.KEEP_STATE) { - runningSum = in.readLong(); - } - } - /** * {@inheritDoc} */ diff --git a/platform-sdk/platform-apps/tests/StatsSigningTestingTool/src/main/java/module-info.java b/platform-sdk/platform-apps/tests/StatsSigningTestingTool/src/main/java/module-info.java index 509f9f29ca18..0cd6b866b724 100644 --- a/platform-sdk/platform-apps/tests/StatsSigningTestingTool/src/main/java/module-info.java +++ b/platform-sdk/platform-apps/tests/StatsSigningTestingTool/src/main/java/module-info.java @@ -1,9 +1,11 @@ module com.swirlds.demo.stats.signing { + requires com.hedera.node.hapi; requires com.swirlds.base; requires com.swirlds.common; requires com.swirlds.logging; requires com.swirlds.metrics.api; requires com.swirlds.platform.core; + requires com.swirlds.state.api; requires com.hedera.pbj.runtime; requires lazysodium.java; requires org.apache.logging.log4j; diff --git a/platform-sdk/platform-apps/tests/StressTestingTool/src/main/java/com/swirlds/demo/stress/StressTestingToolMain.java b/platform-sdk/platform-apps/tests/StressTestingTool/src/main/java/com/swirlds/demo/stress/StressTestingToolMain.java index 817aa74f438e..dd91221963c4 100644 --- a/platform-sdk/platform-apps/tests/StressTestingTool/src/main/java/com/swirlds/demo/stress/StressTestingToolMain.java +++ b/platform-sdk/platform-apps/tests/StressTestingTool/src/main/java/com/swirlds/demo/stress/StressTestingToolMain.java @@ -39,11 +39,11 @@ import com.swirlds.common.threading.framework.config.ThreadConfiguration; import com.swirlds.metrics.api.Metrics; import com.swirlds.platform.Browser; -import com.swirlds.platform.state.MerkleRoot; -import com.swirlds.platform.state.State; +import com.swirlds.platform.state.MerkleStateRoot; import com.swirlds.platform.system.BasicSoftwareVersion; import com.swirlds.platform.system.Platform; import com.swirlds.platform.system.SwirldMain; +import com.swirlds.platform.util.NoOpMerkleStateLifecycles; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.util.List; @@ -231,9 +231,11 @@ private synchronized void generateTransactions() { } @Override - public MerkleRoot newMerkleStateRoot() { - final State state = new State(); - state.setSwirldState(new StressTestingToolState()); + public MerkleStateRoot newMerkleStateRoot() { + final MerkleStateRoot state = new StressTestingToolState( + NoOpMerkleStateLifecycles.NO_OP_MERKLE_STATE_LIFECYCLES, + version -> new BasicSoftwareVersion(SOFTWARE_VERSION.getSoftwareVersion())); + NoOpMerkleStateLifecycles.NO_OP_MERKLE_STATE_LIFECYCLES.initPlatformState(state); return state; } diff --git a/platform-sdk/platform-apps/tests/StressTestingTool/src/main/java/com/swirlds/demo/stress/StressTestingToolState.java b/platform-sdk/platform-apps/tests/StressTestingTool/src/main/java/com/swirlds/demo/stress/StressTestingToolState.java index c4885e40e090..92bda480b8ed 100644 --- a/platform-sdk/platform-apps/tests/StressTestingTool/src/main/java/com/swirlds/demo/stress/StressTestingToolState.java +++ b/platform-sdk/platform-apps/tests/StressTestingTool/src/main/java/com/swirlds/demo/stress/StressTestingToolState.java @@ -26,29 +26,29 @@ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. */ -import com.swirlds.common.io.streams.SerializableDataInputStream; -import com.swirlds.common.io.streams.SerializableDataOutputStream; -import com.swirlds.common.merkle.MerkleLeaf; -import com.swirlds.common.merkle.impl.PartialMerkleLeaf; +import com.hedera.hapi.node.base.SemanticVersion; +import com.swirlds.common.constructable.ConstructableIgnored; import com.swirlds.common.utility.ByteUtils; +import com.swirlds.platform.state.MerkleStateLifecycles; +import com.swirlds.platform.state.MerkleStateRoot; import com.swirlds.platform.state.PlatformStateModifier; import com.swirlds.platform.system.InitTrigger; import com.swirlds.platform.system.Platform; import com.swirlds.platform.system.Round; import com.swirlds.platform.system.SoftwareVersion; -import com.swirlds.platform.system.SwirldState; import com.swirlds.platform.system.events.Event; import com.swirlds.platform.system.transaction.ConsensusTransaction; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; -import java.io.IOException; import java.time.Duration; +import java.util.function.Function; /** * This testing tool simulates configurable processing times for both preHandling and handling for stress testing * purposes. */ -public class StressTestingToolState extends PartialMerkleLeaf implements SwirldState, MerkleLeaf { +@ConstructableIgnored +public class StressTestingToolState extends MerkleStateRoot { private static final long CLASS_ID = 0x79900efa3127b6eL; /** A running sum of transaction contents */ @@ -57,8 +57,11 @@ public class StressTestingToolState extends PartialMerkleLeaf implements SwirldS /** supplies the app config */ public StressTestingToolConfig config; - @SuppressWarnings("unused") - public StressTestingToolState() {} + public StressTestingToolState( + @NonNull final MerkleStateLifecycles lifecycles, + @NonNull final Function versionFactory) { + super(lifecycles, versionFactory); + } private StressTestingToolState(@NonNull final StressTestingToolState sourceState) { super(sourceState); @@ -74,6 +77,7 @@ private StressTestingToolState(@NonNull final StressTestingToolState sourceState @Override public synchronized StressTestingToolState copy() { throwIfImmutable(); + setImmutable(true); return new StressTestingToolState(this); } @@ -84,6 +88,8 @@ public void init( @NonNull final Platform platform, @NonNull final InitTrigger trigger, @Nullable final SoftwareVersion previousSoftwareVersion) { + super.init(platform, trigger, previousSoftwareVersion); + this.config = platform.getContext().getConfiguration().getConfigData(StressTestingToolConfig.class); } @@ -124,22 +130,6 @@ private void busyWait(@NonNull final Duration duration) { } } - /** - * {@inheritDoc} - */ - @Override - public void serialize(@NonNull final SerializableDataOutputStream out) throws IOException { - out.writeLong(runningSum); - } - - /** - * {@inheritDoc} - */ - @Override - public void deserialize(@NonNull final SerializableDataInputStream in, final int version) throws IOException { - runningSum = in.readLong(); - } - /** * {@inheritDoc} */ diff --git a/platform-sdk/platform-apps/tests/StressTestingTool/src/main/java/module-info.java b/platform-sdk/platform-apps/tests/StressTestingTool/src/main/java/module-info.java index 056479da84b5..237005494096 100644 --- a/platform-sdk/platform-apps/tests/StressTestingTool/src/main/java/module-info.java +++ b/platform-sdk/platform-apps/tests/StressTestingTool/src/main/java/module-info.java @@ -1,10 +1,12 @@ module com.swirlds.demo.stress { + requires com.hedera.node.hapi; requires com.swirlds.base; requires com.swirlds.common; requires com.swirlds.config.api; requires com.swirlds.logging; requires com.swirlds.metrics.api; requires com.swirlds.platform.core; + requires com.swirlds.state.api; requires com.hedera.pbj.runtime; requires org.apache.logging.log4j; requires static com.github.spotbugs.annotations; diff --git a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/state/MerkleStateRoot.java b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/state/MerkleStateRoot.java index a4ffddbad224..b1f63a2d318a 100644 --- a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/state/MerkleStateRoot.java +++ b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/state/MerkleStateRoot.java @@ -16,7 +16,7 @@ package com.swirlds.platform.state; -import static com.swirlds.logging.legacy.LogMarker.EXCEPTION; +import static com.swirlds.logging.legacy.LogMarker.*; import static com.swirlds.platform.state.MerkleStateUtils.createInfoString; import static com.swirlds.platform.state.service.schemas.V0540PlatformStateSchema.PLATFORM_STATE_KEY; import static com.swirlds.platform.system.InitTrigger.EVENT_STREAM_RECOVERY; @@ -432,6 +432,8 @@ public void putServiceStateIfAbsent( @NonNull final Supplier nodeSupplier, @NonNull final Consumer nodeInitializer) { + logger.info(STARTUP.getMarker(), "Putting states... ", md.serviceName()); + // Validate the inputs throwIfImmutable(); requireNonNull(md); @@ -449,6 +451,8 @@ public void putServiceStateIfAbsent( readableStatesMap.put(serviceName, new MerkleReadableStates(stateMetadata)); writableStatesMap.put(serviceName, new MerkleWritableStates(serviceName, stateMetadata)); + logger.info(STARTUP.getMarker(), "Put states! Service name: {} ", md.serviceName()); + // Look for a node, and if we don't find it, then insert the one we were given // If there is not a node there, then set it. I don't want to overwrite the existing node, // because it may have been loaded from state on disk, and the node provided here in this @@ -478,8 +482,21 @@ public void putServiceStateIfAbsent( "A label must be computed based on the same " + "service name and state key in the metadata!"); } + logger.info( + STARTUP.getMarker(), + "Setting child.. Service name: {} / Number of children: {} / node: {}", + md.serviceName(), + getNumberOfChildren(), + node); setChild(getNumberOfChildren(), node); } else { + logger.info( + STARTUP.getMarker(), + "Getting child.. Service name: {} / Number of children: {} / node: {}", + md.serviceName(), + getNumberOfChildren(), + nodeIndex); + node = getChild(nodeIndex); } nodeInitializer.accept(node); diff --git a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/state/State.java b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/state/State.java deleted file mode 100644 index b161872e0d93..000000000000 --- a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/state/State.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (C) 2016-2024 Hedera Hashgraph, LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.swirlds.platform.state; - -import static com.swirlds.platform.state.MerkleStateUtils.createInfoString; - -import com.swirlds.base.utility.ToStringBuilder; -import com.swirlds.common.merkle.MerkleNode; -import com.swirlds.common.merkle.impl.PartialNaryMerkleInternal; -import com.swirlds.common.merkle.route.MerkleRouteFactory; -import com.swirlds.common.utility.RuntimeObjectRecord; -import com.swirlds.common.utility.RuntimeObjectRegistry; -import com.swirlds.platform.system.SwirldState; -import edu.umd.cs.findbugs.annotations.NonNull; -import java.nio.file.Path; -import java.util.Objects; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -/** - * The root of the merkle tree holding the state of the Swirlds ledger. Contains two children: the state used by the - * application and the state used by the platform. - * - * @deprecated This class is deprecated for usage as production code. - * It should be only used for testing purposes and will be moved to testFixtures in 0.54. - */ -@Deprecated(forRemoval = true, since = "0.53.0") -public class State extends PartialNaryMerkleInternal implements MerkleRoot { - - private static final Logger logger = LogManager.getLogger(State.class); - - private static final long CLASS_ID = 0x2971b4ba7dd84402L; - - public static class ClassVersion { - public static final int ORIGINAL = 1; - public static final int ADD_MIN_GEN = 2; - public static final int EVENT_REFACTOR = 3; - public static final int MIGRATE_TO_SERIALIZABLE = 4; - public static final int ADD_DUAL_STATE = 5; - public static final int REMOVE_DUAL_STATE = 6; - public static final int MIGRATE_PLATFORM_STATE = 7; - } - - private static class ChildIndices { - /** - * The state written and used by the application. It is the state resulting from all transactions in consensus - * order from all events with received rounds up through the round this State represents. - */ - public static final int SWIRLD_STATE = 0; - /** - * The state written and used by the platform. - */ - public static final int PLATFORM_STATE = 1; - } - - /** - * Used to track the lifespan of this state. - */ - private final RuntimeObjectRecord registryRecord; - - public State() { - registryRecord = RuntimeObjectRegistry.createRecord(getClass()); - updatePlatformState(new PlatformState()); - } - - private State(final State that) { - super(that); - - registryRecord = RuntimeObjectRegistry.createRecord(getClass()); - - if (that.getSwirldState() != null) { - this.setSwirldState(that.getSwirldState().copy()); - } - if (that.getWritablePlatformState() != null) { - this.updatePlatformState(that.getWritablePlatformState().copy()); - } - } - - /** - * {@inheritDoc} - */ - @Override - public MerkleNode migrate(final int version) { - if (version < ClassVersion.REMOVE_DUAL_STATE) { - throw new UnsupportedOperationException("State migration from version " + version + " is not supported." - + " The minimum supported version is " + getMinimumSupportedVersion()); - } - - if (version < ClassVersion.MIGRATE_PLATFORM_STATE - && getSwirldState() instanceof MerkleStateRoot merkleStateRoot) { - PlatformState platformState = getWritablePlatformState().copy(); - setChild(ChildIndices.PLATFORM_STATE, null); - merkleStateRoot.updatePlatformState(platformState); - merkleStateRoot.setRoute(MerkleRouteFactory.getEmptyRoute()); - return merkleStateRoot.copy(); - } - - return this; - } - /** - * {@inheritDoc} - */ - @Override - public int getMinimumSupportedVersion() { - return ClassVersion.REMOVE_DUAL_STATE; - } - - /** - * Get the application state. - * - * @return the application state - */ - @Override - @NonNull - public SwirldState getSwirldState() { - return getChild(ChildIndices.SWIRLD_STATE); - } - - /** - * Set the application state. - * - * @param state the application state - */ - public void setSwirldState(final SwirldState state) { - setChild(ChildIndices.SWIRLD_STATE, state); - } - - /** - * Immutable platform state is not supported by this class. - */ - @NonNull - @Override - public PlatformStateAccessor getReadablePlatformState() { - return getChild(ChildIndices.PLATFORM_STATE); - } - - /** - * Get the platform state. - * @return the platform state - */ - @NonNull - @Override - public PlatformState getWritablePlatformState() { - return getChild(ChildIndices.PLATFORM_STATE); - } - - /** - * Updates the platform state. - * - * @param modifier the platform state - */ - @Override - public void updatePlatformState(@NonNull final PlatformStateModifier modifier) { - if (modifier instanceof PlatformState platformState) { - setChild(ChildIndices.PLATFORM_STATE, platformState); - } else { - throw new UnsupportedOperationException("%s implementation of %s is not supported" - .formatted(modifier.getClass().getSimpleName(), PlatformStateModifier.class.getSimpleName())); - } - } - - /** - * {@inheritDoc} - */ - @Override - public long getClassId() { - return CLASS_ID; - } - - /** - * {@inheritDoc} - */ - @Override - public int getVersion() { - return ClassVersion.MIGRATE_PLATFORM_STATE; - } - - /** - * {@inheritDoc} - */ - @NonNull - @Override - public MerkleRoot copy() { - throwIfImmutable(); - throwIfDestroyed(); - setImmutable(true); - return new State(this); - } - - /** - * {@inheritDoc} - */ - @Override - protected void destroyNode() { - registryRecord.release(); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(final Object other) { - if (this == other) { - return true; - } - if (other == null || getClass() != other.getClass()) { - return false; - } - final MerkleRoot state = (MerkleRoot) other; - return Objects.equals(getReadablePlatformState(), state.getReadablePlatformState()) - && Objects.equals(getSwirldState(), state.getSwirldState()); - } - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - return Objects.hash(getReadablePlatformState(), getSwirldState()); - } - - /** - * Generate a string that describes this state. - * - * @param hashDepth the depth of the tree to visit and print - */ - @NonNull - @Override - public String getInfoString(final int hashDepth) { - final PlatformStateAccessor platformState = getReadablePlatformState(); - return createInfoString(hashDepth, platformState, getHash(), this); - } - - /** - * {@inheritDoc} - */ - @Override - public void createSnapshot(@NonNull final Path targetPath) { - throwIfMutable(); - throwIfDestroyed(); - MerkleTreeSnapshotWriter.createSnapshot(this, targetPath); - } - - /** - * {@inheritDoc} - */ - @Override - public String toString() { - return new ToStringBuilder(this) - .append("platformState", getReadablePlatformState()) - .append("swirldState", getSwirldState()) - .toString(); - } -} diff --git a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/util/NoOpMerkleStateLifecycles.java b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/util/NoOpMerkleStateLifecycles.java new file mode 100644 index 000000000000..5de7b6e9373f --- /dev/null +++ b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/util/NoOpMerkleStateLifecycles.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.swirlds.platform.util; + +import com.hedera.hapi.block.stream.output.StateChanges; +import com.hedera.hapi.node.base.SemanticVersion; +import com.swirlds.common.context.PlatformContext; +import com.swirlds.config.api.Configuration; +import com.swirlds.platform.state.MerkleStateLifecycles; +import com.swirlds.platform.state.MerkleStateRoot; +import com.swirlds.platform.state.service.PlatformStateService; +import com.swirlds.platform.state.service.schemas.V0540PlatformStateSchema; +import com.swirlds.platform.system.*; +import com.swirlds.platform.system.address.AddressBook; +import com.swirlds.platform.system.events.Event; +import com.swirlds.state.State; +import com.swirlds.state.lifecycle.MigrationContext; +import com.swirlds.state.lifecycle.StateDefinition; +import com.swirlds.state.lifecycle.info.NetworkInfo; +import com.swirlds.state.merkle.StateMetadata; +import com.swirlds.state.merkle.singleton.SingletonNode; +import com.swirlds.state.spi.*; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.MarkerManager; + +public enum NoOpMerkleStateLifecycles implements MerkleStateLifecycles { + NO_OP_MERKLE_STATE_LIFECYCLES; + + private static final Logger logger = LogManager.getLogger(NoOpMerkleStateLifecycles.class); + + public List initPlatformState(@NonNull final State state) { + logger.info(MarkerManager.getMarker("DEMO_INFO"), "Init Platform State..."); + + if (!(state instanceof MerkleStateRoot merkleStateRoot)) { + throw new IllegalArgumentException("Can only be used with MerkleStateRoot instances"); + } + final var schema = new V0540PlatformStateSchema(); + schema.statesToCreate().stream() + .sorted(Comparator.comparing(StateDefinition::stateKey)) + .forEach(def -> { + final var md = new StateMetadata<>(PlatformStateService.NAME, schema, def); + if (def.singleton()) { + merkleStateRoot.putServiceStateIfAbsent( + md, + () -> new SingletonNode<>( + md.serviceName(), + md.stateDefinition().stateKey(), + md.singletonClassId(), + md.stateDefinition().valueCodec(), + null)); + } else { + throw new IllegalStateException("PlatformStateService only expected to use singleton states"); + } + }); + + final var writableStates = state.getWritableStates(PlatformStateService.NAME); + + logger.info(MarkerManager.getMarker("DEMO_INFO"), "Writable states: {}", writableStates.stateKeys()); + + final var migrationContext = new MigrationContext() { + @NonNull + @Override + public ReadableStates previousStates() { + return null; + } + + @NonNull + @Override + public WritableStates newStates() { + return writableStates; + } + + @NonNull + @Override + public Configuration configuration() { + return null; + } + + @Nullable + @Override + public NetworkInfo genesisNetworkInfo() { + return null; + } + + @Override + public long newEntityNum() { + return 0; + } + + @Override + public void copyAndReleaseOnDiskState(String stateKey) { + // no-op + } + + @Nullable + @Override + public SemanticVersion previousVersion() { + return null; + } + + @Override + public Map sharedValues() { + return Map.of(); + } + }; + + logger.info( + MarkerManager.getMarker("DEMO_INFO"), + "(MigrationContext) Writable states: {}", + migrationContext.newStates().stateKeys()); + + schema.migrate(migrationContext); + ((CommittableWritableStates) writableStates).commit(); + return Collections.emptyList(); + } + + @Override + public void onPreHandle(@NonNull Event event, @NonNull State state) { + // no-op + } + + @Override + public void onHandleConsensusRound(@NonNull Round round, @NonNull State state) { + // no-op + } + + @Override + public void onSealConsensusRound(@NonNull Round round, @NonNull State state) { + // Touch this round + round.getRoundNum(); + } + + @Override + public void onStateInitialized( + @NonNull State state, + @NonNull Platform platform, + @NonNull InitTrigger trigger, + @Nullable SoftwareVersion previousVersion) { + // no-op + } + + @Override + public void onUpdateWeight( + @NonNull MerkleStateRoot state, @NonNull AddressBook configAddressBook, @NonNull PlatformContext context) { + // no-op + } + + @Override + public void onNewRecoveredState(@NonNull MerkleStateRoot recoveredState) { + // no-op + } +} diff --git a/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/state/StateRegistryTests.java b/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/state/StateRegistryTests.java index 84be53777929..189d8eff00b9 100644 --- a/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/state/StateRegistryTests.java +++ b/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/state/StateRegistryTests.java @@ -81,7 +81,10 @@ void activeStateCountTest() throws IOException { // Restore the registry to its original condition at boot time RuntimeObjectRegistry.reset(); - assertEquals(0, RuntimeObjectRegistry.getActiveObjectsCount(State.class), "no states have been created yet"); + assertEquals( + 0, + RuntimeObjectRegistry.getActiveObjectsCount(MerkleStateRoot.class), + "no states have been created yet"); final List states = new LinkedList<>(); // Create a bunch of states diff --git a/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/turtle/runner/Turtle.java b/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/turtle/runner/Turtle.java index fd00324d1209..04fdf341fdbc 100644 --- a/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/turtle/runner/Turtle.java +++ b/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/turtle/runner/Turtle.java @@ -16,11 +16,16 @@ package com.swirlds.platform.turtle.runner; +import static com.swirlds.platform.test.fixtures.state.FakeMerkleStateLifecycles.FAKE_MERKLE_STATE_LIFECYCLES; + import com.swirlds.base.test.fixtures.time.FakeTime; +import com.swirlds.common.constructable.ClassConstructorPair; import com.swirlds.common.constructable.ConstructableRegistry; import com.swirlds.common.constructable.ConstructableRegistryException; import com.swirlds.common.platform.NodeId; import com.swirlds.common.test.fixtures.Randotron; +import com.swirlds.platform.state.MerkleStateRoot; +import com.swirlds.platform.system.BasicSoftwareVersion; import com.swirlds.platform.system.address.AddressBook; import com.swirlds.platform.test.fixtures.addressbook.RandomAddressBookBuilder; import com.swirlds.platform.test.fixtures.turtle.gossip.SimulatedNetwork; @@ -96,7 +101,11 @@ public class Turtle { timeReportingEnabled = builder.isTimeReportingEnabled(); try { - ConstructableRegistry.getInstance().registerConstructables(""); + ConstructableRegistry.getInstance() + .registerConstructable(new ClassConstructorPair( + MerkleStateRoot.class, + () -> new MerkleStateRoot( + FAKE_MERKLE_STATE_LIFECYCLES, version -> new BasicSoftwareVersion(1)))); } catch (final ConstructableRegistryException e) { throw new RuntimeException(e); } diff --git a/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/turtle/runner/TurtleNode.java b/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/turtle/runner/TurtleNode.java index 10c2e6034fd5..d1afab65cf41 100644 --- a/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/turtle/runner/TurtleNode.java +++ b/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/turtle/runner/TurtleNode.java @@ -18,6 +18,7 @@ import static com.swirlds.common.threading.manager.AdHocThreadManager.getStaticThreadManager; import static com.swirlds.platform.builder.internal.StaticPlatformBuilder.getMetricsProvider; +import static com.swirlds.platform.builder.internal.StaticPlatformBuilder.setupGlobalMetrics; import static com.swirlds.platform.state.signed.StartupStateUtils.getInitialState; import com.swirlds.base.time.Time; @@ -91,6 +92,8 @@ public class TurtleNode { .withValue(BasicConfig_.JVM_PAUSE_DETECTOR_SLEEP_MS, "0") .getOrCreateConfig(); + setupGlobalMetrics(configuration); + final PlatformContext platformContext = TestPlatformContextBuilder.create() .withTime(time) .withConfiguration(configuration) @@ -102,11 +105,10 @@ public class TurtleNode { final Supplier genesisStateSupplier = TurtleTestingToolState::getStateRootNode; final var version = new BasicSoftwareVersion(1); - final NodeId selfId = null; - final var metrics = getMetricsProvider().createPlatformMetrics(selfId); + final var metrics = getMetricsProvider().createPlatformMetrics(nodeId); final var fileSystemManager = FileSystemManager.create(configuration); final var recycleBin = - RecycleBin.create(metrics, configuration, getStaticThreadManager(), time, fileSystemManager, selfId); + RecycleBin.create(metrics, configuration, getStaticThreadManager(), time, fileSystemManager, nodeId); final var reservedState = getInitialState( configuration, recycleBin, version, genesisStateSupplier, "foo", "bar", nodeId, addressBook); diff --git a/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/turtle/runner/TurtleTestingToolState.java b/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/turtle/runner/TurtleTestingToolState.java index 6ab2196681e3..e954300d27a6 100644 --- a/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/turtle/runner/TurtleTestingToolState.java +++ b/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/turtle/runner/TurtleTestingToolState.java @@ -16,18 +16,13 @@ package com.swirlds.platform.turtle.runner; -import com.swirlds.common.io.streams.SerializableDataInputStream; -import com.swirlds.common.io.streams.SerializableDataOutputStream; -import com.swirlds.common.merkle.MerkleLeaf; -import com.swirlds.common.merkle.impl.PartialMerkleLeaf; +import static com.swirlds.platform.test.fixtures.state.FakeMerkleStateLifecycles.FAKE_MERKLE_STATE_LIFECYCLES; + import com.swirlds.common.utility.NonCryptographicHashing; -import com.swirlds.platform.state.MerkleRoot; -import com.swirlds.platform.state.PlatformStateModifier; -import com.swirlds.platform.state.State; +import com.swirlds.platform.state.*; +import com.swirlds.platform.system.BasicSoftwareVersion; import com.swirlds.platform.system.Round; -import com.swirlds.platform.system.SwirldState; import edu.umd.cs.findbugs.annotations.NonNull; -import java.io.IOException; /** * A simple testing application intended for use with TURTLE. @@ -37,7 +32,7 @@ * ﹉∏﹉∏﹉ ﹉∏﹉∏﹉ * */ -public class TurtleTestingToolState extends PartialMerkleLeaf implements SwirldState, MerkleLeaf { +public class TurtleTestingToolState extends MerkleStateRoot { private static final long CLASS_ID = 0xa49b3822a4136ac6L; @@ -48,18 +43,18 @@ private static final class ClassVersion { private long state; - /** - * Zero arg constructor needed for constructable registry. - */ - public TurtleTestingToolState() {} + public TurtleTestingToolState() { + super(FAKE_MERKLE_STATE_LIFECYCLES, version -> new BasicSoftwareVersion(1)); + } /** * Copy constructor. * - * @param that the object to copy + * @param from the object to copy */ - private TurtleTestingToolState(@NonNull final TurtleTestingToolState that) { - this.state = that.state; + private TurtleTestingToolState(@NonNull final TurtleTestingToolState from) { + super(from); + this.state = from.state; } /** @@ -95,25 +90,11 @@ public void handleConsensusRound(@NonNull final Round round, @NonNull final Plat */ @Override public TurtleTestingToolState copy() { + throwIfImmutable(); + setImmutable(true); return new TurtleTestingToolState(this); } - /** - * {@inheritDoc} - */ - @Override - public void serialize(@NonNull final SerializableDataOutputStream out) throws IOException { - out.writeLong(state); - } - - /** - * {@inheritDoc} - */ - @Override - public void deserialize(@NonNull final SerializableDataInputStream in, final int version) throws IOException { - state = in.readLong(); - } - /** * Creates a merkle node to act as a state tree root. * @@ -121,9 +102,8 @@ public void deserialize(@NonNull final SerializableDataInputStream in, final int */ @NonNull public static MerkleRoot getStateRootNode() { - final TurtleTestingToolState turtleState = new TurtleTestingToolState(); - final State root = new State(); - root.setSwirldState(turtleState); - return root; + final MerkleStateRoot state = new TurtleTestingToolState(); + FAKE_MERKLE_STATE_LIFECYCLES.initPlatformState(state); + return state; } } diff --git a/platform-sdk/swirlds-state-impl/src/main/java/com/swirlds/state/merkle/StateUtils.java b/platform-sdk/swirlds-state-impl/src/main/java/com/swirlds/state/merkle/StateUtils.java index c27999baa925..fdd816b472ee 100644 --- a/platform-sdk/swirlds-state-impl/src/main/java/com/swirlds/state/merkle/StateUtils.java +++ b/platform-sdk/swirlds-state-impl/src/main/java/com/swirlds/state/merkle/StateUtils.java @@ -23,17 +23,35 @@ import com.hedera.pbj.runtime.ParseException; import com.hedera.pbj.runtime.io.stream.ReadableStreamingData; import com.hedera.pbj.runtime.io.stream.WritableStreamingData; +import com.swirlds.common.constructable.ClassConstructorPair; +import com.swirlds.common.constructable.ConstructableRegistry; +import com.swirlds.common.constructable.ConstructableRegistryException; import com.swirlds.common.utility.NonCryptographicHashing; +import com.swirlds.logging.legacy.LogMarker; +import com.swirlds.state.merkle.disk.OnDiskKey; +import com.swirlds.state.merkle.disk.OnDiskKeySerializer; +import com.swirlds.state.merkle.disk.OnDiskValue; +import com.swirlds.state.merkle.disk.OnDiskValueSerializer; +import com.swirlds.state.merkle.memory.InMemoryValue; +import com.swirlds.state.merkle.memory.InMemoryWritableKVState; +import com.swirlds.state.merkle.queue.QueueNode; +import com.swirlds.state.merkle.singleton.SingletonNode; +import com.swirlds.state.merkle.singleton.StringLeaf; +import com.swirlds.state.merkle.singleton.ValueLeaf; import edu.umd.cs.findbugs.annotations.NonNull; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Objects; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; /** Utility class for working with states. */ public final class StateUtils { + private static final Logger logger = LogManager.getLogger(StateUtils.class); + /** Prevent instantiation */ private StateUtils() {} @@ -176,7 +194,9 @@ static long hashString(@NonNull final String s) { // Normalize the string so things are deterministic (different JVMs might be using different // default internal representation for strings, and we need to normalize that) final var data = getNormalisedStringBytes(s); - return hashBytes(data); + long l = hashBytes(data); + logger.info(LogMarker.STARTUP.getMarker(), "Hashed string {} to {}", s, l); + return l; } // Will be moved to `NonCryptographicHashing` with @@ -242,4 +262,82 @@ private static boolean isAsciiLetter(char ch) { private static boolean isAsciiNumber(char ch) { return ch >= '0' && ch <= '9'; } + + /** + * Registers with the {@link ConstructableRegistry} system a class ID and a class. While this + * will only be used for in-memory states, it is safe to register for on-disk ones as well. + * + *

The implementation will take the service name and the state key and compute a hash for it. + * It will then convert the hash to a long, and use that as the class ID. It will then register + * an {@link InMemoryWritableKVState}'s value merkle type to be deserialized, answering with the + * generated class ID. + * + * @param md The state metadata + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public static void registerWithSystem( + @NonNull final StateMetadata md, @NonNull ConstructableRegistry constructableRegistry) { + // Register with the system the uniqueId as the "classId" of an InMemoryValue. There can be + // multiple id's associated with InMemoryValue. The secret is that the supplier captures the + // various delegate writers and parsers, and so can parse/write different types of data + // based on the id. + try { + constructableRegistry.registerConstructable(new ClassConstructorPair( + InMemoryValue.class, + () -> new InMemoryValue( + md.inMemoryValueClassId(), + md.stateDefinition().keyCodec(), + md.stateDefinition().valueCodec()))); + constructableRegistry.registerConstructable(new ClassConstructorPair( + OnDiskKey.class, + () -> new OnDiskKey<>( + md.onDiskKeyClassId(), md.stateDefinition().keyCodec()))); + constructableRegistry.registerConstructable(new ClassConstructorPair( + OnDiskKeySerializer.class, + () -> new OnDiskKeySerializer<>( + md.onDiskKeySerializerClassId(), + md.onDiskKeyClassId(), + md.stateDefinition().keyCodec()))); + constructableRegistry.registerConstructable(new ClassConstructorPair( + OnDiskValue.class, + () -> new OnDiskValue<>( + md.onDiskValueClassId(), md.stateDefinition().valueCodec()))); + constructableRegistry.registerConstructable(new ClassConstructorPair( + OnDiskValueSerializer.class, + () -> new OnDiskValueSerializer<>( + md.onDiskValueSerializerClassId(), + md.onDiskValueClassId(), + md.stateDefinition().valueCodec()))); + constructableRegistry.registerConstructable(new ClassConstructorPair( + SingletonNode.class, + () -> new SingletonNode<>( + md.serviceName(), + md.stateDefinition().stateKey(), + md.singletonClassId(), + md.stateDefinition().valueCodec(), + null))); + constructableRegistry.registerConstructable(new ClassConstructorPair( + QueueNode.class, + () -> new QueueNode<>( + md.serviceName(), + md.stateDefinition().stateKey(), + md.queueNodeClassId(), + md.singletonClassId(), + md.stateDefinition().valueCodec()))); + constructableRegistry.registerConstructable(new ClassConstructorPair(StringLeaf.class, StringLeaf::new)); + constructableRegistry.registerConstructable(new ClassConstructorPair( + ValueLeaf.class, + () -> new ValueLeaf<>( + md.singletonClassId(), md.stateDefinition().valueCodec()))); + } catch (ConstructableRegistryException e) { + // This is a fatal error. + throw new IllegalStateException( + "Failed to register with the system '" + + md.serviceName() + + ":" + + md.stateDefinition().stateKey() + + "'", + e); + } + } } diff --git a/platform-sdk/swirlds-state-impl/src/main/java/com/swirlds/state/merkle/singleton/SingletonNode.java b/platform-sdk/swirlds-state-impl/src/main/java/com/swirlds/state/merkle/singleton/SingletonNode.java index 76f8ec9816bb..10cb1298f358 100644 --- a/platform-sdk/swirlds-state-impl/src/main/java/com/swirlds/state/merkle/singleton/SingletonNode.java +++ b/platform-sdk/swirlds-state-impl/src/main/java/com/swirlds/state/merkle/singleton/SingletonNode.java @@ -37,7 +37,7 @@ */ @DebugIterationEndpoint public class SingletonNode extends PartialBinaryMerkleInternal implements Labeled, MerkleInternal { - static final long CLASS_ID = 0x3832CC837AB77BFL; + public static final long CLASS_ID = 0x3832CC837AB77BFL; public static final int CLASS_VERSION = 1; /** diff --git a/platform-sdk/swirlds-state-impl/src/main/java/module-info.java b/platform-sdk/swirlds-state-impl/src/main/java/module-info.java index a899fb136f79..eb3c88b67d11 100644 --- a/platform-sdk/swirlds-state-impl/src/main/java/module-info.java +++ b/platform-sdk/swirlds-state-impl/src/main/java/module-info.java @@ -12,6 +12,7 @@ requires transitive com.swirlds.virtualmap; requires transitive com.hedera.pbj.runtime; requires com.swirlds.fcqueue; + requires com.swirlds.logging; requires org.apache.logging.log4j; requires static transitive com.github.spotbugs.annotations; } diff --git a/platform-sdk/swirlds-unit-tests/core/swirlds-platform-test/src/test/java/com/swirlds/platform/test/StateTest.java b/platform-sdk/swirlds-unit-tests/core/swirlds-platform-test/src/test/java/com/swirlds/platform/test/StateTest.java index beb1563b8d32..6ae696dc8ba4 100644 --- a/platform-sdk/swirlds-unit-tests/core/swirlds-platform-test/src/test/java/com/swirlds/platform/test/StateTest.java +++ b/platform-sdk/swirlds-unit-tests/core/swirlds-platform-test/src/test/java/com/swirlds/platform/test/StateTest.java @@ -30,7 +30,6 @@ import com.swirlds.platform.crypto.CryptoStatic; import com.swirlds.platform.state.MerkleRoot; import com.swirlds.platform.state.MerkleStateRoot; -import com.swirlds.platform.state.State; import com.swirlds.platform.state.signed.SignedState; import com.swirlds.platform.system.BasicSoftwareVersion; import java.util.Random; @@ -86,14 +85,13 @@ void tryReserveTest() { private static SignedState randomSignedState() { Random random = new Random(0); - State root = new State(); - root.setSwirldState(new MerkleStateRoot( - FAKE_MERKLE_STATE_LIFECYCLES, version -> new BasicSoftwareVersion(version.major()))); + MerkleStateRoot merkleStateRoot = + new MerkleStateRoot(FAKE_MERKLE_STATE_LIFECYCLES, version -> new BasicSoftwareVersion(version.major())); boolean shouldSaveToDisk = random.nextBoolean(); SignedState signedState = new SignedState( TestPlatformContextBuilder.create().build().getConfiguration(), CryptoStatic::verifySignature, - root, + merkleStateRoot, "test", shouldSaveToDisk, false, diff --git a/platform-sdk/swirlds-unit-tests/core/swirlds-platform-test/src/test/java/com/swirlds/platform/test/StateTests.java b/platform-sdk/swirlds-unit-tests/core/swirlds-platform-test/src/test/java/com/swirlds/platform/test/StateTests.java index d8569b653915..780c02336dd7 100644 --- a/platform-sdk/swirlds-unit-tests/core/swirlds-platform-test/src/test/java/com/swirlds/platform/test/StateTests.java +++ b/platform-sdk/swirlds-unit-tests/core/swirlds-platform-test/src/test/java/com/swirlds/platform/test/StateTests.java @@ -27,7 +27,7 @@ import com.swirlds.common.test.fixtures.junit.tags.TestComponentTags; import com.swirlds.config.extensions.test.fixtures.TestConfigBuilder; import com.swirlds.platform.state.MerkleRoot; -import com.swirlds.platform.state.State; +import com.swirlds.platform.state.MerkleStateRoot; import com.swirlds.platform.test.fixtures.state.BlockingSwirldState; import java.io.IOException; import java.nio.file.Path; @@ -40,7 +40,7 @@ @DisplayName("State Tests") class StateTests { - private static State state; + private static MerkleStateRoot merkleStateRoot; /** * Temporary directory provided by JUnit */ @@ -53,11 +53,10 @@ static void setUp() throws ConstructableRegistryException { ConstructableRegistry.getInstance().registerConstructables("com.swirlds"); - state = new State(); - state.setSwirldState(new BlockingSwirldState()); + merkleStateRoot = new BlockingSwirldState(); - state.invalidateHash(); - MerkleCryptoFactory.getInstance().digestTreeSync(state); + merkleStateRoot.invalidateHash(); + MerkleCryptoFactory.getInstance().digestTreeSync(merkleStateRoot); } @Test @@ -67,25 +66,25 @@ static void setUp() throws ConstructableRegistryException { void stateSerializationTest() throws IOException { InputOutputStream io = new InputOutputStream(); - io.getOutput().writeMerkleTree(testDirectory, state); + io.getOutput().writeMerkleTree(testDirectory, merkleStateRoot); io.startReading(); final MerkleRoot decodedState = io.getInput().readMerkleTree(testDirectory, Integer.MAX_VALUE); MerkleCryptoFactory.getInstance().digestTreeSync(decodedState); - assertEquals(state.getHash(), decodedState.getHash(), "expected trees to be equal"); - assertTrue(areTreesEqual(state, decodedState), "expected trees to be equal"); + assertEquals(merkleStateRoot.getHash(), decodedState.getHash(), "expected trees to be equal"); + assertTrue(areTreesEqual(merkleStateRoot, decodedState), "expected trees to be equal"); } @Test @Tag(TestComponentTags.PLATFORM) @DisplayName("State Copy Test") void stateCopyTest() { - final MerkleRoot copiedState = state.copy(); + final MerkleRoot copiedState = merkleStateRoot.copy(); MerkleCryptoFactory.getInstance().digestTreeSync(copiedState); - assertEquals(state.getHash(), copiedState.getHash(), "expected trees to be equal"); - assertTrue(areTreesEqual(state, copiedState), "expected trees to be equal"); + assertEquals(merkleStateRoot.getHash(), copiedState.getHash(), "expected trees to be equal"); + assertTrue(areTreesEqual(merkleStateRoot, copiedState), "expected trees to be equal"); } }