src/main/java/org/hyperledger/fabric/sdk/Channel.java
/**
     * 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 orderers
     * @return Future allowing access to the result of the transaction invocation.
     */
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 orderers
@return Future allowing access to the result of the transaction invocation.
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 orderers @return Future allowing access to the result of the transaction invocation .
public CompletableFuture<TransactionEvent> sendTransaction(Collection<ProposalResponse> proposalResponses, Collection<Orderer> orderers, User userContext) {
        try {
            checkChannelState();
            userContextCheck(userContext);
            if (null == proposalResponses) {
                throw new InvalidArgumentException("sendTransaction proposalResponses was null");
            }
            if (null == orderers) {
                throw new InvalidArgumentException("sendTransaction Orderers is null");
            }
            final ArrayList<Orderer> shuffeledOrderers = new ArrayList<>(orderers);
            Collections.shuffle(shuffeledOrderers);
            if (shuffeledOrderers.isEmpty()) {
                throw new InvalidArgumentException("sendTransaction Orderers to send to is empty.");
            }
            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);
            CompletableFuture<TransactionEvent> sret;
            if (getEventHubs().isEmpty() && getEventingPeers().isEmpty()) { 
                logger.debug(format("Completing transaction id %s immediately no event hubs or peer eventing services found in channel %s.", proposalTransactionID, name));
                sret = new CompletableFuture<>();
                sret.complete(null);
            } else {
                sret = registerTxListener(proposalTransactionID);
            }
            logger.debug(format("Channel %s sending transaction to orderer(s) with TxID %s ", name, proposalTransactionID));
            boolean success = false;
            Exception lException = null; 
            BroadcastResponse resp = null;
            for (Orderer orderer : shuffeledOrderers) {
                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);
                    lException = null; 
                    if (resp.getStatus() == Status.SUCCESS) {
                        success = true;
                        break;
                    }
                } 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, e);
                    lException = new Exception(emsg, e);
                }
            }
            if (success) {
                logger.debug(format("Channel %s successful sent to Orderer transaction id: %s",
                        name, proposalTransactionID));
                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;
        }
    }
public CompletableFuture < TransactionEvent > sendTransaction ( Collection < ProposalResponse > proposalResponses , Collection < Orderer > orderers , User userContext ) { try { checkChannelState ( ) ; userContextCheck ( userContext ) ; if ( null == proposalResponses ) { throw new InvalidArgumentException ( "sendTransaction proposalResponses was null" ) ; } if ( null == orderers ) { throw new InvalidArgumentException ( "sendTransaction Orderers is null" ) ; } final ArrayList < Orderer > shuffeledOrderers = new ArrayList < > ( orderers ) ; Collections . shuffle ( shuffeledOrderers ) ; if ( shuffeledOrderers . isEmpty ( ) ) { throw new InvalidArgumentException ( "sendTransaction Orderers to send to is empty." ) ; } 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 ) ; CompletableFuture < TransactionEvent > sret ; if ( getEventHubs ( ) . isEmpty ( ) && getEventingPeers ( ) . isEmpty ( ) ) { logger . debug ( format ( "Completing transaction id %s immediately no event hubs or peer eventing services found in channel %s." , proposalTransactionID , name ) ) ; sret = new CompletableFuture < > ( ) ; sret . complete ( null ) ; } else { sret = registerTxListener ( proposalTransactionID ) ; } logger . debug ( format ( "Channel %s sending transaction to orderer(s) with TxID %s " , name , proposalTransactionID ) ) ; boolean success = false ; Exception lException = null ; BroadcastResponse resp = null ; for ( Orderer orderer : shuffeledOrderers ) { 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 ) ; lException = null ; if ( resp . getStatus ( ) == Status . SUCCESS ) { success = true ; break ; } } 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 , e ) ; lException = new Exception ( emsg , e ) ; } } if ( success ) { logger . debug ( format ( "Channel %s successful sent to Orderer transaction id: %s" , name , proposalTransactionID ) ) ; 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 ; } }
Send transaction to one of a specified set of orderers with the specified user context.
Send transaction to one of a specified set of orderers with the specified user context .
//If there are no eventhubs to complete the future, complete it // immediately but give no transaction event // Save last exception to report to user .. others are just logged. // no longer last exception .. maybe just failed.