github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/core/committer/txvalidator/validator_test.go (about)

     1  /*
     2  Copyright IBM Corp. 2017 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 txvalidator
    18  
    19  import (
    20  	"fmt"
    21  	"os"
    22  	"testing"
    23  
    24  	"github.com/hyperledger/fabric/common/cauthdsl"
    25  	ctxt "github.com/hyperledger/fabric/common/configtx/test"
    26  	"github.com/hyperledger/fabric/common/ledger/testutil"
    27  	"github.com/hyperledger/fabric/common/mocks/scc"
    28  	"github.com/hyperledger/fabric/common/util"
    29  	ccp "github.com/hyperledger/fabric/core/common/ccprovider"
    30  	"github.com/hyperledger/fabric/core/common/sysccprovider"
    31  	"github.com/hyperledger/fabric/core/ledger"
    32  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
    33  	"github.com/hyperledger/fabric/core/ledger/ledgermgmt"
    34  	lutils "github.com/hyperledger/fabric/core/ledger/util"
    35  	"github.com/hyperledger/fabric/core/mocks/ccprovider"
    36  	"github.com/hyperledger/fabric/msp"
    37  	"github.com/hyperledger/fabric/msp/mgmt"
    38  	"github.com/hyperledger/fabric/msp/mgmt/testtools"
    39  	"github.com/hyperledger/fabric/protos/common"
    40  	"github.com/hyperledger/fabric/protos/peer"
    41  	"github.com/hyperledger/fabric/protos/utils"
    42  	"github.com/spf13/viper"
    43  	"github.com/stretchr/testify/assert"
    44  )
    45  
    46  func signedByAnyMember(ids []string) []byte {
    47  	p := cauthdsl.SignedByAnyMember(ids)
    48  	return utils.MarshalOrPanic(p)
    49  }
    50  
    51  func setupLedgerAndValidator(t *testing.T) (ledger.PeerLedger, Validator) {
    52  	viper.Set("peer.fileSystemPath", "/tmp/fabric/validatortest")
    53  	ledgermgmt.InitializeTestEnv()
    54  	gb, err := ctxt.MakeGenesisBlock("TestLedger")
    55  	assert.NoError(t, err)
    56  	theLedger, err := ledgermgmt.CreateLedger(gb)
    57  	assert.NoError(t, err)
    58  	theValidator := NewTxValidator(&mockSupport{l: theLedger})
    59  
    60  	return theLedger, theValidator
    61  }
    62  
    63  func createRWset(t *testing.T, ccnames ...string) []byte {
    64  	rwsetBuilder := rwsetutil.NewRWSetBuilder()
    65  	for _, ccname := range ccnames {
    66  		rwsetBuilder.AddToWriteSet(ccname, "key", []byte("value"))
    67  	}
    68  	rwset := rwsetBuilder.GetTxReadWriteSet()
    69  	rws, err := rwset.ToProtoBytes()
    70  	assert.NoError(t, err)
    71  	return rws
    72  }
    73  
    74  func getProposal(ccID string) (*peer.Proposal, error) {
    75  	cis := &peer.ChaincodeInvocationSpec{
    76  		ChaincodeSpec: &peer.ChaincodeSpec{
    77  			ChaincodeId: &peer.ChaincodeID{Name: ccID, Version: ccVersion},
    78  			Input:       &peer.ChaincodeInput{Args: [][]byte{[]byte("func")}},
    79  			Type:        peer.ChaincodeSpec_GOLANG}}
    80  
    81  	proposal, _, err := utils.CreateProposalFromCIS(common.HeaderType_ENDORSER_TRANSACTION, util.GetTestChainID(), cis, signerSerialized)
    82  	return proposal, err
    83  }
    84  
    85  const ccVersion = "1.0"
    86  
    87  func getEnv(ccID string, res []byte, t *testing.T) *common.Envelope {
    88  	// get a toy proposal
    89  	prop, err := getProposal(ccID)
    90  	assert.NoError(t, err)
    91  
    92  	response := &peer.Response{Status: 200}
    93  
    94  	// endorse it to get a proposal response
    95  	presp, err := utils.CreateProposalResponse(prop.Header, prop.Payload, response, res, nil, &peer.ChaincodeID{Name: ccID, Version: ccVersion}, nil, signer)
    96  	assert.NoError(t, err)
    97  
    98  	// assemble a transaction from that proposal and endorsement
    99  	tx, err := utils.CreateSignedTx(prop, signer, presp)
   100  	assert.NoError(t, err)
   101  
   102  	return tx
   103  }
   104  
   105  func putCCInfoWithVSCCAndVer(theLedger ledger.PeerLedger, ccname, vscc, ver string, policy []byte, t *testing.T) {
   106  	cd := &ccp.ChaincodeData{
   107  		Name:    ccname,
   108  		Version: ver,
   109  		Vscc:    vscc,
   110  		Policy:  policy,
   111  	}
   112  
   113  	cdbytes := utils.MarshalOrPanic(cd)
   114  
   115  	simulator, err := theLedger.NewTxSimulator()
   116  	assert.NoError(t, err)
   117  	simulator.SetState("lscc", ccname, cdbytes)
   118  	simulator.Done()
   119  
   120  	simRes, err := simulator.GetTxSimulationResults()
   121  	assert.NoError(t, err)
   122  	block0 := testutil.ConstructBlock(t, 1, []byte("hash"), [][]byte{simRes}, true)
   123  	err = theLedger.Commit(block0)
   124  	assert.NoError(t, err)
   125  }
   126  
   127  func putCCInfo(theLedger ledger.PeerLedger, ccname string, policy []byte, t *testing.T) {
   128  	putCCInfoWithVSCCAndVer(theLedger, ccname, "vscc", ccVersion, policy, t)
   129  }
   130  
   131  type mockSupport struct {
   132  	l ledger.PeerLedger
   133  }
   134  
   135  func (m *mockSupport) Ledger() ledger.PeerLedger {
   136  	return m.l
   137  }
   138  
   139  func (m *mockSupport) MSPManager() msp.MSPManager {
   140  	return mgmt.GetManagerForChain(util.GetTestChainID())
   141  }
   142  
   143  func (m *mockSupport) Apply(configtx *common.ConfigEnvelope) error {
   144  	return nil
   145  }
   146  
   147  func (m *mockSupport) GetMSPIDs(cid string) []string {
   148  	return []string{"DEFAULT"}
   149  }
   150  
   151  func assertInvalid(block *common.Block, t *testing.T, code peer.TxValidationCode) {
   152  	txsFilter := lutils.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
   153  	assert.True(t, txsFilter.IsInvalid(0))
   154  	assert.True(t, txsFilter.IsSetTo(0, code))
   155  }
   156  
   157  func assertValid(block *common.Block, t *testing.T) {
   158  	txsFilter := lutils.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
   159  	assert.False(t, txsFilter.IsInvalid(0))
   160  }
   161  
   162  func TestInvokeBadRWSet(t *testing.T) {
   163  	l, v := setupLedgerAndValidator(t)
   164  	defer ledgermgmt.CleanupTestEnv()
   165  	defer l.Close()
   166  
   167  	ccID := "mycc"
   168  
   169  	tx := getEnv(ccID, []byte("barf"), t)
   170  	b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}}
   171  
   172  	err := v.Validate(b)
   173  	assert.NoError(t, err)
   174  	assertInvalid(b, t, peer.TxValidationCode_BAD_RWSET)
   175  }
   176  
   177  func TestInvokeNoPolicy(t *testing.T) {
   178  	l, v := setupLedgerAndValidator(t)
   179  	defer ledgermgmt.CleanupTestEnv()
   180  	defer l.Close()
   181  
   182  	ccID := "mycc"
   183  
   184  	putCCInfo(l, ccID, nil, t)
   185  
   186  	tx := getEnv(ccID, createRWset(t, ccID), t)
   187  	b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}}
   188  
   189  	err := v.Validate(b)
   190  	assert.NoError(t, err)
   191  	assertInvalid(b, t, peer.TxValidationCode_INVALID_OTHER_REASON)
   192  }
   193  
   194  func TestInvokeOK(t *testing.T) {
   195  	l, v := setupLedgerAndValidator(t)
   196  	defer ledgermgmt.CleanupTestEnv()
   197  	defer l.Close()
   198  
   199  	ccID := "mycc"
   200  
   201  	putCCInfo(l, ccID, signedByAnyMember([]string{"DEFAULT"}), t)
   202  
   203  	tx := getEnv(ccID, createRWset(t, ccID), t)
   204  	b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}}
   205  
   206  	err := v.Validate(b)
   207  	assert.NoError(t, err)
   208  	assertValid(b, t)
   209  }
   210  
   211  func TestInvokeOKSCC(t *testing.T) {
   212  	l, v := setupLedgerAndValidator(t)
   213  	defer ledgermgmt.CleanupTestEnv()
   214  	defer l.Close()
   215  
   216  	ccID := "lscc"
   217  
   218  	putCCInfo(l, ccID, signedByAnyMember([]string{"DEFAULT"}), t)
   219  
   220  	tx := getEnv(ccID, createRWset(t, ccID), t)
   221  	b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}}
   222  
   223  	err := v.Validate(b)
   224  	assert.NoError(t, err)
   225  	assertValid(b, t)
   226  }
   227  
   228  func TestInvokeNOKWritesToLSCC(t *testing.T) {
   229  	l, v := setupLedgerAndValidator(t)
   230  	defer ledgermgmt.CleanupTestEnv()
   231  	defer l.Close()
   232  
   233  	ccID := "mycc"
   234  
   235  	putCCInfo(l, ccID, signedByAnyMember([]string{"DEFAULT"}), t)
   236  
   237  	tx := getEnv(ccID, createRWset(t, ccID, "lscc"), t)
   238  	b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}}
   239  
   240  	err := v.Validate(b)
   241  	assert.NoError(t, err)
   242  	assertInvalid(b, t, peer.TxValidationCode_ILLEGAL_WRITESET)
   243  }
   244  
   245  func TestInvokeNOKWritesToESCC(t *testing.T) {
   246  	l, v := setupLedgerAndValidator(t)
   247  	defer ledgermgmt.CleanupTestEnv()
   248  	defer l.Close()
   249  
   250  	ccID := "mycc"
   251  
   252  	putCCInfo(l, ccID, signedByAnyMember([]string{"DEFAULT"}), t)
   253  
   254  	tx := getEnv(ccID, createRWset(t, ccID, "escc"), t)
   255  	b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}}
   256  
   257  	err := v.Validate(b)
   258  	assert.NoError(t, err)
   259  	assertInvalid(b, t, peer.TxValidationCode_ILLEGAL_WRITESET)
   260  }
   261  
   262  func TestInvokeNOKWritesToNotExt(t *testing.T) {
   263  	l, v := setupLedgerAndValidator(t)
   264  	defer ledgermgmt.CleanupTestEnv()
   265  	defer l.Close()
   266  
   267  	ccID := "mycc"
   268  
   269  	putCCInfo(l, ccID, signedByAnyMember([]string{"DEFAULT"}), t)
   270  
   271  	tx := getEnv(ccID, createRWset(t, ccID, "notext"), t)
   272  	b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}}
   273  
   274  	err := v.Validate(b)
   275  	assert.NoError(t, err)
   276  	assertInvalid(b, t, peer.TxValidationCode_ILLEGAL_WRITESET)
   277  }
   278  
   279  func TestInvokeNOKInvokesNotExt(t *testing.T) {
   280  	l, v := setupLedgerAndValidator(t)
   281  	defer ledgermgmt.CleanupTestEnv()
   282  	defer l.Close()
   283  
   284  	ccID := "notext"
   285  
   286  	putCCInfo(l, ccID, signedByAnyMember([]string{"DEFAULT"}), t)
   287  
   288  	tx := getEnv(ccID, createRWset(t, ccID), t)
   289  	b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}}
   290  
   291  	err := v.Validate(b)
   292  	assert.NoError(t, err)
   293  	assertInvalid(b, t, peer.TxValidationCode_ILLEGAL_WRITESET)
   294  }
   295  
   296  func TestInvokeNOKInvokesEmptyCCName(t *testing.T) {
   297  	l, v := setupLedgerAndValidator(t)
   298  	defer ledgermgmt.CleanupTestEnv()
   299  	defer l.Close()
   300  
   301  	ccID := ""
   302  
   303  	putCCInfo(l, ccID, signedByAnyMember([]string{"DEFAULT"}), t)
   304  
   305  	tx := getEnv(ccID, createRWset(t, ccID), t)
   306  	b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}}
   307  
   308  	err := v.Validate(b)
   309  	assert.NoError(t, err)
   310  	assertInvalid(b, t, peer.TxValidationCode_INVALID_OTHER_REASON)
   311  }
   312  
   313  func TestInvokeNOKExpiredCC(t *testing.T) {
   314  	l, v := setupLedgerAndValidator(t)
   315  	defer ledgermgmt.CleanupTestEnv()
   316  	defer l.Close()
   317  
   318  	ccID := "mycc"
   319  
   320  	putCCInfoWithVSCCAndVer(l, ccID, "vscc", "badversion", signedByAnyMember([]string{"DEFAULT"}), t)
   321  
   322  	tx := getEnv(ccID, createRWset(t, ccID), t)
   323  	b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}}
   324  
   325  	err := v.Validate(b)
   326  	assert.NoError(t, err)
   327  	assertInvalid(b, t, peer.TxValidationCode_EXPIRED_CHAINCODE)
   328  }
   329  
   330  func TestInvokeNOKBogusActions(t *testing.T) {
   331  	l, v := setupLedgerAndValidator(t)
   332  	defer ledgermgmt.CleanupTestEnv()
   333  	defer l.Close()
   334  
   335  	ccID := "mycc"
   336  
   337  	putCCInfo(l, ccID, signedByAnyMember([]string{"DEFAULT"}), t)
   338  
   339  	tx := getEnv(ccID, []byte("barf"), t)
   340  	b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}}
   341  
   342  	err := v.Validate(b)
   343  	assert.NoError(t, err)
   344  	assertInvalid(b, t, peer.TxValidationCode_BAD_RWSET)
   345  }
   346  
   347  func TestInvokeNOKCCDoesntExist(t *testing.T) {
   348  	l, v := setupLedgerAndValidator(t)
   349  	defer ledgermgmt.CleanupTestEnv()
   350  	defer l.Close()
   351  
   352  	ccID := "mycc"
   353  
   354  	tx := getEnv(ccID, createRWset(t, ccID), t)
   355  	b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}}
   356  
   357  	err := v.Validate(b)
   358  	assert.NoError(t, err)
   359  	assertInvalid(b, t, peer.TxValidationCode_INVALID_OTHER_REASON)
   360  }
   361  
   362  func TestInvokeNOKVSCCUnspecified(t *testing.T) {
   363  	l, v := setupLedgerAndValidator(t)
   364  	defer ledgermgmt.CleanupTestEnv()
   365  	defer l.Close()
   366  
   367  	ccID := "mycc"
   368  
   369  	putCCInfoWithVSCCAndVer(l, ccID, "", ccVersion, signedByAnyMember([]string{"DEFAULT"}), t)
   370  
   371  	tx := getEnv(ccID, createRWset(t, ccID), t)
   372  	b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}}
   373  
   374  	err := v.Validate(b)
   375  	assert.NoError(t, err)
   376  	assertInvalid(b, t, peer.TxValidationCode_INVALID_OTHER_REASON)
   377  }
   378  
   379  func TestInvokeNoBlock(t *testing.T) {
   380  	l, v := setupLedgerAndValidator(t)
   381  	defer ledgermgmt.CleanupTestEnv()
   382  	defer l.Close()
   383  
   384  	err := v.Validate(&common.Block{Data: &common.BlockData{Data: [][]byte{}}})
   385  	assert.NoError(t, err)
   386  }
   387  
   388  var signer msp.SigningIdentity
   389  var signerSerialized []byte
   390  
   391  func TestMain(m *testing.M) {
   392  	sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{})
   393  	ccp.RegisterChaincodeProviderFactory(&ccprovider.MockCcProviderFactory{})
   394  
   395  	msptesttools.LoadMSPSetupForTesting()
   396  
   397  	var err error
   398  	signer, err = mgmt.GetLocalMSP().GetDefaultSigningIdentity()
   399  	if err != nil {
   400  		fmt.Println("Could not get signer")
   401  		os.Exit(-1)
   402  		return
   403  	}
   404  
   405  	signerSerialized, err = signer.Serialize()
   406  	if err != nil {
   407  		fmt.Println("Could not serialize identity")
   408  		os.Exit(-1)
   409  		return
   410  	}
   411  
   412  	os.Exit(m.Run())
   413  }