def test_generator_checksum(self):
        """
    Creating a generator with checksums on the addresses.
    """
        ag = AddressGenerator(
            self.seed_2,
            security_level=AddressGenerator.DEFAULT_SECURITY_LEVEL,
            checksum=True)

        generator = ag.create_iterator()

        # noinspection SpellCheckingInspection
        self.assertEqual(
            next(generator),
            Address(
                b'FNKCVJPUANHNWNBAHFBTCONMCUBC9KCZ9EKREBCJ'
                b'AFMABCTEPLGGXDJXVGPXDCFOUCRBWFJFLEAVOEUPY'
                b'ADHVCBXFD', ),
        )

        # noinspection SpellCheckingInspection
        self.assertEqual(
            next(generator),
            Address(
                b'MSYILYYZLSJ99TDMGQHDOBWGHTBARCBGJZE9PIMQ'
                b'LTEXJXKTDREGVTPA9NDGGLQHTMGISGRAKSLYPGWMB'
                b'WIKQRCIOD', ),
        )
    def test_get_addresses_single(self):
        """
    Generating a single address.
    """
        ag = AddressGenerator(self.seed_1)

        # noinspection SpellCheckingInspection
        self.assertListEqual(
            ag.get_addresses(start=0),
            [
                Address(
                    b'DLEIS9XU9V9T9OURAKDUSQWBQEYFGJLRPRVEWKN9'
                    b'SSUGIHBEIPBPEWISSAURGTQKWKWNHXGCBQTWNOGIY', ),
            ],
        )

        # noinspection SpellCheckingInspection
        self.assertListEqual(
            ag.get_addresses(start=10),
            [
                Address(
                    b'XLXFTFBXUOOHRJDVBDBFEBDQDUKSLSOCLUYWGLAP'
                    b'R9FUROUHPFINIUFKYSRTFMNWKNEPDZATWXIVWJMDD', ),
            ],
        )
    def test_get_addresses_error_step_zero(self):
        """
    Providing a ``step`` value of 0 to ``get_addresses``.
    """
        ag = AddressGenerator(seed=b'')

        with self.assertRaises(ValueError):
            ag.get_addresses(start=0, step=0)
    def test_get_addresses_error_start_too_small(self):
        """
    Providing a negative ``start`` value to ``get_addresses``.

    :py:class:`AddressGenerator` can potentially generate an infinite
    number of addresses, so there is no "end" to offset against.
    """
        ag = AddressGenerator(seed=b'')

        with self.assertRaises(ValueError):
            ag.get_addresses(start=-1)
Exemple #5
0
async def iter_used_addresses(
        adapter,  # type: BaseAdapter
        seed,  # type: Seed
        start,  # type: int
        security_level=None,  # type: Optional[int]
):
    # type: (...) -> Generator[Tuple[Address, List[TransactionHash]], None, None]
    """
    Scans the Tangle for used addresses.

    This is basically the opposite of invoking ``getNewAddresses`` with
    ``stop=None``.
    """
    if security_level is None:
        security_level = AddressGenerator.DEFAULT_SECURITY_LEVEL

    ft_command = FindTransactionsCommand(adapter)

    for addy in AddressGenerator(seed, security_level).create_iterator(start):
        ft_response = await ft_command(addresses=[addy])

        if ft_response['hashes']:
            yield addy, ft_response['hashes']
        else:
            break

        # Reset the command so that we can call it again.
        ft_command.reset()
    async def _execute(self, request):
        inclusion_states = request['inclusionStates']  # type: bool
        seed = request['seed']  # type: Seed
        start = request['start']  # type: int
        stop = request['stop']  # type: Optional[int]

        # Determine the addresses we will be scanning, and pull their
        # transaction hashes.
        if stop is None:
            my_hashes = list(
                chain(*(hashes for _, hashes in await iter_used_addresses(
                    self.adapter, seed, start))))
        else:
            ft_response = \
                await FindTransactionsCommand(self.adapter)(
                    addresses=
                    AddressGenerator(seed).get_addresses(start, stop - start),
                )

            my_hashes = ft_response['hashes']

        return {
            'bundles':
            await get_bundles_from_transaction_hashes(
                adapter=self.adapter,
                transaction_hashes=my_hashes,
                inclusion_states=inclusion_states,
            ),
        }
    def test_get_addresses_step_negative(self):
        """
    Providing a negative ``step`` value to ``get_addresses``.

    This is probably a weird use case, but what the heck.
    """
        ag = AddressGenerator(self.seed_1)

        # noinspection SpellCheckingInspection
        self.assertListEqual(
            ag.get_addresses(start=1, count=2, step=-1),
            [
                Address(
                    b'PNLOTLFSALMICK9PSW9ZWLE9KJAKPKGJZQJDAFMO'
                    b'VLHXMJCJXFPVHOTTOYDIAUAYELXKZWZUITCQBIQKY', ),
                Address(
                    b'DLEIS9XU9V9T9OURAKDUSQWBQEYFGJLRPRVEWKN9'
                    b'SSUGIHBEIPBPEWISSAURGTQKWKWNHXGCBQTWNOGIY', ),
            ],
        )
    def test_security_level_elevated(self):
        """
    Generating addresses with a higher security level.
    """
        ag = AddressGenerator(self.seed_1, security_level=3)

        # noinspection SpellCheckingInspection
        self.assertListEqual(
            ag.get_addresses(start=0, count=3),
            [
                Address(
                    b'BGHTGOUKKNTYFHYUAAPSRUEVN9QQXFOGVCH9Y9BO'
                    b'NWXUBDLSKAWEOFZIVMHXBAYVPGDZEYCKNTUJCLPAX', ),
                Address(
                    b'EGMRJEUIYFUGWAIXXZCHCZUVUUYITICVHDSHCQXG'
                    b'FHJIVDCLTI9ZVRIKRLZQWW9CPOIXVDCBAHVGLUHI9', ),
                Address(
                    b'ENPSARVJZGMMPWZTAIRHADEOZCEVIFNJWSZQHNEI'
                    b'RVEVI9GYMFNEOGNUYCPGPSEFCSDHUHOQKDPVGDKYC', ),
            ],
        )
    def test_security_level_lowered(self):
        """
    Generating addresses with a lower security level.
    """
        ag = AddressGenerator(self.seed_1, security_level=1)

        # noinspection SpellCheckingInspection
        self.assertListEqual(
            ag.get_addresses(start=0, count=3),
            [
                Address(
                    b'KNDWDEEWWFVZLISLYRABGVWZCHZNZLNSEJXFKVGA'
                    b'UFLL9UMZYEZMEJB9BDLAASWTHEKFREUDIUPY9ICKW', ),
                Address(
                    b'CHOBTRTQWTMH9GWFWGWUODRSGPOJOIVJUNIQIBZL'
                    b'HSWNYPHOD9APWJBMJMGLHFZENWFKDYWHX9JDFXTAB', ),
                Address(
                    b'YHTOYQUCLDHAIDILFNPITVPYSTOCFAZIUNDYTRDZ'
                    b'CVMVGZPONPINNVPJTOAOKHHZWLOKIZPVASTOGAKPA', ),
            ],
        )
    async def _find_addresses(self, seed, index, count, security_level, checksum):
        # type: (Seed, int, Optional[int], int, bool) -> List[Address]
        """
        Find addresses matching the command parameters.
        """
        generator = AddressGenerator(seed, security_level, checksum)

        if count is None:
            # Connect to Tangle and find the first address without any
            # transactions.
            for addy in generator.create_iterator(start=index):
                # We use addy.address here because FindTransactions does
                # not work on an address with a checksum
                response = await FindTransactionsCommand(self.adapter)(
                    addresses=[addy.address],
                )

                if not response.get('hashes'):
                    return [addy]

        return generator.get_addresses(start=index, count=count)
    def test_generator_with_offset(self):
        """
    Creating a generator that starts at an offset greater than 0.
    """
        ag = AddressGenerator(self.seed_1)

        generator = ag.create_iterator(start=1, step=2)

        # noinspection SpellCheckingInspection
        self.assertEqual(
            next(generator),
            Address(
                b'PNLOTLFSALMICK9PSW9ZWLE9KJAKPKGJZQJDAFMO'
                b'VLHXMJCJXFPVHOTTOYDIAUAYELXKZWZUITCQBIQKY', ),
        )

        # noinspection SpellCheckingInspection
        self.assertEqual(
            next(generator),
            Address(
                b'IWWMMHBFWCWOZQLBNXDJ9OOTIGXXU9WNUHFGUZWR'
                b'9FWGIUUUQUECHPKXJLIEKZBOVSEA9BCT9DLOCNCEC', ),
        )
    def test_generator(self):
        """
    Creating a generator.
    """
        ag = AddressGenerator(self.seed_2)

        generator = ag.create_iterator()

        # noinspection SpellCheckingInspection
        self.assertEqual(
            next(generator),
            Address(
                b'FNKCVJPUANHNWNBAHFBTCONMCUBC9KCZ9EKREBCJ'
                b'AFMABCTEPLGGXDJXVGPXDCFOUCRBWFJFLEAVOEUPY', ),
        )

        # noinspection SpellCheckingInspection
        self.assertEqual(
            next(generator),
            Address(
                b'MSYILYYZLSJ99TDMGQHDOBWGHTBARCBGJZE9PIMQ'
                b'LTEXJXKTDREGVTPA9NDGGLQHTMGISGRAKSLYPGWMB', ),
        )
    def test_get_addresses_multiple(self):
        """
    Generating multiple addresses in one go.
    """
        ag = AddressGenerator(self.seed_2)

        # noinspection SpellCheckingInspection
        self.assertListEqual(
            ag.get_addresses(start=0, count=3),
            [
                Address(
                    b'FNKCVJPUANHNWNBAHFBTCONMCUBC9KCZ9EKREBCJ'
                    b'AFMABCTEPLGGXDJXVGPXDCFOUCRBWFJFLEAVOEUPY', ),
                Address(
                    b'MSYILYYZLSJ99TDMGQHDOBWGHTBARCBGJZE9PIMQ'
                    b'LTEXJXKTDREGVTPA9NDGGLQHTMGISGRAKSLYPGWMB', ),
                Address(
                    b'IIREHGHXUHARKVZDMHGUUCHZLUEQQULLEUSJHIIB'
                    b'WFYZIZDUFTOVHAWCKRJXUZ9CSUVLTRYSUGBVRMTOW', ),
            ],
        )

        # noinspection SpellCheckingInspection
        self.assertListEqual(
            ag.get_addresses(start=10, count=3),
            [
                Address(
                    b'BPXMVV9UPKBTVPJXPBHHOJYAFLALOYCGTSEDLZBH'
                    b'NFMGEHREBQTRIPZAPREANPMZJNZZNCDIUFOYYGGFY', ),
                Address(
                    b'RUCZQJWKXVDIXTLHHOKGMHOV9AKVDBG9HUQHPWNZ'
                    b'UNKJNFVMULUSLKFJGSTBSNJMRYSJOBVBQSKVXISZB', ),
                Address(
                    b'FQAKF9XVCLTBESJKWCHFOCTVABYEEJP9RXUVAEUW'
                    b'ENFUUQK9VCHFEORHCYDUJQHNUDWNRDUDZTUGKHSPD', ),
            ],
        )
Exemple #14
0
    async def _execute(self, request):
        inclusion_states = request['inclusionStates']  # type: bool
        seed = request['seed']  # type: Seed
        start = request['start']  # type: int
        stop = request['stop']  # type: Optional[int]
        security_level = request['security_level']  # type: Optional[int]

        if stop is None:
            my_addresses = []  # type: List[Address]
            my_hashes = []  # type: List[TransactionHash]

            for addy, hashes in iter_used_addresses(self.adapter, seed, start,
                                                    security_level):
                my_addresses.append(addy)
                my_hashes.extend(hashes)
        else:
            my_addresses = (AddressGenerator(seed,
                                             security_level).get_addresses(
                                                 start, stop - start))
            my_hashes = await FindTransactionsCommand(self.adapter
                                                      )(addresses=my_addresses)
            my_hashes = my_hashes.get('hashes') or []

        account_balance = 0
        if my_hashes:
            # Load balances for the addresses that we generated.
            gb_response = (await GetBalancesCommand(self.adapter)
                           (addresses=my_addresses))

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

        return {
            'addresses':
            list(sorted(my_addresses, key=attrgetter('key_index'))),
            'balance':
            account_balance,
            'bundles':
            get_bundles_from_transaction_hashes(
                adapter=self.adapter,
                transaction_hashes=my_hashes,
                inclusion_states=inclusion_states,
            ),
        }
    def test_security_level_1_with_stop(self):
        """
    Testing GetInputsCoommand:
      - with security_level = 1 (non default)
      - with `stop` parameter
    """

        # one address with index 0 for selected security levels for the random seed.
        # to check with respective outputs from command
        seed = Seed.random()
        address = AddressGenerator(seed, security_level=1).get_addresses(0)[0]

        self.adapter.seed_response('getBalances', {
            'balances': [86],
        })
        # ``getInputs`` uses ``findTransactions`` to identify unused
        # addresses.
        # noinspection SpellCheckingInspection
        self.adapter.seed_response(
            'findTransactions', {
                'hashes': [
                    TransactionHash(
                        b'TESTVALUE9DONTUSEINPRODUCTION99999YFXGOD'
                        b'GISBJAX9PDJIRDMDV9DCRDCAEG9FN9KECCBDDFZ9H'),
                ],
            })
        self.adapter.seed_response('findTransactions', {
            'hashes': [],
        })

        response = GetInputsCommand(self.adapter)(
            seed=seed,
            securityLevel=1,
            stop=1,  # <<<<< here
        )

        self.assertEqual(response['totalBalance'], 86)
        self.assertEqual(len(response['inputs']), 1)

        input0 = response['inputs'][0]
        self.assertIsInstance(input0, Address)
        self.assertEqual(input0, address)
        self.assertEqual(input0.balance, 86)
        self.assertEqual(input0.key_index, 0)
    async 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]
        security_level = request['securityLevel']  # int

        # Determine the addresses we will be scanning.
        if stop is None:
            addresses = [addy for addy, _ in await iter_used_addresses(
                adapter=self.adapter,
                seed=seed,
                start=start,
                security_level=security_level
            )]
        else:
            addresses = (
                AddressGenerator(seed, security_level).get_addresses(
                    start=start,
                    count=stop - start,
                )
            )

        if addresses:
            # Load balances for the addresses that we generated.
            gb_response = await GetBalancesCommand(self.adapter)(addresses=addresses)
        else:
            gb_response = {'balances': []}

        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'],
                },
            )