github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/ledger/kvledger/txmgmt/txmgr/tx_simulator.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package txmgr
     8  
     9  import (
    10  	commonledger "github.com/hechain20/hechain/common/ledger"
    11  	"github.com/hechain20/hechain/core/ledger"
    12  	"github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/rwsetutil"
    13  	"github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/statemetadata"
    14  	"github.com/hechain20/hechain/core/ledger/util"
    15  	"github.com/pkg/errors"
    16  )
    17  
    18  // txSimulator is a transaction simulator used in `LockBasedTxMgr`
    19  type txSimulator struct {
    20  	*queryExecutor
    21  	rwsetBuilder              *rwsetutil.RWSetBuilder
    22  	writePerformed            bool
    23  	pvtdataQueriesPerformed   bool
    24  	simulationResultsComputed bool
    25  	paginatedQueriesPerformed bool
    26  	writesetMetadata          ledger.WritesetMetadata
    27  }
    28  
    29  func newTxSimulator(txmgr *LockBasedTxMgr, txid string, hashFunc rwsetutil.HashFunc) (*txSimulator, error) {
    30  	rwsetBuilder := rwsetutil.NewRWSetBuilder()
    31  	qe := newQueryExecutor(txmgr, txid, rwsetBuilder, true, hashFunc)
    32  	logger.Debugf("constructing new tx simulator txid = [%s]", txid)
    33  	return &txSimulator{qe, rwsetBuilder, false, false, false, false, ledger.WritesetMetadata{}}, nil
    34  }
    35  
    36  // SetState implements method in interface `ledger.TxSimulator`
    37  func (s *txSimulator) SetState(ns string, key string, value []byte) error {
    38  	if err := s.checkWritePrecondition(key, value); err != nil {
    39  		return err
    40  	}
    41  	s.rwsetBuilder.AddToWriteSet(ns, key, value)
    42  	// if this has a key level signature policy, add it to the interest
    43  	return s.checkStateMetadata(ns, key)
    44  }
    45  
    46  // If this key has a SBE policy, add that policy to the set
    47  func (s *txSimulator) checkStateMetadata(ns string, key string) error {
    48  	metabytes, err := s.txmgr.db.GetStateMetadata(ns, key)
    49  	if err != nil {
    50  		return err
    51  	}
    52  	metadata, err := statemetadata.Deserialize(metabytes)
    53  	if err != nil {
    54  		return err
    55  	}
    56  	s.writesetMetadata.Add(ns, "", key, metadata) // empty string represents the public writeset
    57  	return nil
    58  }
    59  
    60  // If this private collection key has a SBE policy, add that policy to the set
    61  func (s *txSimulator) checkPrivateStateMetadata(ns string, coll string, key string) error {
    62  	metabytes, err := s.txmgr.db.GetPrivateDataMetadataByHash(ns, coll, util.ComputeStringHash(key))
    63  	if err != nil {
    64  		return err
    65  	}
    66  	metadata, err := statemetadata.Deserialize(metabytes)
    67  	if err != nil {
    68  		return err
    69  	}
    70  	s.writesetMetadata.Add(ns, coll, key, metadata)
    71  	return nil
    72  }
    73  
    74  // DeleteState implements method in interface `ledger.TxSimulator`
    75  func (s *txSimulator) DeleteState(ns string, key string) error {
    76  	return s.SetState(ns, key, nil)
    77  }
    78  
    79  // SetStateMultipleKeys implements method in interface `ledger.TxSimulator`
    80  func (s *txSimulator) SetStateMultipleKeys(namespace string, kvs map[string][]byte) error {
    81  	for k, v := range kvs {
    82  		if err := s.SetState(namespace, k, v); err != nil {
    83  			return err
    84  		}
    85  	}
    86  	return nil
    87  }
    88  
    89  // SetStateMetadata implements method in interface `ledger.TxSimulator`
    90  func (s *txSimulator) SetStateMetadata(namespace, key string, metadata map[string][]byte) error {
    91  	if err := s.checkWritePrecondition(key, nil); err != nil {
    92  		return err
    93  	}
    94  	s.rwsetBuilder.AddToMetadataWriteSet(namespace, key, metadata)
    95  	return s.checkStateMetadata(namespace, key)
    96  }
    97  
    98  // DeleteStateMetadata implements method in interface `ledger.TxSimulator`
    99  func (s *txSimulator) DeleteStateMetadata(namespace, key string) error {
   100  	return s.SetStateMetadata(namespace, key, nil)
   101  }
   102  
   103  // SetPrivateData implements method in interface `ledger.TxSimulator`
   104  func (s *txSimulator) SetPrivateData(ns, coll, key string, value []byte) error {
   105  	if err := s.queryExecutor.validateCollName(ns, coll); err != nil {
   106  		return err
   107  	}
   108  	if err := s.checkWritePrecondition(key, value); err != nil {
   109  		return err
   110  	}
   111  	s.writePerformed = true
   112  	s.rwsetBuilder.AddToPvtAndHashedWriteSet(ns, coll, key, value)
   113  	return s.checkPrivateStateMetadata(ns, coll, key)
   114  }
   115  
   116  // DeletePrivateData implements method in interface `ledger.TxSimulator`
   117  func (s *txSimulator) DeletePrivateData(ns, coll, key string) error {
   118  	return s.SetPrivateData(ns, coll, key, nil)
   119  }
   120  
   121  // SetPrivateDataMultipleKeys implements method in interface `ledger.TxSimulator`
   122  func (s *txSimulator) SetPrivateDataMultipleKeys(ns, coll string, kvs map[string][]byte) error {
   123  	for k, v := range kvs {
   124  		if err := s.SetPrivateData(ns, coll, k, v); err != nil {
   125  			return err
   126  		}
   127  	}
   128  	return nil
   129  }
   130  
   131  // GetPrivateDataRangeScanIterator implements method in interface `ledger.TxSimulator`
   132  func (s *txSimulator) GetPrivateDataRangeScanIterator(namespace, collection, startKey, endKey string) (commonledger.ResultsIterator, error) {
   133  	if err := s.checkBeforePvtdataQueries(); err != nil {
   134  		return nil, err
   135  	}
   136  	return s.queryExecutor.GetPrivateDataRangeScanIterator(namespace, collection, startKey, endKey)
   137  }
   138  
   139  // SetPrivateDataMetadata implements method in interface `ledger.TxSimulator`
   140  func (s *txSimulator) SetPrivateDataMetadata(namespace, collection, key string, metadata map[string][]byte) error {
   141  	if err := s.queryExecutor.validateCollName(namespace, collection); err != nil {
   142  		return err
   143  	}
   144  	if err := s.checkWritePrecondition(key, nil); err != nil {
   145  		return err
   146  	}
   147  	s.rwsetBuilder.AddToHashedMetadataWriteSet(namespace, collection, key, metadata)
   148  	return s.checkPrivateStateMetadata(namespace, collection, key)
   149  }
   150  
   151  // DeletePrivateMetadata implements method in interface `ledger.TxSimulator`
   152  func (s *txSimulator) DeletePrivateDataMetadata(namespace, collection, key string) error {
   153  	return s.SetPrivateDataMetadata(namespace, collection, key, nil)
   154  }
   155  
   156  // ExecuteQueryOnPrivateData implements method in interface `ledger.TxSimulator`
   157  func (s *txSimulator) ExecuteQueryOnPrivateData(namespace, collection, query string) (commonledger.ResultsIterator, error) {
   158  	if err := s.checkBeforePvtdataQueries(); err != nil {
   159  		return nil, err
   160  	}
   161  	return s.queryExecutor.ExecuteQueryOnPrivateData(namespace, collection, query)
   162  }
   163  
   164  // GetStateRangeScanIteratorWithPagination implements method in interface `ledger.QueryExecutor`
   165  func (s *txSimulator) GetStateRangeScanIteratorWithPagination(namespace string, startKey string,
   166  	endKey string, pageSize int32) (ledger.QueryResultsIterator, error) {
   167  	if err := s.checkBeforePaginatedQueries(); err != nil {
   168  		return nil, err
   169  	}
   170  	return s.queryExecutor.GetStateRangeScanIteratorWithPagination(namespace, startKey, endKey, pageSize)
   171  }
   172  
   173  // ExecuteQueryWithPagination implements method in interface `ledger.QueryExecutor`
   174  func (s *txSimulator) ExecuteQueryWithPagination(namespace, query, bookmark string, pageSize int32) (ledger.QueryResultsIterator, error) {
   175  	if err := s.checkBeforePaginatedQueries(); err != nil {
   176  		return nil, err
   177  	}
   178  	return s.queryExecutor.ExecuteQueryWithPagination(namespace, query, bookmark, pageSize)
   179  }
   180  
   181  // GetTxSimulationResults implements method in interface `ledger.TxSimulator`
   182  func (s *txSimulator) GetTxSimulationResults() (*ledger.TxSimulationResults, error) {
   183  	if s.simulationResultsComputed {
   184  		return nil, errors.New("this function should only be called once on a transaction simulator instance")
   185  	}
   186  	defer func() { s.simulationResultsComputed = true }()
   187  	logger.Debugf("Simulation completed, getting simulation results")
   188  	if s.queryExecutor.err != nil {
   189  		return nil, s.queryExecutor.err
   190  	}
   191  	s.queryExecutor.addRangeQueryInfo()
   192  	simResults, err := s.rwsetBuilder.GetTxSimulationResults()
   193  	if err != nil {
   194  		return nil, err
   195  	}
   196  	// The txSimulator structures need to be cloned so that subsequent RW set additions don't modify these TX simulation results
   197  	simResults.PrivateReads = s.privateReads.Clone()
   198  	simResults.WritesetMetadata = s.writesetMetadata.Clone()
   199  	return simResults, nil
   200  }
   201  
   202  // ExecuteUpdate implements method in interface `ledger.TxSimulator`
   203  func (s *txSimulator) ExecuteUpdate(query string) error {
   204  	return errors.New("not supported")
   205  }
   206  
   207  func (s *txSimulator) checkWritePrecondition(key string, value []byte) error {
   208  	if err := s.checkDone(); err != nil {
   209  		return err
   210  	}
   211  	if err := s.checkPvtdataQueryPerformed(); err != nil {
   212  		return err
   213  	}
   214  	if err := s.checkPaginatedQueryPerformed(); err != nil {
   215  		return err
   216  	}
   217  	s.writePerformed = true
   218  	return s.queryExecutor.txmgr.db.ValidateKeyValue(key, value)
   219  }
   220  
   221  func (s *txSimulator) checkBeforePvtdataQueries() error {
   222  	if s.writePerformed {
   223  		return errors.Errorf("txid [%s]: unsuppored transaction. Queries on pvt data is supported only in a read-only transaction", s.txid)
   224  	}
   225  	s.pvtdataQueriesPerformed = true
   226  	return nil
   227  }
   228  
   229  func (s *txSimulator) checkPvtdataQueryPerformed() error {
   230  	if s.pvtdataQueriesPerformed {
   231  		return errors.Errorf("txid [%s]: unsuppored transaction. Transaction has already performed queries on pvt data. Writes are not allowed", s.txid)
   232  	}
   233  	return nil
   234  }
   235  
   236  func (s *txSimulator) checkBeforePaginatedQueries() error {
   237  	if s.writePerformed {
   238  		return errors.Errorf("txid [%s]: unsuppored transaction. Paginated queries are supported only in a read-only transaction", s.txid)
   239  	}
   240  	s.paginatedQueriesPerformed = true
   241  	return nil
   242  }
   243  
   244  func (s *txSimulator) checkPaginatedQueryPerformed() error {
   245  	if s.paginatedQueriesPerformed {
   246  		return errors.Errorf("txid [%s]: unsuppored transaction. Transaction has already performed a paginated query. Writes are not allowed", s.txid)
   247  	}
   248  	return nil
   249  }