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