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