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  }