github.com/defanghe/fabric@v2.1.1+incompatible/core/ledger/pvtdatastorage/helper.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package pvtdatastorage 8 9 import ( 10 "math" 11 12 "github.com/hyperledger/fabric-protos-go/ledger/rwset" 13 "github.com/hyperledger/fabric/core/ledger" 14 "github.com/hyperledger/fabric/core/ledger/pvtdatapolicy" 15 "github.com/willf/bitset" 16 ) 17 18 func prepareStoreEntries(blockNum uint64, pvtData []*ledger.TxPvtData, btlPolicy pvtdatapolicy.BTLPolicy, 19 missingPvtData ledger.TxMissingPvtDataMap) (*storeEntries, error) { 20 dataEntries := prepareDataEntries(blockNum, pvtData) 21 22 missingDataEntries := prepareMissingDataEntries(blockNum, missingPvtData) 23 24 expiryEntries, err := prepareExpiryEntries(blockNum, dataEntries, missingDataEntries, btlPolicy) 25 if err != nil { 26 return nil, err 27 } 28 29 return &storeEntries{ 30 dataEntries: dataEntries, 31 expiryEntries: expiryEntries, 32 missingDataEntries: missingDataEntries}, nil 33 } 34 35 func prepareDataEntries(blockNum uint64, pvtData []*ledger.TxPvtData) []*dataEntry { 36 var dataEntries []*dataEntry 37 for _, txPvtdata := range pvtData { 38 for _, nsPvtdata := range txPvtdata.WriteSet.NsPvtRwset { 39 for _, collPvtdata := range nsPvtdata.CollectionPvtRwset { 40 txnum := txPvtdata.SeqInBlock 41 ns := nsPvtdata.Namespace 42 coll := collPvtdata.CollectionName 43 dataKey := &dataKey{nsCollBlk{ns, coll, blockNum}, txnum} 44 dataEntries = append(dataEntries, &dataEntry{key: dataKey, value: collPvtdata}) 45 } 46 } 47 } 48 return dataEntries 49 } 50 51 func prepareMissingDataEntries(committingBlk uint64, missingPvtData ledger.TxMissingPvtDataMap) map[missingDataKey]*bitset.BitSet { 52 missingDataEntries := make(map[missingDataKey]*bitset.BitSet) 53 54 for txNum, missingData := range missingPvtData { 55 for _, nsColl := range missingData { 56 key := missingDataKey{nsCollBlk{nsColl.Namespace, nsColl.Collection, committingBlk}, 57 nsColl.IsEligible} 58 59 if _, ok := missingDataEntries[key]; !ok { 60 missingDataEntries[key] = &bitset.BitSet{} 61 } 62 bitmap := missingDataEntries[key] 63 64 bitmap.Set(uint(txNum)) 65 } 66 } 67 68 return missingDataEntries 69 } 70 71 // prepareExpiryEntries returns expiry entries for both private data which is present in the committingBlk 72 // and missing private. 73 func prepareExpiryEntries(committingBlk uint64, dataEntries []*dataEntry, missingDataEntries map[missingDataKey]*bitset.BitSet, 74 btlPolicy pvtdatapolicy.BTLPolicy) ([]*expiryEntry, error) { 75 76 var expiryEntries []*expiryEntry 77 mapByExpiringBlk := make(map[uint64]*ExpiryData) 78 79 // 1. prepare expiryData for non-missing data 80 for _, dataEntry := range dataEntries { 81 prepareExpiryEntriesForPresentData(mapByExpiringBlk, dataEntry.key, btlPolicy) 82 } 83 84 // 2. prepare expiryData for missing data 85 for missingDataKey := range missingDataEntries { 86 prepareExpiryEntriesForMissingData(mapByExpiringBlk, &missingDataKey, btlPolicy) 87 } 88 89 for expiryBlk, expiryData := range mapByExpiringBlk { 90 expiryKey := &expiryKey{expiringBlk: expiryBlk, committingBlk: committingBlk} 91 expiryEntries = append(expiryEntries, &expiryEntry{key: expiryKey, value: expiryData}) 92 } 93 94 return expiryEntries, nil 95 } 96 97 // prepareExpiryDataForPresentData creates expiryData for non-missing pvt data 98 func prepareExpiryEntriesForPresentData(mapByExpiringBlk map[uint64]*ExpiryData, dataKey *dataKey, btlPolicy pvtdatapolicy.BTLPolicy) error { 99 expiringBlk, err := btlPolicy.GetExpiringBlock(dataKey.ns, dataKey.coll, dataKey.blkNum) 100 if err != nil { 101 return err 102 } 103 if neverExpires(expiringBlk) { 104 return nil 105 } 106 107 expiryData := getOrCreateExpiryData(mapByExpiringBlk, expiringBlk) 108 109 expiryData.addPresentData(dataKey.ns, dataKey.coll, dataKey.txNum) 110 return nil 111 } 112 113 // prepareExpiryDataForMissingData creates expiryData for missing pvt data 114 func prepareExpiryEntriesForMissingData(mapByExpiringBlk map[uint64]*ExpiryData, missingKey *missingDataKey, btlPolicy pvtdatapolicy.BTLPolicy) error { 115 expiringBlk, err := btlPolicy.GetExpiringBlock(missingKey.ns, missingKey.coll, missingKey.blkNum) 116 if err != nil { 117 return err 118 } 119 if neverExpires(expiringBlk) { 120 return nil 121 } 122 123 expiryData := getOrCreateExpiryData(mapByExpiringBlk, expiringBlk) 124 125 expiryData.addMissingData(missingKey.ns, missingKey.coll) 126 return nil 127 } 128 129 func getOrCreateExpiryData(mapByExpiringBlk map[uint64]*ExpiryData, expiringBlk uint64) *ExpiryData { 130 expiryData, ok := mapByExpiringBlk[expiringBlk] 131 if !ok { 132 expiryData = newExpiryData() 133 mapByExpiringBlk[expiringBlk] = expiryData 134 } 135 return expiryData 136 } 137 138 // deriveKeys constructs dataKeys and missingDataKey from an expiryEntry 139 func deriveKeys(expiryEntry *expiryEntry) (dataKeys []*dataKey, missingDataKeys []*missingDataKey) { 140 for ns, colls := range expiryEntry.value.Map { 141 // 1. constructs dataKeys of expired existing pvt data 142 for coll, txNums := range colls.Map { 143 for _, txNum := range txNums.List { 144 dataKeys = append(dataKeys, 145 &dataKey{nsCollBlk{ns, coll, expiryEntry.key.committingBlk}, txNum}) 146 } 147 } 148 // 2. constructs missingDataKeys of expired missing pvt data 149 for coll := range colls.MissingDataMap { 150 // one key for eligible entries and another for ieligible entries 151 missingDataKeys = append(missingDataKeys, 152 &missingDataKey{nsCollBlk{ns, coll, expiryEntry.key.committingBlk}, true}) 153 missingDataKeys = append(missingDataKeys, 154 &missingDataKey{nsCollBlk{ns, coll, expiryEntry.key.committingBlk}, false}) 155 156 } 157 } 158 return 159 } 160 161 func passesFilter(dataKey *dataKey, filter ledger.PvtNsCollFilter) bool { 162 return filter == nil || filter.Has(dataKey.ns, dataKey.coll) 163 } 164 165 func isExpired(key nsCollBlk, btl pvtdatapolicy.BTLPolicy, latestBlkNum uint64) (bool, error) { 166 expiringBlk, err := btl.GetExpiringBlock(key.ns, key.coll, key.blkNum) 167 if err != nil { 168 return false, err 169 } 170 171 return latestBlkNum >= expiringBlk, nil 172 } 173 174 func neverExpires(expiringBlkNum uint64) bool { 175 return expiringBlkNum == math.MaxUint64 176 } 177 178 type txPvtdataAssembler struct { 179 blockNum, txNum uint64 180 txWset *rwset.TxPvtReadWriteSet 181 currentNsWSet *rwset.NsPvtReadWriteSet 182 firstCall bool 183 } 184 185 func newTxPvtdataAssembler(blockNum, txNum uint64) *txPvtdataAssembler { 186 return &txPvtdataAssembler{blockNum, txNum, &rwset.TxPvtReadWriteSet{}, nil, true} 187 } 188 189 func (a *txPvtdataAssembler) add(ns string, collPvtWset *rwset.CollectionPvtReadWriteSet) { 190 // start a NsWset 191 if a.firstCall { 192 a.currentNsWSet = &rwset.NsPvtReadWriteSet{Namespace: ns} 193 a.firstCall = false 194 } 195 196 // if a new ns started, add the existing NsWset to TxWset and start a new one 197 if a.currentNsWSet.Namespace != ns { 198 a.txWset.NsPvtRwset = append(a.txWset.NsPvtRwset, a.currentNsWSet) 199 a.currentNsWSet = &rwset.NsPvtReadWriteSet{Namespace: ns} 200 } 201 // add the collWset to the current NsWset 202 a.currentNsWSet.CollectionPvtRwset = append(a.currentNsWSet.CollectionPvtRwset, collPvtWset) 203 } 204 205 func (a *txPvtdataAssembler) done() { 206 if a.currentNsWSet != nil { 207 a.txWset.NsPvtRwset = append(a.txWset.NsPvtRwset, a.currentNsWSet) 208 } 209 a.currentNsWSet = nil 210 } 211 212 func (a *txPvtdataAssembler) getTxPvtdata() *ledger.TxPvtData { 213 a.done() 214 return &ledger.TxPvtData{SeqInBlock: a.txNum, WriteSet: a.txWset} 215 }