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  }