github.com/anjalikarhana/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  }