github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/common/ccprovider/sigcdspackage.go (about)

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