github.com/kchristidis/fabric@v1.0.4-0.20171028114726-837acd08cde1/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 //Unique name of the system chaincode 43 Name string 44 45 //Path to the system chaincode; currently not used 46 Path string 47 48 //InitArgs initialization arguments to startup the system chaincode 49 InitArgs [][]byte 50 51 // Chaincode is the actual chaincode object 52 Chaincode shim.Chaincode 53 54 // InvokableExternal keeps track of whether 55 // this system chaincode can be invoked 56 // through a proposal sent to this peer 57 InvokableExternal bool 58 59 // InvokableCC2CC keeps track of whether 60 // this system chaincode can be invoked 61 // by way of a chaincode-to-chaincode 62 // invocation 63 InvokableCC2CC bool 64 65 // Enabled a convenient switch to enable/disable system chaincode without 66 // having to remove entry from importsysccs.go 67 Enabled 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 }