github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/protos/utils/proputils.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 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 utils
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  
    23  	"encoding/binary"
    24  
    25  	"encoding/hex"
    26  
    27  	"github.com/golang/protobuf/proto"
    28  	"github.com/hyperledger/fabric/bccsp"
    29  	"github.com/hyperledger/fabric/bccsp/factory"
    30  	"github.com/hyperledger/fabric/common/crypto"
    31  	"github.com/hyperledger/fabric/common/util"
    32  	"github.com/hyperledger/fabric/core/chaincode/platforms"
    33  	"github.com/hyperledger/fabric/protos/common"
    34  	"github.com/hyperledger/fabric/protos/peer"
    35  )
    36  
    37  // GetChaincodeInvocationSpec get the ChaincodeInvocationSpec from the proposal
    38  func GetChaincodeInvocationSpec(prop *peer.Proposal) (*peer.ChaincodeInvocationSpec, error) {
    39  	txhdr := &common.Header{}
    40  	err := proto.Unmarshal(prop.Header, txhdr)
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  	ccPropPayload := &peer.ChaincodeProposalPayload{}
    45  	err = proto.Unmarshal(prop.Payload, ccPropPayload)
    46  	if err != nil {
    47  		return nil, err
    48  	}
    49  	cis := &peer.ChaincodeInvocationSpec{}
    50  	err = proto.Unmarshal(ccPropPayload.Input, cis)
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  	return cis, nil
    55  }
    56  
    57  // GetChaincodeProposalContext returns creator and transient
    58  func GetChaincodeProposalContext(prop *peer.Proposal) ([]byte, map[string][]byte, error) {
    59  	if prop == nil {
    60  		return nil, nil, fmt.Errorf("Proposal is nil")
    61  	}
    62  	if len(prop.Header) == 0 {
    63  		return nil, nil, fmt.Errorf("Proposal's header is nil")
    64  	}
    65  	if len(prop.Payload) == 0 {
    66  		return nil, nil, fmt.Errorf("Proposal's payload is nil")
    67  	}
    68  
    69  	//// get back the header
    70  	hdr, err := GetHeader(prop.Header)
    71  	if err != nil {
    72  		return nil, nil, fmt.Errorf("Could not extract the header from the proposal: %s", err)
    73  	}
    74  	if hdr == nil {
    75  		return nil, nil, fmt.Errorf("Unmarshalled header is nil")
    76  	}
    77  
    78  	chdr, err := UnmarshalChannelHeader(hdr.ChannelHeader)
    79  	if err != nil {
    80  		return nil, nil, fmt.Errorf("Could not extract the channel header from the proposal: %s", err)
    81  	}
    82  
    83  	if common.HeaderType(chdr.Type) != common.HeaderType_ENDORSER_TRANSACTION &&
    84  		common.HeaderType(chdr.Type) != common.HeaderType_CONFIG {
    85  		return nil, nil, fmt.Errorf("Invalid proposal type expected ENDORSER_TRANSACTION or CONFIG. Was: %d", chdr.Type)
    86  	}
    87  
    88  	shdr, err := GetSignatureHeader(hdr.SignatureHeader)
    89  	if err != nil {
    90  		return nil, nil, fmt.Errorf("Could not extract the signature header from the proposal: %s", err)
    91  	}
    92  
    93  	ccPropPayload := &peer.ChaincodeProposalPayload{}
    94  	err = proto.Unmarshal(prop.Payload, ccPropPayload)
    95  	if err != nil {
    96  		return nil, nil, err
    97  	}
    98  
    99  	return shdr.Creator, ccPropPayload.TransientMap, nil
   100  }
   101  
   102  // GetHeader Get Header from bytes
   103  func GetHeader(bytes []byte) (*common.Header, error) {
   104  	hdr := &common.Header{}
   105  	err := proto.Unmarshal(bytes, hdr)
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  
   110  	return hdr, nil
   111  }
   112  
   113  // GetNonce returns the nonce used in Proposal
   114  func GetNonce(prop *peer.Proposal) ([]byte, error) {
   115  	// get back the header
   116  	hdr, err := GetHeader(prop.Header)
   117  	if err != nil {
   118  		return nil, fmt.Errorf("Could not extract the header from the proposal: %s", err)
   119  	}
   120  
   121  	chdr, err := UnmarshalChannelHeader(hdr.ChannelHeader)
   122  	if err != nil {
   123  		return nil, fmt.Errorf("Could not extract the channel header from the proposal: %s", err)
   124  	}
   125  	shdr, err := GetSignatureHeader(hdr.SignatureHeader)
   126  	if err != nil {
   127  		return nil, fmt.Errorf("Could not extract the signature header from the proposal: %s", err)
   128  	}
   129  
   130  	if common.HeaderType(chdr.Type) != common.HeaderType_ENDORSER_TRANSACTION &&
   131  		common.HeaderType(chdr.Type) != common.HeaderType_CONFIG {
   132  		return nil, fmt.Errorf("Invalid proposal type expected ENDORSER_TRANSACTION or CONFIG. Was: %d", chdr.Type)
   133  	}
   134  
   135  	if hdr.SignatureHeader == nil {
   136  		return nil, errors.New("Invalid signature header. It must be different from nil.")
   137  	}
   138  
   139  	ccPropPayload := &peer.ChaincodeProposalPayload{}
   140  	err = proto.Unmarshal(prop.Payload, ccPropPayload)
   141  	if err != nil {
   142  		return nil, err
   143  	}
   144  
   145  	return shdr.Nonce, nil
   146  }
   147  
   148  // GetChaincodeHeaderExtension get chaincode header extension given header
   149  func GetChaincodeHeaderExtension(hdr *common.Header) (*peer.ChaincodeHeaderExtension, error) {
   150  	chdr, err := UnmarshalChannelHeader(hdr.ChannelHeader)
   151  	if err != nil {
   152  		return nil, err
   153  	}
   154  
   155  	chaincodeHdrExt := &peer.ChaincodeHeaderExtension{}
   156  	err = proto.Unmarshal(chdr.Extension, chaincodeHdrExt)
   157  	if err != nil {
   158  		return nil, err
   159  	}
   160  
   161  	return chaincodeHdrExt, nil
   162  }
   163  
   164  // GetProposalResponse given proposal in bytes
   165  func GetProposalResponse(prBytes []byte) (*peer.ProposalResponse, error) {
   166  	proposalResponse := &peer.ProposalResponse{}
   167  	err := proto.Unmarshal(prBytes, proposalResponse)
   168  	if err != nil {
   169  		return nil, err
   170  	}
   171  
   172  	return proposalResponse, nil
   173  }
   174  
   175  // GetChaincodeDeploymentSpec returns a ChaincodeDeploymentSpec given args
   176  func GetChaincodeDeploymentSpec(code []byte) (*peer.ChaincodeDeploymentSpec, error) {
   177  	cds := &peer.ChaincodeDeploymentSpec{}
   178  	err := proto.Unmarshal(code, cds)
   179  	if err != nil {
   180  		return nil, err
   181  	}
   182  
   183  	// FAB-2122: Validate the CDS according to platform specific requirements
   184  	platform, err := platforms.Find(cds.ChaincodeSpec.Type)
   185  	if err != nil {
   186  		return nil, err
   187  	}
   188  
   189  	err = platform.ValidateDeploymentSpec(cds)
   190  	if err != nil {
   191  		return nil, err
   192  	}
   193  
   194  	return cds, nil
   195  }
   196  
   197  // GetChaincodeAction gets the ChaincodeAction given chaicnode action bytes
   198  func GetChaincodeAction(caBytes []byte) (*peer.ChaincodeAction, error) {
   199  	chaincodeAction := &peer.ChaincodeAction{}
   200  	err := proto.Unmarshal(caBytes, chaincodeAction)
   201  	if err != nil {
   202  		return nil, err
   203  	}
   204  
   205  	return chaincodeAction, nil
   206  }
   207  
   208  // GetResponse gets the Response given response bytes
   209  func GetResponse(resBytes []byte) (*peer.Response, error) {
   210  	response := &peer.Response{}
   211  	err := proto.Unmarshal(resBytes, response)
   212  	if err != nil {
   213  		return nil, err
   214  	}
   215  
   216  	return response, nil
   217  }
   218  
   219  // GetChaincodeEvents gets the ChaincodeEvents given chaicnode event bytes
   220  func GetChaincodeEvents(eBytes []byte) (*peer.ChaincodeEvent, error) {
   221  	chaincodeEvent := &peer.ChaincodeEvent{}
   222  	err := proto.Unmarshal(eBytes, chaincodeEvent)
   223  	if err != nil {
   224  		return nil, err
   225  	}
   226  
   227  	return chaincodeEvent, nil
   228  }
   229  
   230  // GetProposalResponsePayload gets the proposal response payload
   231  func GetProposalResponsePayload(prpBytes []byte) (*peer.ProposalResponsePayload, error) {
   232  	prp := &peer.ProposalResponsePayload{}
   233  	err := proto.Unmarshal(prpBytes, prp)
   234  	if err != nil {
   235  		return nil, err
   236  	}
   237  
   238  	return prp, nil
   239  }
   240  
   241  // GetProposal returns a Proposal message from its bytes
   242  func GetProposal(propBytes []byte) (*peer.Proposal, error) {
   243  	prop := &peer.Proposal{}
   244  	err := proto.Unmarshal(propBytes, prop)
   245  	if err != nil {
   246  		return nil, err
   247  	}
   248  
   249  	return prop, nil
   250  }
   251  
   252  // GetPayload Get Payload from Envelope message
   253  func GetPayload(e *common.Envelope) (*common.Payload, error) {
   254  	payload := &common.Payload{}
   255  	err := proto.Unmarshal(e.Payload, payload)
   256  	if err != nil {
   257  		return nil, err
   258  	}
   259  
   260  	return payload, nil
   261  }
   262  
   263  // GetTransaction Get Transaction from bytes
   264  func GetTransaction(txBytes []byte) (*peer.Transaction, error) {
   265  	tx := &peer.Transaction{}
   266  	err := proto.Unmarshal(txBytes, tx)
   267  	if err != nil {
   268  		return nil, err
   269  	}
   270  
   271  	return tx, nil
   272  }
   273  
   274  // GetChaincodeActionPayload Get ChaincodeActionPayload from bytes
   275  func GetChaincodeActionPayload(capBytes []byte) (*peer.ChaincodeActionPayload, error) {
   276  	cap := &peer.ChaincodeActionPayload{}
   277  	err := proto.Unmarshal(capBytes, cap)
   278  	if err != nil {
   279  		return nil, err
   280  	}
   281  
   282  	return cap, nil
   283  }
   284  
   285  // GetChaincodeProposalPayload Get ChaincodeProposalPayload from bytes
   286  func GetChaincodeProposalPayload(bytes []byte) (*peer.ChaincodeProposalPayload, error) {
   287  	cpp := &peer.ChaincodeProposalPayload{}
   288  	err := proto.Unmarshal(bytes, cpp)
   289  	if err != nil {
   290  		return nil, err
   291  	}
   292  
   293  	return cpp, nil
   294  }
   295  
   296  // GetSignatureHeader Get SignatureHeader from bytes
   297  func GetSignatureHeader(bytes []byte) (*common.SignatureHeader, error) {
   298  	sh := &common.SignatureHeader{}
   299  	err := proto.Unmarshal(bytes, sh)
   300  	if err != nil {
   301  		return nil, err
   302  	}
   303  
   304  	return sh, nil
   305  }
   306  
   307  // GetSignaturePolicyEnvelope returns a SignaturePolicyEnvelope from bytes
   308  func GetSignaturePolicyEnvelope(bytes []byte) (*common.SignaturePolicyEnvelope, error) {
   309  	p := &common.SignaturePolicyEnvelope{}
   310  	err := proto.Unmarshal(bytes, p)
   311  	if err != nil {
   312  		return nil, err
   313  	}
   314  
   315  	return p, nil
   316  }
   317  
   318  // CreateChaincodeProposal creates a proposal from given input.
   319  // It returns the proposal and the transaction id associated to the proposal
   320  func CreateChaincodeProposal(typ common.HeaderType, chainID string, cis *peer.ChaincodeInvocationSpec, creator []byte) (*peer.Proposal, string, error) {
   321  	return CreateChaincodeProposalWithTransient(typ, chainID, cis, creator, nil)
   322  }
   323  
   324  // CreateChaincodeProposalWithTransient creates a proposal from given input
   325  // It returns the proposal and the transaction id associated to the proposal
   326  func CreateChaincodeProposalWithTransient(typ common.HeaderType, chainID string, cis *peer.ChaincodeInvocationSpec, creator []byte, transientMap map[string][]byte) (*peer.Proposal, string, error) {
   327  	// generate a random nonce
   328  	nonce, err := crypto.GetRandomNonce()
   329  	if err != nil {
   330  		return nil, "", err
   331  	}
   332  
   333  	// compute txid
   334  	txid, err := ComputeProposalTxID(nonce, creator)
   335  	if err != nil {
   336  		return nil, "", err
   337  	}
   338  
   339  	return CreateChaincodeProposalWithTxIDNonceAndTransient(txid, typ, chainID, cis, nonce, creator, transientMap)
   340  }
   341  
   342  // CreateChaincodeProposalWithTxIDNonceAndTransient creates a proposal from given input
   343  func CreateChaincodeProposalWithTxIDNonceAndTransient(txid string, typ common.HeaderType, chainID string, cis *peer.ChaincodeInvocationSpec, nonce, creator []byte, transientMap map[string][]byte) (*peer.Proposal, string, error) {
   344  	ccHdrExt := &peer.ChaincodeHeaderExtension{ChaincodeId: cis.ChaincodeSpec.ChaincodeId}
   345  	ccHdrExtBytes, err := proto.Marshal(ccHdrExt)
   346  	if err != nil {
   347  		return nil, "", err
   348  	}
   349  
   350  	cisBytes, err := proto.Marshal(cis)
   351  	if err != nil {
   352  		return nil, "", err
   353  	}
   354  
   355  	ccPropPayload := &peer.ChaincodeProposalPayload{Input: cisBytes, TransientMap: transientMap}
   356  	ccPropPayloadBytes, err := proto.Marshal(ccPropPayload)
   357  	if err != nil {
   358  		return nil, "", err
   359  	}
   360  
   361  	// TODO: epoch is now set to zero. This must be changed once we
   362  	// get a more appropriate mechanism to handle it in.
   363  	var epoch uint64 = 0
   364  
   365  	timestamp := util.CreateUtcTimestamp()
   366  
   367  	hdr := &common.Header{ChannelHeader: MarshalOrPanic(&common.ChannelHeader{
   368  		Type:      int32(typ),
   369  		TxId:      txid,
   370  		Timestamp: timestamp,
   371  		ChannelId: chainID,
   372  		Extension: ccHdrExtBytes,
   373  		Epoch:     epoch}),
   374  		SignatureHeader: MarshalOrPanic(&common.SignatureHeader{Nonce: nonce, Creator: creator})}
   375  
   376  	hdrBytes, err := proto.Marshal(hdr)
   377  	if err != nil {
   378  		return nil, "", err
   379  	}
   380  
   381  	return &peer.Proposal{Header: hdrBytes, Payload: ccPropPayloadBytes}, txid, nil
   382  }
   383  
   384  // GetBytesProposalResponsePayload gets proposal response payload
   385  func GetBytesProposalResponsePayload(hash []byte, response *peer.Response, result []byte, event []byte, ccid *peer.ChaincodeID) ([]byte, error) {
   386  	cAct := &peer.ChaincodeAction{Events: event, Results: result, Response: response, ChaincodeId: ccid}
   387  	cActBytes, err := proto.Marshal(cAct)
   388  	if err != nil {
   389  		return nil, err
   390  	}
   391  
   392  	prp := &peer.ProposalResponsePayload{Extension: cActBytes, ProposalHash: hash}
   393  	prpBytes, err := proto.Marshal(prp)
   394  	if err != nil {
   395  		return nil, err
   396  	}
   397  
   398  	return prpBytes, nil
   399  }
   400  
   401  // GetBytesChaincodeProposalPayload gets the chaincode proposal payload
   402  func GetBytesChaincodeProposalPayload(cpp *peer.ChaincodeProposalPayload) ([]byte, error) {
   403  	cppBytes, err := proto.Marshal(cpp)
   404  	if err != nil {
   405  		return nil, err
   406  	}
   407  
   408  	return cppBytes, nil
   409  }
   410  
   411  // GetBytesResponse gets the bytes of Response
   412  func GetBytesResponse(res *peer.Response) ([]byte, error) {
   413  	resBytes, err := proto.Marshal(res)
   414  	if err != nil {
   415  		return nil, err
   416  	}
   417  
   418  	return resBytes, nil
   419  }
   420  
   421  // GetBytesChaincodeEvent gets the bytes of ChaincodeEvent
   422  func GetBytesChaincodeEvent(event *peer.ChaincodeEvent) ([]byte, error) {
   423  	eventBytes, err := proto.Marshal(event)
   424  	if err != nil {
   425  		return nil, err
   426  	}
   427  
   428  	return eventBytes, nil
   429  }
   430  
   431  // GetBytesChaincodeActionPayload get the bytes of ChaincodeActionPayload from the message
   432  func GetBytesChaincodeActionPayload(cap *peer.ChaincodeActionPayload) ([]byte, error) {
   433  	capBytes, err := proto.Marshal(cap)
   434  	if err != nil {
   435  		return nil, err
   436  	}
   437  
   438  	return capBytes, nil
   439  }
   440  
   441  // GetBytesProposalResponse gets propoal bytes response
   442  func GetBytesProposalResponse(pr *peer.ProposalResponse) ([]byte, error) {
   443  	respBytes, err := proto.Marshal(pr)
   444  	if err != nil {
   445  		return nil, err
   446  	}
   447  
   448  	return respBytes, nil
   449  }
   450  
   451  // GetBytesProposal returns the bytes of a proposal message
   452  func GetBytesProposal(prop *peer.Proposal) ([]byte, error) {
   453  	propBytes, err := proto.Marshal(prop)
   454  	if err != nil {
   455  		return nil, err
   456  	}
   457  
   458  	return propBytes, nil
   459  }
   460  
   461  // GetBytesHeader get the bytes of Header from the message
   462  func GetBytesHeader(hdr *common.Header) ([]byte, error) {
   463  	bytes, err := proto.Marshal(hdr)
   464  	if err != nil {
   465  		return nil, err
   466  	}
   467  
   468  	return bytes, nil
   469  }
   470  
   471  // GetBytesSignatureHeader get the bytes of SignatureHeader from the message
   472  func GetBytesSignatureHeader(hdr *common.SignatureHeader) ([]byte, error) {
   473  	bytes, err := proto.Marshal(hdr)
   474  	if err != nil {
   475  		return nil, err
   476  	}
   477  
   478  	return bytes, nil
   479  }
   480  
   481  // GetBytesTransaction get the bytes of Transaction from the message
   482  func GetBytesTransaction(tx *peer.Transaction) ([]byte, error) {
   483  	bytes, err := proto.Marshal(tx)
   484  	if err != nil {
   485  		return nil, err
   486  	}
   487  
   488  	return bytes, nil
   489  }
   490  
   491  // GetBytesPayload get the bytes of Payload from the message
   492  func GetBytesPayload(payl *common.Payload) ([]byte, error) {
   493  	bytes, err := proto.Marshal(payl)
   494  	if err != nil {
   495  		return nil, err
   496  	}
   497  
   498  	return bytes, nil
   499  }
   500  
   501  // GetBytesEnvelope get the bytes of Envelope from the message
   502  func GetBytesEnvelope(env *common.Envelope) ([]byte, error) {
   503  	bytes, err := proto.Marshal(env)
   504  	if err != nil {
   505  		return nil, err
   506  	}
   507  
   508  	return bytes, nil
   509  }
   510  
   511  // GetActionFromEnvelope extracts a ChaincodeAction message from a serialized Envelope
   512  func GetActionFromEnvelope(envBytes []byte) (*peer.ChaincodeAction, error) {
   513  	env, err := GetEnvelopeFromBlock(envBytes)
   514  	if err != nil {
   515  		return nil, err
   516  	}
   517  
   518  	payl, err := GetPayload(env)
   519  	if err != nil {
   520  		return nil, err
   521  	}
   522  
   523  	tx, err := GetTransaction(payl.Data)
   524  	if err != nil {
   525  		return nil, err
   526  	}
   527  
   528  	if len(tx.Actions) == 0 {
   529  		return nil, fmt.Errorf("At least one TransactionAction is required")
   530  	}
   531  
   532  	_, respPayload, err := GetPayloads(tx.Actions[0])
   533  	return respPayload, err
   534  }
   535  
   536  // CreateProposalFromCIS returns a proposal given a serialized identity and a ChaincodeInvocationSpec
   537  func CreateProposalFromCIS(typ common.HeaderType, chainID string, cis *peer.ChaincodeInvocationSpec, creator []byte) (*peer.Proposal, string, error) {
   538  	return CreateChaincodeProposal(typ, chainID, cis, creator)
   539  }
   540  
   541  // CreateInstallProposalFromCDS returns a install proposal given a serialized identity and a ChaincodeDeploymentSpec
   542  func CreateInstallProposalFromCDS(ccpack proto.Message, creator []byte) (*peer.Proposal, string, error) {
   543  	return createProposalFromCDS("", ccpack, creator, nil, nil, nil, "install")
   544  }
   545  
   546  // CreateDeployProposalFromCDS returns a deploy proposal given a serialized identity and a ChaincodeDeploymentSpec
   547  func CreateDeployProposalFromCDS(chainID string, cds *peer.ChaincodeDeploymentSpec, creator []byte, policy []byte, escc []byte, vscc []byte) (*peer.Proposal, string, error) {
   548  	return createProposalFromCDS(chainID, cds, creator, policy, escc, vscc, "deploy")
   549  }
   550  
   551  // CreateUpgradeProposalFromCDS returns a upgrade proposal given a serialized identity and a ChaincodeDeploymentSpec
   552  func CreateUpgradeProposalFromCDS(chainID string, cds *peer.ChaincodeDeploymentSpec, creator []byte, policy []byte, escc []byte, vscc []byte) (*peer.Proposal, string, error) {
   553  	return createProposalFromCDS(chainID, cds, creator, policy, escc, vscc, "upgrade")
   554  }
   555  
   556  // createProposalFromCDS returns a deploy or upgrade proposal given a serialized identity and a ChaincodeDeploymentSpec
   557  func createProposalFromCDS(chainID string, msg proto.Message, creator []byte, policy []byte, escc []byte, vscc []byte, propType string) (*peer.Proposal, string, error) {
   558  	//in the new mode, cds will be nil, "deploy" and "upgrade" are instantiates.
   559  	var ccinp *peer.ChaincodeInput
   560  	var b []byte
   561  	var err error
   562  	if msg != nil {
   563  		b, err = proto.Marshal(msg)
   564  		if err != nil {
   565  			return nil, "", err
   566  		}
   567  	}
   568  	switch propType {
   569  	case "deploy":
   570  		fallthrough
   571  	case "upgrade":
   572  		cds, ok := msg.(*peer.ChaincodeDeploymentSpec)
   573  		if !ok || cds == nil {
   574  			return nil, "", fmt.Errorf("invalid message for creating lifecycle chaincode proposal from")
   575  		}
   576  		ccinp = &peer.ChaincodeInput{Args: [][]byte{[]byte(propType), []byte(chainID), b, policy, escc, vscc}}
   577  	case "install":
   578  		ccinp = &peer.ChaincodeInput{Args: [][]byte{[]byte(propType), b}}
   579  	}
   580  
   581  	//wrap the deployment in an invocation spec to lscc...
   582  	lsccSpec := &peer.ChaincodeInvocationSpec{
   583  		ChaincodeSpec: &peer.ChaincodeSpec{
   584  			Type:        peer.ChaincodeSpec_GOLANG,
   585  			ChaincodeId: &peer.ChaincodeID{Name: "lscc"},
   586  			Input:       ccinp}}
   587  
   588  	//...and get the proposal for it
   589  	return CreateProposalFromCIS(common.HeaderType_ENDORSER_TRANSACTION, chainID, lsccSpec, creator)
   590  }
   591  
   592  // ComputeProposalTxID computes TxID as the Hash computed
   593  // over the concatenation of nonce and creator.
   594  func ComputeProposalTxID(nonce, creator []byte) (string, error) {
   595  	// TODO: Get the Hash function to be used from
   596  	// channel configuration
   597  	digest, err := factory.GetDefault().Hash(
   598  		append(nonce, creator...),
   599  		&bccsp.SHA256Opts{})
   600  	if err != nil {
   601  		return "", err
   602  	}
   603  	return hex.EncodeToString(digest), nil
   604  }
   605  
   606  // CheckProposalTxID checks that txid is equal to the Hash computed
   607  // over the concatenation of nonce and creator.
   608  func CheckProposalTxID(txid string, nonce, creator []byte) error {
   609  	computedTxID, err := ComputeProposalTxID(nonce, creator)
   610  	if err != nil {
   611  		return fmt.Errorf("Failed computing target TXID for comparison [%s]", err)
   612  	}
   613  
   614  	if txid != computedTxID {
   615  		return fmt.Errorf("Transaction is not valid. Got [%s], expected [%s]", txid, computedTxID)
   616  	}
   617  
   618  	return nil
   619  }
   620  
   621  // ComputeProposalBinding computes the binding of a proposal
   622  func ComputeProposalBinding(proposal *peer.Proposal) ([]byte, error) {
   623  	if proposal == nil {
   624  		return nil, fmt.Errorf("Porposal is nil")
   625  	}
   626  	if len(proposal.Header) == 0 {
   627  		return nil, fmt.Errorf("Proposal's Header is nil")
   628  	}
   629  
   630  	h, err := GetHeader(proposal.Header)
   631  	if err != nil {
   632  		return nil, err
   633  	}
   634  
   635  	chdr, err := UnmarshalChannelHeader(h.ChannelHeader)
   636  	if err != nil {
   637  		return nil, err
   638  	}
   639  	shdr, err := GetSignatureHeader(h.SignatureHeader)
   640  	if err != nil {
   641  		return nil, err
   642  	}
   643  
   644  	return computeProposalBindingInternal(shdr.Nonce, shdr.Creator, chdr.Epoch)
   645  }
   646  
   647  func computeProposalBindingInternal(nonce, creator []byte, epoch uint64) ([]byte, error) {
   648  	epochBytes := make([]byte, 8)
   649  	binary.LittleEndian.PutUint64(epochBytes, epoch)
   650  
   651  	// TODO: add to genesis block the hash function used for the binding computation.
   652  	digest, err := factory.GetDefault().Hash(
   653  		append(append(nonce, creator...), epochBytes...),
   654  		&bccsp.SHA256Opts{})
   655  	if err != nil {
   656  		return nil, err
   657  	}
   658  	return digest, nil
   659  }