github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/ledger/kvledger/hashcheck_pvtdata_test.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package kvledger
     8  
     9  import (
    10  	"fmt"
    11  	"testing"
    12  
    13  	"github.com/golang/protobuf/proto"
    14  	"github.com/hechain20/hechain/common/ledger/testutil"
    15  	"github.com/hechain20/hechain/core/ledger"
    16  	"github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/rwsetutil"
    17  	"github.com/hyperledger/fabric-protos-go/ledger/rwset"
    18  	"github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset"
    19  	"github.com/hyperledger/fabric-protos-go/peer"
    20  	"github.com/stretchr/testify/require"
    21  )
    22  
    23  func TestConstructValidInvalidBlocksPvtData(t *testing.T) {
    24  	conf, cleanup := testConfig(t)
    25  	defer cleanup()
    26  
    27  	nsCollBtlConfs := []*nsCollBtlConfig{
    28  		{
    29  			namespace: "ns-1",
    30  			btlConfig: map[string]uint64{
    31  				"coll-1": 0,
    32  				"coll-2": 0,
    33  			},
    34  		},
    35  		{
    36  			namespace: "ns-2",
    37  			btlConfig: map[string]uint64{
    38  				"coll-2": 0,
    39  			},
    40  		},
    41  	}
    42  	provider := testutilNewProviderWithCollectionConfig(
    43  		t,
    44  		nsCollBtlConfs,
    45  		conf,
    46  	)
    47  	defer provider.Close()
    48  
    49  	blocksGenerator, gb := testutil.NewBlockGenerator(t, "testLedger", false)
    50  	lg, _ := provider.CreateFromGenesisBlock(gb)
    51  	kvledger := lg.(*kvLedger)
    52  	defer kvledger.Close()
    53  
    54  	// block-1
    55  	commitCollectionConfigsHistoryAndDummyBlock(t, provider, kvledger, nsCollBtlConfs, blocksGenerator)
    56  
    57  	pvtDataTx0, pubSimResTx0 := produceSamplePvtdata(t, 0,
    58  		[][4]string{
    59  			{"ns-1", "coll-1", "tx0-key-1", "tx0-val-1"},
    60  			{"ns-1", "coll-2", "tx0-key-2", "tx0-val-2"},
    61  		},
    62  	)
    63  
    64  	pvtDataTx1, pubSimResTx1 := produceSamplePvtdata(t, 1,
    65  		[][4]string{
    66  			{"ns-1", "coll-1", "tx1-key-1", "tx1-val-1"},
    67  			{"ns-2", "coll-2", "tx1-key-2", "tx1-val-2"},
    68  			{"ns-2", "coll-2", "tx1-key-3", "tx1-val-3"},
    69  			{"ns-2", "coll-2", "tx1-key-4", "tx1-val-4"},
    70  			{"ns-2", "coll-2", "tx1-key-5", "tx1-val-5"},
    71  		},
    72  	)
    73  
    74  	pvtData := map[uint64]*ledger.TxPvtData{
    75  		0: pvtDataTx0,
    76  		1: pvtDataTx1,
    77  	}
    78  	simulationResults := [][]byte{pubSimResTx0, pubSimResTx1}
    79  	missingData := make(ledger.TxMissingPvtData)
    80  	missingData.Add(0, "ns-1", "coll-1", true)
    81  	missingData.Add(0, "ns-1", "coll-2", true)
    82  	missingData.Add(1, "ns-1", "coll-1", true)
    83  	missingData.Add(1, "ns-2", "coll-2", true)
    84  
    85  	// commit block-2
    86  	blk2 := blocksGenerator.NextBlock([][]byte{pubSimResTx0, pubSimResTx1})
    87  	blockAndPvtData1 := &ledger.BlockAndPvtData{
    88  		Block:          blk2,
    89  		PvtData:        pvtData,
    90  		MissingPvtData: missingData,
    91  	}
    92  	require.NoError(t, kvledger.commit(blockAndPvtData1, &ledger.CommitOptions{}))
    93  
    94  	// generate snapshot at block-2
    95  	require.NoError(t, kvledger.generateSnapshot())
    96  	freshConf, cleanup := testConfig(t)
    97  	defer cleanup()
    98  
    99  	freshProvider := testutilNewProviderWithCollectionConfig(
   100  		t,
   101  		nsCollBtlConfs,
   102  		freshConf,
   103  	)
   104  	defer freshProvider.Close()
   105  
   106  	lgr, _, err := freshProvider.CreateFromSnapshot(SnapshotDirForLedgerBlockNum(conf.SnapshotsConfig.RootDir, "testLedger", 2))
   107  	fmt.Printf("%+v", err)
   108  	require.NoError(t, err)
   109  	bootstrappedLedger := lgr.(*kvLedger)
   110  	defer bootstrappedLedger.Close()
   111  
   112  	// commit block-3
   113  	blk3 := blocksGenerator.NextBlock(simulationResults)
   114  	require.NoError(t, bootstrappedLedger.commit(
   115  		&ledger.BlockAndPvtData{
   116  			Block:   blk3,
   117  			PvtData: pvtData,
   118  		},
   119  		&ledger.CommitOptions{},
   120  	))
   121  
   122  	pvtdataCopy := func() map[uint64]*ledger.TxPvtData {
   123  		m := make(map[uint64]*ledger.TxPvtData, len(pvtData))
   124  		for k, v := range pvtData {
   125  			wsCopy := (proto.Clone(v.WriteSet)).(*rwset.TxPvtReadWriteSet)
   126  			m[k] = &ledger.TxPvtData{
   127  				SeqInBlock: v.SeqInBlock,
   128  				WriteSet:   wsCopy,
   129  			}
   130  		}
   131  		return m
   132  	}
   133  
   134  	t.Run("for-data-after-snapshot:extra-collection-is-ignored", func(t *testing.T) {
   135  		lgr := bootstrappedLedger
   136  		pvtdata := pvtdataCopy()
   137  		pvtdata[1], _ = produceSamplePvtdata(t, 1,
   138  			[][4]string{
   139  				{"ns-1", "non-existing-collection", "randomValue", "randomValue"},
   140  			},
   141  		)
   142  
   143  		blocksValidPvtData, hashMismatched, err := constructValidAndInvalidPvtData(
   144  			[]*ledger.ReconciledPvtdata{
   145  				{
   146  					BlockNum:  3,
   147  					WriteSets: pvtdata,
   148  				},
   149  			},
   150  			lgr.blockStore,
   151  			lgr.pvtdataStore,
   152  			2,
   153  		)
   154  		require.NoError(t, err)
   155  		verifyBlocksPvtdata(t,
   156  			map[uint64][]*ledger.TxPvtData{
   157  				3: {
   158  					pvtdata[0],
   159  				},
   160  			},
   161  			blocksValidPvtData,
   162  		)
   163  		// should not include the pvtData passed for the tx1 even in hashmismatched as the collection does not exist in tx1
   164  		require.Len(t, hashMismatched, 0)
   165  	})
   166  
   167  	t.Run("for-data-after-snapshot:hash-mismatch-is-reported", func(t *testing.T) {
   168  		lgr := bootstrappedLedger
   169  		pvtdata := pvtdataCopy()
   170  
   171  		pvtdata[1], _ = produceSamplePvtdata(t, 1,
   172  			[][4]string{
   173  				{"ns-2", "coll-2", "key-2", "randomValue"},
   174  			},
   175  		)
   176  
   177  		blocksValidPvtData, hashMismatches, err := constructValidAndInvalidPvtData(
   178  			[]*ledger.ReconciledPvtdata{
   179  				{
   180  					BlockNum:  3,
   181  					WriteSets: pvtdata,
   182  				},
   183  			},
   184  			lgr.blockStore,
   185  			lgr.pvtdataStore,
   186  			2,
   187  		)
   188  		require.NoError(t, err)
   189  		verifyBlocksPvtdata(t,
   190  			map[uint64][]*ledger.TxPvtData{
   191  				3: {
   192  					pvtdata[0],
   193  				},
   194  			},
   195  			blocksValidPvtData,
   196  		)
   197  		require.Equal(
   198  			t,
   199  			[]*ledger.PvtdataHashMismatch{
   200  				{
   201  					BlockNum:   3,
   202  					TxNum:      1,
   203  					Namespace:  "ns-2",
   204  					Collection: "coll-2",
   205  				},
   206  			},
   207  			hashMismatches,
   208  		)
   209  	})
   210  
   211  	t.Run("works-for-mixed-data-before-and-after-snapshot", func(t *testing.T) {
   212  		lgr := bootstrappedLedger
   213  		pvtdata := pvtdataCopy()
   214  
   215  		blocksValidPvtData, hashMismatches, err := constructValidAndInvalidPvtData(
   216  			[]*ledger.ReconciledPvtdata{
   217  				{
   218  					BlockNum:  2,
   219  					WriteSets: pvtdata,
   220  				},
   221  				{
   222  					BlockNum:  3,
   223  					WriteSets: pvtdata,
   224  				},
   225  			},
   226  			lgr.blockStore,
   227  			lgr.pvtdataStore,
   228  			2,
   229  		)
   230  		require.NoError(t, err)
   231  		verifyBlocksPvtdata(t,
   232  			map[uint64][]*ledger.TxPvtData{
   233  				2: {
   234  					pvtdata[0],
   235  					pvtdata[1],
   236  				},
   237  				3: {
   238  					pvtdata[0],
   239  					pvtdata[1],
   240  				},
   241  			},
   242  			blocksValidPvtData,
   243  		)
   244  		require.Len(t, hashMismatches, 0)
   245  	})
   246  
   247  	t.Run("for-data-before-snapshot:does-not-trim-the-extra-keys", func(t *testing.T) {
   248  		lgr := bootstrappedLedger
   249  		pvtdata := pvtdataCopy()
   250  		pvtdataWithExtraKey := pvtdataCopy()
   251  		pvtdataWithExtraKey[0], _ = produceSamplePvtdata(t, 0,
   252  			[][4]string{
   253  				{"ns-1", "coll-1", "tx0-key-1", "tx0-val-1"},
   254  				{"ns-1", "coll-2", "tx0-key-2", "tx0-val-2"},
   255  				{"ns-1", "coll-2", "extra-key", "extra-val"},
   256  			},
   257  		)
   258  		pvtdataWithExtraKey[2], _ = produceSamplePvtdata(t, 2,
   259  			[][4]string{
   260  				{"ns-1", "coll-1", "tx2-key-1", "tx2-val-1"},
   261  			},
   262  		)
   263  
   264  		blocksValidPvtData, hashMismatches, err := constructValidAndInvalidPvtData(
   265  			[]*ledger.ReconciledPvtdata{
   266  				{
   267  					BlockNum:  2,
   268  					WriteSets: pvtdataWithExtraKey,
   269  				},
   270  			},
   271  			lgr.blockStore,
   272  			lgr.pvtdataStore,
   273  			2,
   274  		)
   275  		require.NoError(t, err)
   276  
   277  		verifyBlocksPvtdata(t,
   278  			map[uint64][]*ledger.TxPvtData{
   279  				2: {
   280  					pvtdataWithExtraKey[0],
   281  					pvtdata[1],
   282  				},
   283  			},
   284  			blocksValidPvtData,
   285  		)
   286  		require.Len(t, hashMismatches, 0)
   287  	})
   288  
   289  	t.Run("for-data-before-snapshot:reports-hash-mismatch-and-partial-data-supplied", func(t *testing.T) {
   290  		lgr := bootstrappedLedger
   291  		temptered := pvtdataCopy()
   292  		temptered[0], _ = produceSamplePvtdata(t, 0,
   293  			[][4]string{
   294  				{"ns-1", "coll-1", "tx0-key-1", "tx0-val-1-tempered"},
   295  			},
   296  		)
   297  		temptered[1], _ = produceSamplePvtdata(t, 1,
   298  			[][4]string{
   299  				{"ns-2", "coll-2", "tx1-key-2", "tx1-val-2-tempered"},
   300  				{"ns-2", "coll-2", "tx1-key-3", "tx1-val-3-tempered"},
   301  			},
   302  		)
   303  
   304  		blocksValidPvtData, hashMismatches, err := constructValidAndInvalidPvtData(
   305  			[]*ledger.ReconciledPvtdata{
   306  				{
   307  					BlockNum:  2,
   308  					WriteSets: temptered,
   309  				},
   310  			},
   311  			lgr.blockStore,
   312  			lgr.pvtdataStore,
   313  			2,
   314  		)
   315  		require.NoError(t, err)
   316  		require.Len(t, blocksValidPvtData, 0)
   317  		require.ElementsMatch(t,
   318  			[]*ledger.PvtdataHashMismatch{
   319  				{
   320  					BlockNum:   2,
   321  					TxNum:      0,
   322  					Namespace:  "ns-1",
   323  					Collection: "coll-1",
   324  				},
   325  				{
   326  					BlockNum:   2,
   327  					TxNum:      1,
   328  					Namespace:  "ns-2",
   329  					Collection: "coll-2",
   330  				},
   331  			},
   332  			hashMismatches,
   333  		)
   334  	})
   335  
   336  	t.Run("for-data-before-snapshot:reports-repeated-key", func(t *testing.T) {
   337  		lgr := bootstrappedLedger
   338  		pvtdata := pvtdataCopy()
   339  		repeatedKeyInTx0Ns1Coll1 := pvtdataCopy()
   340  		repeatedKeyWS := &kvrwset.KVRWSet{
   341  			Writes: []*kvrwset.KVWrite{
   342  				{
   343  					Key:   "tx0-key-1",
   344  					Value: []byte("tx0-val-1"),
   345  				},
   346  				{
   347  					Key:   "tx0-key-1",
   348  					Value: []byte("tx0-val-1-tempered"),
   349  				},
   350  			},
   351  		}
   352  
   353  		repeatedKeyWSBytes, err := proto.Marshal(repeatedKeyWS)
   354  		require.NoError(t, err)
   355  		repeatedKeyInTx0Ns1Coll1[0].WriteSet.NsPvtRwset[0].CollectionPvtRwset[0].Rwset = repeatedKeyWSBytes
   356  
   357  		expectedPartOfTx0, _ := produceSamplePvtdata(t, 0,
   358  			[][4]string{
   359  				{"ns-1", "coll-2", "tx0-key-2", "tx0-val-2"},
   360  			},
   361  		)
   362  
   363  		blocksValidPvtData, hashMismatches, err := constructValidAndInvalidPvtData(
   364  			[]*ledger.ReconciledPvtdata{
   365  				{
   366  					BlockNum:  2,
   367  					WriteSets: repeatedKeyInTx0Ns1Coll1,
   368  				},
   369  			},
   370  			lgr.blockStore,
   371  			lgr.pvtdataStore,
   372  			2,
   373  		)
   374  		require.NoError(t, err)
   375  
   376  		verifyBlocksPvtdata(t,
   377  			map[uint64][]*ledger.TxPvtData{
   378  				2: {
   379  					expectedPartOfTx0,
   380  					pvtdata[1],
   381  				},
   382  			},
   383  			blocksValidPvtData,
   384  		)
   385  
   386  		require.ElementsMatch(t,
   387  			[]*ledger.PvtdataHashMismatch{
   388  				{
   389  					BlockNum:   2,
   390  					TxNum:      0,
   391  					Namespace:  "ns-1",
   392  					Collection: "coll-1",
   393  				},
   394  			},
   395  			hashMismatches,
   396  		)
   397  	})
   398  
   399  	t.Run("for-data-before-snapshot:ignores-bad-data-corrupted-writeset", func(t *testing.T) {
   400  		lgr := bootstrappedLedger
   401  		pvtdata := pvtdataCopy()
   402  		pvtdataWithBadData := pvtdataCopy()
   403  		pvtdataWithBadData[0].WriteSet.NsPvtRwset[0].CollectionPvtRwset[0].Rwset = []byte("bad-data")
   404  
   405  		blocksValidPvtData, hashMismatches, err := constructValidAndInvalidPvtData(
   406  			[]*ledger.ReconciledPvtdata{
   407  				{
   408  					BlockNum:  2,
   409  					WriteSets: pvtdataWithBadData,
   410  				},
   411  			},
   412  			lgr.blockStore,
   413  			lgr.pvtdataStore,
   414  			2,
   415  		)
   416  		require.NoError(t, err)
   417  
   418  		verifyBlocksPvtdata(t,
   419  			map[uint64][]*ledger.TxPvtData{
   420  				2: {
   421  					pvtdata[1],
   422  				},
   423  			},
   424  			blocksValidPvtData,
   425  		)
   426  		require.Len(t, hashMismatches, 0)
   427  	})
   428  
   429  	t.Run("for-data-before-snapshot:ignores-bad-data-empty-collections", func(t *testing.T) {
   430  		lgr := bootstrappedLedger
   431  		pvtdata := pvtdataCopy()
   432  		pvtdataWithEmptyCollections := pvtdataCopy()
   433  		pvtdataWithEmptyCollections[0].WriteSet.NsPvtRwset[0].CollectionPvtRwset[0].Rwset = nil
   434  
   435  		expectedValidDataForTx0, _ := produceSamplePvtdata(t, 0,
   436  			[][4]string{
   437  				{"ns-1", "coll-2", "tx0-key-2", "tx0-val-2"},
   438  			},
   439  		)
   440  
   441  		blocksValidPvtData, hashMismatches, err := constructValidAndInvalidPvtData(
   442  			[]*ledger.ReconciledPvtdata{
   443  				{
   444  					BlockNum:  2,
   445  					WriteSets: pvtdataWithEmptyCollections,
   446  				},
   447  			},
   448  			lgr.blockStore,
   449  			lgr.pvtdataStore,
   450  			2,
   451  		)
   452  		require.NoError(t, err)
   453  
   454  		verifyBlocksPvtdata(t,
   455  			map[uint64][]*ledger.TxPvtData{
   456  				2: {
   457  					expectedValidDataForTx0,
   458  					pvtdata[1],
   459  				},
   460  			},
   461  			blocksValidPvtData,
   462  		)
   463  		require.Len(t, hashMismatches, 0)
   464  	})
   465  }
   466  
   467  func verifyBlocksPvtdata(t *testing.T, expected, actual map[uint64][]*ledger.TxPvtData) {
   468  	require.Len(t, actual, len(expected))
   469  	for blkNum, expectedTx := range expected {
   470  		actualTx := actual[blkNum]
   471  		require.Len(t, actualTx, len(expectedTx))
   472  		m := map[uint64]*rwset.TxPvtReadWriteSet{}
   473  		for _, a := range actualTx {
   474  			m[a.SeqInBlock] = a.WriteSet
   475  		}
   476  
   477  		for _, e := range expectedTx {
   478  			require.NotNil(t, m[e.SeqInBlock])
   479  			require.Equal(t, e.WriteSet, m[e.SeqInBlock])
   480  		}
   481  	}
   482  }
   483  
   484  func produceSamplePvtdata(t *testing.T, txNum uint64, data [][4]string) (*ledger.TxPvtData, []byte) {
   485  	builder := rwsetutil.NewRWSetBuilder()
   486  	for _, d := range data {
   487  		builder.AddToPvtAndHashedWriteSet(d[0], d[1], d[2], []byte(d[3]))
   488  	}
   489  	simRes, err := builder.GetTxSimulationResults()
   490  	require.NoError(t, err)
   491  	pubSimulationResultsBytes, err := proto.Marshal(simRes.PubSimulationResults)
   492  	require.NoError(t, err)
   493  	return &ledger.TxPvtData{SeqInBlock: txNum, WriteSet: simRes.PvtSimulationResults}, pubSimulationResultsBytes
   494  }
   495  
   496  func commitCollectionConfigsHistoryAndDummyBlock(t *testing.T, provider *Provider, kvledger *kvLedger,
   497  	nsCollBtlConfs []*nsCollBtlConfig, blocksGenerator *testutil.BlockGenerator,
   498  ) {
   499  	blockAndPvtdata := prepareNextBlockForTest(t, kvledger, blocksGenerator, "SimulateForBlk1",
   500  		map[string]string{
   501  			"dummyKeyForCollectionConfig": "dummyValForCollectionConfig",
   502  		},
   503  		nil,
   504  	)
   505  	require.NoError(t, kvledger.commit(blockAndPvtdata, &ledger.CommitOptions{}))
   506  
   507  	for _, nsBTLConf := range nsCollBtlConfs {
   508  		namespace := nsBTLConf.namespace
   509  		collConfig := []*peer.StaticCollectionConfig{}
   510  		for coll, btl := range nsBTLConf.btlConfig {
   511  			collConfig = append(collConfig,
   512  				&peer.StaticCollectionConfig{
   513  					Name:        coll,
   514  					BlockToLive: btl,
   515  				},
   516  			)
   517  		}
   518  		addDummyEntryInCollectionConfigHistory(
   519  			t,
   520  			provider,
   521  			kvledger.ledgerID,
   522  			namespace,
   523  			blockAndPvtdata.Block.Header.Number,
   524  			collConfig,
   525  		)
   526  	}
   527  }
   528  
   529  func TestRemoveCollFromTxPvtReadWriteSet(t *testing.T) {
   530  	txpvtrwset := testutilConstructSampleTxPvtRwset(
   531  		[]*testNsColls{
   532  			{ns: "ns-1", colls: []string{"coll-1", "coll-2"}},
   533  			{ns: "ns-2", colls: []string{"coll-3", "coll-4"}},
   534  		},
   535  	)
   536  
   537  	removeCollFromTxPvtReadWriteSet(txpvtrwset, "ns-1", "coll-1")
   538  	require.Equal(
   539  		t,
   540  		testutilConstructSampleTxPvtRwset(
   541  			[]*testNsColls{
   542  				{ns: "ns-1", colls: []string{"coll-2"}},
   543  				{ns: "ns-2", colls: []string{"coll-3", "coll-4"}},
   544  			},
   545  		),
   546  		txpvtrwset,
   547  	)
   548  
   549  	removeCollFromTxPvtReadWriteSet(txpvtrwset, "ns-1", "coll-2")
   550  	require.Equal(
   551  		t,
   552  		testutilConstructSampleTxPvtRwset(
   553  			[]*testNsColls{
   554  				{ns: "ns-2", colls: []string{"coll-3", "coll-4"}},
   555  			},
   556  		),
   557  		txpvtrwset,
   558  	)
   559  }
   560  
   561  func testutilConstructSampleTxPvtRwset(nsCollsList []*testNsColls) *rwset.TxPvtReadWriteSet {
   562  	txPvtRwset := &rwset.TxPvtReadWriteSet{}
   563  	for _, nsColls := range nsCollsList {
   564  		ns := nsColls.ns
   565  		nsdata := &rwset.NsPvtReadWriteSet{
   566  			Namespace:          ns,
   567  			CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{},
   568  		}
   569  		txPvtRwset.NsPvtRwset = append(txPvtRwset.NsPvtRwset, nsdata)
   570  		for _, coll := range nsColls.colls {
   571  			nsdata.CollectionPvtRwset = append(nsdata.CollectionPvtRwset,
   572  				&rwset.CollectionPvtReadWriteSet{
   573  					CollectionName: coll,
   574  					Rwset:          []byte(fmt.Sprintf("pvtrwset-for-%s-%s", ns, coll)),
   575  				},
   576  			)
   577  		}
   578  	}
   579  	return txPvtRwset
   580  }
   581  
   582  type testNsColls struct {
   583  	ns    string
   584  	colls []string
   585  }