def test_stop_threshold_zero(self): """ ``stop`` provided, ``threshold`` is 0. """ # Note that the first address has a zero balance. self.adapter.seed_response('getBalances', { 'balances': [0, 1], }) # To keep the unit test nice and speedy, we will mock the address # generator. We already have plenty of unit tests for that # functionality, so we can get away with mocking it here. mock_address_generator = mock.Mock(return_value=[self.addy0, self.addy1]) with mock.patch( 'iota.crypto.addresses.AddressGenerator.get_addresses', mock_address_generator, ): response = self.command( seed = Seed.random(), stop = 2, threshold = 0, ) self.assertEqual(response['totalBalance'], 1) self.assertEqual(len(response['inputs']), 1) # Address 0 was skipped because it has a zero balance. input0 = response['inputs'][0] self.assertIsInstance(input0, Address) self.assertEqual(input0, self.addy1) self.assertEqual(input0.balance, 1) self.assertEqual(input0.key_index, 1)
def test_no_stop_threshold_not_met(self): """ No ``stop`` provided, balance does not meet ``threshold``. """ self.adapter.seed_response('getBalances', { 'balances': [42, 29, 0], }) # To keep the unit test nice and speedy, we will mock the address # generator. We already have plenty of unit tests for that # functionality, so we can get away with mocking it here. # noinspection PyUnusedLocal def mock_address_generator(ag, start, step=1): for addy in [self.addy0, self.addy1, self.addy2][start::step]: yield addy # When ``stop`` is None, the command uses a generator internally. with mock.patch( 'iota.crypto.addresses.AddressGenerator.create_iterator', mock_address_generator, ): with self.assertRaises(BadApiResponse): self.command( seed = Seed.random(), threshold = 72, )
def test_no_transactions(self): """ There are no transactions for the specified seed. """ # To speed up the test, we will mock the address generator. # :py:class:`iota.crypto.addresses.AddressGenerator` already has # its own test case, so this does not impact the stability of the # codebase. # noinspection PyUnusedLocal def create_generator(ag, start, step=1): for addy in [self.addy1][start::step]: yield addy self.adapter.seed_response( 'findTransactions', { 'duration': 1, 'hashes': [], }, ) with mock.patch( 'iota.crypto.addresses.AddressGenerator.create_iterator', create_generator, ): response = self.command(seed=Seed.random()) self.assertDictEqual(response, {'bundles': []})
def test_generate_multiple_digests(self): """ Generating multiple digests. """ seed = Seed.random() mock_get_private_keys =\ mock.Mock(return_value={'keys': [self.key1, self.key2]}) with mock.patch( 'iota.multisig.commands.get_private_keys.GetPrivateKeysCommand._execute', mock_get_private_keys ): # noinspection PyUnresolvedReferences with mock.patch.object(self.key1, 'get_digest') as mock_get_digest_1: # type: mock.MagicMock mock_get_digest_1.return_value = self.digest1 # noinspection PyUnresolvedReferences with mock.patch.object(self.key2, 'get_digest') as mock_get_digest_2: # type: mock.MagicMock mock_get_digest_2.return_value = self.digest2 result = self.command(seed=seed, index=0, count=2, securityLevel=1) self.assertDictEqual(result, {'digests': [self.digest1, self.digest2]}) mock_get_private_keys.assert_called_once_with({ 'count': 2, 'index': 0, 'securityLevel': 1, 'seed': seed, })
def test_start(self): """ Using ``start`` to offset the key range. """ 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': [], }) # To keep the unit test nice and speedy, we will mock the address # generator. We already have plenty of unit tests for that # functionality, so we can get away with mocking it here. # noinspection PyUnusedLocal def mock_address_generator(ag, start, step=1): # If ``start`` has the wrong value, return garbage to make the # test asplode. for addy in [None, self.addy1, self.addy2][start::step]: yield addy # When ``stop`` is None, the command uses a generator internally. with mock.patch( 'iota.crypto.addresses.AddressGenerator.create_iterator', mock_address_generator, ): response = self.command( seed = Seed.random(), start = 1, ) self.assertEqual(response['totalBalance'], 86) self.assertEqual(len(response['inputs']), 1) input0 = response['inputs'][0] self.assertIsInstance(input0, Address) self.assertEqual(input0, self.addy1) self.assertEqual(input0.balance, 86) self.assertEqual(input0.key_index, 1)
def __init__(self, adapter, seed=None, testnet=False): # type: (AdapterSpec, Optional[TrytesCompatible], bool) -> None """ :param seed: Seed used to generate new addresses. If not provided, a random one will be generated. Note: This value is never transferred to the node/network. """ super(Iota, self).__init__(adapter, testnet) self.seed = Seed(seed) if seed else Seed.random()
def test_fail_index_too_small(self): """ ``index`` is less than 0. """ self.assertFilterErrors( { 'index': -1, 'seed': Seed(self.seed), }, { 'index': [f.Min.CODE_TOO_SMALL], }, )
def test_fail_count_too_small(self): """ ``count`` is less than 1. """ self.assertFilterErrors( { 'count': 0, 'seed': Seed(self.seed), }, { 'count': [f.Min.CODE_TOO_SMALL], }, )
def test_fail_inclusion_states_wrong_type(self): """ ``inclusionStates`` is not a boolean. """ self.assertFilterErrors( { 'inclusionStates': '1', 'seed': Seed(self.seed), }, { 'inclusionStates': [f.Type.CODE_WRONG_TYPE], }, )
def test_fail_index_float(self): """ ``index`` is a float value. """ self.assertFilterErrors( { # Not valid, even with an empty fpart; it must be an int. 'index': 42.0, 'seed': Seed(self.seed), }, { 'index': [f.Type.CODE_WRONG_TYPE], }, )
def test_fail_securityLevel_float(self): """ ``securityLevel`` is a float value. """ self.assertFilterErrors( { 'securityLevel': 1.0, 'seed': Seed(self.seed), }, { 'securityLevel': [f.Type.CODE_WRONG_TYPE], }, )
def test_fail_checksum_wrong_type(self): """ ``checksum`` is not a boolean. """ self.assertFilterErrors( { 'checksum': '2', 'seed': Seed(self.seed), }, { 'checksum': [f.Type.CODE_WRONG_TYPE], }, )
def test_fail_stop_occurs_before_start(self): """ ``stop`` is less than ``start``. """ self.assertFilterErrors( { 'start': 1, 'stop': 0, 'seed': Seed(self.seed), }, { 'start': [GetAccountDataRequestFilter.CODE_INTERVAL_INVALID], }, )
def test_fail_interval_too_large(self): """ ``stop`` is way more than ``start``. """ self.assertFilterErrors( { 'start': 0, 'stop': GetAccountDataRequestFilter.MAX_INTERVAL + 1, 'seed': Seed(self.seed), }, { 'stop': [GetAccountDataRequestFilter.CODE_INTERVAL_TOO_BIG], }, )
def test_pass_happy_path(self): """ Request is valid. """ request = { 'seed': Seed(self.seed), 'index': 1, 'count': 1, } filter_ = self._filter(request) self.assertFilterPasses(filter_) self.assertDictEqual(filter_.cleaned_data, request)
def test_fail_index_string(self): """ ``index`` is a string value. """ self.assertFilterErrors( { # Not valid; it must be an int. 'index': '42', 'seed': Seed(self.seed), }, { 'index': [f.Type.CODE_WRONG_TYPE], }, )
def test_fail_stop_string(self): """ ``stop`` is a string. """ self.assertFilterErrors( { # Not valid; it must be an int. 'stop': '0', 'seed': Seed(self.seed), }, { 'stop': [f.Type.CODE_WRONG_TYPE], }, )
def test_pass_optional_parameters_omitted(self): """ Request omits optional parameters. """ filter_ = self._filter({ 'depth': 100, 'minWeightMagnitude': 13, 'seed': Seed(self.trytes2), 'transfers': [self.transfer1, self.transfer2], }) self.assertFilterPasses(filter_) self.assertDictEqual( filter_.cleaned_data, { 'changeAddress': None, 'inputs': None, 'reference': None, 'depth': 100, 'minWeightMagnitude': 13, 'securityLevel': AddressGenerator.DEFAULT_SECURITY_LEVEL, 'seed': Seed(self.trytes2), 'transfers': [self.transfer1, self.transfer2], })
def test_fail_security_level_too_big(self): """ ``securityLevel`` is > 3. """ self.assertFilterErrors( { 'securityLevel': 4, 'seed': Seed(self.seed), }, { 'securityLevel': [f.Max.CODE_TOO_BIG], }, )
def test_fail_security_level_wrong_type(self): """ ``securityLevel`` is not an int. """ self.assertFilterErrors( { 'securityLevel': '2', 'seed': Seed(self.seed), }, { 'securityLevel': [f.Type.CODE_WRONG_TYPE], }, )
def prompt_for_seed(): # type: () -> Seed """ Prompts the user to enter their seed via stdin. """ seed = secure_input( 'Enter seed and press return (typing will not be shown).\n' 'If no seed is specified, a random one will be used instead.\n' ) if isinstance(seed, text_type): seed = seed.encode('ascii') return Seed(seed) if seed else Seed.random()
def test_fail_securityLevel_too_small(self): """ ``securityLevel`` is less than 1. """ self.assertFilterErrors( { 'securityLevel': 0, 'seed': Seed(self.seed), }, { 'securityLevel': [f.Min.CODE_TOO_SMALL], }, )
def test_fail_securityLevel_string(self): """ ``securityLevel`` is a string value. """ self.assertFilterErrors( { 'securityLevel': '1', 'seed': Seed(self.seed), }, { 'securityLevel': [f.Type.CODE_WRONG_TYPE], }, )
def test_thread_safety(self): """ Address cache is thread-safe, eliminating invalid cache misses when multiple threads attempt to access the cache concurrently. """ AddressGenerator.cache = MemoryAddressCache() seed = Seed.random() generated = [] def get_address(): generator = AddressGenerator(seed) generated.extend(generator.get_addresses(0)) # noinspection PyUnusedLocal def mock_generate_address(address_generator, key_iterator): # type: (AddressGenerator, KeyIterator) -> Address # Insert a teensy delay, to make it more likely that multiple # threads hit the cache concurrently. sleep(0.01) # Note that in this test, the address generator always returns a # new instance. return Address(self.addy, key_index=key_iterator.current) with patch( 'iota.crypto.addresses.AddressGenerator._generate_address', mock_generate_address, ): threads = [Thread(target=get_address) for _ in range(100)] for t in threads: t.start() for t in threads: t.join() # Quick sanity check. self.assertEqual(len(generated), len(threads)) # If the cache is operating in a thread-safe manner, then it will # always return the exact same instance, given the same seed and # key index. expected = generated[0] for actual in generated[1:]: # Compare `id` values instead of using ``self.assertIs`` because # the failure message is a bit easier to understand. self.assertEqual(id(actual), id(expected))
def test_fail_min_weight_magnitude_too_small(self): """ ``minWeightMagnitude`` is < 1. """ self.assertFilterErrors( { 'minWeightMagnitude': 0, 'depth': 100, 'seed': Seed(self.trytes1), 'transfers': [self.transfer1], }, { 'minWeightMagnitude': [f.Min.CODE_TOO_SMALL], }, )
def test_fail_threshold_too_small(self): """ ``threshold`` is less than 0. """ self.assertFilterErrors( { 'threshold': -1, 'seed': Seed(self.seed), }, { 'threshold': [f.Min.CODE_TOO_SMALL], }, )
def test_fail_transfers_empty(self): """ ``transfers`` is an array, but it is empty. """ self.assertFilterErrors( { 'transfers': [], 'depth': 100, 'minWeightMagnitude': 18, 'seed': Seed(self.trytes1), }, { 'transfers': [f.Required.CODE_EMPTY], }, )
def test_fail_transfers_wrong_type(self): """ ``transfers`` is not an array. """ self.assertFilterErrors( { 'transfers': self.transfer1, 'depth': 100, 'minWeightMagnitude': 18, 'seed': Seed(self.trytes1), }, { 'transfers': [f.Type.CODE_WRONG_TYPE], }, )
def test_fail_min_weight_magnitude_null(self): """ ``minWeightMagnitude`` is null. """ self.assertFilterErrors( { 'minWeightMagnitude': None, 'depth': 100, 'seed': Seed(self.trytes1), 'transfers': [self.transfer1], }, { 'minWeightMagnitude': [f.Required.CODE_EMPTY], }, )
def test_fail_stop_float(self): """ ``stop`` is a float. """ self.assertFilterErrors( { # Even with an empty fpart, floats are not valid. # It's gotta be an int. 'stop': 8.0, 'seed': Seed(self.seed), }, { 'stop': [f.Type.CODE_WRONG_TYPE], }, )
def test_fail_unexpected_parameters(self): """ The request contains unexpected parameters. """ self.assertFilterErrors( { 'seed': Seed(self.seed), # Your rules are really beginning to annoy me. 'foo': 'bar', }, { 'foo': [f.FilterMapper.CODE_EXTRA_KEY], }, )
def test_pass_happy_path(self): """ Request is valid. """ request = { 'seed': Seed(self.seed), 'start': 0, 'stop': 10, 'inclusionStates': True, } filter_ = self._filter(request) self.assertFilterPasses(filter_) self.assertDictEqual(filter_.cleaned_data, request)
def test_fail_unexpected_parameters(self): """ The request contains unexpected parameters. """ self.assertFilterErrors( { 'seed': Seed(self.seed), # Told you I did. Reckless is he. Now, matters are worse. 'foo': 'bar', }, { 'foo': [f.FilterMapper.CODE_EXTRA_KEY], }, )
def test_happy_path(self): """ Loading account data for an account. """ # noinspection PyUnusedLocal def mock_iter_used_addresses(adapter, seed, start): """ Mocks the ``iter_used_addresses`` function, so that we can simulate its functionality without actually connecting to the Tangle. References: - :py:func:`iota.commands.extended.utils.iter_used_addresses` """ yield self.addy1, [self.hash1] yield self.addy2, [self.hash2] mock_get_balances = mock.Mock(return_value={'balances': [42, 0]}) # Not particularly realistic, but good enough to prove that the # mocked function was invoked correctly. bundles = [Bundle(), Bundle()] mock_get_bundles_from_transaction_hashes = mock.Mock( return_value=bundles) with mock.patch( 'iota.commands.extended.get_account_data.iter_used_addresses', mock_iter_used_addresses, ): with mock.patch( 'iota.commands.extended.get_account_data.get_bundles_from_transaction_hashes', mock_get_bundles_from_transaction_hashes, ): with mock.patch( 'iota.commands.core.get_balances.GetBalancesCommand._execute', mock_get_balances, ): response = self.command(seed=Seed.random()) self.assertDictEqual( response, { 'addresses': [self.addy1, self.addy2], 'balance': 42, 'bundles': bundles, }, )
def test_security_level_1_no_stop(self): """ Testing GetInputsCoommand: - with security_level = 1 (non default) - without `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] # ``getInputs`` uses ``findTransactions`` and # ``wereAddressesSpentFrom`` to identify unused addresses. # noinspection SpellCheckingInspection self.adapter.seed_response( 'findTransactions', { 'hashes': [ TransactionHash( b'TESTVALUE9DONTUSEINPRODUCTION99999YFXGOD' b'GISBJAX9PDJIRDMDV9DCRDCAEG9FN9KECCBDDFZ9H'), ], }) self.adapter.seed_response('findTransactions', { 'hashes': [], }) self.adapter.seed_response('wereAddressesSpentFrom', { 'states': [False], }) self.adapter.seed_response('getBalances', { 'balances': [86], }) response = GetInputsCommand(self.adapter)( seed=seed, securityLevel=1, ) 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)
def create_one_miniwallet(): sys.stdout = open('wallet.txt', 'wt') miniwallet_seed = Seed.random() print("This is your new Seed:", file=open("wallet.txt", "a")) print(miniwallet_seed, file=open("wallet.txt", "a")) api = iota.Iota(NodeURL, seed=miniwallet_seed) address_set = api.get_new_addresses(index=0, count=2, security_level=2) address_set = address_set['addresses'] print("This is your new Set of Addresses:", file=open("wallet.txt", "a")) address_one = str(address_set[0].with_valid_checksum()) address_two = str(address_set[1].with_valid_checksum()) print("Your Brand new Address 1 :", file=open("wallet.txt", "a")) print(address_one, file=open("wallet.txt", "a")) print("Your Brand new Address 2 :", file=open("wallet.txt", "a")) print(address_two, file=open("wallet.txt", "a")) return (address_one, address_two, miniwallet_seed)
def test_fail_reference_not_trytes(self): """ ``reference`` contains invalid characters. """ self.assertFilterErrors( { 'reference': b'not valid; must contain only uppercase and "9"', 'seed': Seed(self.trytes1), 'depth': 100, 'minWeightMagnitude': 18, 'transfers': [self.transfer1], }, { 'reference': [Trytes.CODE_NOT_TRYTES], }, )
def test_happy_path(self): """ Loading account data for an account. """ # noinspection PyUnusedLocal def mock_iter_used_addresses(adapter, seed, start): """ Mocks the ``iter_used_addresses`` function, so that we can simulate its functionality without actually connecting to the Tangle. References: - :py:func:`iota.commands.extended.utils.iter_used_addresses` """ yield self.addy1, [self.hash1] yield self.addy2, [self.hash2] mock_get_balances = mock.Mock(return_value={'balances': [42, 0]}) # Not particularly realistic, but good enough to prove that the # mocked function was invoked correctly. bundles = [Bundle(), Bundle()] mock_get_bundles_from_transaction_hashes = mock.Mock(return_value=bundles) with mock.patch( 'iota.commands.extended.get_account_data.iter_used_addresses', mock_iter_used_addresses, ): with mock.patch( 'iota.commands.extended.get_account_data.get_bundles_from_transaction_hashes', mock_get_bundles_from_transaction_hashes, ): with mock.patch( 'iota.commands.core.get_balances.GetBalancesCommand._execute', mock_get_balances, ): response = self.command(seed=Seed.random()) self.assertDictEqual( response, { 'addresses': [self.addy1, self.addy2], 'balance': 42, 'bundles': bundles, }, )
def test_no_transactions(self): """ Loading account data for a seed that hasn't been used yet. """ with mock.patch( 'iota.commands.extended.get_account_data.iter_used_addresses', mock.Mock(return_value=[]), ): response = self.command(seed=Seed.random()) self.assertDictEqual( response, { 'addresses': [], 'balance': 0, 'bundles': [], }, )
def test_random(self): """ Generating a random seed. """ with warnings.catch_warnings(record=True) as catched_warnings: # all warnings should be triggered warnings.simplefilter("always") seed = Seed.random() self.assertEqual(len(catched_warnings), 0) # Regression test: ``random`` MUST return a :py:class:`Seed`, NOT a # :py:class:`TryteString`! self.assertIsInstance(seed, Seed) # Regression test: Random seed must be exactly 81 trytes long. # https://github.com/iotaledger/iota.lib.py/issues/44 self.assertEqual(len(seed), Hash.LEN)
def test_random_seed_too_long(self): """ Generating a random seed, which is too long. """ with warnings.catch_warnings(record=True) as catched_warnings: # Cause seed related warnings to be triggered warnings.simplefilter("always", category=SeedWarning) seed = Seed.random(length=Hash.LEN + 1) # check attributes of warning self.assertEqual(len(catched_warnings), 1) self.assertIs(catched_warnings[-1].category, SeedWarning) self.assertIn( "inappropriate length", text_type(catched_warnings[-1].message), ) self.assertEqual(len(seed), Hash.LEN + 1)
def test_stop_no_threshold(self): """ ``stop`` provided, no ``threshold``. """ self.adapter.seed_response('getBalances', { 'balances': [42, 29], }) # To keep the unit test nice and speedy, we will mock the address # generator. We already have plenty of unit tests for that # functionality, so we can get away with mocking it here. mock_address_generator = mock.Mock(return_value=[self.addy0, self.addy1]) with mock.patch( 'iota.crypto.addresses.AddressGenerator.get_addresses', mock_address_generator, ): response = self.command( seed = Seed.random(), start = 0, stop = 2, ) self.assertEqual(response['totalBalance'], 71) self.assertEqual(len(response['inputs']), 2) input0 = response['inputs'][0] self.assertIsInstance(input0, Address) self.assertEqual(input0, self.addy0) self.assertEqual(input0.balance, 42) self.assertEqual(input0.key_index, 0) input1 = response['inputs'][1] self.assertIsInstance(input1, Address) self.assertEqual(input1, self.addy1) self.assertEqual(input1.balance, 29) self.assertEqual(input1.key_index, 1)
def test_stop_threshold_not_met(self): """ ``stop`` provided, balance does not meet ``threshold``. """ self.adapter.seed_response('getBalances', { 'balances': [42, 29], }) # To keep the unit test nice and speedy, we will mock the address # generator. We already have plenty of unit tests for that # functionality, so we can get away with mocking it here. mock_address_generator = mock.Mock(return_value=[self.addy0, self.addy1]) with mock.patch( 'iota.crypto.addresses.AddressGenerator.get_addresses', mock_address_generator, ): with self.assertRaises(BadApiResponse): self.command( seed = Seed.random(), stop = 2, threshold = 72, )
def test_full_scan(self): """ Scanning the Tangle for all transfers. """ # To speed up the test, we will mock the address generator. # :py:class:`iota.crypto.addresses.AddressGenerator` already has # its own test case, so this does not impact the stability of the # codebase. # noinspection PyUnusedLocal def create_generator(ag, start, step=1): for addy in [self.addy1, self.addy2][start::step]: yield addy # The first address received IOTA. self.adapter.seed_response( 'findTransactions', { 'duration': 42, 'hashes': [ 'TESTVALUEFIVE9DONTUSEINPRODUCTION99999VH' 'YHRHJETGYCAFZGABTEUBWCWAS9WF99UHBHRHLIOFJ', ], }, ) # The second address is unused. self.adapter.seed_response( 'findTransactions', { 'duration': 1, 'hashes': [], }, ) self.adapter.seed_response( 'getTrytes', { 'duration': 99, # Thankfully, we do not have to seed a realistic response for # ``getTrytes``, as we will be mocking the ``getBundles`` # command that uses on it. 'trytes': [''], }, ) bundle = Bundle([ Transaction( address = self.addy1, timestamp = 1483033814, # These values are not relevant to the test. hash_ = None, signature_message_fragment = None, value = 42, tag = Tag(b''), current_index = 0, last_index = 0, bundle_hash = None, trunk_transaction_hash = None, branch_transaction_hash = None, attachment_timestamp = 1483033814, attachment_timestamp_lower_bound = 12, attachment_timestamp_upper_bound = 0, nonce = None, ) ]) mock_get_bundles =\ mock.Mock(return_value={ 'bundles': [bundle], }) with mock.patch( 'iota.crypto.addresses.AddressGenerator.create_iterator', create_generator, ): with mock.patch( 'iota.commands.extended.get_bundles.GetBundlesCommand._execute', mock_get_bundles, ): response = self.command(seed=Seed.random()) self.assertDictEqual( response, { 'bundles': [bundle], }, )
def test_stop(self): """ Scanning the Tangle for all transfers, with stop index. """ # noinspection PyUnusedLocal def create_generator(ag, start, step=1): # Inject an invalid value into the generator, to ensure it is # skipped. for addy in [self.addy1, None][start::step]: yield addy # The first address received IOTA. self.adapter.seed_response( 'findTransactions', { 'duration': 42, 'hashes': [ 'TESTVALUEFIVE9DONTUSEINPRODUCTION99999VH' 'YHRHJETGYCAFZGABTEUBWCWAS9WF99UHBHRHLIOFJ', ], }, ) self.adapter.seed_response( 'getTrytes', { 'duration': 99, 'trytes': [''], }, ) bundle = Bundle([ Transaction( address = self.addy1, timestamp = 1483033814, # These values are not relevant to the test. hash_ = None, signature_message_fragment = None, value = 42, tag = Tag(b''), current_index = 0, last_index = 0, bundle_hash = None, trunk_transaction_hash = None, branch_transaction_hash = None, attachment_timestamp = 1483033814, attachment_timestamp_lower_bound = 12, attachment_timestamp_upper_bound = 0, nonce = None, ) ]) mock_get_bundles = mock.Mock(return_value={ 'bundles': [bundle], }) with mock.patch( 'iota.crypto.addresses.AddressGenerator.create_iterator', create_generator, ): with mock.patch( 'iota.commands.extended.get_bundles.GetBundlesCommand._execute', mock_get_bundles, ): response = self.command(seed=Seed.random(), stop=1) self.assertDictEqual( response, { 'bundles': [bundle], }, )
def test_happy_path(self): """ Sending a transfer successfully. """ # noinspection SpellCheckingInspection transaction1 =\ TransactionTrytes( b'GYPRVHBEZOOFXSHQBLCYW9ICTCISLHDBNMMVYD9JJHQMPQCTIQAQTJNNNJ9IDXLRCC' b'OYOXYPCLR9PBEY9ORZIEPPDNTI9CQWYZUOTAVBXPSBOFEQAPFLWXSWUIUSJMSJIIIZ' b'WIKIRH9GCOEVZFKNXEVCUCIIWZQCQEUVRZOCMEL9AMGXJNMLJCIA9UWGRPPHCEOPTS' b'VPKPPPCMQXYBHMSODTWUOABPKWFFFQJHCBVYXLHEWPD9YUDFTGNCYAKQKVEZYRBQRB' b'XIAUX9SVEDUKGMTWQIYXRGSWYRK9SRONVGTW9YGHSZRIXWGPCCUCDRMAXBPDFVHSRY' b'WHGB9DQSQFQKSNICGPIPTRZINYRXQAFSWSEWIFRMSBMGTNYPRWFSOIIWWT9IDSELM9' b'JUOOWFNCCSHUSMGNROBFJX9JQ9XT9PKEGQYQAWAFPRVRRVQPUQBHLSNTEFCDKBWRCD' b'X9EYOBB9KPMTLNNQLADBDLZPRVBCKVCYQEOLARJYAGTBFR9QLPKZBOYWZQOVKCVYRG' b'YI9ZEFIQRKYXLJBZJDBJDJVQZCGYQMROVHNDBLGNLQODPUXFNTADDVYNZJUVPGB9LV' b'PJIYLAPBOEHPMRWUIAJXVQOEM9ROEYUOTNLXVVQEYRQWDTQGDLEYFIYNDPRAIXOZEB' b'CS9P99AZTQQLKEILEVXMSHBIDHLXKUOMMNFKPYHONKEYDCHMUNTTNRYVMMEYHPGASP' b'ZXASKRUPWQSHDMU9VPS99ZZ9SJJYFUJFFMFORBYDILBXCAVJDPDFHTTTIYOVGLRDYR' b'TKHXJORJVYRPTDH9ZCPZ9ZADXZFRSFPIQKWLBRNTWJHXTOAUOL9FVGTUMMPYGYICJD' b'XMOESEVDJWLMCVTJLPIEKBE9JTHDQWV9MRMEWFLPWGJFLUXI9BXPSVWCMUWLZSEWHB' b'DZKXOLYNOZAPOYLQVZAQMOHGTTQEUAOVKVRRGAHNGPUEKHFVPVCOYSJAWHZU9DRROH' b'BETBAFTATVAUGOEGCAYUXACLSSHHVYDHMDGJP9AUCLWLNTFEVGQGHQXSKEMVOVSKQE' b'EWHWZUDTYOBGCURRZSJZLFVQQAAYQO9TRLFFN9HTDQXBSPPJYXMNGLLBHOMNVXNOWE' b'IDMJVCLLDFHBDONQJCJVLBLCSMDOUQCKKCQJMGTSTHBXPXAMLMSXRIPUBMBAWBFNLH' b'LUJTRJLDERLZFUBUSMF999XNHLEEXEENQJNOFFPNPQ9PQICHSATPLZVMVIWLRTKYPI' b'XNFGYWOJSQDAXGFHKZPFLPXQEHCYEAGTIWIJEZTAVLNUMAFWGGLXMBNUQTOFCNLJTC' b'DMWVVZGVBSEBCPFSM99FLOIDTCLUGPSEDLOKZUAEVBLWNMODGZBWOVQT9DPFOTSKRA' b'BQAVOQ9RXWBMAKFYNDCZOJGTCIDMQSQQSODKDXTPFLNOKSIZEOY9HFUTLQRXQMEPGO' b'XQGLLPNSXAUCYPGZMNWMQWSWCKAQYKXJTWINSGPPZG9HLDLEAWUWEVCTVRCBDFOXKU' b'ROXH9HXXAXVPEJFRSLOGRVGYZASTEBAQNXJJROCYRTDPYFUIQJVDHAKEG9YACV9HCP' b'JUEUKOYFNWDXCCJBIFQKYOXGRDHVTHEQUMHO999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999RKWEEVD99A99999999A99999999NFDPEEZCWVYLKZGSLCQNOFUSENI' b'XRHWWTZFBXMPSQHEDFWZULBZFEOMNLRNIDQKDNNIELAOXOVMYEI9PGTKORV9IKTJZQ' b'UBQAWTKBKZ9NEZHBFIMCLV9TTNJNQZUIJDFPTTCTKBJRHAITVSKUCUEMD9M9SQJ999' b'999TKORV9IKTJZQUBQAWTKBKZ9NEZHBFIMCLV9TTNJNQZUIJDFPTTCTKBJRHAITVSK' b'UCUEMD9M9SQJ999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999' ) mock_prepare_transfer =\ mock.Mock(return_value={ 'trytes': [transaction1], }) mock_send_trytes =\ mock.Mock(return_value={ 'trytes': [transaction1], }) with mock.patch( 'iota.commands.extended.prepare_transfer.PrepareTransferCommand._execute', mock_prepare_transfer, ): with mock.patch( 'iota.commands.extended.send_trytes.SendTrytesCommand._execute', mock_send_trytes, ): response = self.command( depth = 100, minWeightMagnitude = 18, seed = Seed.random(), transfers = [ ProposedTransaction( address = Address( b'9999999999999999999999999999999999999999' b'99999999999999999999999999999999999999999' ), value = 0, ), ], ) bundle = response['bundle'] # type: Bundle self.assertEqual(len(bundle), 1) self.assertEqual(bundle[0].as_tryte_string(), transaction1)
def test_get_inclusion_states(self): """ Fetching inclusion states with transactions. """ # noinspection PyUnusedLocal def create_generator(ag, start, step=1): for addy in [self.addy1][start::step]: yield addy # The first address received IOTA. self.adapter.seed_response( 'findTransactions', { 'duration': 42, 'hashes': [ 'TESTVALUEFIVE9DONTUSEINPRODUCTION99999VH' 'YHRHJETGYCAFZGABTEUBWCWAS9WF99UHBHRHLIOFJ', ], }, ) # For this test, we have to generate a real TryteString. transaction_trytes =\ TryteString( b'KMYUMNEUAYODAQSNGWTAERRRHNZBZCOLMVVOBTVWLOFYCJKYMGRAMH9RQ9MTZOSZMH' b'QNZFHFEJEDFQ99HSUNVOTULDJGXEDULS9ZHABVDZODJUMCNWVCPNSCUVKVYWCEXBHW' b'RBZBSWFPQLWZWMUPGQIGAEGOVE9DDXBVCIPKQYCFZFBELTSMVFSIXLPTACTKAFMCTK' b'CPYD9BWDJMLKWAOBDSJNQYAHS9GFIQKZCROLFZJVUEIVXVNBRRLEIWTYVHURUXHSCG' b'DKEIEGPOCXKCYWIBUG9ABYCALYJVFLBNGMS9ARHGTQXBZFLENXCJVKHPVKD9KSAEOL' b'FFVAJCNKLDVHOCDARWUNKARDYMVKFKRSMUTYOUXSBFFYTKRREBDJZTLVUROQFCBXQN' b'SXDDYTZTEBRSXOBMLXHJKSJAVOOVCXATOWNQDWHT9CCUAAJUJKDOQLMAEZACSNFKXZ' b'IGWDQEUEFRZYAOSDNVMSXWYLVDAUXZSHNHAIBEMNPFUGORYUETNJK9UCEMSUJYBBDK' b'BHIPKEINQCGOVYCPKUPJMUCUVZOJSIWYRFMFXYUVSMOUALAQBWIMXBUBXSAETGKJRP' b'AHVAXHQJDMEVSRFYEXUSIEBKMGYCUKFD9JPGUV9AIYUVCRUURKMYUHMVE9OJCYYWTQ' b'WUWFMTBZYFXASHHVCMSWXKBRQFHHQVEQMEULJRWZKLWFFSGGKEHUZZFNDNITSRAUH9' b'PQK9OGLYMVBSHXQLLZHOBBIM9KVUWDLHZRDKQQVLQXGWYXEEVQPDZUO9PVXMALOMRQ' b'VCTHGIZLILSCFKTBRESYZGBZKHXEODNDJZ9GK9ROWYXNGFHZCCBHHZEYEOGWXRGSUD' b'SUZFUAUBXVXZHCUVJSYBWTCYCEDYKZNGWFZYKSQLW9FUYMWDVXKZEWT9SCVMQCODZK' b'DRNKTINTPNOJOLGQJDAJMFWRFSWZJLYZGSTSIDSXLUJBZRZNLEDNBKAUNGTCYUPDRW' b'JOCEBQ9YG9IZLLRMJITISJOTLQMOGXVQIZXHMTJVMMWM9FOIOT9KFZMANEPOEOV9HX' b'JNEGURUKRWDGYNPVGAWMWQVABIJNL9MDXKONEPMYACOZ9BE9UZMAFTKYWPFWIQWAPK' b'GUXQTOQVWYYVZYGQDLBIQDVOZIWGOMGOBAUARICQZVNXD9UVEFBBAJKQBHRHXTBUOW' b'VBFKYQWZWTMMXVKZRIZUBVPQ9XHLJHFHWFZUIZVSNAKBDHDFGJCYQETOMEDTOXIUT9' b'OAJVIHWAGTCNPEZTERMMN9EZEWSJHKQAUMXPBZTNQOEQCVXIMAAYO9NIUFLTCFIMK9' b'9AFAGWJFA9VOFPUDJLRAMORGSUDBLWWKXEDZ9XPQUZSGANGESHKKGGQSGSYDCRLHZD' b'PKA9HKYBKLKKCXYRQQIPXCFETJJDZYPCLUNHGBKEJDRCIHEXKCQQNOV9QFHLGFXOCR' b'HPAFCUTPMY9NOZVQHROYJSCMGRSVMOBWADAZNFIAHWGIQUUZBOVODSFAUNRTXSDU9W' b'EIRBXQNRSJXFRAQGHA9DYOQJGLVZUJKAQ9CTUOTT9ZKQOQNNLJDUPDXZJYPRCVLRZT' b'UCZPNBREYCCKHK9FUWGITAJATFPUOFLZDHPNJYUTXFGNYJOBRD9BVHKZENFXIUYDTL' b'CE9JYIIYMXMCXMWTHOLTQFKFHDLVPGMQNITEUXSYLAQULCZOJVBIPYP9M9X9QCNKBX' b'W9DVJEQFFY9KQVMKNVTAHQVRXUKEM9FZOJLHAGEECZBUHOQFZOSPRXKZOCCKAOHMSV' b'QCFG9CWAHKVWNA9QTLYQI9NKOSHWJCNGPJBLEQPUIWJBIOAWKLBXUCERTSL9FVCLYN' b'ADPYTPKJOIEMAQGWBVGSRCZINXEJODUDCT9FHOUMQM9ZHRMBJYSOMPNMEAJGEHICJI' b'PVXRKCYX9RZVT9TDZIMXGZJAIYJRGIVMSOICSUINRBQILMJOUQYXCYNJ9WGGJFHYTU' b'LWOIPUXXFNTIFNOJRZFSQQNAWBQZOLHHLVGHEPWTKKQEVIPVWZUN9ZBICZ9DZZBVII' b'BF9EPHARZJUFJGBQXQFQIBUECAWRSEKYJNYKNSVBCOWTFBZ9NAHFSAMRBPEYGPRGKW' b'WTWACZOAPEOECUO9OTMGABJVAIICIPXGSXACVINSYEQFTRCQPCEJXZCY9XZWVWVJRZ' b'CYEYNFUUBKPWCHICGJZXKE9GSUDXZYUAPLHAKAHYHDXNPHENTERYMMBQOPSQIDENXK' b'LKCEYCPVTZQLEEJVYJZV9BWU999999999999999999999999999FFL999999999999' b'9999999999999RJQGVD99999999999A99999999USGBXHGJUEWAUAKNPPRHJXDDMQV' b'YDSYZJSDWFYLOQVFGBOSLE9KHFDLDYHUYTXVSFAFCOCLQUHJXTEIQRNBTLHEGJFGVF' b'DJCE9IKAOCSYHLCLWPVVNWNESKLYAJG9FGGZOFXCEYOTWLVIJUHGY9QCU9FMZJY999' b'9999HYBUYQKKRNAVDPVGYBTVDZ9SVQBLCCVLJTPEQWWOIG9CQZIFQKCROH9YHUCNJT' b'SYPBVZVBNESX999999D9TARGPQTNIYRZURQGVHCAWEDRBJIIEJIUZYENVE9LLJQMXH' b'GSUUYUCPSOWBCXVFDCHHAZUDC9LUODYWO' ) self.adapter.seed_response( 'getTrytes', { 'duration': 99, 'trytes': [binary_type(transaction_trytes)], }, ) transaction = Transaction.from_tryte_string(transaction_trytes) mock_get_bundles = mock.Mock(return_value={ 'bundles': [Bundle([transaction])], }) mock_get_latest_inclusion = mock.Mock(return_value={ 'states': { transaction.hash: True, }, }) with mock.patch( 'iota.crypto.addresses.AddressGenerator.create_iterator', create_generator, ): with mock.patch( 'iota.commands.extended.get_bundles.GetBundlesCommand._execute', mock_get_bundles, ): with mock.patch( 'iota.commands.extended.get_latest_inclusion.GetLatestInclusionCommand._execute', mock_get_latest_inclusion, ): response = self.command( seed = Seed.random(), inclusionStates = True, # To keep the test focused, only retrieve a single # transaction. start = 0, stop = 1, ) bundle = response['bundles'][0] # type: Bundle self.assertTrue(bundle[0].is_confirmed)
def test_no_stop_no_threshold(self): """ No ``stop`` provided, no ``threshold``. """ self.adapter.seed_response('getBalances', { 'balances': [42, 29], }) # ``getInputs`` uses ``findTransactions`` to identify unused # addresses. # noinspection SpellCheckingInspection self.adapter.seed_response('findTransactions', { 'hashes': [ TransactionHash( b'TESTVALUE9DONTUSEINPRODUCTION99999WBL9KD' b'EIZDMEDFPEYDIIA9LEMEUCC9MFPBY9TEVCUGSEGGN' ), ], }) # noinspection SpellCheckingInspection self.adapter.seed_response('findTransactions', { 'hashes': [ TransactionHash( b'TESTVALUE9DONTUSEINPRODUCTION99999YFXGOD' b'GISBJAX9PDJIRDMDV9DCRDCAEG9FN9KECCBDDFZ9H' ), ], }) self.adapter.seed_response('findTransactions', { 'hashes': [], }) # To keep the unit test nice and speedy, we will mock the address # generator. We already have plenty of unit tests for that # functionality, so we can get away with mocking it here. # noinspection PyUnusedLocal def mock_address_generator(ag, start, step=1): for addy in [self.addy0, self.addy1, self.addy2][start::step]: yield addy # When ``stop`` is None, the command uses a generator internally. with mock.patch( 'iota.crypto.addresses.AddressGenerator.create_iterator', mock_address_generator, ): response = self.command( seed = Seed.random(), ) self.assertEqual(response['totalBalance'], 71) self.assertEqual(len(response['inputs']), 2) input0 = response['inputs'][0] self.assertIsInstance(input0, Address) self.assertEqual(input0, self.addy0) self.assertEqual(input0.balance, 42) self.assertEqual(input0.key_index, 0) input1 = response['inputs'][1] self.assertIsInstance(input1, Address) self.assertEqual(input1, self.addy1) self.assertEqual(input1.balance, 29) self.assertEqual(input1.key_index, 1)