Ejemplo n.º 1
0
    def next_transaction(self):
        with self._condition:
            # We return the next transaction which hasn't been scheduled and
            # is not blocked by a dependency.

            next_txn = None

            no_longer_available = []

            for txn_id, txn in self._txns_available.items():
                if (self._has_predecessors(txn_id)
                        or self._is_outstanding(txn_id)):
                    continue

                header = TransactionHeader()
                header.ParseFromString(txn.header)
                deps = tuple(header.dependencies)

                if self._dependency_not_processed(deps):
                    continue

                if self._txn_failed_by_dep(deps):
                    no_longer_available.append(txn_id)
                    self._txn_results[txn_id] = \
                        TxnExecutionResult(
                            signature=txn_id,
                            is_valid=False,
                            context_id=None,
                            state_hash=None)
                    continue

                if not self._txn_is_in_valid_batch(txn_id) and \
                        self._can_fail_fast(txn_id):
                    self._txn_results[txn_id] = \
                        TxnExecutionResult(
                            signature=txn_id,
                            is_valid=False,
                            context_id=None,
                            state_hash=None)
                    no_longer_available.append(txn_id)
                    continue

                next_txn = txn
                break

            for txn_id in no_longer_available:
                del self._txns_available[txn_id]

            if next_txn is not None:
                bases = self._get_initial_state_for_transaction(next_txn)

                info = TxnInformation(
                    txn=next_txn,
                    state_hash=self._first_state_hash,
                    base_context_ids=bases)
                self._scheduled.append(next_txn.header_signature)
                del self._txns_available[next_txn.header_signature]
                self._scheduled_txn_info[next_txn.header_signature] = info
                return info
            return None
Ejemplo n.º 2
0
    def next_transaction(self):
        with self._condition:
            # We return the next transaction which hasn't been scheduled and
            # is not blocked by a dependency.

            next_txn = None
            for txn in self._unscheduled_transactions():
                if not self._has_predecessors(txn) and \
                        not self._is_outstanding(txn) and \
                        not self._dependency_not_processed(txn):
                    if self._txn_failed_by_dep(txn):
                        self._txns_available.remove(txn)
                        self._txn_results[txn.header_signature] = \
                            TxnExecutionResult(
                                signature=txn.header_signature,
                                is_valid=False,
                                context_id=None,
                                state_hash=None)
                        continue
                    txn_id = txn.header_signature
                    if not self._txn_is_in_valid_batch(
                            txn_id) and self._can_fail_fast(txn_id):

                        self._txn_results[
                            txn.header_signature] = TxnExecutionResult(
                                False, None, None)
                        self._txns_available.remove(txn)
                        continue
                    next_txn = txn
                    break

            if next_txn is not None:
                bases = self._get_initial_state_for_transaction(next_txn)
                #
                """
                for DAG self._first_state_hash can be changed real_state_hash and set this state for all transaction into this block 
                so we should update  _first_state_hash only for first computing batch into this block 
                """
                if not self._is_first_state_hash_updated:
                    real_state_hash = self._merkle_root(
                    ) if self._merkle_root else ''
                    LOGGER.debug(
                        'next_transaction: real_state_hash=%s bases=%s',
                        real_state_hash[:8], bases)
                    self._first_state_hash = real_state_hash
                    self._is_first_state_hash_updated = True
                LOGGER.debug('next_transaction: tnx=%s STATE=%s\n',
                             next_txn.header_signature[:8],
                             self._first_state_hash[:8])
                info = TxnInformation(txn=next_txn,
                                      state_hash=self._first_state_hash,
                                      base_context_ids=bases)
                self._scheduled.append(next_txn.header_signature)
                self._txns_available.remove(next_txn)
                self._scheduled_txn_info[next_txn.header_signature] = info
                return info
            return None
Ejemplo n.º 3
0
    def set_transaction_execution_result(self,
                                         txn_signature,
                                         is_valid,
                                         context_id,
                                         state_changes=None,
                                         events=None,
                                         data=None,
                                         error_message="",
                                         error_data=b""):
        with self._condition:
            if txn_signature not in self._scheduled:
                raise SchedulerError(
                    "transaction not scheduled: {}".format(txn_signature))
            self._set_least_batch_id(txn_signature=txn_signature)
            if not is_valid:
                self._remove_subsequent_result_because_of_batch_failure(
                    txn_signature)
            is_rescheduled = self._reschedule_if_outstanding(txn_signature)

            if not is_rescheduled:
                self._txn_results[txn_signature] = TxnExecutionResult(
                    signature=txn_signature,
                    is_valid=is_valid,
                    context_id=context_id if is_valid else None,
                    state_hash=self._first_state_hash if is_valid else None,
                    state_changes=state_changes,
                    events=events,
                    data=data,
                    error_message=error_message,
                    error_data=error_data)

            self._condition.notify_all()
Ejemplo n.º 4
0
 def _set_batch_result(self, txn_id, valid, state_hash):
     batch_id = self._txn_to_batch[txn_id]
     self._batch_statuses[batch_id] = BatchExecutionResult(
         is_valid=valid, state_hash=state_hash)
     batch = self._batch_by_id[batch_id]
     for txn in batch.transactions:
         if txn.header_signature not in self._txn_results:
             self._txn_results[txn.header_signature] = TxnExecutionResult(
                 txn.header_signature, is_valid=False)
Ejemplo n.º 5
0
    def set_transaction_execution_result(self,
                                         txn_signature,
                                         is_valid,
                                         context_id,
                                         state_changes=None,
                                         events=None,
                                         data=None,
                                         error_message="",
                                         error_data=b""):
        with self._condition:
            if (self._in_progress_transaction is None
                    or self._in_progress_transaction != txn_signature):
                LOGGER.debug('Received result for %s, but was unscheduled',
                             txn_signature)
                return

            self._in_progress_transaction = None

            if txn_signature not in self._txn_to_batch:
                raise ValueError(
                    "transaction not in any batches: {}".format(txn_signature))

            if txn_signature not in self._txn_results:
                self._txn_results[txn_signature] = TxnExecutionResult(
                    signature=txn_signature,
                    is_valid=is_valid,
                    context_id=context_id if is_valid else None,
                    state_hash=self._previous_state_hash if is_valid else None,
                    state_changes=state_changes,
                    events=events,
                    data=data,
                    error_message=error_message,
                    error_data=error_data)

            batch_signature = self._txn_to_batch[txn_signature]
            if is_valid:
                self._previous_context_id = context_id

            else:
                # txn is invalid, preemptively fail the batch
                self._batch_statuses[batch_signature] = \
                    BatchExecutionResult(is_valid=False, state_hash=None)
            if txn_signature in self._last_in_batch:
                if batch_signature not in self._batch_statuses:
                    # because of the else clause above, txn is valid here
                    self._previous_valid_batch_c_id = self._previous_context_id
                    state_hash = self._calculate_state_root_if_required(
                        batch_id=batch_signature)
                    self._batch_statuses[batch_signature] = \
                        BatchExecutionResult(is_valid=True,
                                             state_hash=state_hash)
                else:
                    self._previous_context_id = self._previous_valid_batch_c_id

            self._condition.notify_all()
Ejemplo n.º 6
0
    def next_transaction(self):
        with self._condition:
            # We return the next transaction which hasn't been scheduled and
            # is not blocked by a dependency.

            next_txn = None
            for txn in self._unscheduled_transactions():
                if not self._has_predecessors(txn) and \
                        not self._is_outstanding(txn) and \
                        not self._dependency_not_processed(txn):
                    if self._txn_failed_by_dep(txn):
                        self._txns_available.remove(txn)
                        self._txn_results[txn.header_signature] = \
                            TxnExecutionResult(
                                signature=txn.header_signature,
                                is_valid=False,
                                context_id=None,
                                state_hash=None)
                        continue
                    txn_id = txn.header_signature
                    if not self._txn_is_in_valid_batch(txn_id) and \
                            self._can_fail_fast(txn_id):

                        self._txn_results[txn.header_signature] = \
                            TxnExecutionResult(False, None, None)
                        self._txns_available.remove(txn)
                        continue
                    next_txn = txn
                    break

            if next_txn is not None:
                bases = self._get_initial_state_for_transaction(next_txn)

                info = TxnInformation(txn=next_txn,
                                      state_hash=self._first_state_hash,
                                      base_context_ids=bases)
                self._scheduled.append(next_txn.header_signature)
                self._txns_available.remove(next_txn)
                self._scheduled_txn_info[next_txn.header_signature] = info
                return info
            return None
Ejemplo n.º 7
0
    def _set_batch_result(self, txn_id, valid, state_hash):
        if txn_id not in self._txn_to_batch:
            # An incomplete transaction in progress will have been removed
            return

        batch_id = self._txn_to_batch[txn_id]
        self._batch_statuses[batch_id] = BatchExecutionResult(
            is_valid=valid, state_hash=state_hash)
        batch = self._batch_by_id[batch_id].batch
        for txn in batch.transactions:
            if txn.header_signature not in self._txn_results:
                self._txn_results[txn.header_signature] = TxnExecutionResult(
                    txn.header_signature, is_valid=False)
Ejemplo n.º 8
0
    def get_transaction_execution_results(self, batch_signature):
        txn_execution_results = []
        is_valid_always_false = False
        if not self.batch_execution_result:
            is_valid_always_false = True

        batch = self.batches[batch_signature]
        for txn in batch.transactions:
            if is_valid_always_false:
                is_valid = False
                context_id = None
            else:
                if txn.payload == b'BAD':
                    is_valid = False
                    context_id = None
                else:
                    is_valid = True
                    context_id = "test"
            txn_execution_results.append(
                TxnExecutionResult(signature=txn.header_signature,
                                   is_valid=is_valid,
                                   context_id=context_id,
                                   state_hash=None))
        return txn_execution_results