github.com/Hnampk/fabric@v2.1.1+incompatible/core/ledger/kvledger/txmgmt/txmgr/lockbasedtxmgr/lockbased_tx_simulator.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package lockbasedtxmgr
     8  
     9  import (
    10  	"fmt"
    11  
    12  	commonledger "github.com/hyperledger/fabric/common/ledger"
    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/txmgr"
    16  	"github.com/pkg/errors"
    17  )
    18  
    19  // LockBasedTxSimulator is a transaction simulator used in `LockBasedTxMgr`
    20  type lockBasedTxSimulator struct {
    21  	lockBasedQueryExecutor
    22  	rwsetBuilder              *rwsetutil.RWSetBuilder
    23  	writePerformed            bool
    24  	pvtdataQueriesPerformed   bool
    25  	simulationResultsComputed bool
    26  	paginatedQueriesPerformed bool
    27  }
    28  
    29  func newLockBasedTxSimulator(txmgr *LockBasedTxMgr, txid string, hasher ledger.Hasher) (*lockBasedTxSimulator, error) {
    30  	rwsetBuilder := rwsetutil.NewRWSetBuilder()
    31  	helper := newQueryHelper(txmgr, rwsetBuilder, true, hasher)
    32  	logger.Debugf("constructing new tx simulator txid = [%s]", txid)
    33  	return &lockBasedTxSimulator{lockBasedQueryExecutor{helper, txid}, rwsetBuilder, false, false, false, false}, nil
    34  }
    35  
    36  // SetState implements method in interface `ledger.TxSimulator`
    37  func (s *lockBasedTxSimulator) 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  	return nil
    43  }
    44  
    45  // DeleteState implements method in interface `ledger.TxSimulator`
    46  func (s *lockBasedTxSimulator) DeleteState(ns string, key string) error {
    47  	return s.SetState(ns, key, nil)
    48  }
    49  
    50  // SetStateMultipleKeys implements method in interface `ledger.TxSimulator`
    51  func (s *lockBasedTxSimulator) SetStateMultipleKeys(namespace string, kvs map[string][]byte) error {
    52  	for k, v := range kvs {
    53  		if err := s.SetState(namespace, k, v); err != nil {
    54  			return err
    55  		}
    56  	}
    57  	return nil
    58  }
    59  
    60  // SetStateMetadata implements method in interface `ledger.TxSimulator`
    61  func (s *lockBasedTxSimulator) SetStateMetadata(namespace, key string, metadata map[string][]byte) error {
    62  	if err := s.checkWritePrecondition(key, nil); err != nil {
    63  		return err
    64  	}
    65  	s.rwsetBuilder.AddToMetadataWriteSet(namespace, key, metadata)
    66  	return nil
    67  }
    68  
    69  // DeleteStateMetadata implements method in interface `ledger.TxSimulator`
    70  func (s *lockBasedTxSimulator) DeleteStateMetadata(namespace, key string) error {
    71  	return s.SetStateMetadata(namespace, key, nil)
    72  }
    73  
    74  // SetPrivateData implements method in interface `ledger.TxSimulator`
    75  func (s *lockBasedTxSimulator) SetPrivateData(ns, coll, key string, value []byte) error {
    76  	if err := s.helper.validateCollName(ns, coll); err != nil {
    77  		return err
    78  	}
    79  	if err := s.checkWritePrecondition(key, value); err != nil {
    80  		return err
    81  	}
    82  	s.writePerformed = true
    83  	s.rwsetBuilder.AddToPvtAndHashedWriteSet(ns, coll, key, value)
    84  	return nil
    85  }
    86  
    87  // DeletePrivateData implements method in interface `ledger.TxSimulator`
    88  func (s *lockBasedTxSimulator) DeletePrivateData(ns, coll, key string) error {
    89  	return s.SetPrivateData(ns, coll, key, nil)
    90  }
    91  
    92  // SetPrivateDataMultipleKeys implements method in interface `ledger.TxSimulator`
    93  func (s *lockBasedTxSimulator) SetPrivateDataMultipleKeys(ns, coll string, kvs map[string][]byte) error {
    94  	for k, v := range kvs {
    95  		if err := s.SetPrivateData(ns, coll, k, v); err != nil {
    96  			return err
    97  		}
    98  	}
    99  	return nil
   100  }
   101  
   102  // GetPrivateDataRangeScanIterator implements method in interface `ledger.TxSimulator`
   103  func (s *lockBasedTxSimulator) GetPrivateDataRangeScanIterator(namespace, collection, startKey, endKey string) (commonledger.ResultsIterator, error) {
   104  	if err := s.checkBeforePvtdataQueries(); err != nil {
   105  		return nil, err
   106  	}
   107  	return s.lockBasedQueryExecutor.GetPrivateDataRangeScanIterator(namespace, collection, startKey, endKey)
   108  }
   109  
   110  // SetPrivateDataMetadata implements method in interface `ledger.TxSimulator`
   111  func (s *lockBasedTxSimulator) SetPrivateDataMetadata(namespace, collection, key string, metadata map[string][]byte) error {
   112  	if err := s.helper.validateCollName(namespace, collection); err != nil {
   113  		return err
   114  	}
   115  	if err := s.checkWritePrecondition(key, nil); err != nil {
   116  		return err
   117  	}
   118  	s.rwsetBuilder.AddToHashedMetadataWriteSet(namespace, collection, key, metadata)
   119  	return nil
   120  }
   121  
   122  // DeletePrivateMetadata implements method in interface `ledger.TxSimulator`
   123  func (s *lockBasedTxSimulator) DeletePrivateDataMetadata(namespace, collection, key string) error {
   124  	return s.SetPrivateDataMetadata(namespace, collection, key, nil)
   125  }
   126  
   127  // ExecuteQueryOnPrivateData implements method in interface `ledger.TxSimulator`
   128  func (s *lockBasedTxSimulator) ExecuteQueryOnPrivateData(namespace, collection, query string) (commonledger.ResultsIterator, error) {
   129  	if err := s.checkBeforePvtdataQueries(); err != nil {
   130  		return nil, err
   131  	}
   132  	return s.lockBasedQueryExecutor.ExecuteQueryOnPrivateData(namespace, collection, query)
   133  }
   134  
   135  // GetStateRangeScanIteratorWithMetadata implements method in interface `ledger.QueryExecutor`
   136  func (s *lockBasedTxSimulator) GetStateRangeScanIteratorWithMetadata(namespace string, startKey string, endKey string, metadata map[string]interface{}) (ledger.QueryResultsIterator, error) {
   137  	if err := s.checkBeforePaginatedQueries(); err != nil {
   138  		return nil, err
   139  	}
   140  	return s.lockBasedQueryExecutor.GetStateRangeScanIteratorWithMetadata(namespace, startKey, endKey, metadata)
   141  }
   142  
   143  // ExecuteQueryWithMetadata implements method in interface `ledger.QueryExecutor`
   144  func (s *lockBasedTxSimulator) ExecuteQueryWithMetadata(namespace, query string, metadata map[string]interface{}) (ledger.QueryResultsIterator, error) {
   145  	if err := s.checkBeforePaginatedQueries(); err != nil {
   146  		return nil, err
   147  	}
   148  	return s.lockBasedQueryExecutor.ExecuteQueryWithMetadata(namespace, query, metadata)
   149  }
   150  
   151  // GetTxSimulationResults implements method in interface `ledger.TxSimulator`
   152  func (s *lockBasedTxSimulator) GetTxSimulationResults() (*ledger.TxSimulationResults, error) {
   153  	if s.simulationResultsComputed {
   154  		return nil, errors.New("this function should only be called once on a transaction simulator instance")
   155  	}
   156  	defer func() { s.simulationResultsComputed = true }()
   157  	logger.Debugf("Simulation completed, getting simulation results")
   158  	if s.helper.err != nil {
   159  		return nil, s.helper.err
   160  	}
   161  	s.helper.addRangeQueryInfo()
   162  	return s.rwsetBuilder.GetTxSimulationResults()
   163  }
   164  
   165  // ExecuteUpdate implements method in interface `ledger.TxSimulator`
   166  func (s *lockBasedTxSimulator) ExecuteUpdate(query string) error {
   167  	return errors.New("not supported")
   168  }
   169  
   170  func (s *lockBasedTxSimulator) checkWritePrecondition(key string, value []byte) error {
   171  	if err := s.helper.checkDone(); err != nil {
   172  		return err
   173  	}
   174  	if err := s.checkPvtdataQueryPerformed(); err != nil {
   175  		return err
   176  	}
   177  	if err := s.checkPaginatedQueryPerformed(); err != nil {
   178  		return err
   179  	}
   180  	s.writePerformed = true
   181  	if err := s.helper.txmgr.db.ValidateKeyValue(key, value); err != nil {
   182  		return err
   183  	}
   184  	return nil
   185  }
   186  
   187  func (s *lockBasedTxSimulator) checkBeforePvtdataQueries() error {
   188  	if s.writePerformed {
   189  		return &txmgr.ErrUnsupportedTransaction{
   190  			Msg: fmt.Sprintf("txid [%s]: Queries on pvt data is supported only in a read-only transaction", s.txid),
   191  		}
   192  	}
   193  	s.pvtdataQueriesPerformed = true
   194  	return nil
   195  }
   196  
   197  func (s *lockBasedTxSimulator) checkPvtdataQueryPerformed() error {
   198  	if s.pvtdataQueriesPerformed {
   199  		return &txmgr.ErrUnsupportedTransaction{
   200  			Msg: fmt.Sprintf("txid [%s]: Transaction has already performed queries on pvt data. Writes are not allowed", s.txid),
   201  		}
   202  	}
   203  	return nil
   204  }
   205  
   206  func (s *lockBasedTxSimulator) checkBeforePaginatedQueries() error {
   207  	if s.writePerformed {
   208  		return &txmgr.ErrUnsupportedTransaction{
   209  			Msg: fmt.Sprintf("txid [%s]: Paginated queries are supported only in a read-only transaction", s.txid),
   210  		}
   211  	}
   212  	s.paginatedQueriesPerformed = true
   213  	return nil
   214  }
   215  
   216  func (s *lockBasedTxSimulator) checkPaginatedQueryPerformed() error {
   217  	if s.paginatedQueriesPerformed {
   218  		return &txmgr.ErrUnsupportedTransaction{
   219  			Msg: fmt.Sprintf("txid [%s]: Transaction has already performed a paginated query. Writes are not allowed", s.txid),
   220  		}
   221  	}
   222  	return nil
   223  }