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
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
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()
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)
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()
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
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)
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