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