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 }