github.com/ewagmig/fabric@v2.1.1+incompatible/core/ledger/kvledger/txmgmt/rwsetutil/query_results_helper.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package rwsetutil
     8  
     9  import (
    10  	"fmt"
    11  
    12  	"github.com/golang/protobuf/proto"
    13  	"github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset"
    14  	"github.com/hyperledger/fabric/bccsp"
    15  	"github.com/hyperledger/fabric/core/ledger"
    16  	"github.com/pkg/errors"
    17  )
    18  
    19  // MerkleTreeLevel used for representing a level of the merkle tree
    20  type MerkleTreeLevel uint32
    21  
    22  // Hash represents bytes of a hash
    23  type Hash []byte
    24  
    25  const (
    26  	leafLevel = MerkleTreeLevel(1)
    27  )
    28  
    29  var (
    30  	hashOpts = &bccsp.SHA256Opts{}
    31  )
    32  
    33  // RangeQueryResultsHelper helps preparing range query results for phantom items detection during validation.
    34  // The results are expected to be fed as they are being iterated over.
    35  // If the `hashingEnabled` is set to true, a merkle tree is built of the hashes over the results.
    36  // The merkle tree helps reducing the size of the RWSet which otherwise would need to store all the raw KVReads
    37  //
    38  // The mental model of the tree can be described as below:
    39  // All the results are treated as leaf nodes (level 0) of the tree. Next up level of the tree is built by collecting 'maxDegree + 1'
    40  // items from the previous level and hashing the entire collection.
    41  // Further upper levels of the tree are built in similar manner however the only difference is that unlike level-0
    42  // (where collection consists of raw KVReads), collection at level 1 and above, consists of the hashes
    43  // (of the collection of previous level).
    44  // This is repeated until we reach at a level where we are left with the number of items less than or equals to `maxDegree`.
    45  // In the last collection, the number of items can be less than 'maxDegree' (except if this is the only collection at the given level).
    46  //
    47  // As a result, if the number of total input results are less than or equals to 'maxDegree', no hashing is performed at all.
    48  // And the final output of the computation is either the collection of raw results (if less that or equals to 'maxDegree') or
    49  // a collection of hashes (that or equals to 'maxDegree') at some level in the tree.
    50  //
    51  // `AddResult` function should be invoke to supply the next result and at the end `Done` function should be invoked.
    52  // The `Done` function does the final processing and returns the final output
    53  type RangeQueryResultsHelper struct {
    54  	pendingResults []*kvrwset.KVRead
    55  	mt             *merkleTree
    56  	maxDegree      uint32
    57  	hashingEnabled bool
    58  	hasher         ledger.Hasher
    59  }
    60  
    61  // NewRangeQueryResultsHelper constructs a RangeQueryResultsHelper
    62  func NewRangeQueryResultsHelper(enableHashing bool, maxDegree uint32, hasher ledger.Hasher) (*RangeQueryResultsHelper, error) {
    63  	helper := &RangeQueryResultsHelper{
    64  		pendingResults: nil,
    65  		hashingEnabled: enableHashing,
    66  		maxDegree:      maxDegree,
    67  		mt:             nil,
    68  		hasher:         hasher,
    69  	}
    70  	if enableHashing {
    71  		var err error
    72  		if helper.mt, err = newMerkleTree(maxDegree, hasher); err != nil {
    73  			return nil, err
    74  		}
    75  	}
    76  	return helper, nil
    77  }
    78  
    79  // AddResult adds a new query result for processing.
    80  // Put the result into the list of pending results. If the number of pending results exceeds `maxDegree`,
    81  // consume the results for incrementally update the merkle tree
    82  func (helper *RangeQueryResultsHelper) AddResult(kvRead *kvrwset.KVRead) error {
    83  	logger.Debug("Adding a result")
    84  	helper.pendingResults = append(helper.pendingResults, kvRead)
    85  	if helper.hashingEnabled && uint32(len(helper.pendingResults)) > helper.maxDegree {
    86  		logger.Debug("Processing the accumulated results")
    87  		if err := helper.processPendingResults(); err != nil {
    88  			return err
    89  		}
    90  	}
    91  	return nil
    92  }
    93  
    94  // Done processes any pending results if needed
    95  // This returns the final pending results (i.e., []*KVRead) and hashes of the results (i.e., *MerkleSummary)
    96  // Only one of these two will be non-nil (except when no results are ever added).
    97  // `MerkleSummary` will be nil if and only if either `enableHashing` is set to false
    98  // or the number of total results are less than `maxDegree`
    99  func (helper *RangeQueryResultsHelper) Done() ([]*kvrwset.KVRead, *kvrwset.QueryReadsMerkleSummary, error) {
   100  	// The merkle tree will be empty if total results are less than or equals to 'maxDegree'
   101  	// i.e., not even once the results were processed for hashing
   102  	if !helper.hashingEnabled || helper.mt.isEmpty() {
   103  		return helper.pendingResults, nil, nil
   104  	}
   105  	if len(helper.pendingResults) != 0 {
   106  		logger.Debug("Processing the pending results")
   107  		if err := helper.processPendingResults(); err != nil {
   108  			return helper.pendingResults, nil, err
   109  		}
   110  	}
   111  	helper.mt.done()
   112  	return helper.pendingResults, helper.mt.getSummery(), nil
   113  }
   114  
   115  // GetMerkleSummary return the current state of the MerkleSummary
   116  // This intermediate state of the merkle tree helps during validation to detect a mismatch early on.
   117  // That helps by not requiring to build the complete merkle tree during validation
   118  // if there is a mismatch in early portion of the result-set.
   119  func (helper *RangeQueryResultsHelper) GetMerkleSummary() *kvrwset.QueryReadsMerkleSummary {
   120  	if !helper.hashingEnabled {
   121  		return nil
   122  	}
   123  	return helper.mt.getSummery()
   124  }
   125  
   126  func (helper *RangeQueryResultsHelper) processPendingResults() error {
   127  	var b []byte
   128  	var err error
   129  	if b, err = serializeKVReads(helper.pendingResults); err != nil {
   130  		return err
   131  	}
   132  	helper.pendingResults = nil
   133  	hash, err := helper.hasher.Hash(b, hashOpts)
   134  	if err != nil {
   135  		return err
   136  	}
   137  	helper.mt.update(hash)
   138  	return nil
   139  }
   140  
   141  func serializeKVReads(kvReads []*kvrwset.KVRead) ([]byte, error) {
   142  	return proto.Marshal(&kvrwset.QueryReads{KvReads: kvReads})
   143  }
   144  
   145  //////////// Merkle tree building code  ///////
   146  
   147  type merkleTree struct {
   148  	tree      map[MerkleTreeLevel][]Hash
   149  	maxLevel  MerkleTreeLevel
   150  	maxDegree uint32
   151  	hasher    ledger.Hasher
   152  }
   153  
   154  func newMerkleTree(maxDegree uint32, hasher ledger.Hasher) (*merkleTree, error) {
   155  	if maxDegree < 2 {
   156  		return nil, errors.Errorf("maxDegree [%d] should not be less than 2 in the merkle tree", maxDegree)
   157  	}
   158  	return &merkleTree{
   159  		make(map[MerkleTreeLevel][]Hash),
   160  		1,
   161  		maxDegree,
   162  		hasher,
   163  	}, nil
   164  }
   165  
   166  // update takes a hash that forms the next leaf level (level-1) node in the merkle tree.
   167  // Also, complete the merkle tree as much as possible with the addition of this new leaf node -
   168  // i.e. recursively build the higher level nodes and delete the underlying sub-tree.
   169  func (m *merkleTree) update(nextLeafLevelHash Hash) error {
   170  	logger.Debugf("Before update() = %s", m)
   171  	defer logger.Debugf("After update() = %s", m)
   172  	m.tree[leafLevel] = append(m.tree[leafLevel], nextLeafLevelHash)
   173  	currentLevel := leafLevel
   174  	for {
   175  		currentLevelHashes := m.tree[currentLevel]
   176  		if uint32(len(currentLevelHashes)) <= m.maxDegree {
   177  			return nil
   178  		}
   179  		nextLevelHash, err := computeCombinedHash(currentLevelHashes, m.hasher)
   180  		if err != nil {
   181  			return err
   182  		}
   183  		delete(m.tree, currentLevel)
   184  		nextLevel := currentLevel + 1
   185  		m.tree[nextLevel] = append(m.tree[nextLevel], nextLevelHash)
   186  		if nextLevel > m.maxLevel {
   187  			m.maxLevel = nextLevel
   188  		}
   189  		currentLevel = nextLevel
   190  	}
   191  }
   192  
   193  // done completes the merkle tree.
   194  // There may have been some nodes that are at the levels lower than the maxLevel (maximum level seen by the tree so far).
   195  // Make the parent nodes out of such nodes till we complete the tree at the level of maxLevel (or maxLevel+1).
   196  func (m *merkleTree) done() error {
   197  	logger.Debugf("Before done() = %s", m)
   198  	defer logger.Debugf("After done() = %s", m)
   199  	currentLevel := leafLevel
   200  	var h Hash
   201  	var err error
   202  	for currentLevel < m.maxLevel {
   203  		currentLevelHashes := m.tree[currentLevel]
   204  		switch len(currentLevelHashes) {
   205  		case 0:
   206  			currentLevel++
   207  			continue
   208  		case 1:
   209  			h = currentLevelHashes[0]
   210  		default:
   211  			if h, err = computeCombinedHash(currentLevelHashes, m.hasher); err != nil {
   212  				return err
   213  			}
   214  		}
   215  		delete(m.tree, currentLevel)
   216  		currentLevel++
   217  		m.tree[currentLevel] = append(m.tree[currentLevel], h)
   218  	}
   219  
   220  	finalHashes := m.tree[m.maxLevel]
   221  	if uint32(len(finalHashes)) > m.maxDegree {
   222  		delete(m.tree, m.maxLevel)
   223  		m.maxLevel++
   224  		combinedHash, err := computeCombinedHash(finalHashes, m.hasher)
   225  		if err != nil {
   226  			return err
   227  		}
   228  		m.tree[m.maxLevel] = []Hash{combinedHash}
   229  	}
   230  	return nil
   231  }
   232  
   233  func (m *merkleTree) getSummery() *kvrwset.QueryReadsMerkleSummary {
   234  	return &kvrwset.QueryReadsMerkleSummary{MaxDegree: m.maxDegree,
   235  		MaxLevel:       uint32(m.getMaxLevel()),
   236  		MaxLevelHashes: hashesToBytes(m.getMaxLevelHashes())}
   237  }
   238  
   239  func (m *merkleTree) getMaxLevel() MerkleTreeLevel {
   240  	return m.maxLevel
   241  }
   242  
   243  func (m *merkleTree) getMaxLevelHashes() []Hash {
   244  	return m.tree[m.maxLevel]
   245  }
   246  
   247  func (m *merkleTree) isEmpty() bool {
   248  	return m.maxLevel == 1 && len(m.tree[m.maxLevel]) == 0
   249  }
   250  
   251  func (m *merkleTree) String() string {
   252  	return fmt.Sprintf("tree := %#v", m.tree)
   253  }
   254  
   255  func computeCombinedHash(hashes []Hash, hasher ledger.Hasher) (Hash, error) {
   256  	combinedHash := []byte{}
   257  	for _, h := range hashes {
   258  		combinedHash = append(combinedHash, h...)
   259  	}
   260  	return hasher.Hash(combinedHash, hashOpts)
   261  }
   262  
   263  func hashesToBytes(hashes []Hash) [][]byte {
   264  	b := [][]byte{}
   265  	for _, hash := range hashes {
   266  		b = append(b, hash)
   267  	}
   268  	return b
   269  }