github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/gossip/privdata/pvtdataprovider.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package privdata 8 9 import ( 10 "bytes" 11 "encoding/hex" 12 "fmt" 13 "time" 14 15 "github.com/golang/protobuf/proto" 16 vsccErrors "github.com/hechain20/hechain/common/errors" 17 "github.com/hechain20/hechain/common/metrics" 18 commonutil "github.com/hechain20/hechain/common/util" 19 pvtdatasc "github.com/hechain20/hechain/core/common/privdata" 20 "github.com/hechain20/hechain/core/ledger" 21 "github.com/hechain20/hechain/core/transientstore" 22 pvtdatacommon "github.com/hechain20/hechain/gossip/privdata/common" 23 "github.com/hechain20/hechain/gossip/util" 24 "github.com/hechain20/hechain/protoutil" 25 "github.com/hyperledger/fabric-protos-go/ledger/rwset" 26 "github.com/hyperledger/fabric-protos-go/msp" 27 "github.com/hyperledger/fabric-protos-go/peer" 28 ) 29 30 type sleeper struct { 31 sleep func(time.Duration) 32 } 33 34 func (s sleeper) Sleep(d time.Duration) { 35 if s.sleep == nil { 36 time.Sleep(d) 37 return 38 } 39 s.sleep(d) 40 } 41 42 type RetrievedPvtdata struct { 43 blockPvtdata *ledger.BlockPvtdata 44 pvtdataRetrievalInfo *pvtdataRetrievalInfo 45 transientStore *transientstore.Store 46 logger util.Logger 47 purgeDurationHistogram metrics.Histogram 48 blockNum uint64 49 transientBlockRetention uint64 50 } 51 52 // GetBlockPvtdata returns the BlockPvtdata 53 func (r *RetrievedPvtdata) GetBlockPvtdata() *ledger.BlockPvtdata { 54 return r.blockPvtdata 55 } 56 57 // Purge purges private data for transactions in the block from the transient store. 58 // Transactions older than the retention period are considered orphaned and also purged. 59 func (r *RetrievedPvtdata) Purge() { 60 purgeStart := time.Now() 61 62 if len(r.blockPvtdata.PvtData) > 0 { 63 // Finally, purge all transactions in block - valid or not valid. 64 if err := r.transientStore.PurgeByTxids(r.pvtdataRetrievalInfo.txns); err != nil { 65 r.logger.Errorf("Purging transactions %v failed: %s", r.pvtdataRetrievalInfo.txns, err) 66 } 67 } 68 69 blockNum := r.blockNum 70 if blockNum%r.transientBlockRetention == 0 && blockNum > r.transientBlockRetention { 71 err := r.transientStore.PurgeBelowHeight(blockNum - r.transientBlockRetention) 72 if err != nil { 73 r.logger.Errorf("Failed purging data from transient store at block [%d]: %s", blockNum, err) 74 } 75 } 76 77 r.purgeDurationHistogram.Observe(time.Since(purgeStart).Seconds()) 78 } 79 80 type eligibilityComputer struct { 81 logger util.Logger 82 storePvtdataOfInvalidTx bool 83 channelID string 84 selfSignedData protoutil.SignedData 85 idDeserializerFactory IdentityDeserializerFactory 86 } 87 88 // computeEligibility computes eligibility of private data and 89 // groups all private data as either eligibleMissing or ineligibleMissing prior to fetching 90 func (ec *eligibilityComputer) computeEligibility(mspID string, pvtdataToRetrieve []*ledger.TxPvtdataInfo) (*pvtdataRetrievalInfo, error) { 91 sources := make(map[rwSetKey][]*peer.Endorsement) 92 eligibleMissingKeys := make(rwsetKeys) 93 ineligibleMissingKeys := make(rwsetKeys) 94 95 var txList []string 96 for _, txPvtdata := range pvtdataToRetrieve { 97 txID := txPvtdata.TxID 98 seqInBlock := txPvtdata.SeqInBlock 99 invalid := txPvtdata.Invalid 100 txList = append(txList, txID) 101 if invalid && !ec.storePvtdataOfInvalidTx { 102 ec.logger.Debugf("Skipping Tx [%s] at sequence [%d] because it's invalid.", txID, seqInBlock) 103 continue 104 } 105 deserializer := ec.idDeserializerFactory.GetIdentityDeserializer(ec.channelID) 106 for _, colInfo := range txPvtdata.CollectionPvtdataInfo { 107 ns := colInfo.Namespace 108 col := colInfo.Collection 109 hash := colInfo.ExpectedHash 110 endorsers := colInfo.Endorsers 111 colConfig := colInfo.CollectionConfig 112 113 policy, err := pvtdatasc.NewSimpleCollection(colConfig, deserializer) 114 if err != nil { 115 ec.logger.Errorf("Failed to retrieve collection access policy for chaincode [%s], collection name [%s] for txID [%s]: %s.", 116 ns, col, txID, err) 117 return nil, &vsccErrors.VSCCExecutionFailureError{Err: err} 118 } 119 120 key := rwSetKey{ 121 txID: txID, 122 seqInBlock: seqInBlock, 123 hash: hex.EncodeToString(hash), 124 namespace: ns, 125 collection: col, 126 } 127 128 // First check if mspID is found in the MemberOrgs before falling back to AccessFilter policy evaluation 129 memberOrgs := policy.MemberOrgs() 130 if _, ok := memberOrgs[mspID]; !ok && 131 !policy.AccessFilter()(ec.selfSignedData) { 132 ec.logger.Debugf("Peer is not eligible for collection: chaincode [%s], "+ 133 "collection name [%s], txID [%s] the policy is [%#v]. Skipping.", 134 ns, col, txID, policy) 135 ineligibleMissingKeys[key] = rwsetInfo{} 136 continue 137 } 138 139 // treat all eligible keys as missing 140 eligibleMissingKeys[key] = rwsetInfo{ 141 invalid: invalid, 142 } 143 sources[key] = endorsersFromEligibleOrgs(ns, col, endorsers, memberOrgs) 144 } 145 } 146 147 return &pvtdataRetrievalInfo{ 148 sources: sources, 149 txns: txList, 150 remainingEligibleMissingKeys: eligibleMissingKeys, 151 ineligibleMissingKeys: ineligibleMissingKeys, 152 }, nil 153 } 154 155 type PvtdataProvider struct { 156 mspID string 157 selfSignedData protoutil.SignedData 158 logger util.Logger 159 listMissingPrivateDataDurationHistogram metrics.Histogram 160 fetchDurationHistogram metrics.Histogram 161 purgeDurationHistogram metrics.Histogram 162 transientStore *transientstore.Store 163 pullRetryThreshold time.Duration 164 prefetchedPvtdata util.PvtDataCollections 165 transientBlockRetention uint64 166 channelID string 167 blockNum uint64 168 storePvtdataOfInvalidTx bool 169 skipPullingInvalidTransactions bool 170 idDeserializerFactory IdentityDeserializerFactory 171 fetcher Fetcher 172 173 sleeper sleeper 174 } 175 176 // RetrievePvtdata is passed a list of private data items from a block, 177 // it determines which private data items this peer is eligible for, and then 178 // retrieves the private data from local cache, local transient store, or a remote peer. 179 func (pdp *PvtdataProvider) RetrievePvtdata(pvtdataToRetrieve []*ledger.TxPvtdataInfo) (*RetrievedPvtdata, error) { 180 retrievedPvtdata := &RetrievedPvtdata{ 181 transientStore: pdp.transientStore, 182 logger: pdp.logger, 183 purgeDurationHistogram: pdp.purgeDurationHistogram, 184 blockNum: pdp.blockNum, 185 transientBlockRetention: pdp.transientBlockRetention, 186 } 187 188 listMissingStart := time.Now() 189 eligibilityComputer := &eligibilityComputer{ 190 logger: pdp.logger, 191 storePvtdataOfInvalidTx: pdp.storePvtdataOfInvalidTx, 192 channelID: pdp.channelID, 193 selfSignedData: pdp.selfSignedData, 194 idDeserializerFactory: pdp.idDeserializerFactory, 195 } 196 197 pvtdataRetrievalInfo, err := eligibilityComputer.computeEligibility(pdp.mspID, pvtdataToRetrieve) 198 if err != nil { 199 return nil, err 200 } 201 pdp.listMissingPrivateDataDurationHistogram.Observe(time.Since(listMissingStart).Seconds()) 202 203 pvtdata := make(rwsetByKeys) 204 205 // If there is no private data to retrieve for the block, skip all population attempts and return 206 if len(pvtdataRetrievalInfo.remainingEligibleMissingKeys) == 0 { 207 pdp.logger.Debugf("No eligible collection private write sets to fetch for block [%d]", pdp.blockNum) 208 retrievedPvtdata.pvtdataRetrievalInfo = pvtdataRetrievalInfo 209 retrievedPvtdata.blockPvtdata = pdp.prepareBlockPvtdata(pvtdata, pvtdataRetrievalInfo) 210 return retrievedPvtdata, nil 211 } 212 213 fetchStats := &fetchStats{} 214 215 totalEligibleMissingKeysToRetrieve := len(pvtdataRetrievalInfo.remainingEligibleMissingKeys) 216 217 // POPULATE FROM CACHE 218 pdp.populateFromCache(pvtdata, pvtdataRetrievalInfo, pvtdataToRetrieve) 219 fetchStats.fromLocalCache = totalEligibleMissingKeysToRetrieve - len(pvtdataRetrievalInfo.remainingEligibleMissingKeys) 220 221 if len(pvtdataRetrievalInfo.remainingEligibleMissingKeys) == 0 { 222 pdp.logger.Infof("Successfully fetched all %d eligible collection private write sets for block [%d] %s", totalEligibleMissingKeysToRetrieve, pdp.blockNum, fetchStats) 223 retrievedPvtdata.pvtdataRetrievalInfo = pvtdataRetrievalInfo 224 retrievedPvtdata.blockPvtdata = pdp.prepareBlockPvtdata(pvtdata, pvtdataRetrievalInfo) 225 return retrievedPvtdata, nil 226 } 227 228 // POPULATE FROM TRANSIENT STORE 229 numRemainingToFetch := len(pvtdataRetrievalInfo.remainingEligibleMissingKeys) 230 pdp.populateFromTransientStore(pvtdata, pvtdataRetrievalInfo) 231 fetchStats.fromTransientStore = numRemainingToFetch - len(pvtdataRetrievalInfo.remainingEligibleMissingKeys) 232 233 if len(pvtdataRetrievalInfo.remainingEligibleMissingKeys) == 0 { 234 pdp.logger.Infof("Successfully fetched all %d eligible collection private write sets for block [%d] %s", totalEligibleMissingKeysToRetrieve, pdp.blockNum, fetchStats) 235 retrievedPvtdata.pvtdataRetrievalInfo = pvtdataRetrievalInfo 236 retrievedPvtdata.blockPvtdata = pdp.prepareBlockPvtdata(pvtdata, pvtdataRetrievalInfo) 237 return retrievedPvtdata, nil 238 } 239 240 // POPULATE FROM REMOTE PEERS 241 numRemainingToFetch = len(pvtdataRetrievalInfo.remainingEligibleMissingKeys) 242 retryThresh := pdp.pullRetryThreshold 243 pdp.logger.Debugf("Could not find all collection private write sets in local peer transient store for block [%d]", pdp.blockNum) 244 pdp.logger.Debugf("Fetching %d collection private write sets from remote peers for a maximum duration of %s", len(pvtdataRetrievalInfo.remainingEligibleMissingKeys), retryThresh) 245 startPull := time.Now() 246 for len(pvtdataRetrievalInfo.remainingEligibleMissingKeys) > 0 && time.Since(startPull) < retryThresh { 247 if needToRetry := pdp.populateFromRemotePeers(pvtdata, pvtdataRetrievalInfo); !needToRetry { 248 break 249 } 250 // If there are still missing keys, sleep before retry 251 pdp.sleeper.Sleep(pullRetrySleepInterval) 252 } 253 elapsedPull := int64(time.Since(startPull) / time.Millisecond) // duration in ms 254 pdp.fetchDurationHistogram.Observe(time.Since(startPull).Seconds()) 255 256 fetchStats.fromRemotePeer = numRemainingToFetch - len(pvtdataRetrievalInfo.remainingEligibleMissingKeys) 257 258 if len(pvtdataRetrievalInfo.remainingEligibleMissingKeys) == 0 { 259 pdp.logger.Debugf("Fetched all missing collection private write sets from remote peers for block [%d] (%dms)", pdp.blockNum, elapsedPull) 260 pdp.logger.Infof("Successfully fetched all %d eligible collection private write sets for block [%d] %s", totalEligibleMissingKeysToRetrieve, pdp.blockNum, fetchStats) 261 } else { 262 pdp.logger.Warningf("Could not fetch all %d eligible collection private write sets for block [%d] %s. Will commit block with missing private write sets:[%v]", 263 totalEligibleMissingKeysToRetrieve, pdp.blockNum, fetchStats, pvtdataRetrievalInfo.remainingEligibleMissingKeys) 264 } 265 266 retrievedPvtdata.pvtdataRetrievalInfo = pvtdataRetrievalInfo 267 retrievedPvtdata.blockPvtdata = pdp.prepareBlockPvtdata(pvtdata, pvtdataRetrievalInfo) 268 return retrievedPvtdata, nil 269 } 270 271 // populateFromCache populates pvtdata with data fetched from cache and updates 272 // pvtdataRetrievalInfo by removing missing data that was fetched from cache 273 func (pdp *PvtdataProvider) populateFromCache(pvtdata rwsetByKeys, pvtdataRetrievalInfo *pvtdataRetrievalInfo, pvtdataToRetrieve []*ledger.TxPvtdataInfo) { 274 pdp.logger.Debugf("Attempting to retrieve %d private write sets from cache.", len(pvtdataRetrievalInfo.remainingEligibleMissingKeys)) 275 276 for _, txPvtdata := range pdp.prefetchedPvtdata { 277 txID := getTxIDBySeqInBlock(txPvtdata.SeqInBlock, pvtdataToRetrieve) 278 // if can't match txID from query, then the data was never requested so skip the entire tx 279 if txID == "" { 280 pdp.logger.Warningf("Found extra data in prefetched at sequence [%d]. Skipping.", txPvtdata.SeqInBlock) 281 continue 282 } 283 for _, ns := range txPvtdata.WriteSet.NsPvtRwset { 284 for _, col := range ns.CollectionPvtRwset { 285 key := rwSetKey{ 286 txID: txID, 287 seqInBlock: txPvtdata.SeqInBlock, 288 collection: col.CollectionName, 289 namespace: ns.Namespace, 290 hash: hex.EncodeToString(commonutil.ComputeSHA256(col.Rwset)), 291 } 292 // skip if key not originally missing 293 if _, missing := pvtdataRetrievalInfo.remainingEligibleMissingKeys[key]; !missing { 294 pdp.logger.Warningf("Found extra data in prefetched:[%v]. Skipping.", key) 295 continue 296 } 297 // populate the pvtdata with the RW set from the cache 298 pvtdata[key] = col.Rwset 299 // remove key from missing 300 delete(pvtdataRetrievalInfo.remainingEligibleMissingKeys, key) 301 } // iterate over collections in the namespace 302 } // iterate over the namespaces in the WSet 303 } // iterate over cached private data in the block 304 } 305 306 // populateFromTransientStore populates pvtdata with data fetched from transient store 307 // and updates pvtdataRetrievalInfo by removing missing data that was fetched from transient store 308 func (pdp *PvtdataProvider) populateFromTransientStore(pvtdata rwsetByKeys, pvtdataRetrievalInfo *pvtdataRetrievalInfo) { 309 pdp.logger.Debugf("Attempting to retrieve %d private write sets from transient store.", len(pvtdataRetrievalInfo.remainingEligibleMissingKeys)) 310 311 // Put into pvtdata RW sets that are missing and found in the transient store 312 for k := range pvtdataRetrievalInfo.remainingEligibleMissingKeys { 313 filter := ledger.NewPvtNsCollFilter() 314 filter.Add(k.namespace, k.collection) 315 iterator, err := pdp.transientStore.GetTxPvtRWSetByTxid(k.txID, filter) 316 if err != nil { 317 pdp.logger.Warningf("Failed fetching private data from transient store: Failed obtaining iterator from transient store: %s", err) 318 return 319 } 320 defer iterator.Close() 321 for { 322 res, err := iterator.Next() 323 if err != nil { 324 pdp.logger.Warningf("Failed fetching private data from transient store: Failed iterating over transient store data: %s", err) 325 return 326 } 327 if res == nil { 328 // End of iteration 329 break 330 } 331 if res.PvtSimulationResultsWithConfig == nil { 332 pdp.logger.Warningf("Resultset's PvtSimulationResultsWithConfig for txID [%s] is nil. Skipping.", k.txID) 333 continue 334 } 335 simRes := res.PvtSimulationResultsWithConfig 336 // simRes.PvtRwset will be nil if the transient store contains an entry for the txid but the entry does not contain the data for the collection 337 if simRes.PvtRwset == nil { 338 pdp.logger.Debugf("The PvtRwset of PvtSimulationResultsWithConfig for txID [%s] is nil. Skipping.", k.txID) 339 continue 340 } 341 for _, ns := range simRes.PvtRwset.NsPvtRwset { 342 for _, col := range ns.CollectionPvtRwset { 343 key := rwSetKey{ 344 txID: k.txID, 345 seqInBlock: k.seqInBlock, 346 collection: col.CollectionName, 347 namespace: ns.Namespace, 348 hash: hex.EncodeToString(commonutil.ComputeSHA256(col.Rwset)), 349 } 350 // skip if not missing 351 if _, missing := pvtdataRetrievalInfo.remainingEligibleMissingKeys[key]; !missing { 352 continue 353 } 354 // populate the pvtdata with the RW set from the transient store 355 pdp.logger.Debugf("Found private data for key %v in transient store", key) 356 pvtdata[key] = col.Rwset 357 // remove key from missing 358 delete(pvtdataRetrievalInfo.remainingEligibleMissingKeys, key) 359 } // iterating over all collections 360 } // iterating over all namespaces 361 } // iterating over the TxPvtRWSet results 362 } 363 } 364 365 // populateFromRemotePeers populates pvtdata with data fetched from remote peers and updates 366 // pvtdataRetrievalInfo by removing missing data that was fetched from remote peers 367 func (pdp *PvtdataProvider) populateFromRemotePeers(pvtdata rwsetByKeys, pvtdataRetrievalInfo *pvtdataRetrievalInfo) bool { 368 pdp.logger.Debugf("Attempting to retrieve %d private write sets from remote peers.", len(pvtdataRetrievalInfo.remainingEligibleMissingKeys)) 369 370 dig2src := make(map[pvtdatacommon.DigKey][]*peer.Endorsement) 371 var skipped int 372 for k, v := range pvtdataRetrievalInfo.remainingEligibleMissingKeys { 373 if v.invalid && pdp.skipPullingInvalidTransactions { 374 pdp.logger.Debugf("Skipping invalid key [%v] because peer is configured to skip pulling rwsets of invalid transactions.", k) 375 skipped++ 376 continue 377 } 378 pdp.logger.Debugf("Fetching [%v] from remote peers", k) 379 dig := pvtdatacommon.DigKey{ 380 TxId: k.txID, 381 SeqInBlock: k.seqInBlock, 382 Collection: k.collection, 383 Namespace: k.namespace, 384 BlockSeq: pdp.blockNum, 385 } 386 dig2src[dig] = pvtdataRetrievalInfo.sources[k] 387 } 388 389 if len(dig2src) == 0 { 390 return false 391 } 392 393 fetchedData, err := pdp.fetcher.fetch(dig2src) 394 if err != nil { 395 pdp.logger.Warningf("Failed fetching private data from remote peers for dig2src:[%v], err: %s", dig2src, err) 396 return true 397 } 398 399 // Iterate over data fetched from remote peers 400 for _, element := range fetchedData.AvailableElements { 401 dig := element.Digest 402 for _, rws := range element.Payload { 403 key := rwSetKey{ 404 txID: dig.TxId, 405 namespace: dig.Namespace, 406 collection: dig.Collection, 407 seqInBlock: dig.SeqInBlock, 408 hash: hex.EncodeToString(commonutil.ComputeSHA256(rws)), 409 } 410 // skip if not missing 411 if _, missing := pvtdataRetrievalInfo.remainingEligibleMissingKeys[key]; !missing { 412 // key isn't missing and was never fetched earlier, log that it wasn't originally requested 413 if _, exists := pvtdata[key]; !exists { 414 pdp.logger.Debugf("Ignoring [%v] because it was never requested.", key) 415 } 416 continue 417 } 418 // populate the pvtdata with the RW set from the remote peer 419 pvtdata[key] = rws 420 // remove key from missing 421 delete(pvtdataRetrievalInfo.remainingEligibleMissingKeys, key) 422 pdp.logger.Debugf("Fetched [%v]", key) 423 } 424 } 425 // Iterate over purged data 426 for _, dig := range fetchedData.PurgedElements { 427 // delete purged key from missing keys 428 for missingPvtRWKey := range pvtdataRetrievalInfo.remainingEligibleMissingKeys { 429 if missingPvtRWKey.namespace == dig.Namespace && 430 missingPvtRWKey.collection == dig.Collection && 431 missingPvtRWKey.seqInBlock == dig.SeqInBlock && 432 missingPvtRWKey.txID == dig.TxId { 433 delete(pvtdataRetrievalInfo.remainingEligibleMissingKeys, missingPvtRWKey) 434 pdp.logger.Warningf("Missing key because was purged or will soon be purged, "+ 435 "continue block commit without [%+v] in private rwset", missingPvtRWKey) 436 } 437 } 438 } 439 440 return len(pvtdataRetrievalInfo.remainingEligibleMissingKeys) > skipped 441 } 442 443 // prepareBlockPvtdata consolidates the fetched private data as well as ineligible and eligible 444 // missing private data into a ledger.BlockPvtdata for the PvtdataProvider to return to the consumer 445 func (pdp *PvtdataProvider) prepareBlockPvtdata(pvtdata rwsetByKeys, pvtdataRetrievalInfo *pvtdataRetrievalInfo) *ledger.BlockPvtdata { 446 blockPvtdata := &ledger.BlockPvtdata{ 447 PvtData: make(ledger.TxPvtDataMap), 448 MissingPvtData: make(ledger.TxMissingPvtData), 449 } 450 451 for seqInBlock, nsRWS := range pvtdata.bySeqsInBlock() { 452 // add all found pvtdata to blockPvtDataPvtdata for seqInBlock 453 blockPvtdata.PvtData[seqInBlock] = &ledger.TxPvtData{ 454 SeqInBlock: seqInBlock, 455 WriteSet: nsRWS.toRWSet(), 456 } 457 } 458 459 for key := range pvtdataRetrievalInfo.remainingEligibleMissingKeys { 460 blockPvtdata.MissingPvtData.Add(key.seqInBlock, key.namespace, key.collection, true) 461 } 462 463 for key := range pvtdataRetrievalInfo.ineligibleMissingKeys { 464 blockPvtdata.MissingPvtData.Add(key.seqInBlock, key.namespace, key.collection, false) 465 } 466 467 return blockPvtdata 468 } 469 470 type pvtdataRetrievalInfo struct { 471 sources map[rwSetKey][]*peer.Endorsement 472 txns []string 473 remainingEligibleMissingKeys rwsetKeys 474 ineligibleMissingKeys rwsetKeys 475 } 476 477 // rwset types 478 479 type readWriteSets []*readWriteSet 480 481 func (s readWriteSets) toRWSet() *rwset.TxPvtReadWriteSet { 482 namespaces := make(map[string]*rwset.NsPvtReadWriteSet) 483 dataModel := rwset.TxReadWriteSet_KV 484 for _, rws := range s { 485 if _, exists := namespaces[rws.namespace]; !exists { 486 namespaces[rws.namespace] = &rwset.NsPvtReadWriteSet{ 487 Namespace: rws.namespace, 488 } 489 } 490 col := &rwset.CollectionPvtReadWriteSet{ 491 CollectionName: rws.collection, 492 Rwset: rws.rws, 493 } 494 namespaces[rws.namespace].CollectionPvtRwset = append(namespaces[rws.namespace].CollectionPvtRwset, col) 495 } 496 497 var namespaceSlice []*rwset.NsPvtReadWriteSet 498 for _, nsRWset := range namespaces { 499 namespaceSlice = append(namespaceSlice, nsRWset) 500 } 501 502 return &rwset.TxPvtReadWriteSet{ 503 DataModel: dataModel, 504 NsPvtRwset: namespaceSlice, 505 } 506 } 507 508 type readWriteSet struct { 509 rwSetKey 510 rws []byte 511 } 512 513 type rwsetByKeys map[rwSetKey][]byte 514 515 func (s rwsetByKeys) bySeqsInBlock() map[uint64]readWriteSets { 516 res := make(map[uint64]readWriteSets) 517 for k, rws := range s { 518 res[k.seqInBlock] = append(res[k.seqInBlock], &readWriteSet{ 519 rws: rws, 520 rwSetKey: k, 521 }) 522 } 523 return res 524 } 525 526 type rwsetInfo struct { 527 invalid bool 528 } 529 530 type rwsetKeys map[rwSetKey]rwsetInfo 531 532 // String returns a string representation of the rwsetKeys 533 func (s rwsetKeys) String() string { 534 var buffer bytes.Buffer 535 for k := range s { 536 buffer.WriteString(fmt.Sprintf("%s\n", k.String())) 537 } 538 return buffer.String() 539 } 540 541 type rwSetKey struct { 542 txID string 543 seqInBlock uint64 544 namespace string 545 collection string 546 hash string 547 } 548 549 // String returns a string representation of the rwSetKey 550 func (k *rwSetKey) String() string { 551 return fmt.Sprintf("txID: %s, seq: %d, namespace: %s, collection: %s, hash: %s", k.txID, k.seqInBlock, k.namespace, k.collection, k.hash) 552 } 553 554 func getTxIDBySeqInBlock(seqInBlock uint64, pvtdataToRetrieve []*ledger.TxPvtdataInfo) string { 555 for _, txPvtdataItem := range pvtdataToRetrieve { 556 if txPvtdataItem.SeqInBlock == seqInBlock { 557 return txPvtdataItem.TxID 558 } 559 } 560 561 return "" 562 } 563 564 func endorsersFromEligibleOrgs(ns string, col string, endorsers []*peer.Endorsement, orgs map[string]struct{}) []*peer.Endorsement { 565 var res []*peer.Endorsement 566 for _, e := range endorsers { 567 sID := &msp.SerializedIdentity{} 568 err := proto.Unmarshal(e.Endorser, sID) 569 if err != nil { 570 logger.Warning("Failed unmarshalling endorser:", err) 571 continue 572 } 573 if _, ok := orgs[sID.Mspid]; !ok { 574 logger.Debug(sID.Mspid, "isn't among the collection's orgs:", orgs, "for namespace", ns, ",collection", col) 575 continue 576 } 577 res = append(res, e) 578 } 579 return res 580 } 581 582 type fetchStats struct { 583 fromLocalCache, fromTransientStore, fromRemotePeer int 584 } 585 586 func (stats fetchStats) String() string { 587 return fmt.Sprintf("(%d from local cache, %d from transient store, %d from other peers)", stats.fromLocalCache, stats.fromTransientStore, stats.fromRemotePeer) 588 }