TransactionBaseTemplate.java
/*
* @copyright defined in LICENSE.txt
*/
package hera.client.internal;
import static hera.api.model.BytesValue.of;
import static hera.util.TransportUtils.copyFrom;
import static org.slf4j.LoggerFactory.getLogger;
import static types.AergoRPCServiceGrpc.newFutureStub;
import hera.ContextProvider;
import hera.ContextProviderInjectable;
import hera.annotation.ApiAudience;
import hera.annotation.ApiStability;
import hera.api.function.Function1;
import hera.api.function.Function3;
import hera.api.model.AccountAddress;
import hera.api.model.Aer;
import hera.api.model.RawTransaction;
import hera.api.model.Transaction;
import hera.api.model.TxHash;
import hera.client.ChannelInjectable;
import hera.exception.InternalCommitException;
import hera.transport.ModelConverter;
import hera.transport.TransactionConverterFactory;
import hera.transport.TransactionInBlockConverterFactory;
import io.grpc.ManagedChannel;
import java.util.concurrent.Future;
import lombok.Getter;
import org.slf4j.Logger;
import types.AergoRPCServiceGrpc.AergoRPCServiceFutureStub;
import types.Blockchain;
import types.Rpc;
@ApiAudience.Private
@ApiStability.Unstable
public class TransactionBaseTemplate implements ChannelInjectable, ContextProviderInjectable {
protected final transient Logger logger = getLogger(getClass());
protected final ModelConverter<Transaction, Blockchain.Tx> transactionConverter =
new TransactionConverterFactory().create();
protected final ModelConverter<Transaction, Blockchain.TxInBlock> transactionInBlockConverter =
new TransactionInBlockConverterFactory().create();
@Getter
protected AergoRPCServiceFutureStub aergoService;
protected ContextProvider contextProvider;
@Override
public void setChannel(final ManagedChannel channel) {
this.aergoService = newFutureStub(channel);
}
@Override
public void setContextProvider(final ContextProvider contextProvider) {
this.contextProvider = contextProvider;
}
@Getter
private final Function1<TxHash, Future<Transaction>> transactionFunction =
new Function1<TxHash, Future<Transaction>>() {
@Override
public Future<Transaction> apply(final TxHash txHash) {
logger.debug("Get transaction with txHash: {}", txHash);
final Rpc.SingleBytes rpcTxHash = Rpc.SingleBytes.newBuilder()
.setValue(copyFrom(txHash.getBytesValue()))
.build();
logger.trace("AergoService getTX arg: {}", rpcTxHash);
final Future<Blockchain.Tx> rawFuture = aergoService.getTX(rpcTxHash);
final Future<Transaction> convertedFuture =
HerajFutures.transform(rawFuture, new Function1<Blockchain.Tx, Transaction>() {
@Override
public Transaction apply(final Blockchain.Tx rpcTx) {
return transactionConverter.convertToDomainModel(rpcTx);
}
});
return convertedFuture;
}
};
@Getter
private final Function1<TxHash, Future<Transaction>> transactionInBlockFunction =
new Function1<TxHash, Future<Transaction>>() {
@Override
public Future<Transaction> apply(final TxHash txHash) {
logger.debug("Get transaction with txHash: {}", txHash);
final Rpc.SingleBytes rpcTxHash = Rpc.SingleBytes.newBuilder()
.setValue(copyFrom(txHash.getBytesValue()))
.build();
logger.trace("AergoService getTX arg: {}", rpcTxHash);
final Future<Blockchain.TxInBlock> rawFuture =
aergoService.getBlockTX(rpcTxHash);
final Future<Transaction> convertedFuture =
HerajFutures.transform(rawFuture, new Function1<Blockchain.TxInBlock, Transaction>() {
@Override
public Transaction apply(final Blockchain.TxInBlock rpcTxInBlock) {
return transactionInBlockConverter.convertToDomainModel(rpcTxInBlock);
}
});
return convertedFuture;
}
};
@Getter
private final Function1<Transaction, Future<TxHash>> commitFunction =
new Function1<Transaction, Future<TxHash>>() {
@Override
public Future<TxHash> apply(final Transaction transaction) {
logger.debug("Commit transaction with signedTx: {}", transaction);
final Blockchain.Tx rpcTx = transactionConverter.convertToRpcModel(transaction);
final Blockchain.TxList rpcTxList =
Blockchain.TxList.newBuilder().addTxs(rpcTx).build();
logger.trace("AergoService commitTX arg: {}", rpcTxList);
final Future<Rpc.CommitResultList> rawFuture = aergoService.commitTX(rpcTxList);
final Future<TxHash> convertedFuture =
HerajFutures.transform(rawFuture, new Function1<Rpc.CommitResultList, TxHash>() {
@Override
public TxHash apply(final Rpc.CommitResultList rpcCommitResultList) {
final Rpc.CommitResult rpcCommitResult =
rpcCommitResultList.getResultsList().get(0);
if (Rpc.CommitStatus.TX_OK != rpcCommitResult.getError()) {
throw new InternalCommitException(rpcCommitResult.getError(),
rpcCommitResult.getDetail());
}
return new TxHash(of(rpcCommitResult.getHash().toByteArray()));
}
});
return convertedFuture;
}
};
@Getter
private final Function3<AccountAddress, AccountAddress, Aer,
Future<TxHash>> sendFunction = new Function3<
AccountAddress, AccountAddress, Aer, Future<TxHash>>() {
@Override
public Future<TxHash> apply(final AccountAddress sender,
final AccountAddress recipient, final Aer amount) {
logger.debug("Send transaction request with sender: {}, recipient: {}, amount", sender,
recipient, amount);
final RawTransaction rawTransaction = RawTransaction.newBuilder()
.chainIdHash(contextProvider.get().getChainIdHash())
.from(sender)
.to(recipient)
.amount(amount)
.nonce(0L)
.build();
final Transaction transaction = Transaction.newBuilder()
.rawTransaction(rawTransaction)
.build();
final Blockchain.Tx rpcTx = transactionConverter.convertToRpcModel(transaction);
logger.trace("AergoService sendTX arg: {}", rpcTx);
final Future<Rpc.CommitResult> rawFuture = aergoService.sendTX(rpcTx);
final Future<TxHash> convertedFuture =
HerajFutures.transform(rawFuture, new Function1<Rpc.CommitResult, TxHash>() {
@Override
public TxHash apply(final Rpc.CommitResult rpcCommitResult) {
if (Rpc.CommitStatus.TX_OK != rpcCommitResult.getError()) {
throw new InternalCommitException(rpcCommitResult.getError(),
rpcCommitResult.getDetail());
}
return new TxHash(of(rpcCommitResult.getHash().toByteArray()));
}
});
return convertedFuture;
}
};
}