github.com/Hnampk/fabric@v2.1.1+incompatible/core/ledger/kvledger/txmgmt/validator/statebasedval/range_query_validator.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package statebasedval
     8  
     9  import (
    10  	"bytes"
    11  
    12  	"github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset"
    13  	"github.com/hyperledger/fabric/core/ledger"
    14  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
    15  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/statedb"
    16  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version"
    17  )
    18  
    19  type rangeQueryValidator interface {
    20  	init(rqInfo *kvrwset.RangeQueryInfo, itr statedb.ResultsIterator) error
    21  	validate() (bool, error)
    22  }
    23  
    24  type rangeQueryResultsValidator struct {
    25  	rqInfo *kvrwset.RangeQueryInfo
    26  	itr    statedb.ResultsIterator
    27  }
    28  
    29  func (v *rangeQueryResultsValidator) init(rqInfo *kvrwset.RangeQueryInfo, itr statedb.ResultsIterator) error {
    30  	v.rqInfo = rqInfo
    31  	v.itr = itr
    32  	return nil
    33  }
    34  
    35  // validate iterates through the results that are present in the range-query-info (captured during simulation)
    36  // and the iterator (latest view of the `committed state` i.e., db + updates). At first mismatch between the results
    37  // from the two sources (the range-query-info and the iterator), the validate returns false.
    38  func (v *rangeQueryResultsValidator) validate() (bool, error) {
    39  	rqResults := v.rqInfo.GetRawReads().GetKvReads()
    40  	itr := v.itr
    41  	var result statedb.QueryResult
    42  	var err error
    43  	if result, err = itr.Next(); err != nil {
    44  		return false, err
    45  	}
    46  	if len(rqResults) == 0 {
    47  		return result == nil, nil
    48  	}
    49  	for i := 0; i < len(rqResults); i++ {
    50  		kvRead := rqResults[i]
    51  		logger.Debugf("comparing kvRead=[%#v] to queryResponse=[%#v]", kvRead, result)
    52  		if result == nil {
    53  			logger.Debugf("Query response nil. Key [%s] got deleted", kvRead.Key)
    54  			return false, nil
    55  		}
    56  		versionedKV := result.(*statedb.VersionedKV)
    57  		if versionedKV.Key != kvRead.Key {
    58  			logger.Debugf("key name mismatch: Key in rwset = [%s], key in query results = [%s]", kvRead.Key, versionedKV.Key)
    59  			return false, nil
    60  		}
    61  		if !version.AreSame(versionedKV.Version, convertToVersionHeight(kvRead.Version)) {
    62  			logger.Debugf(`Version mismatch for key [%s]: Version in rwset = [%#v], latest version = [%#v]`,
    63  				versionedKV.Key, versionedKV.Version, kvRead.Version)
    64  			return false, nil
    65  		}
    66  		if result, err = itr.Next(); err != nil {
    67  			return false, err
    68  		}
    69  	}
    70  	if result != nil {
    71  		// iterator is not exhausted - which means that there are extra results in the given range
    72  		logger.Debugf("Extra result = [%#v]", result)
    73  		return false, nil
    74  	}
    75  	return true, nil
    76  }
    77  
    78  type rangeQueryHashValidator struct {
    79  	rqInfo        *kvrwset.RangeQueryInfo
    80  	itr           statedb.ResultsIterator
    81  	resultsHelper *rwsetutil.RangeQueryResultsHelper
    82  	hasher        ledger.Hasher
    83  }
    84  
    85  func (v *rangeQueryHashValidator) init(rqInfo *kvrwset.RangeQueryInfo, itr statedb.ResultsIterator) error {
    86  	v.rqInfo = rqInfo
    87  	v.itr = itr
    88  	var err error
    89  	v.resultsHelper, err = rwsetutil.NewRangeQueryResultsHelper(true, rqInfo.GetReadsMerkleHashes().MaxDegree, v.hasher)
    90  	return err
    91  }
    92  
    93  // validate iterates through the iterator (latest view of the `committed state` i.e., db + updates)
    94  // and starts building the merkle tree incrementally (Both, during simulation and during validation,
    95  // rwset.RangeQueryResultsHelper is used for building the merkle tree incrementally ).
    96  //
    97  // This function also keeps comparing the under-construction merkle tree with the merkle tree
    98  // summary present in the range-query-info (built during simulation).
    99  // This function returns false on first mismatch between the nodes of the two merkle trees
   100  // at the desired level (the maxLevel of the merkle tree in range-query-info).
   101  func (v *rangeQueryHashValidator) validate() (bool, error) {
   102  	itr := v.itr
   103  	lastMatchedIndex := -1
   104  	inMerkle := v.rqInfo.GetReadsMerkleHashes()
   105  	var merkle *kvrwset.QueryReadsMerkleSummary
   106  	logger.Debugf("inMerkle: %#v", inMerkle)
   107  	for {
   108  		var result statedb.QueryResult
   109  		var err error
   110  		if result, err = itr.Next(); err != nil {
   111  			return false, err
   112  		}
   113  		logger.Debugf("Processing result = %#v", result)
   114  		if result == nil {
   115  			if _, merkle, err = v.resultsHelper.Done(); err != nil {
   116  				return false, err
   117  			}
   118  			equals := merkleSummariesEqual(inMerkle, merkle)
   119  			logger.Debugf("Combined iterator exhausted. merkle=%#v, equals=%t", merkle, equals)
   120  			return equals, nil
   121  		}
   122  		versionedKV := result.(*statedb.VersionedKV)
   123  		v.resultsHelper.AddResult(rwsetutil.NewKVRead(versionedKV.Key, versionedKV.Version))
   124  		merkle := v.resultsHelper.GetMerkleSummary()
   125  
   126  		if merkle.MaxLevel < inMerkle.MaxLevel {
   127  			logger.Debugf("Hashes still under construction. Noting to compare yet. Need more results. Continuing...")
   128  			continue
   129  		}
   130  		if lastMatchedIndex == len(merkle.MaxLevelHashes)-1 {
   131  			logger.Debugf("Need more results to build next entry [index=%d] at level [%d]. Continuing...",
   132  				lastMatchedIndex+1, merkle.MaxLevel)
   133  			continue
   134  		}
   135  		if len(merkle.MaxLevelHashes) > len(inMerkle.MaxLevelHashes) {
   136  			logger.Debugf("Entries exceeded from what are present in the incoming merkleSummary. Validation failed")
   137  			return false, nil
   138  		}
   139  		lastMatchedIndex++
   140  		if !bytes.Equal(merkle.MaxLevelHashes[lastMatchedIndex], inMerkle.MaxLevelHashes[lastMatchedIndex]) {
   141  			logger.Debugf("Hashes does not match at index [%d]. Validation failed", lastMatchedIndex)
   142  			return false, nil
   143  		}
   144  	}
   145  }
   146  
   147  func merkleSummariesEqual(ms, anotherMS *kvrwset.QueryReadsMerkleSummary) bool {
   148  	if anotherMS == nil {
   149  		return false
   150  	}
   151  	if ms.MaxDegree != anotherMS.MaxDegree ||
   152  		ms.MaxLevel != anotherMS.MaxLevel ||
   153  		len(ms.MaxLevelHashes) != len(anotherMS.MaxLevelHashes) {
   154  		return false
   155  	}
   156  	for i := 0; i < len(ms.MaxLevelHashes); i++ {
   157  		if !bytes.Equal(ms.MaxLevelHashes[i], anotherMS.MaxLevelHashes[i]) {
   158  			return false
   159  		}
   160  	}
   161  	return true
   162  }
   163  
   164  func convertToVersionHeight(v *kvrwset.Version) *version.Height {
   165  	return version.NewHeight(v.BlockNum, v.TxNum)
   166  }