github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/gossip/privdata/dataretriever.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 "github.com/hechain20/hechain/core/committer" 11 "github.com/hechain20/hechain/core/ledger" 12 "github.com/hechain20/hechain/core/transientstore" 13 "github.com/hechain20/hechain/gossip/privdata/common" 14 "github.com/hechain20/hechain/gossip/util" 15 protosgossip "github.com/hyperledger/fabric-protos-go/gossip" 16 "github.com/hyperledger/fabric-protos-go/ledger/rwset" 17 "github.com/pkg/errors" 18 ) 19 20 //go:generate mockery -dir . -name RWSetScanner -case underscore -output mocks/ 21 22 // RWSetScanner is the local interface used to generate mocks for foreign interface. 23 type RWSetScanner interface { 24 transientstore.RWSetScanner 25 } 26 27 // StorageDataRetriever defines an API to retrieve private data from the storage. 28 type StorageDataRetriever interface { 29 // CollectionRWSet retrieves for give digest relevant private data if 30 // available otherwise returns nil, bool which is true if data fetched from ledger and false if was fetched from transient store, and an error 31 CollectionRWSet(dig []*protosgossip.PvtDataDigest, blockNum uint64) (Dig2PvtRWSetWithConfig, bool, error) 32 } 33 34 type dataRetriever struct { 35 logger util.Logger 36 store *transientstore.Store 37 committer committer.Committer 38 } 39 40 // NewDataRetriever constructing function for implementation of the 41 // StorageDataRetriever interface 42 func NewDataRetriever(channelID string, store *transientstore.Store, committer committer.Committer) StorageDataRetriever { 43 return &dataRetriever{ 44 logger: logger.With("channel", channelID), 45 store: store, 46 committer: committer, 47 } 48 } 49 50 // CollectionRWSet retrieves for give digest relevant private data if 51 // available otherwise returns nil, bool which is true if data fetched from ledger and false if was fetched from transient store, and an error 52 func (dr *dataRetriever) CollectionRWSet(digests []*protosgossip.PvtDataDigest, blockNum uint64) (Dig2PvtRWSetWithConfig, bool, error) { 53 height, err := dr.committer.LedgerHeight() 54 if err != nil { 55 // if there is an error getting info from the ledger, we need to try to read from transient store 56 return nil, false, errors.Wrap(err, "wasn't able to read ledger height") 57 } 58 59 // The condition may be true for either commit or reconciliation case when another peer sends a request to retrieve private data. 60 // For the commit case, get the private data from the transient store because the block has not been committed. 61 // For the reconciliation case, this peer is further behind the ledger height than the peer that requested for the private data. 62 // In this case, the ledger does not have the requested private data. Also, the data cannot be queried in the transient store, 63 // as the txID in the digest will be missing. 64 if height <= blockNum { // Check whenever current ledger height is equal or below block sequence num. 65 dr.logger.Debug("Current ledger height ", height, "is below requested block sequence number", 66 blockNum, "retrieving private data from transient store") 67 68 results := make(Dig2PvtRWSetWithConfig) 69 for _, dig := range digests { 70 // skip retrieving from transient store if txid is not available 71 if dig.TxId == "" { 72 dr.logger.Infof("Skip querying transient store for chaincode %s, collection name %s, block number %d, sequence in block %d, "+ 73 "as the txid is missing, perhaps because it is a reconciliation request", 74 dig.Namespace, dig.Collection, blockNum, dig.SeqInBlock) 75 76 continue 77 } 78 79 filter := map[string]ledger.PvtCollFilter{ 80 dig.Namespace: map[string]bool{ 81 dig.Collection: true, 82 }, 83 } 84 pvtRWSet, err := dr.fromTransientStore(dig, filter) 85 if err != nil { 86 dr.logger.Errorf("couldn't read from transient store private read-write set, "+ 87 "digest %+v, because of %s", dig, err) 88 continue 89 } 90 results[common.DigKey{ 91 Namespace: dig.Namespace, 92 Collection: dig.Collection, 93 TxId: dig.TxId, 94 BlockSeq: dig.BlockSeq, 95 SeqInBlock: dig.SeqInBlock, 96 }] = pvtRWSet 97 } 98 99 return results, false, nil 100 } 101 // Since ledger height is above block sequence number private data is might be available in the ledger 102 results, err := dr.fromLedger(digests, blockNum) 103 return results, true, err 104 } 105 106 func (dr *dataRetriever) fromLedger(digests []*protosgossip.PvtDataDigest, blockNum uint64) (Dig2PvtRWSetWithConfig, error) { 107 filter := make(map[string]ledger.PvtCollFilter) 108 for _, dig := range digests { 109 if _, ok := filter[dig.Namespace]; !ok { 110 filter[dig.Namespace] = make(ledger.PvtCollFilter) 111 } 112 filter[dig.Namespace][dig.Collection] = true 113 } 114 115 pvtData, err := dr.committer.GetPvtDataByNum(blockNum, filter) 116 if err != nil { 117 return nil, errors.Errorf("wasn't able to obtain private data, block sequence number %d, due to %s", blockNum, err) 118 } 119 120 results := make(Dig2PvtRWSetWithConfig) 121 for _, dig := range digests { 122 dig := dig 123 pvtRWSetWithConfig := &util.PrivateRWSetWithConfig{} 124 for _, data := range pvtData { 125 if data.WriteSet == nil { 126 dr.logger.Warning("Received nil write set for collection tx in block", data.SeqInBlock, "block number", blockNum) 127 continue 128 } 129 130 // private data doesn't hold rwsets for namespace and collection or 131 // belongs to different transaction 132 if !data.Has(dig.Namespace, dig.Collection) || data.SeqInBlock != dig.SeqInBlock { 133 continue 134 } 135 136 pvtRWSet := dr.extractPvtRWsets(data.WriteSet.NsPvtRwset, dig.Namespace, dig.Collection) 137 pvtRWSetWithConfig.RWSet = append(pvtRWSetWithConfig.RWSet, pvtRWSet...) 138 } 139 140 confHistoryRetriever, err := dr.committer.GetConfigHistoryRetriever() 141 if err != nil { 142 return nil, errors.Errorf("cannot obtain configuration history retriever, for collection <%s>"+ 143 " txID <%s> block sequence number <%d> due to <%s>", dig.Collection, dig.TxId, dig.BlockSeq, err) 144 } 145 146 configInfo, err := confHistoryRetriever.MostRecentCollectionConfigBelow(dig.BlockSeq, dig.Namespace) 147 if err != nil { 148 return nil, errors.Errorf("cannot find recent collection config update below block sequence = %d,"+ 149 " collection name = <%s> for chaincode <%s>", dig.BlockSeq, dig.Collection, dig.Namespace) 150 } 151 152 if configInfo == nil { 153 return nil, errors.Errorf("no collection config update below block sequence = <%d>"+ 154 " collection name = <%s> for chaincode <%s> is available ", dig.BlockSeq, dig.Collection, dig.Namespace) 155 } 156 configs := extractCollectionConfig(configInfo.CollectionConfig, dig.Collection) 157 if configs == nil { 158 return nil, errors.Errorf("no collection config was found for collection <%s>"+ 159 " namespace <%s> txID <%s>", dig.Collection, dig.Namespace, dig.TxId) 160 } 161 pvtRWSetWithConfig.CollectionConfig = configs 162 results[common.DigKey{ 163 Namespace: dig.Namespace, 164 Collection: dig.Collection, 165 TxId: dig.TxId, 166 BlockSeq: dig.BlockSeq, 167 SeqInBlock: dig.SeqInBlock, 168 }] = pvtRWSetWithConfig 169 } 170 171 return results, nil 172 } 173 174 func (dr *dataRetriever) fromTransientStore(dig *protosgossip.PvtDataDigest, filter map[string]ledger.PvtCollFilter) (*util.PrivateRWSetWithConfig, error) { 175 results := &util.PrivateRWSetWithConfig{} 176 it, err := dr.store.GetTxPvtRWSetByTxid(dig.TxId, filter) 177 if err != nil { 178 return nil, errors.Errorf("was not able to retrieve private data from transient store, namespace <%s>"+ 179 ", collection name %s, txID <%s>, due to <%s>", dig.Namespace, dig.Collection, dig.TxId, err) 180 } 181 defer it.Close() 182 183 maxEndorsedAt := uint64(0) 184 for { 185 res, err := it.Next() 186 if err != nil { 187 return nil, errors.Errorf("error getting next element out of private data iterator, namespace <%s>"+ 188 ", collection name <%s>, txID <%s>, due to <%s>", dig.Namespace, dig.Collection, dig.TxId, err) 189 } 190 if res == nil { 191 return results, nil 192 } 193 rws := res.PvtSimulationResultsWithConfig 194 if rws == nil { 195 dr.logger.Debug("Skipping nil PvtSimulationResultsWithConfig received at block height", res.ReceivedAtBlockHeight) 196 continue 197 } 198 txPvtRWSet := rws.PvtRwset 199 if txPvtRWSet == nil { 200 dr.logger.Debug("Skipping empty PvtRwset of PvtSimulationResultsWithConfig received at block height", res.ReceivedAtBlockHeight) 201 continue 202 } 203 204 colConfigs, found := rws.CollectionConfigs[dig.Namespace] 205 if !found { 206 dr.logger.Error("No collection config was found for chaincode", dig.Namespace, "collection name", 207 dig.Collection, "txID", dig.TxId) 208 continue 209 } 210 211 configs := extractCollectionConfig(colConfigs, dig.Collection) 212 if configs == nil { 213 dr.logger.Error("No collection config was found for collection", dig.Collection, 214 "namespace", dig.Namespace, "txID", dig.TxId) 215 continue 216 } 217 218 pvtRWSet := dr.extractPvtRWsets(txPvtRWSet.NsPvtRwset, dig.Namespace, dig.Collection) 219 if rws.EndorsedAt >= maxEndorsedAt { 220 maxEndorsedAt = rws.EndorsedAt 221 results.CollectionConfig = configs 222 } 223 results.RWSet = append(results.RWSet, pvtRWSet...) 224 } 225 } 226 227 func (dr *dataRetriever) extractPvtRWsets(pvtRWSets []*rwset.NsPvtReadWriteSet, namespace string, collectionName string) []util.PrivateRWSet { 228 pRWsets := []util.PrivateRWSet{} 229 230 // Iterate over all namespaces 231 for _, nsws := range pvtRWSets { 232 // and in each namespace - iterate over all collections 233 if nsws.Namespace != namespace { 234 dr.logger.Debug("Received private data namespace ", nsws.Namespace, " instead of ", namespace, " skipping...") 235 continue 236 } 237 for _, col := range nsws.CollectionPvtRwset { 238 // This isn't the collection we're looking for 239 if col.CollectionName != collectionName { 240 dr.logger.Debug("Received private data collection ", col.CollectionName, " instead of ", collectionName, " skipping...") 241 continue 242 } 243 // Add the collection pRWset to the accumulated set 244 pRWsets = append(pRWsets, col.Rwset) 245 } 246 } 247 248 return pRWsets 249 }