github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/core/chaincode/chaincode_support.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  		 http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package chaincode
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  	"path/filepath"
    23  	"strconv"
    24  	"sync"
    25  	"time"
    26  
    27  	"github.com/golang/protobuf/proto"
    28  	logging "github.com/op/go-logging"
    29  	"github.com/spf13/viper"
    30  	"golang.org/x/net/context"
    31  
    32  	"strings"
    33  
    34  	"github.com/hyperledger/fabric/common/flogging"
    35  	"github.com/hyperledger/fabric/core/chaincode/platforms"
    36  	"github.com/hyperledger/fabric/core/chaincode/shim"
    37  	"github.com/hyperledger/fabric/core/common/ccprovider"
    38  	"github.com/hyperledger/fabric/core/config"
    39  	"github.com/hyperledger/fabric/core/container"
    40  	"github.com/hyperledger/fabric/core/container/api"
    41  	"github.com/hyperledger/fabric/core/container/ccintf"
    42  	"github.com/hyperledger/fabric/core/ledger"
    43  	pb "github.com/hyperledger/fabric/protos/peer"
    44  )
    45  
    46  type key string
    47  
    48  const (
    49  	// DevModeUserRunsChaincode property allows user to run chaincode in development environment
    50  	DevModeUserRunsChaincode       string = "dev"
    51  	chaincodeStartupTimeoutDefault int    = 5000
    52  	peerAddressDefault             string = "0.0.0.0:7051"
    53  
    54  	//TXSimulatorKey is used to attach ledger simulation context
    55  	TXSimulatorKey key = "txsimulatorkey"
    56  
    57  	//HistoryQueryExecutorKey is used to attach ledger history query executor context
    58  	HistoryQueryExecutorKey key = "historyqueryexecutorkey"
    59  )
    60  
    61  //this is basically the singleton that supports the
    62  //entire chaincode framework. It does NOT know about
    63  //chains. Chains are per-proposal entities that are
    64  //setup as part of "join" and go through this object
    65  //via calls to Execute and Deploy chaincodes.
    66  var theChaincodeSupport *ChaincodeSupport
    67  
    68  //use this for ledger access and make sure TXSimulator is being used
    69  func getTxSimulator(context context.Context) ledger.TxSimulator {
    70  	if txsim, ok := context.Value(TXSimulatorKey).(ledger.TxSimulator); ok {
    71  		return txsim
    72  	}
    73  	//chaincode will not allow state operations
    74  	return nil
    75  }
    76  
    77  //use this for ledger access and make sure HistoryQueryExecutor is being used
    78  func getHistoryQueryExecutor(context context.Context) ledger.HistoryQueryExecutor {
    79  	if historyQueryExecutor, ok := context.Value(HistoryQueryExecutorKey).(ledger.HistoryQueryExecutor); ok {
    80  		return historyQueryExecutor
    81  	}
    82  	//chaincode will not allow state operations
    83  	return nil
    84  }
    85  
    86  //
    87  //chaincode runtime environment encapsulates handler and container environment
    88  //This is where the VM that's running the chaincode would hook in
    89  type chaincodeRTEnv struct {
    90  	handler *Handler
    91  }
    92  
    93  // runningChaincodes contains maps of chaincodeIDs to their chaincodeRTEs
    94  type runningChaincodes struct {
    95  	sync.RWMutex
    96  	// chaincode environment for each chaincode
    97  	chaincodeMap map[string]*chaincodeRTEnv
    98  }
    99  
   100  //GetChain returns the chaincode framework support object
   101  func GetChain() *ChaincodeSupport {
   102  	return theChaincodeSupport
   103  }
   104  
   105  func (chaincodeSupport *ChaincodeSupport) preLaunchSetup(chaincode string) chan bool {
   106  	chaincodeSupport.runningChaincodes.Lock()
   107  	defer chaincodeSupport.runningChaincodes.Unlock()
   108  	//register placeholder Handler. This will be transferred in registerHandler
   109  	//NOTE: from this point, existence of handler for this chaincode means the chaincode
   110  	//is in the process of getting started (or has been started)
   111  	notfy := make(chan bool, 1)
   112  	chaincodeSupport.runningChaincodes.chaincodeMap[chaincode] = &chaincodeRTEnv{handler: &Handler{readyNotify: notfy}}
   113  	return notfy
   114  }
   115  
   116  //call this under lock
   117  func (chaincodeSupport *ChaincodeSupport) chaincodeHasBeenLaunched(chaincode string) (*chaincodeRTEnv, bool) {
   118  	chrte, hasbeenlaunched := chaincodeSupport.runningChaincodes.chaincodeMap[chaincode]
   119  	return chrte, hasbeenlaunched
   120  }
   121  
   122  // NewChaincodeSupport creates a new ChaincodeSupport instance
   123  func NewChaincodeSupport(getCCEndpoint func() (*pb.PeerEndpoint, error), userrunsCC bool, ccstartuptimeout time.Duration) *ChaincodeSupport {
   124  	ccprovider.SetChaincodesPath(config.GetPath("peer.fileSystemPath") + string(filepath.Separator) + "chaincodes")
   125  
   126  	pnid := viper.GetString("peer.networkId")
   127  	pid := viper.GetString("peer.id")
   128  
   129  	theChaincodeSupport = &ChaincodeSupport{runningChaincodes: &runningChaincodes{chaincodeMap: make(map[string]*chaincodeRTEnv)}, peerNetworkID: pnid, peerID: pid}
   130  
   131  	//initialize global chain
   132  
   133  	ccEndpoint, err := getCCEndpoint()
   134  	if err != nil {
   135  		chaincodeLogger.Errorf("Error getting chaincode endpoint, using chaincode.peerAddress: %s", err)
   136  		theChaincodeSupport.peerAddress = viper.GetString("chaincode.peerAddress")
   137  	} else {
   138  		theChaincodeSupport.peerAddress = ccEndpoint.Address
   139  	}
   140  	chaincodeLogger.Infof("Chaincode support using peerAddress: %s\n", theChaincodeSupport.peerAddress)
   141  	//peerAddress = viper.GetString("peer.address")
   142  	if theChaincodeSupport.peerAddress == "" {
   143  		theChaincodeSupport.peerAddress = peerAddressDefault
   144  	}
   145  
   146  	theChaincodeSupport.userRunsCC = userrunsCC
   147  
   148  	theChaincodeSupport.ccStartupTimeout = ccstartuptimeout
   149  
   150  	theChaincodeSupport.peerTLS = viper.GetBool("peer.tls.enabled")
   151  	if theChaincodeSupport.peerTLS {
   152  		theChaincodeSupport.peerTLSCertFile = config.GetPath("peer.tls.cert.file")
   153  		theChaincodeSupport.peerTLSKeyFile = config.GetPath("peer.tls.key.file")
   154  		theChaincodeSupport.peerTLSSvrHostOrd = viper.GetString("peer.tls.serverhostoverride")
   155  	}
   156  
   157  	kadef := 0
   158  	if ka := viper.GetString("chaincode.keepalive"); ka == "" {
   159  		theChaincodeSupport.keepalive = time.Duration(kadef) * time.Second
   160  	} else {
   161  		t, terr := strconv.Atoi(ka)
   162  		if terr != nil {
   163  			chaincodeLogger.Errorf("Invalid keepalive value %s (%s) defaulting to %d", ka, terr, kadef)
   164  			t = kadef
   165  		} else if t <= 0 {
   166  			chaincodeLogger.Debugf("Turn off keepalive(value %s)", ka)
   167  			t = kadef
   168  		}
   169  		theChaincodeSupport.keepalive = time.Duration(t) * time.Second
   170  	}
   171  
   172  	//default chaincode execute timeout is 30 secs
   173  	execto := time.Duration(30) * time.Second
   174  	if eto := viper.GetDuration("chaincode.executetimeout"); eto <= time.Duration(1)*time.Second {
   175  		chaincodeLogger.Errorf("Invalid execute timeout value %s (should be at least 1s); defaulting to %s", eto, execto)
   176  	} else {
   177  		chaincodeLogger.Debugf("Setting execute timeout value to %s", eto)
   178  		execto = eto
   179  	}
   180  
   181  	theChaincodeSupport.executetimeout = execto
   182  
   183  	viper.SetEnvPrefix("CORE")
   184  	viper.AutomaticEnv()
   185  	replacer := strings.NewReplacer(".", "_")
   186  	viper.SetEnvKeyReplacer(replacer)
   187  
   188  	theChaincodeSupport.chaincodeLogLevel = getLogLevelFromViper("level")
   189  	theChaincodeSupport.shimLogLevel = getLogLevelFromViper("shim")
   190  	theChaincodeSupport.logFormat = viper.GetString("chaincode.logging.format")
   191  
   192  	return theChaincodeSupport
   193  }
   194  
   195  // getLogLevelFromViper gets the chaincode container log levels from viper
   196  func getLogLevelFromViper(module string) string {
   197  	levelString := viper.GetString("chaincode.logging." + module)
   198  	_, err := logging.LogLevel(levelString)
   199  
   200  	if err == nil {
   201  		chaincodeLogger.Debugf("CORE_CHAINCODE_%s set to level %s", strings.ToUpper(module), levelString)
   202  	} else {
   203  		chaincodeLogger.Warningf("CORE_CHAINCODE_%s has invalid log level %s. defaulting to %s", strings.ToUpper(module), levelString, flogging.DefaultLevel())
   204  		levelString = flogging.DefaultLevel()
   205  	}
   206  	return levelString
   207  }
   208  
   209  // // ChaincodeStream standard stream for ChaincodeMessage type.
   210  // type ChaincodeStream interface {
   211  // 	Send(*pb.ChaincodeMessage) error
   212  // 	Recv() (*pb.ChaincodeMessage, error)
   213  // }
   214  
   215  // ChaincodeSupport responsible for providing interfacing with chaincodes from the Peer.
   216  type ChaincodeSupport struct {
   217  	runningChaincodes *runningChaincodes
   218  	peerAddress       string
   219  	ccStartupTimeout  time.Duration
   220  	peerNetworkID     string
   221  	peerID            string
   222  	peerTLSCertFile   string
   223  	peerTLSKeyFile    string
   224  	peerTLSSvrHostOrd string
   225  	keepalive         time.Duration
   226  	chaincodeLogLevel string
   227  	shimLogLevel      string
   228  	logFormat         string
   229  	executetimeout    time.Duration
   230  	userRunsCC        bool
   231  	peerTLS           bool
   232  }
   233  
   234  // DuplicateChaincodeHandlerError returned if attempt to register same chaincodeID while a stream already exists.
   235  type DuplicateChaincodeHandlerError struct {
   236  	ChaincodeID *pb.ChaincodeID
   237  }
   238  
   239  func (d *DuplicateChaincodeHandlerError) Error() string {
   240  	return fmt.Sprintf("Duplicate chaincodeID error: %s", d.ChaincodeID)
   241  }
   242  
   243  func newDuplicateChaincodeHandlerError(chaincodeHandler *Handler) error {
   244  	return &DuplicateChaincodeHandlerError{ChaincodeID: chaincodeHandler.ChaincodeID}
   245  }
   246  
   247  func (chaincodeSupport *ChaincodeSupport) registerHandler(chaincodehandler *Handler) error {
   248  	key := chaincodehandler.ChaincodeID.Name
   249  
   250  	chaincodeSupport.runningChaincodes.Lock()
   251  	defer chaincodeSupport.runningChaincodes.Unlock()
   252  
   253  	chrte2, ok := chaincodeSupport.chaincodeHasBeenLaunched(key)
   254  	if ok && chrte2.handler.registered == true {
   255  		chaincodeLogger.Debugf("duplicate registered handler(key:%s) return error", key)
   256  		// Duplicate, return error
   257  		return newDuplicateChaincodeHandlerError(chaincodehandler)
   258  	}
   259  	//a placeholder, unregistered handler will be setup by transaction processing that comes
   260  	//through via consensus. In this case we swap the handler and give it the notify channel
   261  	if chrte2 != nil {
   262  		chaincodehandler.readyNotify = chrte2.handler.readyNotify
   263  		chrte2.handler = chaincodehandler
   264  	} else {
   265  		if chaincodeSupport.userRunsCC == false {
   266  			//this chaincode was not launched by the peer and is attempting
   267  			//to register. Don't allow this.
   268  			return fmt.Errorf("peer will not accepting external chaincode connection %v (except in dev mode)", chaincodehandler.ChaincodeID)
   269  		}
   270  		chaincodeSupport.runningChaincodes.chaincodeMap[key] = &chaincodeRTEnv{handler: chaincodehandler}
   271  	}
   272  
   273  	chaincodehandler.registered = true
   274  
   275  	//now we are ready to receive messages and send back responses
   276  	chaincodehandler.txCtxs = make(map[string]*transactionContext)
   277  	chaincodehandler.txidMap = make(map[string]bool)
   278  
   279  	chaincodeLogger.Debugf("registered handler complete for chaincode %s", key)
   280  
   281  	return nil
   282  }
   283  
   284  func (chaincodeSupport *ChaincodeSupport) deregisterHandler(chaincodehandler *Handler) error {
   285  
   286  	// clean up queryIteratorMap
   287  	for _, context := range chaincodehandler.txCtxs {
   288  		for _, v := range context.queryIteratorMap {
   289  			v.Close()
   290  		}
   291  	}
   292  
   293  	key := chaincodehandler.ChaincodeID.Name
   294  	chaincodeLogger.Debugf("Deregister handler: %s", key)
   295  	chaincodeSupport.runningChaincodes.Lock()
   296  	defer chaincodeSupport.runningChaincodes.Unlock()
   297  	if _, ok := chaincodeSupport.chaincodeHasBeenLaunched(key); !ok {
   298  		// Handler NOT found
   299  		return fmt.Errorf("Error deregistering handler, could not find handler with key: %s", key)
   300  	}
   301  	delete(chaincodeSupport.runningChaincodes.chaincodeMap, key)
   302  	chaincodeLogger.Debugf("Deregistered handler with key: %s", key)
   303  	return nil
   304  }
   305  
   306  // send ready to move to ready state
   307  func (chaincodeSupport *ChaincodeSupport) sendReady(context context.Context, cccid *ccprovider.CCContext, timeout time.Duration) error {
   308  	canName := cccid.GetCanonicalName()
   309  	chaincodeSupport.runningChaincodes.Lock()
   310  	//if its in the map, there must be a connected stream...nothing to do
   311  	var chrte *chaincodeRTEnv
   312  	var ok bool
   313  	if chrte, ok = chaincodeSupport.chaincodeHasBeenLaunched(canName); !ok {
   314  		chaincodeSupport.runningChaincodes.Unlock()
   315  		chaincodeLogger.Debugf("handler not found for chaincode %s", canName)
   316  		return fmt.Errorf("handler not found for chaincode %s", canName)
   317  	}
   318  	chaincodeSupport.runningChaincodes.Unlock()
   319  
   320  	var notfy chan *pb.ChaincodeMessage
   321  	var err error
   322  	if notfy, err = chrte.handler.ready(context, cccid.ChainID, cccid.TxID, cccid.SignedProposal, cccid.Proposal); err != nil {
   323  		return fmt.Errorf("Error sending %s: %s", pb.ChaincodeMessage_READY, err)
   324  	}
   325  	if notfy != nil {
   326  		select {
   327  		case ccMsg := <-notfy:
   328  			if ccMsg.Type == pb.ChaincodeMessage_ERROR {
   329  				err = fmt.Errorf("Error initializing container %s: %s", canName, string(ccMsg.Payload))
   330  			}
   331  			if ccMsg.Type == pb.ChaincodeMessage_COMPLETED {
   332  				res := &pb.Response{}
   333  				_ = proto.Unmarshal(ccMsg.Payload, res)
   334  				if res.Status != shim.OK {
   335  					err = fmt.Errorf("Error initializing container %s: %s", canName, string(res.Message))
   336  				}
   337  				// TODO
   338  				// return res so that endorser can anylyze it.
   339  			}
   340  		case <-time.After(timeout):
   341  			err = fmt.Errorf("Timeout expired while executing send init message")
   342  		}
   343  	}
   344  
   345  	//if initOrReady succeeded, our responsibility to delete the context
   346  	chrte.handler.deleteTxContext(cccid.TxID)
   347  
   348  	return err
   349  }
   350  
   351  //get args and env given chaincodeID
   352  func (chaincodeSupport *ChaincodeSupport) getArgsAndEnv(cccid *ccprovider.CCContext, cLang pb.ChaincodeSpec_Type) (args []string, envs []string, err error) {
   353  	canName := cccid.GetCanonicalName()
   354  	envs = []string{"CORE_CHAINCODE_ID_NAME=" + canName}
   355  
   356  	// ----------------------------------------------------------------------------
   357  	// Pass TLS options to chaincode
   358  	// ----------------------------------------------------------------------------
   359  	// Note: The peer certificate is only baked into the image during the build
   360  	// phase (see core/chaincode/platforms).  This logic below merely assumes the
   361  	// image is already configured appropriately and is simply toggling the feature
   362  	// on or off.  If the peer's x509 has changed since the chaincode was deployed,
   363  	// the image may be stale and the admin will need to remove the current containers
   364  	// before restarting the peer.
   365  	// ----------------------------------------------------------------------------
   366  	if chaincodeSupport.peerTLS {
   367  		envs = append(envs, "CORE_PEER_TLS_ENABLED=true")
   368  		if chaincodeSupport.peerTLSSvrHostOrd != "" {
   369  			envs = append(envs, "CORE_PEER_TLS_SERVERHOSTOVERRIDE="+chaincodeSupport.peerTLSSvrHostOrd)
   370  		}
   371  	} else {
   372  		envs = append(envs, "CORE_PEER_TLS_ENABLED=false")
   373  	}
   374  
   375  	if chaincodeSupport.chaincodeLogLevel != "" {
   376  		envs = append(envs, "CORE_CHAINCODE_LOGGING_LEVEL="+chaincodeSupport.chaincodeLogLevel)
   377  	}
   378  
   379  	if chaincodeSupport.shimLogLevel != "" {
   380  		envs = append(envs, "CORE_CHAINCODE_LOGGING_SHIM="+chaincodeSupport.shimLogLevel)
   381  	}
   382  
   383  	if chaincodeSupport.logFormat != "" {
   384  		envs = append(envs, "CORE_CHAINCODE_LOGGING_FORMAT="+chaincodeSupport.logFormat)
   385  	}
   386  	switch cLang {
   387  	case pb.ChaincodeSpec_GOLANG, pb.ChaincodeSpec_CAR:
   388  		args = []string{"chaincode", fmt.Sprintf("-peer.address=%s", chaincodeSupport.peerAddress)}
   389  	case pb.ChaincodeSpec_JAVA:
   390  		args = []string{"java", "-jar", "chaincode.jar", "--peerAddress", chaincodeSupport.peerAddress}
   391  	default:
   392  		return nil, nil, fmt.Errorf("Unknown chaincodeType: %s", cLang)
   393  	}
   394  	chaincodeLogger.Debugf("Executable is %s", args[0])
   395  	chaincodeLogger.Debugf("Args %v", args)
   396  	return args, envs, nil
   397  }
   398  
   399  // launchAndWaitForRegister will launch container if not already running. Use the targz to create the image if not found
   400  func (chaincodeSupport *ChaincodeSupport) launchAndWaitForRegister(ctxt context.Context, cccid *ccprovider.CCContext, cds *pb.ChaincodeDeploymentSpec, cLang pb.ChaincodeSpec_Type, builder api.BuildSpecFactory) error {
   401  	canName := cccid.GetCanonicalName()
   402  	if canName == "" {
   403  		return fmt.Errorf("chaincode name not set")
   404  	}
   405  
   406  	chaincodeSupport.runningChaincodes.Lock()
   407  	//if its in the map, its either up or being launched. Either case break the
   408  	//multiple launch by failing
   409  	if _, hasBeenLaunched := chaincodeSupport.chaincodeHasBeenLaunched(canName); hasBeenLaunched {
   410  		chaincodeSupport.runningChaincodes.Unlock()
   411  		return fmt.Errorf("Error chaincode is being launched: %s", canName)
   412  	}
   413  
   414  	chaincodeSupport.runningChaincodes.Unlock()
   415  
   416  	//launch the chaincode
   417  
   418  	args, env, err := chaincodeSupport.getArgsAndEnv(cccid, cLang)
   419  	if err != nil {
   420  		return err
   421  	}
   422  
   423  	chaincodeLogger.Debugf("start container: %s(networkid:%s,peerid:%s)", canName, chaincodeSupport.peerNetworkID, chaincodeSupport.peerID)
   424  	chaincodeLogger.Debugf("start container with args: %s", strings.Join(args, " "))
   425  	chaincodeLogger.Debugf("start container with env:\n\t%s", strings.Join(env, "\n\t"))
   426  
   427  	vmtype, _ := chaincodeSupport.getVMType(cds)
   428  
   429  	//set up the shadow handler JIT before container launch to
   430  	//reduce window of when an external chaincode can sneak in
   431  	//and use the launching context and make it its own
   432  	var notfy chan bool
   433  	preLaunchFunc := func() error {
   434  		notfy = chaincodeSupport.preLaunchSetup(canName)
   435  		return nil
   436  	}
   437  
   438  	sir := container.StartImageReq{CCID: ccintf.CCID{ChaincodeSpec: cds.ChaincodeSpec, NetworkID: chaincodeSupport.peerNetworkID, PeerID: chaincodeSupport.peerID, Version: cccid.Version}, Builder: builder, Args: args, Env: env, PrelaunchFunc: preLaunchFunc}
   439  
   440  	ipcCtxt := context.WithValue(ctxt, ccintf.GetCCHandlerKey(), chaincodeSupport)
   441  
   442  	resp, err := container.VMCProcess(ipcCtxt, vmtype, sir)
   443  	if err != nil || (resp != nil && resp.(container.VMCResp).Err != nil) {
   444  		if err == nil {
   445  			err = resp.(container.VMCResp).Err
   446  		}
   447  		err = fmt.Errorf("Error starting container: %s", err)
   448  		chaincodeSupport.runningChaincodes.Lock()
   449  		delete(chaincodeSupport.runningChaincodes.chaincodeMap, canName)
   450  		chaincodeSupport.runningChaincodes.Unlock()
   451  		return err
   452  	}
   453  
   454  	//wait for REGISTER state
   455  	select {
   456  	case ok := <-notfy:
   457  		if !ok {
   458  			err = fmt.Errorf("registration failed for %s(networkid:%s,peerid:%s,tx:%s)", canName, chaincodeSupport.peerNetworkID, chaincodeSupport.peerID, cccid.TxID)
   459  		}
   460  	case <-time.After(chaincodeSupport.ccStartupTimeout):
   461  		err = fmt.Errorf("Timeout expired while starting chaincode %s(networkid:%s,peerid:%s,tx:%s)", canName, chaincodeSupport.peerNetworkID, chaincodeSupport.peerID, cccid.TxID)
   462  	}
   463  	if err != nil {
   464  		chaincodeLogger.Debugf("stopping due to error while launching %s", err)
   465  		errIgnore := chaincodeSupport.Stop(ctxt, cccid, cds)
   466  		if errIgnore != nil {
   467  			chaincodeLogger.Debugf("error on stop %s(%s)", errIgnore, err)
   468  		}
   469  	}
   470  	return err
   471  }
   472  
   473  //Stop stops a chaincode if running
   474  func (chaincodeSupport *ChaincodeSupport) Stop(context context.Context, cccid *ccprovider.CCContext, cds *pb.ChaincodeDeploymentSpec) error {
   475  	canName := cccid.GetCanonicalName()
   476  	if canName == "" {
   477  		return fmt.Errorf("chaincode name not set")
   478  	}
   479  
   480  	//stop the chaincode
   481  	sir := container.StopImageReq{CCID: ccintf.CCID{ChaincodeSpec: cds.ChaincodeSpec, NetworkID: chaincodeSupport.peerNetworkID, PeerID: chaincodeSupport.peerID, Version: cccid.Version}, Timeout: 0}
   482  	// The line below is left for debugging. It replaces the line above to keep
   483  	// the chaincode container around to give you a chance to get data
   484  	//sir := container.StopImageReq{CCID: ccintf.CCID{ChaincodeSpec: cds.ChaincodeSpec, NetworkID: chaincodeSupport.peerNetworkID, PeerID: chaincodeSupport.peerID, ChainID: cccid.ChainID, Version: cccid.Version}, Timeout: 0, Dontremove: true}
   485  
   486  	vmtype, _ := chaincodeSupport.getVMType(cds)
   487  
   488  	_, err := container.VMCProcess(context, vmtype, sir)
   489  	if err != nil {
   490  		err = fmt.Errorf("Error stopping container: %s", err)
   491  		//but proceed to cleanup
   492  	}
   493  
   494  	chaincodeSupport.runningChaincodes.Lock()
   495  	if _, ok := chaincodeSupport.chaincodeHasBeenLaunched(canName); !ok {
   496  		//nothing to do
   497  		chaincodeSupport.runningChaincodes.Unlock()
   498  		return nil
   499  	}
   500  
   501  	delete(chaincodeSupport.runningChaincodes.chaincodeMap, canName)
   502  
   503  	chaincodeSupport.runningChaincodes.Unlock()
   504  
   505  	return err
   506  }
   507  
   508  // Launch will launch the chaincode if not running (if running return nil) and will wait for handler of the chaincode to get into FSM ready state.
   509  func (chaincodeSupport *ChaincodeSupport) Launch(context context.Context, cccid *ccprovider.CCContext, spec interface{}) (*pb.ChaincodeID, *pb.ChaincodeInput, error) {
   510  	//build the chaincode
   511  	var cID *pb.ChaincodeID
   512  	var cMsg *pb.ChaincodeInput
   513  
   514  	var cds *pb.ChaincodeDeploymentSpec
   515  	var ci *pb.ChaincodeInvocationSpec
   516  	if cds, _ = spec.(*pb.ChaincodeDeploymentSpec); cds == nil {
   517  		if ci, _ = spec.(*pb.ChaincodeInvocationSpec); ci == nil {
   518  			panic("Launch should be called with deployment or invocation spec")
   519  		}
   520  	}
   521  	if cds != nil {
   522  		cID = cds.ChaincodeSpec.ChaincodeId
   523  		cMsg = cds.ChaincodeSpec.Input
   524  	} else {
   525  		cID = ci.ChaincodeSpec.ChaincodeId
   526  		cMsg = ci.ChaincodeSpec.Input
   527  	}
   528  
   529  	canName := cccid.GetCanonicalName()
   530  	chaincodeSupport.runningChaincodes.Lock()
   531  	var chrte *chaincodeRTEnv
   532  	var ok bool
   533  	var err error
   534  	//if its in the map, there must be a connected stream...nothing to do
   535  	if chrte, ok = chaincodeSupport.chaincodeHasBeenLaunched(canName); ok {
   536  		if !chrte.handler.registered {
   537  			chaincodeSupport.runningChaincodes.Unlock()
   538  			chaincodeLogger.Debugf("premature execution - chaincode (%s) is being launched", canName)
   539  			err = fmt.Errorf("premature execution - chaincode (%s) is being launched", canName)
   540  			return cID, cMsg, err
   541  		}
   542  		if chrte.handler.isRunning() {
   543  			if chaincodeLogger.IsEnabledFor(logging.DEBUG) {
   544  				chaincodeLogger.Debugf("chaincode is running(no need to launch) : %s", canName)
   545  			}
   546  			chaincodeSupport.runningChaincodes.Unlock()
   547  			return cID, cMsg, nil
   548  		}
   549  		chaincodeLogger.Debugf("Container not in READY state(%s)...send init/ready", chrte.handler.FSM.Current())
   550  	}
   551  	chaincodeSupport.runningChaincodes.Unlock()
   552  
   553  	if cds == nil {
   554  		if cccid.Syscc {
   555  			return cID, cMsg, fmt.Errorf("a syscc should be running (it cannot be launched) %s", canName)
   556  		}
   557  
   558  		if chaincodeSupport.userRunsCC {
   559  			chaincodeLogger.Error("You are attempting to perform an action other than Deploy on Chaincode that is not ready and you are in developer mode. Did you forget to Deploy your chaincode?")
   560  		}
   561  
   562  		var depPayload []byte
   563  
   564  		//hopefully we are restarting from existing image and the deployed transaction exists
   565  		//this will also validate the ID from the LSCC
   566  		depPayload, err = GetCDSFromLSCC(context, cccid.TxID, cccid.SignedProposal, cccid.Proposal, cccid.ChainID, cID.Name)
   567  		if err != nil {
   568  			return cID, cMsg, fmt.Errorf("Could not get deployment transaction from LSCC for %s - %s", canName, err)
   569  		}
   570  		if depPayload == nil {
   571  			return cID, cMsg, fmt.Errorf("failed to get deployment payload %s - %s", canName, err)
   572  		}
   573  
   574  		cds = &pb.ChaincodeDeploymentSpec{}
   575  
   576  		//Get lang from original deployment
   577  		err = proto.Unmarshal(depPayload, cds)
   578  		if err != nil {
   579  			return cID, cMsg, fmt.Errorf("failed to unmarshal deployment transactions for %s - %s", canName, err)
   580  		}
   581  	}
   582  
   583  	//from here on : if we launch the container and get an error, we need to stop the container
   584  
   585  	//launch container if it is a System container or not in dev mode
   586  	if (!chaincodeSupport.userRunsCC || cds.ExecEnv == pb.ChaincodeDeploymentSpec_SYSTEM) && (chrte == nil || chrte.handler == nil) {
   587  		//NOTE-We need to streamline code a bit so the data from LSCC gets passed to this thus
   588  		//avoiding the need to go to the FS. In particular, we should use cdsfs completely. It is
   589  		//just a vestige of old protocol that we continue to use ChaincodeDeploymentSpec for
   590  		//anything other than Install. In particular, instantiate, invoke, upgrade should be using
   591  		//just some form of ChaincodeInvocationSpec.
   592  		//
   593  		//But for now, if we are invoking we have gone through the LSCC path above. If  instantiating
   594  		//or upgrading currently we send a CDS with nil CodePackage. In this case the codepath
   595  		//in the endorser has gone through LSCC validation. Just get the code from the FS.
   596  		if cds.CodePackage == nil {
   597  			//no code bytes for these situations
   598  			if !(chaincodeSupport.userRunsCC || cds.ExecEnv == pb.ChaincodeDeploymentSpec_SYSTEM) {
   599  				ccpack, err := ccprovider.GetChaincodeFromFS(cID.Name, cID.Version)
   600  				if err != nil {
   601  					return cID, cMsg, err
   602  				}
   603  
   604  				cds = ccpack.GetDepSpec()
   605  				chaincodeLogger.Debugf("launchAndWaitForRegister fetched %d bytes from file system", len(cds.CodePackage))
   606  			}
   607  		}
   608  
   609  		builder := func() (io.Reader, error) { return platforms.GenerateDockerBuild(cds) }
   610  
   611  		cLang := cds.ChaincodeSpec.Type
   612  		err = chaincodeSupport.launchAndWaitForRegister(context, cccid, cds, cLang, builder)
   613  		if err != nil {
   614  			chaincodeLogger.Errorf("launchAndWaitForRegister failed %s", err)
   615  			return cID, cMsg, err
   616  		}
   617  	}
   618  
   619  	if err == nil {
   620  		//launch will set the chaincode in Ready state
   621  		err = chaincodeSupport.sendReady(context, cccid, chaincodeSupport.ccStartupTimeout)
   622  		if err != nil {
   623  			chaincodeLogger.Errorf("sending init failed(%s)", err)
   624  			err = fmt.Errorf("Failed to init chaincode(%s)", err)
   625  			errIgnore := chaincodeSupport.Stop(context, cccid, cds)
   626  			if errIgnore != nil {
   627  				chaincodeLogger.Errorf("stop failed %s(%s)", errIgnore, err)
   628  			}
   629  		}
   630  		chaincodeLogger.Debug("sending init completed")
   631  	}
   632  
   633  	chaincodeLogger.Debug("LaunchChaincode complete")
   634  
   635  	return cID, cMsg, err
   636  }
   637  
   638  //getVMType - just returns a string for now. Another possibility is to use a factory method to
   639  //return a VM executor
   640  func (chaincodeSupport *ChaincodeSupport) getVMType(cds *pb.ChaincodeDeploymentSpec) (string, error) {
   641  	if cds.ExecEnv == pb.ChaincodeDeploymentSpec_SYSTEM {
   642  		return container.SYSTEM, nil
   643  	}
   644  	return container.DOCKER, nil
   645  }
   646  
   647  // HandleChaincodeStream implements ccintf.HandleChaincodeStream for all vms to call with appropriate stream
   648  func (chaincodeSupport *ChaincodeSupport) HandleChaincodeStream(ctxt context.Context, stream ccintf.ChaincodeStream) error {
   649  	return HandleChaincodeStream(chaincodeSupport, ctxt, stream)
   650  }
   651  
   652  // Register the bidi stream entry point called by chaincode to register with the Peer.
   653  func (chaincodeSupport *ChaincodeSupport) Register(stream pb.ChaincodeSupport_RegisterServer) error {
   654  	return chaincodeSupport.HandleChaincodeStream(stream.Context(), stream)
   655  }
   656  
   657  // createCCMessage creates a transaction message.
   658  func createCCMessage(typ pb.ChaincodeMessage_Type, txid string, cMsg *pb.ChaincodeInput) (*pb.ChaincodeMessage, error) {
   659  	payload, err := proto.Marshal(cMsg)
   660  	if err != nil {
   661  		fmt.Printf(err.Error())
   662  		return nil, err
   663  	}
   664  	return &pb.ChaincodeMessage{Type: typ, Payload: payload, Txid: txid}, nil
   665  }
   666  
   667  // Execute executes a transaction and waits for it to complete until a timeout value.
   668  func (chaincodeSupport *ChaincodeSupport) Execute(ctxt context.Context, cccid *ccprovider.CCContext, msg *pb.ChaincodeMessage, timeout time.Duration) (*pb.ChaincodeMessage, error) {
   669  	chaincodeLogger.Debugf("Entry")
   670  	defer chaincodeLogger.Debugf("Exit")
   671  	canName := cccid.GetCanonicalName()
   672  	chaincodeLogger.Debugf("chaincode canonical name: %s", canName)
   673  	chaincodeSupport.runningChaincodes.Lock()
   674  	//we expect the chaincode to be running... sanity check
   675  	chrte, ok := chaincodeSupport.chaincodeHasBeenLaunched(canName)
   676  	if !ok {
   677  		chaincodeSupport.runningChaincodes.Unlock()
   678  		chaincodeLogger.Debugf("cannot execute-chaincode is not running: %s", canName)
   679  		return nil, fmt.Errorf("Cannot execute transaction for %s", canName)
   680  	}
   681  	chaincodeSupport.runningChaincodes.Unlock()
   682  
   683  	var notfy chan *pb.ChaincodeMessage
   684  	var err error
   685  	if notfy, err = chrte.handler.sendExecuteMessage(ctxt, cccid.ChainID, msg, cccid.SignedProposal, cccid.Proposal); err != nil {
   686  		return nil, fmt.Errorf("Error sending %s: %s", msg.Type.String(), err)
   687  	}
   688  	var ccresp *pb.ChaincodeMessage
   689  	select {
   690  	case ccresp = <-notfy:
   691  		//response is sent to user or calling chaincode. ChaincodeMessage_ERROR
   692  		//are typically treated as error
   693  	case <-time.After(timeout):
   694  		err = fmt.Errorf("Timeout expired while executing transaction")
   695  	}
   696  
   697  	//our responsibility to delete transaction context if sendExecuteMessage succeeded
   698  	chrte.handler.deleteTxContext(msg.Txid)
   699  
   700  	return ccresp, err
   701  }
   702  
   703  // IsDevMode returns true if the peer was configured with development-mode enabled
   704  func IsDevMode() bool {
   705  	mode := viper.GetString("chaincode.mode")
   706  
   707  	return mode == DevModeUserRunsChaincode
   708  }