github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/internal/peer/lifecycle/chaincode/getinstalledpackage.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  	"path/filepath"
    12  
    13  	"github.com/golang/protobuf/proto"
    14  	"github.com/hechain20/hechain/bccsp"
    15  	"github.com/hechain20/hechain/core/chaincode/persistence"
    16  	"github.com/hechain20/hechain/protoutil"
    17  	cb "github.com/hyperledger/fabric-protos-go/common"
    18  	pb "github.com/hyperledger/fabric-protos-go/peer"
    19  	lb "github.com/hyperledger/fabric-protos-go/peer/lifecycle"
    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  					PeerAddresses:         peerAddresses,
    64  					TLSRootCertFiles:      tlsRootCertFiles,
    65  					ConnectionProfilePath: connectionProfilePath,
    66  					TargetPeer:            targetPeer,
    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  		"targetPeer",
   100  		"package-id",
   101  		"output-directory",
   102  	}
   103  	attachFlags(chaincodeGetInstalledPackageCmd, flagList)
   104  
   105  	return chaincodeGetInstalledPackageCmd
   106  }
   107  
   108  // Get retrieves the installed chaincode package from a peer.
   109  func (i *InstalledPackageGetter) Get() error {
   110  	if i.Command != nil {
   111  		// Parsing of the command line is done so silence cmd usage
   112  		i.Command.SilenceUsage = true
   113  	}
   114  
   115  	if err := i.Input.Validate(); err != nil {
   116  		return err
   117  	}
   118  
   119  	proposal, err := i.createProposal()
   120  	if err != nil {
   121  		return errors.WithMessage(err, "failed to create proposal")
   122  	}
   123  
   124  	signedProposal, err := signProposal(proposal, i.Signer)
   125  	if err != nil {
   126  		return errors.WithMessage(err, "failed to create signed proposal")
   127  	}
   128  
   129  	proposalResponse, err := i.EndorserClient.ProcessProposal(context.Background(), signedProposal)
   130  	if err != nil {
   131  		return errors.WithMessage(err, "failed to endorse proposal")
   132  	}
   133  
   134  	if proposalResponse == nil {
   135  		return errors.New("received nil proposal response")
   136  	}
   137  
   138  	if proposalResponse.Response == nil {
   139  		return errors.New("received proposal response with nil response")
   140  	}
   141  
   142  	if proposalResponse.Response.Status != int32(cb.Status_SUCCESS) {
   143  		return errors.Errorf("proposal failed with status: %d - %s", proposalResponse.Response.Status, proposalResponse.Response.Message)
   144  	}
   145  
   146  	return i.writePackage(proposalResponse)
   147  }
   148  
   149  func (i *InstalledPackageGetter) writePackage(proposalResponse *pb.ProposalResponse) error {
   150  	result := &lb.GetInstalledChaincodePackageResult{}
   151  	err := proto.Unmarshal(proposalResponse.Response.Payload, result)
   152  	if err != nil {
   153  		return errors.Wrap(err, "failed to unmarshal proposal response's response payload")
   154  	}
   155  
   156  	outputFile := filepath.Join(i.Input.OutputDirectory, i.Input.PackageID+".tar.gz")
   157  
   158  	dir, name := filepath.Split(outputFile)
   159  	// translate dir into absolute path
   160  	if dir, err = filepath.Abs(dir); err != nil {
   161  		return err
   162  	}
   163  
   164  	err = i.Writer.WriteFile(dir, name, result.ChaincodeInstallPackage)
   165  	if err != nil {
   166  		err = errors.Wrapf(err, "failed to write chaincode package to %s", outputFile)
   167  		logger.Error(err.Error())
   168  		return err
   169  	}
   170  
   171  	return nil
   172  }
   173  
   174  func (i *InstalledPackageGetter) createProposal() (*pb.Proposal, error) {
   175  	args := &lb.GetInstalledChaincodePackageArgs{
   176  		PackageId: i.Input.PackageID,
   177  	}
   178  
   179  	argsBytes, err := proto.Marshal(args)
   180  	if err != nil {
   181  		return nil, errors.Wrap(err, "failed to marshal args")
   182  	}
   183  
   184  	ccInput := &pb.ChaincodeInput{
   185  		Args: [][]byte{[]byte("GetInstalledChaincodePackage"), argsBytes},
   186  	}
   187  
   188  	cis := &pb.ChaincodeInvocationSpec{
   189  		ChaincodeSpec: &pb.ChaincodeSpec{
   190  			ChaincodeId: &pb.ChaincodeID{Name: lifecycleName},
   191  			Input:       ccInput,
   192  		},
   193  	}
   194  
   195  	signerSerialized, err := i.Signer.Serialize()
   196  	if err != nil {
   197  		return nil, errors.WithMessage(err, "failed to serialize identity")
   198  	}
   199  
   200  	proposal, _, err := protoutil.CreateProposalFromCIS(cb.HeaderType_ENDORSER_TRANSACTION, "", cis, signerSerialized)
   201  	if err != nil {
   202  		return nil, errors.WithMessage(err, "failed to create ChaincodeInvocationSpec proposal")
   203  	}
   204  
   205  	return proposal, nil
   206  }