All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cc.youchain.tx.response.QueuingTransactionReceiptProcessor Maven / Gradle / Ivy

There is a newer version: 1.1.5
Show newest version
package cc.youchain.tx.response;

import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import cc.youchain.protocol.YOUChain;
import cc.youchain.protocol.core.methods.response.TransactionReceipt;
import cc.youchain.protocol.exceptions.TransactionException;
import cc.youchain.utils.Async;

/**
 * Transaction receipt processor that uses a single thread to query for transaction receipts.
 *
 * 

Note:When initially invoked, this processor returns a transaction receipt containing * only the transaction hash of the submitted transaction. This is encapsulated in an * {@link EmptyTransactionReceipt}. */ public class QueuingTransactionReceiptProcessor extends TransactionReceiptProcessor { private final int pollingAttemptsPerTxHash; private final ScheduledExecutorService scheduledExecutorService; private final Callback callback; private final BlockingQueue pendingTransactions; public QueuingTransactionReceiptProcessor( YOUChain youChain, Callback callback, int pollingAttemptsPerTxHash, long pollingFrequency) { super(youChain); this.scheduledExecutorService = Async.defaultExecutorService(); this.callback = callback; this.pendingTransactions = new LinkedBlockingQueue<>(); this.pollingAttemptsPerTxHash = pollingAttemptsPerTxHash; scheduledExecutorService.scheduleAtFixedRate( this::sendTransactionReceiptRequests, pollingFrequency, pollingFrequency, TimeUnit.MILLISECONDS); } @Override public TransactionReceipt waitForTransactionReceipt(String transactionHash) { pendingTransactions.add(new RequestWrapper(transactionHash)); return new EmptyTransactionReceipt(transactionHash); } private void sendTransactionReceiptRequests() { for (RequestWrapper requestWrapper : pendingTransactions) { try { String transactionHash = requestWrapper.getTransactionHash(); Optional transactionReceipt = sendTransactionReceiptRequest(transactionHash); if (transactionReceipt.isPresent()) { callback.accept(transactionReceipt.get()); pendingTransactions.remove(requestWrapper); } else { if (requestWrapper.getCount() == pollingAttemptsPerTxHash) { throw new TransactionException( "No transaction receipt for txHash: " + transactionHash + "received after " + pollingAttemptsPerTxHash + " attempts", transactionHash); } else { requestWrapper.incrementCount(); } } } catch (IOException | TransactionException e) { pendingTransactions.remove(requestWrapper); callback.exception(e); } } } /** * Java doesn't provide a concurrent linked hash set, so we use a simple wrapper to store * details of the number of requests we've made against this specific transaction hash. This * is so we can preserve submission order as we interate over the outstanding transactions. * *

Note - the equals/hashcode methods only operate on the transactionHash field. This is * intentional. */ private static class RequestWrapper { private final String transactionHash; private int count; RequestWrapper(String transactionHash) { this.transactionHash = transactionHash; this.count = 0; } String getTransactionHash() { return transactionHash; } int getCount() { return count; } void incrementCount() { this.count += 1; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } RequestWrapper that = (RequestWrapper) o; return transactionHash.equals(that.transactionHash); } @Override public int hashCode() { return transactionHash.hashCode(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy