Skip to content

Commit

Permalink
test: adapt IssDetectorTests to work with both the deprecated and new…
Browse files Browse the repository at this point in the history
… transaction format

Signed-off-by: Ivan Kavaldzhiev <[email protected]>
  • Loading branch information
IvanKavaldzhiev committed Jan 21, 2025
1 parent b64fc96 commit 50733eb
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.hedera.hapi.platform.event.EventDescriptor;
import com.hedera.hapi.platform.event.EventTransaction;
import com.hedera.hapi.platform.event.EventTransaction.TransactionOneOfType;
import com.hedera.hapi.platform.event.GossipEvent;
import com.hedera.hapi.platform.event.StateSignatureTransaction;
import com.hedera.hapi.util.HapiUtils;
import com.hedera.pbj.runtime.OneOf;
Expand Down Expand Up @@ -58,6 +59,13 @@ public class TestingEventBuilder {

private final Random random;

/**
* Flag that determines whether to use the new transaction format of Bytes.
* <p>
* If set to true, transactions will be encoded in the new format of Bytes. If set to false, the deprecated OneOf format will be used.
*/
private boolean useNewTransactionFormat = false;

/**
* Creator ID to use.
* <p>
Expand Down Expand Up @@ -184,6 +192,19 @@ public TestingEventBuilder(@NonNull final Random random) {
this.random = Objects.requireNonNull(random);
}

/**
* Set the flag for using the new transaction format
* <p>
* If not set, the deprecated transaction format will be used. If it's set the new Bytes format will be used.
*
* @param useNewTransactionFormat the creator ID
* @return this instance
*/
public @NonNull TestingEventBuilder setUseNewTransactionFormat(final boolean useNewTransactionFormat) {
this.useNewTransactionFormat = useNewTransactionFormat;
return this;
}

/**
* Set the creator ID to use.
* <p>
Expand Down Expand Up @@ -592,7 +613,12 @@ private EventDescriptorWrapper createDescriptorFromParent(
final byte[] signature = new byte[SignatureType.RSA.signatureLength()];
random.nextBytes(signature);

final PlatformEvent platformEvent = new PlatformEvent(unsignedEvent, signature);
final PlatformEvent platformEvent = new PlatformEvent(new GossipEvent(
Objects.requireNonNull(unsignedEvent, "The unsignedEvent must not be null")
.getEventCore(),
Objects.requireNonNull(Bytes.wrap(signature), "The signature must not be null"),
useNewTransactionFormat ? null : transactions,
useNewTransactionFormat ? unsignedEvent.getTransactionsBytes() : new ArrayList<>()));

platformEvent.setHash(RandomUtils.randomHash(random));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@
import com.hedera.hapi.node.state.roster.Roster;
import com.hedera.hapi.node.state.roster.RosterEntry;
import com.hedera.hapi.node.transaction.TransactionBody;
import com.hedera.hapi.platform.event.EventTransaction;
import com.hedera.hapi.platform.event.EventTransaction.TransactionOneOfType;
import com.hedera.hapi.platform.event.StateSignatureTransaction;
import com.hedera.pbj.runtime.OneOf;
import com.hedera.pbj.runtime.io.buffer.Bytes;
import com.swirlds.common.context.PlatformContext;
import com.swirlds.common.crypto.Hash;
Expand Down Expand Up @@ -66,7 +69,8 @@
import java.util.Map;
import java.util.Random;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

@DisplayName("IssDetector Tests")
class IssDetectorTests extends PlatformTest {
Expand All @@ -82,7 +86,8 @@ class IssDetectorTests extends PlatformTest {
private static List<EventImpl> generateEventsContainingSignatures(
@NonNull final Randotron random,
final long roundNumber,
@NonNull final RoundHashValidatorTests.HashGenerationData hashGenerationData) {
@NonNull final RoundHashValidatorTests.HashGenerationData hashGenerationData,
final boolean useNewTransactionFormat) {

return hashGenerationData.nodeList().stream()
.map(nodeHashInfo -> {
Expand All @@ -94,14 +99,22 @@ private static List<EventImpl> generateEventsContainingSignatures(

final TestingEventBuilder event = new TestingEventBuilder(random)
.setCreatorId(nodeHashInfo.nodeId())
.setTransactionBytes(List.of(encodeSystemTransaction(signatureTransaction)))
.setSoftwareVersion(SemanticVersion.DEFAULT);

if (useNewTransactionFormat) {
event.setUseNewTransactionFormat(true)
.setTransactionBytes(List.of(encodeSystemTransaction(signatureTransaction)));
} else {
event.setTransactions(List.of(new EventTransaction(
new OneOf<>(TransactionOneOfType.STATE_SIGNATURE_TRANSACTION, signatureTransaction))));
}

return EventImplTestUtils.createEventImpl(event, null, null);
})
.toList();
}

@NonNull
private static Bytes encodeSystemTransaction(@NonNull StateSignatureTransaction stateSignatureTransaction) {
final var transactionBody = TransactionBody.newBuilder().stateSignatureTransaction(stateSignatureTransaction);

Expand Down Expand Up @@ -129,7 +142,8 @@ private static List<EventImpl> generateEventsWithConsistentSignatures(
@NonNull final Randotron random,
@NonNull final Roster roster,
final long roundNumber,
@NonNull final Hash roundHash) {
@NonNull final Hash roundHash,
final boolean useNewTransactionFormat) {
final List<RoundHashValidatorTests.NodeHashInfo> nodeHashInfos = new ArrayList<>();

roster.rosterEntries()
Expand All @@ -138,7 +152,10 @@ private static List<EventImpl> generateEventsWithConsistentSignatures(

// create signature transactions for this round
return generateEventsContainingSignatures(
random, roundNumber, new RoundHashValidatorTests.HashGenerationData(nodeHashInfos, roundHash));
random,
roundNumber,
new RoundHashValidatorTests.HashGenerationData(nodeHashInfos, roundHash),
useNewTransactionFormat);
}

/**
Expand Down Expand Up @@ -181,9 +198,10 @@ private static ConsensusRound createRoundWithSignatureEvents(
return consensusRound;
}

@Test
@ParameterizedTest
@ValueSource(booleans = {true, false})
@DisplayName("No ISSes Test")
void noIss() {
void noIss(final boolean useNewTransactionFormat) {
final Randotron random = Randotron.create();
final Roster roster = RandomRosterBuilder.create(random)
.withSize(100)
Expand All @@ -209,7 +227,8 @@ void noIss() {
final Hash roundHash = randomHash(random);

// create signature transactions for this round
signatureEvents.addAll(generateEventsWithConsistentSignatures(random, roster, currentRound, roundHash));
signatureEvents.addAll(generateEventsWithConsistentSignatures(
random, roster, currentRound, roundHash, useNewTransactionFormat));

// randomly select half of unsubmitted signature events to include in this round
final List<EventImpl> eventsToInclude = selectRandomEvents(random, signatureEvents);
Expand Down Expand Up @@ -245,9 +264,10 @@ void noIss() {
* This test goes through a series of rounds, some of which experience ISSes. The test verifies that the expected
* number of ISSes are registered by the ISS detector.
*/
@Test
@ParameterizedTest
@ValueSource(booleans = {true, false})
@DisplayName("Mixed Order Test")
void mixedOrderTest() {
void mixedOrderTest(final boolean useNewTransactionFormat) {
final Randotron random = Randotron.create();

final Roster roster = RandomRosterBuilder.create(random)
Expand Down Expand Up @@ -326,13 +346,13 @@ void mixedOrderTest() {

// signature events are generated for each round when that round is handled, and then are included randomly
// in subsequent rounds
final List<EventImpl> signatureEvents =
new ArrayList<>(generateEventsContainingSignatures(random, 0, roundData.getFirst()));
final List<EventImpl> signatureEvents = new ArrayList<>(
generateEventsContainingSignatures(random, 0, roundData.getFirst(), useNewTransactionFormat));

for (currentRound++; currentRound < roundsNonAncient; currentRound++) {
// create signature transactions for this round
signatureEvents.addAll(
generateEventsContainingSignatures(random, currentRound, roundData.get((int) currentRound)));
signatureEvents.addAll(generateEventsContainingSignatures(
random, currentRound, roundData.get((int) currentRound), useNewTransactionFormat));

// randomly select half of unsubmitted signature events to include in this round
final List<EventImpl> eventsToInclude = selectRandomEvents(random, signatureEvents);
Expand Down Expand Up @@ -393,9 +413,10 @@ void mixedOrderTest() {
* Handles additional rounds after an ISS occurred, but before all signatures have been submitted. Validates that
* the ISS is detected after enough signatures are submitted, and not before.
*/
@Test
@ParameterizedTest
@ValueSource(booleans = {true, false})
@DisplayName("Decide hash for catastrophic ISS")
void decideForCatastrophicIss() {
void decideForCatastrophicIss(final boolean useNewTransactionFormat) {
final Randotron random = Randotron.create();
final PlatformContext platformContext = createDefaultPlatformContext();

Expand Down Expand Up @@ -425,7 +446,7 @@ void decideForCatastrophicIss() {
.map(RoundHashValidatorTests.NodeHashInfo::nodeStateHash)
.orElseThrow();
final List<EventImpl> signaturesOnCatastrophicRound =
generateEventsContainingSignatures(random, currentRound, catastrophicHashData);
generateEventsContainingSignatures(random, currentRound, catastrophicHashData, useNewTransactionFormat);

// handle the catastrophic round, but don't submit any signatures yet, so it won't be detected
final var catastrophicRound = createRoundWithSignatureEvents(currentRound, List.of());
Expand Down Expand Up @@ -525,9 +546,10 @@ private static List<RoundHashValidatorTests.NodeHashInfo> generateCatastrophicTi
* enough signatures to "decide", there will be enough signatures to declare a catastrophic ISS when shifting the
* window past the ISS round.
*/
@Test
@ParameterizedTest
@ValueSource(booleans = {true, false})
@DisplayName("Catastrophic Shift Before Complete Test")
void catastrophicShiftBeforeCompleteTest() {
void catastrophicShiftBeforeCompleteTest(final boolean useNewTransactionFormat) {
final Randotron random = Randotron.create();
final PlatformContext platformContext = createDefaultPlatformContext();

Expand Down Expand Up @@ -556,7 +578,10 @@ void catastrophicShiftBeforeCompleteTest() {
.map(RoundHashValidatorTests.NodeHashInfo::nodeStateHash)
.orElseThrow();
final List<EventImpl> signaturesOnCatastrophicRound = generateEventsContainingSignatures(
random, currentRound, new RoundHashValidatorTests.HashGenerationData(catastrophicData, null));
random,
currentRound,
new RoundHashValidatorTests.HashGenerationData(catastrophicData, null),
useNewTransactionFormat);

final Map<Long, RosterEntry> nodesById = RosterUtils.toMap(roster);
long submittedWeight = 0;
Expand Down Expand Up @@ -623,9 +648,10 @@ void catastrophicShiftBeforeCompleteTest() {
* Causes a catastrophic ISS, but shifts the window by a large amount past the ISS round. This causes the
* catastrophic ISS to not be registered.
*/
@Test
@ParameterizedTest
@ValueSource(booleans = {true, false})
@DisplayName("Big Shift Test")
void bigShiftTest() {
void bigShiftTest(final boolean useNewTransactionFormat) {
final Randotron random = Randotron.create();

final PlatformContext platformContext = createDefaultPlatformContext();
Expand Down Expand Up @@ -659,7 +685,10 @@ void bigShiftTest() {
.map(RoundHashValidatorTests.NodeHashInfo::nodeStateHash)
.orElseThrow();
final List<EventImpl> signaturesOnCatastrophicRound = generateEventsContainingSignatures(
random, currentRound, new RoundHashValidatorTests.HashGenerationData(catastrophicData, null));
random,
currentRound,
new RoundHashValidatorTests.HashGenerationData(catastrophicData, null),
useNewTransactionFormat);

// handle the catastrophic round, but don't submit any signatures yet, so it won't be detected
final var catastrophicRound = createRoundWithSignatureEvents(currentRound, List.of());
Expand Down Expand Up @@ -713,9 +742,10 @@ void bigShiftTest() {
/**
* Causes a catastrophic ISS, but specifies that round to be ignored. This should cause the ISS to not be detected.
*/
@Test
@ParameterizedTest
@ValueSource(booleans = {true, false})
@DisplayName("Ignored Round Test")
void ignoredRoundTest() {
void ignoredRoundTest(final boolean useNewTransactionFormat) {
final Randotron random = Randotron.create();

final Roster roster = RandomRosterBuilder.create(random)
Expand All @@ -742,7 +772,10 @@ void ignoredRoundTest() {
final List<RoundHashValidatorTests.NodeHashInfo> catastrophicData =
generateCatastrophicTimeoutIss(random, roster, currentRound);
final List<EventImpl> signaturesOnCatastrophicRound = generateEventsContainingSignatures(
random, currentRound, new RoundHashValidatorTests.HashGenerationData(catastrophicData, null));
random,
currentRound,
new RoundHashValidatorTests.HashGenerationData(catastrophicData, null),
useNewTransactionFormat);

// handle the round and all signatures.
// The round has a catastrophic ISS, but should be ignored
Expand Down

0 comments on commit 50733eb

Please sign in to comment.