github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/core/ledger/kvledger/txmgmt/txmgr/tx_simulator.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package txmgr
     8  
     9  import (
    10  	"fmt"
    11  
    12  	commonledger "github.com/osdi23p228/fabric/common/ledger"
    13  	"github.com/osdi23p228/fabric/core/ledger"
    14  	"github.com/osdi23p228/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
    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  }
    27  
    28  func newTxSimulator(txmgr *LockBasedTxMgr, txid string, hashFunc rwsetutil.HashFunc) (*txSimulator, error) {
    29  	rwsetBuilder := rwsetutil.NewRWSetBuilder()
    30  	qe := newQueryExecutor(txmgr, txid, rwsetBuilder, true, hashFunc)
    31  	logger.Debugf("constructing new tx simulator txid = [%s]", txid)
    32  	return &txSimulator{qe, rwsetBuilder, false, false, false, false}, nil
    33  }
    34  
    35  // SetState implements method in interface `ledger.TxSimulator`
    36  func (s *txSimulator) SetState(ns string, key string, value []byte) error {
    37  	if err := s.checkWritePrecondition(key, value); err != nil {
    38  		return err
    39  	}
    40  	s.rwsetBuilder.AddToWriteSet(ns, key, value)
    41  	return nil
    42  }
    43  
    44  // DeleteState implements method in interface `ledger.TxSimulator`
    45  func (s *txSimulator) DeleteState(ns string, key string) error {
    46  	return s.SetState(ns, key, nil)
    47  }
    48  
    49  // SetStateMultipleKeys implements method in interface `ledger.TxSimulator`
    50  func (s *txSimulator) SetStateMultipleKeys(namespace string, kvs map[string][]byte) error {
    51  	for k, v := range kvs {
    52  		if err := s.SetState(namespace, k, v); err != nil {
    53  			return err
    54  		}
    55  	}
    56  	return nil
    57  }
    58  
    59  // SetStateMetadata implements method in interface `ledger.TxSimulator`
    60  func (s *txSimulator) SetStateMetadata(namespace, key string, metadata map[string][]byte) error {
    61  	if err := s.checkWritePrecondition(key, nil); err != nil {
    62  		return err
    63  	}
    64  	s.rwsetBuilder.AddToMetadataWriteSet(namespace, key, metadata)
    65  	return nil
    66  }
    67  
    68  // DeleteStateMetadata implements method in interface `ledger.TxSimulator`
    69  func (s *txSimulator) DeleteStateMetadata(namespace, key string) error {
    70  	return s.SetStateMetadata(namespace, key, nil)
    71  }
    72  
    73  // SetPrivateData implements method in interface `ledger.TxSimulator`
    74  func (s *txSimulator) SetPrivateData(ns, coll, key string, value []byte) error {
    75  	if err := s.queryExecutor.validateCollName(ns, coll); err != nil {
    76  		return err
    77  	}
    78  	if err := s.checkWritePrecondition(key, value); err != nil {
    79  		return err
    80  	}
    81  	s.writePerformed = true
    82  	s.rwsetBuilder.AddToPvtAndHashedWriteSet(ns, coll, key, value)
    83  	return nil
    84  }
    85  
    86  // DeletePrivateData implements method in interface `ledger.TxSimulator`
    87  func (s *txSimulator) DeletePrivateData(ns, coll, key string) error {
    88  	return s.SetPrivateData(ns, coll, key, nil)
    89  }
    90  
    91  // SetPrivateDataMultipleKeys implements method in interface `ledger.TxSimulator`
    92  func (s *txSimulator) SetPrivateDataMultipleKeys(ns, coll string, kvs map[string][]byte) error {
    93  	for k, v := range kvs {
    94  		if err := s.SetPrivateData(ns, coll, k, v); err != nil {
    95  			return err
    96  		}
    97  	}
    98  	return nil
    99  }
   100  
   101  // GetPrivateDataRangeScanIterator implements method in interface `ledger.TxSimulator`
   102  func (s *txSimulator) GetPrivateDataRangeScanIterator(namespace, collection, startKey, endKey string) (commonledger.ResultsIterator, error) {
   103  	if err := s.checkBeforePvtdataQueries(); err != nil {
   104  		return nil, err
   105  	}
   106  	return s.queryExecutor.GetPrivateDataRangeScanIterator(namespace, collection, startKey, endKey)
   107  }
   108  
   109  // SetPrivateDataMetadata implements method in interface `ledger.TxSimulator`
   110  func (s *txSimulator) SetPrivateDataMetadata(namespace, collection, key string, metadata map[string][]byte) error {
   111  	if err := s.queryExecutor.validateCollName(namespace, collection); err != nil {
   112  		return err
   113  	}
   114  	if err := s.checkWritePrecondition(key, nil); err != nil {
   115  		return err
   116  	}
   117  	s.rwsetBuilder.AddToHashedMetadataWriteSet(namespace, collection, key, metadata)
   118  	return nil
   119  }
   120  
   121  // DeletePrivateMetadata implements method in interface `ledger.TxSimulator`
   122  func (s *txSimulator) DeletePrivateDataMetadata(namespace, collection, key string) error {
   123  	return s.SetPrivateDataMetadata(namespace, collection, key, nil)
   124  }
   125  
   126  // ExecuteQueryOnPrivateData implements method in interface `ledger.TxSimulator`
   127  func (s *txSimulator) ExecuteQueryOnPrivateData(namespace, collection, query string) (commonledger.ResultsIterator, error) {
   128  	if err := s.checkBeforePvtdataQueries(); err != nil {
   129  		return nil, err
   130  	}
   131  	return s.queryExecutor.ExecuteQueryOnPrivateData(namespace, collection, query)
   132  }
   133  
   134  // GetStateRangeScanIteratorWithPagination implements method in interface `ledger.QueryExecutor`
   135  func (s *txSimulator) GetStateRangeScanIteratorWithPagination(namespace string, startKey string,
   136  	endKey string, pageSize int32) (ledger.QueryResultsIterator, error) {
   137  	if err := s.checkBeforePaginatedQueries(); err != nil {
   138  		return nil, err
   139  	}
   140  	return s.queryExecutor.GetStateRangeScanIteratorWithPagination(namespace, startKey, endKey, pageSize)
   141  }
   142  
   143  // ExecuteQueryWithPagination implements method in interface `ledger.QueryExecutor`
   144  func (s *txSimulator) ExecuteQueryWithPagination(namespace, query, bookmark string, pageSize int32) (ledger.QueryResultsIterator, error) {
   145  	if err := s.checkBeforePaginatedQueries(); err != nil {
   146  		return nil, err
   147  	}
   148  	return s.queryExecutor.ExecuteQueryWithPagination(namespace, query, bookmark, pageSize)
   149  }
   150  
   151  // GetTxSimulationResults implements method in interface `ledger.TxSimulator`
   152  func (s *txSimulator) 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.queryExecutor.err != nil {
   159  		return nil, s.queryExecutor.err
   160  	}
   161  	s.queryExecutor.addRangeQueryInfo()
   162  	return s.rwsetBuilder.GetTxSimulationResults()
   163  }
   164  
   165  // ExecuteUpdate implements method in interface `ledger.TxSimulator`
   166  func (s *txSimulator) ExecuteUpdate(query string) error {
   167  	return errors.New("not supported")
   168  }
   169  
   170  func (s *txSimulator) checkWritePrecondition(key string, value []byte) error {
   171  	if err := s.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.queryExecutor.txmgr.db.ValidateKeyValue(key, value); err != nil {
   182  		return err
   183  	}
   184  	return nil
   185  }
   186  
   187  func (s *txSimulator) checkBeforePvtdataQueries() error {
   188  	if s.writePerformed {
   189  		return &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 *txSimulator) checkPvtdataQueryPerformed() error {
   198  	if s.pvtdataQueriesPerformed {
   199  		return &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 *txSimulator) checkBeforePaginatedQueries() error {
   207  	if s.writePerformed {
   208  		return &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 *txSimulator) checkPaginatedQueryPerformed() error {
   217  	if s.paginatedQueriesPerformed {
   218  		return &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  }