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

Basic type conversions from address type #1524

Merged
merged 9 commits into from Jul 16, 2019
27 changes: 27 additions & 0 deletions tests/parser/functions/test_convert_to_bool.py
Expand Up @@ -193,3 +193,30 @@ def foo() -> bool:
lambda: get_contract_with_gas_estimation(code),
TypeMismatchException
)


def test_convert_from_address(w3, get_contract_with_gas_estimation):
code = """
@public
def test_address_to_bool(val: address) -> bool:
temp: bool = convert(val, bool)
return temp

@public
def test_literal_zero_address() -> bool:
return convert(ZERO_ADDRESS, bool)

@public
def test_sender() -> bool:
return convert(msg.sender, bool)
"""

a = w3.eth.accounts[0]
c = get_contract_with_gas_estimation(code)

assert c.test_address_to_bool((b'\x00' * 19) + (b'\x01')) is True
assert c.test_address_to_bool(a) is True
assert c.test_address_to_bool(b'\x00' * 20) is False

assert c.test_literal_zero_address() is False
assert c.test_sender() is True
40 changes: 40 additions & 0 deletions tests/parser/functions/test_convert_to_decimal.py
Expand Up @@ -169,3 +169,43 @@ def foobar() -> decimal:
lambda: get_contract_with_gas_estimation(code),
TypeMismatchException
)


def test_convert_from_address(get_contract_with_gas_estimation):
code = """
stor: address

@public
def conv(param: address) -> decimal:
return convert(param, decimal)

@public
def conv_zero_literal() -> decimal:
return convert(ZERO_ADDRESS, decimal)

@public
def conv_zero_stor() -> decimal:
self.stor = ZERO_ADDRESS
return convert(self.stor, decimal)

@public
def conv_neg1_literal() -> decimal:
return convert(0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF, decimal)

@public
def conv_neg1_stor() -> decimal:
self.stor = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF
return convert(self.stor, decimal)
"""

c = get_contract_with_gas_estimation(code)
assert c.conv(b"\x00" * 20) == 0.0
assert c.conv_zero_literal() == 0.0
assert c.conv_zero_stor() == 0.0

assert c.conv(b"\xff" * 20) == -1.0
assert c.conv_neg1_literal() == -1.0
assert c.conv_neg1_stor() == -1.0

assert c.conv((b"\x00" * 19) + b"\x01") == 1.0
assert c.conv((b"\x00" * 18) + b"\x01\x00") == 256.0
117 changes: 107 additions & 10 deletions tests/parser/functions/test_convert_to_int128.py
Expand Up @@ -2,6 +2,9 @@
InvalidLiteralException,
TypeMismatchException,
)
from vyper.utils import (
SizeLimits,
)


def test_convert_to_int128_units(get_contract, assert_tx_failed):
Expand Down Expand Up @@ -204,16 +207,6 @@ def test1():
assert_tx_failed(lambda: c.test1())


def test_convert_from_address(assert_compile_failed, get_contract_with_gas_estimation):
code = """
@public
def test2():
x: int128 = convert(msg.sender, int128)
"""

assert_compile_failed(lambda: get_contract_with_gas_estimation(code), Exception)


def test_convert_out_of_range_literal(assert_compile_failed, get_contract_with_gas_estimation):
code = """
@public
Expand Down Expand Up @@ -292,3 +285,107 @@ def foo() -> int128:
lambda: get_contract_with_gas_estimation(code),
InvalidLiteralException
)


def test_convert_from_address(w3, get_contract):
code = """
stor: address

@public
def testCompiles():
x: int128 = convert(msg.sender, int128)

@public
def conv_neg1_stor() -> int128:
self.stor = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF
return convert(self.stor, int128)

@public
def conv_neg1_literal() -> int128:
return convert(0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF, int128)

@public
def conv_neg1_stor_alt() -> int128:
self.stor = 0x00000000fFFFffffffFfFfFFffFfFffFFFfFffff
return convert(self.stor, int128)

@public
def conv_neg1_literal_alt() -> int128:
return convert(0x00000000fFFFffffffFfFfFFffFfFffFFFfFffff, int128)

@public
def conv_min_stor() -> int128:
self.stor = 0x0000000080000000000000000000000000000000
return convert(self.stor, int128)

@public
def conv_min_literal() -> int128:
return convert(0x0000000080000000000000000000000000000000, int128)

@public
def conv_min_stor_alt() -> int128:
self.stor = 0x1234567880000000000000000000000000000000
return convert(self.stor, int128)

@public
def conv_min_literal_alt() -> int128:
return convert(0x1234567880000000000000000000000000000000, int128)

@public
def conv_zero_stor() -> int128:
self.stor = ZERO_ADDRESS
return convert(self.stor, int128)

@public
def conv_zero_literal() -> int128:
return convert(ZERO_ADDRESS, int128)

@public
def conv_zero_stor_alt() -> int128:
self.stor = 0xffFFfFFf00000000000000000000000000000000
return convert(self.stor, int128)

@public
def conv_zero_literal_alt() -> int128:
return convert(0xffFFfFFf00000000000000000000000000000000, int128)

@public
def conv_max_stor() -> int128:
self.stor = 0xFffffFff7FFFFFFfFffFffFfFFffFffFFfFfffFF
return convert(self.stor, int128)

@public
def conv_max_literal() -> int128:
return convert(0xFffffFff7FFFFFFfFffFffFfFFffFffFFfFfffFF, int128)

@public
def conv_max_stor_alt() -> int128:
self.stor = 0x000000007FfFFffffFFFFfffffffFffFfFffffFF
return convert(self.stor, int128)

@public
def conv_max_literal_alt() -> int128:
return convert(0x000000007FfFFffffFFFFfffffffFffFfFffffFF, int128)
"""

c = get_contract(code)

assert c.conv_neg1_stor() == -1
assert c.conv_neg1_literal() == -1
assert c.conv_neg1_stor_alt() == -1
assert c.conv_neg1_literal_alt() == -1

assert c.conv_min_stor() == SizeLimits.MINNUM
assert c.conv_min_literal() == SizeLimits.MINNUM
assert c.conv_min_stor_alt() == SizeLimits.MINNUM
assert c.conv_min_literal_alt() == SizeLimits.MINNUM

assert c.conv_zero_stor() == 0
assert c.conv_zero_literal() == 0
assert c.conv_zero_stor_alt() == 0
assert c.conv_zero_literal_alt() == 0

assert c.conv_max_stor() == SizeLimits.MAXNUM
assert c.conv_max_literal() == SizeLimits.MAXNUM
assert c.conv_max_stor_alt() == SizeLimits.MAXNUM
assert c.conv_max_literal_alt() == SizeLimits.MAXNUM
22 changes: 22 additions & 0 deletions tests/parser/functions/test_convert_to_uint256.py
Expand Up @@ -112,13 +112,35 @@ def conv2() -> uint256:
@public
def conv3() -> uint256:
return convert(0x744d70FDBE2Ba4CF95131626614a1763DF805B9E, uint256)

@public
def conv_max_stor() -> uint256:
self.stor_a = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF
return convert(self.stor_a, uint256)

@public
def conv_max_literal() -> uint256:
return convert(0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF, uint256)

@public
def conv_min_stor() -> uint256:
self.stor_a = ZERO_ADDRESS
return convert(self.stor_a, uint256)

@public
def conv_min_literal() -> uint256:
return convert(ZERO_ADDRESS, uint256)
"""

c = get_contract(code)

assert c.conv1(a) == int(a, 0)
assert c.conv2() == 663969929716095361663590611662499625636445838238
assert c.conv3() == 663969929716095361663590611662499625636445838238
assert c.conv_max_stor() == (2**160) - 1
assert c.conv_max_literal() == (2**160) - 1
assert c.conv_min_stor() == 0
assert c.conv_min_literal() == 0


def test_convert_from_bool(get_contract_with_gas_estimation):
Expand Down
41 changes: 38 additions & 3 deletions vyper/types/convert.py
Expand Up @@ -28,7 +28,7 @@
)


@signature(('decimal', 'int128', 'uint256', 'bytes32', 'bytes'), '*')
@signature(('decimal', 'int128', 'uint256', 'address', 'bytes32', 'bytes'), '*')
def to_bool(expr, args, kwargs, context):
in_arg = args[0]
input_type, _ = get_type(in_arg)
Expand Down Expand Up @@ -57,7 +57,8 @@ def to_bool(expr, args, kwargs, context):
)


@signature(('num_literal', 'bool', 'decimal', 'uint256', 'bytes32', 'bytes', 'string'), '*')
@signature(('num_literal', 'bool', 'decimal', 'uint256', 'address',
'bytes32', 'bytes', 'string'), '*')
def to_int128(expr, args, kwargs, context):
in_arg = args[0]
input_type, _ = get_type(in_arg)
Expand Down Expand Up @@ -105,6 +106,21 @@ def to_int128(expr, args, kwargs, context):
pos=getpos(expr)
)

elif input_type == 'address':
return LLLnode.from_list(
[
'signextend',
15,
[
'and',
in_arg,
(SizeLimits.ADDRSIZE - 1)
],
],
typ=BaseType('int128', _unit),
pos=getpos(expr)
)

elif input_type in ('string', 'bytes'):
if in_arg.typ.maxlen > 32:
raise TypeMismatchException(
Expand Down Expand Up @@ -221,7 +237,7 @@ def to_uint256(expr, args, kwargs, context):
raise InvalidLiteralException("Invalid input for uint256: %r" % in_arg, expr)


@signature(('bool', 'int128', 'uint256', 'bytes32', 'bytes'), '*')
@signature(('bool', 'int128', 'uint256', 'bytes32', 'bytes', 'address'), '*')
def to_decimal(expr, args, kwargs, context):
in_arg = args[0]
input_type, _ = get_type(in_arg)
Expand Down Expand Up @@ -267,6 +283,25 @@ def to_decimal(expr, args, kwargs, context):
pos=getpos(expr)
)

elif input_type == 'address':
return LLLnode.from_list(
[
'mul',
[
'signextend',
15,
[
'and',
in_arg,
(SizeLimits.ADDRSIZE - 1)
],
],
DECIMAL_DIVISOR
],
typ=BaseType('decimal', _unit, _positional),
pos=getpos(expr)
)

elif input_type == 'bytes32':
if in_arg.typ.is_literal:
if not SizeLimits.in_bounds('int128', (in_arg.value * DECIMAL_DIVISOR)):
Expand Down