github.com/ewagmig/fabric@v2.1.1+incompatible/core/ledger/kvledger/txmgmt/validator/statebasedval/range_query_validator.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package statebasedval 8 9 import ( 10 "bytes" 11 12 "github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset" 13 "github.com/hyperledger/fabric/core/ledger" 14 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil" 15 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/statedb" 16 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version" 17 ) 18 19 type rangeQueryValidator interface { 20 init(rqInfo *kvrwset.RangeQueryInfo, itr statedb.ResultsIterator) error 21 validate() (bool, error) 22 } 23 24 type rangeQueryResultsValidator struct { 25 rqInfo *kvrwset.RangeQueryInfo 26 itr statedb.ResultsIterator 27 } 28 29 func (v *rangeQueryResultsValidator) init(rqInfo *kvrwset.RangeQueryInfo, itr statedb.ResultsIterator) error { 30 v.rqInfo = rqInfo 31 v.itr = itr 32 return nil 33 } 34 35 // validate iterates through the results that are present in the range-query-info (captured during simulation) 36 // and the iterator (latest view of the `committed state` i.e., db + updates). At first mismatch between the results 37 // from the two sources (the range-query-info and the iterator), the validate returns false. 38 func (v *rangeQueryResultsValidator) validate() (bool, error) { 39 rqResults := v.rqInfo.GetRawReads().GetKvReads() 40 itr := v.itr 41 var result statedb.QueryResult 42 var err error 43 if result, err = itr.Next(); err != nil { 44 return false, err 45 } 46 if len(rqResults) == 0 { 47 return result == nil, nil 48 } 49 for i := 0; i < len(rqResults); i++ { 50 kvRead := rqResults[i] 51 logger.Debugf("comparing kvRead=[%#v] to queryResponse=[%#v]", kvRead, result) 52 if result == nil { 53 logger.Debugf("Query response nil. Key [%s] got deleted", kvRead.Key) 54 return false, nil 55 } 56 versionedKV := result.(*statedb.VersionedKV) 57 if versionedKV.Key != kvRead.Key { 58 logger.Debugf("key name mismatch: Key in rwset = [%s], key in query results = [%s]", kvRead.Key, versionedKV.Key) 59 return false, nil 60 } 61 if !version.AreSame(versionedKV.Version, convertToVersionHeight(kvRead.Version)) { 62 logger.Debugf(`Version mismatch for key [%s]: Version in rwset = [%#v], latest version = [%#v]`, 63 versionedKV.Key, versionedKV.Version, kvRead.Version) 64 return false, nil 65 } 66 if result, err = itr.Next(); err != nil { 67 return false, err 68 } 69 } 70 if result != nil { 71 // iterator is not exhausted - which means that there are extra results in the given range 72 logger.Debugf("Extra result = [%#v]", result) 73 return false, nil 74 } 75 return true, nil 76 } 77 78 type rangeQueryHashValidator struct { 79 rqInfo *kvrwset.RangeQueryInfo 80 itr statedb.ResultsIterator 81 resultsHelper *rwsetutil.RangeQueryResultsHelper 82 hasher ledger.Hasher 83 } 84 85 func (v *rangeQueryHashValidator) init(rqInfo *kvrwset.RangeQueryInfo, itr statedb.ResultsIterator) error { 86 v.rqInfo = rqInfo 87 v.itr = itr 88 var err error 89 v.resultsHelper, err = rwsetutil.NewRangeQueryResultsHelper(true, rqInfo.GetReadsMerkleHashes().MaxDegree, v.hasher) 90 return err 91 } 92 93 // validate iterates through the iterator (latest view of the `committed state` i.e., db + updates) 94 // and starts building the merkle tree incrementally (Both, during simulation and during validation, 95 // rwset.RangeQueryResultsHelper is used for building the merkle tree incrementally ). 96 // 97 // This function also keeps comparing the under-construction merkle tree with the merkle tree 98 // summary present in the range-query-info (built during simulation). 99 // This function returns false on first mismatch between the nodes of the two merkle trees 100 // at the desired level (the maxLevel of the merkle tree in range-query-info). 101 func (v *rangeQueryHashValidator) validate() (bool, error) { 102 itr := v.itr 103 lastMatchedIndex := -1 104 inMerkle := v.rqInfo.GetReadsMerkleHashes() 105 var merkle *kvrwset.QueryReadsMerkleSummary 106 logger.Debugf("inMerkle: %#v", inMerkle) 107 for { 108 var result statedb.QueryResult 109 var err error 110 if result, err = itr.Next(); err != nil { 111 return false, err 112 } 113 logger.Debugf("Processing result = %#v", result) 114 if result == nil { 115 if _, merkle, err = v.resultsHelper.Done(); err != nil { 116 return false, err 117 } 118 equals := merkleSummariesEqual(inMerkle, merkle) 119 logger.Debugf("Combined iterator exhausted. merkle=%#v, equals=%t", merkle, equals) 120 return equals, nil 121 } 122 versionedKV := result.(*statedb.VersionedKV) 123 v.resultsHelper.AddResult(rwsetutil.NewKVRead(versionedKV.Key, versionedKV.Version)) 124 merkle := v.resultsHelper.GetMerkleSummary() 125 126 if merkle.MaxLevel < inMerkle.MaxLevel { 127 logger.Debugf("Hashes still under construction. Noting to compare yet. Need more results. Continuing...") 128 continue 129 } 130 if lastMatchedIndex == len(merkle.MaxLevelHashes)-1 { 131 logger.Debugf("Need more results to build next entry [index=%d] at level [%d]. Continuing...", 132 lastMatchedIndex+1, merkle.MaxLevel) 133 continue 134 } 135 if len(merkle.MaxLevelHashes) > len(inMerkle.MaxLevelHashes) { 136 logger.Debugf("Entries exceeded from what are present in the incoming merkleSummary. Validation failed") 137 return false, nil 138 } 139 lastMatchedIndex++ 140 if !bytes.Equal(merkle.MaxLevelHashes[lastMatchedIndex], inMerkle.MaxLevelHashes[lastMatchedIndex]) { 141 logger.Debugf("Hashes does not match at index [%d]. Validation failed", lastMatchedIndex) 142 return false, nil 143 } 144 } 145 } 146 147 func merkleSummariesEqual(ms, anotherMS *kvrwset.QueryReadsMerkleSummary) bool { 148 if anotherMS == nil { 149 return false 150 } 151 if ms.MaxDegree != anotherMS.MaxDegree || 152 ms.MaxLevel != anotherMS.MaxLevel || 153 len(ms.MaxLevelHashes) != len(anotherMS.MaxLevelHashes) { 154 return false 155 } 156 for i := 0; i < len(ms.MaxLevelHashes); i++ { 157 if !bytes.Equal(ms.MaxLevelHashes[i], anotherMS.MaxLevelHashes[i]) { 158 return false 159 } 160 } 161 return true 162 } 163 164 func convertToVersionHeight(v *kvrwset.Version) *version.Height { 165 return version.NewHeight(v.BlockNum, v.TxNum) 166 }