github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/ledger/kvledger/history/query_executer.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package history
     8  
     9  import (
    10  	commonledger "github.com/hechain20/hechain/common/ledger"
    11  	"github.com/hechain20/hechain/common/ledger/blkstorage"
    12  	"github.com/hechain20/hechain/common/ledger/util/leveldbhelper"
    13  	"github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/rwsetutil"
    14  	protoutil "github.com/hechain20/hechain/protoutil"
    15  	"github.com/hyperledger/fabric-protos-go/common"
    16  	"github.com/hyperledger/fabric-protos-go/ledger/queryresult"
    17  	"github.com/pkg/errors"
    18  	"github.com/syndtr/goleveldb/leveldb/iterator"
    19  )
    20  
    21  // QueryExecutor is a query executor against the LevelDB history DB
    22  type QueryExecutor struct {
    23  	levelDB    *leveldbhelper.DBHandle
    24  	blockStore *blkstorage.BlockStore
    25  }
    26  
    27  // GetHistoryForKey implements method in interface `ledger.HistoryQueryExecutor`
    28  func (q *QueryExecutor) GetHistoryForKey(namespace string, key string) (commonledger.ResultsIterator, error) {
    29  	rangeScan := constructRangeScan(namespace, key)
    30  	dbItr, err := q.levelDB.GetIterator(rangeScan.startKey, rangeScan.endKey)
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  
    35  	// By default, dbItr is in the orderer of oldest to newest and its cursor is at the beginning of the entries.
    36  	// Need to call Last() and Next() to move the cursor to the end of the entries so that we can iterate
    37  	// the entries in the order of newest to oldest.
    38  	if dbItr.Last() {
    39  		dbItr.Next()
    40  	}
    41  	return &historyScanner{rangeScan, namespace, key, dbItr, q.blockStore}, nil
    42  }
    43  
    44  // historyScanner implements ResultsIterator for iterating through history results
    45  type historyScanner struct {
    46  	rangeScan  *rangeScan
    47  	namespace  string
    48  	key        string
    49  	dbItr      iterator.Iterator
    50  	blockStore *blkstorage.BlockStore
    51  }
    52  
    53  // Next iterates to the next key, in the order of newest to oldest, from history scanner.
    54  // It decodes blockNumTranNumBytes to get blockNum and tranNum,
    55  // loads the block:tran from block storage, finds the key and returns the result.
    56  func (scanner *historyScanner) Next() (commonledger.QueryResult, error) {
    57  	// call Prev because history query result is returned from newest to oldest
    58  	if !scanner.dbItr.Prev() {
    59  		return nil, nil
    60  	}
    61  
    62  	historyKey := scanner.dbItr.Key()
    63  	blockNum, tranNum, err := scanner.rangeScan.decodeBlockNumTranNum(historyKey)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  	logger.Debugf("Found history record for namespace:%s key:%s at blockNumTranNum %v:%v\n",
    68  		scanner.namespace, scanner.key, blockNum, tranNum)
    69  
    70  	// Get the transaction from block storage that is associated with this history record
    71  	tranEnvelope, err := scanner.blockStore.RetrieveTxByBlockNumTranNum(blockNum, tranNum)
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  
    76  	// Get the txid, key write value, timestamp, and delete indicator associated with this transaction
    77  	queryResult, err := getKeyModificationFromTran(tranEnvelope, scanner.namespace, scanner.key)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  	if queryResult == nil {
    82  		// should not happen, but make sure there is inconsistency between historydb and statedb
    83  		logger.Errorf("No namespace or key is found for namespace %s and key %s with decoded blockNum %d and tranNum %d", scanner.namespace, scanner.key, blockNum, tranNum)
    84  		return nil, errors.Errorf("no namespace or key is found for namespace %s and key %s with decoded blockNum %d and tranNum %d", scanner.namespace, scanner.key, blockNum, tranNum)
    85  	}
    86  	logger.Debugf("Found historic key value for namespace:%s key:%s from transaction %s",
    87  		scanner.namespace, scanner.key, queryResult.(*queryresult.KeyModification).TxId)
    88  	return queryResult, nil
    89  }
    90  
    91  func (scanner *historyScanner) Close() {
    92  	scanner.dbItr.Release()
    93  }
    94  
    95  // getTxIDandKeyWriteValueFromTran inspects a transaction for writes to a given key
    96  func getKeyModificationFromTran(tranEnvelope *common.Envelope, namespace string, key string) (commonledger.QueryResult, error) {
    97  	logger.Debugf("Entering getKeyModificationFromTran %s:%s", namespace, key)
    98  
    99  	// extract action from the envelope
   100  	payload, err := protoutil.UnmarshalPayload(tranEnvelope.Payload)
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  
   105  	tx, err := protoutil.UnmarshalTransaction(payload.Data)
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  
   110  	_, respPayload, err := protoutil.GetPayloads(tx.Actions[0])
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  
   115  	chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  
   120  	txID := chdr.TxId
   121  	timestamp := chdr.Timestamp
   122  
   123  	txRWSet := &rwsetutil.TxRwSet{}
   124  
   125  	// Get the Result from the Action and then Unmarshal
   126  	// it into a TxReadWriteSet using custom unmarshalling
   127  	if err = txRWSet.FromProtoBytes(respPayload.Results); err != nil {
   128  		return nil, err
   129  	}
   130  
   131  	// look for the namespace and key by looping through the transaction's ReadWriteSets
   132  	for _, nsRWSet := range txRWSet.NsRwSets {
   133  		if nsRWSet.NameSpace == namespace {
   134  			// got the correct namespace, now find the key write
   135  			for _, kvWrite := range nsRWSet.KvRwSet.Writes {
   136  				if kvWrite.Key == key {
   137  					return &queryresult.KeyModification{
   138  						TxId: txID, Value: kvWrite.Value,
   139  						Timestamp: timestamp, IsDelete: rwsetutil.IsKVWriteDelete(kvWrite),
   140  					}, nil
   141  				}
   142  			} // end keys loop
   143  			logger.Debugf("key [%s] not found in namespace [%s]'s writeset", key, namespace)
   144  			return nil, nil
   145  		} // end if
   146  	} // end namespaces loop
   147  	logger.Debugf("namespace [%s] not found in transaction's ReadWriteSets", namespace)
   148  	return nil, nil
   149  }