Skip to content

Commit d9e0004

Browse files
committed
[FAB-5630] SideDB - RWSetBuilder enhancements
This CR enhance the read-write set builder for capturing the additional information during simulation of a transaction In addition to the public read-erite set for channel scoped data, this CR allows to capture the hashed read-write set and private read-write set for the private data. Change-Id: I438692d7af0255d589adf8f21cda51a3f00d7418 Signed-off-by: manish <manish.sethi@gmail.com>
1 parent 6e9e042 commit d9e0004

File tree

7 files changed

+901
-112
lines changed

7 files changed

+901
-112
lines changed

core/ledger/kvledger/txmgmt/rwsetutil/rwset_builder.go

Lines changed: 248 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,45 @@ package rwsetutil
1818

1919
import (
2020
"github.com/hyperledger/fabric/common/flogging"
21+
"github.com/hyperledger/fabric/core/ledger"
2122
"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version"
2223
"github.com/hyperledger/fabric/core/ledger/util"
24+
"github.com/hyperledger/fabric/protos/ledger/rwset"
2325
"github.com/hyperledger/fabric/protos/ledger/rwset/kvrwset"
2426
)
2527

2628
var logger = flogging.MustGetLogger("rwsetutil")
2729

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
3334
}
3435

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
3960
}
4061

4162
type rangeQueryKey struct {
@@ -44,80 +65,246 @@ type rangeQueryKey struct {
4465
itrExhausted bool
4566
}
4667

47-
// RWSetBuilder helps building the read-write set
48-
type RWSetBuilder struct {
49-
rwMap map[string]*nsRWs
50-
}
51-
5268
// NewRWSetBuilder constructs a new instance of RWSetBuilder
5369
func NewRWSetBuilder() *RWSetBuilder {
54-
return &RWSetBuilder{make(map[string]*nsRWs)}
70+
return &RWSetBuilder{make(map[string]*nsPubRwBuilder), make(map[string]*nsPvtRwBuilder)}
5571
}
5672

5773
// 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)
6177
}
6278

6379
// 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)
6783
}
6884

6985
// 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)
7288
key := rangeQueryKey{rqi.StartKey, rqi.EndKey, rqi.ItrExhausted}
73-
_, ok := nsRWs.rangeQueriesMap[key]
89+
_, ok := nsPubRwBuilder.rangeQueriesMap[key]
7490
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)
7793
}
7894
}
7995

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+
}
87105

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+
}
94116

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
101122

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+
}
107135
}
108-
kvRWs := &kvrwset.KVRWSet{Reads: reads, Writes: writes, RangeQueriesInfo: rangeQueriesInfo}
109-
nsRWs := &NsRwSet{ns, kvRWs}
110-
txRWSet.NsRwSets = append(txRWSet.NsRwSets, nsRWs)
111136
}
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}
113166
}
114167

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
121179
}
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)}
123310
}

0 commit comments

Comments
 (0)