github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/internal/peer/lifecycle/chaincode/install.go (about) 1 /* 2 Copyright hechain. 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 "github.com/hechain20/hechain/bccsp" 14 "github.com/hechain20/hechain/core/chaincode/persistence" 15 "github.com/hechain20/hechain/protoutil" 16 cb "github.com/hyperledger/fabric-protos-go/common" 17 pb "github.com/hyperledger/fabric-protos-go/peer" 18 lb "github.com/hyperledger/fabric-protos-go/peer/lifecycle" 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 PeerAddresses: peerAddresses, 68 TLSRootCertFiles: tlsRootCertFiles, 69 ConnectionProfilePath: connectionProfilePath, 70 TargetPeer: targetPeer, 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 "targetPeer", 95 } 96 attachFlags(chaincodeInstallCmd, flagList) 97 98 return chaincodeInstallCmd 99 } 100 101 // InstallChaincode installs the chaincode. 102 func (i *Installer) InstallChaincode(args []string) error { 103 if i.Command != nil { 104 // Parsing of the command line is done so silence cmd usage 105 i.Command.SilenceUsage = true 106 } 107 108 i.setInput(args) 109 110 return i.Install() 111 } 112 113 func (i *Installer) setInput(args []string) { 114 i.Input = &InstallInput{} 115 116 if len(args) > 0 { 117 i.Input.PackageFile = args[0] 118 } 119 } 120 121 // Install installs a chaincode for use with _lifecycle. 122 func (i *Installer) Install() error { 123 err := i.Input.Validate() 124 if err != nil { 125 return err 126 } 127 128 pkgBytes, err := i.Reader.ReadFile(i.Input.PackageFile) 129 if err != nil { 130 return errors.WithMessagef(err, "failed to read chaincode package at '%s'", i.Input.PackageFile) 131 } 132 133 serializedSigner, err := i.Signer.Serialize() 134 if err != nil { 135 return errors.Wrap(err, "failed to serialize signer") 136 } 137 138 proposal, err := i.createInstallProposal(pkgBytes, serializedSigner) 139 if err != nil { 140 return err 141 } 142 143 signedProposal, err := signProposal(proposal, i.Signer) 144 if err != nil { 145 return errors.WithMessage(err, "failed to create signed proposal for chaincode install") 146 } 147 148 return i.submitInstallProposal(signedProposal) 149 } 150 151 func (i *Installer) submitInstallProposal(signedProposal *pb.SignedProposal) error { 152 proposalResponse, err := i.EndorserClient.ProcessProposal(context.Background(), signedProposal) 153 if err != nil { 154 return errors.WithMessage(err, "failed to endorse chaincode install") 155 } 156 157 if proposalResponse == nil { 158 return errors.New("chaincode install failed: received nil proposal response") 159 } 160 161 if proposalResponse.Response == nil { 162 return errors.New("chaincode install failed: received proposal response with nil response") 163 } 164 165 if proposalResponse.Response.Status != int32(cb.Status_SUCCESS) { 166 return errors.Errorf("chaincode install failed with status: %d - %s", proposalResponse.Response.Status, proposalResponse.Response.Message) 167 } 168 logger.Infof("Installed remotely: %v", proposalResponse) 169 170 icr := &lb.InstallChaincodeResult{} 171 err = proto.Unmarshal(proposalResponse.Response.Payload, icr) 172 if err != nil { 173 return errors.Wrap(err, "failed to unmarshal proposal response's response payload") 174 } 175 logger.Infof("Chaincode code package identifier: %s", icr.PackageId) 176 177 return nil 178 } 179 180 func (i *Installer) createInstallProposal(pkgBytes []byte, creatorBytes []byte) (*pb.Proposal, error) { 181 installChaincodeArgs := &lb.InstallChaincodeArgs{ 182 ChaincodeInstallPackage: pkgBytes, 183 } 184 185 installChaincodeArgsBytes, err := proto.Marshal(installChaincodeArgs) 186 if err != nil { 187 return nil, errors.Wrap(err, "failed to marshal InstallChaincodeArgs") 188 } 189 190 ccInput := &pb.ChaincodeInput{Args: [][]byte{[]byte("InstallChaincode"), installChaincodeArgsBytes}} 191 192 cis := &pb.ChaincodeInvocationSpec{ 193 ChaincodeSpec: &pb.ChaincodeSpec{ 194 ChaincodeId: &pb.ChaincodeID{Name: lifecycleName}, 195 Input: ccInput, 196 }, 197 } 198 199 proposal, _, err := protoutil.CreateProposalFromCIS(cb.HeaderType_ENDORSER_TRANSACTION, "", cis, creatorBytes) 200 if err != nil { 201 return nil, errors.WithMessage(err, "failed to create proposal for ChaincodeInvocationSpec") 202 } 203 204 return proposal, nil 205 }