github.com/anjalikarhana/fabric@v2.1.1+incompatible/internal/peer/chaincode/package.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  	"io/ioutil"
    11  
    12  	"github.com/golang/protobuf/proto"
    13  	pcommon "github.com/hyperledger/fabric-protos-go/common"
    14  	pb "github.com/hyperledger/fabric-protos-go/peer"
    15  	"github.com/hyperledger/fabric/bccsp"
    16  	"github.com/hyperledger/fabric/bccsp/factory"
    17  	"github.com/hyperledger/fabric/common/policydsl"
    18  	"github.com/hyperledger/fabric/core/common/ccpackage"
    19  	"github.com/hyperledger/fabric/internal/pkg/identity"
    20  	mspmgmt "github.com/hyperledger/fabric/msp/mgmt"
    21  	"github.com/hyperledger/fabric/protoutil"
    22  	"github.com/pkg/errors"
    23  	"github.com/spf13/cobra"
    24  )
    25  
    26  var (
    27  	chaincodePackageCmd   *cobra.Command
    28  	createSignedCCDepSpec bool
    29  	signCCDepSpec         bool
    30  	instantiationPolicy   string
    31  )
    32  
    33  const packageCmdName = "package"
    34  
    35  type ccDepSpecFactory func(spec *pb.ChaincodeSpec) (*pb.ChaincodeDeploymentSpec, error)
    36  
    37  func defaultCDSFactory(spec *pb.ChaincodeSpec) (*pb.ChaincodeDeploymentSpec, error) {
    38  	return getChaincodeDeploymentSpec(spec, true)
    39  }
    40  
    41  // Packager holds the dependencies needed to package
    42  // a chaincode and write it
    43  type Packager struct {
    44  	CDSFactory          ccDepSpecFactory
    45  	ChaincodeCmdFactory *ChaincodeCmdFactory
    46  	Command             *cobra.Command
    47  	Input               *PackageInput
    48  	CryptoProvider      bccsp.BCCSP
    49  }
    50  
    51  // PackageInput holds the input parameters for packaging a
    52  // ChaincodeInstallPackage
    53  type PackageInput struct {
    54  	Name                  string
    55  	Version               string
    56  	InstantiationPolicy   string
    57  	CreateSignedCCDepSpec bool
    58  	SignCCDepSpec         bool
    59  	OutputFile            string
    60  	Path                  string
    61  	Type                  string
    62  }
    63  
    64  // packageCmd returns the cobra command for packaging chaincode
    65  func packageCmd(cf *ChaincodeCmdFactory, cdsFact ccDepSpecFactory, p *Packager, cryptoProvider bccsp.BCCSP) *cobra.Command {
    66  	chaincodePackageCmd = &cobra.Command{
    67  		Use:       "package [outputfile]",
    68  		Short:     "Package a chaincode",
    69  		Long:      "Package a chaincode and write the package to a file.",
    70  		ValidArgs: []string{"1"},
    71  		RunE: func(cmd *cobra.Command, args []string) error {
    72  			if p == nil {
    73  				// UT will supply its own mock factory
    74  				if cdsFact == nil {
    75  					cdsFact = defaultCDSFactory
    76  				}
    77  				p = &Packager{
    78  					CDSFactory:          cdsFact,
    79  					ChaincodeCmdFactory: cf,
    80  					CryptoProvider:      cryptoProvider,
    81  				}
    82  			}
    83  			p.Command = cmd
    84  
    85  			return p.packageChaincode(args)
    86  		},
    87  	}
    88  	flagList := []string{
    89  		"lang",
    90  		"path",
    91  		"ctor",
    92  		"name",
    93  		"version",
    94  		"cc-package",
    95  		"sign",
    96  		"instantiate-policy",
    97  	}
    98  	attachFlags(chaincodePackageCmd, flagList)
    99  
   100  	return chaincodePackageCmd
   101  }
   102  
   103  // packageChaincode packages the chaincode.
   104  func (p *Packager) packageChaincode(args []string) error {
   105  	if p.Command != nil {
   106  		// Parsing of the command line is done so silence cmd usage
   107  		p.Command.SilenceUsage = true
   108  	}
   109  
   110  	if len(args) != 1 {
   111  		return errors.New("output file not specified or invalid number of args (filename should be the only arg)")
   112  	}
   113  	p.setInput(args[0])
   114  
   115  	// LSCC package
   116  	return p.packageCC()
   117  }
   118  
   119  func (p *Packager) setInput(outputFile string) {
   120  	p.Input = &PackageInput{
   121  		Name:                  chaincodeName,
   122  		Version:               chaincodeVersion,
   123  		InstantiationPolicy:   instantiationPolicy,
   124  		CreateSignedCCDepSpec: createSignedCCDepSpec,
   125  		SignCCDepSpec:         signCCDepSpec,
   126  		OutputFile:            outputFile,
   127  		Path:                  chaincodePath,
   128  		Type:                  chaincodeLang,
   129  	}
   130  }
   131  
   132  // packageCC creates the LSCC chaincode packages
   133  // (ChaincodeDeploymentSpec and SignedChaincodeDeploymentSpec)
   134  func (p *Packager) packageCC() error {
   135  	if p.CDSFactory == nil {
   136  		return errors.New("chaincode deployment spec factory not specified")
   137  	}
   138  
   139  	var err error
   140  	if p.ChaincodeCmdFactory == nil {
   141  		p.ChaincodeCmdFactory, err = InitCmdFactory(p.Command.Name(), false, false, p.CryptoProvider)
   142  		if err != nil {
   143  			return err
   144  		}
   145  	}
   146  	spec, err := getChaincodeSpec(p.Command)
   147  	if err != nil {
   148  		return err
   149  	}
   150  
   151  	cds, err := p.CDSFactory(spec)
   152  	if err != nil {
   153  		return errors.WithMessagef(err, "error getting chaincode code %s", p.Input.Name)
   154  	}
   155  
   156  	var bytesToWrite []byte
   157  	if createSignedCCDepSpec {
   158  		bytesToWrite, err = getChaincodeInstallPackage(cds, p.ChaincodeCmdFactory)
   159  		if err != nil {
   160  			return err
   161  		}
   162  	} else {
   163  		bytesToWrite = protoutil.MarshalOrPanic(cds)
   164  	}
   165  
   166  	logger.Debugf("Packaged chaincode into deployment spec of size <%d>, output file ", len(bytesToWrite), p.Input.OutputFile)
   167  	err = ioutil.WriteFile(p.Input.OutputFile, bytesToWrite, 0700)
   168  	if err != nil {
   169  		logger.Errorf("failed writing deployment spec to file [%s]: [%s]", p.Input.OutputFile, err)
   170  		return err
   171  	}
   172  
   173  	return err
   174  }
   175  
   176  func getInstantiationPolicy(policy string) (*pcommon.SignaturePolicyEnvelope, error) {
   177  	p, err := policydsl.FromString(policy)
   178  	if err != nil {
   179  		return nil, errors.WithMessagef(err, "invalid policy %s", policy)
   180  	}
   181  	return p, nil
   182  }
   183  
   184  // getChaincodeInstallPackage returns either a raw ChaincodeDeploymentSpec or
   185  // a Envelope with ChaincodeDeploymentSpec and (optional) signature
   186  func getChaincodeInstallPackage(cds *pb.ChaincodeDeploymentSpec, cf *ChaincodeCmdFactory) ([]byte, error) {
   187  	var owner identity.SignerSerializer
   188  	// check if we need to sign and set the owner
   189  	if createSignedCCDepSpec && signCCDepSpec {
   190  		if cf.Signer == nil {
   191  			return nil, errors.New("signing identity not found")
   192  		}
   193  		owner = cf.Signer
   194  	}
   195  
   196  	ip := instantiationPolicy
   197  	if ip == "" {
   198  		// if an instantiation policy is not given, default
   199  		// to "admin  must sign chaincode instantiation proposals"
   200  		mspid, err := mspmgmt.GetLocalMSP(factory.GetDefault()).GetIdentifier()
   201  		if err != nil {
   202  			return nil, err
   203  		}
   204  		ip = "AND('" + mspid + ".admin')"
   205  	}
   206  
   207  	sp, err := getInstantiationPolicy(ip)
   208  	if err != nil {
   209  		return nil, err
   210  	}
   211  
   212  	// we get the Envelope of type CHAINCODE_PACKAGE
   213  	objToWrite, err := ccpackage.OwnerCreateSignedCCDepSpec(cds, sp, owner)
   214  	if err != nil {
   215  		return nil, err
   216  	}
   217  
   218  	// convert the proto object to bytes
   219  	bytesToWrite, err := proto.Marshal(objToWrite)
   220  	if err != nil {
   221  		return nil, errors.Wrap(err, "error marshalling chaincode package")
   222  	}
   223  
   224  	return bytesToWrite, nil
   225  }