Skip to content

Commit

Permalink
feat: Add explicit TokenType to SingleTransactionRecord. (#10827)
Browse files Browse the repository at this point in the history
Signed-off-by: Joseph Sinclair <[email protected]>
  • Loading branch information
jsync-swirlds authored Jan 12, 2024
1 parent 30ab9fb commit 3df5a2a
Show file tree
Hide file tree
Showing 26 changed files with 165 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@

import static java.util.Objects.requireNonNull;

import com.hedera.hapi.node.base.TokenType;
import com.hedera.hapi.node.base.Transaction;
import com.hedera.hapi.node.transaction.TransactionRecord;
import com.hedera.hapi.streams.TransactionSidecarRecord;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.util.List;

/**
Expand All @@ -30,10 +32,15 @@
public record SingleTransactionRecord(
@NonNull Transaction transaction,
@NonNull TransactionRecord transactionRecord,
@NonNull List<TransactionSidecarRecord> transactionSidecarRecords) {
@NonNull List<TransactionSidecarRecord> transactionSidecarRecords,
@NonNull TransactionOutputs transactionOutputs) {
public SingleTransactionRecord {
requireNonNull(transaction, "transaction must not be null");
requireNonNull(transactionRecord, "record must not be null");
requireNonNull(transactionSidecarRecords, "transactionSidecarRecords must not be null");
requireNonNull(transactionOutputs, "transactionOutputs must not be null");
}

// This is used by BlockStream, and is not serialized.
public record TransactionOutputs(@Nullable TokenType tokenType) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.hedera.hapi.node.base.TokenAssociation;
import com.hedera.hapi.node.base.TokenID;
import com.hedera.hapi.node.base.TokenTransferList;
import com.hedera.hapi.node.base.TokenType;
import com.hedera.hapi.node.base.TopicID;
import com.hedera.hapi.node.base.Transaction;
import com.hedera.hapi.node.base.TransactionID;
Expand Down Expand Up @@ -73,6 +74,7 @@
import com.hedera.node.app.spi.workflows.record.ExternalizedRecordCustomizer;
import com.hedera.node.app.spi.workflows.record.SingleTransactionRecordBuilder;
import com.hedera.node.app.state.SingleTransactionRecord;
import com.hedera.node.app.state.SingleTransactionRecord.TransactionOutputs;
import com.hedera.pbj.runtime.OneOf;
import com.hedera.pbj.runtime.io.buffer.Bytes;
import com.swirlds.common.crypto.DigestType;
Expand Down Expand Up @@ -177,6 +179,7 @@ public class SingleTransactionRecordBuilderImpl
private final ExternalizedRecordCustomizer customizer;

private TokenID tokenID;
private TokenType tokenType;

/**
* Possible behavior of a {@link SingleTransactionRecord} when a parent transaction fails,
Expand Down Expand Up @@ -309,7 +312,8 @@ public SingleTransactionRecord build() {
// Log end of user transaction to transaction state log
logEndTransactionRecord(transactionID, transactionRecord);

return new SingleTransactionRecord(transaction, transactionRecord, transactionSidecarRecords);
return new SingleTransactionRecord(
transaction, transactionRecord, transactionSidecarRecords, new TransactionOutputs(tokenType));
}

public void nullOutSideEffectFields() {
Expand Down Expand Up @@ -562,6 +566,13 @@ public SingleTransactionRecordBuilderImpl addTokenTransferList(@NonNull final To
return this;
}

@Override
@NonNull
public SingleTransactionRecordBuilderImpl tokenType(final @NonNull TokenType tokenType) {
this.tokenType = requireNonNull(tokenType);
return this;
}

/**
* Sets the scheduleRef.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import com.hedera.hapi.node.base.AccountID;
import com.hedera.hapi.node.base.ResponseCodeEnum;
import com.hedera.hapi.node.base.Timestamp;
import com.hedera.hapi.node.base.TokenType;
import com.hedera.hapi.node.base.TransactionID;
import com.hedera.hapi.node.state.recordcache.TransactionRecordEntry;
import com.hedera.hapi.node.transaction.TransactionReceipt;
Expand All @@ -46,6 +47,7 @@
import com.hedera.node.app.spi.state.WritableQueueState;
import com.hedera.node.app.state.DeduplicationCache;
import com.hedera.node.app.state.SingleTransactionRecord;
import com.hedera.node.app.state.SingleTransactionRecord.TransactionOutputs;
import com.hedera.node.app.state.WorkingStateAccessor;
import com.hedera.node.config.ConfigProvider;
import com.hedera.node.config.VersionedConfiguration;
Expand Down Expand Up @@ -78,6 +80,7 @@ final class RecordCacheImplTest extends AppTestBase {
TransactionReceipt.newBuilder().status(UNKNOWN).build();
private static final AccountID PAYER_ACCOUNT_ID =
AccountID.newBuilder().accountNum(1001).build();
private static final TransactionOutputs SIMPLE_OUTPUT = new TransactionOutputs(TokenType.FUNGIBLE_COMMON);

private DeduplicationCache dedupeCache;

Expand Down Expand Up @@ -438,7 +441,7 @@ final var record = TransactionRecord.newBuilder()
.build();

// When the record is added to the cache
cache.add(0, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of())));
cache.add(0, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of(), SIMPLE_OUTPUT)));

// Then we can query for the receipt by transaction ID
assertThat(getReceipt(cache, txId)).isEqualTo(receipt);
Expand All @@ -459,7 +462,7 @@ final var record = TransactionRecord.newBuilder()
.build();

// When the record is added to the cache
cache.add(0, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of())));
cache.add(0, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of(), SIMPLE_OUTPUT)));

// Then we can query for the receipt by transaction ID
assertThat(getReceipts(cache, txId)).containsExactly(receipt);
Expand All @@ -480,7 +483,7 @@ final var record = TransactionRecord.newBuilder()
.build();

// When the record is added to the cache
cache.add(0, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of())));
cache.add(0, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of(), SIMPLE_OUTPUT)));

// Then we can query for the receipt by transaction ID
assertThat(getReceipts(cache, PAYER_ACCOUNT_ID)).containsExactly(receipt);
Expand All @@ -507,7 +510,10 @@ final var record = TransactionRecord.newBuilder()
.transactionID(txId)
.receipt(receipt)
.build();
cache.add(0, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of())));
cache.add(
0,
PAYER_ACCOUNT_ID,
List.of(new SingleTransactionRecord(tx, record, List.of(), SIMPLE_OUTPUT)));
}
}

Expand Down Expand Up @@ -599,7 +605,7 @@ final var record = TransactionRecord.newBuilder()
.build();

// When the record is added to the cache
cache.add(0, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of())));
cache.add(0, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of(), SIMPLE_OUTPUT)));

// Then we can query for the receipt by transaction ID
assertThat(getRecord(cache, txId)).isEqualTo(record);
Expand All @@ -620,7 +626,7 @@ final var record = TransactionRecord.newBuilder()
.build();

// When the record is added to the cache
cache.add(0, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of())));
cache.add(0, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of(), SIMPLE_OUTPUT)));

// Then we can query for the receipt by transaction ID
assertThat(getRecords(cache, txId)).containsExactly(record);
Expand All @@ -646,10 +652,16 @@ void unclassifiableStatusIsNotPriority() {
.build();

// When the unclassifiable record is added to the cache
cache.add(0, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, unclassifiableRecord, List.of())));
cache.add(
0,
PAYER_ACCOUNT_ID,
List.of(new SingleTransactionRecord(tx, unclassifiableRecord, List.of(), SIMPLE_OUTPUT)));
// It does not prevent a "good" record from using this transaction id
assertThat(cache.hasDuplicate(txId, 0L)).isEqualTo(NO_DUPLICATE);
cache.add(0, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, classifiableRecord, List.of())));
cache.add(
0,
PAYER_ACCOUNT_ID,
List.of(new SingleTransactionRecord(tx, classifiableRecord, List.of(), SIMPLE_OUTPUT)));

// And we get the success record from userTransactionRecord()
assertThat(cache.getHistory(txId)).isNotNull();
Expand All @@ -673,7 +685,7 @@ final var record = TransactionRecord.newBuilder()
.build();

// When the record is added to the cache
cache.add(0, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of())));
cache.add(0, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of(), SIMPLE_OUTPUT)));

// Then we can query for the receipt by transaction ID
assertThat(cache.getRecords(PAYER_ACCOUNT_ID)).containsExactly(record);
Expand Down Expand Up @@ -731,7 +743,7 @@ final var record = TransactionRecord.newBuilder()
.build();

// When the record is added to the cache
cache.add(1L, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of())));
cache.add(1L, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of(), SIMPLE_OUTPUT)));

// Then we can check for a duplicate by transaction ID
assertThat(cache.hasDuplicate(txId, 2L)).isEqualTo(OTHER_NODE);
Expand All @@ -751,7 +763,7 @@ final var record = TransactionRecord.newBuilder()
.build();

// When the record is added to the cache
cache.add(1L, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of())));
cache.add(1L, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of(), SIMPLE_OUTPUT)));

// Then we can check for a duplicate by transaction ID
assertThat(cache.hasDuplicate(txId, 1L)).isEqualTo(SAME_NODE);
Expand All @@ -771,9 +783,9 @@ final var record = TransactionRecord.newBuilder()
.build();

// When the record is added to the cache
cache.add(1L, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of())));
cache.add(2L, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of())));
cache.add(3L, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of())));
cache.add(1L, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of(), SIMPLE_OUTPUT)));
cache.add(2L, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of(), SIMPLE_OUTPUT)));
cache.add(3L, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of(), SIMPLE_OUTPUT)));

// Then we can check for a duplicate by transaction ID
assertThat(cache.hasDuplicate(txId, 11L)).isEqualTo(OTHER_NODE);
Expand All @@ -794,9 +806,9 @@ final var record = TransactionRecord.newBuilder()
.build();

// When the record is added to the cache
cache.add(1L, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of())));
cache.add(2L, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of())));
cache.add(3L, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of())));
cache.add(1L, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of(), SIMPLE_OUTPUT)));
cache.add(2L, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of(), SIMPLE_OUTPUT)));
cache.add(3L, PAYER_ACCOUNT_ID, List.of(new SingleTransactionRecord(tx, record, List.of(), SIMPLE_OUTPUT)));

// Then we can check for a duplicate by transaction ID
assertThat(cache.hasDuplicate(txId, currentNodeId)).isEqualTo(SAME_NODE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import com.hedera.hapi.node.base.SemanticVersion;
import com.hedera.hapi.node.base.Timestamp;
import com.hedera.hapi.node.base.TokenType;
import com.hedera.hapi.node.base.Transaction;
import com.hedera.hapi.node.transaction.SignedTransaction;
import com.hedera.hapi.node.transaction.TransactionBody;
Expand All @@ -31,6 +32,7 @@
import com.hedera.hapi.streams.TransactionSidecarRecord;
import com.hedera.node.app.records.impl.producers.formats.v6.BlockRecordFormatV6;
import com.hedera.node.app.state.SingleTransactionRecord;
import com.hedera.node.app.state.SingleTransactionRecord.TransactionOutputs;
import com.hedera.pbj.runtime.io.buffer.BufferedData;
import com.hedera.pbj.runtime.io.buffer.Bytes;
import com.hedera.pbj.runtime.io.stream.ReadableStreamingData;
Expand Down Expand Up @@ -81,6 +83,8 @@ public class RecordTestData {
new boolean[] {false, true, true, true, false, true, false, false, true};
// block seconds 24, 26, 28, 30, 32, 34, 36, 38, 40

/** Transaction Outputs data */
private static final TransactionOutputs SIMPLE_OUTPUT = new TransactionOutputs(TokenType.FUNGIBLE_COMMON);
/** Test Signer for signing record stream files */
public static final Signer SIGNER;
/** Test user public key */
Expand All @@ -104,8 +108,8 @@ public class RecordTestData {
final RecordStreamFile recordStreamFile =
RecordStreamFile.JSON.parse(new ReadableStreamingData(Files.newInputStream(jsonPath)));
final List<SingleTransactionRecord> realRecordStreamItems = recordStreamFile.recordStreamItems().stream()
.map(item ->
new SingleTransactionRecord(item.transaction(), item.record(), Collections.emptyList()))
.map(item -> new SingleTransactionRecord(
item.transaction(), item.record(), Collections.emptyList(), SIMPLE_OUTPUT))
.toList();
// load real sidecar items from a JSON resource file
final Path sidecarPath = Path.of(RecordTestData.class
Expand Down Expand Up @@ -240,6 +244,6 @@ private static SingleTransactionRecord changeTransactionConsensusTimeAndGenerate
}
}
// return new SingleTransactionRecord
return new SingleTransactionRecord(newTransaction, newTransactionRecord, sidecarItems);
return new SingleTransactionRecord(newTransaction, newTransactionRecord, sidecarItems, SIMPLE_OUTPUT);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import com.hedera.node.app.spi.state.ReadableStates;
import com.hedera.node.app.state.DeduplicationCache;
import com.hedera.node.app.state.SingleTransactionRecord;
import com.hedera.node.app.state.SingleTransactionRecord.TransactionOutputs;
import com.hedera.node.app.state.WorkingStateAccessor;
import com.hedera.node.app.state.recordcache.DeduplicationCacheImpl;
import com.hedera.node.app.state.recordcache.RecordCacheImpl;
Expand Down Expand Up @@ -289,7 +290,8 @@ private void givenRecordCacheState() {
}

private SingleTransactionRecord singleTransactionRecord(TransactionRecord record) {
return new SingleTransactionRecord(Transaction.DEFAULT, record, List.of());
return new SingleTransactionRecord(
Transaction.DEFAULT, record, List.of(), new TransactionOutputs(TokenType.FUNGIBLE_COMMON));
}

protected MapReadableKVState<AccountID, Account> readableAccountState() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ public void handle(@NonNull final HandleContext context) throws HandleException
final var record = context.recordBuilder(TokenAccountWipeRecordBuilder.class);
// Set newTotalSupply in record
record.newTotalSupply(newTotalSupply);
record.tokenType(token.tokenType());
}

@NonNull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ public void handle(@NonNull final HandleContext context) throws HandleException
validateTrue(treasuryRel.kycGranted(), ACCOUNT_KYC_NOT_GRANTED_FOR_TOKEN);
}

TokenBurnRecordBuilder record = context.recordBuilder(TokenBurnRecordBuilder.class);
if (token.tokenType() == TokenType.FUNGIBLE_COMMON) {
validateTrue(fungibleBurnCount >= 0 && nftSerialNums.isEmpty(), INVALID_TOKEN_BURN_AMOUNT);
final var newTotalSupply = changeSupply(
Expand All @@ -131,7 +132,7 @@ public void handle(@NonNull final HandleContext context) throws HandleException
accountStore,
tokenStore,
tokenRelStore);
context.recordBuilder(TokenBurnRecordBuilder.class).newTotalSupply(newTotalSupply);
record.newTotalSupply(newTotalSupply);
} else {
validateTrue(!nftSerialNums.isEmpty(), INVALID_TOKEN_BURN_METADATA);

Expand All @@ -158,8 +159,9 @@ public void handle(@NonNull final HandleContext context) throws HandleException

// Remove the nft objects
nftSerialNums.forEach(serialNum -> nftStore.remove(tokenId, serialNum));
context.recordBuilder(TokenBurnRecordBuilder.class).newTotalSupply(newTotalSupply);
record.newTotalSupply(newTotalSupply);
}
record.tokenType(token.tokenType());
}

@NonNull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ public void handle(@NonNull final HandleContext context) {

// Update record with newly created token id
recordBuilder.tokenID(newTokenId);
recordBuilder.tokenType(newToken.tokenType());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import com.hedera.node.app.service.token.impl.WritableAccountStore;
import com.hedera.node.app.service.token.impl.WritableTokenStore;
import com.hedera.node.app.service.token.impl.util.TokenHandlerHelper;
import com.hedera.node.app.service.token.records.TokenBaseRecordBuilder;
import com.hedera.node.app.spi.fees.FeeContext;
import com.hedera.node.app.spi.fees.Fees;
import com.hedera.node.app.spi.workflows.HandleContext;
Expand Down Expand Up @@ -94,6 +95,9 @@ public void handle(@NonNull final HandleContext context) throws HandleException
.numberTreasuryTitles(account.numberTreasuryTitles() - 1)
.build();
accountStore.put(updatedAccount);

final var record = context.recordBuilder(TokenBaseRecordBuilder.class);
record.tokenType(updatedToken.tokenType());
}

@NonNull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import com.hedera.node.app.service.token.impl.WritableTokenStore;
import com.hedera.node.app.service.token.impl.util.TokenHandlerHelper;
import com.hedera.node.app.service.token.impl.validators.CustomFeesValidator;
import com.hedera.node.app.service.token.records.TokenBaseRecordBuilder;
import com.hedera.node.app.spi.fees.FeeContext;
import com.hedera.node.app.spi.fees.Fees;
import com.hedera.node.app.spi.workflows.HandleContext;
Expand Down Expand Up @@ -123,6 +124,9 @@ public void handle(@NonNull final HandleContext context) {
final var copy = token.copyBuilder().customFees(op.customFees());
// add token to the modifications map
tokenStore.put(copy.build());

final var record = context.recordBuilder(TokenBaseRecordBuilder.class);
record.tokenType(token.tokenType());
}

/**
Expand Down
Loading

0 comments on commit 3df5a2a

Please sign in to comment.