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 }