Esempio n. 1
0
        /**
         * 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);
        }
Esempio n. 2
0
 //Copy constructor
 public SDLayout(SDLayout sdLayout)
 {
     foreach (SDGroup group in sdLayout.Groups)
     {
         groups.Add(new SDGroup(group));
     }
 }
Esempio n. 3
0
        /**
         * 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);
        }
Esempio n. 4
0
        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);
        }