github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/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 convers 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  	return &ChaincodeData{Name: ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name, Version: ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version, Data: ccpack.datab, Id: ccpack.id}
   134  }
   135  
   136  func (ccpack *SignedCDSPackage) getCDSData(scds *pb.SignedChaincodeDeploymentSpec) ([]byte, []byte, *SignedCDSData, error) {
   137  	// check for nil argument. It is an assertion that getCDSData
   138  	// is never called on a package that did not go through/succeed
   139  	// package initialization.
   140  	if scds == nil {
   141  		panic("nil cds")
   142  	}
   143  
   144  	cds := &pb.ChaincodeDeploymentSpec{}
   145  	err := proto.Unmarshal(scds.ChaincodeDeploymentSpec, cds)
   146  	if err != nil {
   147  		return nil, nil, nil, err
   148  	}
   149  
   150  	if err = factory.InitFactories(nil); err != nil {
   151  		return nil, nil, nil, fmt.Errorf("Internal error, BCCSP could not be initialized : %s", err)
   152  	}
   153  
   154  	//get the hash object
   155  	hash, err := factory.GetDefault().GetHash(&bccsp.SHAOpts{})
   156  	if err != nil {
   157  		return nil, nil, nil, err
   158  	}
   159  
   160  	scdsdata := &SignedCDSData{}
   161  
   162  	//get the code hash
   163  	scdsdata.CodeHash = hash.Sum(cds.CodePackage)
   164  
   165  	hash.Reset()
   166  
   167  	//get the metadata hash
   168  	hash.Write([]byte(cds.ChaincodeSpec.ChaincodeId.Name))
   169  	hash.Write([]byte(cds.ChaincodeSpec.ChaincodeId.Version))
   170  
   171  	scdsdata.MetaDataHash = hash.Sum(nil)
   172  
   173  	hash.Reset()
   174  
   175  	//get the signature hashes
   176  	if scds.InstantiationPolicy == nil {
   177  		return nil, nil, nil, fmt.Errorf("instantiation policy cannot be nil for chaincode (%s:%s)", cds.ChaincodeSpec.ChaincodeId.Name, cds.ChaincodeSpec.ChaincodeId.Version)
   178  	}
   179  
   180  	hash.Write(scds.InstantiationPolicy)
   181  	for _, o := range scds.OwnerEndorsements {
   182  		hash.Write(o.Endorser)
   183  	}
   184  	scdsdata.SignatureHash = hash.Sum(nil)
   185  
   186  	//marshall data
   187  	b, err := proto.Marshal(scdsdata)
   188  	if err != nil {
   189  		return nil, nil, nil, err
   190  	}
   191  
   192  	hash.Reset()
   193  
   194  	//compute the id
   195  	hash.Write(scdsdata.CodeHash)
   196  	hash.Write(scdsdata.MetaDataHash)
   197  	hash.Write(scdsdata.SignatureHash)
   198  
   199  	id := hash.Sum(nil)
   200  
   201  	return b, id, scdsdata, nil
   202  }
   203  
   204  // ValidateCC returns error if the chaincode is not found or if its not a
   205  // ChaincodeDeploymentSpec
   206  func (ccpack *SignedCDSPackage) ValidateCC(ccdata *ChaincodeData) error {
   207  	if ccpack.sDepSpec == nil {
   208  		return fmt.Errorf("uninitialized package")
   209  	}
   210  
   211  	if ccpack.sDepSpec.ChaincodeDeploymentSpec == nil {
   212  		return fmt.Errorf("signed chaincode deployment spec cannot be nil in a package")
   213  	}
   214  
   215  	if ccpack.depSpec == nil {
   216  		return fmt.Errorf("chaincode deployment spec cannot be nil in a package")
   217  	}
   218  
   219  	if ccdata.Name != ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name || ccdata.Version != ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version {
   220  		return fmt.Errorf("invalid chaincode data %v (%v)", ccdata, ccpack.depSpec.ChaincodeSpec.ChaincodeId)
   221  	}
   222  
   223  	otherdata := &SignedCDSData{}
   224  	err := proto.Unmarshal(ccdata.Data, otherdata)
   225  	if err != nil {
   226  		return err
   227  	}
   228  
   229  	if !ccpack.data.Equals(otherdata) {
   230  		return fmt.Errorf("data mismatch")
   231  	}
   232  
   233  	return nil
   234  }
   235  
   236  //InitFromBuffer sets the buffer if valid and returns ChaincodeData
   237  func (ccpack *SignedCDSPackage) InitFromBuffer(buf []byte) (*ChaincodeData, error) {
   238  	//incase ccpack is reused
   239  	ccpack.reset()
   240  
   241  	env := &common.Envelope{}
   242  	err := proto.Unmarshal(buf, env)
   243  	if err != nil {
   244  		return nil, fmt.Errorf("failed to unmarshal envelope from bytes")
   245  	}
   246  	cHdr, sDepSpec, err := ccpackage.ExtractSignedCCDepSpec(env)
   247  	if err != nil {
   248  		return nil, err
   249  	}
   250  	if cHdr.Type != int32(common.HeaderType_CHAINCODE_PACKAGE) {
   251  		return nil, fmt.Errorf("invalid type of envelope for chaincode package")
   252  	}
   253  
   254  	depSpec := &pb.ChaincodeDeploymentSpec{}
   255  	err = proto.Unmarshal(sDepSpec.ChaincodeDeploymentSpec, depSpec)
   256  	if err != nil {
   257  		return nil, fmt.Errorf("error getting deployment spec")
   258  	}
   259  
   260  	databytes, id, data, err := ccpack.getCDSData(sDepSpec)
   261  	if err != nil {
   262  		return nil, err
   263  	}
   264  
   265  	ccpack.buf = buf
   266  	ccpack.sDepSpec = sDepSpec
   267  	ccpack.depSpec = depSpec
   268  	ccpack.env = env
   269  	ccpack.data = data
   270  	ccpack.datab = databytes
   271  	ccpack.id = id
   272  
   273  	return ccpack.GetChaincodeData(), nil
   274  }
   275  
   276  //InitFromFS returns the chaincode and its package from the file system
   277  func (ccpack *SignedCDSPackage) InitFromFS(ccname string, ccversion string) ([]byte, *pb.ChaincodeDeploymentSpec, error) {
   278  	//incase ccpack is reused
   279  	ccpack.reset()
   280  
   281  	buf, err := GetChaincodePackage(ccname, ccversion)
   282  	if err != nil {
   283  		return nil, nil, err
   284  	}
   285  
   286  	if _, err = ccpack.InitFromBuffer(buf); err != nil {
   287  		return nil, nil, err
   288  	}
   289  
   290  	return ccpack.buf, ccpack.depSpec, nil
   291  }
   292  
   293  //PutChaincodeToFS - serializes chaincode to a package on the file system
   294  func (ccpack *SignedCDSPackage) PutChaincodeToFS() error {
   295  	if ccpack.buf == nil {
   296  		return fmt.Errorf("uninitialized package")
   297  	}
   298  
   299  	if ccpack.id == nil {
   300  		return fmt.Errorf("id cannot be nil if buf is not nil")
   301  	}
   302  
   303  	if ccpack.sDepSpec == nil || ccpack.depSpec == nil {
   304  		return fmt.Errorf("depspec cannot be nil if buf is not nil")
   305  	}
   306  
   307  	if ccpack.env == nil {
   308  		return fmt.Errorf("env cannot be nil if buf and depspec are not nil")
   309  	}
   310  
   311  	if ccpack.data == nil {
   312  		return fmt.Errorf("nil data")
   313  	}
   314  
   315  	if ccpack.datab == nil {
   316  		return fmt.Errorf("nil data bytes")
   317  	}
   318  
   319  	ccname := ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name
   320  	ccversion := ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version
   321  
   322  	//return error if chaincode exists
   323  	path := fmt.Sprintf("%s/%s.%s", chaincodeInstallPath, ccname, ccversion)
   324  	if _, err := os.Stat(path); err == nil {
   325  		return fmt.Errorf("chaincode %s exists", path)
   326  	}
   327  
   328  	if err := ioutil.WriteFile(path, ccpack.buf, 0644); err != nil {
   329  		return err
   330  	}
   331  
   332  	return nil
   333  }