/** * Endorsement selection by random layout group and random endorsers there in. */ public static SDEndorserState ENDORSEMENT_SELECTION_RANDOM(SDChaindcode sdChaindcode) { List <SDLayout> layouts = sdChaindcode.Layouts; SDLayout pickedLayout = layouts[0]; if (layouts.Count > 1) { // more than one pick a random one. pickedLayout = layouts[random.Next(layouts.Count)]; } Dictionary <string, SDEndorser> retMap = new Dictionary <string, SDEndorser>(); //hold results. foreach (SDGroup group in pickedLayout.Groups) { // go through groups getting random required endorsers List <SDEndorser> endorsers = group.Endorsers.Shuffle().ToList(); // randomize. int required = group.StillRequired; // what's needed in that group. List <SDEndorser> sdEndorsers = endorsers.GetRange(0, required).ToList(); // pick top endorsers. sdEndorsers.ForEach(sdEndorser => { if (!retMap.ContainsKey(sdEndorser.Endpoint)) { retMap.Add(sdEndorser.Endpoint, sdEndorser); } }); } SDEndorserState sdEndorserState = new SDEndorserState(); //returned result. sdEndorserState.SDEndorsers = retMap.Values.ToList(); sdEndorserState.PickedLayout = pickedLayout; return(sdEndorserState); }
//Copy constructor public SDLayout(SDLayout sdLayout) { foreach (SDGroup group in sdLayout.Groups) { groups.Add(new SDGroup(group)); } }
/** * Endorsement selection by layout group that has least required and block height is the highest (most up to date). */ public static SDEndorserState ENDORSEMENT_SELECTION_LEAST_REQUIRED_BLOCKHEIGHT(SDChaindcode sdChaindcode) { List <SDLayout> layouts = sdChaindcode.Layouts; SDLayout pickedLayout = null; Dictionary <SDLayout, HashSet <SDEndorser> > layoutEndorsers = new Dictionary <SDLayout, HashSet <SDEndorser> >(); // if (layouts.size() > 1) { // pick layout by least number of endorsers .. least number of peers hit and smaller block! foreach (SDLayout sdLayout in layouts) { HashSet <LGroup> remainingGroups = new HashSet <LGroup>(); foreach (SDGroup sdGroup in sdLayout.Groups) { remainingGroups.Add(new LGroup(sdGroup)); } // These are required as there is no choice. HashSet <SDEndorser> required = new HashSet <SDEndorser>(); foreach (LGroup lgroup in remainingGroups) { if (lgroup.StillRequired == lgroup.Endorsers.Count) { required.AddRange(lgroup.Endorsers); } } //add those that there are no choice. if (required.Count > 0) { List <LGroup> remove = new List <LGroup>(); foreach (LGroup lGroup in remainingGroups) { if (!lGroup.Endorsed(required)) { remove.Add(lGroup); } } remove.ForEach(a => remainingGroups.Remove(a)); if (!layoutEndorsers.ContainsKey(sdLayout)) { layoutEndorsers[sdLayout] = new HashSet <SDEndorser>(); } layoutEndorsers[sdLayout].AddRange(required); } if (remainingGroups.Count == 0) { // no more groups here done for this layout. continue; // done with this layout there really were no choices. } //Now go through groups finding which endorsers can satisfy the most groups. do { Dictionary <SDEndorser, int> matchCount = new Dictionary <SDEndorser, int>(); foreach (LGroup group in remainingGroups) { foreach (SDEndorser sdEndorser in group.Endorsers) { if (matchCount.ContainsKey(sdEndorser)) { matchCount[sdEndorser] = matchCount[sdEndorser] + 1; } else { matchCount[sdEndorser] = 1; } } } List <SDEndorser> theMost = new List <SDEndorser>(); int maxMatch = 0; foreach (SDEndorser sdEndorser in matchCount.Keys) { int count = matchCount[sdEndorser]; if (count > maxMatch) { theMost.Clear(); theMost.Add(sdEndorser); maxMatch = count; } else if (count == maxMatch) { theMost.Add(sdEndorser); } } HashSet <SDEndorser> theVeryMost = new HashSet <SDEndorser>(); long max = 0L; // Tie breaker: Pick one with greatest ledger height. foreach (SDEndorser sd in theMost) { if (sd.LedgerHeight > max) { max = sd.LedgerHeight; theVeryMost.Clear(); theVeryMost.Add(sd); } } List <LGroup> remove2 = new List <LGroup>(remainingGroups.Count); foreach (LGroup lGroup in remainingGroups) { if (!lGroup.Endorsed(theVeryMost)) { remove2.Add(lGroup); } } if (!layoutEndorsers.ContainsKey(sdLayout)) { layoutEndorsers[sdLayout] = new HashSet <SDEndorser>(); } layoutEndorsers[sdLayout].AddRange(theVeryMost); remove2.ForEach(a => remainingGroups.Remove(a)); } while (remainingGroups.Count > 0); // Now pick the layout with least endorsers } //Pick layout which needs least endorsements. int min = int.MaxValue; HashSet <SDLayout> theLeast = new HashSet <SDLayout>(); foreach (SDLayout sdLayoutK in layoutEndorsers.Keys) { int count = layoutEndorsers[sdLayoutK].Count; if (count < min) { theLeast.Clear(); theLeast.Add(sdLayoutK); min = count; } else if (count == min) { theLeast.Add(sdLayoutK); } } if (theLeast.Count == 1) { pickedLayout = theLeast.First(); } else { long max = 0L; // Tie breaker: Pick one with greatest ledger height. foreach (SDLayout sdLayout in theLeast) { long height = 0; foreach (SDEndorser sdEndorser in layoutEndorsers[sdLayout]) { height += sdEndorser.LedgerHeight; } if (height > max) { max = height; pickedLayout = sdLayout; } } } SDEndorserState sdEndorserState = new SDEndorserState(); sdEndorserState.SDEndorsers = pickedLayout != null ? layoutEndorsers[pickedLayout].ToList() : new List <SDEndorser>(); sdEndorserState.PickedLayout = pickedLayout; return(sdEndorserState); }
public async Task <Dictionary <string, SDChaindcode> > DiscoverEndorserEndpointsAsync(TransactionContext tContext, List <List <ServiceDiscoveryChaincodeCalls> > chaincodeNames, CancellationToken token = default(CancellationToken)) { if (null == chaincodeNames) { logger.Warn("Discover of chaincode names was null."); return(new Dictionary <string, SDChaindcode>()); } if (chaincodeNames.Count == 0) { logger.Warn("Discover of chaincode names was empty."); return(new Dictionary <string, SDChaindcode>()); } if (IS_DEBUG_LEVEL) { StringBuilder cns = new StringBuilder(1000); string sep = ""; cns.Append("["); foreach (List <ServiceDiscoveryChaincodeCalls> s in chaincodeNames) { ServiceDiscoveryChaincodeCalls n = s[0]; cns.Append(sep).Append(n.Write(s.GetRange(1, s.Count - 1))); sep = ", "; } cns.Append("]"); logger.Debug($"Channel {channelName} doing discovery for chaincodes: {cns}"); } List <Peer> speers = serviceDiscoveryPeers.Shuffle().ToList(); Dictionary <string, SDChaindcode> ret = new Dictionary <string, SDChaindcode>(); sdNetwork = await NetworkDiscoveryAsync(tContext, false, token).ConfigureAwait(false); token.ThrowIfCancellationRequested(); ServiceDiscoveryException serviceDiscoveryException = null; foreach (Peer serviceDiscoveryPeer in speers) { serviceDiscoveryException = null; try { logger.Debug($"Channel {channelName} doing discovery for chaincodes on peer: {serviceDiscoveryPeer}"); TransactionContext ltransactionContext = tContext.RetryTransactionSameContext(); byte[] clientTLSCertificateDigest = serviceDiscoveryPeer.GetClientTLSCertificateDigest(); if (null == clientTLSCertificateDigest) { logger.Warn($"Channel {channelName} peer {serviceDiscoveryPeer} requires mutual tls for service discovery."); continue; } ByteString clientIdent = ltransactionContext.Identity.ToByteString(); ByteString tlshash = ByteString.CopyFrom(clientTLSCertificateDigest); AuthInfo authentication = new AuthInfo(); authentication.ClientIdentity = clientIdent; authentication.ClientTlsCertHash = tlshash; List <Query> fq = new List <Query>(chaincodeNames.Count); foreach (List <ServiceDiscoveryChaincodeCalls> chaincodeName in chaincodeNames) { if (ret.ContainsKey(chaincodeName[0].Name)) { continue; } List <ChaincodeCall> chaincodeCalls = new List <ChaincodeCall>(); chaincodeName.ForEach(serviceDiscoveryChaincodeCalls => chaincodeCalls.Add(serviceDiscoveryChaincodeCalls.Build())); List <ChaincodeInterest> cinn = new List <ChaincodeInterest>(1); //chaincodeName.ForEach(ServiceDiscoveryChaincodeCalls.Build); ChaincodeInterest cci = new ChaincodeInterest(); cci.Chaincodes.Add(chaincodeCalls); cinn.Add(cci); ChaincodeQuery chaincodeQuery = new ChaincodeQuery(); chaincodeQuery.Interests.AddRange(cinn); Query q = new Query(); q.Channel = channelName; q.CcQuery = chaincodeQuery; fq.Add(q); } if (fq.Count == 0) { //this would be odd but lets take care of it. break; } Request request = new Request(); request.Queries.AddRange(fq); request.Authentication = authentication; ByteString payloadBytes = request.ToByteString(); ByteString signatureBytes = ltransactionContext.SignByteStrings(payloadBytes); SignedRequest sr = new SignedRequest(); sr.Payload = payloadBytes; sr.Signature = signatureBytes; if (IS_TRACE_LEVEL && null != diagnosticFileDumper) // dump protobuf we sent { logger.Trace($"Service discovery channel {channelName} {serviceDiscoveryPeer} service chaincode query sent {diagnosticFileDumper.CreateDiagnosticProtobufFile(sr.ToByteArray())}"); } logger.Debug($"Channel {channelName} peer {serviceDiscoveryPeer} sending chaincode query request"); Response response = await serviceDiscoveryPeer.SendDiscoveryRequestAsync(sr, SERVICE_DISCOVERY_WAITTIME, token).ConfigureAwait(false); if (IS_TRACE_LEVEL && null != diagnosticFileDumper) // dump protobuf we get { logger.Trace($"Service discovery channel {channelName} {serviceDiscoveryPeer} query returned {diagnosticFileDumper.CreateDiagnosticProtobufFile(response.ToByteArray())}"); } logger.Debug($"Channel {channelName} peer {serviceDiscoveryPeer} completed chaincode query request"); //serviceDiscoveryPeer.HasConnected(); foreach (QueryResult queryResult in response.Results) { if (queryResult.ResultCase == QueryResult.ResultOneofCase.Error) { ServiceDiscoveryException discoveryException = new ServiceDiscoveryException($"Error {queryResult.Error.Content}"); logger.Error(discoveryException.Message); continue; } if (queryResult.ResultCase != QueryResult.ResultOneofCase.CcQueryRes) { ServiceDiscoveryException discoveryException = new ServiceDiscoveryException($"Error expected chaincode endorsement query but got {queryResult.ResultCase.ToString()}"); logger.Error(discoveryException.Message); continue; } ChaincodeQueryResult ccQueryRes = queryResult.CcQueryRes; if (ccQueryRes.Content.Count == 0) { throw new ServiceDiscoveryException($"Error {queryResult.Error.Content}"); } foreach (EndorsementDescriptor es in ccQueryRes.Content) { string chaincode = es.Chaincode; List <SDLayout> layouts = new List <SDLayout>(); foreach (Layout layout in es.Layouts) { SDLayout sdLayout = null; Dictionary <string, uint> quantitiesByGroupMap = layout.QuantitiesByGroup.ToDictionary(a => a.Key, a => a.Value); foreach (string key in quantitiesByGroupMap.Keys) { uint quantity = quantitiesByGroupMap[key]; if (quantity < 1) { continue; } Peers peers = es.EndorsersByGroups.GetOrNull(key); if (peers == null || peers.Peers_.Count == 0) { continue; } List <SDEndorser> sdEndorsers = new List <SDEndorser>(); foreach (Protos.Discovery.Peer pp in peers.Peers_) { SDEndorser ppp = new SDEndorser(channel, pp, null, null); string endPoint = ppp.Endpoint; SDEndorser nppp = sdNetwork.GetEndorserByEndpoint(endPoint); if (null == nppp) { sdNetwork = await NetworkDiscoveryAsync(tContext, true, token).ConfigureAwait(false); if (null == sdNetwork) { throw new ServiceDiscoveryException("Failed to discover network resources."); } nppp = sdNetwork.GetEndorserByEndpoint(ppp.Endpoint); if (null == nppp) { throw new ServiceDiscoveryException($"Failed to discover peer endpoint information {ppp.Endpoint} for chaincode {chaincode}"); } } sdEndorsers.Add(nppp); } if (sdLayout == null) { sdLayout = new SDLayout(); layouts.Add(sdLayout); } sdLayout.AddGroup(key, (int)quantity, sdEndorsers); } } if (layouts.Count == 0) { logger.Warn($"Channel {channelName} chaincode {chaincode} discovered no layouts!"); } else { if (IS_DEBUG_LEVEL) { StringBuilder sb = new StringBuilder(1000); sb.Append("Channel ").Append(channelName).Append(" found ").Append(layouts.Count).Append(" layouts for chaincode: ").Append(es.Chaincode); sb.Append(", layouts: ["); string sep = ""; foreach (SDLayout layout in layouts) { sb.Append(sep).Append(layout); sep = ", "; } sb.Append("]"); logger.Debug(sb.ToString()); } ret[chaincode] = new SDChaindcode(es.Chaincode, layouts); } } } if (ret.Count == chaincodeNames.Count) { break; // found them all. } } catch (ServiceDiscoveryException e) { logger.Warn($"Service discovery error on peer {serviceDiscoveryPeer}. Error: {e.Message}"); serviceDiscoveryException = e; } catch (Exception e) { logger.Warn($"Service discovery error on peer {serviceDiscoveryPeer}. Error: {e.Message}"); serviceDiscoveryException = new ServiceDiscoveryException(e.Message, e); } } if (null != serviceDiscoveryException) { throw serviceDiscoveryException; } if (ret.Count != chaincodeNames.Count()) { logger.Warn($"Channel {channelName} failed to find all layouts for chaincodes. Expected: {chaincodeNames.Count} and found: {ret.Count}"); } return(ret); }