func (cc *ChannelClient) prepareOptsFromOptions(options ...chclient.Option) (chclient.Opts, error) {
	txnOpts := chclient.Opts{}
	for _, option := range options {
		err := option(&txnOpts)
		if err != nil {
			return txnOpts, errors.WithMessage(err, "Failed to read opts")
		}
	}
	return txnOpts, nil
}
prepareOptsFromOptions Reads apitxn.Opts from chclient.Option array
package chclient
import (
	"reflect"
	"time"
	"github.com/hyperledger/fabric-sdk-go/api/apiconfig"
	fab "github.com/hyperledger/fabric-sdk-go/api/apifabclient"
	"github.com/hyperledger/fabric-sdk-go/api/apitxn/chclient"
	"github.com/hyperledger/fabric-sdk-go/pkg/errors/multi"
	"github.com/hyperledger/fabric-sdk-go/pkg/errors/retry"
	"github.com/hyperledger/fabric-sdk-go/pkg/errors/status"
	"github.com/hyperledger/fabric-sdk-go/pkg/fabric-txn/discovery"
	"github.com/hyperledger/fabric-sdk-go/pkg/fabric-txn/discovery/greylist"
	txnHandlerImpl "github.com/hyperledger/fabric-sdk-go/pkg/fabric-txn/txnhandler"
	"github.com/hyperledger/fabric-sdk-go/pkg/logging"
	"github.com/pkg/errors"
)
var logger = logging.NewLogger("fabric_sdk_go")
const (
	defaultHandlerTimeout = time.Second * 10
)
type ChannelClient struct {
	context   fab.ProviderContext
	discovery fab.DiscoveryService
	selection fab.SelectionService
	channel   fab.Channel
	eventHub  fab.EventHub
	greylist  *greylist.Filter
}
type Context struct {
	fab.ProviderContext
	DiscoveryService fab.DiscoveryService
	SelectionService fab.SelectionService
	Channel          fab.Channel
	EventHub         fab.EventHub
}
func New(c Context) (*ChannelClient, error) {
	greylistProvider := greylist.New(c.Config().TimeoutOrDefault(apiconfig.DiscoveryGreylistExpiry))
	channelClient := ChannelClient{
		greylist:  greylistProvider,
		context:   c,
		discovery: discovery.NewDiscoveryFilterService(c.DiscoveryService, greylistProvider),
		selection: c.SelectionService,
		channel:   c.Channel,
		eventHub:  c.EventHub,
	}
	return &channelClient, nil
}
func (cc *ChannelClient) Query(request chclient.Request, options ...chclient.Option) (chclient.Response, error) {
	return cc.InvokeHandler(txnHandlerImpl.NewQueryHandler(), request, cc.addDefaultTimeout(apiconfig.Query, options...)...)
}
func (cc *ChannelClient) Execute(request chclient.Request, options ...chclient.Option) (chclient.Response, error) {
	return cc.InvokeHandler(txnHandlerImpl.NewExecuteHandler(), request, cc.addDefaultTimeout(apiconfig.Execute, options...)...)
}
func (cc *ChannelClient) InvokeHandler(handler chclient.Handler, request chclient.Request, options ...chclient.Option) (chclient.Response, error) {
	txnOpts, err := cc.prepareOptsFromOptions(options...)
	if err != nil {
		return chclient.Response{}, err
	}
	requestContext, clientContext, err := cc.prepareHandlerContexts(request, txnOpts)
	if err != nil {
		return chclient.Response{}, err
	}
	complete := make(chan bool)
	go func() {
	handleInvoke:
		handler.Handle(requestContext, clientContext)
		if cc.resolveRetry(requestContext, txnOpts) {
			goto handleInvoke
		}
		complete <- true
	}()
	select {
	case <-complete:
		return requestContext.Response, requestContext.Error
	case <-time.After(requestContext.Opts.Timeout):
		return chclient.Response{}, status.New(status.ClientStatus, status.Timeout.ToInt32(),
			"request timed out", nil)
	}
}
func (cc *ChannelClient) resolveRetry(ctx *chclient.RequestContext, opts chclient.Opts) bool {
	errs, ok := ctx.Error.(multi.Errors)
	if !ok {
		errs = append(errs, ctx.Error)
	}
	for _, e := range errs {
		if ctx.RetryHandler.Required(e) {
			logger.Infof("Retrying on error %s", e)
			cc.greylist.Greylist(e)
			ctx.Opts.ProposalProcessors = opts.ProposalProcessors
			ctx.Error = nil
			ctx.Response = chclient.Response{}
			return true
		}
	}
	return false
}
func (cc *ChannelClient) prepareHandlerContexts(request chclient.Request, options chclient.Opts) (*chclient.RequestContext, *chclient.ClientContext, error) {
	if request.ChaincodeID == "" || request.Fcn == "" {
		return nil, nil, errors.New("ChaincodeID and Fcn are required")
	}
	clientContext := &chclient.ClientContext{
		Channel:   cc.channel,
		Selection: cc.selection,
		Discovery: cc.discovery,
		EventHub:  cc.eventHub,
	}
	requestContext := &chclient.RequestContext{
		Request:      request,
		Opts:         options,
		Response:     chclient.Response{},
		RetryHandler: retry.New(options.Retry),
	}
	if requestContext.Opts.Timeout == 0 {
		requestContext.Opts.Timeout = defaultHandlerTimeout
	}
	return requestContext, clientContext, nil
}