Esempio n. 1
0
def test_version_check(evm_version):
    assert opcodes.version_check(begin=evm_version)
    assert opcodes.version_check(end=evm_version)
    assert opcodes.version_check(begin=evm_version, end=evm_version)
    if evm_version not in ("byzantium", "atlantis"):
        assert not opcodes.version_check(end="byzantium")
    if evm_version != "istanbul":
        assert not opcodes.version_check(begin="istanbul")
Esempio n. 2
0
def test_version_check(evm_version):
    assert opcodes.version_check(begin=evm_version)
    assert opcodes.version_check(end=evm_version)
    assert opcodes.version_check(begin=evm_version, end=evm_version)
    if evm_version not in ("byzantium", "atlantis"):
        assert not opcodes.version_check(end="byzantium")
    istanbul_check = opcodes.version_check(begin="istanbul")
    assert istanbul_check == (opcodes.EVM_VERSIONS[evm_version] >=
                              opcodes.EVM_VERSIONS["istanbul"])
Esempio n. 3
0
def shift(expr, args, kwargs, context):

    if args[1].typ.is_literal:
        shift_abs = abs(args[1].value)
    else:
        shift_abs = ['sub', 0, '_s']

    if version_check(begin="constantinople"):
        left_shift = ['shl', '_s', '_v']
        right_shift = ['shr', shift_abs, '_v']
    else:
        # If second argument is positive, left-shift so multiply by a power of two
        # If it is negative, divide by a power of two
        # node that if the abs of the second argument >= 256, then in the EVM
        # 2**(second arg) = 0, and multiplying OR dividing by 0 gives 0
        left_shift = ['mul', '_v', ['exp', 2, '_s']]
        right_shift = ['div', '_v', ['exp', 2, shift_abs]]

    if not args[1].typ.is_literal:
        node_list = ['if', ['slt', '_s', 0], right_shift, left_shift]
    elif args[1].value >= 0:
        node_list = left_shift
    else:
        node_list = right_shift

    return LLLnode.from_list(
        [
            'with', '_v', args[0], [
                'with', '_s', args[1],
                    node_list,
            ],
        ],
        typ=BaseType('uint256'),
        pos=getpos(expr),
    )
Esempio n. 4
0
def int128_clamp(lll_node):
    if version_check(begin="constantinople"):
        return [
            "with",
            "_val",
            lll_node,
            [
                "seq_unchecked",
                ["dup1", "_val"],
                ["if", ["slt", "_val", 0], ["not", "pass"]],
                ["assert", ["iszero", ["shr", 127, "pass"]]],
            ],
        ]
    else:
        return [
            "clamp",
            ["mload", MemoryPositions.MINNUM],
            lll_node,
            ["mload", MemoryPositions.MAXNUM],
        ]
Esempio n. 5
0
 def attribute(self):
     # x.balance: balance of address x
     if self.expr.attr == 'balance':
         addr = Expr.parse_value_expr(self.expr.value, self.context)
         if not is_base_type(addr.typ, 'address'):
             raise TypeMismatch(
                 "Type mismatch: balance keyword expects an address as input",
                 self.expr)
         if (isinstance(self.expr.value, vy_ast.Name)
                 and self.expr.value.id == "self"
                 and version_check(begin="istanbul")):
             seq = ['selfbalance']
         else:
             seq = ['balance', addr]
         return LLLnode.from_list(
             seq,
             typ=BaseType('uint256'),
             location=None,
             pos=getpos(self.expr),
         )
     # x.codesize: codesize of address x
     elif self.expr.attr == 'codesize' or self.expr.attr == 'is_contract':
         addr = Expr.parse_value_expr(self.expr.value, self.context)
         if not is_base_type(addr.typ, 'address'):
             raise TypeMismatch(
                 "Type mismatch: codesize keyword expects an address as input",
                 self.expr,
             )
         if self.expr.attr == 'codesize':
             eval_code = ['extcodesize', addr]
             output_type = 'int128'
         else:
             eval_code = ['gt', ['extcodesize', addr], 0]
             output_type = 'bool'
         return LLLnode.from_list(
             eval_code,
             typ=BaseType(output_type),
             location=None,
             pos=getpos(self.expr),
         )
     # x.codehash: keccak of address x
     elif self.expr.attr == 'codehash':
         addr = Expr.parse_value_expr(self.expr.value, self.context)
         if not is_base_type(addr.typ, 'address'):
             raise TypeMismatch(
                 "codehash keyword expects an address as input",
                 self.expr,
             )
         if not version_check(begin="constantinople"):
             raise EvmVersionException(
                 "address.codehash is unavailable prior to constantinople ruleset",
                 self.expr)
         return LLLnode.from_list(['extcodehash', addr],
                                  typ=BaseType('bytes32'),
                                  location=None,
                                  pos=getpos(self.expr))
     # self.x: global attribute
     elif isinstance(self.expr.value,
                     vy_ast.Name) and self.expr.value.id == "self":
         if self.expr.attr not in self.context.globals:
             raise VariableDeclarationException(
                 "Persistent variable undeclared: " + self.expr.attr,
                 self.expr,
             )
         var = self.context.globals[self.expr.attr]
         return LLLnode.from_list(
             var.pos,
             typ=var.typ,
             location='storage',
             pos=getpos(self.expr),
             annotation='self.' + self.expr.attr,
         )
     # Reserved keywords
     elif (isinstance(self.expr.value, vy_ast.Name)
           and self.expr.value.id in ENVIRONMENT_VARIABLES):
         key = self.expr.value.id + "." + self.expr.attr
         if key == "msg.sender":
             if self.context.is_private:
                 raise StructureException(
                     "msg.sender not allowed in private functions.",
                     self.expr)
             return LLLnode.from_list(['caller'],
                                      typ='address',
                                      pos=getpos(self.expr))
         elif key == "msg.value":
             if not self.context.is_payable:
                 raise NonPayableViolation(
                     "Cannot use msg.value in a non-payable function",
                     self.expr,
                 )
             return LLLnode.from_list(
                 ['callvalue'],
                 typ=BaseType('uint256'),
                 pos=getpos(self.expr),
             )
         elif key == "msg.gas":
             return LLLnode.from_list(
                 ['gas'],
                 typ='uint256',
                 pos=getpos(self.expr),
             )
         elif key == "block.difficulty":
             return LLLnode.from_list(
                 ['difficulty'],
                 typ='uint256',
                 pos=getpos(self.expr),
             )
         elif key == "block.timestamp":
             return LLLnode.from_list(
                 ['timestamp'],
                 typ=BaseType('uint256'),
                 pos=getpos(self.expr),
             )
         elif key == "block.coinbase":
             return LLLnode.from_list(['coinbase'],
                                      typ='address',
                                      pos=getpos(self.expr))
         elif key == "block.number":
             return LLLnode.from_list(['number'],
                                      typ='uint256',
                                      pos=getpos(self.expr))
         elif key == "block.prevhash":
             return LLLnode.from_list(
                 ['blockhash', ['sub', 'number', 1]],
                 typ='bytes32',
                 pos=getpos(self.expr),
             )
         elif key == "tx.origin":
             return LLLnode.from_list(['origin'],
                                      typ='address',
                                      pos=getpos(self.expr))
         elif key == "chain.id":
             if not version_check(begin="istanbul"):
                 raise EvmVersionException(
                     "chain.id is unavailable prior to istanbul ruleset",
                     self.expr)
             return LLLnode.from_list(['chainid'],
                                      typ='uint256',
                                      pos=getpos(self.expr))
         else:
             raise StructureException("Unsupported keyword: " + key,
                                      self.expr)
     # Other variables
     else:
         sub = Expr.parse_variable_location(self.expr.value, self.context)
         # contract type
         if isinstance(sub.typ, ContractType):
             return sub
         if not isinstance(sub.typ, StructType):
             raise TypeMismatch(
                 "Type mismatch: member variable access not expected",
                 self.expr.value,
             )
         attrs = list(sub.typ.members.keys())
         if self.expr.attr not in attrs:
             raise TypeMismatch(
                 f"Member {self.expr.attr} not found. Only the following available: "
                 f"{' '.join(attrs)}",
                 self.expr,
             )
         return add_variable_offset(sub,
                                    self.expr.attr,
                                    pos=getpos(self.expr))
Esempio n. 6
0
    def parse_BinOp(self):
        left = Expr.parse_value_expr(self.expr.left, self.context)
        right = Expr.parse_value_expr(self.expr.right, self.context)

        if not is_numeric_type(left.typ) or not is_numeric_type(right.typ):
            return

        pos = getpos(self.expr)
        types = {left.typ.typ, right.typ.typ}
        literals = {left.typ.is_literal, right.typ.is_literal}

        # If one value of the operation is a literal, we recast it to match the non-literal type.
        # We know this is OK because types were already verified in the actual typechecking pass.
        # This is a temporary solution to not break parser while we work toward removing types
        # altogether at this stage of complition. @iamdefinitelyahuman
        if literals == {True, False
                        } and len(types) > 1 and "decimal" not in types:
            if left.typ.is_literal and SizeLimits.in_bounds(
                    right.typ.typ, left.value):
                left = LLLnode.from_list(
                    left.value,
                    typ=BaseType(right.typ.typ, None, is_literal=True),
                    pos=pos,
                )
            elif right.typ.is_literal and SizeLimits.in_bounds(
                    left.typ.typ, right.value):
                right = LLLnode.from_list(
                    right.value,
                    typ=BaseType(left.typ.typ, None, is_literal=True),
                    pos=pos,
                )

        ltyp, rtyp = left.typ.typ, right.typ.typ
        if ltyp != rtyp:
            # Sanity check - ensure that we aren't dealing with different types
            # This should be unreachable due to the type check pass
            return

        arith = None
        if isinstance(self.expr.op, (vy_ast.Add, vy_ast.Sub)):
            new_typ = BaseType(ltyp)

            if ltyp == "uint256":
                if isinstance(self.expr.op, vy_ast.Add):
                    # safeadd
                    arith = [
                        "seq", ["assert", ["ge", ["add", "l", "r"], "l"]],
                        ["add", "l", "r"]
                    ]

                elif isinstance(self.expr.op, vy_ast.Sub):
                    # safesub
                    arith = [
                        "seq", ["assert", ["ge", "l", "r"]], ["sub", "l", "r"]
                    ]

            elif ltyp == "int256":
                if isinstance(self.expr.op, vy_ast.Add):
                    op, comp1, comp2 = "add", "sge", "slt"
                else:
                    op, comp1, comp2 = "sub", "sle", "sgt"

                if right.typ.is_literal:
                    if right.value >= 0:
                        arith = [
                            "seq", ["assert", [comp1, [op, "l", "r"], "l"]],
                            [op, "l", "r"]
                        ]
                    else:
                        arith = [
                            "seq", ["assert", [comp2, [op, "l", "r"], "l"]],
                            [op, "l", "r"]
                        ]
                else:
                    arith = [
                        "with",
                        "ans",
                        [op, "l", "r"],
                        [
                            "seq",
                            [
                                "assert",
                                [
                                    "or",
                                    [
                                        "and", ["sge", "r", 0],
                                        [comp1, "ans", "l"]
                                    ],
                                    [
                                        "and", ["slt", "r", 0],
                                        [comp2, "ans", "l"]
                                    ],
                                ],
                            ],
                            "ans",
                        ],
                    ]

            elif ltyp in ("decimal", "int128"):
                op = "add" if isinstance(self.expr.op, vy_ast.Add) else "sub"
                arith = [op, "l", "r"]

        elif isinstance(self.expr.op, vy_ast.Mult):
            new_typ = BaseType(ltyp)
            if ltyp == "uint256":
                arith = [
                    "with",
                    "ans",
                    ["mul", "l", "r"],
                    [
                        "seq",
                        [
                            "assert",
                            [
                                "or", ["eq", ["div", "ans", "l"], "r"],
                                ["iszero", "l"]
                            ]
                        ],
                        "ans",
                    ],
                ]

            elif ltyp == "int256":
                if version_check(begin="constantinople"):
                    upper_bound = ["shl", 255, 1]
                else:
                    upper_bound = -(2**255)
                if not left.typ.is_literal and not right.typ.is_literal:
                    bounds_check = [
                        "assert",
                        [
                            "or", ["ne", "l", ["not", 0]],
                            ["ne", "r", upper_bound]
                        ],
                    ]
                elif left.typ.is_literal and left.value == -1:
                    bounds_check = ["assert", ["ne", "r", upper_bound]]
                elif right.typ.is_literal and right.value == -(2**255):
                    bounds_check = ["assert", ["ne", "l", ["not", 0]]]
                else:
                    bounds_check = "pass"
                arith = [
                    "with",
                    "ans",
                    ["mul", "l", "r"],
                    [
                        "seq",
                        bounds_check,
                        [
                            "assert",
                            [
                                "or", ["eq", ["sdiv", "ans", "l"], "r"],
                                ["iszero", "l"]
                            ]
                        ],
                        "ans",
                    ],
                ]

            elif ltyp == "int128":
                arith = ["mul", "l", "r"]

            elif ltyp == "decimal":
                arith = [
                    "with",
                    "ans",
                    ["mul", "l", "r"],
                    [
                        "seq",
                        [
                            "assert",
                            [
                                "or", ["eq", ["sdiv", "ans", "l"], "r"],
                                ["iszero", "l"]
                            ]
                        ],
                        ["sdiv", "ans", DECIMAL_DIVISOR],
                    ],
                ]

        elif isinstance(self.expr.op, vy_ast.Div):
            if right.typ.is_literal and right.value == 0:
                return

            new_typ = BaseType(ltyp)

            if right.typ.is_literal:
                divisor = "r"
            else:
                # only apply the non-zero clamp when r is not a constant
                divisor = ["clamp_nonzero", "r"]

            if ltyp == "uint256":
                arith = ["div", "l", divisor]

            elif ltyp == "int256":
                if version_check(begin="constantinople"):
                    upper_bound = ["shl", 255, 1]
                else:
                    upper_bound = -(2**255)
                if not left.typ.is_literal and not right.typ.is_literal:
                    bounds_check = [
                        "assert",
                        [
                            "or", ["ne", "r", ["not", 0]],
                            ["ne", "l", upper_bound]
                        ],
                    ]
                elif left.typ.is_literal and left.value == -(2**255):
                    bounds_check = ["assert", ["ne", "r", ["not", 0]]]
                elif right.typ.is_literal and right.value == -1:
                    bounds_check = ["assert", ["ne", "l", upper_bound]]
                else:
                    bounds_check = "pass"
                arith = ["seq", bounds_check, ["sdiv", "l", divisor]]

            elif ltyp in ("int128", "int256"):
                arith = ["sdiv", "l", divisor]

            elif ltyp == "decimal":
                arith = [
                    "sdiv",
                    ["mul", "l", DECIMAL_DIVISOR],
                    divisor,
                ]

        elif isinstance(self.expr.op, vy_ast.Mod):
            if right.typ.is_literal and right.value == 0:
                return

            new_typ = BaseType(ltyp)

            if right.typ.is_literal:
                divisor = "r"
            else:
                # only apply the non-zero clamp when r is not a constant
                divisor = ["clamp_nonzero", "r"]

            if ltyp == "uint256":
                arith = ["mod", "l", divisor]
            else:
                arith = ["smod", "l", divisor]

        elif isinstance(self.expr.op, vy_ast.Pow):
            new_typ = BaseType(ltyp)

            if self.expr.left.get("value") == 1:
                return LLLnode.from_list([1], typ=new_typ, pos=pos)
            if self.expr.left.get("value") == 0:
                return LLLnode.from_list(["iszero", right],
                                         typ=new_typ,
                                         pos=pos)

            if ltyp == "int128":
                is_signed = True
                num_bits = 128
            elif ltyp == "int256":
                is_signed = True
                num_bits = 256
            else:
                is_signed = False
                num_bits = 256

            if isinstance(self.expr.left, vy_ast.Int):
                value = self.expr.left.value
                upper_bound = calculate_largest_power(value, num_bits,
                                                      is_signed) + 1
                # for signed integers, this also prevents negative values
                clamp = ["lt", right, upper_bound]
                return LLLnode.from_list(
                    ["seq", ["assert", clamp], ["exp", left, right]],
                    typ=new_typ,
                    pos=pos,
                )
            elif isinstance(self.expr.right, vy_ast.Int):
                value = self.expr.right.value
                upper_bound = calculate_largest_base(value, num_bits,
                                                     is_signed) + 1
                if is_signed:
                    clamp = [
                        "and", ["slt", left, upper_bound],
                        ["sgt", left, -upper_bound]
                    ]
                else:
                    clamp = ["lt", left, upper_bound]
                return LLLnode.from_list(
                    ["seq", ["assert", clamp], ["exp", left, right]],
                    typ=new_typ,
                    pos=pos,
                )
            else:
                # `a ** b` where neither `a` or `b` are known
                # TODO this is currently unreachable, once we implement a way to do it safely
                # remove the check in `vyper/context/types/value/numeric.py`
                return

        if arith is None:
            return

        p = ["seq"]
        if new_typ.typ == "int128":
            p.append(int128_clamp(arith))
        elif new_typ.typ == "decimal":
            p.append([
                "clamp",
                ["mload", MemoryPositions.MINDECIMAL],
                arith,
                ["mload", MemoryPositions.MAXDECIMAL],
            ])
        elif new_typ.typ in ("uint256", "int256"):
            p.append(arith)
        else:
            return

        p = ["with", "l", left, ["with", "r", right, p]]
        return LLLnode.from_list(p, typ=new_typ, pos=pos)
Esempio n. 7
0
 def parse_Attribute(self):
     # x.balance: balance of address x
     if self.expr.attr == "balance":
         addr = Expr.parse_value_expr(self.expr.value, self.context)
         if is_base_type(addr.typ, "address"):
             if (isinstance(self.expr.value, vy_ast.Name)
                     and self.expr.value.id == "self"
                     and version_check(begin="istanbul")):
                 seq = ["selfbalance"]
             else:
                 seq = ["balance", addr]
             return LLLnode.from_list(
                 seq,
                 typ=BaseType("uint256"),
                 location=None,
                 pos=getpos(self.expr),
             )
     # x.codesize: codesize of address x
     elif self.expr.attr == "codesize" or self.expr.attr == "is_contract":
         addr = Expr.parse_value_expr(self.expr.value, self.context)
         if is_base_type(addr.typ, "address"):
             if self.expr.attr == "codesize":
                 if self.expr.value.id == "self":
                     eval_code = ["codesize"]
                 else:
                     eval_code = ["extcodesize", addr]
                 output_type = "uint256"
             else:
                 eval_code = ["gt", ["extcodesize", addr], 0]
                 output_type = "bool"
             return LLLnode.from_list(
                 eval_code,
                 typ=BaseType(output_type),
                 location=None,
                 pos=getpos(self.expr),
             )
     # x.codehash: keccak of address x
     elif self.expr.attr == "codehash":
         addr = Expr.parse_value_expr(self.expr.value, self.context)
         if not version_check(begin="constantinople"):
             raise EvmVersionException(
                 "address.codehash is unavailable prior to constantinople ruleset",
                 self.expr)
         if is_base_type(addr.typ, "address"):
             return LLLnode.from_list(
                 ["extcodehash", addr],
                 typ=BaseType("bytes32"),
                 location=None,
                 pos=getpos(self.expr),
             )
     # self.x: global attribute
     elif isinstance(self.expr.value,
                     vy_ast.Name) and self.expr.value.id == "self":
         type_ = self.expr._metadata["type"]
         var = self.context.globals[self.expr.attr]
         return LLLnode.from_list(
             type_.position.position,
             typ=var.typ,
             location="storage",
             pos=getpos(self.expr),
             annotation="self." + self.expr.attr,
         )
     # Reserved keywords
     elif (isinstance(self.expr.value, vy_ast.Name)
           and self.expr.value.id in ENVIRONMENT_VARIABLES):
         key = f"{self.expr.value.id}.{self.expr.attr}"
         if key == "msg.sender" and not self.context.is_internal:
             return LLLnode.from_list(["caller"],
                                      typ="address",
                                      pos=getpos(self.expr))
         elif key == "msg.data" and not self.context.is_internal:
             is_len = self.expr._metadata.get("is_len")
             if is_len is True:
                 typ = ByteArrayType(32)
                 pos = self.context.new_internal_variable(typ)
                 node = ["seq", ["mstore", pos, "calldatasize"], pos]
                 return LLLnode.from_list(node,
                                          typ=typ,
                                          pos=getpos(self.expr),
                                          location="memory")
             size = self.expr._metadata.get("size")
             typ = ByteArrayType(size + 32)
             pos = self.context.new_internal_variable(typ)
             node = [
                 "seq",
                 ["assert", ["le", size, "calldatasize"]],
                 ["mstore", pos, size],
                 ["calldatacopy", pos + 32, 0, size],
                 pos,
             ]
             return LLLnode.from_list(node,
                                      typ=typ,
                                      pos=getpos(self.expr),
                                      location="memory")
         elif key == "msg.value" and self.context.is_payable:
             return LLLnode.from_list(
                 ["callvalue"],
                 typ=BaseType("uint256"),
                 pos=getpos(self.expr),
             )
         elif key == "msg.gas":
             return LLLnode.from_list(
                 ["gas"],
                 typ="uint256",
                 pos=getpos(self.expr),
             )
         elif key == "block.difficulty":
             return LLLnode.from_list(
                 ["difficulty"],
                 typ="uint256",
                 pos=getpos(self.expr),
             )
         elif key == "block.timestamp":
             return LLLnode.from_list(
                 ["timestamp"],
                 typ=BaseType("uint256"),
                 pos=getpos(self.expr),
             )
         elif key == "block.coinbase":
             return LLLnode.from_list(["coinbase"],
                                      typ="address",
                                      pos=getpos(self.expr))
         elif key == "block.number":
             return LLLnode.from_list(["number"],
                                      typ="uint256",
                                      pos=getpos(self.expr))
         elif key == "block.prevhash":
             return LLLnode.from_list(
                 ["blockhash", ["sub", "number", 1]],
                 typ="bytes32",
                 pos=getpos(self.expr),
             )
         elif key == "tx.origin":
             return LLLnode.from_list(["origin"],
                                      typ="address",
                                      pos=getpos(self.expr))
         elif key == "chain.id":
             if not version_check(begin="istanbul"):
                 raise EvmVersionException(
                     "chain.id is unavailable prior to istanbul ruleset",
                     self.expr)
             return LLLnode.from_list(["chainid"],
                                      typ="uint256",
                                      pos=getpos(self.expr))
     # Other variables
     else:
         sub = Expr.parse_variable_location(self.expr.value, self.context)
         # contract type
         if isinstance(sub.typ, InterfaceType):
             return sub
         if isinstance(sub.typ,
                       StructType) and self.expr.attr in sub.typ.members:
             return add_variable_offset(sub,
                                        self.expr.attr,
                                        pos=getpos(self.expr))
Esempio n. 8
0
def test_version_check_no_begin_or_end():
    with pytest.raises(CompilerPanic):
        opcodes.version_check()
Esempio n. 9
0
def make_arg_clamper(datapos, mempos, typ, is_init=False):
    """
    Clamps argument to type limits.

    Arguments
    ---------
    datapos : int | LLLnode
        Calldata offset of the value being clamped
    mempos : int | LLLnode
        Memory offset that the value is stored at during clamping
    typ : vyper.types.types.BaseType
        Type of the value
    is_init : bool, optional
        Boolean indicating if we are generating init bytecode

    Returns
    -------
    LLLnode
        Arg clamper LLL
    """

    if not is_init:
        data_decl = ["calldataload", ["add", 4, datapos]]
        copier = functools.partial(_mk_calldatacopy_copier, mempos=mempos)
    else:
        data_decl = ["codeload", ["add", "~codelen", datapos]]
        copier = functools.partial(_mk_codecopy_copier, mempos=mempos)
    # Numbers: make sure they're in range
    if is_base_type(typ, "int128"):
        return LLLnode.from_list(int128_clamp(data_decl),
                                 typ=typ,
                                 annotation="checking int128 input")
    # Booleans: make sure they're zero or one
    elif is_base_type(typ, "bool"):
        if version_check(begin="constantinople"):
            lll = ["assert", ["iszero", ["shr", 1, data_decl]]]
        else:
            lll = ["uclamplt", data_decl, 2]
        return LLLnode.from_list(lll,
                                 typ=typ,
                                 annotation="checking bool input")
    # Addresses: make sure they're in range
    elif is_base_type(typ, "address"):
        if version_check(begin="constantinople"):
            lll = ["assert", ["iszero", ["shr", 160, data_decl]]]
        else:
            lll = ["uclamplt", data_decl, ["mload", MemoryPositions.ADDRSIZE]]
        return LLLnode.from_list(lll,
                                 typ=typ,
                                 annotation="checking address input")
    # Bytes: make sure they have the right size
    elif isinstance(typ, ByteArrayLike):
        return LLLnode.from_list(
            [
                "seq",
                copier(data_decl, 32 + typ.maxlen),
                [
                    "assert",
                    [
                        "le", ["calldataload", ["add", 4, data_decl]],
                        typ.maxlen
                    ]
                ],
            ],
            typ=None,
            annotation="checking bytearray input",
        )
    # Lists: recurse
    elif isinstance(typ, ListType):
        if typ.count > 5 or (type(datapos) is list and type(mempos) is list):
            # find ultimate base type
            subtype = typ.subtype
            while hasattr(subtype, "subtype"):
                subtype = subtype.subtype

            # make arg clamper for the base type
            offset = MemoryPositions.FREE_LOOP_INDEX
            clamper = make_arg_clamper(
                ["add", datapos, ["mload", offset]],
                ["add", mempos, ["mload", offset]],
                subtype,
                is_init,
            )
            if clamper.value == "pass":
                # no point looping if the base type doesn't require clamping
                return clamper

            # loop the entire array at once, even if it's multidimensional
            type_size = get_size_of_type(typ)
            i_incr = get_size_of_type(subtype) * 32

            mem_to = type_size * 32
            loop_label = f"_check_list_loop_{str(uuid.uuid4())}"

            lll_node = [
                ["mstore", offset, 0],  # init loop
                ["label", loop_label],
                clamper,
                ["mstore", offset, ["add", ["mload", offset], i_incr]],
                [
                    "if", ["lt", ["mload", offset], mem_to],
                    ["goto", loop_label]
                ],
            ]
        else:
            lll_node = []
            for i in range(typ.count):
                offset = get_size_of_type(typ.subtype) * 32 * i
                lll_node.append(
                    make_arg_clamper(datapos + offset, mempos + offset,
                                     typ.subtype, is_init))
        return LLLnode.from_list(["seq"] + lll_node,
                                 typ=None,
                                 annotation="checking list input")
    # Otherwise don't make any checks
    else:
        return LLLnode.from_list("pass")
Esempio n. 10
0
def to_int256(expr, args, kwargs, context):
    in_arg = args[0]
    input_type, _ = get_type(in_arg)

    if input_type == "num_literal":
        if isinstance(in_arg, int):
            if not SizeLimits.in_bounds("int256", in_arg):
                raise InvalidLiteral(f"Number out of range: {in_arg}")
            return LLLnode.from_list(in_arg,
                                     typ=BaseType("int256", ),
                                     pos=getpos(expr))
        elif isinstance(in_arg, Decimal):
            if not SizeLimits.in_bounds("int256", math.trunc(in_arg)):
                raise InvalidLiteral(
                    f"Number out of range: {math.trunc(in_arg)}")
            return LLLnode.from_list(math.trunc(in_arg),
                                     typ=BaseType("int256"),
                                     pos=getpos(expr))
        else:
            raise InvalidLiteral(f"Unknown numeric literal type: {in_arg}")

    elif isinstance(in_arg, LLLnode) and input_type == "int128":
        return LLLnode.from_list(in_arg,
                                 typ=BaseType("int256"),
                                 pos=getpos(expr))

    elif isinstance(in_arg, LLLnode) and input_type == "uint256":
        if version_check(begin="constantinople"):
            upper_bound = ["shl", 255, 1]
        else:
            upper_bound = -(2**255)
        return LLLnode.from_list(["uclamplt", in_arg, upper_bound],
                                 typ=BaseType("int256"),
                                 pos=getpos(expr))

    elif isinstance(in_arg, LLLnode) and input_type == "decimal":
        return LLLnode.from_list(
            ["sdiv", in_arg, DECIMAL_DIVISOR],
            typ=BaseType("int256"),
            pos=getpos(expr),
        )

    elif isinstance(in_arg, LLLnode) and input_type == "bool":
        return LLLnode.from_list(in_arg,
                                 typ=BaseType("int256"),
                                 pos=getpos(expr))

    elif isinstance(in_arg, LLLnode) and input_type in ("bytes32", "address"):
        return LLLnode(value=in_arg.value,
                       args=in_arg.args,
                       typ=BaseType("int256"),
                       pos=getpos(expr))

    elif isinstance(in_arg, LLLnode) and input_type in ("Bytes", "String"):
        if in_arg.typ.maxlen > 32:
            raise TypeMismatch(
                f"Cannot convert bytes array of max length {in_arg.typ.maxlen} to int256",
                expr,
            )
        return byte_array_to_num(in_arg, expr, "int256")

    else:
        raise InvalidLiteral(f"Invalid input for int256: {in_arg}", expr)
Esempio n. 11
0
def address_clamp(lll_node):
    if version_check(begin="constantinople"):
        return ["assert", ["iszero", ["shr", 160, lll_node]]]
    else:
        return ["uclamplt", lll_node, ["mload", MemoryPositions.ADDRSIZE]]