github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/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/osdi23p228/fabric/core/ledger" 14 "github.com/osdi23p228/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 elgMissingDataEntries, inelgMissingDataEntries := prepareMissingDataEntries(blockNum, missingPvtData) 23 24 expiryEntries, err := prepareExpiryEntries(blockNum, dataEntries, elgMissingDataEntries, inelgMissingDataEntries, btlPolicy) 25 if err != nil { 26 return nil, err 27 } 28 29 return &storeEntries{ 30 dataEntries: dataEntries, 31 expiryEntries: expiryEntries, 32 elgMissingDataEntries: elgMissingDataEntries, 33 inelgMissingDataEntries: inelgMissingDataEntries, 34 }, nil 35 } 36 37 func prepareDataEntries(blockNum uint64, pvtData []*ledger.TxPvtData) []*dataEntry { 38 var dataEntries []*dataEntry 39 for _, txPvtdata := range pvtData { 40 for _, nsPvtdata := range txPvtdata.WriteSet.NsPvtRwset { 41 for _, collPvtdata := range nsPvtdata.CollectionPvtRwset { 42 txnum := txPvtdata.SeqInBlock 43 ns := nsPvtdata.Namespace 44 coll := collPvtdata.CollectionName 45 dataKey := &dataKey{nsCollBlk{ns, coll, blockNum}, txnum} 46 dataEntries = append(dataEntries, &dataEntry{key: dataKey, value: collPvtdata}) 47 } 48 } 49 } 50 return dataEntries 51 } 52 53 func prepareMissingDataEntries( 54 committingBlk uint64, 55 missingPvtData ledger.TxMissingPvtDataMap, 56 ) (map[missingDataKey]*bitset.BitSet, map[missingDataKey]*bitset.BitSet) { 57 elgMissingDataEntries := make(map[missingDataKey]*bitset.BitSet) 58 inelgMissingDataEntries := make(map[missingDataKey]*bitset.BitSet) 59 60 for txNum, missingData := range missingPvtData { 61 for _, nsColl := range missingData { 62 key := missingDataKey{ 63 nsCollBlk{ 64 ns: nsColl.Namespace, 65 coll: nsColl.Collection, 66 blkNum: committingBlk, 67 }, 68 } 69 70 switch nsColl.IsEligible { 71 case true: 72 if _, ok := elgMissingDataEntries[key]; !ok { 73 elgMissingDataEntries[key] = &bitset.BitSet{} 74 } 75 elgMissingDataEntries[key].Set(uint(txNum)) 76 default: 77 if _, ok := inelgMissingDataEntries[key]; !ok { 78 inelgMissingDataEntries[key] = &bitset.BitSet{} 79 } 80 inelgMissingDataEntries[key].Set(uint(txNum)) 81 } 82 } 83 } 84 85 return elgMissingDataEntries, inelgMissingDataEntries 86 } 87 88 // prepareExpiryEntries returns expiry entries for both private data which is present in the committingBlk 89 // and missing private. 90 func prepareExpiryEntries(committingBlk uint64, dataEntries []*dataEntry, elgMissingDataEntries, inelgMissingDataEntries map[missingDataKey]*bitset.BitSet, 91 btlPolicy pvtdatapolicy.BTLPolicy) ([]*expiryEntry, error) { 92 var expiryEntries []*expiryEntry 93 mapByExpiringBlk := make(map[uint64]*ExpiryData) 94 95 for _, dataEntry := range dataEntries { 96 if err := prepareExpiryEntriesForPresentData(mapByExpiringBlk, dataEntry.key, btlPolicy); err != nil { 97 return nil, err 98 } 99 } 100 101 for missingDataKey := range elgMissingDataEntries { 102 if err := prepareExpiryEntriesForMissingData(mapByExpiringBlk, &missingDataKey, btlPolicy); err != nil { 103 return nil, err 104 } 105 } 106 107 for missingDataKey := range inelgMissingDataEntries { 108 if err := prepareExpiryEntriesForMissingData(mapByExpiringBlk, &missingDataKey, btlPolicy); err != nil { 109 return nil, err 110 } 111 } 112 113 for expiryBlk, expiryData := range mapByExpiringBlk { 114 expiryKey := &expiryKey{expiringBlk: expiryBlk, committingBlk: committingBlk} 115 expiryEntries = append(expiryEntries, &expiryEntry{key: expiryKey, value: expiryData}) 116 } 117 118 return expiryEntries, nil 119 } 120 121 // prepareExpiryDataForPresentData creates expiryData for non-missing pvt data 122 func prepareExpiryEntriesForPresentData(mapByExpiringBlk map[uint64]*ExpiryData, dataKey *dataKey, btlPolicy pvtdatapolicy.BTLPolicy) error { 123 expiringBlk, err := btlPolicy.GetExpiringBlock(dataKey.ns, dataKey.coll, dataKey.blkNum) 124 if err != nil { 125 return err 126 } 127 if neverExpires(expiringBlk) { 128 return nil 129 } 130 131 expiryData := getOrCreateExpiryData(mapByExpiringBlk, expiringBlk) 132 133 expiryData.addPresentData(dataKey.ns, dataKey.coll, dataKey.txNum) 134 return nil 135 } 136 137 // prepareExpiryDataForMissingData creates expiryData for missing pvt data 138 func prepareExpiryEntriesForMissingData(mapByExpiringBlk map[uint64]*ExpiryData, missingKey *missingDataKey, btlPolicy pvtdatapolicy.BTLPolicy) error { 139 expiringBlk, err := btlPolicy.GetExpiringBlock(missingKey.ns, missingKey.coll, missingKey.blkNum) 140 if err != nil { 141 return err 142 } 143 if neverExpires(expiringBlk) { 144 return nil 145 } 146 147 expiryData := getOrCreateExpiryData(mapByExpiringBlk, expiringBlk) 148 149 expiryData.addMissingData(missingKey.ns, missingKey.coll) 150 return nil 151 } 152 153 func getOrCreateExpiryData(mapByExpiringBlk map[uint64]*ExpiryData, expiringBlk uint64) *ExpiryData { 154 expiryData, ok := mapByExpiringBlk[expiringBlk] 155 if !ok { 156 expiryData = newExpiryData() 157 mapByExpiringBlk[expiringBlk] = expiryData 158 } 159 return expiryData 160 } 161 162 // deriveKeys constructs dataKeys and missingDataKey from an expiryEntry 163 func deriveKeys(expiryEntry *expiryEntry) ([]*dataKey, []*missingDataKey) { 164 var dataKeys []*dataKey 165 var missingDataKeys []*missingDataKey 166 167 for ns, colls := range expiryEntry.value.Map { 168 for coll, txNums := range colls.Map { 169 for _, txNum := range txNums.List { 170 dataKeys = append(dataKeys, 171 &dataKey{ 172 nsCollBlk: nsCollBlk{ 173 ns: ns, 174 coll: coll, 175 blkNum: expiryEntry.key.committingBlk, 176 }, 177 txNum: txNum, 178 }) 179 } 180 } 181 182 for coll := range colls.MissingDataMap { 183 missingDataKeys = append(missingDataKeys, 184 &missingDataKey{ 185 nsCollBlk: nsCollBlk{ 186 ns: ns, 187 coll: coll, 188 blkNum: expiryEntry.key.committingBlk, 189 }, 190 }) 191 } 192 } 193 194 return dataKeys, missingDataKeys 195 } 196 197 func passesFilter(dataKey *dataKey, filter ledger.PvtNsCollFilter) bool { 198 return filter == nil || filter.Has(dataKey.ns, dataKey.coll) 199 } 200 201 func isExpired(key nsCollBlk, btl pvtdatapolicy.BTLPolicy, latestBlkNum uint64) (bool, error) { 202 expiringBlk, err := btl.GetExpiringBlock(key.ns, key.coll, key.blkNum) 203 if err != nil { 204 return false, err 205 } 206 207 return latestBlkNum >= expiringBlk, nil 208 } 209 210 func neverExpires(expiringBlkNum uint64) bool { 211 return expiringBlkNum == math.MaxUint64 212 } 213 214 type txPvtdataAssembler struct { 215 blockNum, txNum uint64 216 txWset *rwset.TxPvtReadWriteSet 217 currentNsWSet *rwset.NsPvtReadWriteSet 218 firstCall bool 219 } 220 221 func newTxPvtdataAssembler(blockNum, txNum uint64) *txPvtdataAssembler { 222 return &txPvtdataAssembler{blockNum, txNum, &rwset.TxPvtReadWriteSet{}, nil, true} 223 } 224 225 func (a *txPvtdataAssembler) add(ns string, collPvtWset *rwset.CollectionPvtReadWriteSet) { 226 // start a NsWset 227 if a.firstCall { 228 a.currentNsWSet = &rwset.NsPvtReadWriteSet{Namespace: ns} 229 a.firstCall = false 230 } 231 232 // if a new ns started, add the existing NsWset to TxWset and start a new one 233 if a.currentNsWSet.Namespace != ns { 234 a.txWset.NsPvtRwset = append(a.txWset.NsPvtRwset, a.currentNsWSet) 235 a.currentNsWSet = &rwset.NsPvtReadWriteSet{Namespace: ns} 236 } 237 // add the collWset to the current NsWset 238 a.currentNsWSet.CollectionPvtRwset = append(a.currentNsWSet.CollectionPvtRwset, collPvtWset) 239 } 240 241 func (a *txPvtdataAssembler) done() { 242 if a.currentNsWSet != nil { 243 a.txWset.NsPvtRwset = append(a.txWset.NsPvtRwset, a.currentNsWSet) 244 } 245 a.currentNsWSet = nil 246 } 247 248 func (a *txPvtdataAssembler) getTxPvtdata() *ledger.TxPvtData { 249 a.done() 250 return &ledger.TxPvtData{SeqInBlock: a.txNum, WriteSet: a.txWset} 251 }