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