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