github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/core/ledger/kvledger/hashcheck_pvtdata.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package kvledger
     8  
     9  import (
    10  	"bytes"
    11  
    12  	"github.com/hyperledger/fabric-protos-go/ledger/rwset"
    13  	"github.com/hyperledger/fabric/common/util"
    14  	"github.com/hyperledger/fabric/core/ledger"
    15  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
    16  	"github.com/hyperledger/fabric/core/ledger/ledgerstorage"
    17  	"github.com/hyperledger/fabric/protoutil"
    18  )
    19  
    20  // constructValidAndInvalidPvtData computes the valid pvt data and hash mismatch list
    21  // from a received pvt data list of old blocks.
    22  func constructValidAndInvalidPvtData(reconciledPvtdata []*ledger.ReconciledPvtdata, blockStore *ledgerstorage.Store) (
    23  	map[uint64][]*ledger.TxPvtData, []*ledger.PvtdataHashMismatch, error,
    24  ) {
    25  	// for each block, for each transaction, retrieve the txEnvelope to
    26  	// compare the hash of pvtRwSet in the block and the hash of the received
    27  	// txPvtData. On a mismatch, add an entry to hashMismatch list.
    28  	// On a match, add the pvtData to the validPvtData list
    29  	validPvtData := make(map[uint64][]*ledger.TxPvtData)
    30  	var invalidPvtData []*ledger.PvtdataHashMismatch
    31  
    32  	for _, pvtdata := range reconciledPvtdata {
    33  		validData, invalidData, err := findValidAndInvalidPvtdata(pvtdata, blockStore)
    34  		if err != nil {
    35  			return nil, nil, err
    36  		}
    37  		if len(validData) > 0 {
    38  			validPvtData[pvtdata.BlockNum] = validData
    39  		}
    40  		invalidPvtData = append(invalidPvtData, invalidData...)
    41  	} // for each block's pvtData
    42  	return validPvtData, invalidPvtData, nil
    43  }
    44  
    45  func findValidAndInvalidPvtdata(reconciledPvtdata *ledger.ReconciledPvtdata, blockStore *ledgerstorage.Store) (
    46  	[]*ledger.TxPvtData, []*ledger.PvtdataHashMismatch, error,
    47  ) {
    48  	var validPvtData []*ledger.TxPvtData
    49  	var invalidPvtData []*ledger.PvtdataHashMismatch
    50  	for _, txPvtData := range reconciledPvtdata.WriteSets {
    51  		// (1) retrieve the txrwset from the blockstore
    52  		logger.Debugf("Retrieving rwset of blockNum:[%d], txNum:[%d]", reconciledPvtdata.BlockNum, txPvtData.SeqInBlock)
    53  		txRWSet, err := retrieveRwsetForTx(reconciledPvtdata.BlockNum, txPvtData.SeqInBlock, blockStore)
    54  		if err != nil {
    55  			return nil, nil, err
    56  		}
    57  
    58  		// (2) validate passed pvtData against the pvtData hash in the tx rwset.
    59  		logger.Debugf("Constructing valid and invalid pvtData using rwset of blockNum:[%d], txNum:[%d]",
    60  			reconciledPvtdata.BlockNum, txPvtData.SeqInBlock)
    61  		validData, invalidData := findValidAndInvalidTxPvtData(txPvtData, txRWSet, reconciledPvtdata.BlockNum)
    62  
    63  		// (3) append validData to validPvtDataPvt list of this block and
    64  		// invalidData to invalidPvtData list
    65  		if validData != nil {
    66  			validPvtData = append(validPvtData, validData)
    67  		}
    68  		invalidPvtData = append(invalidPvtData, invalidData...)
    69  	} // for each tx's pvtData
    70  	return validPvtData, invalidPvtData, nil
    71  }
    72  
    73  func retrieveRwsetForTx(blkNum uint64, txNum uint64, blockStore *ledgerstorage.Store) (*rwsetutil.TxRwSet, error) {
    74  	// retrieve the txEnvelope from the block store so that the hash of
    75  	// the pvtData can be retrieved for comparison
    76  	txEnvelope, err := blockStore.RetrieveTxByBlockNumTranNum(blkNum, txNum)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  	// retrieve pvtRWset hash from the txEnvelope
    81  	responsePayload, err := protoutil.GetActionFromEnvelopeMsg(txEnvelope)
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  	txRWSet := &rwsetutil.TxRwSet{}
    86  	if err := txRWSet.FromProtoBytes(responsePayload.Results); err != nil {
    87  		return nil, err
    88  	}
    89  	return txRWSet, nil
    90  }
    91  
    92  func findValidAndInvalidTxPvtData(txPvtData *ledger.TxPvtData, txRWSet *rwsetutil.TxRwSet, blkNum uint64) (
    93  	*ledger.TxPvtData, []*ledger.PvtdataHashMismatch,
    94  ) {
    95  	var invalidPvtData []*ledger.PvtdataHashMismatch
    96  	var toDeleteNsColl []*nsColl
    97  	// Compare the hash of pvtData with the hash present in the rwset to
    98  	// find valid and invalid pvt data
    99  	for _, nsRwset := range txPvtData.WriteSet.NsPvtRwset {
   100  		txNum := txPvtData.SeqInBlock
   101  		invalidData, invalidNsColl := findInvalidNsPvtData(nsRwset, txRWSet, blkNum, txNum)
   102  		invalidPvtData = append(invalidPvtData, invalidData...)
   103  		toDeleteNsColl = append(toDeleteNsColl, invalidNsColl...)
   104  	}
   105  	for _, nsColl := range toDeleteNsColl {
   106  		removeCollFromTxPvtReadWriteSet(txPvtData.WriteSet, nsColl.ns, nsColl.coll)
   107  	}
   108  	if len(txPvtData.WriteSet.NsPvtRwset) == 0 {
   109  		// denotes that all namespaces had
   110  		// invalid pvt data
   111  		return nil, invalidPvtData
   112  	}
   113  	return txPvtData, invalidPvtData
   114  }
   115  
   116  // Remove removes the rwset for the given <ns, coll> tuple. If after this removal,
   117  // there are no more collection in the namespace <ns>, the whole namespace entry is removed
   118  func removeCollFromTxPvtReadWriteSet(p *rwset.TxPvtReadWriteSet, ns, coll string) {
   119  	for i := 0; i < len(p.NsPvtRwset); i++ {
   120  		n := p.NsPvtRwset[i]
   121  		if n.Namespace != ns {
   122  			continue
   123  		}
   124  		removeCollFromNsPvtWriteSet(n, coll)
   125  		if len(n.CollectionPvtRwset) == 0 {
   126  			p.NsPvtRwset = append(p.NsPvtRwset[:i], p.NsPvtRwset[i+1:]...)
   127  		}
   128  		return
   129  	}
   130  }
   131  
   132  func removeCollFromNsPvtWriteSet(n *rwset.NsPvtReadWriteSet, collName string) {
   133  	for i := 0; i < len(n.CollectionPvtRwset); i++ {
   134  		c := n.CollectionPvtRwset[i]
   135  		if c.CollectionName != collName {
   136  			continue
   137  		}
   138  		n.CollectionPvtRwset = append(n.CollectionPvtRwset[:i], n.CollectionPvtRwset[i+1:]...)
   139  		return
   140  	}
   141  }
   142  
   143  type nsColl struct {
   144  	ns, coll string
   145  }
   146  
   147  func findInvalidNsPvtData(nsRwset *rwset.NsPvtReadWriteSet, txRWSet *rwsetutil.TxRwSet, blkNum, txNum uint64) (
   148  	[]*ledger.PvtdataHashMismatch, []*nsColl,
   149  ) {
   150  	var invalidPvtData []*ledger.PvtdataHashMismatch
   151  	var invalidNsColl []*nsColl
   152  
   153  	ns := nsRwset.Namespace
   154  	for _, collPvtRwset := range nsRwset.CollectionPvtRwset {
   155  		coll := collPvtRwset.CollectionName
   156  		rwsetHash := txRWSet.GetPvtDataHash(ns, coll)
   157  		if rwsetHash == nil {
   158  			logger.Warningf("namespace: %s collection: %s was not accessed by txNum %d in BlkNum %d. "+
   159  				"Unnecessary pvtdata has been passed", ns, coll, txNum, blkNum)
   160  			invalidNsColl = append(invalidNsColl, &nsColl{ns, coll})
   161  			continue
   162  		}
   163  
   164  		if !bytes.Equal(util.ComputeSHA256(collPvtRwset.Rwset), rwsetHash) {
   165  			invalidPvtData = append(invalidPvtData, &ledger.PvtdataHashMismatch{
   166  				BlockNum:     blkNum,
   167  				TxNum:        txNum,
   168  				Namespace:    ns,
   169  				Collection:   coll,
   170  				ExpectedHash: rwsetHash})
   171  			invalidNsColl = append(invalidNsColl, &nsColl{ns, coll})
   172  		}
   173  	}
   174  	return invalidPvtData, invalidNsColl
   175  }