github.com/true-sqn/fabric@v2.1.1+incompatible/protoutil/proputils_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package protoutil_test
     8  
     9  import (
    10  	"bytes"
    11  	"crypto/sha256"
    12  	"encoding/hex"
    13  	"fmt"
    14  	"os"
    15  	"testing"
    16  
    17  	"github.com/golang/protobuf/proto"
    18  	"github.com/hyperledger/fabric-protos-go/common"
    19  	pb "github.com/hyperledger/fabric-protos-go/peer"
    20  	"github.com/hyperledger/fabric/bccsp/sw"
    21  	"github.com/hyperledger/fabric/msp"
    22  	mspmgmt "github.com/hyperledger/fabric/msp/mgmt"
    23  	msptesttools "github.com/hyperledger/fabric/msp/mgmt/testtools"
    24  	"github.com/hyperledger/fabric/protoutil"
    25  	"github.com/stretchr/testify/assert"
    26  )
    27  
    28  func createCIS() *pb.ChaincodeInvocationSpec {
    29  	return &pb.ChaincodeInvocationSpec{
    30  		ChaincodeSpec: &pb.ChaincodeSpec{
    31  			Type:        pb.ChaincodeSpec_GOLANG,
    32  			ChaincodeId: &pb.ChaincodeID{Name: "chaincode_name"},
    33  			Input:       &pb.ChaincodeInput{Args: [][]byte{[]byte("arg1"), []byte("arg2")}}}}
    34  }
    35  
    36  func TestGetChaincodeDeploymentSpec(t *testing.T) {
    37  	_, err := protoutil.UnmarshalChaincodeDeploymentSpec([]byte("bad spec"))
    38  	assert.Error(t, err, "Expected error with malformed spec")
    39  
    40  	cds, _ := proto.Marshal(&pb.ChaincodeDeploymentSpec{
    41  		ChaincodeSpec: &pb.ChaincodeSpec{
    42  			Type: pb.ChaincodeSpec_GOLANG,
    43  		},
    44  	})
    45  	_, err = protoutil.UnmarshalChaincodeDeploymentSpec(cds)
    46  	assert.NoError(t, err, "Unexpected error getting deployment spec")
    47  }
    48  
    49  func TestCDSProposals(t *testing.T) {
    50  	var prop *pb.Proposal
    51  	var err error
    52  	var txid string
    53  	creator := []byte("creator")
    54  	cds := &pb.ChaincodeDeploymentSpec{
    55  		ChaincodeSpec: &pb.ChaincodeSpec{
    56  			Type: pb.ChaincodeSpec_GOLANG,
    57  		},
    58  	}
    59  	policy := []byte("policy")
    60  	escc := []byte("escc")
    61  	vscc := []byte("vscc")
    62  	chainID := "testchannelid"
    63  
    64  	// install
    65  	prop, txid, err = protoutil.CreateInstallProposalFromCDS(cds, creator)
    66  	assert.NotNil(t, prop, "Install proposal should not be nil")
    67  	assert.NoError(t, err, "Unexpected error creating install proposal")
    68  	assert.NotEqual(t, "", txid, "txid should not be empty")
    69  
    70  	// deploy
    71  	prop, txid, err = protoutil.CreateDeployProposalFromCDS(chainID, cds, creator, policy, escc, vscc, nil)
    72  	assert.NotNil(t, prop, "Deploy proposal should not be nil")
    73  	assert.NoError(t, err, "Unexpected error creating deploy proposal")
    74  	assert.NotEqual(t, "", txid, "txid should not be empty")
    75  
    76  	// upgrade
    77  	prop, txid, err = protoutil.CreateUpgradeProposalFromCDS(chainID, cds, creator, policy, escc, vscc, nil)
    78  	assert.NotNil(t, prop, "Upgrade proposal should not be nil")
    79  	assert.NoError(t, err, "Unexpected error creating upgrade proposal")
    80  	assert.NotEqual(t, "", txid, "txid should not be empty")
    81  
    82  }
    83  
    84  func TestProposal(t *testing.T) {
    85  	// create a proposal from a ChaincodeInvocationSpec
    86  	prop, _, err := protoutil.CreateChaincodeProposalWithTransient(
    87  		common.HeaderType_ENDORSER_TRANSACTION,
    88  		testChannelID, createCIS(),
    89  		[]byte("creator"),
    90  		map[string][]byte{"certx": []byte("transient")})
    91  	if err != nil {
    92  		t.Fatalf("Could not create chaincode proposal, err %s\n", err)
    93  		return
    94  	}
    95  
    96  	// serialize the proposal
    97  	pBytes, err := proto.Marshal(prop)
    98  	if err != nil {
    99  		t.Fatalf("Could not serialize the chaincode proposal, err %s\n", err)
   100  		return
   101  	}
   102  
   103  	// deserialize it and expect it to be the same
   104  	propBack, err := protoutil.UnmarshalProposal(pBytes)
   105  	if err != nil {
   106  		t.Fatalf("Could not deserialize the chaincode proposal, err %s\n", err)
   107  		return
   108  	}
   109  	if !proto.Equal(prop, propBack) {
   110  		t.Fatalf("Proposal and deserialized proposals don't match\n")
   111  		return
   112  	}
   113  
   114  	// get back the header
   115  	hdr, err := protoutil.UnmarshalHeader(prop.Header)
   116  	if err != nil {
   117  		t.Fatalf("Could not extract the header from the proposal, err %s\n", err)
   118  	}
   119  
   120  	hdrBytes, err := protoutil.GetBytesHeader(hdr)
   121  	if err != nil {
   122  		t.Fatalf("Could not marshal the header, err %s\n", err)
   123  	}
   124  
   125  	hdr, err = protoutil.UnmarshalHeader(hdrBytes)
   126  	if err != nil {
   127  		t.Fatalf("Could not unmarshal the header, err %s\n", err)
   128  	}
   129  
   130  	chdr, err := protoutil.UnmarshalChannelHeader(hdr.ChannelHeader)
   131  	if err != nil {
   132  		t.Fatalf("Could not unmarshal channel header, err %s", err)
   133  	}
   134  
   135  	shdr, err := protoutil.UnmarshalSignatureHeader(hdr.SignatureHeader)
   136  	if err != nil {
   137  		t.Fatalf("Could not unmarshal signature header, err %s", err)
   138  	}
   139  
   140  	_, err = protoutil.GetBytesSignatureHeader(shdr)
   141  	if err != nil {
   142  		t.Fatalf("Could not marshal signature header, err %s", err)
   143  	}
   144  
   145  	// sanity check on header
   146  	if chdr.Type != int32(common.HeaderType_ENDORSER_TRANSACTION) ||
   147  		shdr.Nonce == nil ||
   148  		string(shdr.Creator) != "creator" {
   149  		t.Fatalf("Invalid header after unmarshalling\n")
   150  		return
   151  	}
   152  
   153  	// get back the header extension
   154  	hdrExt, err := protoutil.UnmarshalChaincodeHeaderExtension(chdr.Extension)
   155  	if err != nil {
   156  		t.Fatalf("Could not extract the header extensions from the proposal, err %s\n", err)
   157  		return
   158  	}
   159  
   160  	// sanity check on header extension
   161  	if string(hdrExt.ChaincodeId.Name) != "chaincode_name" {
   162  		t.Fatalf("Invalid header extension after unmarshalling\n")
   163  		return
   164  	}
   165  
   166  	cpp, err := protoutil.UnmarshalChaincodeProposalPayload(prop.Payload)
   167  	if err != nil {
   168  		t.Fatalf("could not unmarshal proposal payload")
   169  	}
   170  
   171  	cis, err := protoutil.UnmarshalChaincodeInvocationSpec(cpp.Input)
   172  	if err != nil {
   173  		t.Fatalf("could not unmarshal proposal chaincode invocation spec")
   174  	}
   175  
   176  	// sanity check on cis
   177  	if cis.ChaincodeSpec.Type != pb.ChaincodeSpec_GOLANG ||
   178  		cis.ChaincodeSpec.ChaincodeId.Name != "chaincode_name" ||
   179  		len(cis.ChaincodeSpec.Input.Args) != 2 ||
   180  		string(cis.ChaincodeSpec.Input.Args[0]) != "arg1" ||
   181  		string(cis.ChaincodeSpec.Input.Args[1]) != "arg2" {
   182  		t.Fatalf("Invalid chaincode invocation spec after unmarshalling\n")
   183  		return
   184  	}
   185  
   186  	if string(shdr.Creator) != "creator" {
   187  		t.Fatalf("Failed checking Creator field. Invalid value, expectext 'creator', got [%s]", string(shdr.Creator))
   188  		return
   189  	}
   190  	value, ok := cpp.TransientMap["certx"]
   191  	if !ok || string(value) != "transient" {
   192  		t.Fatalf("Failed checking Transient field. Invalid value, expectext 'transient', got [%s]", string(value))
   193  		return
   194  	}
   195  }
   196  
   197  func TestProposalWithTxID(t *testing.T) {
   198  	// create a proposal from a ChaincodeInvocationSpec
   199  	prop, txid, err := protoutil.CreateChaincodeProposalWithTxIDAndTransient(
   200  		common.HeaderType_ENDORSER_TRANSACTION,
   201  		testChannelID,
   202  		createCIS(),
   203  		[]byte("creator"),
   204  		"testtx",
   205  		map[string][]byte{"certx": []byte("transient")},
   206  	)
   207  	assert.Nil(t, err)
   208  	assert.NotNil(t, prop)
   209  	assert.Equal(t, txid, "testtx")
   210  
   211  	prop, txid, err = protoutil.CreateChaincodeProposalWithTxIDAndTransient(
   212  		common.HeaderType_ENDORSER_TRANSACTION,
   213  		testChannelID,
   214  		createCIS(),
   215  		[]byte("creator"),
   216  		"",
   217  		map[string][]byte{"certx": []byte("transient")},
   218  	)
   219  	assert.Nil(t, err)
   220  	assert.NotNil(t, prop)
   221  	assert.NotEmpty(t, txid)
   222  }
   223  
   224  func TestProposalResponse(t *testing.T) {
   225  	events := &pb.ChaincodeEvent{
   226  		ChaincodeId: "ccid",
   227  		EventName:   "EventName",
   228  		Payload:     []byte("EventPayload"),
   229  		TxId:        "TxID"}
   230  	ccid := &pb.ChaincodeID{
   231  		Name:    "ccid",
   232  		Version: "v1",
   233  	}
   234  
   235  	pHashBytes := []byte("proposal_hash")
   236  	pResponse := &pb.Response{Status: 200}
   237  	results := []byte("results")
   238  	eventBytes, err := protoutil.GetBytesChaincodeEvent(events)
   239  	if err != nil {
   240  		t.Fatalf("Failure while marshalling the ProposalResponsePayload")
   241  		return
   242  	}
   243  
   244  	// get the bytes of the response
   245  	pResponseBytes, err := protoutil.GetBytesResponse(pResponse)
   246  	if err != nil {
   247  		t.Fatalf("Failure while marshalling the Response")
   248  		return
   249  	}
   250  
   251  	// get the response from bytes
   252  	_, err = protoutil.UnmarshalResponse(pResponseBytes)
   253  	if err != nil {
   254  		t.Fatalf("Failure while unmarshalling the Response")
   255  		return
   256  	}
   257  
   258  	// get the bytes of the ProposalResponsePayload
   259  	prpBytes, err := protoutil.GetBytesProposalResponsePayload(pHashBytes, pResponse, results, eventBytes, ccid)
   260  	if err != nil {
   261  		t.Fatalf("Failure while marshalling the ProposalResponsePayload")
   262  		return
   263  	}
   264  
   265  	// get the ProposalResponsePayload message
   266  	prp, err := protoutil.UnmarshalProposalResponsePayload(prpBytes)
   267  	if err != nil {
   268  		t.Fatalf("Failure while unmarshalling the ProposalResponsePayload")
   269  		return
   270  	}
   271  
   272  	// get the ChaincodeAction message
   273  	act, err := protoutil.UnmarshalChaincodeAction(prp.Extension)
   274  	if err != nil {
   275  		t.Fatalf("Failure while unmarshalling the ChaincodeAction")
   276  		return
   277  	}
   278  
   279  	// sanity check on the action
   280  	if string(act.Results) != "results" {
   281  		t.Fatalf("Invalid actions after unmarshalling")
   282  		return
   283  	}
   284  
   285  	event, err := protoutil.UnmarshalChaincodeEvents(act.Events)
   286  	if err != nil {
   287  		t.Fatalf("Failure while unmarshalling the ChainCodeEvents")
   288  		return
   289  	}
   290  
   291  	// sanity check on the event
   292  	if string(event.ChaincodeId) != "ccid" {
   293  		t.Fatalf("Invalid actions after unmarshalling")
   294  		return
   295  	}
   296  
   297  	pr := &pb.ProposalResponse{
   298  		Payload:     prpBytes,
   299  		Endorsement: &pb.Endorsement{Endorser: []byte("endorser"), Signature: []byte("signature")},
   300  		Version:     1, // TODO: pick right version number
   301  		Response:    &pb.Response{Status: 200, Message: "OK"}}
   302  
   303  	// create a proposal response
   304  	prBytes, err := protoutil.GetBytesProposalResponse(pr)
   305  	if err != nil {
   306  		t.Fatalf("Failure while marshalling the ProposalResponse")
   307  		return
   308  	}
   309  
   310  	// get the proposal response message back
   311  	prBack, err := protoutil.UnmarshalProposalResponse(prBytes)
   312  	if err != nil {
   313  		t.Fatalf("Failure while unmarshalling the ProposalResponse")
   314  		return
   315  	}
   316  
   317  	// sanity check on pr
   318  	if prBack.Response.Status != 200 ||
   319  		string(prBack.Endorsement.Signature) != "signature" ||
   320  		string(prBack.Endorsement.Endorser) != "endorser" ||
   321  		!bytes.Equal(prBack.Payload, prpBytes) {
   322  		t.Fatalf("Invalid ProposalResponse after unmarshalling")
   323  		return
   324  	}
   325  }
   326  
   327  func TestEnvelope(t *testing.T) {
   328  	// create a proposal from a ChaincodeInvocationSpec
   329  	prop, _, err := protoutil.CreateChaincodeProposal(common.HeaderType_ENDORSER_TRANSACTION, testChannelID, createCIS(), signerSerialized)
   330  	if err != nil {
   331  		t.Fatalf("Could not create chaincode proposal, err %s\n", err)
   332  		return
   333  	}
   334  
   335  	response := &pb.Response{Status: 200, Payload: []byte("payload")}
   336  	result := []byte("res")
   337  	ccid := &pb.ChaincodeID{Name: "foo", Version: "v1"}
   338  
   339  	presp, err := protoutil.CreateProposalResponse(prop.Header, prop.Payload, response, result, nil, ccid, signer)
   340  	if err != nil {
   341  		t.Fatalf("Could not create proposal response, err %s\n", err)
   342  		return
   343  	}
   344  
   345  	tx, err := protoutil.CreateSignedTx(prop, signer, presp)
   346  	if err != nil {
   347  		t.Fatalf("Could not create signed tx, err %s\n", err)
   348  		return
   349  	}
   350  
   351  	envBytes, err := protoutil.GetBytesEnvelope(tx)
   352  	if err != nil {
   353  		t.Fatalf("Could not marshal envelope, err %s\n", err)
   354  		return
   355  	}
   356  
   357  	tx, err = protoutil.GetEnvelopeFromBlock(envBytes)
   358  	if err != nil {
   359  		t.Fatalf("Could not unmarshal envelope, err %s\n", err)
   360  		return
   361  	}
   362  
   363  	act2, err := protoutil.GetActionFromEnvelope(envBytes)
   364  	if err != nil {
   365  		t.Fatalf("Could not extract actions from envelop, err %s\n", err)
   366  		return
   367  	}
   368  
   369  	if act2.Response.Status != response.Status {
   370  		t.Fatalf("response staus don't match")
   371  		return
   372  	}
   373  	if !bytes.Equal(act2.Response.Payload, response.Payload) {
   374  		t.Fatalf("response payload don't match")
   375  		return
   376  	}
   377  
   378  	if !bytes.Equal(act2.Results, result) {
   379  		t.Fatalf("results don't match")
   380  		return
   381  	}
   382  
   383  	txpayl, err := protoutil.UnmarshalPayload(tx.Payload)
   384  	if err != nil {
   385  		t.Fatalf("Could not unmarshal payload, err %s\n", err)
   386  		return
   387  	}
   388  
   389  	tx2, err := protoutil.UnmarshalTransaction(txpayl.Data)
   390  	if err != nil {
   391  		t.Fatalf("Could not unmarshal Transaction, err %s\n", err)
   392  		return
   393  	}
   394  
   395  	sh, err := protoutil.UnmarshalSignatureHeader(tx2.Actions[0].Header)
   396  	if err != nil {
   397  		t.Fatalf("Could not unmarshal SignatureHeader, err %s\n", err)
   398  		return
   399  	}
   400  
   401  	if !bytes.Equal(sh.Creator, signerSerialized) {
   402  		t.Fatalf("creator does not match")
   403  		return
   404  	}
   405  
   406  	cap, err := protoutil.UnmarshalChaincodeActionPayload(tx2.Actions[0].Payload)
   407  	if err != nil {
   408  		t.Fatalf("Could not unmarshal ChaincodeActionPayload, err %s\n", err)
   409  		return
   410  	}
   411  	assert.NotNil(t, cap)
   412  
   413  	prp, err := protoutil.UnmarshalProposalResponsePayload(cap.Action.ProposalResponsePayload)
   414  	if err != nil {
   415  		t.Fatalf("Could not unmarshal ProposalResponsePayload, err %s\n", err)
   416  		return
   417  	}
   418  
   419  	ca, err := protoutil.UnmarshalChaincodeAction(prp.Extension)
   420  	if err != nil {
   421  		t.Fatalf("Could not unmarshal ChaincodeAction, err %s\n", err)
   422  		return
   423  	}
   424  
   425  	if ca.Response.Status != response.Status {
   426  		t.Fatalf("response staus don't match")
   427  		return
   428  	}
   429  	if !bytes.Equal(ca.Response.Payload, response.Payload) {
   430  		t.Fatalf("response payload don't match")
   431  		return
   432  	}
   433  
   434  	if !bytes.Equal(ca.Results, result) {
   435  		t.Fatalf("results don't match")
   436  		return
   437  	}
   438  }
   439  
   440  func TestProposalTxID(t *testing.T) {
   441  	nonce := []byte{1}
   442  	creator := []byte{2}
   443  
   444  	txid := protoutil.ComputeTxID(nonce, creator)
   445  	assert.NotEmpty(t, txid, "TxID cannot be empty.")
   446  	assert.Nil(t, protoutil.CheckTxID(txid, nonce, creator))
   447  	assert.Error(t, protoutil.CheckTxID("", nonce, creator))
   448  
   449  	txid = protoutil.ComputeTxID(nil, nil)
   450  	assert.NotEmpty(t, txid, "TxID cannot be empty.")
   451  }
   452  
   453  func TestComputeProposalTxID(t *testing.T) {
   454  	txid := protoutil.ComputeTxID([]byte{1}, []byte{1})
   455  
   456  	// Compute the function computed by ComputeTxID,
   457  	// namely, base64(sha256(nonce||creator))
   458  	hf := sha256.New()
   459  	hf.Write([]byte{1})
   460  	hf.Write([]byte{1})
   461  	hashOut := hf.Sum(nil)
   462  	txid2 := hex.EncodeToString(hashOut)
   463  
   464  	t.Logf("% x\n", hashOut)
   465  	t.Logf("% s\n", txid)
   466  	t.Logf("% s\n", txid2)
   467  
   468  	assert.Equal(t, txid, txid2)
   469  }
   470  
   471  var signer msp.SigningIdentity
   472  var signerSerialized []byte
   473  
   474  func TestMain(m *testing.M) {
   475  	// setup the MSP manager so that we can sign/verify
   476  	err := msptesttools.LoadMSPSetupForTesting()
   477  	if err != nil {
   478  		os.Exit(-1)
   479  		fmt.Printf("Could not initialize msp")
   480  		return
   481  	}
   482  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   483  	if err != nil {
   484  		os.Exit(-1)
   485  		fmt.Printf("Could not initialize cryptoProvider")
   486  		return
   487  	}
   488  	signer, err = mspmgmt.GetLocalMSP(cryptoProvider).GetDefaultSigningIdentity()
   489  	if err != nil {
   490  		os.Exit(-1)
   491  		fmt.Printf("Could not get signer")
   492  		return
   493  	}
   494  
   495  	signerSerialized, err = signer.Serialize()
   496  	if err != nil {
   497  		os.Exit(-1)
   498  		fmt.Printf("Could not serialize identity")
   499  		return
   500  	}
   501  
   502  	os.Exit(m.Run())
   503  }
   504  
   505  func TestInvokedChaincodeName(t *testing.T) {
   506  	t.Run("Success", func(t *testing.T) {
   507  		name, err := protoutil.InvokedChaincodeName(protoutil.MarshalOrPanic(&pb.Proposal{
   508  			Payload: protoutil.MarshalOrPanic(&pb.ChaincodeProposalPayload{
   509  				Input: protoutil.MarshalOrPanic(&pb.ChaincodeInvocationSpec{
   510  					ChaincodeSpec: &pb.ChaincodeSpec{
   511  						ChaincodeId: &pb.ChaincodeID{
   512  							Name: "cscc",
   513  						},
   514  					},
   515  				}),
   516  			}),
   517  		}))
   518  		assert.NoError(t, err)
   519  		assert.Equal(t, "cscc", name)
   520  	})
   521  
   522  	t.Run("BadProposalBytes", func(t *testing.T) {
   523  		_, err := protoutil.InvokedChaincodeName([]byte("garbage"))
   524  		assert.EqualError(t, err, "could not unmarshal proposal: proto: can't skip unknown wire type 7")
   525  	})
   526  
   527  	t.Run("BadChaincodeProposalBytes", func(t *testing.T) {
   528  		_, err := protoutil.InvokedChaincodeName(protoutil.MarshalOrPanic(&pb.Proposal{
   529  			Payload: []byte("garbage"),
   530  		}))
   531  		assert.EqualError(t, err, "could not unmarshal chaincode proposal payload: proto: can't skip unknown wire type 7")
   532  	})
   533  
   534  	t.Run("BadChaincodeInvocationSpec", func(t *testing.T) {
   535  		_, err := protoutil.InvokedChaincodeName(protoutil.MarshalOrPanic(&pb.Proposal{
   536  			Payload: protoutil.MarshalOrPanic(&pb.ChaincodeProposalPayload{
   537  				Input: []byte("garbage"),
   538  			}),
   539  		}))
   540  		assert.EqualError(t, err, "could not unmarshal chaincode invocation spec: proto: can't skip unknown wire type 7")
   541  	})
   542  
   543  	t.Run("NilChaincodeSpec", func(t *testing.T) {
   544  		_, err := protoutil.InvokedChaincodeName(protoutil.MarshalOrPanic(&pb.Proposal{
   545  			Payload: protoutil.MarshalOrPanic(&pb.ChaincodeProposalPayload{
   546  				Input: protoutil.MarshalOrPanic(&pb.ChaincodeInvocationSpec{}),
   547  			}),
   548  		}))
   549  		assert.EqualError(t, err, "chaincode spec is nil")
   550  	})
   551  
   552  	t.Run("NilChaincodeID", func(t *testing.T) {
   553  		_, err := protoutil.InvokedChaincodeName(protoutil.MarshalOrPanic(&pb.Proposal{
   554  			Payload: protoutil.MarshalOrPanic(&pb.ChaincodeProposalPayload{
   555  				Input: protoutil.MarshalOrPanic(&pb.ChaincodeInvocationSpec{
   556  					ChaincodeSpec: &pb.ChaincodeSpec{},
   557  				}),
   558  			}),
   559  		}))
   560  		assert.EqualError(t, err, "chaincode id is nil")
   561  	})
   562  }