Skip to content

Commit

Permalink
refactor: adapt StatsSigningTestingTool to work with Bytes wrapper fo…
Browse files Browse the repository at this point in the history
…r transactions (#17144)

Signed-off-by: Mustafa Uzun <[email protected]>
Signed-off-by: Ivan Kavaldzhiev <[email protected]>
Co-authored-by: Mustafa Uzun <[email protected]>
Co-authored-by: Roger Barker <[email protected]>
  • Loading branch information
3 people authored Jan 15, 2025
1 parent 307b469 commit 84fb83b
Show file tree
Hide file tree
Showing 6 changed files with 441 additions and 19 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,30 @@
// SPDX-License-Identifier: Apache-2.0
/*
* Copyright (C) 2024-2025 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.
*/

plugins { id("org.hiero.gradle.module.application") }

// Remove the following line to enable all 'javac' lint checks that we have turned on by default
// and then fix the reported issues.
tasks.withType<JavaCompile>().configureEach { options.compilerArgs.add("-Xlint:-cast") }

application.mainClass = "com.swirlds.demo.stats.signing.StatsSigningTestingToolMain"

testModuleInfo {
requires("org.assertj.core")
requires("org.junit.jupiter.api")
requires("org.mockito")
requires("org.junit.jupiter.params")
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
import static com.swirlds.platform.test.fixtures.state.FakeStateLifecycles.FAKE_MERKLE_STATE_LIFECYCLES;
import static com.swirlds.platform.test.fixtures.state.FakeStateLifecycles.registerMerkleStateRootClassIds;

import com.hedera.hapi.platform.event.StateSignatureTransaction;
import com.hedera.pbj.runtime.io.buffer.Bytes;
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;
Expand All @@ -52,6 +55,8 @@
import com.swirlds.platform.system.Platform;
import com.swirlds.platform.system.SwirldMain;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

Expand All @@ -63,12 +68,13 @@
public class StatsSigningTestingToolMain implements SwirldMain<StatsSigningTestingToolState> {
// the first four come from the parameters in the config.txt file

public static final byte SYSTEM_TRANSACTION_MARKER = 0;
private static final Logger logger = LogManager.getLogger(StatsSigningTestingToolMain.class);

static {
try {
logger.info(STARTUP.getMarker(), "Registering StatsSigningTestingToolState with ConstructableRegistry");
ConstructableRegistry constructableRegistry = ConstructableRegistry.getInstance();
final ConstructableRegistry constructableRegistry = ConstructableRegistry.getInstance();
constructableRegistry.registerConstructable(
new ClassConstructorPair(StatsSigningTestingToolState.class, () -> {
StatsSigningTestingToolState statsSigningTestingToolState =
Expand All @@ -77,7 +83,7 @@ public class StatsSigningTestingToolMain implements SwirldMain<StatsSigningTesti
}));
registerMerkleStateRootClassIds();
logger.info(STARTUP.getMarker(), "StatsSigningTestingToolState is registered with ConstructableRegistry");
} catch (ConstructableRegistryException e) {
} catch (final ConstructableRegistryException e) {
logger.error(STARTUP.getMarker(), "Failed to register StatsSigningTestingToolState", e);
throw new RuntimeException(e);
}
Expand Down Expand Up @@ -255,7 +261,7 @@ private synchronized void generateTransactions() {

if (transPerSecToCreate > -1) { // if not unlimited (-1 means unlimited)
// ramp up the TPS to the expected value
long elapsedTime = now / MILLISECONDS_TO_NANOSECONDS - rampUpStartTimeMilliSeconds;
final long elapsedTime = now / MILLISECONDS_TO_NANOSECONDS - rampUpStartTimeMilliSeconds;
double rampUpTPS = 0;
if (elapsedTime < TPS_RAMP_UP_WINDOW_MILLISECONDS) {
rampUpTPS = expectedTPS * elapsedTime / ((double) (TPS_RAMP_UP_WINDOW_MILLISECONDS));
Expand Down Expand Up @@ -314,4 +320,21 @@ public StateLifecycles<StatsSigningTestingToolState> newStateLifecycles() {
public BasicSoftwareVersion getSoftwareVersion() {
return softwareVersion;
}

@Override
@NonNull
public Bytes encodeSystemTransaction(@NonNull final StateSignatureTransaction transaction) {
final var bytes = new ByteArrayOutputStream();
final var out = new WritableStreamingData(bytes);

// Add a marker to indicate the start of a system transaction. This is used
// to later differentiate between application transactions and system transactions.
out.writeByte(SYSTEM_TRANSACTION_MARKER);
try {
StateSignatureTransaction.PROTOBUF.write(transaction, out);
return Bytes.wrap(bytes.toByteArray());
} catch (final IOException e) {
throw new IllegalStateException("Failed to encode a system transaction.", e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@
package com.swirlds.demo.stats.signing;

import static com.swirlds.common.utility.CommonUtils.hex;
import static com.swirlds.demo.stats.signing.StatsSigningTestingToolMain.SYSTEM_TRANSACTION_MARKER;
import static com.swirlds.logging.legacy.LogMarker.EXCEPTION;
import static com.swirlds.logging.legacy.LogMarker.TESTING_EXCEPTIONS_ACCEPTABLE_RECONNECT;

import com.hedera.hapi.platform.event.StateSignatureTransaction;
import com.hedera.pbj.runtime.ParseException;
import com.hedera.pbj.runtime.io.buffer.Bytes;
import com.swirlds.common.context.PlatformContext;
import com.swirlds.common.crypto.CryptographyHolder;
import com.swirlds.common.crypto.TransactionSignature;
Expand Down Expand Up @@ -77,12 +80,27 @@ public void onPreHandle(
@NonNull Event event,
@NonNull StatsSigningTestingToolState state,
@NonNull Consumer<ScopedSystemTransaction<StateSignatureTransaction>> stateSignatureTransactionCallback) {

final SttTransactionPool sttTransactionPool = transactionPoolSupplier.get();
if (sttTransactionPool != null) {
event.forEachTransaction(transaction -> {
// We are not interested in pre-handling any system transactions, as they are
// specific for the platform only.We also don't want to consume deprecated
// EventTransaction.STATE_SIGNATURE_TRANSACTION system transactions in the
// callback,since it's intended to be used only for the new form of encoded system
// transactions in Bytes.Thus, we can directly skip the current
// iteration, if it processes a deprecated system transaction with the
// EventTransaction.STATE_SIGNATURE_TRANSACTION type.
if (transaction.isSystem()) {
return;
}

// We should consume in the callback the new form of system transactions in Bytes
if (areTransactionBytesSystemOnes(transaction)) {
consumeSystemTransaction(transaction, event, stateSignatureTransactionCallback);
return;
}

final TransactionSignature transactionSignature =
sttTransactionPool.expandSignatures(transaction.getApplicationTransaction());
if (transactionSignature != null) {
Expand All @@ -99,13 +117,29 @@ public void onHandleConsensusRound(
@NonNull StatsSigningTestingToolState state,
@NonNull Consumer<ScopedSystemTransaction<StateSignatureTransaction>> stateSignatureTransactionCallback) {
state.throwIfImmutable();
round.forEachTransaction(v -> handleTransaction(v, state));

round.forEachEventTransaction((event, transaction) -> {
// We are not interested in handling any system transactions, as they are
// specific for the platform only.We also don't want to consume deprecated
// EventTransaction.STATE_SIGNATURE_TRANSACTION system transactions in the
// callback,since it's intended to be used only for the new form of encoded system
// transactions in Bytes.Thus, we can directly skip the current
// iteration, if it processes a deprecated system transaction with the
// EventTransaction.STATE_SIGNATURE_TRANSACTION type.
if (transaction.isSystem()) {
return;
}

// We should consume in the callback the new form of system transactions in Bytes
if (areTransactionBytesSystemOnes(transaction)) {
consumeSystemTransaction(transaction, event, stateSignatureTransactionCallback);
} else {
handleTransaction(transaction, state);
}
});
}

private void handleTransaction(final ConsensusTransaction trans, final StatsSigningTestingToolState state) {
if (trans.isSystem()) {
return;
}
final TransactionSignature s = trans.getMetadata();

if (s != null && validateSignature(s, trans) && s.getSignatureStatus() != VerificationStatus.VALID) {
Expand Down Expand Up @@ -133,6 +167,40 @@ private void handleTransaction(final ConsensusTransaction trans, final StatsSign
maybeDelay();
}

/**
* Checks if the transaction bytes are system ones.
*
* @param transaction the transaction to check
* @return true if the transaction bytes are system ones, false otherwise
*/
private boolean areTransactionBytesSystemOnes(@NonNull final Transaction transaction) {
final var transactionBytes = transaction.getApplicationTransaction();

if (transactionBytes.length() == 0) {
return false;
}

return transactionBytes.getByte(0) == SYSTEM_TRANSACTION_MARKER;
}

private void consumeSystemTransaction(
@NonNull final Transaction transaction,
@NonNull final Event event,
@NonNull
final Consumer<ScopedSystemTransaction<StateSignatureTransaction>>
stateSignatureTransactionCallback) {
try {
final Bytes transactionBytes = transaction.getApplicationTransaction();
final Bytes strippedSystemTransactionBytes = transactionBytes.slice(1, transactionBytes.length() - 1);
final StateSignatureTransaction stateSignatureTransaction =
StateSignatureTransaction.PROTOBUF.parse(strippedSystemTransactionBytes);
stateSignatureTransactionCallback.accept(new ScopedSystemTransaction<>(
event.getCreatorId(), event.getSoftwareVersion(), stateSignatureTransaction));
} catch (final ParseException e) {
logger.error("Failed to parse StateSignatureTransaction", e);
}
}

private void maybeDelay() {
if (SYNTHETIC_HANDLE_TIME) {
final long start = System.nanoTime();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2024 Hedera Hashgraph, LLC
* Copyright (C) 2022-2025 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.
Expand Down Expand Up @@ -165,7 +165,7 @@ private void init() {
final byte[] sig = exSig.getSignature();

transactions[i] = TransactionCodec.encode(alg, transactionId, sig, data);
} catch (SignatureException e) {
} catch (final SignatureException e) {
// If we are unable to sign the transaction then log the failure and create an unsigned transaction
logger.error(
EXCEPTION.getMarker(),
Expand Down Expand Up @@ -202,7 +202,7 @@ private void tryAcquirePrimitives() {
if (algorithm.isAvailable()) {
activeAlgorithms.put(algorithm.getId(), algorithm);
}
} catch (Exception ex) {
} catch (final Exception ex) {
logger.error(
EXCEPTION.getMarker(),
"Failed to Activate Signing Algorithm [ id = {}, class = {} ]",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2024 Hedera Hashgraph, LLC
* Copyright (C) 2022-2025 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.
Expand Down Expand Up @@ -30,14 +30,15 @@
* The core transaction encoder and decoder implementation. See below for the binary transaction format specification.
* <p>
* Transaction Structure:
* ------------------------------------------------------------------------------------------------------------
* | 8 bytes | 1 byte | 1 byte | 4 bytes | pklen bytes | 4 bytes | siglen bytes | 4 bytes | datalen bytes |
* |---------|--------|----------|-----------|-------------|---------|--------------|---------|---------------|
* | id | signed | sigAlgId | pklen | pk | siglen | sig | datalen | data |
* ------------------------------------------------------------------------------------------------------------
* ---------------------------------------------------------------------------------------------------------------------
* | 1 byte | 8 bytes | 1 byte | 1 byte | 4 bytes | pklen bytes | 4 bytes | siglen bytes | 4 bytes | datalen bytes |
* |--------|---------|--------|----------|-----------|-------------|---------|--------------|---------|---------------|
* | marker | id | signed | sigAlgId | pklen | pk | siglen | sig | datalen | data |
* ---------------------------------------------------------------------------------------------------------------------
*/
final class TransactionCodec {

public static final byte APPLICATION_TRANSACTION_MARKER = 1;
public static final byte NO_ALGORITHM_PRESENT = -1;

private static final int PREAMBLE_SIZE = Long.BYTES + (Byte.BYTES * 2);
Expand Down Expand Up @@ -78,11 +79,14 @@ public static int overheadSize(final SigningAlgorithm algorithm) {

public static byte[] encode(
final SigningAlgorithm algorithm, final long transactionId, final byte[] signature, final byte[] data) {
final ByteBuffer buffer = ByteBuffer.allocate(bufferSize(algorithm, (data != null) ? data.length : 0));
final ByteBuffer buffer = ByteBuffer.allocate(1 + bufferSize(algorithm, (data != null) ? data.length : 0));
final boolean signed =
algorithm != null && algorithm.isAvailable() && signature != null && signature.length > 0;

buffer.putLong(transactionId)
// Add a marker byte in the very beginning to indicate the start of an application transaction. This is used
// to later differentiate between application transactions and system transactions.
buffer.put(APPLICATION_TRANSACTION_MARKER)
.putLong(transactionId)
.put((signed) ? (byte) 1 : 0)
.put((signed) ? algorithm.getId() : NO_ALGORITHM_PRESENT)
.putInt((signed) ? algorithm.getPublicKeyLength() : 0);
Expand Down
Loading

0 comments on commit 84fb83b

Please sign in to comment.