Skip to content

Commit

Permalink
FAB-11570 Endorsing error
Browse files Browse the repository at this point in the history
Change-Id: I23a9098af6f440ee8584c0f78500f259a36b7835
Signed-off-by: rickr <[email protected]>
  • Loading branch information
cr22rc committed Sep 12, 2018
1 parent 502b7ea commit ef604d1
Show file tree
Hide file tree
Showing 9 changed files with 921 additions and 230 deletions.
136 changes: 85 additions & 51 deletions src/main/java/org/hyperledger/fabric/sdk/Channel.java
Original file line number Diff line number Diff line change
Expand Up @@ -1363,17 +1363,14 @@ public SDOrdererAddition setSDOrdererAddition(SDOrdererAddition sdOrdererAdditio

}

static byte[] combineCerts(Collection<byte[]>... certCollections) throws IOException {
private static byte[] combineCerts(Collection<byte[]>... certCollections) throws IOException {
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
for (Collection<byte[]> certCollection : certCollections) {

for (byte[] cert : certCollection) {
outputStream.write(cert);

}

}

return outputStream.toByteArray();
}
}
Expand Down Expand Up @@ -3176,6 +3173,28 @@ public Collection<ProposalResponse> sendTransactionProposal(TransactionProposalR
return sendProposal(transactionProposalRequest, getEndorsingPeers());
}

private static class PeerExactMatch { // use original equals of Peer and not what's overrident
final Peer peer;

private PeerExactMatch(Peer peer) {
this.peer = peer;
}

@Override
public boolean equals(Object obj) {
if (!(obj instanceof PeerExactMatch)) {
return false;
}

return peer == ((PeerExactMatch) obj).peer;
}

@Override
public int hashCode() {
return System.identityHashCode(peer);
}
}

/**
* Send a transaction proposal.
*
Expand Down Expand Up @@ -3247,30 +3266,45 @@ public Collection<ProposalResponse> sendTransactionProposalToEndorsers(Transacti
throw new ServiceDiscoveryException(format("Channel %s failed to find and endorsers for chaincode %s no layouts found.", name, chaincodeName));
}

SDChaindcode sdChaindcodeNI = new SDChaindcode(sdChaindcode); //copy. no ignored.
SDChaindcode sdChaindcodeEndorsementCopy = new SDChaindcode(sdChaindcode); //copy. no ignored.

final boolean inspectResults = discoveryOptions.inspectResults;

if (sdChaindcodeNI.ignoreList(discoveryOptions.getIgnoreList()) < 1) { // apply ignore list
if (sdChaindcodeEndorsementCopy.ignoreList(discoveryOptions.getIgnoreList()) < 1) { // apply ignore list
throw new ServiceDiscoveryException("Applying ignore list reduced to no available endorser options.");
}

if (IS_TRACE_LEVEL && null != discoveryOptions.getIgnoreList() && !discoveryOptions.getIgnoreList().isEmpty()) {
logger.trace(format("SDchaincode after ignore list: %s", sdChaindcodeNI));
logger.trace(format("SDchaincode after ignore list: %s", sdChaindcodeEndorsementCopy));
}
final EndorsementSelector lendorsementSelector = discoveryOptions.endorsementSelector != null ?
final ServiceDiscovery.EndorsementSelector lendorsementSelector = discoveryOptions.endorsementSelector != null ?
discoveryOptions.endorsementSelector : this.endorsementSelector;
try {

final Map<String, ProposalResponse> goodResponses = new HashMap<>(); // all good endorsements by endpoint
final Map<String, ProposalResponse> allTried = new HashMap<>(); // all tried by endpoint
final Map<SDEndorser, ProposalResponse> goodResponses = new HashMap<>(); // all good endorsements by endpoint
final Map<SDEndorser, ProposalResponse> allTried = new HashMap<>(); // all tried by endpoint

boolean done = false;
int attempts = 1; //safety valve

do {
logger.trace(format("Attempts: %d, chaincode discovery state: %s", attempts, sdChaindcodeNI));
final SDEndorserState sdEndorserState = lendorsementSelector.endorserSelector(sdChaindcodeNI);
if (IS_TRACE_LEVEL) {
logger.trace(format("Attempts: %d, chaincode discovery state: %s", attempts, sdChaindcodeEndorsementCopy));
}
final SDEndorserState sdEndorserState = lendorsementSelector.endorserSelector(sdChaindcodeEndorsementCopy);

if (IS_TRACE_LEVEL) {

StringBuilder sb = new StringBuilder(1000);
String sep = "";
for (SDEndorser sdEndorser : sdEndorserState.getSdEndorsers()) {
sb.append(sep).append(sdEndorser);
sep = ", ";
}

logger.trace(format("Attempts: %d, chaincode discovery state: %s. Endorser selector picked: %s. With selected endorsers: %s", attempts, sdChaindcodeEndorsementCopy.name, sdEndorserState.getPickedLayout(), sb.toString()));

}

Collection<SDEndorser> ep = sdEndorserState.getSdEndorsers();
ep = new ArrayList<>(ep); // just in case it's not already a copy
Expand All @@ -3286,11 +3320,13 @@ public Collection<ProposalResponse> sendTransactionProposalToEndorsers(Transacti
}

//Safety check make sure the selector isn't giving back endpoints to retry
ep.removeIf(sdEndorser -> goodResponses.keySet().contains(sdEndorser.getEndpoint()));
ep.removeIf(sdEndorser -> goodResponses.keySet().contains(sdEndorser));

if (ep.isEmpty()) { // this would be odd but lets go with it.
Set<String> needed = sdChaindcode.meetsEndorsmentPolicy(goodResponses.keySet());
if (needed != null) {
logger.debug(format("Channel %s, chaincode %s attempts: %d endorser selector returned no additional endorements needed.", name, chaincodeName, attempts));

Collection<SDEndorser> needed = sdChaindcode.meetsEndorsmentPolicy(goodResponses.keySet());
if (needed != null) { // means endorsment meet with those in the needed.
ArrayList<ProposalResponse> ret = new ArrayList<>(needed.size());
needed.forEach(s -> ret.add(goodResponses.get(s)));

Expand Down Expand Up @@ -3319,16 +3355,17 @@ public Collection<ProposalResponse> sendTransactionProposalToEndorsers(Transacti
}
}

HashMap<String, Peer> stringPeerHashMap = new HashMap<>(peerEndpointMap);
ArrayList<Peer> endorsers = new ArrayList<>(ep.size());
for (SDEndorser endpoint : ep) {
Map<String, Peer> lpeerEndpointMap = new HashMap<>(peerEndpointMap);
Map<SDEndorser, Peer> endorsers = new HashMap<>(ep.size());
Map<PeerExactMatch, SDEndorser> peer2sdEndorser = new HashMap<>(ep.size());
for (SDEndorser sdEndorser : ep) {

Peer epeer = stringPeerHashMap.get(endpoint.getEndpoint());
Peer epeer = lpeerEndpointMap.get(sdEndorser.getEndpoint());
if (epeer != null && !epeer.hasConnected()) {
// mostly because gossip may have malicious data so if we've not connected update TLS props from chaincode discovery.
final Properties properties = epeer.getProperties();

final byte[] bytes = combineCerts(endpoint.getTLSCerts(), endpoint.getTLSIntermediateCerts());
final byte[] bytes = combineCerts(sdEndorser.getTLSCerts(), sdEndorser.getTLSIntermediateCerts());
properties.put("pemBytes", bytes);
epeer.setProperties(properties);

Expand All @@ -3337,12 +3374,12 @@ public Collection<ProposalResponse> sendTransactionProposalToEndorsers(Transacti

@Override
public String getMspId() {
return endpoint.getMspid();
return sdEndorser.getMspid();
}

@Override
public String getEndpoint() {
return endpoint.getEndpoint();
return sdEndorser.getEndpoint();
}

@Override
Expand All @@ -3358,12 +3395,12 @@ public HFClient getClient() {
@Override
public byte[][] getTLSCerts() {

return endpoint.getTLSCerts().toArray(new byte[endpoint.getTLSCerts().size()][]);
return sdEndorser.getTLSCerts().toArray(new byte[sdEndorser.getTLSCerts().size()][]);
}

@Override
public byte[][] getTLSIntermediateCerts() {
return endpoint.getTLSIntermediateCerts().toArray(new byte[endpoint.getTLSIntermediateCerts().size()][]);
return sdEndorser.getTLSIntermediateCerts().toArray(new byte[sdEndorser.getTLSIntermediateCerts().size()][]);
}

@Override
Expand All @@ -3372,36 +3409,37 @@ public Map<String, Peer> getEndpointMap() {
}
});
}
endorsers.add(epeer);
endorsers.put(sdEndorser, epeer);
peer2sdEndorser.put(new PeerExactMatch(epeer), sdEndorser); // reverse
}

final Collection<ProposalResponse> proposalResponses = sendProposalToPeers(endorsers, invokeProposal, transactionContext);
HashSet<String> loopGood = new HashSet<>();
HashSet<String> loopBad = new HashSet<>();
final Collection<ProposalResponse> proposalResponses = sendProposalToPeers(endorsers.values(), invokeProposal, transactionContext);
HashSet<SDEndorser> loopGood = new HashSet<>();
HashSet<SDEndorser> loopBad = new HashSet<>();

for (ProposalResponse proposalResponse : proposalResponses) {
final String endpoint = proposalResponse.getPeer().getEndpoint();
allTried.put(endpoint, proposalResponse);
final SDEndorser sdEndorser = peer2sdEndorser.get(new PeerExactMatch(proposalResponse.getPeer()));
allTried.put(sdEndorser, proposalResponse);

final ChaincodeResponse.Status status = proposalResponse.getStatus();

if (ChaincodeResponse.Status.SUCCESS.equals(status)) {

goodResponses.put(endpoint, proposalResponse);
logger.trace(format("Channel %s, chaincode %s attempts %d good endorsements: %s", name, chaincodeName, attempts, endpoint));
loopGood.add(endpoint);
goodResponses.put(sdEndorser, proposalResponse);
logger.trace(format("Channel %s, chaincode %s attempts %d good endorsements: %s", name, chaincodeName, attempts, sdEndorser));
loopGood.add(sdEndorser);

} else {
logger.debug(format("Channel %s, chaincode %s attempts %d bad endorsements: %s", name, chaincodeName, attempts, endpoint));
loopBad.add(endpoint);
logger.debug(format("Channel %s, chaincode %s attempts %d bad endorsements: %s", name, chaincodeName, attempts, sdEndorser));
loopBad.add(sdEndorser);
}
}

//Always check on original
Set<String> needed = sdChaindcode.meetsEndorsmentPolicy(goodResponses.keySet());
if (needed != null) {
ArrayList<ProposalResponse> ret = new ArrayList<>(needed.size());
needed.forEach(s -> ret.add(goodResponses.get(s)));
Collection<SDEndorser> required = sdChaindcode.meetsEndorsmentPolicy(goodResponses.keySet());
if (required != null) {
ArrayList<ProposalResponse> ret = new ArrayList<>(required.size());
required.forEach(s -> ret.add(goodResponses.get(s)));

if (IS_DEBUG_LEVEL) {

Expand All @@ -3410,26 +3448,22 @@ public Map<String, Peer> getEndpointMap() {
for (ProposalResponse proposalResponse : ret) {
sb.append(sep).append(proposalResponse.getPeer());
sep = ", ";

}

logger.debug(format("Channel %s, chaincode %s got all needed endorsements: %s", name, chaincodeName, sb.toString()));

}

return ret; // the happy path :)!

} else { //still don't have the needed endorsements.

sdChaindcodeNI.endorsedList(loopGood);
sdChaindcodeEndorsementCopy.endorsedList(loopGood); // mark the good ones in the working copy.

if (sdChaindcodeNI.ignoreList(loopBad) < 1) { // apply ignore list
if (sdChaindcodeEndorsementCopy.ignoreListSDEndorser(loopBad) < 1) { // apply ignore list
done = true; // no more layouts
}
}

} while (!done && ++attempts <= 5);
logger.trace(format("Endorsements not achieved chaincode: %s, done: %b, attempts: %d", chaincodeName, done, attempts));
logger.debug(format("Endorsements not achieved chaincode: %s, done: %b, attempts: %d", chaincodeName, done, attempts));
if (inspectResults) {
return allTried.values();
} else {
Expand Down Expand Up @@ -3598,10 +3632,10 @@ private Collection<ProposalResponse> sendProposal(TransactionRequest proposalReq
}
}

private transient EndorsementSelector endorsementSelector = ServiceDiscovery.DEFAULT_ENDORSEMENT_SELECTION;
private transient ServiceDiscovery.EndorsementSelector endorsementSelector = ServiceDiscovery.DEFAULT_ENDORSEMENT_SELECTION;

public EndorsementSelector setSDEndorserSelector(EndorsementSelector endorsementSelector) {
EndorsementSelector ret = this.endorsementSelector;
public ServiceDiscovery.EndorsementSelector setSDEndorserSelector(ServiceDiscovery.EndorsementSelector endorsementSelector) {
ServiceDiscovery.EndorsementSelector ret = this.endorsementSelector;
this.endorsementSelector = endorsementSelector;
return ret;

Expand Down Expand Up @@ -4204,7 +4238,7 @@ List<String> getCollections() {
*/
public static class DiscoveryOptions {
Set<String> ignoreList = new HashSet<>();
EndorsementSelector endorsementSelector = null;
ServiceDiscovery.EndorsementSelector endorsementSelector = null;
boolean inspectResults = false;
boolean forceDiscovery = false;

Expand Down Expand Up @@ -4245,7 +4279,7 @@ public DiscoveryOptions setInspectResults(boolean inspectResults) {
* @return
* @throws InvalidArgumentException
*/
public DiscoveryOptions setEndorsementSelector(EndorsementSelector endorsementSelector) throws InvalidArgumentException {
public DiscoveryOptions setEndorsementSelector(ServiceDiscovery.EndorsementSelector endorsementSelector) throws InvalidArgumentException {
if (endorsementSelector == null) {
throw new InvalidArgumentException("endorsementSelector parameter is null.");
}
Expand Down
24 changes: 0 additions & 24 deletions src/main/java/org/hyperledger/fabric/sdk/EndorsementSelector.java

This file was deleted.

4 changes: 2 additions & 2 deletions src/main/java/org/hyperledger/fabric/sdk/HFClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -527,10 +527,10 @@ public Orderer newOrderer(String name, String grpcURL, Properties properties) th
}

/**
* Query the channels for peers
* Query the joined channels for peers
*
* @param peer the peer to query
* @return A set of strings with the peer names.
* @return A set of strings with the names of the channels the peer has joined.
* @throws InvalidArgumentException
* @throws ProposalException
*/
Expand Down
Loading

0 comments on commit ef604d1

Please sign in to comment.