Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add new event hashing algorithm #14340

Merged
merged 6 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
import com.swirlds.platform.event.validation.InternalEventValidator;
import com.swirlds.platform.eventhandling.DefaultTransactionHandler;
import com.swirlds.platform.eventhandling.DefaultTransactionPrehandler;
import com.swirlds.platform.eventhandling.EventConfig;
import com.swirlds.platform.eventhandling.TransactionHandler;
import com.swirlds.platform.eventhandling.TransactionPrehandler;
import com.swirlds.platform.gossip.SyncGossip;
Expand Down Expand Up @@ -257,7 +258,12 @@ public PlatformComponentBuilder withEventHasher(@NonNull final EventHasher event
@NonNull
public EventHasher buildEventHasher() {
if (eventHasher == null) {
eventHasher = new DefaultEventHasher();
eventHasher = new DefaultEventHasher(
blocks.appVersion().getPbjSemanticVersion(),
blocks.platformContext()
.getConfiguration()
.getConfigData(EventConfig.class)
.migrateEventHashing());
}
return eventHasher;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
import com.swirlds.platform.event.PlatformEvent;
import com.swirlds.platform.event.creation.EventCreationConfig;
import com.swirlds.platform.event.creation.EventCreator;
import com.swirlds.platform.event.hashing.PbjHasher;
import com.swirlds.platform.event.hashing.StatefulEventHasher;
import com.swirlds.platform.event.hashing.UnsignedEventHasher;
import com.swirlds.platform.eventhandling.EventConfig;
import com.swirlds.platform.system.SoftwareVersion;
import com.swirlds.platform.system.address.AddressBook;
Expand Down Expand Up @@ -119,7 +121,7 @@ public class TipsetEventCreator implements EventCreator {
/**
* Event hasher for unsigned events.
*/
private final StatefulEventHasher statefulEventHasher = new StatefulEventHasher();
private final UnsignedEventHasher eventHasher;

/**
* Create a new tipset event creator.
Expand Down Expand Up @@ -169,6 +171,12 @@ public TipsetEventCreator(
noParentFoundLogger = new RateLimitedLogger(logger, time, Duration.ofMinutes(1));

this.eventWindow = EventWindow.getGenesisEventWindow(ancientMode);
this.eventHasher = platformContext
.getConfiguration()
.getConfigData(EventConfig.class)
.migrateEventHashing()
? new PbjHasher()
: new StatefulEventHasher();
}

/**
Expand Down Expand Up @@ -441,7 +449,7 @@ private UnsignedEvent assembleEventObject(@Nullable final EventDescriptor otherP
: ConsensusConstants.ROUND_FIRST,
timeCreated,
transactionSupplier.getTransactions());
statefulEventHasher.hashEvent(event);
eventHasher.hashUnsignedEvent(event);

return event;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,42 @@

package com.swirlds.platform.event.hashing;

import com.hedera.hapi.node.base.SemanticVersion;
import com.swirlds.platform.event.PlatformEvent;
import com.swirlds.state.spi.HapiUtils;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.util.Objects;

/**
* Default implementation of the {@link EventHasher}.
*/
public class DefaultEventHasher implements EventHasher {
private final SemanticVersion currentSoftwareVersion;
private final boolean migrateEventHashing;

/**
* Constructs a new {@link DefaultEventHasher} with the given {@link SemanticVersion} and migration flag.
*
* @param currentSoftwareVersion the current software version
* @param migrateEventHashing if true then use the new event hashing algorithm for new events, events created by
* previous software versions will still need to be hashed using the old algorithm.
*/
public DefaultEventHasher(
@NonNull final SemanticVersion currentSoftwareVersion, final boolean migrateEventHashing) {
this.currentSoftwareVersion = Objects.requireNonNull(currentSoftwareVersion);
this.migrateEventHashing = migrateEventHashing;
}

@Override
@NonNull
public PlatformEvent hashEvent(@NonNull final PlatformEvent event) {
Objects.requireNonNull(event);
if (migrateEventHashing
lpetrovic05 marked this conversation as resolved.
Show resolved Hide resolved
&& HapiUtils.SEMANTIC_VERSION_COMPARATOR.compare(currentSoftwareVersion, event.getSoftwareVersion())
== 0) {
new PbjHasher().hashEvent(event);
return event;
}
new StatefulEventHasher().hashEvent(event);
return event;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,39 @@
import com.swirlds.common.crypto.Hash;
import com.swirlds.common.crypto.HashingOutputStream;
import com.swirlds.platform.event.PlatformEvent;
import com.swirlds.platform.system.events.UnsignedEvent;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.io.IOException;
import java.util.Objects;

/**
* Hashes the PBJ representation of an event. This hasher double hashes each payload in order to allow redaction of
* payloads without invalidating the event hash.
*/
public class PbjHasher implements EventHasher {
public class PbjHasher implements EventHasher, UnsignedEventHasher {

/** The hashing stream for the event. */
private final HashingOutputStream eventHashingStream = new HashingOutputStream(DigestType.SHA_384.buildDigest());
/** The hashing stream for the payloads. */
private final HashingOutputStream payloadHashingStream = new HashingOutputStream(DigestType.SHA_384.buildDigest());

@Override
@NonNull
public PlatformEvent hashEvent(@NonNull final PlatformEvent event) {
lpetrovic05 marked this conversation as resolved.
Show resolved Hide resolved
EventCore.PROTOBUF.toBytes(event.getUnsignedEvent().getEventCore()).writeTo(eventHashingStream);
event.getUnsignedEvent().getPayloads().forEach(payload -> {
Objects.requireNonNull(event);
hashUnsignedEvent(event.getUnsignedEvent());
event.setHash(event.getUnsignedEvent().getHash());
return event;
}

/**
* Hashes the given {@link UnsignedEvent} and sets the hash on the event.
*
* @param event the event to hash
*/
public void hashUnsignedEvent(@NonNull final UnsignedEvent event) {
EventCore.PROTOBUF.toBytes(event.getEventCore()).writeTo(eventHashingStream);
event.getPayloads().forEach(payload -> {
EventPayload.PROTOBUF.toBytes(payload).writeTo(payloadHashingStream);
try {
eventHashingStream.write(payloadHashingStream.getDigest());
Expand All @@ -49,7 +64,5 @@ public PlatformEvent hashEvent(@NonNull final PlatformEvent event) {
});

event.setHash(new Hash(eventHashingStream.getDigest(), DigestType.SHA_384));

return event;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
/**
* An implementation of {@link EventHasher} that is stateful and thus not safe to use by multiple threads concurrently.
*/
public class StatefulEventHasher implements EventHasher {
public class StatefulEventHasher implements EventHasher, UnsignedEventHasher {
private final HashingOutputStream hashingOutputStream = new HashingOutputStream(DigestType.SHA_384.buildDigest());
private final SerializableDataOutputStream outputStream = new SerializableDataOutputStream(hashingOutputStream);

Expand All @@ -54,14 +54,12 @@ public PlatformEvent hashEvent(@NonNull final PlatformEvent event) {
* Hashes the given {@link UnsignedEvent} and sets the hash on the event.
*
* @param event the event to hash
* @return the hashed event
*/
@NonNull
public UnsignedEvent hashEvent(@NonNull final UnsignedEvent event) {
@Override
public void hashUnsignedEvent(@NonNull final UnsignedEvent event) {
try {
event.serializeLegacyHashBytes(outputStream);
event.setHash(new Hash(hashingOutputStream.getDigest(), DigestType.SHA_384));
return event;
} catch (final IOException e) {
throw new RuntimeException("An exception occurred while trying to hash an event!", e);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* 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.event.hashing;

import com.swirlds.platform.system.events.UnsignedEvent;
import edu.umd.cs.findbugs.annotations.NonNull;

/**
* Hashes unsigned events.
*/
public interface UnsignedEventHasher {

/**
lpetrovic05 marked this conversation as resolved.
Show resolved Hide resolved
* Hashes the event and builds the event descriptor.
*
* @param event the event to hash
*/
void hashUnsignedEvent(@NonNull final UnsignedEvent event);
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@
* ancient or not. Once this setting has been enabled on a network, it can
* never be disabled again (migration pathway is one-way).
* @param useOldStyleIntakeQueue if true then use an old style queue between gossip and the intake queue
* @param migrateEventHashing if true then use the new event hashing algorithm for new events, events
* created by previous software versions will still need to be hashed using the
* old algorithm.
*/
@ConfigData("event")
public record EventConfig(
Expand All @@ -44,7 +47,8 @@ public record EventConfig(
@ConfigProperty(defaultValue = "/opt/hgcapp/eventsStreams") String eventsLogDir,
@ConfigProperty(defaultValue = "true") boolean enableEventStreaming,
@ConfigProperty(defaultValue = "false") boolean useBirthRoundAncientThreshold,
@ConfigProperty(defaultValue = "true") boolean useOldStyleIntakeQueue) {
@ConfigProperty(defaultValue = "true") boolean useOldStyleIntakeQueue,
@ConfigProperty(defaultValue = "false") boolean migrateEventHashing) {

/**
* @return the {@link AncientMode} based on useBirthRoundAncientThreshold
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public static UnsignedEvent randomUnsignedEventWithTimestamp(
if (fakeHash) {
unsignedEvent.setHash(RandomUtils.randomHash(random));
} else {
new StatefulEventHasher().hashEvent(unsignedEvent);
new StatefulEventHasher().hashUnsignedEvent(unsignedEvent);
}
return unsignedEvent;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,11 @@
import com.swirlds.platform.event.hashing.EventHasher;
import com.swirlds.platform.event.orphan.DefaultOrphanBuffer;
import com.swirlds.platform.event.orphan.OrphanBuffer;
import com.swirlds.platform.eventhandling.EventConfig;
import com.swirlds.platform.gossip.IntakeEventCounter;
import com.swirlds.platform.gossip.NoOpIntakeEventCounter;
import com.swirlds.platform.internal.ConsensusRound;
import com.swirlds.platform.system.BasicSoftwareVersion;
import com.swirlds.platform.system.address.AddressBook;
import com.swirlds.platform.test.consensus.framework.ConsensusOutput;
import com.swirlds.platform.test.fixtures.event.IndexedEvent;
Expand Down Expand Up @@ -82,7 +84,12 @@ public TestIntake(@NonNull final PlatformContext platformContext, @NonNull final
model = WiringModelBuilder.create(platformContext).build();

hasherWiring = new ComponentWiring<>(model, EventHasher.class, directScheduler("eventHasher"));
final EventHasher eventHasher = new DefaultEventHasher();
final EventHasher eventHasher = new DefaultEventHasher(
new BasicSoftwareVersion(1).getPbjSemanticVersion(),
platformContext
.getConfiguration()
.getConfigData(EventConfig.class)
.migrateEventHashing());
hasherWiring.bind(eventHasher);

final PassThroughWiring<PlatformEvent> postHashCollectorWiring =
Expand Down
Loading