github.com/anjalikarhana/fabric@v2.1.1+incompatible/protoutil/proputils.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package protoutil
     8  
     9  import (
    10  	"crypto/sha256"
    11  	"encoding/hex"
    12  	"time"
    13  
    14  	"github.com/golang/protobuf/proto"
    15  	"github.com/golang/protobuf/ptypes"
    16  	"github.com/hyperledger/fabric-protos-go/common"
    17  	"github.com/hyperledger/fabric-protos-go/peer"
    18  	"github.com/pkg/errors"
    19  )
    20  
    21  // CreateChaincodeProposal creates a proposal from given input.
    22  // It returns the proposal and the transaction id associated to the proposal
    23  func CreateChaincodeProposal(typ common.HeaderType, channelID string, cis *peer.ChaincodeInvocationSpec, creator []byte) (*peer.Proposal, string, error) {
    24  	return CreateChaincodeProposalWithTransient(typ, channelID, cis, creator, nil)
    25  }
    26  
    27  // CreateChaincodeProposalWithTransient creates a proposal from given input
    28  // It returns the proposal and the transaction id associated to the proposal
    29  func CreateChaincodeProposalWithTransient(typ common.HeaderType, channelID string, cis *peer.ChaincodeInvocationSpec, creator []byte, transientMap map[string][]byte) (*peer.Proposal, string, error) {
    30  	// generate a random nonce
    31  	nonce, err := getRandomNonce()
    32  	if err != nil {
    33  		return nil, "", err
    34  	}
    35  
    36  	// compute txid
    37  	txid := ComputeTxID(nonce, creator)
    38  
    39  	return CreateChaincodeProposalWithTxIDNonceAndTransient(txid, typ, channelID, cis, nonce, creator, transientMap)
    40  }
    41  
    42  // CreateChaincodeProposalWithTxIDAndTransient creates a proposal from given
    43  // input. It returns the proposal and the transaction id associated with the
    44  // proposal
    45  func CreateChaincodeProposalWithTxIDAndTransient(typ common.HeaderType, channelID string, cis *peer.ChaincodeInvocationSpec, creator []byte, txid string, transientMap map[string][]byte) (*peer.Proposal, string, error) {
    46  	// generate a random nonce
    47  	nonce, err := getRandomNonce()
    48  	if err != nil {
    49  		return nil, "", err
    50  	}
    51  
    52  	// compute txid unless provided by tests
    53  	if txid == "" {
    54  		txid = ComputeTxID(nonce, creator)
    55  	}
    56  
    57  	return CreateChaincodeProposalWithTxIDNonceAndTransient(txid, typ, channelID, cis, nonce, creator, transientMap)
    58  }
    59  
    60  // CreateChaincodeProposalWithTxIDNonceAndTransient creates a proposal from
    61  // given input
    62  func CreateChaincodeProposalWithTxIDNonceAndTransient(txid string, typ common.HeaderType, channelID string, cis *peer.ChaincodeInvocationSpec, nonce, creator []byte, transientMap map[string][]byte) (*peer.Proposal, string, error) {
    63  	ccHdrExt := &peer.ChaincodeHeaderExtension{ChaincodeId: cis.ChaincodeSpec.ChaincodeId}
    64  	ccHdrExtBytes, err := proto.Marshal(ccHdrExt)
    65  	if err != nil {
    66  		return nil, "", errors.Wrap(err, "error marshaling ChaincodeHeaderExtension")
    67  	}
    68  
    69  	cisBytes, err := proto.Marshal(cis)
    70  	if err != nil {
    71  		return nil, "", errors.Wrap(err, "error marshaling ChaincodeInvocationSpec")
    72  	}
    73  
    74  	ccPropPayload := &peer.ChaincodeProposalPayload{Input: cisBytes, TransientMap: transientMap}
    75  	ccPropPayloadBytes, err := proto.Marshal(ccPropPayload)
    76  	if err != nil {
    77  		return nil, "", errors.Wrap(err, "error marshaling ChaincodeProposalPayload")
    78  	}
    79  
    80  	// TODO: epoch is now set to zero. This must be changed once we
    81  	// get a more appropriate mechanism to handle it in.
    82  	var epoch uint64
    83  
    84  	timestamp, err := ptypes.TimestampProto(time.Now().UTC())
    85  	if err != nil {
    86  		return nil, "", errors.Wrap(err, "error validating Timestamp")
    87  	}
    88  
    89  	hdr := &common.Header{
    90  		ChannelHeader: MarshalOrPanic(
    91  			&common.ChannelHeader{
    92  				Type:      int32(typ),
    93  				TxId:      txid,
    94  				Timestamp: timestamp,
    95  				ChannelId: channelID,
    96  				Extension: ccHdrExtBytes,
    97  				Epoch:     epoch,
    98  			},
    99  		),
   100  		SignatureHeader: MarshalOrPanic(
   101  			&common.SignatureHeader{
   102  				Nonce:   nonce,
   103  				Creator: creator,
   104  			},
   105  		),
   106  	}
   107  
   108  	hdrBytes, err := proto.Marshal(hdr)
   109  	if err != nil {
   110  		return nil, "", err
   111  	}
   112  
   113  	prop := &peer.Proposal{
   114  		Header:  hdrBytes,
   115  		Payload: ccPropPayloadBytes,
   116  	}
   117  	return prop, txid, nil
   118  }
   119  
   120  // GetBytesProposalResponsePayload gets proposal response payload
   121  func GetBytesProposalResponsePayload(hash []byte, response *peer.Response, result []byte, event []byte, ccid *peer.ChaincodeID) ([]byte, error) {
   122  	cAct := &peer.ChaincodeAction{
   123  		Events: event, Results: result,
   124  		Response:    response,
   125  		ChaincodeId: ccid,
   126  	}
   127  	cActBytes, err := proto.Marshal(cAct)
   128  	if err != nil {
   129  		return nil, errors.Wrap(err, "error marshaling ChaincodeAction")
   130  	}
   131  
   132  	prp := &peer.ProposalResponsePayload{
   133  		Extension:    cActBytes,
   134  		ProposalHash: hash,
   135  	}
   136  	prpBytes, err := proto.Marshal(prp)
   137  	return prpBytes, errors.Wrap(err, "error marshaling ProposalResponsePayload")
   138  }
   139  
   140  // GetBytesChaincodeProposalPayload gets the chaincode proposal payload
   141  func GetBytesChaincodeProposalPayload(cpp *peer.ChaincodeProposalPayload) ([]byte, error) {
   142  	cppBytes, err := proto.Marshal(cpp)
   143  	return cppBytes, errors.Wrap(err, "error marshaling ChaincodeProposalPayload")
   144  }
   145  
   146  // GetBytesResponse gets the bytes of Response
   147  func GetBytesResponse(res *peer.Response) ([]byte, error) {
   148  	resBytes, err := proto.Marshal(res)
   149  	return resBytes, errors.Wrap(err, "error marshaling Response")
   150  }
   151  
   152  // GetBytesChaincodeEvent gets the bytes of ChaincodeEvent
   153  func GetBytesChaincodeEvent(event *peer.ChaincodeEvent) ([]byte, error) {
   154  	eventBytes, err := proto.Marshal(event)
   155  	return eventBytes, errors.Wrap(err, "error marshaling ChaincodeEvent")
   156  }
   157  
   158  // GetBytesChaincodeActionPayload get the bytes of ChaincodeActionPayload from
   159  // the message
   160  func GetBytesChaincodeActionPayload(cap *peer.ChaincodeActionPayload) ([]byte, error) {
   161  	capBytes, err := proto.Marshal(cap)
   162  	return capBytes, errors.Wrap(err, "error marshaling ChaincodeActionPayload")
   163  }
   164  
   165  // GetBytesProposalResponse gets proposal bytes response
   166  func GetBytesProposalResponse(pr *peer.ProposalResponse) ([]byte, error) {
   167  	respBytes, err := proto.Marshal(pr)
   168  	return respBytes, errors.Wrap(err, "error marshaling ProposalResponse")
   169  }
   170  
   171  // GetBytesHeader get the bytes of Header from the message
   172  func GetBytesHeader(hdr *common.Header) ([]byte, error) {
   173  	bytes, err := proto.Marshal(hdr)
   174  	return bytes, errors.Wrap(err, "error marshaling Header")
   175  }
   176  
   177  // GetBytesSignatureHeader get the bytes of SignatureHeader from the message
   178  func GetBytesSignatureHeader(hdr *common.SignatureHeader) ([]byte, error) {
   179  	bytes, err := proto.Marshal(hdr)
   180  	return bytes, errors.Wrap(err, "error marshaling SignatureHeader")
   181  }
   182  
   183  // GetBytesTransaction get the bytes of Transaction from the message
   184  func GetBytesTransaction(tx *peer.Transaction) ([]byte, error) {
   185  	bytes, err := proto.Marshal(tx)
   186  	return bytes, errors.Wrap(err, "error unmarshaling Transaction")
   187  }
   188  
   189  // GetBytesPayload get the bytes of Payload from the message
   190  func GetBytesPayload(payl *common.Payload) ([]byte, error) {
   191  	bytes, err := proto.Marshal(payl)
   192  	return bytes, errors.Wrap(err, "error marshaling Payload")
   193  }
   194  
   195  // GetBytesEnvelope get the bytes of Envelope from the message
   196  func GetBytesEnvelope(env *common.Envelope) ([]byte, error) {
   197  	bytes, err := proto.Marshal(env)
   198  	return bytes, errors.Wrap(err, "error marshaling Envelope")
   199  }
   200  
   201  // GetActionFromEnvelope extracts a ChaincodeAction message from a
   202  // serialized Envelope
   203  // TODO: fix function name as per FAB-11831
   204  func GetActionFromEnvelope(envBytes []byte) (*peer.ChaincodeAction, error) {
   205  	env, err := GetEnvelopeFromBlock(envBytes)
   206  	if err != nil {
   207  		return nil, err
   208  	}
   209  	return GetActionFromEnvelopeMsg(env)
   210  }
   211  
   212  func GetActionFromEnvelopeMsg(env *common.Envelope) (*peer.ChaincodeAction, error) {
   213  	payl, err := UnmarshalPayload(env.Payload)
   214  	if err != nil {
   215  		return nil, err
   216  	}
   217  
   218  	tx, err := UnmarshalTransaction(payl.Data)
   219  	if err != nil {
   220  		return nil, err
   221  	}
   222  
   223  	if len(tx.Actions) == 0 {
   224  		return nil, errors.New("at least one TransactionAction required")
   225  	}
   226  
   227  	_, respPayload, err := GetPayloads(tx.Actions[0])
   228  	return respPayload, err
   229  }
   230  
   231  // CreateProposalFromCISAndTxid returns a proposal given a serialized identity
   232  // and a ChaincodeInvocationSpec
   233  func CreateProposalFromCISAndTxid(txid string, typ common.HeaderType, channelID string, cis *peer.ChaincodeInvocationSpec, creator []byte) (*peer.Proposal, string, error) {
   234  	nonce, err := getRandomNonce()
   235  	if err != nil {
   236  		return nil, "", err
   237  	}
   238  	return CreateChaincodeProposalWithTxIDNonceAndTransient(txid, typ, channelID, cis, nonce, creator, nil)
   239  }
   240  
   241  // CreateProposalFromCIS returns a proposal given a serialized identity and a
   242  // ChaincodeInvocationSpec
   243  func CreateProposalFromCIS(typ common.HeaderType, channelID string, cis *peer.ChaincodeInvocationSpec, creator []byte) (*peer.Proposal, string, error) {
   244  	return CreateChaincodeProposal(typ, channelID, cis, creator)
   245  }
   246  
   247  // CreateGetChaincodesProposal returns a GETCHAINCODES proposal given a
   248  // serialized identity
   249  func CreateGetChaincodesProposal(channelID string, creator []byte) (*peer.Proposal, string, error) {
   250  	ccinp := &peer.ChaincodeInput{Args: [][]byte{[]byte("getchaincodes")}}
   251  	lsccSpec := &peer.ChaincodeInvocationSpec{
   252  		ChaincodeSpec: &peer.ChaincodeSpec{
   253  			Type:        peer.ChaincodeSpec_GOLANG,
   254  			ChaincodeId: &peer.ChaincodeID{Name: "lscc"},
   255  			Input:       ccinp,
   256  		},
   257  	}
   258  	return CreateProposalFromCIS(common.HeaderType_ENDORSER_TRANSACTION, channelID, lsccSpec, creator)
   259  }
   260  
   261  // CreateGetInstalledChaincodesProposal returns a GETINSTALLEDCHAINCODES
   262  // proposal given a serialized identity
   263  func CreateGetInstalledChaincodesProposal(creator []byte) (*peer.Proposal, string, error) {
   264  	ccinp := &peer.ChaincodeInput{Args: [][]byte{[]byte("getinstalledchaincodes")}}
   265  	lsccSpec := &peer.ChaincodeInvocationSpec{
   266  		ChaincodeSpec: &peer.ChaincodeSpec{
   267  			Type:        peer.ChaincodeSpec_GOLANG,
   268  			ChaincodeId: &peer.ChaincodeID{Name: "lscc"},
   269  			Input:       ccinp,
   270  		},
   271  	}
   272  	return CreateProposalFromCIS(common.HeaderType_ENDORSER_TRANSACTION, "", lsccSpec, creator)
   273  }
   274  
   275  // CreateInstallProposalFromCDS returns a install proposal given a serialized
   276  // identity and a ChaincodeDeploymentSpec
   277  func CreateInstallProposalFromCDS(ccpack proto.Message, creator []byte) (*peer.Proposal, string, error) {
   278  	return createProposalFromCDS("", ccpack, creator, "install")
   279  }
   280  
   281  // CreateDeployProposalFromCDS returns a deploy proposal given a serialized
   282  // identity and a ChaincodeDeploymentSpec
   283  func CreateDeployProposalFromCDS(
   284  	channelID string,
   285  	cds *peer.ChaincodeDeploymentSpec,
   286  	creator []byte,
   287  	policy []byte,
   288  	escc []byte,
   289  	vscc []byte,
   290  	collectionConfig []byte) (*peer.Proposal, string, error) {
   291  	if collectionConfig == nil {
   292  		return createProposalFromCDS(channelID, cds, creator, "deploy", policy, escc, vscc)
   293  	}
   294  	return createProposalFromCDS(channelID, cds, creator, "deploy", policy, escc, vscc, collectionConfig)
   295  }
   296  
   297  // CreateUpgradeProposalFromCDS returns a upgrade proposal given a serialized
   298  // identity and a ChaincodeDeploymentSpec
   299  func CreateUpgradeProposalFromCDS(
   300  	channelID string,
   301  	cds *peer.ChaincodeDeploymentSpec,
   302  	creator []byte,
   303  	policy []byte,
   304  	escc []byte,
   305  	vscc []byte,
   306  	collectionConfig []byte) (*peer.Proposal, string, error) {
   307  	if collectionConfig == nil {
   308  		return createProposalFromCDS(channelID, cds, creator, "upgrade", policy, escc, vscc)
   309  	}
   310  	return createProposalFromCDS(channelID, cds, creator, "upgrade", policy, escc, vscc, collectionConfig)
   311  }
   312  
   313  // createProposalFromCDS returns a deploy or upgrade proposal given a
   314  // serialized identity and a ChaincodeDeploymentSpec
   315  func createProposalFromCDS(channelID string, msg proto.Message, creator []byte, propType string, args ...[]byte) (*peer.Proposal, string, error) {
   316  	// in the new mode, cds will be nil, "deploy" and "upgrade" are instantiates.
   317  	var ccinp *peer.ChaincodeInput
   318  	var b []byte
   319  	var err error
   320  	if msg != nil {
   321  		b, err = proto.Marshal(msg)
   322  		if err != nil {
   323  			return nil, "", err
   324  		}
   325  	}
   326  	switch propType {
   327  	case "deploy":
   328  		fallthrough
   329  	case "upgrade":
   330  		cds, ok := msg.(*peer.ChaincodeDeploymentSpec)
   331  		if !ok || cds == nil {
   332  			return nil, "", errors.New("invalid message for creating lifecycle chaincode proposal")
   333  		}
   334  		Args := [][]byte{[]byte(propType), []byte(channelID), b}
   335  		Args = append(Args, args...)
   336  
   337  		ccinp = &peer.ChaincodeInput{Args: Args}
   338  	case "install":
   339  		ccinp = &peer.ChaincodeInput{Args: [][]byte{[]byte(propType), b}}
   340  	}
   341  
   342  	// wrap the deployment in an invocation spec to lscc...
   343  	lsccSpec := &peer.ChaincodeInvocationSpec{
   344  		ChaincodeSpec: &peer.ChaincodeSpec{
   345  			Type:        peer.ChaincodeSpec_GOLANG,
   346  			ChaincodeId: &peer.ChaincodeID{Name: "lscc"},
   347  			Input:       ccinp,
   348  		},
   349  	}
   350  
   351  	// ...and get the proposal for it
   352  	return CreateProposalFromCIS(common.HeaderType_ENDORSER_TRANSACTION, channelID, lsccSpec, creator)
   353  }
   354  
   355  // ComputeTxID computes TxID as the Hash computed
   356  // over the concatenation of nonce and creator.
   357  func ComputeTxID(nonce, creator []byte) string {
   358  	// TODO: Get the Hash function to be used from
   359  	// channel configuration
   360  	hasher := sha256.New()
   361  	hasher.Write(nonce)
   362  	hasher.Write(creator)
   363  	return hex.EncodeToString(hasher.Sum(nil))
   364  }
   365  
   366  // CheckTxID checks that txid is equal to the Hash computed
   367  // over the concatenation of nonce and creator.
   368  func CheckTxID(txid string, nonce, creator []byte) error {
   369  	computedTxID := ComputeTxID(nonce, creator)
   370  
   371  	if txid != computedTxID {
   372  		return errors.Errorf("invalid txid. got [%s], expected [%s]", txid, computedTxID)
   373  	}
   374  
   375  	return nil
   376  }
   377  
   378  // InvokedChaincodeName takes the proposal bytes of a SignedProposal, and unpacks it all the way down,
   379  // until either an error is encountered, or the chaincode name is found. This is useful primarily
   380  // for chaincodes which wish to know the chaincode name originally invoked, in order to deny cc2cc
   381  // invocations (or, perhaps to deny direct invocations and require cc2cc).
   382  func InvokedChaincodeName(proposalBytes []byte) (string, error) {
   383  	proposal := &peer.Proposal{}
   384  	err := proto.Unmarshal(proposalBytes, proposal)
   385  	if err != nil {
   386  		return "", errors.WithMessage(err, "could not unmarshal proposal")
   387  	}
   388  
   389  	proposalPayload := &peer.ChaincodeProposalPayload{}
   390  	err = proto.Unmarshal(proposal.Payload, proposalPayload)
   391  	if err != nil {
   392  		return "", errors.WithMessage(err, "could not unmarshal chaincode proposal payload")
   393  	}
   394  
   395  	cis := &peer.ChaincodeInvocationSpec{}
   396  	err = proto.Unmarshal(proposalPayload.Input, cis)
   397  	if err != nil {
   398  		return "", errors.WithMessage(err, "could not unmarshal chaincode invocation spec")
   399  	}
   400  
   401  	if cis.ChaincodeSpec == nil {
   402  		return "", errors.Errorf("chaincode spec is nil")
   403  	}
   404  
   405  	if cis.ChaincodeSpec.ChaincodeId == nil {
   406  		return "", errors.Errorf("chaincode id is nil")
   407  	}
   408  
   409  	return cis.ChaincodeSpec.ChaincodeId.Name, nil
   410  }