github.com/true-sqn/fabric@v2.1.1+incompatible/core/ledger/kvledger/txmgmt/rwsetutil/rwset_builder.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  		 http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package rwsetutil
    18  
    19  import (
    20  	"github.com/hyperledger/fabric-protos-go/ledger/rwset"
    21  	"github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset"
    22  	"github.com/hyperledger/fabric/common/flogging"
    23  	"github.com/hyperledger/fabric/core/ledger"
    24  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version"
    25  	"github.com/hyperledger/fabric/core/ledger/util"
    26  )
    27  
    28  var logger = flogging.MustGetLogger("rwsetutil")
    29  
    30  // RWSetBuilder helps building the read-write set
    31  type RWSetBuilder struct {
    32  	pubRwBuilderMap map[string]*nsPubRwBuilder
    33  	pvtRwBuilderMap map[string]*nsPvtRwBuilder
    34  }
    35  
    36  type nsPubRwBuilder struct {
    37  	namespace         string
    38  	readMap           map[string]*kvrwset.KVRead //for mvcc validation
    39  	writeMap          map[string]*kvrwset.KVWrite
    40  	metadataWriteMap  map[string]*kvrwset.KVMetadataWrite
    41  	rangeQueriesMap   map[rangeQueryKey]*kvrwset.RangeQueryInfo //for phantom read validation
    42  	rangeQueriesKeys  []rangeQueryKey
    43  	collHashRwBuilder map[string]*collHashRwBuilder
    44  }
    45  
    46  type collHashRwBuilder struct {
    47  	collName         string
    48  	readMap          map[string]*kvrwset.KVReadHash
    49  	writeMap         map[string]*kvrwset.KVWriteHash
    50  	metadataWriteMap map[string]*kvrwset.KVMetadataWriteHash
    51  	pvtDataHash      []byte
    52  }
    53  
    54  type nsPvtRwBuilder struct {
    55  	namespace         string
    56  	collPvtRwBuilders map[string]*collPvtRwBuilder
    57  }
    58  
    59  type collPvtRwBuilder struct {
    60  	collectionName   string
    61  	writeMap         map[string]*kvrwset.KVWrite
    62  	metadataWriteMap map[string]*kvrwset.KVMetadataWrite
    63  }
    64  
    65  type rangeQueryKey struct {
    66  	startKey     string
    67  	endKey       string
    68  	itrExhausted bool
    69  }
    70  
    71  // NewRWSetBuilder constructs a new instance of RWSetBuilder
    72  func NewRWSetBuilder() *RWSetBuilder {
    73  	return &RWSetBuilder{make(map[string]*nsPubRwBuilder), make(map[string]*nsPvtRwBuilder)}
    74  }
    75  
    76  // AddToReadSet adds a key and corresponding version to the read-set
    77  func (b *RWSetBuilder) AddToReadSet(ns string, key string, version *version.Height) {
    78  	nsPubRwBuilder := b.getOrCreateNsPubRwBuilder(ns)
    79  	nsPubRwBuilder.readMap[key] = NewKVRead(key, version)
    80  }
    81  
    82  // AddToWriteSet adds a key and value to the write-set
    83  func (b *RWSetBuilder) AddToWriteSet(ns string, key string, value []byte) {
    84  	nsPubRwBuilder := b.getOrCreateNsPubRwBuilder(ns)
    85  	nsPubRwBuilder.writeMap[key] = newKVWrite(key, value)
    86  }
    87  
    88  // AddToMetadataWriteSet adds a metadata to a key in the write-set
    89  // A nil/empty-map for 'metadata' parameter indicates the delete of the metadata
    90  func (b *RWSetBuilder) AddToMetadataWriteSet(ns, key string, metadata map[string][]byte) {
    91  	b.getOrCreateNsPubRwBuilder(ns).
    92  		metadataWriteMap[key] = mapToMetadataWrite(key, metadata)
    93  }
    94  
    95  // AddToRangeQuerySet adds a range query info for performing phantom read validation
    96  func (b *RWSetBuilder) AddToRangeQuerySet(ns string, rqi *kvrwset.RangeQueryInfo) {
    97  	nsPubRwBuilder := b.getOrCreateNsPubRwBuilder(ns)
    98  	key := rangeQueryKey{rqi.StartKey, rqi.EndKey, rqi.ItrExhausted}
    99  	_, ok := nsPubRwBuilder.rangeQueriesMap[key]
   100  	if !ok {
   101  		nsPubRwBuilder.rangeQueriesMap[key] = rqi
   102  		nsPubRwBuilder.rangeQueriesKeys = append(nsPubRwBuilder.rangeQueriesKeys, key)
   103  	}
   104  }
   105  
   106  // AddToHashedReadSet adds a key and corresponding version to the hashed read-set
   107  func (b *RWSetBuilder) AddToHashedReadSet(ns string, coll string, key string, version *version.Height) {
   108  	kvReadHash := newPvtKVReadHash(key, version)
   109  	b.getOrCreateCollHashedRwBuilder(ns, coll).readMap[key] = kvReadHash
   110  }
   111  
   112  // AddToPvtAndHashedWriteSet adds a key and value to the private and hashed write-set
   113  func (b *RWSetBuilder) AddToPvtAndHashedWriteSet(ns string, coll string, key string, value []byte) {
   114  	kvWrite, kvWriteHash := newPvtKVWriteAndHash(key, value)
   115  	b.getOrCreateCollPvtRwBuilder(ns, coll).writeMap[key] = kvWrite
   116  	b.getOrCreateCollHashedRwBuilder(ns, coll).writeMap[key] = kvWriteHash
   117  }
   118  
   119  // AddToHashedMetadataWriteSet adds a metadata to a key in the hashed write-set
   120  func (b *RWSetBuilder) AddToHashedMetadataWriteSet(ns, coll, key string, metadata map[string][]byte) {
   121  	// pvt write set just need the key; not the entire metadata. The metadata is stored only
   122  	// by the hashed key. Pvt write-set need to know the key for handling a special case where only
   123  	// metadata is updated so, the version of the key present in the pvt data should be incremented
   124  	b.getOrCreateCollPvtRwBuilder(ns, coll).
   125  		metadataWriteMap[key] = &kvrwset.KVMetadataWrite{Key: key, Entries: nil}
   126  	b.getOrCreateCollHashedRwBuilder(ns, coll).
   127  		metadataWriteMap[key] = mapToMetadataWriteHash(key, metadata)
   128  }
   129  
   130  // GetTxSimulationResults returns the proto bytes of public rwset
   131  // (public data + hashes of private data) and the private rwset for the transaction
   132  func (b *RWSetBuilder) GetTxSimulationResults() (*ledger.TxSimulationResults, error) {
   133  	pvtData := b.getTxPvtReadWriteSet()
   134  	var err error
   135  
   136  	var pubDataProto *rwset.TxReadWriteSet
   137  	var pvtDataProto *rwset.TxPvtReadWriteSet
   138  
   139  	// Populate the collection-level hashes into pub rwset and compute the proto bytes for pvt rwset
   140  	if pvtData != nil {
   141  		if pvtDataProto, err = pvtData.toProtoMsg(); err != nil {
   142  			return nil, err
   143  		}
   144  		for _, ns := range pvtDataProto.NsPvtRwset {
   145  			for _, coll := range ns.CollectionPvtRwset {
   146  				b.setPvtCollectionHash(ns.Namespace, coll.CollectionName, coll.Rwset)
   147  			}
   148  		}
   149  	}
   150  	// Compute the proto bytes for pub rwset
   151  	pubSet := b.GetTxReadWriteSet()
   152  	if pubSet != nil {
   153  		if pubDataProto, err = pubSet.toProtoMsg(); err != nil {
   154  			return nil, err
   155  		}
   156  	}
   157  	return &ledger.TxSimulationResults{
   158  		PubSimulationResults: pubDataProto,
   159  		PvtSimulationResults: pvtDataProto,
   160  	}, nil
   161  }
   162  
   163  func (b *RWSetBuilder) setPvtCollectionHash(ns string, coll string, pvtDataProto []byte) {
   164  	collHashedBuilder := b.getOrCreateCollHashedRwBuilder(ns, coll)
   165  	collHashedBuilder.pvtDataHash = util.ComputeHash(pvtDataProto)
   166  }
   167  
   168  // GetTxReadWriteSet returns the read-write set
   169  // TODO make this function private once txmgr starts using new function `GetTxSimulationResults` introduced here
   170  func (b *RWSetBuilder) GetTxReadWriteSet() *TxRwSet {
   171  	sortedNsPubBuilders := []*nsPubRwBuilder{}
   172  	util.GetValuesBySortedKeys(&(b.pubRwBuilderMap), &sortedNsPubBuilders)
   173  
   174  	var nsPubRwSets []*NsRwSet
   175  	for _, nsPubRwBuilder := range sortedNsPubBuilders {
   176  		nsPubRwSets = append(nsPubRwSets, nsPubRwBuilder.build())
   177  	}
   178  	return &TxRwSet{NsRwSets: nsPubRwSets}
   179  }
   180  
   181  // getTxPvtReadWriteSet returns the private read-write set
   182  func (b *RWSetBuilder) getTxPvtReadWriteSet() *TxPvtRwSet {
   183  	sortedNsPvtBuilders := []*nsPvtRwBuilder{}
   184  	util.GetValuesBySortedKeys(&(b.pvtRwBuilderMap), &sortedNsPvtBuilders)
   185  
   186  	var nsPvtRwSets []*NsPvtRwSet
   187  	for _, nsPvtRwBuilder := range sortedNsPvtBuilders {
   188  		nsPvtRwSets = append(nsPvtRwSets, nsPvtRwBuilder.build())
   189  	}
   190  	if len(nsPvtRwSets) == 0 {
   191  		return nil
   192  	}
   193  	return &TxPvtRwSet{NsPvtRwSet: nsPvtRwSets}
   194  }
   195  
   196  func (b *nsPubRwBuilder) build() *NsRwSet {
   197  	var readSet []*kvrwset.KVRead
   198  	var writeSet []*kvrwset.KVWrite
   199  	var metadataWriteSet []*kvrwset.KVMetadataWrite
   200  	var rangeQueriesInfo []*kvrwset.RangeQueryInfo
   201  	var collHashedRwSet []*CollHashedRwSet
   202  	//add read set
   203  	util.GetValuesBySortedKeys(&(b.readMap), &readSet)
   204  	//add write set
   205  	util.GetValuesBySortedKeys(&(b.writeMap), &writeSet)
   206  	util.GetValuesBySortedKeys(&(b.metadataWriteMap), &metadataWriteSet)
   207  	//add range query info
   208  	for _, key := range b.rangeQueriesKeys {
   209  		rangeQueriesInfo = append(rangeQueriesInfo, b.rangeQueriesMap[key])
   210  	}
   211  	// add hashed rws for private collections
   212  	sortedCollBuilders := []*collHashRwBuilder{}
   213  	util.GetValuesBySortedKeys(&(b.collHashRwBuilder), &sortedCollBuilders)
   214  	for _, collBuilder := range sortedCollBuilders {
   215  		collHashedRwSet = append(collHashedRwSet, collBuilder.build())
   216  	}
   217  	return &NsRwSet{
   218  		NameSpace: b.namespace,
   219  		KvRwSet: &kvrwset.KVRWSet{
   220  			Reads:            readSet,
   221  			Writes:           writeSet,
   222  			MetadataWrites:   metadataWriteSet,
   223  			RangeQueriesInfo: rangeQueriesInfo,
   224  		},
   225  		CollHashedRwSets: collHashedRwSet,
   226  	}
   227  }
   228  
   229  func (b *nsPvtRwBuilder) build() *NsPvtRwSet {
   230  	sortedCollBuilders := []*collPvtRwBuilder{}
   231  	util.GetValuesBySortedKeys(&(b.collPvtRwBuilders), &sortedCollBuilders)
   232  
   233  	var collPvtRwSets []*CollPvtRwSet
   234  	for _, collBuilder := range sortedCollBuilders {
   235  		collPvtRwSets = append(collPvtRwSets, collBuilder.build())
   236  	}
   237  	return &NsPvtRwSet{NameSpace: b.namespace, CollPvtRwSets: collPvtRwSets}
   238  }
   239  
   240  func (b *collHashRwBuilder) build() *CollHashedRwSet {
   241  	var readSet []*kvrwset.KVReadHash
   242  	var writeSet []*kvrwset.KVWriteHash
   243  	var metadataWriteSet []*kvrwset.KVMetadataWriteHash
   244  
   245  	util.GetValuesBySortedKeys(&(b.readMap), &readSet)
   246  	util.GetValuesBySortedKeys(&(b.writeMap), &writeSet)
   247  	util.GetValuesBySortedKeys(&(b.metadataWriteMap), &metadataWriteSet)
   248  	return &CollHashedRwSet{
   249  		CollectionName: b.collName,
   250  		HashedRwSet: &kvrwset.HashedRWSet{
   251  			HashedReads:    readSet,
   252  			HashedWrites:   writeSet,
   253  			MetadataWrites: metadataWriteSet,
   254  		},
   255  		PvtRwSetHash: b.pvtDataHash,
   256  	}
   257  }
   258  
   259  func (b *collPvtRwBuilder) build() *CollPvtRwSet {
   260  	var writeSet []*kvrwset.KVWrite
   261  	var metadataWriteSet []*kvrwset.KVMetadataWrite
   262  	util.GetValuesBySortedKeys(&(b.writeMap), &writeSet)
   263  	util.GetValuesBySortedKeys(&(b.metadataWriteMap), &metadataWriteSet)
   264  	return &CollPvtRwSet{
   265  		CollectionName: b.collectionName,
   266  		KvRwSet: &kvrwset.KVRWSet{
   267  			Writes:         writeSet,
   268  			MetadataWrites: metadataWriteSet,
   269  		},
   270  	}
   271  }
   272  
   273  func (b *RWSetBuilder) getOrCreateNsPubRwBuilder(ns string) *nsPubRwBuilder {
   274  	nsPubRwBuilder, ok := b.pubRwBuilderMap[ns]
   275  	if !ok {
   276  		nsPubRwBuilder = newNsPubRwBuilder(ns)
   277  		b.pubRwBuilderMap[ns] = nsPubRwBuilder
   278  	}
   279  	return nsPubRwBuilder
   280  }
   281  
   282  func (b *RWSetBuilder) getOrCreateNsPvtRwBuilder(ns string) *nsPvtRwBuilder {
   283  	nsPvtRwBuilder, ok := b.pvtRwBuilderMap[ns]
   284  	if !ok {
   285  		nsPvtRwBuilder = newNsPvtRwBuilder(ns)
   286  		b.pvtRwBuilderMap[ns] = nsPvtRwBuilder
   287  	}
   288  	return nsPvtRwBuilder
   289  }
   290  
   291  func (b *RWSetBuilder) getOrCreateCollHashedRwBuilder(ns string, coll string) *collHashRwBuilder {
   292  	nsPubRwBuilder := b.getOrCreateNsPubRwBuilder(ns)
   293  	collHashRwBuilder, ok := nsPubRwBuilder.collHashRwBuilder[coll]
   294  	if !ok {
   295  		collHashRwBuilder = newCollHashRwBuilder(coll)
   296  		nsPubRwBuilder.collHashRwBuilder[coll] = collHashRwBuilder
   297  	}
   298  	return collHashRwBuilder
   299  }
   300  
   301  func (b *RWSetBuilder) getOrCreateCollPvtRwBuilder(ns string, coll string) *collPvtRwBuilder {
   302  	nsPvtRwBuilder := b.getOrCreateNsPvtRwBuilder(ns)
   303  	collPvtRwBuilder, ok := nsPvtRwBuilder.collPvtRwBuilders[coll]
   304  	if !ok {
   305  		collPvtRwBuilder = newCollPvtRwBuilder(coll)
   306  		nsPvtRwBuilder.collPvtRwBuilders[coll] = collPvtRwBuilder
   307  	}
   308  	return collPvtRwBuilder
   309  }
   310  
   311  func newNsPubRwBuilder(namespace string) *nsPubRwBuilder {
   312  	return &nsPubRwBuilder{
   313  		namespace,
   314  		make(map[string]*kvrwset.KVRead),
   315  		make(map[string]*kvrwset.KVWrite),
   316  		make(map[string]*kvrwset.KVMetadataWrite),
   317  		make(map[rangeQueryKey]*kvrwset.RangeQueryInfo),
   318  		nil,
   319  		make(map[string]*collHashRwBuilder),
   320  	}
   321  }
   322  
   323  func newNsPvtRwBuilder(namespace string) *nsPvtRwBuilder {
   324  	return &nsPvtRwBuilder{namespace, make(map[string]*collPvtRwBuilder)}
   325  }
   326  
   327  func newCollHashRwBuilder(collName string) *collHashRwBuilder {
   328  	return &collHashRwBuilder{
   329  		collName,
   330  		make(map[string]*kvrwset.KVReadHash),
   331  		make(map[string]*kvrwset.KVWriteHash),
   332  		make(map[string]*kvrwset.KVMetadataWriteHash),
   333  		nil,
   334  	}
   335  }
   336  
   337  func newCollPvtRwBuilder(collName string) *collPvtRwBuilder {
   338  	return &collPvtRwBuilder{
   339  		collName,
   340  		make(map[string]*kvrwset.KVWrite),
   341  		make(map[string]*kvrwset.KVMetadataWrite),
   342  	}
   343  }
   344  
   345  func mapToMetadataWrite(key string, m map[string][]byte) *kvrwset.KVMetadataWrite {
   346  	proto := &kvrwset.KVMetadataWrite{Key: key}
   347  	names := util.GetSortedKeys(m)
   348  	for _, name := range names {
   349  		proto.Entries = append(proto.Entries,
   350  			&kvrwset.KVMetadataEntry{Name: name, Value: m[name]},
   351  		)
   352  	}
   353  	return proto
   354  }
   355  
   356  func mapToMetadataWriteHash(key string, m map[string][]byte) *kvrwset.KVMetadataWriteHash {
   357  	proto := &kvrwset.KVMetadataWriteHash{KeyHash: util.ComputeStringHash(key)}
   358  	names := util.GetSortedKeys(m)
   359  	for _, name := range names {
   360  		proto.Entries = append(proto.Entries,
   361  			&kvrwset.KVMetadataEntry{Name: name, Value: m[name]},
   362  		)
   363  	}
   364  	return proto
   365  }