func functionSet() string {
	var functionNames string
	for name := range functionRegistry {
		functionNames = functionNames + " " + name
	}
	return functionNames
}
functionSet returns a string enumerating all available functions
package main
import (
	"crypto/rand"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/asn1"
	"encoding/json"
	"fmt"
	"reflect"
	"strconv"
	"strings"
	"time"
	"github.com/securekey/fabric-snaps/util/rolesmgr"
	"github.com/golang/protobuf/proto"
	"github.com/hyperledger/fabric-sdk-go/pkg/common/logging"
	fabApi "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab"
	"github.com/hyperledger/fabric/bccsp"
	"github.com/hyperledger/fabric/bccsp/factory"
	"github.com/hyperledger/fabric/bccsp/signer"
	acl "github.com/hyperledger/fabric/core/aclmgmt"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	"github.com/hyperledger/fabric/core/peer"
	protosMSP "github.com/hyperledger/fabric/protos/msp"
	pb "github.com/hyperledger/fabric/protos/peer"
	mgmtapi "github.com/securekey/fabric-snaps/configmanager/api"
	"github.com/securekey/fabric-snaps/configmanager/pkg/mgmt"
	configmgmtService "github.com/securekey/fabric-snaps/configmanager/pkg/service"
	cfgsnapapi "github.com/securekey/fabric-snaps/configurationsnap/api"
	"github.com/securekey/fabric-snaps/configurationsnap/cmd/configurationscc/config"
	"github.com/securekey/fabric-snaps/configurationsnap/cmd/configurationscc/listener"
	"github.com/securekey/fabric-snaps/healthcheck"
	metricsutil "github.com/securekey/fabric-snaps/metrics/pkg/util"
	"github.com/securekey/fabric-snaps/transactionsnap/api"
	"github.com/securekey/fabric-snaps/transactionsnap/pkg/txsnapservice"
	"github.com/securekey/fabric-snaps/util"
	"github.com/securekey/fabric-snaps/util/errors"
)
var functionRegistry = map[string]func(shim.ChaincodeStubInterface, [][]byte, *Metrics) pb.Response{
	"healthCheck":     healthCheck,
	"save":            save,
	"get":             get,
	"getFromCache":    getFromCache,
	"delete":          delete,
	"refresh":         refresh,
	"generateKeyPair": generateKeyPair,
	"generateCSR":     generateCSR,
}
var signatureRegistry = map[string]x509.SignatureAlgorithm{
	"ECDSAWithSHA1":    x509.ECDSAWithSHA1,
	"ECDSAWithSHA256":  x509.ECDSAWithSHA256,
	"ECDSAWithSHA384":  x509.ECDSAWithSHA384,
	"ECDSAWithSHA512":  x509.ECDSAWithSHA512,
	"SHA256WithRSAPSS": x509.SHA256WithRSAPSS,
	"SHA384WithRSAPSS": x509.SHA384WithRSAPSS,
	"SHA512WithRSAPSS": x509.SHA512WithRSAPSS,
	"DSAWithSHA256":    x509.DSAWithSHA256,
	"DSAWithSHA1":      x509.DSAWithSHA1,
	"SHA512WithRSA":    x509.SHA512WithRSA,
	"SHA384WithRSA":    x509.SHA384WithRSA,
	"SHA256WithRSA":    x509.SHA256WithRSA,
	"SHA1WithRSA":      x509.SHA1WithRSA,
	"MD5WithRSA":       x509.MD5WithRSA,
	"MD2WithRSA":       x509.MD2WithRSA,
}
var supportedAlgs = []string{"ECDSA", "ECDSAP256", "ECDSAP384", "RSA", "RSA1024", "RSA2048", "RSA3072", "RSA4096"}
var availableFunctions = functionSet()
var logger = logging.NewLogger("configsnap")
type ConfigurationSnap struct {
	metrics *Metrics
}
var peerConfigPath = ""
var aclProvider acl.ACLProvider
const (
	configDataReadACLPrefix = "configdata/read/"
	configDataWriteACLPrefix = "configdata/write/"
	configSnapName = "configurationsnap"
	connectBackoff = time.Second
	publicKeyAlgRSA = "RSA"
	publicKeyAlgDSA = "DSA"
	publicKeyAlgECDSA = "ECDSA"
)
func (configSnap *ConfigurationSnap) Init(stub shim.ChaincodeStubInterface) pb.Response {
	logger.Debugf("******** Init Config Snap on channel [%s]\n", stub.GetChannelID())
	if stub.GetChannelID() != "" {
		if !rolesmgr.HasEndorserRole() {
			logger.Infof("Not starting Config Snap on channel [%s] since this peer is not an endorser", stub.GetChannelID())
			return shim.Success(nil)
		}
		logger.Infof("******** Init Config Snap on channel [%s]", stub.GetChannelID())
		peerMspID, err := config.GetPeerMSPID(peerConfigPath)
		if err != nil {
			return util.CreateShimResponseFromError(errors.WithMessage(errors.InitializeSnapError, err, "Error initializing Configuration Snap"), logger, stub)
		}
		peerID, err := config.GetPeerID(peerConfigPath)
		if err != nil {
			return util.CreateShimResponseFromError(errors.WithMessage(errors.InitializeSnapError, err, "Error initializing Configuration Snap"), logger, stub)
		}
		interval := config.GetDefaultRefreshInterval()
		logger.Debugf("******** Call initialize for [%s][%s][%v]", peerMspID, peerID, interval)
		configmgmtService.Initialize(stub, peerMspID)
		eventSource := &listener.EventSource{
			ChannelID:   stub.GetChannelID(),
			ChaincodeID: configSnapName,
			EventName:   cfgsnapapi.ConfigCCEventName,
		}
		updateListener, err1 := listener.NewChaincodeListener(eventSource)
		if err1 != nil {
			return util.CreateShimResponseFromError(errors.WithMessage(errors.InitializeSnapError, err1, "Error initializing Configuration Snap"), logger, stub)
		}
		go listenConfigEvents(stub.GetChannelID(), updateListener, configSnap.metrics)
		periodicRefresh(stub.GetChannelID(), interval, configSnap.metrics)
	}
	return shim.Success(nil)
}
func listenConfigEvents(channelID string, updateListener listener.ChaincodeListener, metrics *Metrics) {
	for {
		eventChannel, err := updateListener.Listen()
		if err != nil {
			e := errors.Errorf(errors.SystemError, "Error listening for updates on channel [%s]: %s", channelID, err)
			logger.Warnf(e.Error())
			time.Sleep(connectBackoff)
			continue
		}
		for updateEvent := range eventChannel {
			if updateEvent == nil {
				continue
			}
			go sendRefreshRequest(channelID, metrics)
		}
	}
}
func (configSnap *ConfigurationSnap) Invoke(stub shim.ChaincodeStubInterface) (resp pb.Response) {
	defer util.HandlePanic(&resp, logger, stub)
	args := stub.GetArgs()
	if len(args) == 0 {
		return util.CreateShimResponseFromError(errors.New(errors.MissingRequiredParameterError, fmt.Sprintf("Function not provided. Expecting one of (%s)", availableFunctions)), logger, stub)
	}
	functionName := string(args[0])
	function, ok := functionRegistry[functionName]
	if !ok {
		return util.CreateShimResponseFromError(errors.New(errors.InvalidFunctionError, fmt.Sprintf("Invalid function: %s. Expecting one of (%s)", functionName, availableFunctions)), logger, stub)
	}
	functionArgs := args[1:]
	logger.Debugf("Invoking function [%s] with args: %s", functionName, functionArgs)
	return function(stub, functionArgs, configSnap.metrics)
}