github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/core/ledger/kvledger/txmgmt/validator/statebasedval/state_based_validator_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 statebasedval
    18  
    19  import (
    20  	"os"
    21  	"testing"
    22  
    23  	"github.com/hyperledger/fabric/common/ledger/testutil"
    24  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
    25  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/statedb"
    26  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/statedb/stateleveldb"
    27  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version"
    28  	"github.com/hyperledger/fabric/core/ledger/util"
    29  	"github.com/hyperledger/fabric/protos/common"
    30  	"github.com/hyperledger/fabric/protos/ledger/rwset/kvrwset"
    31  	"github.com/hyperledger/fabric/protos/peer"
    32  	"github.com/spf13/viper"
    33  )
    34  
    35  func TestMain(m *testing.M) {
    36  	viper.Set("peer.fileSystemPath", "/tmp/fabric/ledgertests/kvledger/txmgmt/validator/statebasedval")
    37  	os.Exit(m.Run())
    38  }
    39  
    40  func TestValidator(t *testing.T) {
    41  	testDBEnv := stateleveldb.NewTestVDBEnv(t)
    42  	defer testDBEnv.Cleanup()
    43  
    44  	db, err := testDBEnv.DBProvider.GetDBHandle("TestDB")
    45  	testutil.AssertNoError(t, err, "")
    46  
    47  	//populate db with initial data
    48  	batch := statedb.NewUpdateBatch()
    49  	batch.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 0))
    50  	batch.Put("ns1", "key2", []byte("value2"), version.NewHeight(1, 1))
    51  	batch.Put("ns1", "key3", []byte("value3"), version.NewHeight(1, 2))
    52  	batch.Put("ns1", "key4", []byte("value4"), version.NewHeight(1, 3))
    53  	batch.Put("ns1", "key5", []byte("value5"), version.NewHeight(1, 4))
    54  	db.ApplyUpdates(batch, version.NewHeight(1, 4))
    55  
    56  	validator := NewValidator(db)
    57  
    58  	//rwset1 should be valid
    59  	rwsetBuilder1 := rwsetutil.NewRWSetBuilder()
    60  	rwsetBuilder1.AddToReadSet("ns1", "key1", version.NewHeight(1, 0))
    61  	rwsetBuilder1.AddToReadSet("ns2", "key2", nil)
    62  	checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder1.GetTxReadWriteSet()}, nil, []int{})
    63  
    64  	//rwset2 should not be valid
    65  	rwsetBuilder2 := rwsetutil.NewRWSetBuilder()
    66  	rwsetBuilder2.AddToReadSet("ns1", "key1", version.NewHeight(1, 1))
    67  	checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder2.GetTxReadWriteSet()}, nil, []int{0})
    68  
    69  	//rwset3 should not be valid
    70  	rwsetBuilder3 := rwsetutil.NewRWSetBuilder()
    71  	rwsetBuilder3.AddToReadSet("ns1", "key1", nil)
    72  	checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder3.GetTxReadWriteSet()}, nil, []int{0})
    73  
    74  	// rwset4 and rwset5 within same block - rwset4 should be valid and makes rwset5 as invalid
    75  	rwsetBuilder4 := rwsetutil.NewRWSetBuilder()
    76  	rwsetBuilder4.AddToReadSet("ns1", "key1", version.NewHeight(1, 0))
    77  	rwsetBuilder4.AddToWriteSet("ns1", "key1", []byte("value1_new"))
    78  
    79  	rwsetBuilder5 := rwsetutil.NewRWSetBuilder()
    80  	rwsetBuilder5.AddToReadSet("ns1", "key1", version.NewHeight(1, 0))
    81  	checkValidation(t, validator,
    82  		[]*rwsetutil.TxRwSet{rwsetBuilder4.GetTxReadWriteSet(), rwsetBuilder5.GetTxReadWriteSet()}, nil, []int{1})
    83  }
    84  
    85  func TestValidatorSkipInvalidTxs(t *testing.T) {
    86  	testDBEnv := stateleveldb.NewTestVDBEnv(t)
    87  	defer testDBEnv.Cleanup()
    88  	db, err := testDBEnv.DBProvider.GetDBHandle("TestDB")
    89  	testutil.AssertNoError(t, err, "")
    90  	validator := NewValidator(db)
    91  
    92  	rwsetBuilder1 := rwsetutil.NewRWSetBuilder()
    93  	rwsetBuilder1.AddToWriteSet("ns1", "key1", []byte("value1"))
    94  	rwsetBuilder2 := rwsetutil.NewRWSetBuilder()
    95  	rwsetBuilder2.AddToWriteSet("ns1", "key2", []byte("value2"))
    96  	rwsetBuilder3 := rwsetutil.NewRWSetBuilder()
    97  	rwsetBuilder3.AddToWriteSet("ns1", "key3", []byte("value3"))
    98  	flags := util.NewTxValidationFlags(4)
    99  	flags.SetFlag(1, peer.TxValidationCode_BAD_CREATOR_SIGNATURE)
   100  	checkValidation(t, validator,
   101  		[]*rwsetutil.TxRwSet{rwsetBuilder1.GetTxReadWriteSet(), rwsetBuilder2.GetTxReadWriteSet(), rwsetBuilder3.GetTxReadWriteSet()},
   102  		flags, []int{1})
   103  }
   104  
   105  func TestPhantomValidation(t *testing.T) {
   106  	testDBEnv := stateleveldb.NewTestVDBEnv(t)
   107  	defer testDBEnv.Cleanup()
   108  
   109  	db, err := testDBEnv.DBProvider.GetDBHandle("TestDB")
   110  	testutil.AssertNoError(t, err, "")
   111  
   112  	//populate db with initial data
   113  	batch := statedb.NewUpdateBatch()
   114  	batch.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 0))
   115  	batch.Put("ns1", "key2", []byte("value2"), version.NewHeight(1, 1))
   116  	batch.Put("ns1", "key3", []byte("value3"), version.NewHeight(1, 2))
   117  	batch.Put("ns1", "key4", []byte("value4"), version.NewHeight(1, 3))
   118  	batch.Put("ns1", "key5", []byte("value5"), version.NewHeight(1, 4))
   119  	db.ApplyUpdates(batch, version.NewHeight(1, 4))
   120  
   121  	validator := NewValidator(db)
   122  
   123  	//rwset1 should be valid
   124  	rwsetBuilder1 := rwsetutil.NewRWSetBuilder()
   125  	rqi1 := &kvrwset.RangeQueryInfo{StartKey: "key2", EndKey: "key4", ItrExhausted: true}
   126  	rqi1.SetRawReads([]*kvrwset.KVRead{
   127  		rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)),
   128  		rwsetutil.NewKVRead("key3", version.NewHeight(1, 2))})
   129  	rwsetBuilder1.AddToRangeQuerySet("ns1", rqi1)
   130  	checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder1.GetTxReadWriteSet()}, nil, []int{})
   131  
   132  	//rwset2 should not be valid - Version of key4 changed
   133  	rwsetBuilder2 := rwsetutil.NewRWSetBuilder()
   134  	rqi2 := &kvrwset.RangeQueryInfo{StartKey: "key2", EndKey: "key4", ItrExhausted: false}
   135  	rqi2.SetRawReads([]*kvrwset.KVRead{
   136  		rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)),
   137  		rwsetutil.NewKVRead("key3", version.NewHeight(1, 2)),
   138  		rwsetutil.NewKVRead("key4", version.NewHeight(1, 2))})
   139  	rwsetBuilder2.AddToRangeQuerySet("ns1", rqi2)
   140  	checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder2.GetTxReadWriteSet()}, nil, []int{0})
   141  
   142  	//rwset3 should not be valid - simulate key3 got committed to db
   143  	rwsetBuilder3 := rwsetutil.NewRWSetBuilder()
   144  	rqi3 := &kvrwset.RangeQueryInfo{StartKey: "key2", EndKey: "key4", ItrExhausted: false}
   145  	rqi3.SetRawReads([]*kvrwset.KVRead{
   146  		rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)),
   147  		rwsetutil.NewKVRead("key4", version.NewHeight(1, 3))})
   148  	rwsetBuilder3.AddToRangeQuerySet("ns1", rqi3)
   149  	checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder3.GetTxReadWriteSet()}, nil, []int{0})
   150  
   151  	// //Remove a key in rwset4 and rwset5 should become invalid
   152  	rwsetBuilder4 := rwsetutil.NewRWSetBuilder()
   153  	rwsetBuilder4.AddToWriteSet("ns1", "key3", nil)
   154  	rwsetBuilder5 := rwsetutil.NewRWSetBuilder()
   155  	rqi5 := &kvrwset.RangeQueryInfo{StartKey: "key2", EndKey: "key4", ItrExhausted: false}
   156  	rqi5.SetRawReads([]*kvrwset.KVRead{
   157  		rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)),
   158  		rwsetutil.NewKVRead("key3", version.NewHeight(1, 2)),
   159  		rwsetutil.NewKVRead("key4", version.NewHeight(1, 3))})
   160  	rwsetBuilder5.AddToRangeQuerySet("ns1", rqi5)
   161  	checkValidation(t, validator, []*rwsetutil.TxRwSet{
   162  		rwsetBuilder4.GetTxReadWriteSet(), rwsetBuilder5.GetTxReadWriteSet()}, nil, []int{1})
   163  
   164  	//Add a key in rwset6 and rwset7 should become invalid
   165  	rwsetBuilder6 := rwsetutil.NewRWSetBuilder()
   166  	rwsetBuilder6.AddToWriteSet("ns1", "key2_1", []byte("value2_1"))
   167  
   168  	rwsetBuilder7 := rwsetutil.NewRWSetBuilder()
   169  	rqi7 := &kvrwset.RangeQueryInfo{StartKey: "key2", EndKey: "key4", ItrExhausted: false}
   170  	rqi7.SetRawReads([]*kvrwset.KVRead{
   171  		rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)),
   172  		rwsetutil.NewKVRead("key3", version.NewHeight(1, 2)),
   173  		rwsetutil.NewKVRead("key4", version.NewHeight(1, 3))})
   174  	rwsetBuilder7.AddToRangeQuerySet("ns1", rqi7)
   175  	checkValidation(t, validator, []*rwsetutil.TxRwSet{
   176  		rwsetBuilder6.GetTxReadWriteSet(), rwsetBuilder7.GetTxReadWriteSet()}, nil, []int{1})
   177  }
   178  
   179  func TestPhantomHashBasedValidation(t *testing.T) {
   180  	testDBEnv := stateleveldb.NewTestVDBEnv(t)
   181  	defer testDBEnv.Cleanup()
   182  
   183  	db, err := testDBEnv.DBProvider.GetDBHandle("TestDB")
   184  	testutil.AssertNoError(t, err, "")
   185  
   186  	//populate db with initial data
   187  	batch := statedb.NewUpdateBatch()
   188  	batch.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 0))
   189  	batch.Put("ns1", "key2", []byte("value2"), version.NewHeight(1, 1))
   190  	batch.Put("ns1", "key3", []byte("value3"), version.NewHeight(1, 2))
   191  	batch.Put("ns1", "key4", []byte("value4"), version.NewHeight(1, 3))
   192  	batch.Put("ns1", "key5", []byte("value5"), version.NewHeight(1, 4))
   193  	batch.Put("ns1", "key6", []byte("value6"), version.NewHeight(1, 5))
   194  	batch.Put("ns1", "key7", []byte("value7"), version.NewHeight(1, 6))
   195  	batch.Put("ns1", "key8", []byte("value8"), version.NewHeight(1, 7))
   196  	batch.Put("ns1", "key9", []byte("value9"), version.NewHeight(1, 8))
   197  	db.ApplyUpdates(batch, version.NewHeight(1, 8))
   198  
   199  	validator := NewValidator(db)
   200  
   201  	rwsetBuilder1 := rwsetutil.NewRWSetBuilder()
   202  	rqi1 := &kvrwset.RangeQueryInfo{StartKey: "key2", EndKey: "key9", ItrExhausted: true}
   203  	kvReadsDuringSimulation1 := []*kvrwset.KVRead{
   204  		rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)),
   205  		rwsetutil.NewKVRead("key3", version.NewHeight(1, 2)),
   206  		rwsetutil.NewKVRead("key4", version.NewHeight(1, 3)),
   207  		rwsetutil.NewKVRead("key5", version.NewHeight(1, 4)),
   208  		rwsetutil.NewKVRead("key6", version.NewHeight(1, 5)),
   209  		rwsetutil.NewKVRead("key7", version.NewHeight(1, 6)),
   210  		rwsetutil.NewKVRead("key8", version.NewHeight(1, 7)),
   211  	}
   212  	rqi1.SetMerkelSummary(buildTestHashResults(t, 2, kvReadsDuringSimulation1))
   213  	rwsetBuilder1.AddToRangeQuerySet("ns1", rqi1)
   214  	checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder1.GetTxReadWriteSet()}, nil, []int{})
   215  
   216  	rwsetBuilder2 := rwsetutil.NewRWSetBuilder()
   217  	rqi2 := &kvrwset.RangeQueryInfo{StartKey: "key1", EndKey: "key9", ItrExhausted: false}
   218  	kvReadsDuringSimulation2 := []*kvrwset.KVRead{
   219  		rwsetutil.NewKVRead("key1", version.NewHeight(1, 0)),
   220  		rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)),
   221  		rwsetutil.NewKVRead("key3", version.NewHeight(1, 1)),
   222  		rwsetutil.NewKVRead("key4", version.NewHeight(1, 3)),
   223  		rwsetutil.NewKVRead("key5", version.NewHeight(1, 4)),
   224  		rwsetutil.NewKVRead("key6", version.NewHeight(1, 5)),
   225  		rwsetutil.NewKVRead("key7", version.NewHeight(1, 6)),
   226  		rwsetutil.NewKVRead("key8", version.NewHeight(1, 7)),
   227  		rwsetutil.NewKVRead("key9", version.NewHeight(1, 8)),
   228  	}
   229  	rqi2.SetMerkelSummary(buildTestHashResults(t, 2, kvReadsDuringSimulation2))
   230  	rwsetBuilder2.AddToRangeQuerySet("ns1", rqi2)
   231  	checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder2.GetTxReadWriteSet()}, nil, []int{0})
   232  }
   233  
   234  func checkValidation(t *testing.T, validator *Validator, rwsets []*rwsetutil.TxRwSet,
   235  	alreadyMarkedFlags util.TxValidationFlags, expectedInvalidTxIndexes []int) {
   236  	simulationResults := [][]byte{}
   237  	for _, txRWS := range rwsets {
   238  		sr, err := txRWS.ToProtoBytes()
   239  		testutil.AssertNoError(t, err, "")
   240  		simulationResults = append(simulationResults, sr)
   241  	}
   242  	block := testutil.ConstructBlock(t, 1, []byte("dummyPreviousHash"), simulationResults, false)
   243  	block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = alreadyMarkedFlags
   244  	_, err := validator.ValidateAndPrepareBatch(block, true)
   245  	txsFltr := util.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
   246  	invalidTxs := make([]int, 0)
   247  	for i := 0; i < len(block.Data.Data); i++ {
   248  		if txsFltr.IsInvalid(i) {
   249  			invalidTxs = append(invalidTxs, i)
   250  		}
   251  	}
   252  	testutil.AssertNoError(t, err, "")
   253  	testutil.AssertEquals(t, len(invalidTxs), len(expectedInvalidTxIndexes))
   254  	testutil.AssertContainsAll(t, invalidTxs, expectedInvalidTxIndexes)
   255  }
   256  
   257  func buildTestHashResults(t *testing.T, maxDegree int, kvReads []*kvrwset.KVRead) *kvrwset.QueryReadsMerkleSummary {
   258  	if len(kvReads) <= maxDegree {
   259  		t.Fatal("This method should be called with number of KVReads more than maxDegree; Else, hashing won't be performedrwset")
   260  	}
   261  	helper, _ := rwsetutil.NewRangeQueryResultsHelper(true, uint32(maxDegree))
   262  	for _, kvRead := range kvReads {
   263  		helper.AddResult(kvRead)
   264  	}
   265  	_, h, err := helper.Done()
   266  	testutil.AssertNoError(t, err, "")
   267  	testutil.AssertNotNil(t, h)
   268  	return h
   269  }