github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/core/transientstore/store_helper.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package transientstore
     8  
     9  import (
    10  	"bytes"
    11  	"errors"
    12  
    13  	"github.com/hyperledger/fabric-protos-go/ledger/rwset"
    14  	"github.com/hyperledger/fabric-protos-go/peer"
    15  	"github.com/hyperledger/fabric/common/ledger/util"
    16  	"github.com/hyperledger/fabric/core/ledger"
    17  )
    18  
    19  var (
    20  	prwsetPrefix             = []byte("P")[0] // key prefix for storing private write set in transient store.
    21  	purgeIndexByHeightPrefix = []byte("H")[0] // key prefix for storing index on private write set using received at block height.
    22  	purgeIndexByTxidPrefix   = []byte("T")[0] // key prefix for storing index on private write set using txid
    23  	compositeKeySep          = byte(0x00)
    24  )
    25  
    26  // createCompositeKeyForPvtRWSet creates a key for storing private write set
    27  // in the transient store. The structure of the key is <prwsetPrefix>~txid~uuid~blockHeight.
    28  func createCompositeKeyForPvtRWSet(txid string, uuid string, blockHeight uint64) []byte {
    29  	var compositeKey []byte
    30  	compositeKey = append(compositeKey, prwsetPrefix)
    31  	compositeKey = append(compositeKey, compositeKeySep)
    32  	compositeKey = append(compositeKey, createCompositeKeyWithoutPrefixForTxid(txid, uuid, blockHeight)...)
    33  
    34  	return compositeKey
    35  }
    36  
    37  // createCompositeKeyForPurgeIndexByTxid creates a key to index private write set based on
    38  // txid such that purge based on txid can be achieved. The structure
    39  // of the key is <purgeIndexByTxidPrefix>~txid~uuid~blockHeight.
    40  func createCompositeKeyForPurgeIndexByTxid(txid string, uuid string, blockHeight uint64) []byte {
    41  	var compositeKey []byte
    42  	compositeKey = append(compositeKey, purgeIndexByTxidPrefix)
    43  	compositeKey = append(compositeKey, compositeKeySep)
    44  	compositeKey = append(compositeKey, createCompositeKeyWithoutPrefixForTxid(txid, uuid, blockHeight)...)
    45  
    46  	return compositeKey
    47  }
    48  
    49  // createCompositeKeyWithoutPrefixForTxid creates a composite key of structure txid~uuid~blockHeight.
    50  func createCompositeKeyWithoutPrefixForTxid(txid string, uuid string, blockHeight uint64) []byte {
    51  	var compositeKey []byte
    52  	compositeKey = append(compositeKey, []byte(txid)...)
    53  	compositeKey = append(compositeKey, compositeKeySep)
    54  	compositeKey = append(compositeKey, []byte(uuid)...)
    55  	compositeKey = append(compositeKey, compositeKeySep)
    56  	compositeKey = append(compositeKey, util.EncodeOrderPreservingVarUint64(blockHeight)...)
    57  
    58  	return compositeKey
    59  }
    60  
    61  // createCompositeKeyForPurgeIndexByHeight creates a key to index private write set based on
    62  // received at block height such that purge based on block height can be achieved. The structure
    63  // of the key is <purgeIndexByHeightPrefix>~blockHeight~txid~uuid.
    64  func createCompositeKeyForPurgeIndexByHeight(blockHeight uint64, txid string, uuid string) []byte {
    65  	var compositeKey []byte
    66  	compositeKey = append(compositeKey, purgeIndexByHeightPrefix)
    67  	compositeKey = append(compositeKey, compositeKeySep)
    68  	compositeKey = append(compositeKey, util.EncodeOrderPreservingVarUint64(blockHeight)...)
    69  	compositeKey = append(compositeKey, compositeKeySep)
    70  	compositeKey = append(compositeKey, []byte(txid)...)
    71  	compositeKey = append(compositeKey, compositeKeySep)
    72  	compositeKey = append(compositeKey, []byte(uuid)...)
    73  
    74  	return compositeKey
    75  }
    76  
    77  // splitCompositeKeyOfPvtRWSet splits the compositeKey (<prwsetPrefix>~txid~uuid~blockHeight)
    78  // into uuid and blockHeight.
    79  func splitCompositeKeyOfPvtRWSet(compositeKey []byte) (uuid string, blockHeight uint64, err error) {
    80  	return splitCompositeKeyWithoutPrefixForTxid(compositeKey[2:])
    81  }
    82  
    83  // splitCompositeKeyOfPurgeIndexByTxid splits the compositeKey (<purgeIndexByTxidPrefix>~txid~uuid~blockHeight)
    84  // into uuid and blockHeight.
    85  func splitCompositeKeyOfPurgeIndexByTxid(compositeKey []byte) (uuid string, blockHeight uint64, err error) {
    86  	return splitCompositeKeyWithoutPrefixForTxid(compositeKey[2:])
    87  }
    88  
    89  // splitCompositeKeyOfPurgeIndexByHeight splits the compositeKey (<purgeIndexByHeightPrefix>~blockHeight~txid~uuid)
    90  // into txid, uuid and blockHeight.
    91  func splitCompositeKeyOfPurgeIndexByHeight(compositeKey []byte) (txid string, uuid string, blockHeight uint64, err error) {
    92  	var n int
    93  	blockHeight, n, err = util.DecodeOrderPreservingVarUint64(compositeKey[2:])
    94  	if err != nil {
    95  		return
    96  	}
    97  	splits := bytes.Split(compositeKey[n+3:], []byte{compositeKeySep})
    98  	txid = string(splits[0])
    99  	uuid = string(splits[1])
   100  	return
   101  }
   102  
   103  // splitCompositeKeyWithoutPrefixForTxid splits the composite key txid~uuid~blockHeight into
   104  // uuid and blockHeight
   105  func splitCompositeKeyWithoutPrefixForTxid(compositeKey []byte) (uuid string, blockHeight uint64, err error) {
   106  	// skip txid as all functions which requires split of composite key already has it
   107  	firstSepIndex := bytes.IndexByte(compositeKey, compositeKeySep)
   108  	secondSepIndex := firstSepIndex + bytes.IndexByte(compositeKey[firstSepIndex+1:], compositeKeySep) + 1
   109  	uuid = string(compositeKey[firstSepIndex+1 : secondSepIndex])
   110  	blockHeight, _, err = util.DecodeOrderPreservingVarUint64(compositeKey[secondSepIndex+1:])
   111  	return
   112  }
   113  
   114  // createTxidRangeStartKey returns a startKey to do a range query on transient store using txid
   115  func createTxidRangeStartKey(txid string) []byte {
   116  	var startKey []byte
   117  	startKey = append(startKey, prwsetPrefix)
   118  	startKey = append(startKey, compositeKeySep)
   119  	startKey = append(startKey, []byte(txid)...)
   120  	startKey = append(startKey, compositeKeySep)
   121  	return startKey
   122  }
   123  
   124  // createTxidRangeEndKey returns a endKey to do a range query on transient store using txid
   125  func createTxidRangeEndKey(txid string) []byte {
   126  	var endKey []byte
   127  	endKey = append(endKey, prwsetPrefix)
   128  	endKey = append(endKey, compositeKeySep)
   129  	endKey = append(endKey, []byte(txid)...)
   130  	// As txid is a fixed length string (i.e., 128 bits long UUID), 0xff can be used as a stopper.
   131  	// Otherwise a super-string of a given txid would also fall under the end key of range query.
   132  	endKey = append(endKey, byte(0xff))
   133  	return endKey
   134  }
   135  
   136  // createPurgeIndexByHeightRangeStartKey returns a startKey to do a range query on index stored in transient store
   137  // using blockHeight
   138  func createPurgeIndexByHeightRangeStartKey(blockHeight uint64) []byte {
   139  	var startKey []byte
   140  	startKey = append(startKey, purgeIndexByHeightPrefix)
   141  	startKey = append(startKey, compositeKeySep)
   142  	startKey = append(startKey, util.EncodeOrderPreservingVarUint64(blockHeight)...)
   143  	startKey = append(startKey, compositeKeySep)
   144  	return startKey
   145  }
   146  
   147  // createPurgeIndexByHeightRangeEndKey returns a endKey to do a range query on index stored in transient store
   148  // using blockHeight
   149  func createPurgeIndexByHeightRangeEndKey(blockHeight uint64) []byte {
   150  	var endKey []byte
   151  	endKey = append(endKey, purgeIndexByHeightPrefix)
   152  	endKey = append(endKey, compositeKeySep)
   153  	endKey = append(endKey, util.EncodeOrderPreservingVarUint64(blockHeight)...)
   154  	endKey = append(endKey, byte(0xff))
   155  	return endKey
   156  }
   157  
   158  // createPurgeIndexByTxidRangeStartKey returns a startKey to do a range query on index stored in transient store
   159  // using txid
   160  func createPurgeIndexByTxidRangeStartKey(txid string) []byte {
   161  	var startKey []byte
   162  	startKey = append(startKey, purgeIndexByTxidPrefix)
   163  	startKey = append(startKey, compositeKeySep)
   164  	startKey = append(startKey, []byte(txid)...)
   165  	startKey = append(startKey, compositeKeySep)
   166  	return startKey
   167  }
   168  
   169  // createPurgeIndexByTxidRangeEndKey returns a endKey to do a range query on index stored in transient store
   170  // using txid
   171  func createPurgeIndexByTxidRangeEndKey(txid string) []byte {
   172  	var endKey []byte
   173  	endKey = append(endKey, purgeIndexByTxidPrefix)
   174  	endKey = append(endKey, compositeKeySep)
   175  	endKey = append(endKey, []byte(txid)...)
   176  	// As txid is a fixed length string (i.e., 128 bits long UUID), 0xff can be used as a stopper.
   177  	// Otherwise a super-string of a given txid would also fall under the end key of range query.
   178  	endKey = append(endKey, byte(0xff))
   179  	return endKey
   180  }
   181  
   182  // trimPvtWSet returns a `TxPvtReadWriteSet` that retains only list of 'ns/collections' supplied in the filter
   183  // A nil filter does not filter any results and returns the original `pvtWSet` as is
   184  func trimPvtWSet(pvtWSet *rwset.TxPvtReadWriteSet, filter ledger.PvtNsCollFilter) *rwset.TxPvtReadWriteSet {
   185  	if filter == nil {
   186  		return pvtWSet
   187  	}
   188  
   189  	var filteredNsRwSet []*rwset.NsPvtReadWriteSet
   190  	for _, ns := range pvtWSet.NsPvtRwset {
   191  		var filteredCollRwSet []*rwset.CollectionPvtReadWriteSet
   192  		for _, coll := range ns.CollectionPvtRwset {
   193  			if filter.Has(ns.Namespace, coll.CollectionName) {
   194  				filteredCollRwSet = append(filteredCollRwSet, coll)
   195  			}
   196  		}
   197  		if filteredCollRwSet != nil {
   198  			filteredNsRwSet = append(filteredNsRwSet,
   199  				&rwset.NsPvtReadWriteSet{
   200  					Namespace:          ns.Namespace,
   201  					CollectionPvtRwset: filteredCollRwSet,
   202  				},
   203  			)
   204  		}
   205  	}
   206  	var filteredTxPvtRwSet *rwset.TxPvtReadWriteSet
   207  	if filteredNsRwSet != nil {
   208  		filteredTxPvtRwSet = &rwset.TxPvtReadWriteSet{
   209  			DataModel:  pvtWSet.GetDataModel(),
   210  			NsPvtRwset: filteredNsRwSet,
   211  		}
   212  	}
   213  	return filteredTxPvtRwSet
   214  }
   215  
   216  func trimPvtCollectionConfigs(configs map[string]*peer.CollectionConfigPackage,
   217  	filter ledger.PvtNsCollFilter) (map[string]*peer.CollectionConfigPackage, error) {
   218  	if filter == nil {
   219  		return configs, nil
   220  	}
   221  	result := make(map[string]*peer.CollectionConfigPackage)
   222  
   223  	for ns, pkg := range configs {
   224  		result[ns] = &peer.CollectionConfigPackage{}
   225  		for _, colConf := range pkg.GetConfig() {
   226  			switch cconf := colConf.Payload.(type) {
   227  			case *peer.CollectionConfig_StaticCollectionConfig:
   228  				if filter.Has(ns, cconf.StaticCollectionConfig.Name) {
   229  					result[ns].Config = append(result[ns].Config, colConf)
   230  				}
   231  			default:
   232  				return nil, errors.New("unexpected collection type")
   233  			}
   234  		}
   235  	}
   236  	return result, nil
   237  }