github.com/true-sqn/fabric@v2.1.1+incompatible/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/hyperledger/fabric/core/ledger" 19 lgrutil "github.com/hyperledger/fabric/core/ledger/util" 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) verifyPvtState(ns, coll, key string, expectedVal string) { 57 qe, err := v.lgr.NewQueryExecutor() 58 v.assert.NoError(err) 59 defer qe.Done() 60 committedVal, err := qe.GetPrivateData(ns, coll, key) 61 v.assert.NoError(err) 62 v.t.Logf("val=%s", committedVal) 63 var expectedValBytes []byte 64 if expectedVal != "" { 65 expectedValBytes = []byte(expectedVal) 66 } 67 v.assert.Equal(expectedValBytes, committedVal) 68 } 69 70 func (v *verifier) verifyMostRecentCollectionConfigBelow(blockNum uint64, chaincodeName string, expectOut *expectedCollConfInfo) { 71 configHistory, err := v.lgr.GetConfigHistoryRetriever() 72 v.assert.NoError(err) 73 actualCollectionConfigInfo, err := configHistory.MostRecentCollectionConfigBelow(blockNum, chaincodeName) 74 v.assert.NoError(err) 75 if expectOut == nil { 76 v.assert.Nil(actualCollectionConfigInfo) 77 return 78 } 79 v.t.Logf("Retrieved CollectionConfigInfo=%s", spew.Sdump(actualCollectionConfigInfo)) 80 actualCommittingBlockNum := actualCollectionConfigInfo.CommittingBlockNum 81 actualCollConf := convertFromCollConfigProto(actualCollectionConfigInfo.CollectionConfig) 82 v.assert.Equal(expectOut.committingBlockNum, actualCommittingBlockNum) 83 v.assert.Equal(expectOut.collConfs, actualCollConf) 84 } 85 86 func (v *verifier) verifyBlockAndPvtData(blockNum uint64, filter ledger.PvtNsCollFilter, verifyLogic func(r *retrievedBlockAndPvtdata)) { 87 out, err := v.lgr.GetPvtDataAndBlockByNum(blockNum, filter) 88 v.assert.NoError(err) 89 v.t.Logf("Retrieved Block = %s, pvtdata = %s", spew.Sdump(out.Block), spew.Sdump(out.PvtData)) 90 verifyLogic(&retrievedBlockAndPvtdata{out, v.assert}) 91 } 92 93 func (v *verifier) verifyBlockAndPvtDataSameAs(blockNum uint64, expectedOut *ledger.BlockAndPvtData) { 94 v.verifyBlockAndPvtData(blockNum, nil, func(r *retrievedBlockAndPvtdata) { 95 r.sameAs(expectedOut) 96 }) 97 } 98 99 func (v *verifier) verifyMissingPvtDataSameAs(recentNBlocks int, expectedMissingData ledger.MissingPvtDataInfo) { 100 missingDataTracker, err := v.lgr.GetMissingPvtDataTracker() 101 v.assert.NoError(err) 102 missingPvtData, err := missingDataTracker.GetMissingPvtDataInfoForMostRecentBlocks(recentNBlocks) 103 v.assert.NoError(err) 104 v.assert.Equal(expectedMissingData, missingPvtData) 105 } 106 107 func (v *verifier) verifyGetTransactionByID(txid string, expectedOut *protopeer.ProcessedTransaction) { 108 tran, err := v.lgr.GetTransactionByID(txid) 109 v.assert.NoError(err) 110 envelopEqual := proto.Equal(expectedOut.TransactionEnvelope, tran.TransactionEnvelope) 111 v.assert.True(envelopEqual) 112 v.assert.Equal(expectedOut.ValidationCode, tran.ValidationCode) 113 } 114 115 func (v *verifier) verifyTxValidationCode(txid string, expectedCode protopeer.TxValidationCode) { 116 tran, err := v.lgr.GetTransactionByID(txid) 117 v.assert.NoError(err) 118 v.assert.Equal(int32(expectedCode), tran.ValidationCode) 119 } 120 121 func (v *verifier) verifyHistory(ns, key string, expectedVals []string) { 122 hqe, err := v.lgr.NewHistoryQueryExecutor() 123 v.assert.NoError(err) 124 itr, err := hqe.GetHistoryForKey(ns, key) 125 v.assert.NoError(err) 126 historyValues := []string{} 127 for { 128 result, err := itr.Next() 129 v.assert.NoError(err) 130 if result == nil { 131 break 132 } 133 historyValues = append(historyValues, string(result.(*queryresult.KeyModification).GetValue())) 134 } 135 v.assert.Equal(expectedVals, historyValues) 136 } 137 138 //////////// structs used by verifier ////////////////////////////////////////////////////////////// 139 type expectedCollConfInfo struct { 140 committingBlockNum uint64 141 collConfs []*collConf 142 } 143 144 type retrievedBlockAndPvtdata struct { 145 *ledger.BlockAndPvtData 146 assert *assert.Assertions 147 } 148 149 func (r *retrievedBlockAndPvtdata) sameAs(expectedBlockAndPvtdata *ledger.BlockAndPvtData) { 150 r.samePvtdata(expectedBlockAndPvtdata.PvtData) 151 r.sameBlockHeaderAndData(expectedBlockAndPvtdata.Block) 152 r.sameMetadata(expectedBlockAndPvtdata.Block) 153 } 154 155 func (r *retrievedBlockAndPvtdata) hasNumTx(numTx int) { 156 r.assert.Len(r.Block.Data.Data, numTx) 157 } 158 159 func (r *retrievedBlockAndPvtdata) hasNoPvtdata() { 160 r.assert.Len(r.PvtData, 0) 161 } 162 163 func (r *retrievedBlockAndPvtdata) pvtdataShouldContain(txSeq int, ns, coll, key, value string) { 164 txPvtData := r.BlockAndPvtData.PvtData[uint64(txSeq)] 165 for _, nsdata := range txPvtData.WriteSet.NsPvtRwset { 166 if nsdata.Namespace == ns { 167 for _, colldata := range nsdata.CollectionPvtRwset { 168 if colldata.CollectionName == coll { 169 rwset := &kvrwset.KVRWSet{} 170 r.assert.NoError(proto.Unmarshal(colldata.Rwset, rwset)) 171 for _, w := range rwset.Writes { 172 if w.Key == key { 173 r.assert.Equal([]byte(value), w.Value) 174 return 175 } 176 } 177 } 178 } 179 } 180 } 181 r.assert.FailNow("Requested kv not found") 182 } 183 184 func (r *retrievedBlockAndPvtdata) pvtdataShouldNotContain(ns, coll string) { 185 allTxPvtData := r.BlockAndPvtData.PvtData 186 for _, txPvtData := range allTxPvtData { 187 r.assert.False(txPvtData.Has(ns, coll)) 188 } 189 } 190 191 func (r *retrievedBlockAndPvtdata) sameBlockHeaderAndData(expectedBlock *common.Block) { 192 r.assert.True(proto.Equal(expectedBlock.Data, r.BlockAndPvtData.Block.Data)) 193 r.assert.True(proto.Equal(expectedBlock.Header, r.BlockAndPvtData.Block.Header)) 194 } 195 196 func (r *retrievedBlockAndPvtdata) sameMetadata(expectedBlock *common.Block) { 197 // marshalling/unmarshalling treats a nil byte and empty byte interchangeably (based on which scheme is chosen proto vs gob) 198 // so explicitly comparing each metadata 199 retrievedMetadata := r.Block.Metadata.Metadata 200 expectedMetadata := expectedBlock.Metadata.Metadata 201 r.assert.Equal(len(expectedMetadata), len(retrievedMetadata)) 202 for i := 0; i < len(expectedMetadata); i++ { 203 if len(expectedMetadata[i])+len(retrievedMetadata[i]) != 0 { 204 if i != int(common.BlockMetadataIndex_COMMIT_HASH) { 205 r.assert.Equal(expectedMetadata[i], retrievedMetadata[i]) 206 } else { 207 // in order to compare the exact hash value, we need to duplicate the 208 // production code in this test too (which is not recommended). 209 commitHash := &common.Metadata{} 210 err := proto.Unmarshal(retrievedMetadata[common.BlockMetadataIndex_COMMIT_HASH], 211 commitHash) 212 r.assert.NoError(err) 213 r.assert.Equal(len(commitHash.Value), 32) 214 } 215 } 216 } 217 } 218 219 func (r *retrievedBlockAndPvtdata) containsValidationCode(txSeq int, validationCode protopeer.TxValidationCode) { 220 var txFilter lgrutil.TxValidationFlags 221 txFilter = r.BlockAndPvtData.Block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] 222 r.assert.Equal(validationCode, txFilter.Flag(txSeq)) 223 } 224 225 func (r *retrievedBlockAndPvtdata) samePvtdata(expectedPvtdata map[uint64]*ledger.TxPvtData) { 226 r.assert.Equal(len(expectedPvtdata), len(r.BlockAndPvtData.PvtData)) 227 for txNum, pvtData := range expectedPvtdata { 228 actualPvtData := r.BlockAndPvtData.PvtData[txNum] 229 r.assert.Equal(pvtData.SeqInBlock, actualPvtData.SeqInBlock) 230 r.assert.True(proto.Equal(pvtData.WriteSet, actualPvtData.WriteSet)) 231 } 232 }