Beispiel #1
0
def test_unsafe_op_int(get_contract, typ, op):
    contract_1 = f"""
@external
def foo(x: {typ}, y: {typ}) -> {typ}:
    return unsafe_{op}(x, y)
    """

    contract_2 = """
@external
def foo(x: {typ}) -> {typ}:
    return unsafe_{op}(x, {literal})
    """

    fns = {
        "add": operator.add,
        "sub": operator.sub,
        "mul": operator.mul,
        "div": evm_div
    }
    fn = fns[op]

    int_info = parse_integer_typeinfo(typ)
    c1 = get_contract(contract_1)

    lo, hi = int_bounds(int_info.is_signed, int_info.bits)
    # (roughly 8k cases total generated)
    # TODO refactor to use fixtures
    NUM_CASES = 15
    xs = [random.randrange(lo, hi) for _ in range(NUM_CASES)]
    ys = [random.randrange(lo, hi) for _ in range(NUM_CASES)]

    mod_bound = 2**int_info.bits

    # poor man's fuzzing - hypothesis doesn't make it easy
    # with the parametrized strategy
    if int_info.is_signed:
        xs += [lo, lo + 1, -1, 0, 1, hi - 1, hi]
        ys += [lo, lo + 1, -1, 0, 1, hi - 1, hi]
        for (x, y) in itertools.product(xs, ys):
            expected = unsigned_to_signed(fn(x, y) % mod_bound, int_info.bits)

            assert c1.foo(x, y) == expected

            c2 = get_contract(contract_2.format(typ=typ, op=op, literal=y))
            assert c2.foo(x) == expected

    else:
        # 0x80 has some weird properties, like
        # it's a fixed point of multiplication by 0xFF
        fixed_pt = 2**(int_info.bits - 1)
        xs += [0, 1, hi - 1, hi, fixed_pt]
        ys += [0, 1, hi - 1, hi, fixed_pt]
        for (x, y) in itertools.product(xs, ys):
            expected = fn(x, y) % mod_bound
            assert c1.foo(x, y) == expected

            c2 = get_contract(contract_2.format(typ=typ, op=op, literal=y))
            assert c2.foo(x) == expected
Beispiel #2
0
def test_sint_clamper_failing(w3, assert_tx_failed, get_contract, n, evm_version):
    bits = 8 * (n + 1)
    lo, hi = int_bounds(True, bits)
    values = [-(2 ** 255), 2 ** 255 - 1, lo - 1, hi + 1]
    code = f"""
@external
def foo(s: int{bits}) -> int{bits}:
    return s
    """

    c = get_contract(code, evm_version=evm_version)
    for v in values:
        assert_tx_failed(lambda: _make_tx(w3, c.address, f"foo(int{bits})", [v]))
Beispiel #3
0
def test_sint_clamper_passing(w3, get_contract, n, evm_version):
    bits = 8 * (n + 1)
    lo, hi = int_bounds(True, bits)
    values = [-1, 0, 1, lo, hi]
    code = f"""
@external
def foo(s: int{bits}) -> int{bits}:
    return s
    """

    c = get_contract(code, evm_version=evm_version)
    for v in values:
        assert c.foo(v) == v
Beispiel #4
0
def test_minmax_value_int(get_contract, op, typ):
    code = f"""
@external
def foo() -> {typ}:
    return {op}({typ})
    """
    c = get_contract(code)

    typ_info = parse_integer_typeinfo(typ)
    (lo, hi) = int_bounds(typ_info.is_signed, typ_info.bits)
    if op == "min_value":
        assert c.foo() == lo
    elif op == "max_value":
        assert c.foo() == hi
Beispiel #5
0
def test_unsafe_op_int(get_contract, typ, op):
    code = f"""
@external
def foo(x: {typ}, y: {typ}) -> {typ}:
    return unsafe_{op}(x, y)
    """
    fns = {
        "add": operator.add,
        "sub": operator.sub,
        "mul": operator.mul,
        "div": evm_div
    }
    fn = fns[op]

    int_info = parse_integer_typeinfo(typ)
    c = get_contract(code)

    lo, hi = int_bounds(int_info.is_signed, int_info.bits)
    NUM_CASES = 33  # any more than this and fuzzer takes too long
    xs = [random.randrange(lo, hi) for _ in range(NUM_CASES)]
    ys = [random.randrange(lo, hi) for _ in range(NUM_CASES)]

    mod_bound = 2**int_info.bits

    # poor man's fuzzing - hypothesis doesn't make it easy
    # with the parametrized strategy
    if int_info.is_signed:
        xs += [lo, lo + 1, -1, 0, 1, hi - 1, hi]
        ys += [lo, lo + 1, -1, 0, 1, hi - 1, hi]
        for (x, y) in itertools.product(xs, ys):
            expected = _as_signed(fn(x, y) % mod_bound, int_info.bits)
            assert c.foo(x, y) == expected
    else:
        # 0x80 has some weird properties, like
        # it's a fixed point of multiplication by 0xFF
        fixed_pt = 2**(int_info.bits - 1)
        xs += [0, 1, hi - 1, hi, fixed_pt]
        ys += [0, 1, hi - 1, hi, fixed_pt]
        for (x, y) in itertools.product(xs, ys):
            assert c.foo(x, y) == fn(x, y) % mod_bound
Beispiel #6
0
def test_enum_conversion_2(get_contract_with_gas_estimation,
                           assert_compile_failed, assert_tx_failed, val, typ):
    contract = f"""
enum Status:
    STARTED
    PAUSED
    STOPPED

@external
def foo(a: {typ}) -> Status:
    return convert(a, Status)
    """
    if typ == "uint256":
        c = get_contract_with_gas_estimation(contract)
        lo, hi = int_bounds(signed=False, bits=3)
        if lo <= val <= hi:
            assert c.foo(val) == val
        else:
            assert_tx_failed(lambda: c.foo(val))
    else:
        assert_compile_failed(
            lambda: get_contract_with_gas_estimation(contract), TypeMismatch)
Beispiel #7
0
import itertools
import operator
import random

import pytest

from vyper.codegen.types.types import UNSIGNED_INTEGER_TYPES, parse_integer_typeinfo
from vyper.exceptions import InvalidType, OverflowException, ZeroDivisionException
from vyper.utils import SizeLimits, evm_div, evm_mod, int_bounds

PARAMS = []
for t in sorted(UNSIGNED_INTEGER_TYPES):
    info = parse_integer_typeinfo(t)
    lo, hi = int_bounds(bits=info.bits, signed=info.is_signed)
    PARAMS.append((t, lo, hi, info.bits))


@pytest.mark.parametrize("typ,lo,hi,bits", PARAMS)
def test_exponent_base_zero(get_contract, typ, lo, hi, bits):
    code = f"""
@external
def foo(x: {typ}) -> {typ}:
    return 0 ** x
    """
    c = get_contract(code)
    assert c.foo(0) == 1
    assert c.foo(1) == 0
    assert c.foo(42) == 0
    assert c.foo(hi) == 0

Beispiel #8
0
 def bounds(self) -> Tuple[int, int]:
     # The bounds of this type
     # (note behavior for decimal: int value in IR land,
     # rather than Decimal value in Python land)
     return int_bounds(signed=self.is_signed, bits=self.bits)
Beispiel #9
0
 def bounds(self) -> Tuple[int, int]:
     return int_bounds(signed=self.is_signed, bits=self.bits)
Beispiel #10
0
                    (SignedIntegerAbstractType, _SignedIntegerDefinition),
                    {"_bits": bits})
    # class Uint256Definition(UnsignedIntegerAbstractType, _UnsignedIntegerDefinition):
    #    _bits = 256
    uint_def = type(uint,
                    (UnsignedIntegerAbstractType, _UnsignedIntegerDefinition),
                    {"_bits": bits})

    globals()[sint] = sint_def
    globals()[uint] = uint_def

    globals()[f"Int{bits}Primitive"] = type(
        f"Int{bits}Primitive",
        (_NumericPrimitive, ),
        {
            "_bounds": int_bounds(signed=True, bits=bits),
            "_id": f"int{bits}",
            "_type": sint_def,
            "_valid_literal": (vy_ast.Int, ),
        },
    )

    globals()[f"Uint{bits}Primitive"] = type(
        f"Uint{bits}Primitive",
        (_NumericPrimitive, ),
        {
            "_bounds": int_bounds(signed=False, bits=bits),
            "_id": f"uint{bits}",
            "_type": uint_def,
            "_valid_literal": (vy_ast.Int, ),
        },
Beispiel #11
0
def _comparison_helper(binop, args, prefer_strict=False):
    assert binop in COMPARISON_OPS

    if _is_int(args[0]):
        binop = _flip_comparison_op(binop)
        args = [args[1], args[0]]

    unsigned = not binop.startswith("s")
    is_strict = binop.endswith("t")
    is_gt = "g" in binop

    # local version of _evm_int which defaults to the current binop's signedness
    def _int(x):
        return _evm_int(x, unsigned=unsigned)

    lo, hi = int_bounds(bits=256, signed=not unsigned)

    # for comparison operators, we have three special boundary cases:
    # almost always, never and almost never.
    # almost_always is always true for the non-strict ("ge" and co)
    # comparators. for strict comparators ("gt" and co), almost_always
    # is true except for one case. never is never true for the strict
    # comparators. never is almost always false for the non-strict
    # comparators, except for one case. and almost_never is almost
    # never true (except one case) for the strict comparators.
    if is_gt:
        almost_always, never = lo, hi
        almost_never = hi - 1
    else:
        almost_always, never = hi, lo
        almost_never = lo + 1

    if is_strict and _int(args[1]) == never:
        # e.g. gt x MAX_UINT256, slt x MIN_INT256
        return (0, [])

    if not is_strict and _int(args[1]) == almost_always:
        # e.g. ge x MIN_UINT256, sle x MAX_INT256
        return (1, [])

    if is_strict and _int(args[1]) == almost_never:
        # (lt x 1), (gt x (MAX_UINT256 - 1)), (slt x (MIN_INT256 + 1))
        return ("eq", [args[0], never])

    # rewrites. in positions where iszero is preferred, (gt x 5) => (ge x 6)
    if is_strict != prefer_strict and _is_int(args[1]):
        rhs = _int(args[1])

        if prefer_strict and rhs == never:
            # e.g. ge x MAX_UINT256, sle x MIN_INT256
            return ("eq", args)

        if not prefer_strict and rhs == almost_always:
            # e.g. gt x 0, slt x MAX_INT256
            return ("ne", args)

        if is_gt == is_strict:
            # x > 1 => x >= 2
            # x <= 1 => x < 2
            new_rhs = rhs + 1
        else:
            # x >= 1 => x > 0
            # x < 1 => x <= 0
            new_rhs = rhs - 1

        # if args[1] is OOB, it should have been handled above
        # in the always/never cases
        assert _wrap256(new_rhs, unsigned) == new_rhs, "bad optimizer step"

        # change the strictness of the op
        if prefer_strict:
            # e.g. "sge" => "sgt"
            new_op = binop.replace("e", "t")
        else:
            # e.g. "sgt" => "sge"
            new_op = binop.replace("t", "e")

        return (new_op, [args[0], new_rhs])

    # special cases that are not covered by others:

    if binop == "gt" and _int(args[1]) == 0:
        # improve codesize (not gas), and maybe trigger
        # downstream optimizations
        return ("iszero", [["iszero", args[0]]])