示例#1
0
文件: expr.py 项目: skellet0r/vyper
 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),
             )
     # x.code: codecopy/extcodecopy of address x
     elif self.expr.attr == "code":
         addr = Expr.parse_value_expr(self.expr.value, self.context)
         if is_base_type(addr.typ, "address"):
             # These adhoc nodes will be replaced with a valid node in `Slice.build_LLL`
             if addr.value == "address":  # for `self.code`
                 return LLLnode.from_list(["~selfcode"],
                                          typ=ByteArrayType(0))
             return LLLnode.from_list(["~extcode", addr],
                                      typ=ByteArrayType(0))
     # 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":
             return LLLnode.from_list(["caller"],
                                      typ="address",
                                      pos=getpos(self.expr))
         elif key == "msg.data":
             # This adhoc node will be replaced with a valid node in `Slice/Len.build_LLL`
             return LLLnode.from_list(["~calldata"], typ=ByteArrayType(0))
         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.gaslimit":
             return LLLnode.from_list(["gaslimit"],
                                      typ="uint256",
                                      pos=getpos(self.expr))
         elif key == "block.basefee":
             return LLLnode.from_list(["basefee"],
                                      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 == "tx.gasprice":
             return LLLnode.from_list(["gasprice"],
                                      typ="uint256",
                                      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 get_element_ptr(sub,
                                    self.expr.attr,
                                    pos=getpos(self.expr))
示例#2
0
文件: expr.py 项目: skellet0r/vyper
    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 codegen 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, 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, 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", "uint8"):
                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 in ("int128", "uint8"):
                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 in ("uint8", "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 == "int128":
                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 in ("uint8", "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
            elif ltyp == "uint8":
                is_signed = False
                num_bits = 8
            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

        arith = LLLnode.from_list(arith, typ=new_typ)

        p = [
            "with",
            "l",
            left,
            [
                "with",
                "r",
                right,
                # note clamp_basetype is a noop on [u]int256
                # note: clamp_basetype throws on unclampable input
                clamp_basetype(arith),
            ],
        ]
        return LLLnode.from_list(p, typ=new_typ, pos=pos)
示例#3
0
文件: expr.py 项目: skellet0r/vyper
 def _is_valid_interface_assign(self):
     if self.expr.args and len(self.expr.args) == 1:
         arg_lll = Expr(self.expr.args[0], self.context).lll_node
         if arg_lll.typ == BaseType("address"):
             return True, arg_lll
     return False, None
示例#4
0
def get_bytearray_length(arg):
    typ = BaseType("uint256")
    return IRnode.from_list(LOAD(arg), typ=typ)
示例#5
0
文件: stmt.py 项目: skellet0r/vyper
    def _parse_For_range(self):
        # attempt to use the type specified by type checking, fall back to `int256`
        # this is a stopgap solution to allow uint256 - it will be properly solved
        # once we refactor type system
        iter_typ = "int256"
        if "type" in self.stmt.target._metadata:
            iter_typ = self.stmt.target._metadata["type"]._id

        # Get arg0
        arg0 = self.stmt.iter.args[0]
        num_of_args = len(self.stmt.iter.args)

        # Type 1 for, e.g. for i in range(10): ...
        if num_of_args == 1:
            arg0_val = self._get_range_const_value(arg0)
            start = LLLnode.from_list(0, typ=iter_typ, pos=getpos(self.stmt))
            rounds = arg0_val

        # Type 2 for, e.g. for i in range(100, 110): ...
        elif self._check_valid_range_constant(self.stmt.iter.args[1],
                                              raise_exception=False)[0]:
            arg0_val = self._get_range_const_value(arg0)
            arg1_val = self._get_range_const_value(self.stmt.iter.args[1])
            start = LLLnode.from_list(arg0_val,
                                      typ=iter_typ,
                                      pos=getpos(self.stmt))
            rounds = LLLnode.from_list(arg1_val - arg0_val,
                                       typ=iter_typ,
                                       pos=getpos(self.stmt))

        # Type 3 for, e.g. for i in range(x, x + 10): ...
        else:
            arg1 = self.stmt.iter.args[1]
            rounds = self._get_range_const_value(arg1.right)
            start = Expr.parse_value_expr(arg0, self.context)

        r = rounds if isinstance(rounds, int) else rounds.value
        if r < 1:
            return

        varname = self.stmt.target.id
        i = LLLnode.from_list(self.context.fresh_varname("range_ix"),
                              typ="uint256")
        iptr = self.context.new_variable(varname,
                                         BaseType(iter_typ),
                                         pos=getpos(self.stmt))

        self.context.forvars[varname] = True

        loop_body = ["seq"]
        # store the current value of i so it is accessible to userland
        loop_body.append(["mstore", iptr, i])
        loop_body.append(parse_body(self.stmt.body, self.context))

        lll_node = LLLnode.from_list(
            ["repeat", i, start, rounds, rounds, loop_body],
            pos=getpos(self.stmt),
        )
        del self.context.forvars[varname]

        return lll_node
示例#6
0
def get_bytearray_length(arg):
    typ = BaseType("uint256")
    return LLLnode.from_list([load_op(arg.location), arg], typ=typ)
示例#7
0
def _dynarray_make_setter(dst, src, pos=None):
    assert isinstance(src.typ, DArrayType)
    assert isinstance(dst.typ, DArrayType)

    if src.value == "~empty":
        return LLLnode.from_list([store_op(dst.location), dst, 0], pos=pos)

    if src.value == "multi":
        ret = ["seq"]
        # handle literals

        # write the length word
        store_length = [store_op(dst.location), dst, len(src.args)]
        ann = None
        if src.annotation is not None:
            ann = f"len({src.annotation})"
        store_length = LLLnode.from_list(store_length, annotation=ann)
        ret.append(store_length)

        n_items = len(src.args)
        for i in range(n_items):
            k = LLLnode.from_list(i, typ="uint256")
            dst_i = get_element_ptr(dst, k, pos=pos, array_bounds_check=False)
            src_i = get_element_ptr(src, k, pos=pos, array_bounds_check=False)
            ret.append(make_setter(dst_i, src_i, pos))

        return ret

    with src.cache_when_complex("darray_src") as (b1, src):

        # for ABI-encoded dynamic data, we must loop to unpack, since
        # the layout does not match our memory layout
        should_loop = (src.encoding in (Encoding.ABI, Encoding.JSON_ABI)
                       and src.typ.subtype.abi_type.is_dynamic())

        # if the subtype is dynamic, there might be a lot of
        # unused space inside of each element. for instance
        # DynArray[DynArray[uint256, 100], 5] where all the child
        # arrays are empty - for this case, we recursively call
        # into make_setter instead of straight bytes copy
        # TODO we can make this heuristic more precise, e.g.
        # loop when subtype.is_dynamic AND location == storage
        # OR array_size <= /bound where loop is cheaper than memcpy/
        should_loop |= src.typ.subtype.abi_type.is_dynamic()
        should_loop |= _needs_clamp(src.typ.subtype, src.encoding)

        if should_loop:
            uint = BaseType("uint256")

            # note: name clobbering for the ix is OK because
            # we never reach outside our level of nesting
            i = LLLnode.from_list(_freshname("copy_darray_ix"), typ=uint)

            loop_body = make_setter(
                get_element_ptr(dst, i, array_bounds_check=False, pos=pos),
                get_element_ptr(src, i, array_bounds_check=False, pos=pos),
                pos=pos,
            )
            loop_body.annotation = f"{dst}[i] = {src}[i]"

            with get_dyn_array_count(src).cache_when_complex(
                    "darray_count") as (b2, len_):
                store_len = [store_op(dst.location), dst, len_]
                loop = ["repeat", i, 0, len_, src.typ.count, loop_body]

                return b1.resolve(b2.resolve(["seq", store_len, loop]))

        element_size = src.typ.subtype.memory_bytes_required
        # 32 bytes + number of elements * size of element in bytes
        n_bytes = ["add", _mul(get_dyn_array_count(src), element_size), 32]
        max_bytes = src.typ.memory_bytes_required

        return b1.resolve(copy_bytes(dst, src, n_bytes, max_bytes, pos=pos))