github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/core/ledger/kvledger/txmgmt/rwsetutil/query_results_helper.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 rwsetutil 18 19 import ( 20 "fmt" 21 22 "github.com/golang/protobuf/proto" 23 "github.com/hyperledger/fabric/bccsp" 24 bccspfactory "github.com/hyperledger/fabric/bccsp/factory" 25 "github.com/hyperledger/fabric/protos/ledger/rwset/kvrwset" 26 ) 27 28 // MerkleTreeLevel used for representing a level of the merkle tree 29 type MerkleTreeLevel uint32 30 31 // Hash represents bytes of a hash 32 type Hash []byte 33 34 const ( 35 leafLevel = MerkleTreeLevel(1) 36 ) 37 38 var ( 39 hashOpts = &bccsp.SHA256Opts{} 40 ) 41 42 // RangeQueryResultsHelper helps preparing range query results for phantom items detection during validation. 43 // The results are expected to be fed as they are being iterated over. 44 // If the `hashingEnabled` is set to true, a merkle tree is built of the hashes over the results. 45 // The merkle tree helps reducing the size of the RWSet which otherwise would need to store all the raw KVReads 46 // 47 // The mental model of the tree can be described as below: 48 // All the results are treated as leaf nodes (level 0) of the tree. Next up level of the tree is built by collecting 'maxDegree + 1' 49 // items from the previous level and hashing the entire collection. 50 // Further upper levels of the tree are built in similar manner however the only difference is that unlike level-0 51 // (where collection consists of raw KVReads), collection at level 1 and above, consists of the hashes 52 // (of the collection of previous level). 53 // This is repeated until we reach at a level where we are left with the number of items less than or equals to `maxDegree`. 54 // In the last collection, the number of items can be less than 'maxDegree' (except if this is the only collection at the given level). 55 // 56 // As a result, if the number of total input results are less than or equals to 'maxDegree', no hashing is performed at all. 57 // And the final output of the computation is either the collection of raw results (if less that or equals to 'maxDegree') or 58 // a collection of hashes (that or equals to 'maxDegree') at some level in the tree. 59 // 60 // `AddResult` function should be invoke to supply the next result and at the end `Done` function should be invoked. 61 // The `Done` function does the final processing and returns the final output 62 type RangeQueryResultsHelper struct { 63 pendingResults []*kvrwset.KVRead 64 hashingEnabled bool 65 maxDegree uint32 66 mt *merkleTree 67 } 68 69 // NewRangeQueryResultsHelper constructs a RangeQueryResultsHelper 70 func NewRangeQueryResultsHelper(enableHashing bool, maxDegree uint32) (*RangeQueryResultsHelper, error) { 71 helper := &RangeQueryResultsHelper{nil, enableHashing, maxDegree, nil} 72 if enableHashing { 73 var err error 74 if helper.mt, err = newMerkleTree(maxDegree); err != nil { 75 return nil, err 76 } 77 } 78 return helper, nil 79 } 80 81 // AddResult adds a new query result for processing. 82 // Put the result into the list of pending results. If the number of pending results exceeds `maxDegree`, 83 // consume the results for incrementally update the merkle tree 84 func (helper *RangeQueryResultsHelper) AddResult(kvRead *kvrwset.KVRead) error { 85 logger.Debug("Adding a result") 86 helper.pendingResults = append(helper.pendingResults, kvRead) 87 if helper.hashingEnabled && uint32(len(helper.pendingResults)) > helper.maxDegree { 88 logger.Debug("Processing the accumulated results") 89 if err := helper.processPendingResults(); err != nil { 90 return err 91 } 92 } 93 return nil 94 } 95 96 // Done processes any pending results if needed 97 // This returns the final pending results (i.e., []*KVRead) and hashes of the results (i.e., *MerkleSummary) 98 // Only one of these two will be non-nil (except when no results are ever added). 99 // `MerkleSummary` will be nil if and only if either `enableHashing` is set to false 100 // or the number of total results are less than `maxDegree` 101 func (helper *RangeQueryResultsHelper) Done() ([]*kvrwset.KVRead, *kvrwset.QueryReadsMerkleSummary, error) { 102 // The merkle tree will be empty if total results are less than or equals to 'maxDegree' 103 // i.e., not even once the results were processed for hashing 104 if !helper.hashingEnabled || helper.mt.isEmpty() { 105 return helper.pendingResults, nil, nil 106 } 107 if len(helper.pendingResults) != 0 { 108 logger.Debug("Processing the pending results") 109 if err := helper.processPendingResults(); err != nil { 110 return helper.pendingResults, nil, err 111 } 112 } 113 helper.mt.done() 114 return helper.pendingResults, helper.mt.getSummery(), nil 115 } 116 117 // GetMerkleSummary return the current state of the MerkleSummary 118 // This intermediate state of the merkle tree helps during validation to detect a mismatch early on. 119 // That helps by not requiring to build the complete merkle tree during validation 120 // if there is a mismatch in early portion of the result-set. 121 func (helper *RangeQueryResultsHelper) GetMerkleSummary() *kvrwset.QueryReadsMerkleSummary { 122 if !helper.hashingEnabled { 123 return nil 124 } 125 return helper.mt.getSummery() 126 } 127 128 func (helper *RangeQueryResultsHelper) processPendingResults() error { 129 var b []byte 130 var err error 131 if b, err = serializeKVReads(helper.pendingResults); err != nil { 132 return err 133 } 134 helper.pendingResults = nil 135 hash, err := bccspfactory.GetDefault().Hash(b, hashOpts) 136 if err != nil { 137 return err 138 } 139 helper.mt.update(hash) 140 return nil 141 } 142 143 func serializeKVReads(kvReads []*kvrwset.KVRead) ([]byte, error) { 144 return proto.Marshal(&kvrwset.QueryReads{KvReads: kvReads}) 145 } 146 147 //////////// Merkle tree building code /////// 148 149 type merkleTree struct { 150 maxDegree uint32 151 tree map[MerkleTreeLevel][]Hash 152 maxLevel MerkleTreeLevel 153 } 154 155 func newMerkleTree(maxDegree uint32) (*merkleTree, error) { 156 if maxDegree < 2 { 157 return nil, fmt.Errorf("maxDegree [is %d] should not be less than 2 in the merkle tree", maxDegree) 158 } 159 return &merkleTree{maxDegree, make(map[MerkleTreeLevel][]Hash), 1}, nil 160 } 161 162 // update takes a hash that forms the next leaf level (level-1) node in the merkle tree. 163 // Also, complete the merkle tree as much as possible with the addition of this new leaf node - 164 // i.e. recursively build the higher level nodes and delete the underlying sub-tree. 165 func (m *merkleTree) update(nextLeafLevelHash Hash) error { 166 logger.Debugf("Before update() = %s", m) 167 defer logger.Debugf("After update() = %s", m) 168 m.tree[leafLevel] = append(m.tree[leafLevel], nextLeafLevelHash) 169 currentLevel := leafLevel 170 for { 171 currentLevelHashes := m.tree[currentLevel] 172 if uint32(len(currentLevelHashes)) <= m.maxDegree { 173 return nil 174 } 175 nextLevelHash, err := computeCombinedHash(currentLevelHashes) 176 if err != nil { 177 return err 178 } 179 delete(m.tree, currentLevel) 180 nextLevel := currentLevel + 1 181 m.tree[nextLevel] = append(m.tree[nextLevel], nextLevelHash) 182 if nextLevel > m.maxLevel { 183 m.maxLevel = nextLevel 184 } 185 currentLevel = nextLevel 186 } 187 } 188 189 // done completes the merkle tree. 190 // There may have been some nodes that are at the levels lower than the maxLevel (maximum level seen by the tree so far). 191 // Make the parent nodes out of such nodes till we complete the tree at the level of maxLevel (or maxLevel+1). 192 func (m *merkleTree) done() error { 193 logger.Debugf("Before done() = %s", m) 194 defer logger.Debugf("After done() = %s", m) 195 currentLevel := leafLevel 196 var h Hash 197 var err error 198 for currentLevel < m.maxLevel { 199 currentLevelHashes := m.tree[currentLevel] 200 switch len(currentLevelHashes) { 201 case 0: 202 currentLevel++ 203 continue 204 case 1: 205 h = currentLevelHashes[0] 206 default: 207 if h, err = computeCombinedHash(currentLevelHashes); err != nil { 208 return err 209 } 210 } 211 delete(m.tree, currentLevel) 212 currentLevel++ 213 m.tree[currentLevel] = append(m.tree[currentLevel], h) 214 } 215 216 finalHashes := m.tree[m.maxLevel] 217 if uint32(len(finalHashes)) > m.maxDegree { 218 delete(m.tree, m.maxLevel) 219 m.maxLevel++ 220 combinedHash, err := computeCombinedHash(finalHashes) 221 if err != nil { 222 return err 223 } 224 m.tree[m.maxLevel] = []Hash{combinedHash} 225 } 226 return nil 227 } 228 229 func (m *merkleTree) getSummery() *kvrwset.QueryReadsMerkleSummary { 230 return &kvrwset.QueryReadsMerkleSummary{MaxDegree: m.maxDegree, 231 MaxLevel: uint32(m.maxLevel), 232 MaxLevelHashes: hashesToBytes(m.tree[m.maxLevel])} 233 } 234 235 func (m *merkleTree) getMaxLevel() MerkleTreeLevel { 236 return m.maxLevel 237 } 238 239 func (m *merkleTree) getMaxLevelHashes() []Hash { 240 return m.tree[m.maxLevel] 241 } 242 243 func (m *merkleTree) isEmpty() bool { 244 return m.maxLevel == 1 && len(m.tree[m.maxLevel]) == 0 245 } 246 247 func (m *merkleTree) String() string { 248 return fmt.Sprintf("tree := %#v", m.tree) 249 } 250 251 func computeCombinedHash(hashes []Hash) (Hash, error) { 252 combinedHash := []byte{} 253 for _, h := range hashes { 254 combinedHash = append(combinedHash, h...) 255 } 256 return bccspfactory.GetDefault().Hash(combinedHash, hashOpts) 257 } 258 259 func hashesToBytes(hashes []Hash) [][]byte { 260 b := [][]byte{} 261 for _, hash := range hashes { 262 b = append(b, hash) 263 } 264 return b 265 }