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