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 }