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

Commit 8d2c2e8

Browse files
authored
Merge pull request #112 from plenarius/chop_checksum_for_core_commands
[#101] Filter that automatically removes checksums for core commands
2 parents ac8cdee + b5263df commit 8d2c2e8

File tree

4 files changed

+89
-5
lines changed

4 files changed

+89
-5
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 AddressNoChecksum, Trytes
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()
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 AddressNoChecksum, Trytes
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()
4141
| f.Unicode(encoding='ascii', normalize=False)
4242
)
4343
),

iota/filters.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,42 @@ def _apply(self, value):
142142
'result_type': self.result_type.__name__,
143143
},
144144
)
145+
146+
147+
class AddressNoChecksum(Trytes):
148+
"""
149+
Validates a sequence as an Address then chops off the checksum if it exists
150+
"""
151+
ADDRESS_BAD_CHECKSUM = 'address_bad_checksum'
152+
153+
templates = {
154+
ADDRESS_BAD_CHECKSUM: 'Checksum is {supplied_checksum}, should be {expected_checksum}?',
155+
}
156+
157+
def __init__(self):
158+
# type: (type) -> None
159+
super(AddressNoChecksum, self).__init__(result_type=Address)
160+
161+
def _apply(self, value):
162+
super(AddressNoChecksum, self)._apply(value)
163+
164+
if self._has_errors:
165+
return None
166+
167+
# Possible it's still just a TryteString
168+
if not isinstance(value, Address):
169+
value = Address(value)
170+
171+
# Bail out if we have a bad checksum
172+
if value.checksum and not value.is_checksum_valid():
173+
return self._invalid_value(
174+
value = value,
175+
reason = self.ADDRESS_BAD_CHECKSUM,
176+
exc_info = True,
177+
178+
context = {
179+
'supplied_checksum': value.checksum,
180+
'expected_checksum': value.with_valid_checksum().checksum,
181+
},
182+
)
183+
return Address(value.address)

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 AddressNoChecksum, GeneratedAddress, NodeUri, Trytes
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_no_checksum_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_with_checksum_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_with_bad_checksum_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)