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

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package tests
     8  
     9  import (
    10  	"testing"
    11  
    12  	"github.com/davecgh/go-spew/spew"
    13  	"github.com/golang/protobuf/proto"
    14  	"github.com/hyperledger/fabric-protos-go/common"
    15  	"github.com/hyperledger/fabric-protos-go/ledger/queryresult"
    16  	"github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset"
    17  	protopeer "github.com/hyperledger/fabric-protos-go/peer"
    18  	"github.com/osdi23p228/fabric/core/ledger"
    19  	"github.com/osdi23p228/fabric/internal/pkg/txflags"
    20  	"github.com/stretchr/testify/assert"
    21  )
    22  
    23  // verifier provides functions that help tests with less verbose code for querying the ledger
    24  // and verifying the actual results with the expected results
    25  // For the straight forward functions, tests can call them directly on the ledger
    26  type verifier struct {
    27  	lgr    ledger.PeerLedger
    28  	assert *assert.Assertions
    29  	t      *testing.T
    30  }
    31  
    32  func newVerifier(lgr ledger.PeerLedger, t *testing.T) *verifier {
    33  	return &verifier{lgr, assert.New(t), t}
    34  }
    35  
    36  func (v *verifier) verifyLedgerHeight(expectedHt uint64) {
    37  	info, err := v.lgr.GetBlockchainInfo()
    38  	v.assert.NoError(err)
    39  	v.assert.Equal(expectedHt, info.Height)
    40  }
    41  
    42  func (v *verifier) verifyPubState(ns, key string, expectedVal string) {
    43  	qe, err := v.lgr.NewQueryExecutor()
    44  	v.assert.NoError(err)
    45  	defer qe.Done()
    46  	committedVal, err := qe.GetState(ns, key)
    47  	v.assert.NoError(err)
    48  	v.t.Logf("val=%s", committedVal)
    49  	var expectedValBytes []byte
    50  	if expectedVal != "" {
    51  		expectedValBytes = []byte(expectedVal)
    52  	}
    53  	v.assert.Equal(expectedValBytes, committedVal)
    54  }
    55  
    56  func (v *verifier) verifyPvtdataHashState(ns, coll, key string, expectedValHash []byte) {
    57  	qe, err := v.lgr.NewQueryExecutor()
    58  	v.assert.NoError(err)
    59  	defer qe.Done()
    60  	committedValHash, err := qe.GetPrivateDataHash(ns, coll, key)
    61  	v.assert.NoError(err)
    62  	v.assert.Equal(expectedValHash, committedValHash)
    63  }
    64  
    65  func (v *verifier) verifyPvtState(ns, coll, key string, expectedVal string) {
    66  	qe, err := v.lgr.NewQueryExecutor()
    67  	v.assert.NoError(err)
    68  	defer qe.Done()
    69  	committedVal, err := qe.GetPrivateData(ns, coll, key)
    70  	v.assert.NoError(err)
    71  	v.t.Logf("val=%s", committedVal)
    72  	var expectedValBytes []byte
    73  	if expectedVal != "" {
    74  		expectedValBytes = []byte(expectedVal)
    75  	}
    76  	v.assert.Equal(expectedValBytes, committedVal)
    77  }
    78  
    79  func (v *verifier) verifyMostRecentCollectionConfigBelow(blockNum uint64, chaincodeName string, expectOut *expectedCollConfInfo) {
    80  	configHistory, err := v.lgr.GetConfigHistoryRetriever()
    81  	v.assert.NoError(err)
    82  	actualCollectionConfigInfo, err := configHistory.MostRecentCollectionConfigBelow(blockNum, chaincodeName)
    83  	v.assert.NoError(err)
    84  	if expectOut == nil {
    85  		v.assert.Nil(actualCollectionConfigInfo)
    86  		return
    87  	}
    88  	v.t.Logf("Retrieved CollectionConfigInfo=%s", spew.Sdump(actualCollectionConfigInfo))
    89  	actualCommittingBlockNum := actualCollectionConfigInfo.CommittingBlockNum
    90  	actualCollConf := convertFromCollConfigProto(actualCollectionConfigInfo.CollectionConfig)
    91  	v.assert.Equal(expectOut.committingBlockNum, actualCommittingBlockNum)
    92  	v.assert.Equal(expectOut.collConfs, actualCollConf)
    93  }
    94  
    95  func (v *verifier) verifyBlockAndPvtData(blockNum uint64, filter ledger.PvtNsCollFilter, verifyLogic func(r *retrievedBlockAndPvtdata)) {
    96  	out, err := v.lgr.GetPvtDataAndBlockByNum(blockNum, filter)
    97  	v.assert.NoError(err)
    98  	v.t.Logf("Retrieved Block = %s, pvtdata = %s", spew.Sdump(out.Block), spew.Sdump(out.PvtData))
    99  	verifyLogic(&retrievedBlockAndPvtdata{out, v.assert})
   100  }
   101  
   102  func (v *verifier) verifyBlockAndPvtDataSameAs(blockNum uint64, expectedOut *ledger.BlockAndPvtData) {
   103  	v.verifyBlockAndPvtData(blockNum, nil, func(r *retrievedBlockAndPvtdata) {
   104  		r.sameAs(expectedOut)
   105  	})
   106  }
   107  
   108  func (v *verifier) verifyMissingPvtDataSameAs(recentNBlocks int, expectedMissingData ledger.MissingPvtDataInfo) {
   109  	missingDataTracker, err := v.lgr.GetMissingPvtDataTracker()
   110  	v.assert.NoError(err)
   111  	missingPvtData, err := missingDataTracker.GetMissingPvtDataInfoForMostRecentBlocks(recentNBlocks)
   112  	v.assert.NoError(err)
   113  	v.assert.Equal(expectedMissingData, missingPvtData)
   114  }
   115  
   116  func (v *verifier) verifyGetTransactionByID(txid string, expectedOut *protopeer.ProcessedTransaction) {
   117  	tran, err := v.lgr.GetTransactionByID(txid)
   118  	v.assert.NoError(err)
   119  	envelopEqual := proto.Equal(expectedOut.TransactionEnvelope, tran.TransactionEnvelope)
   120  	v.assert.True(envelopEqual)
   121  	v.assert.Equal(expectedOut.ValidationCode, tran.ValidationCode)
   122  }
   123  
   124  func (v *verifier) verifyTxValidationCode(txid string, expectedCode protopeer.TxValidationCode) {
   125  	tran, err := v.lgr.GetTransactionByID(txid)
   126  	v.assert.NoError(err)
   127  	v.assert.Equal(int32(expectedCode), tran.ValidationCode)
   128  }
   129  
   130  func (v *verifier) verifyHistory(ns, key string, expectedVals []string) {
   131  	hqe, err := v.lgr.NewHistoryQueryExecutor()
   132  	v.assert.NoError(err)
   133  	itr, err := hqe.GetHistoryForKey(ns, key)
   134  	v.assert.NoError(err)
   135  	historyValues := []string{}
   136  	for {
   137  		result, err := itr.Next()
   138  		v.assert.NoError(err)
   139  		if result == nil {
   140  			break
   141  		}
   142  		historyValues = append(historyValues, string(result.(*queryresult.KeyModification).GetValue()))
   143  	}
   144  	v.assert.Equal(expectedVals, historyValues)
   145  }
   146  
   147  func (v *verifier) verifyCommitHashExists() {
   148  	bcInfo, err := v.lgr.GetBlockchainInfo()
   149  	v.assert.NoError(err)
   150  	b, err := v.lgr.GetPvtDataAndBlockByNum(bcInfo.Height-1, nil)
   151  	v.assert.NoError(err)
   152  	r := &retrievedBlockAndPvtdata{BlockAndPvtData: b, assert: v.assert}
   153  	r.containsCommitHash()
   154  }
   155  
   156  func (v *verifier) verifyCommitHashNotExists() {
   157  	bcInfo, err := v.lgr.GetBlockchainInfo()
   158  	v.assert.NoError(err)
   159  	b, err := v.lgr.GetPvtDataAndBlockByNum(bcInfo.Height-1, nil)
   160  	v.assert.NoError(err)
   161  	r := &retrievedBlockAndPvtdata{BlockAndPvtData: b, assert: v.assert}
   162  	r.notContainCommitHash()
   163  }
   164  
   165  ////////////  structs used by verifier  //////////////////////////////////////////////////////////////
   166  type expectedCollConfInfo struct {
   167  	committingBlockNum uint64
   168  	collConfs          []*collConf
   169  }
   170  
   171  type retrievedBlockAndPvtdata struct {
   172  	*ledger.BlockAndPvtData
   173  	assert *assert.Assertions
   174  }
   175  
   176  func (r *retrievedBlockAndPvtdata) sameAs(expectedBlockAndPvtdata *ledger.BlockAndPvtData) {
   177  	r.samePvtdata(expectedBlockAndPvtdata.PvtData)
   178  	r.sameBlockHeaderAndData(expectedBlockAndPvtdata.Block)
   179  	r.sameMetadata(expectedBlockAndPvtdata.Block)
   180  }
   181  
   182  func (r *retrievedBlockAndPvtdata) hasNumTx(numTx int) {
   183  	r.assert.Len(r.Block.Data.Data, numTx)
   184  }
   185  
   186  func (r *retrievedBlockAndPvtdata) hasNoPvtdata() {
   187  	r.assert.Len(r.PvtData, 0)
   188  }
   189  
   190  func (r *retrievedBlockAndPvtdata) pvtdataShouldContain(txSeq int, ns, coll, key, value string) {
   191  	txPvtData := r.BlockAndPvtData.PvtData[uint64(txSeq)]
   192  	for _, nsdata := range txPvtData.WriteSet.NsPvtRwset {
   193  		if nsdata.Namespace == ns {
   194  			for _, colldata := range nsdata.CollectionPvtRwset {
   195  				if colldata.CollectionName == coll {
   196  					rwset := &kvrwset.KVRWSet{}
   197  					r.assert.NoError(proto.Unmarshal(colldata.Rwset, rwset))
   198  					for _, w := range rwset.Writes {
   199  						if w.Key == key {
   200  							r.assert.Equal([]byte(value), w.Value)
   201  							return
   202  						}
   203  					}
   204  				}
   205  			}
   206  		}
   207  	}
   208  	r.assert.FailNow("Requested kv not found")
   209  }
   210  
   211  func (r *retrievedBlockAndPvtdata) pvtdataShouldNotContain(ns, coll string) {
   212  	allTxPvtData := r.BlockAndPvtData.PvtData
   213  	for _, txPvtData := range allTxPvtData {
   214  		r.assert.False(txPvtData.Has(ns, coll))
   215  	}
   216  }
   217  
   218  func (r *retrievedBlockAndPvtdata) sameBlockHeaderAndData(expectedBlock *common.Block) {
   219  	r.assert.True(proto.Equal(expectedBlock.Data, r.BlockAndPvtData.Block.Data))
   220  	r.assert.True(proto.Equal(expectedBlock.Header, r.BlockAndPvtData.Block.Header))
   221  }
   222  
   223  func (r *retrievedBlockAndPvtdata) sameMetadata(expectedBlock *common.Block) {
   224  	// marshalling/unmarshalling treats a nil byte and empty byte interchangeably (based on which scheme is chosen proto vs gob)
   225  	// so explicitly comparing each metadata
   226  	retrievedMetadata := r.Block.Metadata.Metadata
   227  	expectedMetadata := expectedBlock.Metadata.Metadata
   228  	r.assert.Equal(len(expectedMetadata), len(retrievedMetadata))
   229  	for i := 0; i < len(expectedMetadata); i++ {
   230  		if i == int(common.BlockMetadataIndex_COMMIT_HASH) {
   231  			// in order to compare the exact hash value, we need to duplicate the
   232  			// production code in this test too, so skipping this match
   233  			continue
   234  		}
   235  		if len(expectedMetadata[i])+len(retrievedMetadata[i]) != 0 {
   236  			r.assert.Equal(expectedMetadata[i], retrievedMetadata[i])
   237  		}
   238  	}
   239  }
   240  
   241  func (r *retrievedBlockAndPvtdata) containsValidationCode(txSeq int, validationCode protopeer.TxValidationCode) {
   242  	txFilter := txflags.ValidationFlags(r.BlockAndPvtData.Block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
   243  	r.assert.Equal(validationCode, txFilter.Flag(txSeq))
   244  }
   245  
   246  func (r *retrievedBlockAndPvtdata) samePvtdata(expectedPvtdata map[uint64]*ledger.TxPvtData) {
   247  	r.assert.Equal(len(expectedPvtdata), len(r.BlockAndPvtData.PvtData))
   248  	for txNum, pvtData := range expectedPvtdata {
   249  		actualPvtData := r.BlockAndPvtData.PvtData[txNum]
   250  		r.assert.Equal(pvtData.SeqInBlock, actualPvtData.SeqInBlock)
   251  		r.assert.True(proto.Equal(pvtData.WriteSet, actualPvtData.WriteSet))
   252  	}
   253  }
   254  
   255  func (r *retrievedBlockAndPvtdata) containsCommitHash() {
   256  	commitHash := &common.Metadata{}
   257  	spew.Dump(r.Block.Metadata)
   258  	err := proto.Unmarshal(
   259  		r.Block.Metadata.Metadata[common.BlockMetadataIndex_COMMIT_HASH],
   260  		commitHash,
   261  	)
   262  	r.assert.NoError(err)
   263  	r.assert.Equal(len(commitHash.Value), 32)
   264  }
   265  
   266  func (r *retrievedBlockAndPvtdata) notContainCommitHash() {
   267  	exists := len(r.Block.Metadata.Metadata) >= int(common.BlockMetadataIndex_COMMIT_HASH)+1 &&
   268  		len(r.Block.Metadata.Metadata[common.BlockMetadataIndex_COMMIT_HASH]) > 0
   269  	r.assert.False(exists)
   270  }