github.com/lzy4123/fabric@v2.1.1+incompatible/internal/peer/chaincode/install.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package chaincode 8 9 import ( 10 "context" 11 "io/ioutil" 12 13 "github.com/golang/protobuf/proto" 14 cb "github.com/hyperledger/fabric-protos-go/common" 15 pb "github.com/hyperledger/fabric-protos-go/peer" 16 "github.com/hyperledger/fabric/bccsp" 17 "github.com/hyperledger/fabric/core/common/ccpackage" 18 "github.com/hyperledger/fabric/core/common/ccprovider" 19 "github.com/hyperledger/fabric/internal/peer/common" 20 "github.com/hyperledger/fabric/internal/pkg/identity" 21 "github.com/hyperledger/fabric/protoutil" 22 "github.com/pkg/errors" 23 "github.com/spf13/cobra" 24 ) 25 26 var chaincodeInstallCmd *cobra.Command 27 28 const ( 29 installCmdName = "install" 30 ) 31 32 // Installer holds the dependencies needed to install 33 // a chaincode 34 type Installer struct { 35 Command *cobra.Command 36 EndorserClients []pb.EndorserClient 37 Input *InstallInput 38 Signer identity.SignerSerializer 39 CryptoProvider bccsp.BCCSP 40 } 41 42 // InstallInput holds the input parameters for installing 43 // a chaincode 44 type InstallInput struct { 45 Name string 46 Version string 47 Language string 48 PackageFile string 49 Path string 50 } 51 52 // installCmd returns the cobra command for chaincode install 53 func installCmd(cf *ChaincodeCmdFactory, i *Installer, cryptoProvider bccsp.BCCSP) *cobra.Command { 54 chaincodeInstallCmd = &cobra.Command{ 55 Use: "install", 56 Short: "Install a chaincode.", 57 Long: "Install a chaincode on a peer. This installs a chaincode deployment spec package (if provided) or packages the specified chaincode before subsequently installing it.", 58 ValidArgs: []string{"1"}, 59 RunE: func(cmd *cobra.Command, args []string) error { 60 if i == nil { 61 var err error 62 if cf == nil { 63 cf, err = InitCmdFactory(cmd.Name(), true, false, cryptoProvider) 64 if err != nil { 65 return err 66 } 67 } 68 i = &Installer{ 69 Command: cmd, 70 EndorserClients: cf.EndorserClients, 71 Signer: cf.Signer, 72 CryptoProvider: cryptoProvider, 73 } 74 } 75 return i.installChaincode(args) 76 }, 77 } 78 flagList := []string{ 79 "lang", 80 "ctor", 81 "path", 82 "name", 83 "version", 84 "peerAddresses", 85 "tlsRootCertFiles", 86 "connectionProfile", 87 } 88 attachFlags(chaincodeInstallCmd, flagList) 89 90 return chaincodeInstallCmd 91 } 92 93 // installChaincode installs the chaincode 94 func (i *Installer) installChaincode(args []string) error { 95 if i.Command != nil { 96 // Parsing of the command line is done so silence cmd usage 97 i.Command.SilenceUsage = true 98 } 99 100 i.setInput(args) 101 102 // LSCC install 103 return i.install() 104 } 105 106 func (i *Installer) setInput(args []string) { 107 i.Input = &InstallInput{ 108 Name: chaincodeName, 109 Version: chaincodeVersion, 110 Path: chaincodePath, 111 } 112 113 if len(args) > 0 { 114 i.Input.PackageFile = args[0] 115 } 116 } 117 118 // install installs a chaincode deployment spec to "peer.address" 119 // for use with lscc 120 func (i *Installer) install() error { 121 ccPkgMsg, err := i.getChaincodePackageMessage() 122 if err != nil { 123 return err 124 } 125 126 proposal, err := i.createInstallProposal(ccPkgMsg) 127 if err != nil { 128 return err 129 } 130 131 signedProposal, err := protoutil.GetSignedProposal(proposal, i.Signer) 132 if err != nil { 133 return errors.WithMessagef(err, "error creating signed proposal for %s", chainFuncName) 134 } 135 136 return i.submitInstallProposal(signedProposal) 137 } 138 139 func (i *Installer) submitInstallProposal(signedProposal *pb.SignedProposal) error { 140 // install is currently only supported for one peer 141 proposalResponse, err := i.EndorserClients[0].ProcessProposal(context.Background(), signedProposal) 142 if err != nil { 143 return errors.WithMessage(err, "error endorsing chaincode install") 144 } 145 146 if proposalResponse == nil { 147 return errors.New("error during install: received nil proposal response") 148 } 149 150 if proposalResponse.Response == nil { 151 return errors.New("error during install: received proposal response with nil response") 152 } 153 154 if proposalResponse.Response.Status != int32(cb.Status_SUCCESS) { 155 return errors.Errorf("install failed with status: %d - %s", proposalResponse.Response.Status, proposalResponse.Response.Message) 156 } 157 logger.Infof("Installed remotely: %v", proposalResponse) 158 159 return nil 160 } 161 162 func (i *Installer) getChaincodePackageMessage() (proto.Message, error) { 163 // if no package provided, create one 164 if i.Input.PackageFile == "" { 165 if i.Input.Path == common.UndefinedParamValue || i.Input.Version == common.UndefinedParamValue || i.Input.Name == common.UndefinedParamValue { 166 return nil, errors.Errorf("must supply value for %s name, path and version parameters", chainFuncName) 167 } 168 // generate a raw ChaincodeDeploymentSpec 169 ccPkgMsg, err := genChaincodeDeploymentSpec(i.Command, i.Input.Name, i.Input.Version) 170 if err != nil { 171 return nil, err 172 } 173 return ccPkgMsg, nil 174 } 175 176 // read in a package generated by the "package" sub-command (and perhaps signed 177 // by multiple owners with the "signpackage" sub-command) 178 // var cds *pb.ChaincodeDeploymentSpec 179 ccPkgMsg, cds, err := getPackageFromFile(i.Input.PackageFile, i.CryptoProvider) 180 if err != nil { 181 return nil, err 182 } 183 184 // get the chaincode details from cds 185 cName := cds.ChaincodeSpec.ChaincodeId.Name 186 cVersion := cds.ChaincodeSpec.ChaincodeId.Version 187 188 // if user provided chaincodeName, use it for validation 189 if i.Input.Name != "" && i.Input.Name != cName { 190 return nil, errors.Errorf("chaincode name %s does not match name %s in package", i.Input.Name, cName) 191 } 192 193 // if user provided chaincodeVersion, use it for validation 194 if i.Input.Version != "" && i.Input.Version != cVersion { 195 return nil, errors.Errorf("chaincode version %s does not match version %s in packages", i.Input.Version, cVersion) 196 } 197 198 return ccPkgMsg, nil 199 } 200 201 func (i *Installer) createInstallProposal(msg proto.Message) (*pb.Proposal, error) { 202 creator, err := i.Signer.Serialize() 203 if err != nil { 204 return nil, errors.WithMessage(err, "error serializing identity") 205 } 206 207 prop, _, err := protoutil.CreateInstallProposalFromCDS(msg, creator) 208 if err != nil { 209 return nil, errors.WithMessagef(err, "error creating proposal for %s", chainFuncName) 210 } 211 212 return prop, nil 213 } 214 215 // genChaincodeDeploymentSpec creates ChaincodeDeploymentSpec as the package to install 216 func genChaincodeDeploymentSpec(cmd *cobra.Command, chaincodeName, chaincodeVersion string) (*pb.ChaincodeDeploymentSpec, error) { 217 if existed, _ := ccprovider.ChaincodePackageExists(chaincodeName, chaincodeVersion); existed { 218 return nil, errors.Errorf("chaincode %s:%s already exists", chaincodeName, chaincodeVersion) 219 } 220 221 spec, err := getChaincodeSpec(cmd) 222 if err != nil { 223 return nil, err 224 } 225 226 cds, err := getChaincodeDeploymentSpec(spec, true) 227 if err != nil { 228 return nil, errors.WithMessagef(err, "error getting chaincode deployment spec for %s", chaincodeName) 229 } 230 231 return cds, nil 232 } 233 234 // getPackageFromFile get the chaincode package from file and the extracted ChaincodeDeploymentSpec 235 func getPackageFromFile(ccPkgFile string, cryptoProvider bccsp.BCCSP) (proto.Message, *pb.ChaincodeDeploymentSpec, error) { 236 ccPkgBytes, err := ioutil.ReadFile(ccPkgFile) 237 if err != nil { 238 return nil, nil, err 239 } 240 241 // the bytes should be a valid package (CDS or SignedCDS) 242 ccpack, err := ccprovider.GetCCPackage(ccPkgBytes, cryptoProvider) 243 if err != nil { 244 return nil, nil, err 245 } 246 247 // either CDS or Envelope 248 o := ccpack.GetPackageObject() 249 250 // try CDS first 251 cds, ok := o.(*pb.ChaincodeDeploymentSpec) 252 if !ok || cds == nil { 253 // try Envelope next 254 env, ok := o.(*cb.Envelope) 255 if !ok || env == nil { 256 return nil, nil, errors.New("error extracting valid chaincode package") 257 } 258 259 // this will check for a valid package Envelope 260 _, sCDS, err := ccpackage.ExtractSignedCCDepSpec(env) 261 if err != nil { 262 return nil, nil, errors.WithMessage(err, "error extracting valid signed chaincode package") 263 } 264 265 // ...and get the CDS at last 266 cds, err = protoutil.UnmarshalChaincodeDeploymentSpec(sCDS.ChaincodeDeploymentSpec) 267 if err != nil { 268 return nil, nil, errors.WithMessage(err, "error extracting chaincode deployment spec") 269 } 270 271 err = platformRegistry.ValidateDeploymentSpec(cds.ChaincodeSpec.Type.String(), cds.CodePackage) 272 if err != nil { 273 return nil, nil, errors.WithMessage(err, "chaincode deployment spec validation failed") 274 } 275 } 276 277 return o, cds, nil 278 }