github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/validator/sawtooth_validator/execution/scheduler.py (about) 1 # Copyright 2016 Intel Corporation 2 # 3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # you may not use this file except in compliance with the License. 5 # You may obtain a copy of the License at 6 # 7 # http://www.apache.org/licenses/LICENSE-2.0 8 # 9 # Unless required by applicable law or agreed to in writing, software 10 # distributed under the License is distributed on an "AS IS" BASIS, 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 # See the License for the specific language governing permissions and 13 # limitations under the License. 14 # ------------------------------------------------------------------------------ 15 16 from abc import ABCMeta 17 from abc import abstractmethod 18 19 20 class Scheduler(object, metaclass=ABCMeta): 21 """Abstract class for scheduling transaction execution. 22 23 Implementations of this class are expected to be thread-safe. 24 """ 25 26 @abstractmethod 27 def add_batch(self, batch, state_hash=None, required=False): 28 """Adds a batch to the scheduler. 29 30 The batch, and thus its associated transactions, will be added to the 31 scheduling queue. 32 33 Args: 34 batch: A batch_pb2.Batch instance. 35 state_hash: The expected resulting state_hash after the 36 transactions have been applied. 37 required: The given batch must be included in the completed 38 schedule. That is, it will not be removed when a call to 39 `unschedule_incomplete_batches` is made. Defaults to `False`. 40 """ 41 raise NotImplementedError() 42 43 @abstractmethod 44 def get_batch_execution_result(self, batch_signature): 45 """Signifies whether a particular batch is valid, returns 46 None if the batch hasn't fully been processed. 47 48 Args: 49 batch_signature (str): The signature of the batch, which must match 50 the header_signature field of the Batch. 51 52 Returns: 53 BatchExecutionResult: The result of batch execution. 54 """ 55 raise NotImplementedError() 56 57 @abstractmethod 58 def get_transaction_execution_results(self, batch_signature): 59 """Get all TransactionExecutionResults for a batch. If the batch isn't 60 finished or is invalid, returns None. 61 62 Args: 63 batch_signature (str): The signature of the batch, which must match 64 the header_signature field of the Batch. 65 66 Returns: 67 list of :obj:`TransactionExecutionResult`: The results of all 68 transactions executed in the batch. 69 """ 70 raise NotImplementedError() 71 72 @abstractmethod 73 def set_transaction_execution_result( 74 self, txn_signature, is_valid, context_id, state_changes, events, 75 data, error_message, error_data): 76 """Set the status of an executed transaction. 77 78 Called by the executor after a transaction has been processed. 79 80 The scheduler must know when transactions have finished being 81 applied so that it can determine which transactions will become 82 eligible for processing. 83 84 Args: 85 txn_signature (str): The signature of the transaction, which 86 must match the header_signature field of the Transaction 87 object which was part of the added Batch. 88 is_valid (bool): True if transaction applied successfully or False 89 if the transaction failed and was not applied. 90 context_id (str): If status is True, contains the context_id 91 associated with the state changes made by the transaction. 92 If status is False, this should be set to None. 93 94 Raises: 95 ValueError: Thrown if transaction_signature does not match a 96 transaction. 97 """ 98 raise NotImplementedError() 99 100 @abstractmethod 101 def next_transaction(self): 102 """Returns the next transaction, if any, that can be processed. 103 104 Returns: 105 A Transaction object or None if there is not a transaction which 106 can be processed. A value of None does not necessarily indicate 107 there are no more transactions, only that there are no 108 transactions which have had their dependencies met. 109 """ 110 raise NotImplementedError() 111 112 @abstractmethod 113 def unschedule_incomplete_batches(self): 114 """Remove any incomplete batches from the schedule. 115 """ 116 raise NotImplementedError() 117 118 @abstractmethod 119 def is_transaction_in_schedule(self, txn_signature): 120 """Returns True if a transaction is in this schedule. 121 122 Args: 123 txn_signature (str): The signature of the transaction, which 124 must match the header_signature field of the Transaction 125 object which was part of the added Batch. 126 """ 127 raise NotImplementedError() 128 129 @abstractmethod 130 def finalize(self): 131 """Tell the scheduler that no more batches/transactions will be added. 132 133 This will change the state of the scheduler. After this call and all 134 transactions are marked applied, complete() will return True. After 135 finalize() is called, batches can no longer be added to the scheduler. 136 """ 137 raise NotImplementedError() 138 139 @abstractmethod 140 def complete(self, block): 141 """Returns True if all transactions have been marked as applied. 142 143 Args: 144 block (bool): If True, block until complete, or if False return 145 the completion status. 146 147 Returns: 148 True if all transactions have been marked as applied and that the 149 finalize() has been called. 150 """ 151 raise NotImplementedError() 152 153 @abstractmethod 154 def cancel(self): 155 """Cancels the schedule of transactions. The cancelling of a scheduler 156 is an idempotent operation. The iterator will raise 157 StopIteration, completing iteration on the iterator. 158 Returns: 159 None 160 """ 161 raise NotImplementedError() 162 163 @abstractmethod 164 def is_cancelled(self): 165 """Returns whether .cancel() has been called on this scheduler. 166 167 168 Returns: 169 A bool specifing if the scheduler's .cancel() method has been 170 called. 171 """ 172 raise NotImplementedError() 173 174 @abstractmethod 175 def __iter__(self): 176 """Returns a Transaction iterator. 177 178 All schedulers must be iterable, with the iterator returning the 179 transactions, with the iteration blocking if finalize() has not been 180 called. Multiple iterators are allowed and each will start from 181 the first transaction regardless of whether it has been marked as 182 applied. 183 184 Returns: 185 An Transaction iterator. 186 """ 187 raise NotImplementedError() 188 189 @abstractmethod 190 def get_transaction(self, index): 191 """Returns the scheduled Transaction at index. 192 193 This is used by SchedulerIterator to return a consistent order of 194 Transactions. Once the Scheduler has picked 195 196 Returns: 197 Returns the Transaction at index. 198 """ 199 raise NotImplementedError() 200 201 @abstractmethod 202 def count(self): 203 """The count of transactions which have been scheduled. 204 205 Returns: 206 An integer. 207 """ 208 raise NotImplementedError() 209 210 211 class SchedulerIterator(object): 212 def __init__(self, scheduler, condition, start_index=0): 213 self._scheduler = scheduler 214 self._condition = condition 215 self._next_index = start_index 216 217 # pylint: disable=inconsistent-return-statements 218 def __next__(self): 219 with self._condition: 220 # Catch-up. This will return transactions that have already been 221 # scheduled. 222 if self._next_index < self._scheduler.count(): 223 txn = self._scheduler.get_transaction(self._next_index) 224 self._next_index += 1 225 return txn 226 227 # Return the next transaction, potentially blocking with wait(). 228 # Exit by throwing StopIteration when the scheduler is complete 229 # and we have returned all the scheduler's transactions or the 230 # scheduler was cancelled. 231 while True: 232 if (self._scheduler.complete(block=False) 233 and self._scheduler.count() == self._next_index 234 or self._scheduler.is_cancelled()): 235 raise StopIteration() 236 237 txn = self._scheduler.next_transaction() 238 if txn is not None: 239 self._next_index += 1 240 return txn 241 242 self._condition.wait() 243 244 245 class BatchExecutionResult(object): 246 """The resulting execution data from running the batch's transactions 247 through the executor. 248 249 Attributes: 250 is_valid (bool): True if the batch is valid, False otherwise. 251 state_hash (str): The state hash from applying the state changes from 252 the transactions in this batch and all prior transactions in valid 253 batches since the last state hash was returned. Will always be 254 in the BatchExecutionResult for batches that were added to 255 add_batch with a state hash. 256 """ 257 258 def __init__(self, is_valid, state_hash): 259 self.is_valid = is_valid 260 self.state_hash = state_hash 261 262 263 class TxnExecutionResult: 264 """The resulting execution data from running the transaction through the 265 executor. 266 267 Attributes: 268 signature (str): The header signature of the transaction. 269 is_valid (bool): True if the transaction is valid, False otherwise. 270 context_id (str): The context id against which the transaction was run. 271 state_hash (str): The state hash against which the transaction was run. 272 state_changes (list of :obj:`transaction_receipt_pb2.StateChange`): The 273 state changes that were a result of applying this transaction. 274 events (list of :obj:`client_event_pb2.Event`): The events that were 275 returned while executing this transaction. 276 data (list of (str, bytes)): Opaque data that was returned while 277 executing this transaction. 278 error_message (str): An error message that was returned while executing 279 this transaction. 280 error_data (bytes): Error data that was returned while executing this 281 transaction. 282 """ 283 284 def __init__(self, signature, is_valid, context_id=None, state_hash=None, 285 state_changes=None, events=None, data=None, error_message="", 286 error_data=b""): 287 288 if is_valid and context_id is None: 289 raise ValueError( 290 "There must be a context_id for valid transactions") 291 if not is_valid and context_id is not None: 292 raise ValueError( 293 "context_id must be None for invalid transactions") 294 if not is_valid and state_hash is not None: 295 raise ValueError( 296 "state_hash must be None for invalid transactions") 297 298 self.signature = signature 299 self.is_valid = is_valid 300 self.context_id = context_id 301 self.state_hash = state_hash 302 self.state_changes = state_changes if state_changes is not None else [] 303 self.events = events if events is not None else [] 304 self.data = data if data is not None else [] 305 self.error_message = error_message 306 self.error_data = error_data 307 308 309 class TxnInformation(object): 310 """Information about a transaction from the 311 scheduler to the executor. 312 Attributes: 313 txn transaction_pb2.Transaction protobuf class 314 state_hash (str): the state hash that 315 this txn should be applied against 316 """ 317 318 def __init__(self, txn, state_hash, base_context_ids): 319 self.txn = txn 320 self.state_hash = state_hash 321 self.base_context_ids = base_context_ids