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