github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/core/common/validation/fullflow_test.go (about)

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