func (chaincodeSupport *ChaincodeSupport) Register(stream pb.ChaincodeSupport_RegisterServer) error {
	return HandleChaincodeStream(chaincodeSupport, stream)
}
Register the bidi stream entry point called by chaincode to register with the Peer.
package chaincode
import (
	"bytes"
	"fmt"
	"io"
	"sync"
	"time"
	"github.com/golang/protobuf/proto"
	"github.com/op/go-logging"
	"github.com/spf13/viper"
	"golang.org/x/net/context"
	google_protobuf "google/protobuf"
	"github.com/openblockchain/obc-peer/openchain/container"
	"github.com/openblockchain/obc-peer/openchain/crypto"
	pb "github.com/openblockchain/obc-peer/protos"
)
var chaincodeLog = logging.MustGetLogger("chaincode")
type ChainName string
const (
	DefaultChain ChainName = "default"
	DevModeUserRunsChaincode       string = "dev"
	chaincodeStartupTimeoutDefault int    = 5000
	chaincodeInstallPathDefault    string = "/go/bin/"
	peerAddressDefault             string = "0.0.0.0:30303"
)
var chains map[ChainName]*ChaincodeSupport
func init() {
	chains = make(map[ChainName]*ChaincodeSupport)
}
type handlerMap struct {
	sync.RWMutex
	chaincodeMap map[string]*Handler
}
func GetChain(name ChainName) *ChaincodeSupport {
	return chains[name]
}
func (chaincodeSupport *ChaincodeSupport) preLaunchSetup(chaincode string) chan bool {
	notfy := make(chan bool, 1)
	chaincodeSupport.handlerMap.chaincodeMap[chaincode] = &Handler{readyNotify: notfy}
	return notfy
}
func (chaincodeSupport *ChaincodeSupport) chaincodeHasBeenLaunched(chaincode string) (*Handler, bool) {
	handler, hasbeenlaunched := chaincodeSupport.handlerMap.chaincodeMap[chaincode]
	return handler, hasbeenlaunched
}
func NewChaincodeSupport(chainname ChainName, getPeerEndpoint func() (*pb.PeerEndpoint, error), userrunsCC bool, ccstartuptimeout time.Duration, secHelper crypto.Peer) *ChaincodeSupport {
	s := &ChaincodeSupport{name: chainname, handlerMap: &handlerMap{chaincodeMap: make(map[string]*Handler)}, secHelper: secHelper}
	chains[chainname] = s
	peerEndpoint, err := getPeerEndpoint()
	if err != nil {
		chaincodeLog.Error(fmt.Sprintf("Error getting PeerEndpoint, using peer.address: %s", err))
		s.peerAddress = viper.GetString("peer.address")
	} else {
		s.peerAddress = peerEndpoint.Address
	}
	chaincodeLog.Info("Chaincode support using peerAddress: %s\n", s.peerAddress)
	if s.peerAddress == "" {
		s.peerAddress = peerAddressDefault
	}
	s.userRunsCC = userrunsCC
	s.ccStartupTimeout = ccstartuptimeout * time.Millisecond
	s.chaincodeInstallPath = chaincodeInstallPathDefault
	return s
}
type ChaincodeSupport struct {
	name                 ChainName
	handlerMap           *handlerMap
	peerAddress          string
	ccStartupTimeout     time.Duration
	chaincodeInstallPath string
	userRunsCC           bool
	secHelper            crypto.Peer
}
type DuplicateChaincodeHandlerError struct {
	ChaincodeID *pb.ChaincodeID
}
func (d *DuplicateChaincodeHandlerError) Error() string {
	return fmt.Sprintf("Duplicate chaincodeID error: %s", d.ChaincodeID)
}
func newDuplicateChaincodeHandlerError(chaincodeHandler *Handler) error {
	return &DuplicateChaincodeHandlerError{ChaincodeID: chaincodeHandler.ChaincodeID}
}
func (chaincodeSupport *ChaincodeSupport) registerHandler(chaincodehandler *Handler) error {
	key := chaincodehandler.ChaincodeID.Name
	chaincodeSupport.handlerMap.Lock()
	defer chaincodeSupport.handlerMap.Unlock()
	h2, ok := chaincodeSupport.chaincodeHasBeenLaunched(key)
	if ok && h2.registered == true {
		chaincodeLogger.Debug("duplicate registered handler(key:%s) return error", key)
		return newDuplicateChaincodeHandlerError(chaincodehandler)
	}
	if h2 != nil {
		chaincodehandler.readyNotify = h2.readyNotify
		delete(chaincodeSupport.handlerMap.chaincodeMap, key)
	}
	chaincodeSupport.handlerMap.chaincodeMap[key] = chaincodehandler
	chaincodehandler.registered = true
	chaincodehandler.txCtxs = make(map[string]*transactionContext)
	chaincodehandler.uuidMap = make(map[string]bool)
	chaincodehandler.isTransaction = make(map[string]bool)
	chaincodeLogger.Debug("registered handler complete for chaincode %s", key)
	return nil
}
func (chaincodeSupport *ChaincodeSupport) deregisterHandler(chaincodehandler *Handler) error {
	for _, context := range chaincodehandler.txCtxs {
		for _, v := range context.rangeQueryIteratorMap {
			v.Close()
		}
	}
	key := chaincodehandler.ChaincodeID.Name
	chaincodeLogger.Debug("Deregister handler: %s", key)
	chaincodeSupport.handlerMap.Lock()
	defer chaincodeSupport.handlerMap.Unlock()
	if _, ok := chaincodeSupport.chaincodeHasBeenLaunched(key); !ok {
		return fmt.Errorf("Error deregistering handler, could not find handler with key: %s", key)
	}
	delete(chaincodeSupport.handlerMap.chaincodeMap, key)
	chaincodeLogger.Debug("Deregistered handler with key: %s", key)
	return nil
}
func (chaincodeSupport *ChaincodeSupport) GetExecutionContext(context context.Context, requestContext *pb.ChaincodeRequestContext) (*pb.ChaincodeExecutionContext, error) {
	timeStamp := &google_protobuf.Timestamp{Seconds: time.Now().UnixNano(), Nanos: 0}
	executionContext := &pb.ChaincodeExecutionContext{ChaincodeId: requestContext.GetId(),
		Timestamp: timeStamp}
	chaincodeLog.Debug("returning execution context: %s", executionContext)
	return executionContext, nil
}
func (chaincodeSupport *ChaincodeSupport) sendInitOrReady(context context.Context, uuid string, chaincode string, f *string, initArgs []string, timeout time.Duration, tx *pb.Transaction) error {
	chaincodeSupport.handlerMap.Lock()
	var handler *Handler
	var ok bool
	if handler, ok = chaincodeSupport.chaincodeHasBeenLaunched(chaincode); !ok {
		chaincodeSupport.handlerMap.Unlock()
		chaincodeLog.Debug("handler not found for chaincode %s", chaincode)
		return fmt.Errorf("handler not found for chaincode %s", chaincode)
	}
	chaincodeSupport.handlerMap.Unlock()
	var notfy chan *pb.ChaincodeMessage
	var err error
	if notfy, err = handler.initOrReady(uuid, f, initArgs, tx); err != nil {
		return fmt.Errorf("Error sending %s: %s", pb.ChaincodeMessage_INIT, err)
	}
	if notfy != nil {
		select {
		case ccMsg := <-notfy:
			if ccMsg.Type == pb.ChaincodeMessage_ERROR {
				err = fmt.Errorf("Error initializing container %s: %s", chaincode, string(ccMsg.Payload))
			}
		case <-time.After(timeout):
			err = fmt.Errorf("Timeout expired while executing send init message")
		}
	}
	handler.deleteTxContext(uuid)
	return err
}
func (chaincodeSupport *ChaincodeSupport) getArgsAndEnv(cID *pb.ChaincodeID) (args []string, envs []string, err error) {
	envs = []string{"OPENCHAIN_CHAINCODE_ID_NAME=" + cID.Name}
	args = []string{chaincodeSupport.chaincodeInstallPath + cID.Name, fmt.Sprintf("-peer.address=%s", chaincodeSupport.peerAddress)}
	chaincodeLog.Debug("Executable is %s", args[0])
	return args, envs, nil
}
func (chaincodeSupport *ChaincodeSupport) launchAndWaitForRegister(context context.Context, cID *pb.ChaincodeID, uuid string) (bool, error) {
	chaincode := cID.Name
	if chaincode == "" {
		return false, fmt.Errorf("chaincode name not set")
	}
	chaincodeSupport.handlerMap.Lock()
	var ok bool
	if _, ok = chaincodeSupport.chaincodeHasBeenLaunched(chaincode); ok {
		chaincodeLog.Debug("chaincode is running and ready: %s", chaincode)
		chaincodeSupport.handlerMap.Unlock()
		return true, nil
	}
	alreadyRunning := false
	notfy := chaincodeSupport.preLaunchSetup(chaincode)
	chaincodeSupport.handlerMap.Unlock()
	args, env, err := chaincodeSupport.getArgsAndEnv(cID)
	if err != nil {
		return alreadyRunning, err
	}
	vmname := container.GetVMFromName(chaincode)
	chaincodeLog.Debug("start container: %s", vmname)
	sir := container.StartImageReq{ID: vmname, Args: args, Env: env}
	resp, err := container.VMCProcess(context, "Docker", sir)
	if err != nil || (resp != nil && resp.(container.VMCResp).Err != nil) {
		if err == nil {
			err = resp.(container.VMCResp).Err
		}
		err = fmt.Errorf("Error starting container: %s", err)
		chaincodeSupport.handlerMap.Lock()
		delete(chaincodeSupport.handlerMap.chaincodeMap, chaincode)
		chaincodeSupport.handlerMap.Unlock()
		return alreadyRunning, err
	}
	select {
	case ok := <-notfy:
		if !ok {
			err = fmt.Errorf("registration failed for %s(tx:%s)", vmname, uuid)
		}
	case <-time.After(chaincodeSupport.ccStartupTimeout):
		err = fmt.Errorf("Timeout expired while starting chaincode %s(tx:%s)", vmname, uuid)
	}
	if err != nil {
		chaincodeLog.Debug("stopping due to error while launching %s", err)
		errIgnore := chaincodeSupport.stopChaincode(context, cID)
		if errIgnore != nil {
			chaincodeLog.Debug("error on stop %s(%s)", errIgnore, err)
		}
	}
	return alreadyRunning, err
}
func (chaincodeSupport *ChaincodeSupport) stopChaincode(context context.Context, cID *pb.ChaincodeID) error {
	chaincode := cID.Name
	if chaincode == "" {
		return fmt.Errorf("chaincode name not set")
	}
	vmname := container.GetVMFromName(chaincode)
	sir := container.StopImageReq{ID: vmname, Timeout: 0}
	_, err := container.VMCProcess(context, "Docker", sir)
	if err != nil {
		err = fmt.Errorf("Error stopping container: %s", err)
	}
	chaincodeSupport.handlerMap.Lock()
	if _, ok := chaincodeSupport.chaincodeHasBeenLaunched(chaincode); !ok {
		chaincodeSupport.handlerMap.Unlock()
		return nil
	}
	delete(chaincodeSupport.handlerMap.chaincodeMap, chaincode)
	chaincodeSupport.handlerMap.Unlock()
	return err
}
func (chaincodeSupport *ChaincodeSupport) LaunchChaincode(context context.Context, t *pb.Transaction) (*pb.ChaincodeID, *pb.ChaincodeInput, error) {
	var cID *pb.ChaincodeID
	var cMsg *pb.ChaincodeInput
	var f *string
	var initargs []string
	if t.Type == pb.Transaction_CHAINCODE_NEW {
		cds := &pb.ChaincodeDeploymentSpec{}
		err := proto.Unmarshal(t.Payload, cds)
		if err != nil {
			return nil, nil, err
		}
		cID = cds.ChaincodeSpec.ChaincodeID
		cMsg = cds.ChaincodeSpec.CtorMsg
		f = &cMsg.Function
		initargs = cMsg.Args
	} else if t.Type == pb.Transaction_CHAINCODE_EXECUTE || t.Type == pb.Transaction_CHAINCODE_QUERY {
		ci := &pb.ChaincodeInvocationSpec{}
		err := proto.Unmarshal(t.Payload, ci)
		if err != nil {
			return nil, nil, err
		}
		cID = ci.ChaincodeSpec.ChaincodeID
		cMsg = ci.ChaincodeSpec.CtorMsg
	} else {
		chaincodeSupport.handlerMap.Unlock()
		return nil, nil, fmt.Errorf("invalid transaction type: %d", t.Type)
	}
	chaincode := cID.Name
	chaincodeSupport.handlerMap.Lock()
	var handler *Handler
	var ok bool
	var err error
	if handler, ok = chaincodeSupport.chaincodeHasBeenLaunched(chaincode); ok {
		if !handler.registered {
			chaincodeSupport.handlerMap.Unlock()
			chaincodeLog.Debug("premature execution - chaincode (%s) is being launched", chaincode)
			err = fmt.Errorf("premature execution - chaincode (%s) is being launched", chaincode)
			return cID, cMsg, err
		}
		if handler.isRunning() {
			chaincodeLog.Debug("chaincode is running(no need to launch) : %s", chaincode)
			chaincodeSupport.handlerMap.Unlock()
			return cID, cMsg, nil
		}
		chaincodeLog.Debug("Container not in READY state(%s)...send init/ready", handler.FSM.Current())
	}
	chaincodeSupport.handlerMap.Unlock()
	if !chaincodeSupport.userRunsCC && handler == nil {
		_, err = chaincodeSupport.launchAndWaitForRegister(context, cID, t.Uuid)
		if err != nil {
			chaincodeLog.Debug("launchAndWaitForRegister failed %s", err)
			return cID, cMsg, err
		}
	}
	if err == nil {
		err = chaincodeSupport.sendInitOrReady(context, t.Uuid, chaincode, f, initargs, chaincodeSupport.ccStartupTimeout, t)
		if err != nil {
			chaincodeLog.Debug("sending init failed(%s)", err)
			err = fmt.Errorf("Failed to init chaincode(%s)", err)
			errIgnore := chaincodeSupport.stopChaincode(context, cID)
			if errIgnore != nil {
				chaincodeLog.Debug("stop failed %s(%s)", errIgnore, err)
			}
		}
		chaincodeLog.Debug("sending init completed")
	}
	chaincodeLog.Debug("LaunchChaincode complete")
	return cID, cMsg, err
}
func (chaincodeSupport *ChaincodeSupport) getSecHelper() crypto.Peer {
	return chaincodeSupport.secHelper
}
func (chaincodeSupport *ChaincodeSupport) DeployChaincode(context context.Context, t *pb.Transaction) (*pb.ChaincodeDeploymentSpec, error) {
	if chaincodeSupport.userRunsCC {
		chaincodeLog.Debug("user runs chaincode, not deploying chaincode")
		return nil, nil
	}
	cds := &pb.ChaincodeDeploymentSpec{}
	err := proto.Unmarshal(t.Payload, cds)
	if err != nil {
		return nil, err
	}
	cID := cds.ChaincodeSpec.ChaincodeID
	chaincode := cID.Name
	if err != nil {
		return cds, err
	}
	chaincodeSupport.handlerMap.Lock()
	if _, ok := chaincodeSupport.chaincodeHasBeenLaunched(chaincode); ok {
		chaincodeLog.Debug("deploy ?!! there's a chaincode with that name running: %s", chaincode)
		chaincodeSupport.handlerMap.Unlock()
		return cds, fmt.Errorf("deploy attempted but a chaincode with same name running %s", chaincode)
	}
	chaincodeSupport.handlerMap.Unlock()
	args, envs, err := chaincodeSupport.getArgsAndEnv(cID)
	if err != nil {
		return cds, fmt.Errorf("error getting args for chaincode %s", err)
	}
	vmname := container.GetVMFromName(chaincode)
	var targz io.Reader = bytes.NewBuffer(cds.CodePackage)
	cir := &container.CreateImageReq{ID: vmname, Args: args, Reader: targz, Env: envs}
	chaincodeLog.Debug("deploying chaincode %s", vmname)
	_, err = container.VMCProcess(context, "Docker", cir)
	if err != nil {
		err = fmt.Errorf("Error starting container: %s", err)
	}
	return cds, err
}