github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/core/ledger/kvledger/hashcheck_pvtdata_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package kvledger
     8  
     9  import (
    10  	"fmt"
    11  	"strings"
    12  	"testing"
    13  
    14  	"github.com/golang/protobuf/proto"
    15  	"github.com/hyperledger/fabric-protos-go/ledger/rwset"
    16  	"github.com/osdi23p228/fabric/common/ledger/testutil"
    17  	"github.com/osdi23p228/fabric/core/ledger"
    18  	"github.com/osdi23p228/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
    19  	"github.com/osdi23p228/fabric/protoutil"
    20  	"github.com/stretchr/testify/require"
    21  )
    22  
    23  func TestConstructValidInvalidBlocksPvtData(t *testing.T) {
    24  	conf, cleanup := testConfig(t)
    25  	defer cleanup()
    26  	nsCollBtlConfs := []*nsCollBtlConfig{
    27  		{
    28  			namespace: "ns-1",
    29  			btlConfig: map[string]uint64{
    30  				"coll-1": 0,
    31  				"coll-2": 0,
    32  			},
    33  		},
    34  		{
    35  			namespace: "ns-2",
    36  			btlConfig: map[string]uint64{
    37  				"coll-2": 0,
    38  			},
    39  		},
    40  		{
    41  			namespace: "ns-4",
    42  			btlConfig: map[string]uint64{
    43  				"coll-2": 0,
    44  			},
    45  		},
    46  		{
    47  			namespace: "ns-6",
    48  			btlConfig: map[string]uint64{
    49  				"coll-2": 0,
    50  			},
    51  		},
    52  	}
    53  	provider := testutilNewProviderWithCollectionConfig(
    54  		t,
    55  		nsCollBtlConfs,
    56  		conf,
    57  	)
    58  	defer provider.Close()
    59  
    60  	_, gb := testutil.NewBlockGenerator(t, "testLedger", false)
    61  	gbHash := protoutil.BlockHeaderHash(gb.Header)
    62  	lg, _ := provider.Create(gb)
    63  	defer lg.Close()
    64  
    65  	// construct pvtData and pubRwSet (i.e., hashed rw set)
    66  	v0 := []byte{0}
    67  	pvtDataBlk1Tx0, pubSimResBytesBlk1Tx0 := produceSamplePvtdata(t, 0, []string{"ns-1:coll-1", "ns-1:coll-2"}, [][]byte{v0, v0})
    68  	v1 := []byte{1}
    69  	pvtDataBlk1Tx1, pubSimResBytesBlk1Tx1 := produceSamplePvtdata(t, 1, []string{"ns-1:coll-1", "ns-1:coll-2"}, [][]byte{v1, v1})
    70  	v2 := []byte{2}
    71  	pvtDataBlk1Tx2, pubSimResBytesBlk1Tx2 := produceSamplePvtdata(t, 2, []string{"ns-1:coll-1", "ns-2:coll-2"}, [][]byte{v2, v2})
    72  	v3 := []byte{3}
    73  	pvtDataBlk1Tx3, pubSimResBytesBlk1Tx3 := produceSamplePvtdata(t, 3, []string{"ns-1:coll-1", "ns-1:coll-2"}, [][]byte{v3, v3})
    74  	v4 := []byte{4}
    75  	pvtDataBlk1Tx4, pubSimResBytesBlk1Tx4 := produceSamplePvtdata(t, 4, []string{"ns-1:coll-1", "ns-4:coll-2"}, [][]byte{v4, v4})
    76  	v5 := []byte{5}
    77  	pvtDataBlk1Tx5, pubSimResBytesBlk1Tx5 := produceSamplePvtdata(t, 5, []string{"ns-1:coll-1", "ns-1:coll-2"}, [][]byte{v5, v5})
    78  	v6 := []byte{6}
    79  	pvtDataBlk1Tx6, pubSimResBytesBlk1Tx6 := produceSamplePvtdata(t, 6, []string{"ns-6:coll-2"}, [][]byte{v6})
    80  	v7 := []byte{7}
    81  	_, pubSimResBytesBlk1Tx7 := produceSamplePvtdata(t, 7, []string{"ns-1:coll-2"}, [][]byte{v7})
    82  	wrongPvtDataBlk1Tx7, _ := produceSamplePvtdata(t, 7, []string{"ns-6:coll-2"}, [][]byte{v6})
    83  
    84  	pubSimulationResults := &rwset.TxReadWriteSet{}
    85  	err := proto.Unmarshal(pubSimResBytesBlk1Tx7, pubSimulationResults)
    86  	require.NoError(t, err)
    87  	tx7PvtdataHash := pubSimulationResults.NsRwset[0].CollectionHashedRwset[0].PvtRwsetHash
    88  
    89  	// construct block1
    90  	simulationResultsBlk1 := [][]byte{pubSimResBytesBlk1Tx0, pubSimResBytesBlk1Tx1, pubSimResBytesBlk1Tx2,
    91  		pubSimResBytesBlk1Tx3, pubSimResBytesBlk1Tx4, pubSimResBytesBlk1Tx5,
    92  		pubSimResBytesBlk1Tx6, pubSimResBytesBlk1Tx7}
    93  	blk1 := testutil.ConstructBlock(t, 1, gbHash, simulationResultsBlk1, false)
    94  
    95  	// construct a pvtData list for block1
    96  	pvtDataBlk1 := map[uint64]*ledger.TxPvtData{
    97  		0: pvtDataBlk1Tx0,
    98  		1: pvtDataBlk1Tx1,
    99  		2: pvtDataBlk1Tx2,
   100  		4: pvtDataBlk1Tx4,
   101  		5: pvtDataBlk1Tx5,
   102  	}
   103  
   104  	// construct a missingData list for block1
   105  	missingData := make(ledger.TxMissingPvtDataMap)
   106  	missingData.Add(3, "ns-1", "coll-1", true)
   107  	missingData.Add(3, "ns-1", "coll-2", true)
   108  	missingData.Add(6, "ns-6", "coll-2", true)
   109  	missingData.Add(7, "ns-1", "coll-2", true)
   110  
   111  	// commit block1
   112  	blockAndPvtData1 := &ledger.BlockAndPvtData{
   113  		Block:          blk1,
   114  		PvtData:        pvtDataBlk1,
   115  		MissingPvtData: missingData}
   116  	require.NoError(t, lg.(*kvLedger).commitToPvtAndBlockStore(blockAndPvtData1))
   117  
   118  	// construct pvtData from missing data in tx3, tx6, and tx7
   119  	pvtdata := []*ledger.ReconciledPvtdata{
   120  		{
   121  			BlockNum: 1,
   122  			WriteSets: map[uint64]*ledger.TxPvtData{
   123  				3: pvtDataBlk1Tx3,
   124  				6: pvtDataBlk1Tx6,
   125  				7: wrongPvtDataBlk1Tx7,
   126  				// ns-6:coll-2 does not present in tx7
   127  			},
   128  		},
   129  	}
   130  
   131  	expectedValidBlocksPvtData := map[uint64][]*ledger.TxPvtData{
   132  		1: {
   133  			pvtDataBlk1Tx3,
   134  			pvtDataBlk1Tx6,
   135  		},
   136  	}
   137  
   138  	blocksValidPvtData, hashMismatched, err := constructValidAndInvalidPvtData(pvtdata, lg.(*kvLedger).blockStore)
   139  	require.NoError(t, err)
   140  	require.Equal(t, len(expectedValidBlocksPvtData), len(blocksValidPvtData))
   141  	require.ElementsMatch(t, expectedValidBlocksPvtData[1], blocksValidPvtData[1])
   142  	// should not include the pvtData passed for the tx7 even in hashmismatched as ns-6:coll-2 does not exist in tx7
   143  	require.Len(t, hashMismatched, 0)
   144  
   145  	// construct pvtData from missing data in tx7 with wrong pvtData
   146  	wrongPvtDataBlk1Tx7, _ = produceSamplePvtdata(t, 7, []string{"ns-1:coll-2"}, [][]byte{v6})
   147  	pvtdata = []*ledger.ReconciledPvtdata{
   148  		{
   149  			BlockNum: 1,
   150  			WriteSets: map[uint64]*ledger.TxPvtData{
   151  				7: wrongPvtDataBlk1Tx7,
   152  				// ns-1:coll-1 exists in tx7 but the passed pvtData is incorrect
   153  			},
   154  		},
   155  	}
   156  
   157  	expectedHashMismatches := []*ledger.PvtdataHashMismatch{
   158  		{
   159  			BlockNum:     1,
   160  			TxNum:        7,
   161  			Namespace:    "ns-1",
   162  			Collection:   "coll-2",
   163  			ExpectedHash: tx7PvtdataHash,
   164  		},
   165  	}
   166  
   167  	blocksValidPvtData, hashMismatches, err := constructValidAndInvalidPvtData(pvtdata, lg.(*kvLedger).blockStore)
   168  	require.NoError(t, err)
   169  	require.Len(t, blocksValidPvtData, 0)
   170  
   171  	require.ElementsMatch(t, expectedHashMismatches, hashMismatches)
   172  }
   173  
   174  func produceSamplePvtdata(t *testing.T, txNum uint64, nsColls []string, values [][]byte) (*ledger.TxPvtData, []byte) {
   175  	builder := rwsetutil.NewRWSetBuilder()
   176  	for index, nsColl := range nsColls {
   177  		nsCollSplit := strings.Split(nsColl, ":")
   178  		ns := nsCollSplit[0]
   179  		coll := nsCollSplit[1]
   180  		key := fmt.Sprintf("key-%s-%s", ns, coll)
   181  		value := values[index]
   182  		builder.AddToPvtAndHashedWriteSet(ns, coll, key, value)
   183  	}
   184  	simRes, err := builder.GetTxSimulationResults()
   185  	require.NoError(t, err)
   186  	pubSimulationResultsBytes, err := proto.Marshal(simRes.PubSimulationResults)
   187  	require.NoError(t, err)
   188  	return &ledger.TxPvtData{SeqInBlock: txNum, WriteSet: simRes.PvtSimulationResults}, pubSimulationResultsBytes
   189  }
   190  
   191  func TestRemoveCollFromTxPvtReadWriteSet(t *testing.T) {
   192  	txpvtrwset := testutilConstructSampleTxPvtRwset(
   193  		[]*testNsColls{
   194  			{ns: "ns-1", colls: []string{"coll-1", "coll-2"}},
   195  			{ns: "ns-2", colls: []string{"coll-3", "coll-4"}},
   196  		},
   197  	)
   198  
   199  	removeCollFromTxPvtReadWriteSet(txpvtrwset, "ns-1", "coll-1")
   200  	require.Equal(
   201  		t,
   202  		testutilConstructSampleTxPvtRwset(
   203  			[]*testNsColls{
   204  				{ns: "ns-1", colls: []string{"coll-2"}},
   205  				{ns: "ns-2", colls: []string{"coll-3", "coll-4"}},
   206  			},
   207  		),
   208  		txpvtrwset,
   209  	)
   210  
   211  	removeCollFromTxPvtReadWriteSet(txpvtrwset, "ns-1", "coll-2")
   212  	require.Equal(
   213  		t,
   214  		testutilConstructSampleTxPvtRwset(
   215  			[]*testNsColls{
   216  				{ns: "ns-2", colls: []string{"coll-3", "coll-4"}},
   217  			},
   218  		),
   219  		txpvtrwset,
   220  	)
   221  }
   222  
   223  func testutilConstructSampleTxPvtRwset(nsCollsList []*testNsColls) *rwset.TxPvtReadWriteSet {
   224  	txPvtRwset := &rwset.TxPvtReadWriteSet{}
   225  	for _, nsColls := range nsCollsList {
   226  		ns := nsColls.ns
   227  		nsdata := &rwset.NsPvtReadWriteSet{
   228  			Namespace:          ns,
   229  			CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{},
   230  		}
   231  		txPvtRwset.NsPvtRwset = append(txPvtRwset.NsPvtRwset, nsdata)
   232  		for _, coll := range nsColls.colls {
   233  			nsdata.CollectionPvtRwset = append(nsdata.CollectionPvtRwset,
   234  				&rwset.CollectionPvtReadWriteSet{
   235  					CollectionName: coll,
   236  					Rwset:          []byte(fmt.Sprintf("pvtrwset-for-%s-%s", ns, coll)),
   237  				},
   238  			)
   239  		}
   240  	}
   241  	return txPvtRwset
   242  }
   243  
   244  type testNsColls struct {
   245  	ns    string
   246  	colls []string
   247  }