示例#1
0
    def test_generator_with_offset(self):
        """
    Creating a generator that starts at an offset greater than 0.
    """
        # Seed is not important for this test; it is only used by
        # :py:class:`KeyGenerator`, which we will mock in this test.
        ag = AddressGenerator(seed=b'')

        # noinspection PyUnresolvedReferences
        with patch.object(ag, '_create_digest_generator',
                          self._mock_digest_gen):
            generator = ag.create_generator(start=1, step=2)

            self.assertEqual(next(generator), self.addy1)
            self.assertEqual(next(generator), self.addy3)
示例#2
0
    def _execute(self, request):
        stop = request['stop']  # type: Optional[int]
        seed = request['seed']  # type: Seed
        start = request['start']  # type: int
        threshold = request['threshold']  # type: Optional[int]

        generator = AddressGenerator(seed)

        # Determine the addresses we will be scanning.
        if stop is None:
            # This is similar to the ``getNewAddresses`` command, except it
            # is interested in all the addresses that `getNewAddresses`
            # skips.
            addresses = []  # type: List[Address]
            for addy in generator.create_generator(start):
                ft_response = FindTransactionsCommand(
                    self.adapter)(addresses=[addy])

                if ft_response.get('hashes'):
                    addresses.append(addy)
                else:
                    break
        else:
            addresses = generator.get_addresses(start, stop)

        # Load balances for the addresses that we generated.
        gb_response = GetBalancesCommand(self.adapter)(addresses=addresses)

        result = {
            'inputs': [],
            'totalBalance': 0,
        }

        threshold_met = threshold is None

        for i, balance in enumerate(gb_response['balances']):
            addresses[i].balance = balance

            if balance:
                result['inputs'].append(addresses[i])
                result['totalBalance'] += balance

                if (threshold
                        is not None) and (result['totalBalance'] >= threshold):
                    threshold_met = True
                    break

        if threshold_met:
            return result
        else:
            # This is an exception case, but note that we attach the result
            # to the exception context so that it can be used for
            # troubleshooting.
            raise with_context(
                exc=BadApiResponse(
                    'Accumulated balance {balance} is less than threshold {threshold} '
                    '(``exc.context`` contains more information).'.format(
                        threshold=threshold,
                        balance=result['totalBalance'],
                    ), ),
                context={
                    'inputs': result['inputs'],
                    'request': request,
                    'total_balance': result['totalBalance'],
                },
            )
示例#3
0
    def _execute(self, request):
        stop = request['stop']  # type: Optional[int]
        inclusion_states = request['inclusionStates']  # type: bool
        seed = request['seed']  # type: Seed
        start = request['start']  # type: int

        generator = AddressGenerator(seed)
        ft_command = FindTransactionsCommand(self.adapter)

        # Determine the addresses we will be scanning, and pull their
        # transaction hashes.
        if stop is None:
            # This is similar to the ``getNewAddresses`` command, except it
            # is interested in all the addresses that `getNewAddresses`
            # skips.
            hashes = []
            for addy in generator.create_generator(start):
                ft_response = ft_command(addresses=[addy])

                if ft_response.get('hashes'):
                    hashes += ft_response['hashes']
                else:
                    break

                # Reset the command so that we can call it again.
                ft_command.reset()
        else:
            ft_response =\
              ft_command(addresses=generator.get_addresses(start, stop - start))

            hashes = ft_response.get('hashes') or []

        all_bundles = []  # type: List[Bundle]

        if hashes:
            # Sort transactions into tail and non-tail.
            tail_transaction_hashes = set()
            non_tail_bundle_hashes = set()

            gt_response = GetTrytesCommand(self.adapter)(hashes=hashes)
            all_transactions = list(
                map(
                    Transaction.from_tryte_string,
                    gt_response['trytes'],
                ))  # type: List[Transaction]

            for txn in all_transactions:
                if txn.is_tail:
                    tail_transaction_hashes.add(txn.hash)
                else:
                    # Capture the bundle ID instead of the transaction hash so that
                    # we can query the node to find the tail transaction for that
                    # bundle.
                    non_tail_bundle_hashes.add(txn.bundle_hash)

            if non_tail_bundle_hashes:
                for txn in self._find_transactions(
                        bundles=list(non_tail_bundle_hashes)):
                    if txn.is_tail:
                        if txn.hash not in tail_transaction_hashes:
                            all_transactions.append(txn)
                            tail_transaction_hashes.add(txn.hash)

            # Filter out all non-tail transactions.
            tail_transactions = [
                txn for txn in all_transactions
                if txn.hash in tail_transaction_hashes
            ]

            # Attach inclusion states, if requested.
            if inclusion_states:
                gli_response = GetLatestInclusionCommand(self.adapter)(
                    hashes=list(tail_transaction_hashes), )

                for txn in tail_transactions:
                    txn.is_confirmed = gli_response['states'].get(txn.hash)

            # Find the bundles for each transaction.
            for txn in tail_transactions:
                gb_response = GetBundlesCommand(
                    self.adapter)(transaction=txn.hash)
                txn_bundles = gb_response['bundles']  # type: List[Bundle]

                if inclusion_states:
                    for bundle in txn_bundles:
                        bundle.is_confirmed = txn.is_confirmed

                all_bundles.extend(txn_bundles)

        return {
            # Sort bundles by tail transaction timestamp.
            'bundles':
            list(
                sorted(
                    all_bundles,
                    key=lambda bundle_: bundle_.tail_transaction.timestamp,
                )),
        }