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