Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Piper/rewrite decoding logic so i can understand it #9

Merged
390 changes: 59 additions & 331 deletions eth_abi/abi.py

Large diffs are not rendered by default.

402 changes: 402 additions & 0 deletions eth_abi/decoding.py

Large diffs are not rendered by default.

458 changes: 458 additions & 0 deletions eth_abi/encoding.py

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions eth_abi/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ class EncodingError(Exception):
pass


class EncodingTypeError(EncodingError):
"""
Raised when trying to encode a value which is of the wrong type for the
desired encoding type.
"""
pass


class ValueOutOfBounds(EncodingError):
"""
Raised when trying to encode a value which is out bounds for the desired
Expand All @@ -12,3 +20,11 @@ class ValueOutOfBounds(EncodingError):

class DecodingError(Exception):
pass


class InsufficientDataBytes(DecodingError):
pass


class NonEmptyPaddingBytes(DecodingError):
pass
86 changes: 0 additions & 86 deletions eth_abi/utils.py

This file was deleted.

Empty file added eth_abi/utils/__init__.py
Empty file.
94 changes: 94 additions & 0 deletions eth_abi/utils/numeric.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import sys
import math
import decimal

from eth_utils import (
encode_hex,
is_number,
)

from eth_abi.constants import (
TT256,
)


if sys.version_info.major == 2:
import struct

def int_to_big_endian(value):
cs = []
while value > 0:
cs.append(chr(value % 256))
value /= 256
s = ''.join(reversed(cs))
return s

def big_endian_to_int(value):
if len(value) == 1:
return ord(value)
elif len(value) <= 8:
return struct.unpack('>Q', value.rjust(8, '\x00'))[0]
else:
return int(encode_hex(value), 16)
else:
def int_to_big_endian(value):
byte_length = math.ceil(value.bit_length() / 8)
return (value).to_bytes(byte_length, byteorder='big')

def big_endian_to_int(value):
return int.from_bytes(value, byteorder='big')


def ceil32(x):
return x if x % 32 == 0 else x + 32 - (x % 32)


def encode_int(value):
'''encodes an integer into serialization'''
if not is_number(value) or value < 0 or value >= TT256:
raise Exception("Integer invalid or out of range: %r" % value)
return int_to_big_endian(value)


def compute_unsigned_integer_bounds(num_bits):
return (
0,
2 ** num_bits - 1,
)


def compute_signed_integer_bounds(num_bits):
return (
-1 * 2 ** (num_bits - 1),
2 ** (num_bits - 1) - 1,
)


def compute_unsigned_real_bounds(num_high_bits, num_low_bits):
integer_lower_bound, integer_upper_bount = compute_unsigned_integer_bounds(
num_high_bits,
)
return (
integer_lower_bound * 1.0 / 2 ** num_low_bits,
integer_upper_bount * 1.0 / 2 ** num_low_bits,
)


def compute_signed_real_bounds(num_high_bits, num_low_bits):
integer_lower_bound, integer_upper_bount = compute_signed_integer_bounds(
num_high_bits,
)
return (
integer_lower_bound * 1.0 / 2 ** num_low_bits,
integer_upper_bount * 1.0 / 2 ** num_low_bits,
)


def quantize_value(value, decimal_bit_size):
num_decimals = int(math.ceil(math.log10(2 ** decimal_bit_size)))
if num_decimals == 0:
quantize_value = decimal.Decimal('1')
else:
quantize_value = decimal.Decimal('1.{0}'.format(''.zfill(num_decimals)))
decimal_value = decimal.Decimal(value)
return decimal_value.quantize(quantize_value)
12 changes: 12 additions & 0 deletions eth_abi/utils/padding.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import functools

from eth_utils import (
pad_left,
pad_right,
)


zpad = functools.partial(pad_left, pad_with='\x00')
zpad32 = functools.partial(pad_left, to_size=32, pad_with='\x00')
zpad_right = functools.partial(pad_right, pad_with='\x00')
zpad32_right = functools.partial(pad_right, to_size=32, pad_with='\x00')
2 changes: 1 addition & 1 deletion pytest.ini
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[pytest]
python_paths= .
addopts= -v
addopts= -v --hypothesis-show-statistics --showlocals
8 changes: 4 additions & 4 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pytest>=2.8.2
pytest-pythonpath>=0.3
tox>=1.8.0
hypothesis==3.4.0
pytest>=3.0.3
pytest-pythonpath>=0.7.1
tox>=2.4.1
hypothesis>=3.6.1
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
url='https://github.com/pipermerriam/ethereum-abi-utils',
include_package_data=True,
install_requires=[
'rlp>=0.4.6',
'ethereum-utils>=0.2.0',
],
py_modules=['eth_abi'],
license="MIT",
Expand Down
33 changes: 29 additions & 4 deletions tests/decoding/test_decode_abi.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
@pytest.mark.parametrize(
'input,expected',
(
('0x00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001', [6, 1]),
('0x00000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000000ffffffff', [2**32-1, 2**32-1]),
('0x00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001', (6, 1)),
('0x00000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000000ffffffff', (2**32-1, 2**32-1)),
)
)
def test_decode_two_uint32(input, expected):
Expand All @@ -29,7 +29,32 @@ def test_decode_various():
'6d616c000000000000000000000000000000000000000000000000000000000000000000000000000'
'00000000000000000')

expected = [b'82a978b3f5962a5b0957d9ee9eef472ee55b42f1', 1,
b'stupid pink animal\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', 0]
expected = (
'0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1',
1,
b'stupid pink animal\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
0,
)
output = decode_abi(['address', 'uint32', 'bytes32', 'int32'], data)
assert output == expected


@pytest.mark.parametrize(
'types,data,expected',
(
(
('uint256', 'bytes'),
(
'0x'
'0000000000000000000000000000000000000000000000000000000000000000'
'0000000000000000000000000000000000000000000000000000000000000040'
'0000000000000000000000000000000000000000000000000000000000000000'
'0000000000000000000000000000000000000000000000000000000000000000'
),
(0, b''),
),
),
)
def test_decode_uint256_and_bytes(types, data, expected):
actual = decode_abi(types, data)
assert actual == expected
12 changes: 6 additions & 6 deletions tests/decoding/test_decode_single_type.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest

from rlp.utils import (
from eth_utils import (
decode_hex,
)

Expand Down Expand Up @@ -106,23 +106,23 @@ def test_decode_bytes32(input, expected):
(
(
'0x0000000000000000000000000000000000000000000000000000000000000000',
b'0000000000000000000000000000000000000000',
'0x0000000000000000000000000000000000000000',
),
(
'0x000000000000000000000000c305c901078781c232a2a521c2af7980f8385ee9',
b'c305c901078781c232a2a521c2af7980f8385ee9',
'0xc305c901078781c232a2a521c2af7980f8385ee9',
),
(
'0x0000000000000000000000000005c901078781c232a2a521c2af7980f8385ee9',
b'0005c901078781c232a2a521c2af7980f8385ee9',
'0x0005c901078781c232a2a521c2af7980f8385ee9',
),
(
'0x000000000000000000000000c305c901078781c232a2a521c2af7980f8385000',
b'c305c901078781c232a2a521c2af7980f8385000',
'0xc305c901078781c232a2a521c2af7980f8385000',
),
(
'0x0000000000000000000000000005c901078781c232a2a521c2af7980f8385000',
b'0005c901078781c232a2a521c2af7980f8385000',
'0x0005c901078781c232a2a521c2af7980f8385000',
),
)
)
Expand Down
Loading