@@ -18,24 +18,45 @@ package rwsetutil
18
18
19
19
import (
20
20
"github.com/hyperledger/fabric/common/flogging"
21
+ "github.com/hyperledger/fabric/core/ledger"
21
22
"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version"
22
23
"github.com/hyperledger/fabric/core/ledger/util"
24
+ "github.com/hyperledger/fabric/protos/ledger/rwset"
23
25
"github.com/hyperledger/fabric/protos/ledger/rwset/kvrwset"
24
26
)
25
27
26
28
var logger = flogging .MustGetLogger ("rwsetutil" )
27
29
28
- type nsRWs struct {
29
- readMap map [string ]* kvrwset.KVRead //for mvcc validation
30
- writeMap map [string ]* kvrwset.KVWrite
31
- rangeQueriesMap map [rangeQueryKey ]* kvrwset.RangeQueryInfo //for phantom read validation
32
- rangeQueriesKeys []rangeQueryKey
30
+ // RWSetBuilder helps building the read-write set
31
+ type RWSetBuilder struct {
32
+ pubRwBuilderMap map [string ]* nsPubRwBuilder
33
+ pvtRwBuilderMap map [string ]* nsPvtRwBuilder
33
34
}
34
35
35
- func newNsRWs () * nsRWs {
36
- return & nsRWs {make (map [string ]* kvrwset.KVRead ),
37
- make (map [string ]* kvrwset.KVWrite ),
38
- make (map [rangeQueryKey ]* kvrwset.RangeQueryInfo ), nil }
36
+ type nsPubRwBuilder struct {
37
+ namespace string
38
+ readMap map [string ]* kvrwset.KVRead //for mvcc validation
39
+ writeMap map [string ]* kvrwset.KVWrite
40
+ rangeQueriesMap map [rangeQueryKey ]* kvrwset.RangeQueryInfo //for phantom read validation
41
+ rangeQueriesKeys []rangeQueryKey
42
+ collHashRwBuilder map [string ]* collHashRwBuilder
43
+ }
44
+
45
+ type collHashRwBuilder struct {
46
+ collName string
47
+ readMap map [string ]* kvrwset.KVReadHash
48
+ writeMap map [string ]* kvrwset.KVWriteHash
49
+ pvtDataHash []byte
50
+ }
51
+
52
+ type nsPvtRwBuilder struct {
53
+ namespace string
54
+ collPvtRwBuilders map [string ]* collPvtRwBuilder
55
+ }
56
+
57
+ type collPvtRwBuilder struct {
58
+ collectionName string
59
+ writeMap map [string ]* kvrwset.KVWrite
39
60
}
40
61
41
62
type rangeQueryKey struct {
@@ -44,80 +65,246 @@ type rangeQueryKey struct {
44
65
itrExhausted bool
45
66
}
46
67
47
- // RWSetBuilder helps building the read-write set
48
- type RWSetBuilder struct {
49
- rwMap map [string ]* nsRWs
50
- }
51
-
52
68
// NewRWSetBuilder constructs a new instance of RWSetBuilder
53
69
func NewRWSetBuilder () * RWSetBuilder {
54
- return & RWSetBuilder {make (map [string ]* nsRWs )}
70
+ return & RWSetBuilder {make (map [string ]* nsPubRwBuilder ), make ( map [ string ] * nsPvtRwBuilder )}
55
71
}
56
72
57
73
// AddToReadSet adds a key and corresponding version to the read-set
58
- func (rws * RWSetBuilder ) AddToReadSet (ns string , key string , version * version.Height ) {
59
- nsRWs := rws . getOrCreateNsRW (ns )
60
- nsRWs .readMap [key ] = NewKVRead (key , version )
74
+ func (b * RWSetBuilder ) AddToReadSet (ns string , key string , version * version.Height ) {
75
+ nsPubRwBuilder := b . getOrCreateNsPubRwBuilder (ns )
76
+ nsPubRwBuilder .readMap [key ] = NewKVRead (key , version )
61
77
}
62
78
63
79
// AddToWriteSet adds a key and value to the write-set
64
- func (rws * RWSetBuilder ) AddToWriteSet (ns string , key string , value []byte ) {
65
- nsRWs := rws . getOrCreateNsRW (ns )
66
- nsRWs .writeMap [key ] = newKVWrite (key , value )
80
+ func (b * RWSetBuilder ) AddToWriteSet (ns string , key string , value []byte ) {
81
+ nsPubRwBuilder := b . getOrCreateNsPubRwBuilder (ns )
82
+ nsPubRwBuilder .writeMap [key ] = newKVWrite (key , value )
67
83
}
68
84
69
85
// AddToRangeQuerySet adds a range query info for performing phantom read validation
70
- func (rws * RWSetBuilder ) AddToRangeQuerySet (ns string , rqi * kvrwset.RangeQueryInfo ) {
71
- nsRWs := rws . getOrCreateNsRW (ns )
86
+ func (b * RWSetBuilder ) AddToRangeQuerySet (ns string , rqi * kvrwset.RangeQueryInfo ) {
87
+ nsPubRwBuilder := b . getOrCreateNsPubRwBuilder (ns )
72
88
key := rangeQueryKey {rqi .StartKey , rqi .EndKey , rqi .ItrExhausted }
73
- _ , ok := nsRWs .rangeQueriesMap [key ]
89
+ _ , ok := nsPubRwBuilder .rangeQueriesMap [key ]
74
90
if ! ok {
75
- nsRWs .rangeQueriesMap [key ] = rqi
76
- nsRWs .rangeQueriesKeys = append (nsRWs .rangeQueriesKeys , key )
91
+ nsPubRwBuilder .rangeQueriesMap [key ] = rqi
92
+ nsPubRwBuilder .rangeQueriesKeys = append (nsPubRwBuilder .rangeQueriesKeys , key )
77
93
}
78
94
}
79
95
80
- // GetTxReadWriteSet returns the read-write set in the form that can be serialized
81
- func (rws * RWSetBuilder ) GetTxReadWriteSet () * TxRwSet {
82
- txRWSet := & TxRwSet {}
83
- sortedNamespaces := util .GetSortedKeys (rws .rwMap )
84
- for _ , ns := range sortedNamespaces {
85
- //Get namespace specific read-writes
86
- nsReadWriteMap := rws .rwMap [ns ]
96
+ // AddToHashedReadSet adds a key and corresponding version to the hashed read-set
97
+ func (b * RWSetBuilder ) AddToHashedReadSet (ns string , coll string , key string , version * version.Height ) error {
98
+ kvReadHash , err := newPvtKVReadHash (key , version )
99
+ if err != nil {
100
+ return err
101
+ }
102
+ b .getOrCreateCollHashedRwBuilder (ns , coll ).readMap [key ] = kvReadHash
103
+ return nil
104
+ }
87
105
88
- //add read set
89
- var reads []* kvrwset.KVRead
90
- sortedReadKeys := util .GetSortedKeys (nsReadWriteMap .readMap )
91
- for _ , key := range sortedReadKeys {
92
- reads = append (reads , nsReadWriteMap .readMap [key ])
93
- }
106
+ // AddToPvtAndHashedWriteSet adds a key and value to the private and hashed write-set
107
+ func (b * RWSetBuilder ) AddToPvtAndHashedWriteSet (ns string , coll string , key string , value []byte ) error {
108
+ kvWrite , kvWriteHash , err := newPvtKVWriteAndHash (key , value )
109
+ if err != nil {
110
+ return err
111
+ }
112
+ b .getOrCreateCollPvtRwBuilder (ns , coll ).writeMap [key ] = kvWrite
113
+ b .getOrCreateCollHashedRwBuilder (ns , coll ).writeMap [key ] = kvWriteHash
114
+ return nil
115
+ }
94
116
95
- //add write set
96
- var writes []* kvrwset.KVWrite
97
- sortedWriteKeys := util .GetSortedKeys (nsReadWriteMap .writeMap )
98
- for _ , key := range sortedWriteKeys {
99
- writes = append (writes , nsReadWriteMap .writeMap [key ])
100
- }
117
+ // GetTxSimulationResults returns the proto bytes of public rwset
118
+ // (public data + hashes of private data) and the private rwset for the transaction
119
+ func (b * RWSetBuilder ) GetTxSimulationResults () (* ledger.TxSimulationResults , error ) {
120
+ pvtData := b .getTxPvtReadWriteSet ()
121
+ var err error
101
122
102
- //add range query info
103
- var rangeQueriesInfo []* kvrwset.RangeQueryInfo
104
- rangeQueriesMap := nsReadWriteMap .rangeQueriesMap
105
- for _ , key := range nsReadWriteMap .rangeQueriesKeys {
106
- rangeQueriesInfo = append (rangeQueriesInfo , rangeQueriesMap [key ])
123
+ var pubDataProto * rwset.TxReadWriteSet
124
+ var pvtDataProto * rwset.TxPvtReadWriteSet
125
+
126
+ // Populate the collection-level hashes into pub rwset and compute the proto bytes for pvt rwset
127
+ if pvtData != nil {
128
+ if pvtDataProto , err = pvtData .toProtoMsg (); err != nil {
129
+ return nil , err
130
+ }
131
+ for _ , ns := range pvtDataProto .NsPvtRwset {
132
+ for _ , coll := range ns .CollectionPvtRwset {
133
+ b .setPvtCollectionHash (ns .Namespace , coll .CollectionName , coll .Rwset )
134
+ }
107
135
}
108
- kvRWs := & kvrwset.KVRWSet {Reads : reads , Writes : writes , RangeQueriesInfo : rangeQueriesInfo }
109
- nsRWs := & NsRwSet {ns , kvRWs }
110
- txRWSet .NsRwSets = append (txRWSet .NsRwSets , nsRWs )
111
136
}
112
- return txRWSet
137
+ // Compute the proto bytes for pub rwset
138
+ pubSet := b .GetTxReadWriteSet ()
139
+ if pubSet != nil {
140
+ if pubDataProto , err = b .GetTxReadWriteSet ().toProtoMsg (); err != nil {
141
+ return nil , err
142
+ }
143
+ }
144
+ return & ledger.TxSimulationResults {
145
+ PubSimulationResults : pubDataProto ,
146
+ PvtSimulationResults : pvtDataProto ,
147
+ }, nil
148
+ }
149
+
150
+ func (b * RWSetBuilder ) setPvtCollectionHash (ns string , coll string , pvtDataProto []byte ) {
151
+ collHashedBuilder := b .getOrCreateCollHashedRwBuilder (ns , coll )
152
+ collHashedBuilder .pvtDataHash = util .ComputeHash (pvtDataProto )
153
+ }
154
+
155
+ // GetTxReadWriteSet returns the read-write set
156
+ // TODO make this function private once txmgr starts using new function `GetTxSimulationResults` introduced here
157
+ func (b * RWSetBuilder ) GetTxReadWriteSet () * TxRwSet {
158
+ sortedNsPubBuilders := []* nsPubRwBuilder {}
159
+ util .GetValuesBySortedKeys (& (b .pubRwBuilderMap ), & sortedNsPubBuilders )
160
+
161
+ var nsPubRwSets []* NsRwSet
162
+ for _ , nsPubRwBuilder := range sortedNsPubBuilders {
163
+ nsPubRwSets = append (nsPubRwSets , nsPubRwBuilder .build ())
164
+ }
165
+ return & TxRwSet {NsRwSets : nsPubRwSets }
113
166
}
114
167
115
- func (rws * RWSetBuilder ) getOrCreateNsRW (ns string ) * nsRWs {
116
- var nsRWs * nsRWs
117
- var ok bool
118
- if nsRWs , ok = rws .rwMap [ns ]; ! ok {
119
- nsRWs = newNsRWs ()
120
- rws .rwMap [ns ] = nsRWs
168
+ // getTxPvtReadWriteSet returns the private read-write set
169
+ func (b * RWSetBuilder ) getTxPvtReadWriteSet () * TxPvtRwSet {
170
+ sortedNsPvtBuilders := []* nsPvtRwBuilder {}
171
+ util .GetValuesBySortedKeys (& (b .pvtRwBuilderMap ), & sortedNsPvtBuilders )
172
+
173
+ var nsPvtRwSets []* NsPvtRwSet
174
+ for _ , nsPvtRwBuilder := range sortedNsPvtBuilders {
175
+ nsPvtRwSets = append (nsPvtRwSets , nsPvtRwBuilder .build ())
176
+ }
177
+ if len (nsPvtRwSets ) == 0 {
178
+ return nil
121
179
}
122
- return nsRWs
180
+ return & TxPvtRwSet {NsPvtRwSet : nsPvtRwSets }
181
+ }
182
+
183
+ func (b * nsPubRwBuilder ) build () * NsRwSet {
184
+ var readSet []* kvrwset.KVRead
185
+ var writeSet []* kvrwset.KVWrite
186
+ var rangeQueriesInfo []* kvrwset.RangeQueryInfo
187
+ var collHashedRwSet []* CollHashedRwSet
188
+ //add read set
189
+ util .GetValuesBySortedKeys (& (b .readMap ), & readSet )
190
+ //add write set
191
+ util .GetValuesBySortedKeys (& (b .writeMap ), & writeSet )
192
+ //add range query info
193
+ for _ , key := range b .rangeQueriesKeys {
194
+ rangeQueriesInfo = append (rangeQueriesInfo , b .rangeQueriesMap [key ])
195
+ }
196
+ // add hashed rws for private collections
197
+ sortedCollBuilders := []* collHashRwBuilder {}
198
+ util .GetValuesBySortedKeys (& (b .collHashRwBuilder ), & sortedCollBuilders )
199
+ for _ , collBuilder := range sortedCollBuilders {
200
+ collHashedRwSet = append (collHashedRwSet , collBuilder .build ())
201
+ }
202
+ return & NsRwSet {
203
+ NameSpace : b .namespace ,
204
+ KvRwSet : & kvrwset.KVRWSet {Reads : readSet , Writes : writeSet , RangeQueriesInfo : rangeQueriesInfo },
205
+ CollHashedRwSets : collHashedRwSet ,
206
+ }
207
+ }
208
+
209
+ func (b * nsPvtRwBuilder ) build () * NsPvtRwSet {
210
+ sortedCollBuilders := []* collPvtRwBuilder {}
211
+ util .GetValuesBySortedKeys (& (b .collPvtRwBuilders ), & sortedCollBuilders )
212
+
213
+ var collPvtRwSets []* CollPvtRwSet
214
+ for _ , collBuilder := range sortedCollBuilders {
215
+ collPvtRwSets = append (collPvtRwSets , collBuilder .build ())
216
+ }
217
+ return & NsPvtRwSet {NameSpace : b .namespace , CollPvtRwSets : collPvtRwSets }
218
+ }
219
+
220
+ func (b * collHashRwBuilder ) build () * CollHashedRwSet {
221
+ var readSet []* kvrwset.KVReadHash
222
+ var writeSet []* kvrwset.KVWriteHash
223
+ util .GetValuesBySortedKeys (& (b .readMap ), & readSet )
224
+ util .GetValuesBySortedKeys (& (b .writeMap ), & writeSet )
225
+ return & CollHashedRwSet {
226
+ CollectionName : b .collName ,
227
+ HashedRwSet : & kvrwset.HashedRWSet {
228
+ HashedReads : readSet ,
229
+ HashedWrites : writeSet ,
230
+ },
231
+ PvtRwSetHash : b .pvtDataHash ,
232
+ }
233
+ }
234
+
235
+ func (b * collPvtRwBuilder ) build () * CollPvtRwSet {
236
+ var writeSet []* kvrwset.KVWrite
237
+ util .GetValuesBySortedKeys (& (b .writeMap ), & writeSet )
238
+ return & CollPvtRwSet {
239
+ CollectionName : b .collectionName ,
240
+ KvRwSet : & kvrwset.KVRWSet {
241
+ Writes : writeSet ,
242
+ },
243
+ }
244
+ }
245
+
246
+ func (b * RWSetBuilder ) getOrCreateNsPubRwBuilder (ns string ) * nsPubRwBuilder {
247
+ nsPubRwBuilder , ok := b .pubRwBuilderMap [ns ]
248
+ if ! ok {
249
+ nsPubRwBuilder = newNsPubRwBuilder (ns )
250
+ b .pubRwBuilderMap [ns ] = nsPubRwBuilder
251
+ }
252
+ return nsPubRwBuilder
253
+ }
254
+
255
+ func (b * RWSetBuilder ) getOrCreateNsPvtRwBuilder (ns string ) * nsPvtRwBuilder {
256
+ nsPvtRwBuilder , ok := b .pvtRwBuilderMap [ns ]
257
+ if ! ok {
258
+ nsPvtRwBuilder = newNsPvtRwBuilder (ns )
259
+ b .pvtRwBuilderMap [ns ] = nsPvtRwBuilder
260
+ }
261
+ return nsPvtRwBuilder
262
+ }
263
+
264
+ func (b * RWSetBuilder ) getOrCreateCollHashedRwBuilder (ns string , coll string ) * collHashRwBuilder {
265
+ nsPubRwBuilder := b .getOrCreateNsPubRwBuilder (ns )
266
+ collHashRwBuilder , ok := nsPubRwBuilder .collHashRwBuilder [coll ]
267
+ if ! ok {
268
+ collHashRwBuilder = newCollHashRwBuilder (coll )
269
+ nsPubRwBuilder .collHashRwBuilder [coll ] = collHashRwBuilder
270
+ }
271
+ return collHashRwBuilder
272
+ }
273
+
274
+ func (b * RWSetBuilder ) getOrCreateCollPvtRwBuilder (ns string , coll string ) * collPvtRwBuilder {
275
+ nsPvtRwBuilder := b .getOrCreateNsPvtRwBuilder (ns )
276
+ collPvtRwBuilder , ok := nsPvtRwBuilder .collPvtRwBuilders [coll ]
277
+ if ! ok {
278
+ collPvtRwBuilder = newCollPvtRwBuilder (coll )
279
+ nsPvtRwBuilder .collPvtRwBuilders [coll ] = collPvtRwBuilder
280
+ }
281
+ return collPvtRwBuilder
282
+ }
283
+
284
+ func newNsPubRwBuilder (namespace string ) * nsPubRwBuilder {
285
+ return & nsPubRwBuilder {
286
+ namespace ,
287
+ make (map [string ]* kvrwset.KVRead ),
288
+ make (map [string ]* kvrwset.KVWrite ),
289
+ make (map [rangeQueryKey ]* kvrwset.RangeQueryInfo ),
290
+ nil ,
291
+ make (map [string ]* collHashRwBuilder ),
292
+ }
293
+ }
294
+
295
+ func newNsPvtRwBuilder (namespace string ) * nsPvtRwBuilder {
296
+ return & nsPvtRwBuilder {namespace , make (map [string ]* collPvtRwBuilder )}
297
+ }
298
+
299
+ func newCollHashRwBuilder (collName string ) * collHashRwBuilder {
300
+ return & collHashRwBuilder {
301
+ collName ,
302
+ make (map [string ]* kvrwset.KVReadHash ),
303
+ make (map [string ]* kvrwset.KVWriteHash ),
304
+ nil ,
305
+ }
306
+ }
307
+
308
+ func newCollPvtRwBuilder (collName string ) * collPvtRwBuilder {
309
+ return & collPvtRwBuilder {collName , make (map [string ]* kvrwset.KVWrite )}
123
310
}
0 commit comments