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

     1  /*
     2  Copyright hechain. 2022 All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package validation
     8  
     9  import (
    10  	"fmt"
    11  	"math/rand"
    12  	"os"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/hechain20/hechain/bccsp/sw"
    17  	"github.com/hechain20/hechain/msp"
    18  	mspmgmt "github.com/hechain20/hechain/msp/mgmt"
    19  	msptesttools "github.com/hechain20/hechain/msp/mgmt/testtools"
    20  	"github.com/hechain20/hechain/protoutil"
    21  	"github.com/hyperledger/fabric-protos-go/common"
    22  	"github.com/hyperledger/fabric-protos-go/peer"
    23  	"github.com/stretchr/testify/require"
    24  )
    25  
    26  func getProposal(channelID string) (*peer.Proposal, error) {
    27  	cis := &peer.ChaincodeInvocationSpec{
    28  		ChaincodeSpec: &peer.ChaincodeSpec{
    29  			ChaincodeId: getChaincodeID(),
    30  			Type:        peer.ChaincodeSpec_GOLANG,
    31  		},
    32  	}
    33  
    34  	proposal, _, err := protoutil.CreateProposalFromCIS(common.HeaderType_ENDORSER_TRANSACTION, channelID, cis, signerSerialized)
    35  	return proposal, err
    36  }
    37  
    38  func getChaincodeID() *peer.ChaincodeID {
    39  	return &peer.ChaincodeID{Name: "foo", Version: "v1"}
    40  }
    41  
    42  func createSignedTxTwoActions(proposal *peer.Proposal, signer msp.SigningIdentity, resps ...*peer.ProposalResponse) (*common.Envelope, error) {
    43  	if len(resps) == 0 {
    44  		return nil, fmt.Errorf("At least one proposal response is necessary")
    45  	}
    46  
    47  	// the original header
    48  	hdr, err := protoutil.UnmarshalHeader(proposal.Header)
    49  	if err != nil {
    50  		return nil, fmt.Errorf("Could not unmarshal the proposal header")
    51  	}
    52  
    53  	// the original payload
    54  	pPayl, err := protoutil.UnmarshalChaincodeProposalPayload(proposal.Payload)
    55  	if err != nil {
    56  		return nil, fmt.Errorf("Could not unmarshal the proposal payload")
    57  	}
    58  
    59  	// fill endorsements
    60  	endorsements := make([]*peer.Endorsement, len(resps))
    61  	for n, r := range resps {
    62  		endorsements[n] = r.Endorsement
    63  	}
    64  
    65  	// create ChaincodeEndorsedAction
    66  	cea := &peer.ChaincodeEndorsedAction{ProposalResponsePayload: resps[0].Payload, Endorsements: endorsements}
    67  
    68  	// obtain the bytes of the proposal payload that will go to the transaction
    69  	propPayloadBytes, err := protoutil.GetBytesProposalPayloadForTx(pPayl)
    70  	if err != nil {
    71  		return nil, err
    72  	}
    73  
    74  	// serialize the chaincode action payload
    75  	cap := &peer.ChaincodeActionPayload{ChaincodeProposalPayload: propPayloadBytes, Action: cea}
    76  	capBytes, err := protoutil.GetBytesChaincodeActionPayload(cap)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  
    81  	// create a transaction
    82  	taa := &peer.TransactionAction{Header: hdr.SignatureHeader, Payload: capBytes}
    83  	taas := make([]*peer.TransactionAction, 2)
    84  	taas[0] = taa
    85  	taas[1] = taa
    86  	tx := &peer.Transaction{Actions: taas}
    87  
    88  	// serialize the tx
    89  	txBytes, err := protoutil.GetBytesTransaction(tx)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  
    94  	// create the payload
    95  	payl := &common.Payload{Header: hdr, Data: txBytes}
    96  	paylBytes, err := protoutil.GetBytesPayload(payl)
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  
   101  	// sign the payload
   102  	sig, err := signer.Sign(paylBytes)
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  
   107  	// here's the envelope
   108  	return &common.Envelope{Payload: paylBytes, Signature: sig}, nil
   109  }
   110  
   111  func TestGoodPath(t *testing.T) {
   112  	// get a toy proposal
   113  	prop, err := getProposal("testchannelid")
   114  	if err != nil {
   115  		t.Fatalf("getProposal failed, err %s", err)
   116  		return
   117  	}
   118  
   119  	response := &peer.Response{Status: 200}
   120  	simRes := []byte("simulation_result")
   121  
   122  	// endorse it to get a proposal response
   123  	presp, err := protoutil.CreateProposalResponse(prop.Header, prop.Payload, response, simRes, nil, getChaincodeID(), signer)
   124  	if err != nil {
   125  		t.Fatalf("CreateProposalResponse failed, err %s", err)
   126  		return
   127  	}
   128  
   129  	// assemble a transaction from that proposal and endorsement
   130  	tx, err := protoutil.CreateSignedTx(prop, signer, presp)
   131  	if err != nil {
   132  		t.Fatalf("CreateSignedTx failed, err %s", err)
   133  		return
   134  	}
   135  
   136  	// validate the transaction
   137  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   138  	require.NoError(t, err)
   139  	payl, txResult := ValidateTransaction(tx, cryptoProvider)
   140  	if txResult != peer.TxValidationCode_VALID {
   141  		t.Fatalf("ValidateTransaction failed, err %s", err)
   142  		return
   143  	}
   144  
   145  	txx, err := protoutil.UnmarshalTransaction(payl.Data)
   146  	if err != nil {
   147  		t.Fatalf("GetTransaction failed, err %s", err)
   148  		return
   149  	}
   150  
   151  	act := txx.Actions
   152  
   153  	// expect one single action
   154  	if len(act) != 1 {
   155  		t.Fatalf("Ivalid number of TransactionAction, expected 1, got %d", len(act))
   156  		return
   157  	}
   158  
   159  	// get the payload of the action
   160  	_, simResBack, err := protoutil.GetPayloads(act[0])
   161  	if err != nil {
   162  		t.Fatalf("GetPayloads failed, err %s", err)
   163  		return
   164  	}
   165  
   166  	// compare it to the original action and expect it to be equal
   167  	if string(simRes) != string(simResBack.Results) {
   168  		t.Fatal("Simulation results are different")
   169  		return
   170  	}
   171  }
   172  
   173  func TestTXWithTwoActionsRejected(t *testing.T) {
   174  	// get a toy proposal
   175  	prop, err := getProposal("testchannelid")
   176  	if err != nil {
   177  		t.Fatalf("getProposal failed, err %s", err)
   178  		return
   179  	}
   180  
   181  	response := &peer.Response{Status: 200}
   182  	simRes := []byte("simulation_result")
   183  
   184  	// endorse it to get a proposal response
   185  	presp, err := protoutil.CreateProposalResponse(prop.Header, prop.Payload, response, simRes, nil, &peer.ChaincodeID{Name: "somename", Version: "someversion"}, signer)
   186  	if err != nil {
   187  		t.Fatalf("CreateProposalResponse failed, err %s", err)
   188  		return
   189  	}
   190  
   191  	// assemble a transaction from that proposal and endorsement
   192  	tx, err := createSignedTxTwoActions(prop, signer, presp)
   193  	if err != nil {
   194  		t.Fatalf("CreateSignedTx failed, err %s", err)
   195  		return
   196  	}
   197  
   198  	// validate the transaction
   199  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   200  	require.NoError(t, err)
   201  	_, txResult := ValidateTransaction(tx, cryptoProvider)
   202  	if txResult == peer.TxValidationCode_VALID {
   203  		t.Fatalf("ValidateTransaction should have failed")
   204  		return
   205  	}
   206  }
   207  
   208  func corrupt(bytes []byte) {
   209  	rand.Seed(time.Now().UnixNano())
   210  	bytes[rand.Intn(len(bytes))]--
   211  }
   212  
   213  func TestBadTx(t *testing.T) {
   214  	// get a toy proposal
   215  	prop, err := getProposal("testchannelid")
   216  	if err != nil {
   217  		t.Fatalf("getProposal failed, err %s", err)
   218  		return
   219  	}
   220  
   221  	response := &peer.Response{Status: 200}
   222  	simRes := []byte("simulation_result")
   223  
   224  	// endorse it to get a proposal response
   225  	presp, err := protoutil.CreateProposalResponse(prop.Header, prop.Payload, response, simRes, nil, getChaincodeID(), signer)
   226  	if err != nil {
   227  		t.Fatalf("CreateProposalResponse failed, err %s", err)
   228  		return
   229  	}
   230  
   231  	// assemble a transaction from that proposal and endorsement
   232  	tx, err := protoutil.CreateSignedTx(prop, signer, presp)
   233  	if err != nil {
   234  		t.Fatalf("CreateSignedTx failed, err %s", err)
   235  		return
   236  	}
   237  
   238  	// mess with the transaction payload
   239  	paylOrig := tx.Payload
   240  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   241  	require.NoError(t, err)
   242  	for i := 0; i < len(paylOrig); i++ {
   243  		paylCopy := make([]byte, len(paylOrig))
   244  		copy(paylCopy, paylOrig)
   245  		paylCopy[i] = byte(int(paylCopy[i]+1) % 255)
   246  		// validate the transaction it should fail
   247  		_, txResult := ValidateTransaction(&common.Envelope{Signature: tx.Signature, Payload: paylCopy}, cryptoProvider)
   248  		if txResult == peer.TxValidationCode_VALID {
   249  			t.Fatal("ValidateTransaction should have failed")
   250  			return
   251  		}
   252  	}
   253  
   254  	// assemble a transaction from that proposal and endorsement
   255  	tx, err = protoutil.CreateSignedTx(prop, signer, presp)
   256  	if err != nil {
   257  		t.Fatalf("CreateSignedTx failed, err %s", err)
   258  		return
   259  	}
   260  
   261  	// mess with the transaction payload
   262  	corrupt(tx.Signature)
   263  
   264  	// validate the transaction it should fail
   265  	_, txResult := ValidateTransaction(tx, cryptoProvider)
   266  	if txResult == peer.TxValidationCode_VALID {
   267  		t.Fatal("ValidateTransaction should have failed")
   268  		return
   269  	}
   270  }
   271  
   272  func Test2EndorsersAgree(t *testing.T) {
   273  	// get a toy proposal
   274  	prop, err := getProposal("testchannelid")
   275  	if err != nil {
   276  		t.Fatalf("getProposal failed, err %s", err)
   277  		return
   278  	}
   279  
   280  	response1 := &peer.Response{Status: 200}
   281  	simRes1 := []byte("simulation_result")
   282  
   283  	// endorse it to get a proposal response
   284  	presp1, err := protoutil.CreateProposalResponse(prop.Header, prop.Payload, response1, simRes1, nil, getChaincodeID(), signer)
   285  	if err != nil {
   286  		t.Fatalf("CreateProposalResponse failed, err %s", err)
   287  		return
   288  	}
   289  
   290  	response2 := &peer.Response{Status: 200}
   291  	simRes2 := []byte("simulation_result")
   292  
   293  	// endorse it to get a proposal response
   294  	presp2, err := protoutil.CreateProposalResponse(prop.Header, prop.Payload, response2, simRes2, nil, getChaincodeID(), signer)
   295  	if err != nil {
   296  		t.Fatalf("CreateProposalResponse failed, err %s", err)
   297  		return
   298  	}
   299  
   300  	// assemble a transaction from that proposal and endorsement
   301  	tx, err := protoutil.CreateSignedTx(prop, signer, presp1, presp2)
   302  	if err != nil {
   303  		t.Fatalf("CreateSignedTx failed, err %s", err)
   304  		return
   305  	}
   306  
   307  	// validate the transaction
   308  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   309  	require.NoError(t, err)
   310  	_, txResult := ValidateTransaction(tx, cryptoProvider)
   311  	if txResult != peer.TxValidationCode_VALID {
   312  		t.Fatalf("ValidateTransaction failed, err %s", err)
   313  		return
   314  	}
   315  }
   316  
   317  func Test2EndorsersDisagree(t *testing.T) {
   318  	// get a toy proposal
   319  	prop, err := getProposal("testchannelid")
   320  	if err != nil {
   321  		t.Fatalf("getProposal failed, err %s", err)
   322  		return
   323  	}
   324  
   325  	response1 := &peer.Response{Status: 200}
   326  	simRes1 := []byte("simulation_result1")
   327  
   328  	// endorse it to get a proposal response
   329  	presp1, err := protoutil.CreateProposalResponse(prop.Header, prop.Payload, response1, simRes1, nil, getChaincodeID(), signer)
   330  	if err != nil {
   331  		t.Fatalf("CreateProposalResponse failed, err %s", err)
   332  		return
   333  	}
   334  
   335  	response2 := &peer.Response{Status: 200}
   336  	simRes2 := []byte("simulation_result2")
   337  
   338  	// endorse it to get a proposal response
   339  	presp2, err := protoutil.CreateProposalResponse(prop.Header, prop.Payload, response2, simRes2, nil, getChaincodeID(), signer)
   340  	if err != nil {
   341  		t.Fatalf("CreateProposalResponse failed, err %s", err)
   342  		return
   343  	}
   344  
   345  	// assemble a transaction from that proposal and endorsement
   346  	_, err = protoutil.CreateSignedTx(prop, signer, presp1, presp2)
   347  	if err == nil {
   348  		t.Fatal("CreateSignedTx should have failed")
   349  		return
   350  	}
   351  }
   352  
   353  func TestInvocationsBadArgs(t *testing.T) {
   354  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   355  	require.NoError(t, err)
   356  
   357  	_, code := ValidateTransaction(nil, cryptoProvider)
   358  	require.Equal(t, code, peer.TxValidationCode_NIL_ENVELOPE)
   359  	err = validateEndorserTransaction(nil, nil)
   360  	require.Error(t, err)
   361  	err = validateConfigTransaction(nil, nil)
   362  	require.Error(t, err)
   363  	_, _, err = validateCommonHeader(nil)
   364  	require.Error(t, err)
   365  	err = validateChannelHeader(nil)
   366  	require.Error(t, err)
   367  	err = validateChannelHeader(&common.ChannelHeader{})
   368  	require.Error(t, err)
   369  	err = validateSignatureHeader(nil)
   370  	require.Error(t, err)
   371  	err = validateSignatureHeader(&common.SignatureHeader{})
   372  	require.Error(t, err)
   373  	err = validateSignatureHeader(&common.SignatureHeader{Nonce: []byte("a")})
   374  	require.Error(t, err)
   375  	err = checkSignatureFromCreator(nil, nil, nil, "", cryptoProvider)
   376  	require.Error(t, err)
   377  }
   378  
   379  var (
   380  	signer           msp.SigningIdentity
   381  	signerSerialized []byte
   382  	signerMSPId      string
   383  )
   384  
   385  func TestMain(m *testing.M) {
   386  	// setup crypto algorithms
   387  	// setup the MSP manager so that we can sign/verify
   388  	err := msptesttools.LoadMSPSetupForTesting()
   389  	if err != nil {
   390  		fmt.Printf("Could not initialize msp, err %s", err)
   391  		os.Exit(-1)
   392  		return
   393  	}
   394  
   395  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   396  	if err != nil {
   397  		fmt.Printf("Initialize cryptoProvider bccsp failed: %s", err)
   398  		os.Exit(-1)
   399  		return
   400  	}
   401  
   402  	signer, err = mspmgmt.GetLocalMSP(cryptoProvider).GetDefaultSigningIdentity()
   403  	if err != nil {
   404  		fmt.Println("Could not get signer")
   405  		os.Exit(-1)
   406  		return
   407  	}
   408  	signerMSPId = signer.GetMSPIdentifier()
   409  
   410  	signerSerialized, err = signer.Serialize()
   411  	if err != nil {
   412  		fmt.Println("Could not serialize identity")
   413  		os.Exit(-1)
   414  		return
   415  	}
   416  
   417  	os.Exit(m.Run())
   418  }