code: func (s *Service) GetEndorsersForChaincode(chaincodes []*fab.ChaincodeCall, opts ...coptions.Opt) ([]fab.Peer, error) {
  	if s.chResponseCache.IsClosed() {
  		return nil, errors.Errorf("Selection service has been closed")
  	}
  
  	logger.Debugf("Getting endorsers for chaincodes [%#v]...", chaincodes)
  	if len(chaincodes) == 0 {
  		return nil, errors.New("no chaincode IDs provided")
  	}
  
  	params := soptions.Params{RetryOpts: s.retryOpts}
  	coptions.Apply(&params, opts)
  
  	chResponse, err := s.getChannelResponse(chaincodes, params.RetryOpts)
  	if err != nil {
  		return nil, errors.Wrapf(err, "error getting channel response for channel [%s]", s.channelID)
  	}
  
  	// Execute getEndorsers with retries since the discovered peers may be out of sync with
  	// the peers returned from the endorser query and it may take a while for them to sync.
  	endpoints, err := retry.NewInvoker(retry.New(s.retryOpts)).Invoke(
  		func() (interface{}, error) {
  			return s.getEndorsers(chaincodes, chResponse, params.PeerFilter, params.PeerSorter)
  		},
  	)
  
  	if err != nil || endpoints == nil {
  		return nil, err
  	}
  
  	return asPeers(s.ctx, endpoints.(discclient.Endorsers)), nil
  }
docs: // GetEndorsersForChaincode returns the endorsing peers for the given chaincodes