Skip to content
This repository was archived by the owner on Jan 13, 2023. It is now read-only.

Commit a480d60

Browse files
committed
Initial work on #101 - Create a filter that just quietly removes checksums since the core api doesn't care for them, update get_balances and find_transactions with that filter
1 parent 9c67ba3 commit a480d60

File tree

4 files changed

+118
-8
lines changed

4 files changed

+118
-8
lines changed

iota/commands/core/find_transactions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from iota import Address, Tag, TransactionHash
99
from iota.commands import FilterCommand, RequestFilter, ResponseFilter
10-
from iota.filters import Trytes
10+
from iota.filters import Trytes, AddressNoChecksum
1111

1212
__all__ = [
1313
'FindTransactionsCommand',
@@ -43,7 +43,7 @@ def __init__(self):
4343
f.Array
4444
| f.FilterRepeater(
4545
f.Required
46-
| Trytes(result_type=Address)
46+
| AddressNoChecksum(result_type=Address)
4747
| f.Unicode(encoding='ascii', normalize=False)
4848
)
4949
),

iota/commands/core/get_balances.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from iota import Address
88
from iota.commands import FilterCommand, RequestFilter, ResponseFilter
9-
from iota.filters import Trytes
9+
from iota.filters import Trytes, AddressNoChecksum
1010

1111
__all__ = [
1212
'GetBalancesCommand',
@@ -37,7 +37,7 @@ def __init__(self):
3737
| f.Array
3838
| f.FilterRepeater(
3939
f.Required
40-
| Trytes(result_type=Address)
40+
| AddressNoChecksum(result_type=Address)
4141
| f.Unicode(encoding='ascii', normalize=False)
4242
)
4343
),

iota/filters.py

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
from iota import Address, TryteString, TrytesCompatible
1111

12-
1312
class GeneratedAddress(f.BaseFilter):
1413
"""
1514
Validates an incoming value as a generated :py:class:`Address` (must
@@ -69,10 +68,12 @@ class Trytes(f.BaseFilter):
6968
"""
7069
Validates a sequence as a sequence of trytes.
7170
"""
72-
CODE_NOT_TRYTES = 'not_trytes'
73-
CODE_WRONG_FORMAT = 'wrong_format'
71+
ADDRESS_BAD_CHECKSUM = 'address_bad_checksum'
72+
CODE_NOT_TRYTES = 'not_trytes'
73+
CODE_WRONG_FORMAT = 'wrong_format'
7474

7575
templates = {
76+
ADDRESS_BAD_CHECKSUM: 'The checksum for this address is invalid.',
7677
CODE_NOT_TRYTES: 'This value is not a valid tryte sequence.',
7778
CODE_WRONG_FORMAT: 'This value is not a valid {result_type}.',
7879
}
@@ -142,3 +143,67 @@ def _apply(self, value):
142143
'result_type': self.result_type.__name__,
143144
},
144145
)
146+
147+
148+
class AddressNoChecksum(Trytes):
149+
"""
150+
Validates a sequence as a sequence of trytes.
151+
"""
152+
153+
def _apply(self, value):
154+
# noinspection PyTypeChecker
155+
value =\
156+
self._filter(
157+
filter_chain = f.Type((binary_type, bytearray, text_type, TryteString)),
158+
value = value,
159+
) # type: TrytesCompatible
160+
161+
if self._has_errors:
162+
return None
163+
164+
# If the incoming value already is an Address then we just make sure it has no checksum
165+
if isinstance(value, Address):
166+
if value.checksum and not value.is_checksum_valid():
167+
return self._invalid_value(
168+
value = value,
169+
reason = self.ADDRESS_BAD_CHECKSUM,
170+
exc_info = True,
171+
172+
template_vars = {
173+
'result_type': self.ADDRESS_BAD_CHECKSUM,
174+
},
175+
)
176+
return Address(value.address)
177+
178+
# First convert to a generic TryteString, to make sure that the
179+
# sequence doesn't contain any invalid characters.
180+
try:
181+
value = TryteString(value)
182+
except ValueError:
183+
return self._invalid_value(value, self.CODE_NOT_TRYTES, exc_info=True)
184+
185+
# Now coerce to the expected type and verify that there are no
186+
# type-specific errors.
187+
try:
188+
addy = Address(value)
189+
if addy.checksum and not addy.is_checksum_valid():
190+
return self._invalid_value(
191+
value = addy,
192+
reason = self.ADDRESS_BAD_CHECKSUM,
193+
exc_info = True,
194+
195+
template_vars = {
196+
'result_type': self.ADDRESS_BAD_CHECKSUM,
197+
},
198+
)
199+
return Address(addy.address)
200+
except ValueError:
201+
return self._invalid_value(
202+
value = value,
203+
reason = self.CODE_WRONG_FORMAT,
204+
exc_info = True,
205+
206+
template_vars = {
207+
'result_type': self.result_type.__name__,
208+
},
209+
)

test/filters_test.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from filters.test import BaseFilterTestCase
77

88
from iota import Address, TryteString, TransactionHash
9-
from iota.filters import GeneratedAddress, NodeUri, Trytes
9+
from iota.filters import GeneratedAddress, NodeUri, Trytes, AddressNoChecksum
1010

1111

1212
class GeneratedAddressTestCase(BaseFilterTestCase):
@@ -201,3 +201,48 @@ def test_fail_wrong_type(self):
201201
[TryteString(b'RBTC9D9DCDQAEASBYBCCKBFA')],
202202
[f.Type.CODE_WRONG_TYPE],
203203
)
204+
205+
206+
# noinspection SpellCheckingInspection
207+
class AddressNoChecksumTestCase(BaseFilterTestCase):
208+
filter_type = AddressNoChecksum
209+
210+
# noinspection SpellCheckingInspection
211+
def setUp(self):
212+
super(AddressNoChecksumTestCase, self).setUp()
213+
214+
# Define some addresses that we can reuse between tests
215+
"""
216+
Incoming value is not an :py:class:`Address` instance.
217+
"""
218+
self.tryte1 = (
219+
b'TESTVALUE9DONTUSEINPRODUCTION99999FBFFTG'
220+
b'QFWEHEL9KCAFXBJBXGE9HID9XCOHFIDABHDG9AHDR'
221+
)
222+
self.checksum = b'ENXYJOBP9'
223+
self.address = Address(self.tryte1)
224+
self.address_with_checksum = Address(self.tryte1 + self.checksum)
225+
self.address_with_bad_checksum = Address(self.tryte1 + b'DEADBEEF9')
226+
227+
def test_pass_checksumless_addy(self):
228+
"""
229+
Incoming value is tryte in address form or Address object
230+
"""
231+
self.assertFilterPasses(self.tryte1)
232+
self.assertFilterPasses(self.address)
233+
234+
def test_pass_withchecksum_addy(self):
235+
"""
236+
After passing through the filter an address with a checksum should
237+
return the address without
238+
"""
239+
self.assertFilterPasses(self.address_with_checksum, self.address)
240+
241+
def test_fail_badchecksum_addy(self):
242+
"""
243+
If they've got a bad checksum in their address we should probably tell
244+
them so they don't wonder why something works in one place and not another
245+
"""
246+
self.assertFilterErrors(
247+
self.address_with_bad_checksum,
248+
[AddressNoChecksum.ADDRESS_BAD_CHECKSUM])

0 commit comments

Comments
 (0)