iota/transaction/validator.py
def _create_validator(self):
        # type: () -> Generator[Text, None, None]
        """
        Creates a generator that does all the work.
        """
        # Group transactions by address to make it easier to iterate
        # over inputs.
        grouped_transactions = self.bundle.group_transactions()

        # Define a few expected values.
        bundle_hash = self.bundle.hash
        last_index = len(self.bundle) - 1

        # Track a few others as we go along.
        balance = 0

        # Check indices and balance first.
        # Note that we use a counter to keep track of the current index,
        # since at this point we can't trust that the transactions have
        # correct ``current_index`` values.
        counter = 0
        for group in grouped_transactions:
            for txn in group:
                balance += txn.value

                if txn.bundle_hash != bundle_hash:
                    yield 'Transaction {i} has invalid bundle hash.'.format(
                        i=counter,
                    )

                if txn.current_index != counter:
                    yield (
                        'Transaction {i} has invalid current index value '
                        '(expected {i}, actual {actual}).'.format(
                            actual=txn.current_index,
                            i=counter,
                        )
                    )

                if txn.last_index != last_index:
                    yield (
                        'Transaction {i} has invalid last index value '
                        '(expected {expected}, actual {actual}).'.format(
                            actual=txn.last_index,
                            expected=last_index,
                            i=counter,
                        )
                    )

                counter += 1

        # Bundle must be balanced (spends must match inputs).
        if balance != 0:
            yield (
                'Bundle has invalid balance '
                '(expected 0, actual {actual}).'.format(
                    actual=balance,
                )
            )

        # Signature validation is only meaningful if the transactions
        # are otherwise valid.
        if not self._errors:
            signature_validation_queue = []  # type: List[List[Transaction]]

            for group in grouped_transactions:
                # Signature validation only applies to inputs.
                if group[0].value >= 0:
                    continue

                validate_group_signature = True
                for j, txn in enumerate(group):
                    if (j > 0) and (txn.value != 0):
                        # Input is malformed; signature fragments after
                        # the first should have zero value.
                        yield (
                            'Transaction {i} has invalid value '
                            '(expected 0, actual {actual}).'.format(
                                actual=txn.value,

                                # If we get to this point, we know that
                                # the ``current_index`` value for each
                                # transaction can be trusted.
                                i=txn.current_index,
                            )
                        )

                        # We won't be able to validate the signature,
                        # but continue anyway, so that we can check that
                        # the other transactions in the group have the
                        # correct ``value``.
                        validate_group_signature = False
                        continue

                # After collecting the signature fragment from each
                # transaction in the group, queue them up to run through
                # the validator.
                #
                # We have to perform signature validation separately so
                # that we can try different algorithms (for
                # backwards-compatibility).
                #
                # References:
                #
                # - https://github.com/iotaledger/kerl#kerl-integration-in-iota
                if validate_group_signature:
                    signature_validation_queue.append(group)

            # Once we've finished checking the attributes from each
            # transaction in the bundle, go back and validate
            # signatures.
            if signature_validation_queue:
                # ``yield from`` is an option here, but for
                # compatibility with Python 2 clients, we will do it the
                # old-fashioned way.
                for error in self._get_bundle_signature_errors(
                        signature_validation_queue
                ):
                    yield error
def _create_validator(self):
        # type: () -> Generator[Text, None, None]
        """
        Creates a generator that does all the work.
        """
        # Group transactions by address to make it easier to iterate
        # over inputs.
        grouped_transactions = self.bundle.group_transactions()

        # Define a few expected values.
        bundle_hash = self.bundle.hash
        last_index = len(self.bundle) - 1

        # Track a few others as we go along.
        balance = 0

        # Check indices and balance first.
        # Note that we use a counter to keep track of the current index,
        # since at this point we can't trust that the transactions have
        # correct ``current_index`` values.
        counter = 0
        for group in grouped_transactions:
            for txn in group:
                balance += txn.value

                if txn.bundle_hash != bundle_hash:
                    yield 'Transaction {i} has invalid bundle hash.'.format(
                        i=counter,
                    )

                if txn.current_index != counter:
                    yield (
                        'Transaction {i} has invalid current index value '
                        '(expected {i}, actual {actual}).'.format(
                            actual=txn.current_index,
                            i=counter,
                        )
                    )

                if txn.last_index != last_index:
                    yield (
                        'Transaction {i} has invalid last index value '
                        '(expected {expected}, actual {actual}).'.format(
                            actual=txn.last_index,
                            expected=last_index,
                            i=counter,
                        )
                    )

                counter += 1

        # Bundle must be balanced (spends must match inputs).
        if balance != 0:
            yield (
                'Bundle has invalid balance '
                '(expected 0, actual {actual}).'.format(
                    actual=balance,
                )
            )

        # Signature validation is only meaningful if the transactions
        # are otherwise valid.
        if not self._errors:
            signature_validation_queue = []  # type: List[List[Transaction]]

            for group in grouped_transactions:
                # Signature validation only applies to inputs.
                if group[0].value >= 0:
                    continue

                validate_group_signature = True
                for j, txn in enumerate(group):
                    if (j > 0) and (txn.value != 0):
                        # Input is malformed; signature fragments after
                        # the first should have zero value.
                        yield (
                            'Transaction {i} has invalid value '
                            '(expected 0, actual {actual}).'.format(
                                actual=txn.value,

                                # If we get to this point, we know that
                                # the ``current_index`` value for each
                                # transaction can be trusted.
                                i=txn.current_index,
                            )
                        )

                        # We won't be able to validate the signature,
                        # but continue anyway, so that we can check that
                        # the other transactions in the group have the
                        # correct ``value``.
                        validate_group_signature = False
                        continue

                # After collecting the signature fragment from each
                # transaction in the group, queue them up to run through
                # the validator.
                #
                # We have to perform signature validation separately so
                # that we can try different algorithms (for
                # backwards-compatibility).
                #
                # References:
                #
                # - https://github.com/iotaledger/kerl#kerl-integration-in-iota
                if validate_group_signature:
                    signature_validation_queue.append(group)

            # Once we've finished checking the attributes from each
            # transaction in the bundle, go back and validate
            # signatures.
            if signature_validation_queue:
                # ``yield from`` is an option here, but for
                # compatibility with Python 2 clients, we will do it the
                # old-fashioned way.
                for error in self._get_bundle_signature_errors(
                        signature_validation_queue
                ):
                    yield error
Creates a generator that does all the work.