github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/core/scc/sysccapi.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 scc
    18  
    19  import (
    20  	"fmt"
    21  
    22  	"golang.org/x/net/context"
    23  
    24  	"github.com/hyperledger/fabric/common/flogging"
    25  	"github.com/hyperledger/fabric/common/util"
    26  	"github.com/hyperledger/fabric/core/chaincode/shim"
    27  	"github.com/hyperledger/fabric/core/common/ccprovider"
    28  	"github.com/hyperledger/fabric/core/container/inproccontroller"
    29  	"github.com/hyperledger/fabric/core/peer"
    30  
    31  	"github.com/spf13/viper"
    32  
    33  	pb "github.com/hyperledger/fabric/protos/peer"
    34  )
    35  
    36  var sysccLogger = flogging.MustGetLogger("sccapi")
    37  
    38  // SystemChaincode defines the metadata needed to initialize system chaincode
    39  // when the fabric comes up. SystemChaincodes are installed by adding an
    40  // entry in importsysccs.go
    41  type SystemChaincode struct {
    42  	// Enabled a convenient switch to enable/disable system chaincode without
    43  	// having to remove entry from importsysccs.go
    44  	Enabled bool
    45  
    46  	//Unique name of the system chaincode
    47  	Name string
    48  
    49  	//Path to the system chaincode; currently not used
    50  	Path string
    51  
    52  	//InitArgs initialization arguments to startup the system chaincode
    53  	InitArgs [][]byte
    54  
    55  	// Chaincode is the actual chaincode object
    56  	Chaincode shim.Chaincode
    57  
    58  	// InvokableExternal keeps track of whether
    59  	// this system chaincode can be invoked
    60  	// through a proposal sent to this peer
    61  	InvokableExternal bool
    62  
    63  	// InvokableCC2CC keeps track of whether
    64  	// this system chaincode can be invoked
    65  	// by way of a chaincode-to-chaincode
    66  	// invocation
    67  	InvokableCC2CC bool
    68  }
    69  
    70  // RegisterSysCC registers the given system chaincode with the peer
    71  func RegisterSysCC(syscc *SystemChaincode) error {
    72  	if !syscc.Enabled || !isWhitelisted(syscc) {
    73  		sysccLogger.Info(fmt.Sprintf("system chaincode (%s,%s,%t) disabled", syscc.Name, syscc.Path, syscc.Enabled))
    74  		return nil
    75  	}
    76  
    77  	err := inproccontroller.Register(syscc.Path, syscc.Chaincode)
    78  	if err != nil {
    79  		//if the type is registered, the instance may not be... keep going
    80  		if _, ok := err.(inproccontroller.SysCCRegisteredErr); !ok {
    81  			errStr := fmt.Sprintf("could not register (%s,%v): %s", syscc.Path, syscc, err)
    82  			sysccLogger.Error(errStr)
    83  			return fmt.Errorf(errStr)
    84  		}
    85  	}
    86  
    87  	sysccLogger.Infof("system chaincode %s(%s) registered", syscc.Name, syscc.Path)
    88  	return err
    89  }
    90  
    91  // deploySysCC deploys the given system chaincode on a chain
    92  func deploySysCC(chainID string, syscc *SystemChaincode) error {
    93  	if !syscc.Enabled || !isWhitelisted(syscc) {
    94  		sysccLogger.Info(fmt.Sprintf("system chaincode (%s,%s) disabled", syscc.Name, syscc.Path))
    95  		return nil
    96  	}
    97  
    98  	var err error
    99  
   100  	ccprov := ccprovider.GetChaincodeProvider()
   101  
   102  	ctxt := context.Background()
   103  	if chainID != "" {
   104  		lgr := peer.GetLedger(chainID)
   105  		if lgr == nil {
   106  			panic(fmt.Sprintf("syschain %s start up failure - unexpected nil ledger for channel %s", syscc.Name, chainID))
   107  		}
   108  
   109  		_, err := ccprov.GetContext(lgr)
   110  		if err != nil {
   111  			return err
   112  		}
   113  
   114  		defer ccprov.ReleaseContext()
   115  	}
   116  
   117  	chaincodeID := &pb.ChaincodeID{Path: syscc.Path, Name: syscc.Name}
   118  	spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeId: chaincodeID, Input: &pb.ChaincodeInput{Args: syscc.InitArgs}}
   119  
   120  	// First build and get the deployment spec
   121  	chaincodeDeploymentSpec, err := buildSysCC(ctxt, spec)
   122  
   123  	if err != nil {
   124  		sysccLogger.Error(fmt.Sprintf("Error deploying chaincode spec: %v\n\n error: %s", spec, err))
   125  		return err
   126  	}
   127  
   128  	txid := util.GenerateUUID()
   129  
   130  	version := util.GetSysCCVersion()
   131  
   132  	cccid := ccprov.GetCCContext(chainID, chaincodeDeploymentSpec.ChaincodeSpec.ChaincodeId.Name, version, txid, true, nil, nil)
   133  
   134  	_, _, err = ccprov.ExecuteWithErrorFilter(ctxt, cccid, chaincodeDeploymentSpec)
   135  
   136  	sysccLogger.Infof("system chaincode %s/%s(%s) deployed", syscc.Name, chainID, syscc.Path)
   137  
   138  	return err
   139  }
   140  
   141  // DeDeploySysCC stops the system chaincode and deregisters it from inproccontroller
   142  func DeDeploySysCC(chainID string, syscc *SystemChaincode) error {
   143  	chaincodeID := &pb.ChaincodeID{Path: syscc.Path, Name: syscc.Name}
   144  	spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeId: chaincodeID, Input: &pb.ChaincodeInput{Args: syscc.InitArgs}}
   145  
   146  	ctx := context.Background()
   147  	// First build and get the deployment spec
   148  	chaincodeDeploymentSpec, err := buildSysCC(ctx, spec)
   149  
   150  	if err != nil {
   151  		sysccLogger.Error(fmt.Sprintf("Error deploying chaincode spec: %v\n\n error: %s", spec, err))
   152  		return err
   153  	}
   154  
   155  	ccprov := ccprovider.GetChaincodeProvider()
   156  
   157  	version := util.GetSysCCVersion()
   158  
   159  	cccid := ccprov.GetCCContext(chainID, syscc.Name, version, "", true, nil, nil)
   160  
   161  	err = ccprov.Stop(ctx, cccid, chaincodeDeploymentSpec)
   162  
   163  	return err
   164  }
   165  
   166  // buildLocal builds a given chaincode code
   167  func buildSysCC(context context.Context, spec *pb.ChaincodeSpec) (*pb.ChaincodeDeploymentSpec, error) {
   168  	var codePackageBytes []byte
   169  	chaincodeDeploymentSpec := &pb.ChaincodeDeploymentSpec{ExecEnv: pb.ChaincodeDeploymentSpec_SYSTEM, ChaincodeSpec: spec, CodePackage: codePackageBytes}
   170  	return chaincodeDeploymentSpec, nil
   171  }
   172  
   173  func isWhitelisted(syscc *SystemChaincode) bool {
   174  	chaincodes := viper.GetStringMapString("chaincode.system")
   175  	val, ok := chaincodes[syscc.Name]
   176  	enabled := val == "enable" || val == "true" || val == "yes"
   177  	return ok && enabled
   178  }