github.com/lzy4123/fabric@v2.1.1+incompatible/internal/peer/lifecycle/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 12 "github.com/golang/protobuf/proto" 13 cb "github.com/hyperledger/fabric-protos-go/common" 14 pb "github.com/hyperledger/fabric-protos-go/peer" 15 lb "github.com/hyperledger/fabric-protos-go/peer/lifecycle" 16 "github.com/hyperledger/fabric/bccsp" 17 "github.com/hyperledger/fabric/core/chaincode/persistence" 18 "github.com/hyperledger/fabric/protoutil" 19 "github.com/pkg/errors" 20 "github.com/spf13/cobra" 21 "github.com/spf13/viper" 22 ) 23 24 // Reader defines the interface needed for reading a file. 25 type Reader interface { 26 ReadFile(string) ([]byte, error) 27 } 28 29 // Installer holds the dependencies needed to install 30 // a chaincode. 31 type Installer struct { 32 Command *cobra.Command 33 EndorserClient EndorserClient 34 Input *InstallInput 35 Reader Reader 36 Signer Signer 37 } 38 39 // InstallInput holds the input parameters for installing 40 // a chaincode. 41 type InstallInput struct { 42 PackageFile string 43 } 44 45 // Validate checks that the required install parameters 46 // are provided. 47 func (i *InstallInput) Validate() error { 48 if i.PackageFile == "" { 49 return errors.New("chaincode install package must be provided") 50 } 51 52 return nil 53 } 54 55 // InstallCmd returns the cobra command for chaincode install. 56 func InstallCmd(i *Installer, cryptoProvider bccsp.BCCSP) *cobra.Command { 57 chaincodeInstallCmd := &cobra.Command{ 58 Use: "install", 59 Short: "Install a chaincode.", 60 Long: "Install a chaincode on a peer.", 61 ValidArgs: []string{"1"}, 62 RunE: func(cmd *cobra.Command, args []string) error { 63 if i == nil { 64 ccInput := &ClientConnectionsInput{ 65 CommandName: cmd.Name(), 66 EndorserRequired: true, 67 ChannelID: channelID, 68 PeerAddresses: peerAddresses, 69 TLSRootCertFiles: tlsRootCertFiles, 70 ConnectionProfilePath: connectionProfilePath, 71 TLSEnabled: viper.GetBool("peer.tls.enabled"), 72 } 73 c, err := NewClientConnections(ccInput, cryptoProvider) 74 if err != nil { 75 return err 76 } 77 78 // install is currently only supported for one peer so just use 79 // the first endorser client 80 i = &Installer{ 81 Command: cmd, 82 EndorserClient: c.EndorserClients[0], 83 Reader: &persistence.FilesystemIO{}, 84 Signer: c.Signer, 85 } 86 } 87 return i.InstallChaincode(args) 88 }, 89 } 90 flagList := []string{ 91 "peerAddresses", 92 "tlsRootCertFiles", 93 "connectionProfile", 94 } 95 attachFlags(chaincodeInstallCmd, flagList) 96 97 return chaincodeInstallCmd 98 } 99 100 // InstallChaincode installs the chaincode. 101 func (i *Installer) InstallChaincode(args []string) error { 102 if i.Command != nil { 103 // Parsing of the command line is done so silence cmd usage 104 i.Command.SilenceUsage = true 105 } 106 107 i.setInput(args) 108 109 return i.Install() 110 } 111 112 func (i *Installer) setInput(args []string) { 113 i.Input = &InstallInput{} 114 115 if len(args) > 0 { 116 i.Input.PackageFile = args[0] 117 } 118 } 119 120 // Install installs a chaincode for use with _lifecycle. 121 func (i *Installer) Install() error { 122 err := i.Input.Validate() 123 if err != nil { 124 return err 125 } 126 127 pkgBytes, err := i.Reader.ReadFile(i.Input.PackageFile) 128 if err != nil { 129 return errors.WithMessagef(err, "failed to read chaincode package at '%s'", i.Input.PackageFile) 130 } 131 132 serializedSigner, err := i.Signer.Serialize() 133 if err != nil { 134 return errors.Wrap(err, "failed to serialize signer") 135 } 136 137 proposal, err := i.createInstallProposal(pkgBytes, serializedSigner) 138 if err != nil { 139 return err 140 } 141 142 signedProposal, err := signProposal(proposal, i.Signer) 143 if err != nil { 144 return errors.WithMessage(err, "failed to create signed proposal for chaincode install") 145 } 146 147 return i.submitInstallProposal(signedProposal) 148 } 149 150 func (i *Installer) submitInstallProposal(signedProposal *pb.SignedProposal) error { 151 proposalResponse, err := i.EndorserClient.ProcessProposal(context.Background(), signedProposal) 152 if err != nil { 153 return errors.WithMessage(err, "failed to endorse chaincode install") 154 } 155 156 if proposalResponse == nil { 157 return errors.New("chaincode install failed: received nil proposal response") 158 } 159 160 if proposalResponse.Response == nil { 161 return errors.New("chaincode install failed: received proposal response with nil response") 162 } 163 164 if proposalResponse.Response.Status != int32(cb.Status_SUCCESS) { 165 return errors.Errorf("chaincode install failed with status: %d - %s", proposalResponse.Response.Status, proposalResponse.Response.Message) 166 } 167 logger.Infof("Installed remotely: %v", proposalResponse) 168 169 icr := &lb.InstallChaincodeResult{} 170 err = proto.Unmarshal(proposalResponse.Response.Payload, icr) 171 if err != nil { 172 return errors.Wrap(err, "failed to unmarshal proposal response's response payload") 173 } 174 logger.Infof("Chaincode code package identifier: %s", icr.PackageId) 175 176 return nil 177 } 178 179 func (i *Installer) createInstallProposal(pkgBytes []byte, creatorBytes []byte) (*pb.Proposal, error) { 180 installChaincodeArgs := &lb.InstallChaincodeArgs{ 181 ChaincodeInstallPackage: pkgBytes, 182 } 183 184 installChaincodeArgsBytes, err := proto.Marshal(installChaincodeArgs) 185 if err != nil { 186 return nil, errors.Wrap(err, "failed to marshal InstallChaincodeArgs") 187 } 188 189 ccInput := &pb.ChaincodeInput{Args: [][]byte{[]byte("InstallChaincode"), installChaincodeArgsBytes}} 190 191 cis := &pb.ChaincodeInvocationSpec{ 192 ChaincodeSpec: &pb.ChaincodeSpec{ 193 ChaincodeId: &pb.ChaincodeID{Name: lifecycleName}, 194 Input: ccInput, 195 }, 196 } 197 198 proposal, _, err := protoutil.CreateProposalFromCIS(cb.HeaderType_ENDORSER_TRANSACTION, "", cis, creatorBytes) 199 if err != nil { 200 return nil, errors.WithMessage(err, "failed to create proposal for ChaincodeInvocationSpec") 201 } 202 203 return proposal, nil 204 }