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 }