use of org.hyperledger.fabric.sdk.transaction.TransactionBuilder in project fabric-sdk-java by hyperledger.
the class Channel method sendTransaction.
/**
* Send transaction to one of a specified set of orderers with the specified user context.
* IF there are no event hubs or eventing peers this future returns immediately completed
* indicating that orderer has accepted the transaction only.
*
* @param proposalResponses
* @param transactionOptions
* @return Future allowing access to the result of the transaction invocation.
*/
public CompletableFuture<TransactionEvent> sendTransaction(Collection<ProposalResponse> proposalResponses, TransactionOptions transactionOptions) {
try {
if (null == transactionOptions) {
throw new InvalidArgumentException("Parameter transactionOptions can't be null");
}
checkChannelState();
User userContext = transactionOptions.userContext != null ? transactionOptions.userContext : client.getUserContext();
userContextCheck(userContext);
if (null == proposalResponses) {
throw new InvalidArgumentException("sendTransaction proposalResponses was null");
}
List<Orderer> orderers = transactionOptions.orderers != null ? transactionOptions.orderers : new ArrayList<>(getOrderers());
// make certain we have our own copy
final List<Orderer> shuffeledOrderers = new ArrayList<>(orderers);
if (transactionOptions.shuffleOrders) {
Collections.shuffle(shuffeledOrderers);
}
if (config.getProposalConsistencyValidation()) {
HashSet<ProposalResponse> invalid = new HashSet<>();
int consistencyGroups = SDKUtils.getProposalConsistencySets(proposalResponses, invalid).size();
if (consistencyGroups != 1 || !invalid.isEmpty()) {
throw new IllegalArgumentException(format("The proposal responses have %d inconsistent groups with %d that are invalid." + " Expected all to be consistent and none to be invalid.", consistencyGroups, invalid.size()));
}
}
List<FabricProposalResponse.Endorsement> ed = new LinkedList<>();
FabricProposal.Proposal proposal = null;
ByteString proposalResponsePayload = null;
String proposalTransactionID = null;
for (ProposalResponse sdkProposalResponse : proposalResponses) {
ed.add(sdkProposalResponse.getProposalResponse().getEndorsement());
if (proposal == null) {
proposal = sdkProposalResponse.getProposal();
proposalTransactionID = sdkProposalResponse.getTransactionID();
proposalResponsePayload = sdkProposalResponse.getProposalResponse().getPayload();
}
}
TransactionBuilder transactionBuilder = TransactionBuilder.newBuilder();
Payload transactionPayload = transactionBuilder.chaincodeProposal(proposal).endorsements(ed).proposalResponsePayload(proposalResponsePayload).build();
Envelope transactionEnvelope = createTransactionEnvelope(transactionPayload, userContext);
NOfEvents nOfEvents = transactionOptions.nOfEvents;
if (nOfEvents == null) {
nOfEvents = NOfEvents.createNofEvents();
Collection<Peer> eventingPeers = getEventingPeers();
boolean anyAdded = false;
if (!eventingPeers.isEmpty()) {
anyAdded = true;
nOfEvents.addPeers(eventingPeers);
}
Collection<EventHub> eventHubs = getEventHubs();
if (!eventHubs.isEmpty()) {
anyAdded = true;
nOfEvents.addEventHubs(getEventHubs());
}
if (!anyAdded) {
nOfEvents = NOfEvents.createNoEvents();
}
} else if (nOfEvents != NOfEvents.nofNoEvents) {
StringBuilder issues = new StringBuilder(100);
Collection<Peer> eventingPeers = getEventingPeers();
nOfEvents.unSeenPeers().forEach(peer -> {
if (peer.getChannel() != this) {
issues.append(format("Peer %s added to NOFEvents does not belong this channel. ", peer.getName()));
} else if (!eventingPeers.contains(peer)) {
issues.append(format("Peer %s added to NOFEvents is not a eventing Peer in this channel. ", peer.getName()));
}
});
nOfEvents.unSeenEventHubs().forEach(eventHub -> {
if (!eventHubs.contains(eventHub)) {
issues.append(format("Eventhub %s added to NOFEvents does not belong this channel. ", eventHub.getName()));
}
});
if (nOfEvents.unSeenEventHubs().isEmpty() && nOfEvents.unSeenPeers().isEmpty()) {
issues.append("NofEvents had no Eventhubs added or Peer eventing services.");
}
String foundIssues = issues.toString();
if (!foundIssues.isEmpty()) {
throw new InvalidArgumentException(foundIssues);
}
}
final boolean replyonly = nOfEvents == NOfEvents.nofNoEvents || (getEventHubs().isEmpty() && getEventingPeers().isEmpty());
CompletableFuture<TransactionEvent> sret;
if (replyonly) {
// If there are no eventhubs to complete the future, complete it
// immediately but give no transaction event
logger.debug(format("Completing transaction id %s immediately no event hubs or peer eventing services found in channel %s.", proposalTransactionID, name));
sret = new CompletableFuture<>();
} else {
sret = registerTxListener(proposalTransactionID, nOfEvents, transactionOptions.failFast);
}
logger.debug(format("Channel %s sending transaction to orderer(s) with TxID %s ", name, proposalTransactionID));
boolean success = false;
// Save last exception to report to user .. others are just logged.
Exception lException = null;
BroadcastResponse resp = null;
Orderer failed = null;
for (Orderer orderer : shuffeledOrderers) {
if (failed != null) {
logger.warn(format("Channel %s %s failed. Now trying %s.", name, failed, orderer));
}
failed = orderer;
try {
if (null != diagnosticFileDumper) {
logger.trace(format("Sending to channel %s, orderer: %s, transaction: %s", name, orderer.getName(), diagnosticFileDumper.createDiagnosticProtobufFile(transactionEnvelope.toByteArray())));
}
resp = orderer.sendTransaction(transactionEnvelope);
// no longer last exception .. maybe just failed.
lException = null;
if (resp.getStatus() == Status.SUCCESS) {
success = true;
break;
} else {
logger.warn(format("Channel %s %s failed. Status returned %s", name, orderer, getRespData(resp)));
}
} catch (Exception e) {
String emsg = format("Channel %s unsuccessful sendTransaction to orderer %s (%s)", name, orderer.getName(), orderer.getUrl());
if (resp != null) {
emsg = format("Channel %s unsuccessful sendTransaction to orderer %s (%s). %s", name, orderer.getName(), orderer.getUrl(), getRespData(resp));
}
logger.error(emsg);
lException = new Exception(emsg, e);
}
}
if (success) {
logger.debug(format("Channel %s successful sent to Orderer transaction id: %s", name, proposalTransactionID));
if (replyonly) {
// just say we're done.
sret.complete(null);
}
return sret;
} else {
String emsg = format("Channel %s failed to place transaction %s on Orderer. Cause: UNSUCCESSFUL. %s", name, proposalTransactionID, getRespData(resp));
unregisterTxListener(proposalTransactionID);
CompletableFuture<TransactionEvent> ret = new CompletableFuture<>();
ret.completeExceptionally(lException != null ? new Exception(emsg, lException) : new Exception(emsg));
return ret;
}
} catch (Exception e) {
CompletableFuture<TransactionEvent> future = new CompletableFuture<>();
future.completeExceptionally(e);
return future;
}
}
Aggregations