diff --git a/platform-sdk/swirlds-common/src/main/java/com/swirlds/common/config/PlatformSchedulersConfig.java b/platform-sdk/swirlds-common/src/main/java/com/swirlds/common/config/PlatformSchedulersConfig.java index c0c8cf8fe5c5..0850585ade4b 100644 --- a/platform-sdk/swirlds-common/src/main/java/com/swirlds/common/config/PlatformSchedulersConfig.java +++ b/platform-sdk/swirlds-common/src/main/java/com/swirlds/common/config/PlatformSchedulersConfig.java @@ -19,7 +19,6 @@ import com.swirlds.common.wiring.schedulers.builders.TaskSchedulerType; import com.swirlds.config.api.ConfigData; import com.swirlds.config.api.ConfigProperty; -import edu.umd.cs.findbugs.annotations.NonNull; /** * Contains configuration values for the platform schedulers. @@ -46,103 +45,27 @@ * @param signedStateFileManagerSchedulerType the signed state file manager scheduler type * @param signedStateFileManagerUnhandledCapacity number of unhandled tasks allowed in the signed state file manager * scheduler + * @param stateSignerSchedulerType the state signer scheduler type + * @param stateSignerUnhandledCapacity number of unhandled tasks allowed in the state signer scheduler, + * default is -1 (unlimited) */ @ConfigData("platformSchedulers") public record PlatformSchedulersConfig( - @ConfigProperty(defaultValue = "SEQUENTIAL") String internalEventValidatorSchedulerType, + @ConfigProperty(defaultValue = "SEQUENTIAL") TaskSchedulerType internalEventValidatorSchedulerType, @ConfigProperty(defaultValue = "500") int internalEventValidatorUnhandledCapacity, - @ConfigProperty(defaultValue = "SEQUENTIAL") String eventDeduplicatorSchedulerType, + @ConfigProperty(defaultValue = "SEQUENTIAL") TaskSchedulerType eventDeduplicatorSchedulerType, @ConfigProperty(defaultValue = "500") int eventDeduplicatorUnhandledCapacity, - @ConfigProperty(defaultValue = "SEQUENTIAL") String eventSignatureValidatorSchedulerType, + @ConfigProperty(defaultValue = "SEQUENTIAL") TaskSchedulerType eventSignatureValidatorSchedulerType, @ConfigProperty(defaultValue = "500") int eventSignatureValidatorUnhandledCapacity, - @ConfigProperty(defaultValue = "SEQUENTIAL") String orphanBufferSchedulerType, + @ConfigProperty(defaultValue = "SEQUENTIAL") TaskSchedulerType orphanBufferSchedulerType, @ConfigProperty(defaultValue = "500") int orphanBufferUnhandledCapacity, - @ConfigProperty(defaultValue = "SEQUENTIAL") String inOrderLinkerSchedulerType, + @ConfigProperty(defaultValue = "SEQUENTIAL") TaskSchedulerType inOrderLinkerSchedulerType, @ConfigProperty(defaultValue = "500") int inOrderLinkerUnhandledCapacity, - @ConfigProperty(defaultValue = "SEQUENTIAL") String linkedEventIntakeSchedulerType, + @ConfigProperty(defaultValue = "SEQUENTIAL") TaskSchedulerType linkedEventIntakeSchedulerType, @ConfigProperty(defaultValue = "500") int linkedEventIntakeUnhandledCapacity, - @ConfigProperty(defaultValue = "SEQUENTIAL") String eventCreationManagerSchedulerType, + @ConfigProperty(defaultValue = "SEQUENTIAL") TaskSchedulerType eventCreationManagerSchedulerType, @ConfigProperty(defaultValue = "500") int eventCreationManagerUnhandledCapacity, - @ConfigProperty(defaultValue = "SEQUENTIAL_THREAD") String signedStateFileManagerSchedulerType, - @ConfigProperty(defaultValue = "20") int signedStateFileManagerUnhandledCapacity) { - - /** - * Get the internal event validator scheduler type - * - * @return the internal event validator scheduler type - */ - @NonNull - public TaskSchedulerType getInternalEventValidatorSchedulerType() { - return TaskSchedulerType.valueOf(internalEventValidatorSchedulerType); - } - - /** - * Get the event deduplicator scheduler type - * - * @return the event deduplicator scheduler type - */ - @NonNull - public TaskSchedulerType getEventDeduplicatorSchedulerType() { - return TaskSchedulerType.valueOf(eventDeduplicatorSchedulerType); - } - - /** - * Get the event signature validator scheduler type - * - * @return the event signature validator scheduler type - */ - @NonNull - public TaskSchedulerType getEventSignatureValidatorSchedulerType() { - return TaskSchedulerType.valueOf(eventSignatureValidatorSchedulerType); - } - - /** - * Get the orphan buffer scheduler type - * - * @return the orphan buffer scheduler type - */ - @NonNull - public TaskSchedulerType getOrphanBufferSchedulerType() { - return TaskSchedulerType.valueOf(orphanBufferSchedulerType); - } - - /** - * Get the in-order linker scheduler type - * - * @return the in-order linker scheduler type - */ - @NonNull - public TaskSchedulerType getInOrderLinkerSchedulerType() { - return TaskSchedulerType.valueOf(inOrderLinkerSchedulerType); - } - - /** - * Get the linked event intake scheduler type - * - * @return the linked event intake scheduler type - */ - @NonNull - public TaskSchedulerType getLinkedEventIntakeSchedulerType() { - return TaskSchedulerType.valueOf(linkedEventIntakeSchedulerType); - } - - /** - * Get the event creation manager scheduler type - * - * @return the event creation manager scheduler type - */ - @NonNull - public TaskSchedulerType getEventCreationManagerSchedulerType() { - return TaskSchedulerType.valueOf(eventCreationManagerSchedulerType); - } - - /** - * Get the signed state file manager scheduler type - * - * @return the signed state file manager scheduler type - */ - @NonNull - public TaskSchedulerType getSignedStateFileManagerSchedulerType() { - return TaskSchedulerType.valueOf(signedStateFileManagerSchedulerType); - } -} + @ConfigProperty(defaultValue = "SEQUENTIAL_THREAD") TaskSchedulerType signedStateFileManagerSchedulerType, + @ConfigProperty(defaultValue = "20") int signedStateFileManagerUnhandledCapacity, + @ConfigProperty(defaultValue = "SEQUENTIAL_THREAD") TaskSchedulerType stateSignerSchedulerType, + @ConfigProperty(defaultValue = "-1") int stateSignerUnhandledCapacity) {} diff --git a/platform-sdk/swirlds-config-impl/src/main/java/com/swirlds/config/impl/internal/ConverterService.java b/platform-sdk/swirlds-config-impl/src/main/java/com/swirlds/config/impl/internal/ConverterService.java index 8ecc75689c04..dbadb477e607 100644 --- a/platform-sdk/swirlds-config-impl/src/main/java/com/swirlds/config/impl/internal/ConverterService.java +++ b/platform-sdk/swirlds-config-impl/src/main/java/com/swirlds/config/impl/internal/ConverterService.java @@ -52,7 +52,6 @@ import java.util.Objects; class ConverterService implements ConfigLifecycle { - private final Map, ConfigConverter> converters; private boolean initialized = false; @@ -116,7 +115,7 @@ private > Class getConverterType(@NonNull fin .orElseGet(() -> getConverterType((Class) converterClass.getSuperclass())); } - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "rawtypes"}) @Nullable T convert(@Nullable final String value, @NonNull final Class targetClass) { throwIfNotInitialized(); @@ -128,6 +127,20 @@ T convert(@Nullable final String value, @NonNull final Class targetClass) return (T) value; } final ConfigConverter converter = (ConfigConverter) converters.get(targetClass); + + if (converter == null && targetClass.isEnum()) { + // FUTURE WORK: once logging is added to this module, log a warning here + // ("No converter defined for type '" + targetClass + "'. Converting using backup enum converter."); + try { + return (T) Enum.valueOf((Class) targetClass, value); + } catch (final IllegalArgumentException e) { + throw new IllegalArgumentException( + "Can not convert value '%s' of Enum '%s' by default. Please add a custom config converter." + .formatted(value, targetClass), + e); + } + } + if (converter == null) { throw new IllegalArgumentException("No converter defined for type '" + targetClass + "'"); } diff --git a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/StateSigner.java b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/StateSigner.java new file mode 100644 index 000000000000..bd28bc889770 --- /dev/null +++ b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/StateSigner.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2023 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; + +import com.swirlds.common.crypto.Hash; +import com.swirlds.common.crypto.Signature; +import com.swirlds.common.stream.HashSigner; +import com.swirlds.platform.state.signed.ReservedSignedState; +import com.swirlds.platform.system.status.PlatformStatus; +import com.swirlds.platform.system.status.PlatformStatusGetter; +import com.swirlds.platform.system.transaction.StateSignatureTransaction; +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; +import java.util.Objects; + +/** + * This class is responsible for signing states and producing {@link StateSignatureTransaction}s. + */ +public class StateSigner { + /** An object responsible for signing states with this node's key. */ + private final HashSigner signer; + /** provides the current platform status */ + private final PlatformStatusGetter platformStatusGetter; + + /** + * Create a new {@link StateSigner} instance. + * + * @param signer an object responsible for signing states with this node's key + * @param platformStatusGetter provides the current platform status + */ + public StateSigner(@NonNull final HashSigner signer, @NonNull final PlatformStatusGetter platformStatusGetter) { + this.signer = Objects.requireNonNull(signer); + this.platformStatusGetter = Objects.requireNonNull(platformStatusGetter); + } + + /** + * Sign the given state and produce a {@link StateSignatureTransaction} containing the signature. This method + * assumes that the given {@link ReservedSignedState} is reserved by the caller and will release the state when + * done. + * + * @param reservedSignedState the state to sign + * @return a {@link StateSignatureTransaction} containing the signature, or null if the state should not be signed + */ + public @Nullable StateSignatureTransaction signState(@NonNull final ReservedSignedState reservedSignedState) { + try (reservedSignedState) { + if (platformStatusGetter.getCurrentStatus() == PlatformStatus.REPLAYING_EVENTS) { + // the only time we don't want to submit signatures is during PCES replay + return null; + } + + final Hash stateHash = + Objects.requireNonNull(reservedSignedState.get().getState().getHash()); + final Signature signature = signer.sign(stateHash); + Objects.requireNonNull(signature); + + return new StateSignatureTransaction(reservedSignedState.get().getRound(), signature, stateHash); + } + } +} diff --git a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/SwirldsPlatform.java b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/SwirldsPlatform.java index 9e9c07717d96..47117b8ac857 100644 --- a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/SwirldsPlatform.java +++ b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/SwirldsPlatform.java @@ -182,7 +182,6 @@ import com.swirlds.platform.system.status.actions.StartedReplayingEventsAction; import com.swirlds.platform.system.transaction.StateSignatureTransaction; import com.swirlds.platform.system.transaction.SwirldTransaction; -import com.swirlds.platform.system.transaction.SystemTransaction; import com.swirlds.platform.threading.PauseAndLoad; import com.swirlds.platform.util.PlatformComponents; import com.swirlds.platform.wiring.PlatformWiring; @@ -503,15 +502,19 @@ public class SwirldsPlatform implements Platform { actualMainClassName, selfId, swirldName); + + transactionPool = new TransactionPool(platformContext); + // FUTURE WORK: at some point this should be part of the unified platform wiring final WiringModel model = WiringModel.create(platformContext, Time.getCurrent()); components.add(model); platformWiring = components.add(new PlatformWiring(platformContext, time)); platformWiring.wireExternalComponents( - preconsensusEventWriter, platformStatusManager, appCommunicationComponent); + preconsensusEventWriter, platformStatusManager, appCommunicationComponent, transactionPool); - platformWiring.bind(signedStateFileManager); + final StateSigner stateSigner = new StateSigner(new PlatformSigner(keysAndCerts), platformStatusManager); + platformWiring.bind(signedStateFileManager, stateSigner); final LatestCompleteStateNexus latestCompleteState = new LatestCompleteStateNexus(stateConfig, platformContext.getMetrics()); @@ -529,13 +532,11 @@ public class SwirldsPlatform implements Platform { platformContext, threadManager, dispatchBuilder, - new PlatformSigner(keysAndCerts), - txn -> this.createSystemTransaction(txn, true), newLatestCompleteStateConsumer, this::handleFatalError, - platformStatusManager, savedStateController, - platformWiring.getDumpStateToDiskInput()::put); + platformWiring.getDumpStateToDiskInput()::put, + platformWiring.getSignStateInput()::put); // Load the minimum generation into the pre-consensus event writer final List savedStates = getSavedStateFiles(actualMainClassName, selfId, swirldName); @@ -596,8 +597,6 @@ public class SwirldsPlatform implements Platform { final TransactionConfig transactionConfig = platformContext.getConfiguration().getConfigData(TransactionConfig.class); - transactionPool = new TransactionPool(platformContext); - // This object makes a copy of the state. After this point, initialState becomes immutable. swirldStateManager = new SwirldStateManager( platformContext, @@ -925,18 +924,6 @@ public NodeId getSelfId() { return selfId; } - /** - * Stores a new system transaction that will be added to an event in the future. - * - * @param systemTransaction the new system transaction to be included in a future event - * @return {@code true} if successful, {@code false} otherwise - */ - private boolean createSystemTransaction( - @NonNull final SystemTransaction systemTransaction, final boolean priority) { - Objects.requireNonNull(systemTransaction); - return transactionPool.submitTransaction(systemTransaction, priority); - } - /** * Initialize the state. * diff --git a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/components/common/query/PrioritySystemTransactionSubmitter.java b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/components/common/query/PrioritySystemTransactionSubmitter.java deleted file mode 100644 index 9567e686b156..000000000000 --- a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/components/common/query/PrioritySystemTransactionSubmitter.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2016-2023 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.components.common.query; - -import com.swirlds.platform.system.transaction.SystemTransaction; - -/** - * An object or method that submits a priority system transaction to the transaction pool for inclusion in an event. - * Priority system transactions are included in events before other transactions. Generally, priority transactions will - * be included in the very next event created. The only exception is if there is not enough room in the next event for - * all priority transactions waiting. - */ -@FunctionalInterface -public interface PrioritySystemTransactionSubmitter { - - /** - * Submits a priority system transaction for inclusion in an event. Submission is guaranteed to succeed. - * - * @param systemTransaction - * the system transaction to submit - * @return {@code true} if the transaction was successfully submitted, {@code false} otherwise - */ - boolean submit(SystemTransaction systemTransaction); -} diff --git a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/components/state/DefaultStateManagementComponent.java b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/components/state/DefaultStateManagementComponent.java index 01511b9427df..1ac3aec8b40a 100644 --- a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/components/state/DefaultStateManagementComponent.java +++ b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/components/state/DefaultStateManagementComponent.java @@ -22,17 +22,12 @@ import com.swirlds.base.time.Time; import com.swirlds.common.config.StateConfig; import com.swirlds.common.context.PlatformContext; -import com.swirlds.common.crypto.Signature; -import com.swirlds.common.stream.HashSigner; import com.swirlds.common.threading.manager.ThreadManager; import com.swirlds.platform.components.SavedStateController; import com.swirlds.platform.components.common.output.FatalErrorConsumer; -import com.swirlds.platform.components.common.query.PrioritySystemTransactionSubmitter; import com.swirlds.platform.components.state.output.NewLatestCompleteStateConsumer; -import com.swirlds.platform.crypto.PlatformSigner; import com.swirlds.platform.dispatch.DispatchBuilder; import com.swirlds.platform.dispatch.triggers.flow.StateHashedTrigger; -import com.swirlds.platform.state.SignatureTransmitter; import com.swirlds.platform.state.signed.ReservedSignedState; import com.swirlds.platform.state.signed.SignedState; import com.swirlds.platform.state.signed.SignedStateGarbageCollector; @@ -44,7 +39,6 @@ import com.swirlds.platform.state.signed.SourceOfSignedState; import com.swirlds.platform.state.signed.StateDumpRequest; import com.swirlds.platform.state.signed.StateToDiskReason; -import com.swirlds.platform.system.status.PlatformStatusGetter; import com.swirlds.platform.util.HashLogger; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; @@ -63,16 +57,6 @@ public class DefaultStateManagementComponent implements StateManagementComponent private static final Logger logger = LogManager.getLogger(DefaultStateManagementComponent.class); - /** - * An object responsible for signing states with this node's key. - */ - private final HashSigner signer; - - /** - * Submits state signature transactions to the transaction pool - */ - private final SignatureTransmitter signatureTransmitter; - /** * Signed states are deleted on this background thread. */ @@ -100,17 +84,15 @@ public class DefaultStateManagementComponent implements StateManagementComponent private final SavedStateController savedStateController; private final Consumer stateDumpConsumer; + private final Consumer stateSigner; /** * @param platformContext the platform context * @param threadManager manages platform thread resources * @param dispatchBuilder builds dispatchers. This is deprecated, do not wire new things together * with this. - * @param signer an object capable of signing with the platform's private key - * @param prioritySystemTransactionSubmitter submits priority system transactions * @param newLatestCompleteStateConsumer consumer to invoke when there is a new latest complete signed state * @param fatalErrorConsumer consumer to invoke when a fatal error has occurred - * @param platformStatusGetter gets the current platform status * @param savedStateController controls which states are saved to disk * @param stateDumpConsumer consumer to invoke when a state is requested to be dumped to disk */ @@ -118,29 +100,24 @@ public DefaultStateManagementComponent( @NonNull final PlatformContext platformContext, @NonNull final ThreadManager threadManager, @NonNull final DispatchBuilder dispatchBuilder, - @NonNull final PlatformSigner signer, - @NonNull final PrioritySystemTransactionSubmitter prioritySystemTransactionSubmitter, @NonNull final NewLatestCompleteStateConsumer newLatestCompleteStateConsumer, @NonNull final FatalErrorConsumer fatalErrorConsumer, - @NonNull final PlatformStatusGetter platformStatusGetter, @NonNull final SavedStateController savedStateController, - @NonNull final Consumer stateDumpConsumer) { + @NonNull final Consumer stateDumpConsumer, + @NonNull final Consumer stateSigner) { Objects.requireNonNull(platformContext); Objects.requireNonNull(threadManager); - Objects.requireNonNull(prioritySystemTransactionSubmitter); Objects.requireNonNull(newLatestCompleteStateConsumer); Objects.requireNonNull(fatalErrorConsumer); - Objects.requireNonNull(platformStatusGetter); - this.signer = Objects.requireNonNull(signer); - this.signatureTransmitter = new SignatureTransmitter(prioritySystemTransactionSubmitter, platformStatusGetter); // Various metrics about signed states final SignedStateMetrics signedStateMetrics = new SignedStateMetrics(platformContext.getMetrics()); this.signedStateGarbageCollector = new SignedStateGarbageCollector(threadManager, signedStateMetrics); this.signedStateSentinel = new SignedStateSentinel(platformContext, threadManager, Time.getCurrent()); this.savedStateController = Objects.requireNonNull(savedStateController); this.stateDumpConsumer = Objects.requireNonNull(stateDumpConsumer); + this.stateSigner = Objects.requireNonNull(stateSigner); hashLogger = new HashLogger(threadManager, platformContext.getConfiguration().getConfigData(StateConfig.class)); @@ -224,11 +201,7 @@ public void newSignedStateFromTransactions(@NonNull final ReservedSignedState si newSignedStateBeingTracked(signedState.get(), SourceOfSignedState.TRANSACTIONS); - final Signature signature = signer.sign(signedState.get().getState().getHash()); - signatureTransmitter.transmitSignature( - signedState.get().getRound(), - signature, - signedState.get().getState().getHash()); + stateSigner.accept(signedState.getAndReserve("signing state from transactions")); signedStateManager.addState(signedState.get()); } diff --git a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/eventhandling/TransactionPool.java b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/eventhandling/TransactionPool.java index a9d0d0da0fba..e60713f395aa 100644 --- a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/eventhandling/TransactionPool.java +++ b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/eventhandling/TransactionPool.java @@ -23,6 +23,7 @@ import com.swirlds.platform.system.transaction.ConsensusTransaction; import com.swirlds.platform.system.transaction.ConsensusTransactionImpl; import com.swirlds.platform.system.transaction.StateSignatureTransaction; +import com.swirlds.platform.system.transaction.SystemTransaction; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import java.util.LinkedList; @@ -206,6 +207,14 @@ public synchronized boolean submitTransaction( return true; } + /** + * Same as {@link #submitTransaction(ConsensusTransactionImpl, boolean)} but with priority set to true. + * This method has no return since system transactions are never rejected. + */ + public synchronized void submitSystemTransaction(@NonNull final SystemTransaction transaction) { + submitTransaction(transaction, true); + } + /** * get the number of buffered transactions * diff --git a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/state/SignatureTransmitter.java b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/state/SignatureTransmitter.java deleted file mode 100644 index 730f9be9a2ae..000000000000 --- a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/state/SignatureTransmitter.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2016-2023 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.logging.legacy.LogMarker.EXCEPTION; - -import com.swirlds.common.crypto.Hash; -import com.swirlds.common.crypto.Signature; -import com.swirlds.platform.components.common.query.PrioritySystemTransactionSubmitter; -import com.swirlds.platform.system.status.PlatformStatus; -import com.swirlds.platform.system.status.PlatformStatusGetter; -import com.swirlds.platform.system.transaction.StateSignatureTransaction; -import com.swirlds.platform.system.transaction.SystemTransaction; -import edu.umd.cs.findbugs.annotations.NonNull; -import java.util.Objects; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -/** - * This class transmits this node's signature on a signed state (via transactions). - */ -public final class SignatureTransmitter { - - private static final Logger logger = LogManager.getLogger(SignatureTransmitter.class); - - private final PrioritySystemTransactionSubmitter prioritySystemTransactionSubmitter; - private final PlatformStatusGetter platformStatusGetter; - - /** - * Create a new SignatureTransmitter. - * - * @param prioritySystemTransactionSubmitter used to submit system transactions at high priority - * @param platformStatusGetter provides the current platform status - */ - public SignatureTransmitter( - @NonNull final PrioritySystemTransactionSubmitter prioritySystemTransactionSubmitter, - @NonNull final PlatformStatusGetter platformStatusGetter) { - - this.prioritySystemTransactionSubmitter = Objects.requireNonNull(prioritySystemTransactionSubmitter); - this.platformStatusGetter = Objects.requireNonNull(platformStatusGetter); - } - - /** - * Transmit this node's signature to other nodes for a signed state. Signatures from zero weight nodes are - * transmitted and valuable for the purpose of detecting ISSes. - * - * @param round the round of the state that was signed - * @param signature the self signature on the state - * @param stateHash the hash of the state that was signed - */ - public void transmitSignature(final long round, @NonNull final Signature signature, @NonNull final Hash stateHash) { - - Objects.requireNonNull(signature); - Objects.requireNonNull(stateHash); - - if (platformStatusGetter.getCurrentStatus() == PlatformStatus.REPLAYING_EVENTS) { - // the only time we don't want to submit signatures is during PCES replay - return; - } - - final SystemTransaction signatureTransaction = new StateSignatureTransaction(round, signature, stateHash); - final boolean success = prioritySystemTransactionSubmitter.submit(signatureTransaction); - - if (!success) { - logger.error(EXCEPTION.getMarker(), "failed to create signed state transaction"); - } - } -} diff --git a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/wiring/PlatformSchedulers.java b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/wiring/PlatformSchedulers.java index 7f6906c6ba1e..dbc2e10f5721 100644 --- a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/wiring/PlatformSchedulers.java +++ b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/wiring/PlatformSchedulers.java @@ -24,6 +24,7 @@ import com.swirlds.platform.internal.ConsensusRound; import com.swirlds.platform.internal.EventImpl; import com.swirlds.platform.state.signed.StateSavingResult; +import com.swirlds.platform.system.transaction.StateSignatureTransaction; import edu.umd.cs.findbugs.annotations.NonNull; import java.util.List; @@ -38,6 +39,7 @@ * @param linkedEventIntakeScheduler the scheduler for the linked event intake * @param eventCreationManagerScheduler the scheduler for the event creation manager * @param signedStateFileManagerScheduler the scheduler for the signed state file manager + * @param stateSignerScheduler the scheduler for the state signer */ public record PlatformSchedulers( @NonNull TaskScheduler internalEventValidatorScheduler, @@ -47,7 +49,8 @@ public record PlatformSchedulers( @NonNull TaskScheduler inOrderLinkerScheduler, @NonNull TaskScheduler> linkedEventIntakeScheduler, @NonNull TaskScheduler eventCreationManagerScheduler, - @NonNull TaskScheduler signedStateFileManagerScheduler) { + @NonNull TaskScheduler signedStateFileManagerScheduler, + @NonNull TaskScheduler stateSignerScheduler) { /** * Instantiate the schedulers for the platform, for the given wiring model @@ -62,59 +65,64 @@ public static PlatformSchedulers create(@NonNull final PlatformContext context, return new PlatformSchedulers( model.schedulerBuilder("internalEventValidator") - .withType(config.getInternalEventValidatorSchedulerType()) + .withType(config.internalEventValidatorSchedulerType()) .withUnhandledTaskCapacity(config.internalEventValidatorUnhandledCapacity()) .withFlushingEnabled(true) .withMetricsBuilder(model.metricsBuilder().withUnhandledTaskMetricEnabled(true)) .build() .cast(), model.schedulerBuilder("eventDeduplicator") - .withType(config.getEventDeduplicatorSchedulerType()) + .withType(config.eventDeduplicatorSchedulerType()) .withUnhandledTaskCapacity(config.eventDeduplicatorUnhandledCapacity()) .withFlushingEnabled(true) .withMetricsBuilder(model.metricsBuilder().withUnhandledTaskMetricEnabled(true)) .build() .cast(), model.schedulerBuilder("eventSignatureValidator") - .withType(config.getEventSignatureValidatorSchedulerType()) + .withType(config.eventSignatureValidatorSchedulerType()) .withUnhandledTaskCapacity(config.eventSignatureValidatorUnhandledCapacity()) .withFlushingEnabled(true) .withMetricsBuilder(model.metricsBuilder().withUnhandledTaskMetricEnabled(true)) .build() .cast(), model.schedulerBuilder("orphanBuffer") - .withType(config.getOrphanBufferSchedulerType()) + .withType(config.orphanBufferSchedulerType()) .withUnhandledTaskCapacity(config.orphanBufferUnhandledCapacity()) .withFlushingEnabled(true) .withMetricsBuilder(model.metricsBuilder().withUnhandledTaskMetricEnabled(true)) .build() .cast(), model.schedulerBuilder("inOrderLinker") - .withType(config.getInOrderLinkerSchedulerType()) + .withType(config.inOrderLinkerSchedulerType()) .withUnhandledTaskCapacity(config.inOrderLinkerUnhandledCapacity()) .withFlushingEnabled(true) .withMetricsBuilder(model.metricsBuilder().withUnhandledTaskMetricEnabled(true)) .build() .cast(), model.schedulerBuilder("linkedEventIntake") - .withType(config.getLinkedEventIntakeSchedulerType()) + .withType(config.linkedEventIntakeSchedulerType()) .withUnhandledTaskCapacity(config.linkedEventIntakeUnhandledCapacity()) .withFlushingEnabled(true) .withMetricsBuilder(model.metricsBuilder().withUnhandledTaskMetricEnabled(true)) .build() .cast(), model.schedulerBuilder("eventCreationManager") - .withType(config.getEventCreationManagerSchedulerType()) + .withType(config.eventCreationManagerSchedulerType()) .withUnhandledTaskCapacity(config.eventCreationManagerUnhandledCapacity()) .withFlushingEnabled(true) .withMetricsBuilder(model.metricsBuilder().withUnhandledTaskMetricEnabled(true)) .build() .cast(), model.schedulerBuilder("signedStateFileManager") - .withType(config.getSignedStateFileManagerSchedulerType()) + .withType(config.signedStateFileManagerSchedulerType()) .withUnhandledTaskCapacity(config.signedStateFileManagerUnhandledCapacity()) .withMetricsBuilder(model.metricsBuilder().withUnhandledTaskMetricEnabled(true)) .build() + .cast(), + model.schedulerBuilder("stateSigner") + .withType(config.stateSignerSchedulerType()) + .withUnhandledTaskCapacity(config.stateSignerUnhandledCapacity()) + .build() .cast()); } } diff --git a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/wiring/PlatformWiring.java b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/wiring/PlatformWiring.java index 1898cabd83f2..f429b0531ca3 100644 --- a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/wiring/PlatformWiring.java +++ b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/wiring/PlatformWiring.java @@ -27,6 +27,7 @@ import com.swirlds.common.wiring.model.WiringModel; import com.swirlds.common.wiring.wires.input.InputWire; import com.swirlds.common.wiring.wires.output.OutputWire; +import com.swirlds.platform.StateSigner; import com.swirlds.platform.components.LinkedEventIntake; import com.swirlds.platform.components.appcomm.AppCommunicationComponent; import com.swirlds.platform.event.GossipEvent; @@ -38,6 +39,7 @@ import com.swirlds.platform.event.validation.AddressBookUpdate; import com.swirlds.platform.event.validation.EventSignatureValidator; import com.swirlds.platform.event.validation.InternalEventValidator; +import com.swirlds.platform.eventhandling.TransactionPool; import com.swirlds.platform.state.signed.ReservedSignedState; import com.swirlds.platform.state.signed.SignedStateFileManager; import com.swirlds.platform.state.signed.StateDumpRequest; @@ -61,6 +63,7 @@ public class PlatformWiring implements Startable, Stoppable, Clearable { private final LinkedEventIntakeWiring linkedEventIntakeWiring; private final EventCreationManagerWiring eventCreationManagerWiring; private final SignedStateFileManagerWiring signedStateFileManagerWiring; + private final StateSignerWiring stateSignerWiring; private final PlatformCoordinator platformCoordinator; @@ -111,6 +114,7 @@ public PlatformWiring(@NonNull final PlatformContext platformContext, @NonNull f signedStateFileManagerWiring = SignedStateFileManagerWiring.create(schedulers.signedStateFileManagerScheduler()); + stateSignerWiring = StateSignerWiring.create(schedulers.stateSignerScheduler()); wire(); } @@ -167,11 +171,13 @@ private void wire() { * @param preconsensusEventWriter the preconsensus event writer to wire * @param statusManager the status manager to wire * @param appCommunicationComponent the app communication component to wire + * @param transactionPool the transaction pool to wire */ public void wireExternalComponents( @NonNull final PreconsensusEventWriter preconsensusEventWriter, @NonNull final PlatformStatusManager statusManager, - @NonNull final AppCommunicationComponent appCommunicationComponent) { + @NonNull final AppCommunicationComponent appCommunicationComponent, + @NonNull final TransactionPool transactionPool) { signedStateFileManagerWiring .oldestMinimumGenerationOnDiskOutputWire() @@ -184,6 +190,7 @@ public void wireExternalComponents( signedStateFileManagerWiring .stateSavingResultOutputWire() .solderTo("app communication", appCommunicationComponent::stateSavedToDisk); + stateSignerWiring.stateSignature().solderTo("transaction pool", transactionPool::submitSystemTransaction); } /** @@ -222,9 +229,12 @@ public void bindIntake( * Bind components to the wiring. * * @param signedStateFileManager the signed state file manager to bind + * @param stateSigner the state signer to bind */ - public void bind(@NonNull final SignedStateFileManager signedStateFileManager) { + public void bind( + @NonNull final SignedStateFileManager signedStateFileManager, @NonNull final StateSigner stateSigner) { signedStateFileManagerWiring.bind(signedStateFileManager); + stateSignerWiring.bind(stateSigner); // FUTURE WORK: bind all the things! } @@ -280,6 +290,19 @@ public InputWire getDumpStateToDiskInput() { return signedStateFileManagerWiring.dumpStateToDisk(); } + /** + * Get the input wire for signing a state + *

+ * Future work: this is a temporary hook to allow the components to sign a state, prior to the whole + * system being migrated to the new framework. + * + * @return the input wire for signing a state + */ + @NonNull + public InputWire getSignStateInput() { + return stateSignerWiring.signState(); + } + /** * Inject a new minimum generation non-ancient on all components that need it. *

diff --git a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/wiring/StateSignerWiring.java b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/wiring/StateSignerWiring.java new file mode 100644 index 000000000000..51489e10160b --- /dev/null +++ b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/wiring/StateSignerWiring.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2023 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.wiring; + +import com.swirlds.common.wiring.schedulers.TaskScheduler; +import com.swirlds.common.wiring.wires.input.BindableInputWire; +import com.swirlds.common.wiring.wires.input.InputWire; +import com.swirlds.common.wiring.wires.output.OutputWire; +import com.swirlds.platform.StateSigner; +import com.swirlds.platform.state.signed.ReservedSignedState; +import com.swirlds.platform.system.transaction.StateSignatureTransaction; +import edu.umd.cs.findbugs.annotations.NonNull; + +/** + * The wiring for the {@link com.swirlds.platform.StateSigner} + * + * @param signState the input wire for signing a state + * @param stateSignature the output wire for the state signature + */ +public record StateSignerWiring( + @NonNull InputWire signState, + @NonNull OutputWire stateSignature) { + + /** + * Create a new instance of this wiring + * + * @param scheduler the task scheduler for this wiring + * @return the new wiring instance + */ + public static StateSignerWiring create(@NonNull final TaskScheduler scheduler) { + return new StateSignerWiring(scheduler.buildInputWire("sign a state"), scheduler.getOutputWire()); + } + + /** + * Bind the wires to the {@link com.swirlds.platform.StateSigner} + * + * @param stateSigner the state signer + */ + public void bind(@NonNull final StateSigner stateSigner) { + ((BindableInputWire) signState).bind(stateSigner::signState); + } +} diff --git a/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/components/state/StateManagementComponentTests.java b/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/components/state/StateManagementComponentTests.java index 5c546b8c81f3..961a5423919f 100644 --- a/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/components/state/StateManagementComponentTests.java +++ b/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/components/state/StateManagementComponentTests.java @@ -21,9 +21,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; import com.swirlds.common.config.StateConfig_; import com.swirlds.common.context.PlatformContext; @@ -35,15 +33,13 @@ import com.swirlds.common.test.fixtures.AssertionUtils; import com.swirlds.common.test.fixtures.RandomUtils; import com.swirlds.common.threading.manager.AdHocThreadManager; -import com.swirlds.platform.crypto.PlatformSigner; import com.swirlds.platform.dispatch.DispatchBuilder; import com.swirlds.platform.dispatch.DispatchConfiguration; import com.swirlds.platform.state.RandomSignedStateGenerator; +import com.swirlds.platform.state.signed.ReservedSignedState; import com.swirlds.platform.state.signed.SignedState; import com.swirlds.platform.state.signed.SourceOfSignedState; import com.swirlds.platform.system.address.AddressBook; -import com.swirlds.platform.system.status.PlatformStatus; -import com.swirlds.platform.system.status.PlatformStatusGetter; import com.swirlds.platform.system.transaction.StateSignatureTransaction; import com.swirlds.test.framework.config.TestConfigBuilder; import com.swirlds.test.framework.context.TestPlatformContextBuilder; @@ -55,6 +51,7 @@ import java.util.Map; import java.util.Random; import java.util.concurrent.ExecutionException; +import java.util.function.Consumer; import java.util.stream.IntStream; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -357,11 +354,14 @@ private DefaultStateManagementComponent newStateManagementComponent( .withConfiguration(configBuilder.getOrCreateConfig()) .build(); - final PlatformSigner signer = mock(PlatformSigner.class); - when(signer.sign(any(Hash.class))).thenReturn(mock(Signature.class)); - - final PlatformStatusGetter platformStatusGetter = mock(PlatformStatusGetter.class); - when(platformStatusGetter.getCurrentStatus()).thenReturn(PlatformStatus.ACTIVE); + final Consumer signer = rs -> { + try (rs) { + systemTransactionConsumer.consume(new StateSignatureTransaction( + rs.get().getRound(), + mock(Signature.class), + rs.get().getState().getHash())); + } + }; final DispatchConfiguration dispatchConfiguration = platformContext.getConfiguration().getConfigData(DispatchConfiguration.class); @@ -372,13 +372,11 @@ private DefaultStateManagementComponent newStateManagementComponent( platformContext, AdHocThreadManager.getStaticThreadManager(), dispatchBuilder, - signer, - systemTransactionConsumer::consume, newLatestCompleteStateConsumer::consume, (msg, t, code) -> {}, - platformStatusGetter, controller, - r -> {}); + r -> {}, + signer); dispatchBuilder.start(); diff --git a/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/wiring/PlatformWiringTests.java b/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/wiring/PlatformWiringTests.java index f1b0354a877f..041122de5f0c 100644 --- a/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/wiring/PlatformWiringTests.java +++ b/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/wiring/PlatformWiringTests.java @@ -22,6 +22,7 @@ import com.swirlds.base.test.fixtures.time.FakeTime; import com.swirlds.common.context.PlatformContext; import com.swirlds.config.api.Configuration; +import com.swirlds.platform.StateSigner; import com.swirlds.platform.components.LinkedEventIntake; import com.swirlds.platform.event.creation.EventCreationManager; import com.swirlds.platform.event.deduplication.EventDeduplicator; @@ -51,7 +52,7 @@ void testBindingsWithLegacyIntake() { final PlatformWiring wiring = new PlatformWiring(platformContext, new FakeTime()); - wiring.bind(mock(SignedStateFileManager.class)); + wiring.bind(mock(SignedStateFileManager.class), mock(StateSigner.class)); assertFalse(wiring.getModel().checkForUnboundInputWires()); } @@ -76,7 +77,7 @@ void testBindingsWithNewIntake() { mock(InOrderLinker.class), mock(LinkedEventIntake.class), mock(EventCreationManager.class)); - wiring.bind(mock(SignedStateFileManager.class)); + wiring.bind(mock(SignedStateFileManager.class), mock(StateSigner.class)); assertFalse(wiring.getModel().checkForUnboundInputWires()); }