Skip to content

Commit

Permalink
feat: serialize API3 reports and send to the blockchain
Browse files Browse the repository at this point in the history
  • Loading branch information
Mateusz Czeladka committed Jan 15, 2025
1 parent a34074b commit 2917c9e
Show file tree
Hide file tree
Showing 13 changed files with 600 additions and 93 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.bloxbean.cardano.client.account.Account;
import com.bloxbean.cardano.client.backend.api.BackendService;
import org.cardanofoundation.lob.app.blockchain_common.service_assistance.MetadataChecker;
import org.cardanofoundation.lob.app.blockchain_publisher.service.L1TransactionCreator;
import org.cardanofoundation.lob.app.blockchain_publisher.service.API1L1TransactionCreator;
import org.cardanofoundation.lob.app.blockchain_publisher.service.API1MetadataSerialiser;
import org.cardanofoundation.lob.app.blockchain_publisher.service.transation_submit.*;
import org.cardanofoundation.lob.app.blockchain_reader.BlockchainReaderPublicApiIF;
Expand Down Expand Up @@ -38,15 +38,15 @@ public TransactionSubmissionService transactionSubmissionService(
}

@Bean
public L1TransactionCreator l1TransactionCreator(@Qualifier("yaci_blockfrost") BackendService backendService,
API1MetadataSerialiser API1MetadataSerialiser,
BlockchainReaderPublicApiIF blockchainReaderPublicApi,
MetadataChecker metadataChecker,
Account organiserAccount,
@Value("${l1.transaction.metadata_label:1447}") int metadataLabel,
@Value("${l1.transaction.debug_store_output_tx:false}") boolean debugStoreOutputTx
public API1L1TransactionCreator l1TransactionCreator(@Qualifier("yaci_blockfrost") BackendService backendService,
API1MetadataSerialiser API1MetadataSerialiser,
BlockchainReaderPublicApiIF blockchainReaderPublicApi,
MetadataChecker metadataChecker,
Account organiserAccount,
@Value("${l1.transaction.metadata_label:1447}") int metadataLabel,
@Value("${l1.transaction.debug_store_output_tx:false}") boolean debugStoreOutputTx
) {
return new L1TransactionCreator(backendService,
return new API1L1TransactionCreator(backendService,
API1MetadataSerialiser,
blockchainReaderPublicApi,
metadataChecker,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.cardanofoundation.lob.app.blockchain_publisher.domain.core;

import org.cardanofoundation.lob.app.blockchain_publisher.domain.entity.txs.TransactionEntity;

import java.util.Set;

public record API1BlockchainTransactions(String organisationId,
Set<TransactionEntity> submittedTransactions,
Set<TransactionEntity> remainingTransactions,
long creationSlot,
byte[] serialisedTxData) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.cardanofoundation.lob.app.blockchain_publisher.domain.core;

import org.cardanofoundation.lob.app.blockchain_publisher.domain.entity.reports.ReportEntity;

public record API3BlockchainTransaction(ReportEntity report,
long creationSlot,
byte[] serialisedTxData) {
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.cardanofoundation.lob.app.blockchain_publisher.domain.core;

public record SerializedCardanoL1Transaction(byte[] txBytes,
byte[] metadataCbor,
String metadataJson) { }
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
@Service("blockchain_publisher.TransactionDispatcherJob")
@Slf4j
@RequiredArgsConstructor
@ConditionalOnProperty(value = "lob.blockchain_publisher.dispatcher.enabled", havingValue = "true", matchIfMissing = true)
@ConditionalOnProperty(value = "lob.blockchain_publisher.dispatcher.txs.enabled", havingValue = "true", matchIfMissing = true)
public class TransactionDispatcherJob {

private final BlockchainTransactionsDispatcher blockchainTransactionsDispatcher;
Expand All @@ -22,8 +22,8 @@ public void init() {
}

@Scheduled(
fixedDelayString = "${lob.blockchain_publisher.dispatcher.fixed_delay:PT10S}",
initialDelayString = "${lob.blockchain_publisher.dispatcher.initial_delay:PT1M}")
fixedDelayString = "${lob.blockchain_publisher.dispatcher.txs.fixed_delay:PT10S}",
initialDelayString = "${lob.blockchain_publisher.dispatcher.txs.initial_delay:PT1M}")
public void execute() {
log.info("Pooling for blockchain transactions to be send to the blockchain...");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.cardanofoundation.lob.app.blockchain_common.service_assistance.MetadataChecker;
import org.cardanofoundation.lob.app.blockchain_publisher.domain.core.BlockchainTransactions;
import org.cardanofoundation.lob.app.blockchain_publisher.domain.core.API1BlockchainTransactions;
import org.cardanofoundation.lob.app.blockchain_publisher.domain.core.SerializedCardanoL1Transaction;
import org.cardanofoundation.lob.app.blockchain_publisher.domain.entity.txs.TransactionEntity;
import org.cardanofoundation.lob.app.blockchain_reader.BlockchainReaderPublicApiIF;
import org.springframework.stereotype.Service;
import org.zalando.problem.Problem;

import java.io.IOException;
Expand All @@ -39,9 +41,10 @@
import static org.apache.commons.collections4.iterators.PeekingIterator.peekingIterator;
import static org.zalando.problem.Status.INTERNAL_SERVER_ERROR;

@Service
@Slf4j
@RequiredArgsConstructor
public class L1TransactionCreator {
public class API1L1TransactionCreator {

private static final int CARDANO_MAX_TRANSACTION_SIZE_BYTES = 16384;

Expand All @@ -58,24 +61,24 @@ public class L1TransactionCreator {

@PostConstruct
public void init() {
log.info("L1TransactionCreator::metadata label: {}", metadataLabel);
log.info("L1TransactionCreator::debug store output tx: {}", debugStoreOutputTx);
log.info("API1L1TransactionCreator::metadata label: {}", metadataLabel);
log.info("API1L1TransactionCreator::debug store output tx: {}", debugStoreOutputTx);

runId = UUID.randomUUID().toString();
log.info("L1TransactionCreator::runId: {}", runId);
log.info("API1L1TransactionCreator::runId: {}", runId);

log.info("L1TransactionCreator is initialised.");
log.info("API1L1TransactionCreator is initialised.");
}

public Either<Problem, Optional<BlockchainTransactions>> pullBlockchainTransaction(String organisationId,
Set<TransactionEntity> txs) {
public Either<Problem, Optional<API1BlockchainTransactions>> pullBlockchainTransaction(String organisationId,
Set<TransactionEntity> txs) {
return blockchainReaderPublicApi.getChainTip()
.flatMap(chainTip -> handleTransactionCreation(organisationId, txs, chainTip.getAbsoluteSlot()));
}

private Either<Problem, Optional<BlockchainTransactions>> handleTransactionCreation(String organisationId,
Set<TransactionEntity> transactions,
long creationSlot) {
private Either<Problem, Optional<API1BlockchainTransactions>> handleTransactionCreation(String organisationId,
Set<TransactionEntity> transactions,
long creationSlot) {
try {
return createTransaction(organisationId, transactions, creationSlot);
} catch (IOException e) {
Expand All @@ -90,9 +93,9 @@ private Either<Problem, Optional<BlockchainTransactions>> handleTransactionCreat
}

// error or transactions to process or no more transactions to process in case of blockchain transaction creation
private Either<Problem, Optional<BlockchainTransactions>> createTransaction(String organisationId,
Set<TransactionEntity> transactions,
long creationSlot) throws IOException {
private Either<Problem, Optional<API1BlockchainTransactions>> createTransaction(String organisationId,
Set<TransactionEntity> transactions,
long creationSlot) throws IOException {
log.info("Splitting {} passedTransactions into blockchain passedTransactions", transactions.size());

val transactionsBatch = new LinkedHashSet<TransactionEntity>();
Expand All @@ -110,7 +113,7 @@ private Either<Problem, Optional<BlockchainTransactions>> createTransaction(Stri
}

val serializedTransaction = serializedTransactionsE.get();
val txBytes = serializedTransaction.txBytes;
val txBytes = serializedTransaction.txBytes();

val transactionLinePeek = it.peek();
if (transactionLinePeek == null) { // next one is last element
Expand All @@ -125,7 +128,7 @@ private Either<Problem, Optional<BlockchainTransactions>> createTransaction(Stri
return Either.left(newChunkTxBytesE.getLeft());
}
val newSerializedTransaction = newChunkTxBytesE.get();
val newChunkTxBytes = newSerializedTransaction.txBytes;
val newChunkTxBytes = newSerializedTransaction.txBytes();

if (newChunkTxBytes.length >= CARDANO_MAX_TRANSACTION_SIZE_BYTES) {
log.info("Blockchain transaction created, id:{}", TransactionUtil.getTxHash(txBytes));
Expand All @@ -135,7 +138,7 @@ private Either<Problem, Optional<BlockchainTransactions>> createTransaction(Stri

val remainingTxs = calculateRemainingTransactions(transactions, transactionsBatch);

return Either.right(Optional.of(new BlockchainTransactions(organisationId, transactionsBatch, remainingTxs, creationSlot, txBytes)));
return Either.right(Optional.of(new API1BlockchainTransactions(organisationId, transactionsBatch, remainingTxs, creationSlot, txBytes)));
}
}

Expand All @@ -152,15 +155,16 @@ private Either<Problem, Optional<BlockchainTransactions>> createTransaction(Stri
}

val serTx = serializedTxE.get();
log.info("Blockchain transaction created, id:{}, debugTxOutput:{}", TransactionUtil.getTxHash(serTx.txBytes), this.debugStoreOutputTx);
val txBytes = serTx.txBytes();
log.info("Blockchain transaction created, id:{}, debugTxOutput:{}", TransactionUtil.getTxHash(txBytes), this.debugStoreOutputTx);

potentiallyStoreTxs(creationSlot, serTx);
val txBytes = serTx.txBytes;

log.info("Transaction size: {}", txBytes.length);

val remaining = calculateRemainingTransactions(transactions, transactionsBatch);

return Either.right(Optional.of(new BlockchainTransactions(organisationId, transactionsBatch, remaining, creationSlot, txBytes)));
return Either.right(Optional.of(new API1BlockchainTransactions(organisationId, transactionsBatch, remaining, creationSlot, txBytes)));
}

// no transactions to process
Expand All @@ -171,15 +175,15 @@ private Either<Problem, Optional<BlockchainTransactions>> createTransaction(Stri
private void potentiallyStoreTxs(long creationSlot, SerializedCardanoL1Transaction tx) throws IOException {
if (debugStoreOutputTx) {
val timestamp = DateTimeFormatter.ISO_INSTANT.format(Instant.now());
val name = STR."lob-txs-metadata-\{runId}-\{timestamp}-\{creationSlot}";
val name = STR."lob-txs-api1-metadata-\{runId}-\{timestamp}-\{creationSlot}";
val tmpJsonTxFile = Files.createTempFile(name, ".json");
val tmpCborFile = Files.createTempFile(name, ".cbor");

log.info("DebugStoreTx enabled, storing JSON tx metadata to file: {}", tmpJsonTxFile);
Files.writeString(tmpJsonTxFile, tx.metadataJson);
Files.writeString(tmpJsonTxFile, tx.metadataJson());

log.info("DebugStoreTx enabled, storing CBOR tx metadata to file: {}", tmpCborFile);
Files.write(tmpCborFile, tx.metadataCbor);
Files.write(tmpCborFile, tx.metadataCbor());
}
}

Expand Down Expand Up @@ -249,8 +253,4 @@ protected byte[] serialiseTransaction(Metadata metadata) throws CborSerializatio
.serialize();
}

public record SerializedCardanoL1Transaction(byte[] txBytes,
byte[] metadataCbor,
String metadataJson) { }

}
Loading

0 comments on commit 2917c9e

Please sign in to comment.