github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/core/common/ccprovider/sigcdspackage.go (about)

     1  /*
     2  Copyright IBM Corp. 2017 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  		 http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package ccprovider
    18  
    19  import (
    20  	"fmt"
    21  	"io/ioutil"
    22  	"os"
    23  
    24  	"github.com/golang/protobuf/proto"
    25  
    26  	"bytes"
    27  
    28  	"github.com/hyperledger/fabric/bccsp"
    29  	"github.com/hyperledger/fabric/bccsp/factory"
    30  	"github.com/hyperledger/fabric/core/common/ccpackage"
    31  	"github.com/hyperledger/fabric/protos/common"
    32  	pb "github.com/hyperledger/fabric/protos/peer"
    33  )
    34  
    35  //----- SignedCDSData ------
    36  
    37  //SignedCDSData is data stored in the LSCC on instantiation of a CC
    38  //for SignedCDSPackage. This needs to be serialized for ChaincodeData
    39  //hence the protobuf format
    40  type SignedCDSData struct {
    41  	CodeHash      []byte `protobuf:"bytes,1,opt,name=hash"`
    42  	MetaDataHash  []byte `protobuf:"bytes,2,opt,name=metadatahash"`
    43  	SignatureHash []byte `protobuf:"bytes,3,opt,name=signaturehash"`
    44  }
    45  
    46  //----implement functions needed from proto.Message for proto's mar/unmarshal functions
    47  
    48  //Reset resets
    49  func (data *SignedCDSData) Reset() { *data = SignedCDSData{} }
    50  
    51  //String converts to string
    52  func (data *SignedCDSData) String() string { return proto.CompactTextString(data) }
    53  
    54  //ProtoMessage just exists to make proto happy
    55  func (*SignedCDSData) ProtoMessage() {}
    56  
    57  //Equals data equals other
    58  func (data *SignedCDSData) Equals(other *SignedCDSData) bool {
    59  	return other != nil &&
    60  		bytes.Equal(data.CodeHash, other.CodeHash) &&
    61  		bytes.Equal(data.MetaDataHash, other.MetaDataHash) &&
    62  		bytes.Equal(data.SignatureHash, other.SignatureHash)
    63  }
    64  
    65  //-------- SignedCDSPackage ---------
    66  
    67  //SignedCDSPackage encapsulates SignedChaincodeDeploymentSpec.
    68  type SignedCDSPackage struct {
    69  	buf      []byte
    70  	depSpec  *pb.ChaincodeDeploymentSpec
    71  	sDepSpec *pb.SignedChaincodeDeploymentSpec
    72  	env      *common.Envelope
    73  	data     *SignedCDSData
    74  	datab    []byte
    75  	id       []byte
    76  }
    77  
    78  // resets data
    79  func (ccpack *SignedCDSPackage) reset() {
    80  	*ccpack = SignedCDSPackage{}
    81  }
    82  
    83  // GetId gets the fingerprint of the chaincode based on package computation
    84  func (ccpack *SignedCDSPackage) GetId() []byte {
    85  	//this has to be after creating a package and initializing it
    86  	//If those steps fail, GetId() should never be called
    87  	if ccpack.id == nil {
    88  		panic("GetId called on uninitialized package")
    89  	}
    90  	return ccpack.id
    91  }
    92  
    93  // GetDepSpec gets the ChaincodeDeploymentSpec from the package
    94  func (ccpack *SignedCDSPackage) GetDepSpec() *pb.ChaincodeDeploymentSpec {
    95  	//this has to be after creating a package and initializing it
    96  	//If those steps fail, GetDepSpec() should never be called
    97  	if ccpack.depSpec == nil {
    98  		panic("GetDepSpec called on uninitialized package")
    99  	}
   100  	return ccpack.depSpec
   101  }
   102  
   103  // GetInstantiationPolicy gets the instantiation policy from the package
   104  func (ccpack *SignedCDSPackage) GetInstantiationPolicy() []byte {
   105  	if ccpack.sDepSpec == nil {
   106  		panic("GetInstantiationPolicy called on uninitialized package")
   107  	}
   108  	return ccpack.sDepSpec.InstantiationPolicy
   109  }
   110  
   111  // GetDepSpecBytes gets the serialized ChaincodeDeploymentSpec from the package
   112  func (ccpack *SignedCDSPackage) GetDepSpecBytes() []byte {
   113  	//this has to be after creating a package and initializing it
   114  	//If those steps fail, GetDepSpecBytes() should never be called
   115  	if ccpack.sDepSpec == nil || ccpack.sDepSpec.ChaincodeDeploymentSpec == nil {
   116  		panic("GetDepSpecBytes called on uninitialized package")
   117  	}
   118  	return ccpack.sDepSpec.ChaincodeDeploymentSpec
   119  }
   120  
   121  // GetPackageObject gets the ChaincodeDeploymentSpec as proto.Message
   122  func (ccpack *SignedCDSPackage) GetPackageObject() proto.Message {
   123  	return ccpack.env
   124  }
   125  
   126  // GetChaincodeData gets the ChaincodeData
   127  func (ccpack *SignedCDSPackage) GetChaincodeData() *ChaincodeData {
   128  	//this has to be after creating a package and initializing it
   129  	//If those steps fail, GetChaincodeData() should never be called
   130  	if ccpack.depSpec == nil || ccpack.datab == nil || ccpack.id == nil {
   131  		panic("GetChaincodeData called on uninitialized package")
   132  	}
   133  
   134  	var instPolicy []byte
   135  	if ccpack.sDepSpec != nil {
   136  		instPolicy = ccpack.sDepSpec.InstantiationPolicy
   137  	}
   138  
   139  	return &ChaincodeData{
   140  		Name:                ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name,
   141  		Version:             ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version,
   142  		Data:                ccpack.datab,
   143  		Id:                  ccpack.id,
   144  		InstantiationPolicy: instPolicy,
   145  	}
   146  }
   147  
   148  func (ccpack *SignedCDSPackage) getCDSData(scds *pb.SignedChaincodeDeploymentSpec) ([]byte, []byte, *SignedCDSData, error) {
   149  	// check for nil argument. It is an assertion that getCDSData
   150  	// is never called on a package that did not go through/succeed
   151  	// package initialization.
   152  	if scds == nil {
   153  		panic("nil cds")
   154  	}
   155  
   156  	cds := &pb.ChaincodeDeploymentSpec{}
   157  	err := proto.Unmarshal(scds.ChaincodeDeploymentSpec, cds)
   158  	if err != nil {
   159  		return nil, nil, nil, err
   160  	}
   161  
   162  	if err = factory.InitFactories(nil); err != nil {
   163  		return nil, nil, nil, fmt.Errorf("Internal error, BCCSP could not be initialized : %s", err)
   164  	}
   165  
   166  	//get the hash object
   167  	hash, err := factory.GetDefault().GetHash(&bccsp.SHAOpts{})
   168  	if err != nil {
   169  		return nil, nil, nil, err
   170  	}
   171  
   172  	scdsdata := &SignedCDSData{}
   173  
   174  	//get the code hash
   175  	hash.Write(cds.CodePackage)
   176  	scdsdata.CodeHash = hash.Sum(nil)
   177  
   178  	hash.Reset()
   179  
   180  	//get the metadata hash
   181  	hash.Write([]byte(cds.ChaincodeSpec.ChaincodeId.Name))
   182  	hash.Write([]byte(cds.ChaincodeSpec.ChaincodeId.Version))
   183  
   184  	scdsdata.MetaDataHash = hash.Sum(nil)
   185  
   186  	hash.Reset()
   187  
   188  	//get the signature hashes
   189  	if scds.InstantiationPolicy == nil {
   190  		return nil, nil, nil, fmt.Errorf("instantiation policy cannot be nil for chaincode (%s:%s)", cds.ChaincodeSpec.ChaincodeId.Name, cds.ChaincodeSpec.ChaincodeId.Version)
   191  	}
   192  
   193  	hash.Write(scds.InstantiationPolicy)
   194  	for _, o := range scds.OwnerEndorsements {
   195  		hash.Write(o.Endorser)
   196  	}
   197  	scdsdata.SignatureHash = hash.Sum(nil)
   198  
   199  	//marshall data
   200  	b, err := proto.Marshal(scdsdata)
   201  	if err != nil {
   202  		return nil, nil, nil, err
   203  	}
   204  
   205  	hash.Reset()
   206  
   207  	//compute the id
   208  	hash.Write(scdsdata.CodeHash)
   209  	hash.Write(scdsdata.MetaDataHash)
   210  	hash.Write(scdsdata.SignatureHash)
   211  
   212  	id := hash.Sum(nil)
   213  
   214  	return b, id, scdsdata, nil
   215  }
   216  
   217  // ValidateCC returns error if the chaincode is not found or if its not a
   218  // ChaincodeDeploymentSpec
   219  func (ccpack *SignedCDSPackage) ValidateCC(ccdata *ChaincodeData) error {
   220  	if ccpack.sDepSpec == nil {
   221  		return fmt.Errorf("uninitialized package")
   222  	}
   223  
   224  	if ccpack.sDepSpec.ChaincodeDeploymentSpec == nil {
   225  		return fmt.Errorf("signed chaincode deployment spec cannot be nil in a package")
   226  	}
   227  
   228  	if ccpack.depSpec == nil {
   229  		return fmt.Errorf("chaincode deployment spec cannot be nil in a package")
   230  	}
   231  
   232  	if ccdata.Name != ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name || ccdata.Version != ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version {
   233  		return fmt.Errorf("invalid chaincode data %v (%v)", ccdata, ccpack.depSpec.ChaincodeSpec.ChaincodeId)
   234  	}
   235  
   236  	otherdata := &SignedCDSData{}
   237  	err := proto.Unmarshal(ccdata.Data, otherdata)
   238  	if err != nil {
   239  		return err
   240  	}
   241  
   242  	if !ccpack.data.Equals(otherdata) {
   243  		return fmt.Errorf("data mismatch")
   244  	}
   245  
   246  	return nil
   247  }
   248  
   249  //InitFromBuffer sets the buffer if valid and returns ChaincodeData
   250  func (ccpack *SignedCDSPackage) InitFromBuffer(buf []byte) (*ChaincodeData, error) {
   251  	//incase ccpack is reused
   252  	ccpack.reset()
   253  
   254  	env := &common.Envelope{}
   255  	err := proto.Unmarshal(buf, env)
   256  	if err != nil {
   257  		return nil, fmt.Errorf("failed to unmarshal envelope from bytes")
   258  	}
   259  	cHdr, sDepSpec, err := ccpackage.ExtractSignedCCDepSpec(env)
   260  	if err != nil {
   261  		return nil, err
   262  	}
   263  	if cHdr.Type != int32(common.HeaderType_CHAINCODE_PACKAGE) {
   264  		return nil, fmt.Errorf("invalid type of envelope for chaincode package")
   265  	}
   266  
   267  	depSpec := &pb.ChaincodeDeploymentSpec{}
   268  	err = proto.Unmarshal(sDepSpec.ChaincodeDeploymentSpec, depSpec)
   269  	if err != nil {
   270  		return nil, fmt.Errorf("error getting deployment spec")
   271  	}
   272  
   273  	databytes, id, data, err := ccpack.getCDSData(sDepSpec)
   274  	if err != nil {
   275  		return nil, err
   276  	}
   277  
   278  	ccpack.buf = buf
   279  	ccpack.sDepSpec = sDepSpec
   280  	ccpack.depSpec = depSpec
   281  	ccpack.env = env
   282  	ccpack.data = data
   283  	ccpack.datab = databytes
   284  	ccpack.id = id
   285  
   286  	return ccpack.GetChaincodeData(), nil
   287  }
   288  
   289  //InitFromFS returns the chaincode and its package from the file system
   290  func (ccpack *SignedCDSPackage) InitFromFS(ccname string, ccversion string) ([]byte, *pb.ChaincodeDeploymentSpec, error) {
   291  	//incase ccpack is reused
   292  	ccpack.reset()
   293  
   294  	buf, err := GetChaincodePackage(ccname, ccversion)
   295  	if err != nil {
   296  		return nil, nil, err
   297  	}
   298  
   299  	if _, err = ccpack.InitFromBuffer(buf); err != nil {
   300  		return nil, nil, err
   301  	}
   302  
   303  	return ccpack.buf, ccpack.depSpec, nil
   304  }
   305  
   306  //PutChaincodeToFS - serializes chaincode to a package on the file system
   307  func (ccpack *SignedCDSPackage) PutChaincodeToFS() error {
   308  	if ccpack.buf == nil {
   309  		return fmt.Errorf("uninitialized package")
   310  	}
   311  
   312  	if ccpack.id == nil {
   313  		return fmt.Errorf("id cannot be nil if buf is not nil")
   314  	}
   315  
   316  	if ccpack.sDepSpec == nil || ccpack.depSpec == nil {
   317  		return fmt.Errorf("depspec cannot be nil if buf is not nil")
   318  	}
   319  
   320  	if ccpack.env == nil {
   321  		return fmt.Errorf("env cannot be nil if buf and depspec are not nil")
   322  	}
   323  
   324  	if ccpack.data == nil {
   325  		return fmt.Errorf("nil data")
   326  	}
   327  
   328  	if ccpack.datab == nil {
   329  		return fmt.Errorf("nil data bytes")
   330  	}
   331  
   332  	ccname := ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name
   333  	ccversion := ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version
   334  
   335  	//return error if chaincode exists
   336  	path := fmt.Sprintf("%s/%s.%s", chaincodeInstallPath, ccname, ccversion)
   337  	if _, err := os.Stat(path); err == nil {
   338  		return fmt.Errorf("chaincode %s exists", path)
   339  	}
   340  
   341  	if err := ioutil.WriteFile(path, ccpack.buf, 0644); err != nil {
   342  		return err
   343  	}
   344  
   345  	return nil
   346  }