github.com/defanghe/fabric@v2.1.1+incompatible/internal/peer/lifecycle/chaincode/getinstalledpackage.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 "path/filepath" 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 lb "github.com/hyperledger/fabric-protos-go/peer/lifecycle" 17 "github.com/hyperledger/fabric/bccsp" 18 "github.com/hyperledger/fabric/core/chaincode/persistence" 19 "github.com/hyperledger/fabric/protoutil" 20 "github.com/pkg/errors" 21 "github.com/spf13/cobra" 22 "github.com/spf13/viper" 23 ) 24 25 // InstalledPackageGetter holds the dependencies needed to retrieve 26 // an installed chaincode package from a peer. 27 type InstalledPackageGetter struct { 28 Command *cobra.Command 29 Input *GetInstalledPackageInput 30 EndorserClient EndorserClient 31 Signer Signer 32 Writer Writer 33 } 34 35 // GetInstalledPackageInput holds all of the input parameters for 36 // getting an installed chaincode package from a peer. 37 type GetInstalledPackageInput struct { 38 PackageID string 39 OutputDirectory string 40 } 41 42 // Validate checks that the required parameters are provided. 43 func (i *GetInstalledPackageInput) Validate() error { 44 if i.PackageID == "" { 45 return errors.New("The required parameter 'package-id' is empty. Rerun the command with --package-id flag") 46 } 47 48 return nil 49 } 50 51 // GetInstalledPackageCmd returns the cobra command for getting an 52 // installed chaincode package from a peer. 53 func GetInstalledPackageCmd(i *InstalledPackageGetter, cryptoProvider bccsp.BCCSP) *cobra.Command { 54 chaincodeGetInstalledPackageCmd := &cobra.Command{ 55 Use: "getinstalledpackage [outputfile]", 56 Short: "Get an installed chaincode package from a peer.", 57 Long: "Get an installed chaincode package from a peer.", 58 RunE: func(cmd *cobra.Command, args []string) error { 59 if i == nil { 60 ccInput := &ClientConnectionsInput{ 61 CommandName: cmd.Name(), 62 EndorserRequired: true, 63 ChannelID: channelID, 64 PeerAddresses: peerAddresses, 65 TLSRootCertFiles: tlsRootCertFiles, 66 ConnectionProfilePath: connectionProfilePath, 67 TLSEnabled: viper.GetBool("peer.tls.enabled"), 68 } 69 70 cc, err := NewClientConnections(ccInput, cryptoProvider) 71 if err != nil { 72 return err 73 } 74 75 gipInput := &GetInstalledPackageInput{ 76 PackageID: packageID, 77 OutputDirectory: outputDirectory, 78 } 79 80 // getinstalledpackage only supports one peer connection, 81 // which is why we only wire in the first endorser 82 // client 83 i = &InstalledPackageGetter{ 84 Command: cmd, 85 EndorserClient: cc.EndorserClients[0], 86 Input: gipInput, 87 Signer: cc.Signer, 88 Writer: &persistence.FilesystemIO{}, 89 } 90 } 91 return i.Get() 92 }, 93 } 94 95 flagList := []string{ 96 "peerAddresses", 97 "tlsRootCertFiles", 98 "connectionProfile", 99 "package-id", 100 "output-directory", 101 } 102 attachFlags(chaincodeGetInstalledPackageCmd, flagList) 103 104 return chaincodeGetInstalledPackageCmd 105 } 106 107 // Get retrieves the installed chaincode package from a peer. 108 func (i *InstalledPackageGetter) Get() error { 109 if i.Command != nil { 110 // Parsing of the command line is done so silence cmd usage 111 i.Command.SilenceUsage = true 112 } 113 114 if err := i.Input.Validate(); err != nil { 115 return err 116 } 117 118 proposal, err := i.createProposal() 119 if err != nil { 120 return errors.WithMessage(err, "failed to create proposal") 121 } 122 123 signedProposal, err := signProposal(proposal, i.Signer) 124 if err != nil { 125 return errors.WithMessage(err, "failed to create signed proposal") 126 } 127 128 proposalResponse, err := i.EndorserClient.ProcessProposal(context.Background(), signedProposal) 129 if err != nil { 130 return errors.WithMessage(err, "failed to endorse proposal") 131 } 132 133 if proposalResponse == nil { 134 return errors.New("received nil proposal response") 135 } 136 137 if proposalResponse.Response == nil { 138 return errors.New("received proposal response with nil response") 139 } 140 141 if proposalResponse.Response.Status != int32(cb.Status_SUCCESS) { 142 return errors.Errorf("proposal failed with status: %d - %s", proposalResponse.Response.Status, proposalResponse.Response.Message) 143 } 144 145 return i.writePackage(proposalResponse) 146 } 147 148 func (i *InstalledPackageGetter) writePackage(proposalResponse *pb.ProposalResponse) error { 149 result := &lb.GetInstalledChaincodePackageResult{} 150 err := proto.Unmarshal(proposalResponse.Response.Payload, result) 151 if err != nil { 152 return errors.Wrap(err, "failed to unmarshal proposal response's response payload") 153 } 154 155 outputFile := filepath.Join(i.Input.OutputDirectory, i.Input.PackageID+".tar.gz") 156 157 dir, name := filepath.Split(outputFile) 158 // translate dir into absolute path 159 if dir, err = filepath.Abs(dir); err != nil { 160 return err 161 } 162 163 err = i.Writer.WriteFile(dir, name, result.ChaincodeInstallPackage) 164 if err != nil { 165 err = errors.Wrapf(err, "failed to write chaincode package to %s", outputFile) 166 logger.Error(err.Error()) 167 return err 168 } 169 170 return nil 171 } 172 173 func (i *InstalledPackageGetter) createProposal() (*pb.Proposal, error) { 174 args := &lb.GetInstalledChaincodePackageArgs{ 175 PackageId: i.Input.PackageID, 176 } 177 178 argsBytes, err := proto.Marshal(args) 179 if err != nil { 180 return nil, errors.Wrap(err, "failed to marshal args") 181 } 182 183 ccInput := &pb.ChaincodeInput{ 184 Args: [][]byte{[]byte("GetInstalledChaincodePackage"), argsBytes}, 185 } 186 187 cis := &pb.ChaincodeInvocationSpec{ 188 ChaincodeSpec: &pb.ChaincodeSpec{ 189 ChaincodeId: &pb.ChaincodeID{Name: lifecycleName}, 190 Input: ccInput, 191 }, 192 } 193 194 signerSerialized, err := i.Signer.Serialize() 195 if err != nil { 196 return nil, errors.WithMessage(err, "failed to serialize identity") 197 } 198 199 proposal, _, err := protoutil.CreateProposalFromCIS(cb.HeaderType_ENDORSER_TRANSACTION, "", cis, signerSerialized) 200 if err != nil { 201 return nil, errors.WithMessage(err, "failed to create ChaincodeInvocationSpec proposal") 202 } 203 204 return proposal, nil 205 }