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 __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() self.helpers = Helpers(self)
def setUp(self): super(AddressGeneratorTestCase, self).setUp() self.seed_1 =\ Seed( b'TESTVALUE9DONTUSEINPRODUCTION999999GFDDC' b'PFIIEHBCWFN9KHRBEIHHREFCKBVGUGEDXCFHDFPAL', ) self.seed_2 =\ Seed( b'TESTVALUE9DONTUSEINPRODUCTION99999DCZGVE' b'JIZEKEGEEHYE9DOHCHLHMGAFDGEEQFUDVGGDGHRDR', )
def test_pass_compatible_types(self): """ Request contains values that can be converted to the expected types. """ filter_ = self._filter({ # ``seed`` can be any TrytesCompatible value. 'seed': bytearray(self.seed.encode('ascii')), # These values must be integers, however. 'index': 100, 'count': 8, 'securityLevel': 2, # ``checksum`` must be boolean. 'checksum': False, }) self.assertFilterPasses(filter_) self.assertDictEqual( filter_.cleaned_data, { 'seed': Seed(self.seed), 'index': 100, 'count': 8, 'securityLevel': 2, 'checksum': False, }, )
def setUp(self): super(GetNewAddressesCommandTestCase, self).setUp() self.adapter = MockAdapter() self.command = GetNewAddressesCommand(self.adapter) self.seed =\ Seed( b'TESTVALUE9DONTUSEINPRODUCTION99999ZDCCUF' b'CBBIQCLGMEXAVFQEOF9DRAB9VCEBAGXAF9VF9FLHP', ) self.addy_1 =\ Address( b'NYMWLBUJEISSACZZBRENC9HEHYQXHCGQHSNHVCEA' b'ZDCTEVNGSDUEKTSYBSQGMVJRIEDHWDYSEYCFAZAH9', ) self.addy_2 =\ Address( b'NTPSEVZHQITARYWHIRTSIFSERINLRYVXLGIQKKHY' b'IWYTLQUUHDWSOVXLIKVJTYZBFKLABWRBFYVSMD9NB', ) self.addy_1_checksum =\ Address( b'NYMWLBUJEISSACZZBRENC9HEHYQXHCGQHSNHVCEA' b'ZDCTEVNGSDUEKTSYBSQGMVJRIEDHWDYSEYCFAZAH' b'9T9FPJROTW', )
def test_pass_compatible_types(self): """ The request contains values that can be converted to the expected types. """ filter_ = self._filter({ # ``seed`` can be any value that is convertible into a # TryteString. 'seed': binary_type(self.seed), # These values must still be integers/bools, however. 'start': 42, 'stop': 86, 'inclusionStates': True, 'security_level': 2 }) self.assertFilterPasses(filter_) self.assertDictEqual( filter_.cleaned_data, { 'seed': Seed(self.seed), 'start': 42, 'stop': 86, 'inclusionStates': True, 'security_level': 2 }, )
def test_pass_optional_parameters_excluded(self): """ The request contains only required parameters. """ filter_ = self._filter({ 'seed': Seed(self.seed), }) self.assertFilterPasses(filter_) self.assertDictEqual( filter_.cleaned_data, { 'seed': Seed(self.seed), 'start': 0, 'stop': None, 'inclusionStates': False, })
def test_pass_compatible_types(self): """ The request contains values that can be converted to the expected types. """ filter_ = self._filter({ # ``seed`` can be any value that is convertible into an ASCII # representation of a TryteString. 'seed': bytearray(self.seed.encode('ascii')), # These values must still be integers, however. 'start': 42, 'stop': 86, 'threshold': 99, "securityLevel": 3, }) self.assertFilterPasses(filter_) self.assertDictEqual( filter_.cleaned_data, { 'seed': Seed(self.seed), 'start': 42, 'stop': 86, 'threshold': 99, "securityLevel": 3, }, )
def test_fail_inputs_contents_invalid(self): """ ``inputs`` is a non-empty array, but it contains invalid values. """ self.assertFilterErrors( { 'inputs': [ b'', True, None, b'not valid trytes', # This is actually valid; I just added it to make sure the # filter isn't cheating! TryteString(self.trytes4), 2130706433, b'9' * 82, ], 'depth': 100, 'minWeightMagnitude': 18, 'seed': Seed(self.trytes1), 'transfers': [self.transfer1], }, { 'inputs.0': [f.Required.CODE_EMPTY], 'inputs.1': [f.Type.CODE_WRONG_TYPE], 'inputs.2': [f.Required.CODE_EMPTY], 'inputs.3': [Trytes.CODE_NOT_TRYTES], 'inputs.5': [f.Type.CODE_WRONG_TYPE], 'inputs.6': [Trytes.CODE_WRONG_FORMAT], }, )
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_async.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_async.crypto.addresses.AddressGenerator.create_iterator', mock_address_generator, ): with self.assertRaises(BadApiResponse): self.command( seed=Seed.random(), threshold=72, )
def test_pass_compatible_types(self): """ Request contains values that can be converted to the expected types. """ filter_ = self._filter({ # ``seed`` can be any value that is convertible to TryteString. 'seed': binary_type(self.seed), # These values must be integers, however. 'index': 100, 'count': 8, 'securityLevel': 1, }) self.assertFilterPasses(filter_) self.assertDictEqual( filter_.cleaned_data, { 'seed': Seed(self.seed), 'index': 100, 'count': 8, 'securityLevel': 1, }, )
def test_pass_compatible_types(self): """ The request contains values that can be converted to the expected types. """ filter_ = self._filter({ # ``seed`` can be any TrytesCompatible value. 'seed': bytearray(self.seed.encode('ascii')), # These values must still be integers/bools, however. 'start': 42, 'stop': 86, 'inclusionStates': True, }) self.assertFilterPasses(filter_) self.assertDictEqual( filter_.cleaned_data, { 'seed': Seed(self.seed), 'start': 42, 'stop': 86, 'inclusionStates': True, }, )
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_async.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_fail_transfers_contents_invalid(self): """ ``transfers`` is a non-empty array, but it contains invalid values. """ self.assertFilterErrors( { 'transfers': [ None, # This value is valid; just adding it to make sure the filter # doesn't cheat! ProposedTransaction(address=Address(self.trytes2), value=42), { 'address': Address(self.trytes2), 'value': 42 }, ], 'depth': 100, 'minWeightMagnitude': 18, 'seed': Seed(self.trytes1), }, { 'transfers.0': [f.Required.CODE_EMPTY], 'transfers.2': [f.Type.CODE_WRONG_TYPE], }, )
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_async.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_async.crypto.addresses.AddressGenerator.create_iterator', create_generator, ): response = self.command(seed=Seed.random()) self.assertDictEqual(response, {'bundles': []})
def test_pass_optional_parameters_excluded(self): """ The request contains only required parameters. """ filter_ = self._filter({ 'seed': Seed(self.seed), }) self.assertFilterPasses(filter_) self.assertDictEqual( filter_.cleaned_data, { 'seed': Seed(self.seed), 'start': 0, 'stop': None, 'threshold': None, "securityLevel": AddressGenerator.DEFAULT_SECURITY_LEVEL, })
def seed_from_filepath(filepath): # type: (Text) -> Seed """ Reads a seed from the first line of a text file. Any lines after the first are ignored. """ with open(filepath, 'rb') as f_: return Seed(f_.readline().strip())
def test_pass_optional_parameters_excluded(self): """ Request omits optional parameters. """ filter_ = self._filter({ 'seed': Seed(self.seed), }) self.assertFilterPasses(filter_) self.assertDictEqual( filter_.cleaned_data, { 'seed': Seed(self.seed), 'index': 0, 'count': 1, 'securityLevel': AddressGenerator.DEFAULT_SECURITY_LEVEL, }, )
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_async.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, seed, security_level=DEFAULT_SECURITY_LEVEL, checksum=False, ): # type: (TrytesCompatible, int, bool) -> None super(AddressGenerator, self).__init__() self.security_level = security_level self.checksum = checksum self.seed = Seed(seed)
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_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_security_level_too_small(self): """ ``securityLevel`` is < 1. """ self.assertFilterErrors( { 'securityLevel': 0, 'seed': Seed(self.seed), }, { 'securityLevel': [f.Min.CODE_TOO_SMALL], }, )
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 test_fail_stop_too_small(self): """ ``stop`` is less than 0. """ self.assertFilterErrors( { 'stop': -1, 'seed': Seed(self.seed), }, { 'stop': [f.Min.CODE_TOO_SMALL], }, )
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_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_securityLevel_string(self): """ ``securityLevel`` is a string value. """ self.assertFilterErrors( { 'securityLevel': '1', 'seed': Seed(self.seed), }, { 'securityLevel': [f.Type.CODE_WRONG_TYPE], }, )