github.com/true-sqn/fabric@v2.1.1+incompatible/core/ledger/kvledger/txmgmt/rwsetutil/rwset_builder.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 "github.com/hyperledger/fabric-protos-go/ledger/rwset" 21 "github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset" 22 "github.com/hyperledger/fabric/common/flogging" 23 "github.com/hyperledger/fabric/core/ledger" 24 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version" 25 "github.com/hyperledger/fabric/core/ledger/util" 26 ) 27 28 var logger = flogging.MustGetLogger("rwsetutil") 29 30 // RWSetBuilder helps building the read-write set 31 type RWSetBuilder struct { 32 pubRwBuilderMap map[string]*nsPubRwBuilder 33 pvtRwBuilderMap map[string]*nsPvtRwBuilder 34 } 35 36 type nsPubRwBuilder struct { 37 namespace string 38 readMap map[string]*kvrwset.KVRead //for mvcc validation 39 writeMap map[string]*kvrwset.KVWrite 40 metadataWriteMap map[string]*kvrwset.KVMetadataWrite 41 rangeQueriesMap map[rangeQueryKey]*kvrwset.RangeQueryInfo //for phantom read validation 42 rangeQueriesKeys []rangeQueryKey 43 collHashRwBuilder map[string]*collHashRwBuilder 44 } 45 46 type collHashRwBuilder struct { 47 collName string 48 readMap map[string]*kvrwset.KVReadHash 49 writeMap map[string]*kvrwset.KVWriteHash 50 metadataWriteMap map[string]*kvrwset.KVMetadataWriteHash 51 pvtDataHash []byte 52 } 53 54 type nsPvtRwBuilder struct { 55 namespace string 56 collPvtRwBuilders map[string]*collPvtRwBuilder 57 } 58 59 type collPvtRwBuilder struct { 60 collectionName string 61 writeMap map[string]*kvrwset.KVWrite 62 metadataWriteMap map[string]*kvrwset.KVMetadataWrite 63 } 64 65 type rangeQueryKey struct { 66 startKey string 67 endKey string 68 itrExhausted bool 69 } 70 71 // NewRWSetBuilder constructs a new instance of RWSetBuilder 72 func NewRWSetBuilder() *RWSetBuilder { 73 return &RWSetBuilder{make(map[string]*nsPubRwBuilder), make(map[string]*nsPvtRwBuilder)} 74 } 75 76 // AddToReadSet adds a key and corresponding version to the read-set 77 func (b *RWSetBuilder) AddToReadSet(ns string, key string, version *version.Height) { 78 nsPubRwBuilder := b.getOrCreateNsPubRwBuilder(ns) 79 nsPubRwBuilder.readMap[key] = NewKVRead(key, version) 80 } 81 82 // AddToWriteSet adds a key and value to the write-set 83 func (b *RWSetBuilder) AddToWriteSet(ns string, key string, value []byte) { 84 nsPubRwBuilder := b.getOrCreateNsPubRwBuilder(ns) 85 nsPubRwBuilder.writeMap[key] = newKVWrite(key, value) 86 } 87 88 // AddToMetadataWriteSet adds a metadata to a key in the write-set 89 // A nil/empty-map for 'metadata' parameter indicates the delete of the metadata 90 func (b *RWSetBuilder) AddToMetadataWriteSet(ns, key string, metadata map[string][]byte) { 91 b.getOrCreateNsPubRwBuilder(ns). 92 metadataWriteMap[key] = mapToMetadataWrite(key, metadata) 93 } 94 95 // AddToRangeQuerySet adds a range query info for performing phantom read validation 96 func (b *RWSetBuilder) AddToRangeQuerySet(ns string, rqi *kvrwset.RangeQueryInfo) { 97 nsPubRwBuilder := b.getOrCreateNsPubRwBuilder(ns) 98 key := rangeQueryKey{rqi.StartKey, rqi.EndKey, rqi.ItrExhausted} 99 _, ok := nsPubRwBuilder.rangeQueriesMap[key] 100 if !ok { 101 nsPubRwBuilder.rangeQueriesMap[key] = rqi 102 nsPubRwBuilder.rangeQueriesKeys = append(nsPubRwBuilder.rangeQueriesKeys, key) 103 } 104 } 105 106 // AddToHashedReadSet adds a key and corresponding version to the hashed read-set 107 func (b *RWSetBuilder) AddToHashedReadSet(ns string, coll string, key string, version *version.Height) { 108 kvReadHash := newPvtKVReadHash(key, version) 109 b.getOrCreateCollHashedRwBuilder(ns, coll).readMap[key] = kvReadHash 110 } 111 112 // AddToPvtAndHashedWriteSet adds a key and value to the private and hashed write-set 113 func (b *RWSetBuilder) AddToPvtAndHashedWriteSet(ns string, coll string, key string, value []byte) { 114 kvWrite, kvWriteHash := newPvtKVWriteAndHash(key, value) 115 b.getOrCreateCollPvtRwBuilder(ns, coll).writeMap[key] = kvWrite 116 b.getOrCreateCollHashedRwBuilder(ns, coll).writeMap[key] = kvWriteHash 117 } 118 119 // AddToHashedMetadataWriteSet adds a metadata to a key in the hashed write-set 120 func (b *RWSetBuilder) AddToHashedMetadataWriteSet(ns, coll, key string, metadata map[string][]byte) { 121 // pvt write set just need the key; not the entire metadata. The metadata is stored only 122 // by the hashed key. Pvt write-set need to know the key for handling a special case where only 123 // metadata is updated so, the version of the key present in the pvt data should be incremented 124 b.getOrCreateCollPvtRwBuilder(ns, coll). 125 metadataWriteMap[key] = &kvrwset.KVMetadataWrite{Key: key, Entries: nil} 126 b.getOrCreateCollHashedRwBuilder(ns, coll). 127 metadataWriteMap[key] = mapToMetadataWriteHash(key, metadata) 128 } 129 130 // GetTxSimulationResults returns the proto bytes of public rwset 131 // (public data + hashes of private data) and the private rwset for the transaction 132 func (b *RWSetBuilder) GetTxSimulationResults() (*ledger.TxSimulationResults, error) { 133 pvtData := b.getTxPvtReadWriteSet() 134 var err error 135 136 var pubDataProto *rwset.TxReadWriteSet 137 var pvtDataProto *rwset.TxPvtReadWriteSet 138 139 // Populate the collection-level hashes into pub rwset and compute the proto bytes for pvt rwset 140 if pvtData != nil { 141 if pvtDataProto, err = pvtData.toProtoMsg(); err != nil { 142 return nil, err 143 } 144 for _, ns := range pvtDataProto.NsPvtRwset { 145 for _, coll := range ns.CollectionPvtRwset { 146 b.setPvtCollectionHash(ns.Namespace, coll.CollectionName, coll.Rwset) 147 } 148 } 149 } 150 // Compute the proto bytes for pub rwset 151 pubSet := b.GetTxReadWriteSet() 152 if pubSet != nil { 153 if pubDataProto, err = pubSet.toProtoMsg(); err != nil { 154 return nil, err 155 } 156 } 157 return &ledger.TxSimulationResults{ 158 PubSimulationResults: pubDataProto, 159 PvtSimulationResults: pvtDataProto, 160 }, nil 161 } 162 163 func (b *RWSetBuilder) setPvtCollectionHash(ns string, coll string, pvtDataProto []byte) { 164 collHashedBuilder := b.getOrCreateCollHashedRwBuilder(ns, coll) 165 collHashedBuilder.pvtDataHash = util.ComputeHash(pvtDataProto) 166 } 167 168 // GetTxReadWriteSet returns the read-write set 169 // TODO make this function private once txmgr starts using new function `GetTxSimulationResults` introduced here 170 func (b *RWSetBuilder) GetTxReadWriteSet() *TxRwSet { 171 sortedNsPubBuilders := []*nsPubRwBuilder{} 172 util.GetValuesBySortedKeys(&(b.pubRwBuilderMap), &sortedNsPubBuilders) 173 174 var nsPubRwSets []*NsRwSet 175 for _, nsPubRwBuilder := range sortedNsPubBuilders { 176 nsPubRwSets = append(nsPubRwSets, nsPubRwBuilder.build()) 177 } 178 return &TxRwSet{NsRwSets: nsPubRwSets} 179 } 180 181 // getTxPvtReadWriteSet returns the private read-write set 182 func (b *RWSetBuilder) getTxPvtReadWriteSet() *TxPvtRwSet { 183 sortedNsPvtBuilders := []*nsPvtRwBuilder{} 184 util.GetValuesBySortedKeys(&(b.pvtRwBuilderMap), &sortedNsPvtBuilders) 185 186 var nsPvtRwSets []*NsPvtRwSet 187 for _, nsPvtRwBuilder := range sortedNsPvtBuilders { 188 nsPvtRwSets = append(nsPvtRwSets, nsPvtRwBuilder.build()) 189 } 190 if len(nsPvtRwSets) == 0 { 191 return nil 192 } 193 return &TxPvtRwSet{NsPvtRwSet: nsPvtRwSets} 194 } 195 196 func (b *nsPubRwBuilder) build() *NsRwSet { 197 var readSet []*kvrwset.KVRead 198 var writeSet []*kvrwset.KVWrite 199 var metadataWriteSet []*kvrwset.KVMetadataWrite 200 var rangeQueriesInfo []*kvrwset.RangeQueryInfo 201 var collHashedRwSet []*CollHashedRwSet 202 //add read set 203 util.GetValuesBySortedKeys(&(b.readMap), &readSet) 204 //add write set 205 util.GetValuesBySortedKeys(&(b.writeMap), &writeSet) 206 util.GetValuesBySortedKeys(&(b.metadataWriteMap), &metadataWriteSet) 207 //add range query info 208 for _, key := range b.rangeQueriesKeys { 209 rangeQueriesInfo = append(rangeQueriesInfo, b.rangeQueriesMap[key]) 210 } 211 // add hashed rws for private collections 212 sortedCollBuilders := []*collHashRwBuilder{} 213 util.GetValuesBySortedKeys(&(b.collHashRwBuilder), &sortedCollBuilders) 214 for _, collBuilder := range sortedCollBuilders { 215 collHashedRwSet = append(collHashedRwSet, collBuilder.build()) 216 } 217 return &NsRwSet{ 218 NameSpace: b.namespace, 219 KvRwSet: &kvrwset.KVRWSet{ 220 Reads: readSet, 221 Writes: writeSet, 222 MetadataWrites: metadataWriteSet, 223 RangeQueriesInfo: rangeQueriesInfo, 224 }, 225 CollHashedRwSets: collHashedRwSet, 226 } 227 } 228 229 func (b *nsPvtRwBuilder) build() *NsPvtRwSet { 230 sortedCollBuilders := []*collPvtRwBuilder{} 231 util.GetValuesBySortedKeys(&(b.collPvtRwBuilders), &sortedCollBuilders) 232 233 var collPvtRwSets []*CollPvtRwSet 234 for _, collBuilder := range sortedCollBuilders { 235 collPvtRwSets = append(collPvtRwSets, collBuilder.build()) 236 } 237 return &NsPvtRwSet{NameSpace: b.namespace, CollPvtRwSets: collPvtRwSets} 238 } 239 240 func (b *collHashRwBuilder) build() *CollHashedRwSet { 241 var readSet []*kvrwset.KVReadHash 242 var writeSet []*kvrwset.KVWriteHash 243 var metadataWriteSet []*kvrwset.KVMetadataWriteHash 244 245 util.GetValuesBySortedKeys(&(b.readMap), &readSet) 246 util.GetValuesBySortedKeys(&(b.writeMap), &writeSet) 247 util.GetValuesBySortedKeys(&(b.metadataWriteMap), &metadataWriteSet) 248 return &CollHashedRwSet{ 249 CollectionName: b.collName, 250 HashedRwSet: &kvrwset.HashedRWSet{ 251 HashedReads: readSet, 252 HashedWrites: writeSet, 253 MetadataWrites: metadataWriteSet, 254 }, 255 PvtRwSetHash: b.pvtDataHash, 256 } 257 } 258 259 func (b *collPvtRwBuilder) build() *CollPvtRwSet { 260 var writeSet []*kvrwset.KVWrite 261 var metadataWriteSet []*kvrwset.KVMetadataWrite 262 util.GetValuesBySortedKeys(&(b.writeMap), &writeSet) 263 util.GetValuesBySortedKeys(&(b.metadataWriteMap), &metadataWriteSet) 264 return &CollPvtRwSet{ 265 CollectionName: b.collectionName, 266 KvRwSet: &kvrwset.KVRWSet{ 267 Writes: writeSet, 268 MetadataWrites: metadataWriteSet, 269 }, 270 } 271 } 272 273 func (b *RWSetBuilder) getOrCreateNsPubRwBuilder(ns string) *nsPubRwBuilder { 274 nsPubRwBuilder, ok := b.pubRwBuilderMap[ns] 275 if !ok { 276 nsPubRwBuilder = newNsPubRwBuilder(ns) 277 b.pubRwBuilderMap[ns] = nsPubRwBuilder 278 } 279 return nsPubRwBuilder 280 } 281 282 func (b *RWSetBuilder) getOrCreateNsPvtRwBuilder(ns string) *nsPvtRwBuilder { 283 nsPvtRwBuilder, ok := b.pvtRwBuilderMap[ns] 284 if !ok { 285 nsPvtRwBuilder = newNsPvtRwBuilder(ns) 286 b.pvtRwBuilderMap[ns] = nsPvtRwBuilder 287 } 288 return nsPvtRwBuilder 289 } 290 291 func (b *RWSetBuilder) getOrCreateCollHashedRwBuilder(ns string, coll string) *collHashRwBuilder { 292 nsPubRwBuilder := b.getOrCreateNsPubRwBuilder(ns) 293 collHashRwBuilder, ok := nsPubRwBuilder.collHashRwBuilder[coll] 294 if !ok { 295 collHashRwBuilder = newCollHashRwBuilder(coll) 296 nsPubRwBuilder.collHashRwBuilder[coll] = collHashRwBuilder 297 } 298 return collHashRwBuilder 299 } 300 301 func (b *RWSetBuilder) getOrCreateCollPvtRwBuilder(ns string, coll string) *collPvtRwBuilder { 302 nsPvtRwBuilder := b.getOrCreateNsPvtRwBuilder(ns) 303 collPvtRwBuilder, ok := nsPvtRwBuilder.collPvtRwBuilders[coll] 304 if !ok { 305 collPvtRwBuilder = newCollPvtRwBuilder(coll) 306 nsPvtRwBuilder.collPvtRwBuilders[coll] = collPvtRwBuilder 307 } 308 return collPvtRwBuilder 309 } 310 311 func newNsPubRwBuilder(namespace string) *nsPubRwBuilder { 312 return &nsPubRwBuilder{ 313 namespace, 314 make(map[string]*kvrwset.KVRead), 315 make(map[string]*kvrwset.KVWrite), 316 make(map[string]*kvrwset.KVMetadataWrite), 317 make(map[rangeQueryKey]*kvrwset.RangeQueryInfo), 318 nil, 319 make(map[string]*collHashRwBuilder), 320 } 321 } 322 323 func newNsPvtRwBuilder(namespace string) *nsPvtRwBuilder { 324 return &nsPvtRwBuilder{namespace, make(map[string]*collPvtRwBuilder)} 325 } 326 327 func newCollHashRwBuilder(collName string) *collHashRwBuilder { 328 return &collHashRwBuilder{ 329 collName, 330 make(map[string]*kvrwset.KVReadHash), 331 make(map[string]*kvrwset.KVWriteHash), 332 make(map[string]*kvrwset.KVMetadataWriteHash), 333 nil, 334 } 335 } 336 337 func newCollPvtRwBuilder(collName string) *collPvtRwBuilder { 338 return &collPvtRwBuilder{ 339 collName, 340 make(map[string]*kvrwset.KVWrite), 341 make(map[string]*kvrwset.KVMetadataWrite), 342 } 343 } 344 345 func mapToMetadataWrite(key string, m map[string][]byte) *kvrwset.KVMetadataWrite { 346 proto := &kvrwset.KVMetadataWrite{Key: key} 347 names := util.GetSortedKeys(m) 348 for _, name := range names { 349 proto.Entries = append(proto.Entries, 350 &kvrwset.KVMetadataEntry{Name: name, Value: m[name]}, 351 ) 352 } 353 return proto 354 } 355 356 func mapToMetadataWriteHash(key string, m map[string][]byte) *kvrwset.KVMetadataWriteHash { 357 proto := &kvrwset.KVMetadataWriteHash{KeyHash: util.ComputeStringHash(key)} 358 names := util.GetSortedKeys(m) 359 for _, name := range names { 360 proto.Entries = append(proto.Entries, 361 &kvrwset.KVMetadataEntry{Name: name, Value: m[name]}, 362 ) 363 } 364 return proto 365 }