Beispiel #1
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":
         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 = 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.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))
Beispiel #2
0
def gen_tuple_return(stmt, context, sub):
    # Is from a call expression.
    if sub.args and len(
            sub.args[0].args) > 0 and sub.args[0].args[0].value == 'call':
        # self-call to public.
        mem_pos = sub.args[0].args[-1]
        mem_size = get_size_of_type(sub.typ) * 32
        return LLLnode.from_list(['return', mem_pos, mem_size], typ=sub.typ)

    elif (sub.annotation and 'Internal Call' in sub.annotation):
        mem_pos = sub.args[
            -1].value if sub.value == 'seq_unchecked' else sub.args[0].args[-1]
        mem_size = get_size_of_type(sub.typ) * 32
        # Add zero padder if bytes are present in output.
        zero_padder = ['pass']
        byte_arrays = [(i, x) for i, x in enumerate(sub.typ.tuple_members())
                       if isinstance(x, ByteArrayLike)]
        if byte_arrays:
            i, x = byte_arrays[-1]
            zero_padder = zero_pad(bytez_placeholder=[
                'add', mem_pos, ['mload', mem_pos + i * 32]
            ],
                                   maxlen=x.maxlen,
                                   context=context)
        return LLLnode.from_list(
            ['seq'] + [sub] + [zero_padder] +
            [make_return_stmt(stmt, context, mem_pos, mem_size)],
            typ=sub.typ,
            pos=getpos(stmt),
            valency=0)

    subs = []
    # Pre-allocate loop_memory_position if required for private function returning.
    loop_memory_position = (context.new_placeholder(
        typ=BaseType('uint256')) if context.is_private else None)
    # Allocate dynamic off set counter, to keep track of the total packed dynamic data size.
    dynamic_offset_counter_placeholder = context.new_placeholder(
        typ=BaseType('uint256'))
    dynamic_offset_counter = LLLnode(
        dynamic_offset_counter_placeholder,
        typ=None,
        annotation="dynamic_offset_counter"  # dynamic offset position counter.
    )
    new_sub = LLLnode.from_list(
        context.new_placeholder(typ=BaseType('uint256')),
        typ=context.return_type,
        location='memory',
        annotation='new_sub',
    )
    left_token = LLLnode.from_list('_loc', typ=new_sub.typ, location="memory")

    def get_dynamic_offset_value():
        # Get value of dynamic offset counter.
        return ['mload', dynamic_offset_counter]

    def increment_dynamic_offset(dynamic_spot):
        # Increment dyanmic offset counter in memory.
        return [
            'mstore', dynamic_offset_counter,
            [
                'add', ['add', ['ceil32', ['mload', dynamic_spot]], 32],
                ['mload', dynamic_offset_counter]
            ]
        ]

    if not isinstance(context.return_type, TupleLike):
        raise TypeMismatchException(
            'Trying to return %r when expecting %r' %
            (sub.typ, context.return_type), getpos(stmt))
    items = context.return_type.tuple_items()

    dynamic_offset_start = 32 * len(items)  # The static list of args end.

    for i, (key, typ) in enumerate(items):
        variable_offset = LLLnode.from_list(
            ['add', 32 * i, left_token],
            typ=typ,
            annotation='variable_offset',
        )  # variable offset of destination
        if sub.typ.is_literal:
            arg = sub.args[i]
        else:
            arg = add_variable_offset(parent=sub, key=key, pos=getpos(stmt))

        if isinstance(typ, ByteArrayLike):
            # Store offset pointer value.
            subs.append(
                ['mstore', variable_offset,
                 get_dynamic_offset_value()])

            # Store dynamic data, from offset pointer onwards.
            dynamic_spot = LLLnode.from_list(
                ['add', left_token,
                 get_dynamic_offset_value()],
                location="memory",
                typ=typ,
                annotation='dynamic_spot',
            )
            subs.append(
                make_setter(dynamic_spot,
                            arg,
                            location="memory",
                            pos=getpos(stmt)))
            subs.append(increment_dynamic_offset(dynamic_spot))

        elif isinstance(typ, BaseType):
            subs.append(
                make_setter(variable_offset, arg, "memory", pos=getpos(stmt)))
        elif isinstance(typ, TupleLike):
            subs.append(gen_tuple_return(stmt, context, arg))
        else:
            # Maybe this should panic because the type error should be
            # caught at an earlier type-checking stage.
            raise TypeMismatchException(
                "Can't return type %s as part of tuple" % arg.typ, stmt)

    setter = LLLnode.from_list([
        'seq', ['mstore', dynamic_offset_counter, dynamic_offset_start],
        ['with', '_loc', new_sub, ['seq'] + subs]
    ],
                               typ=None)

    return LLLnode.from_list([
        'seq', setter,
        make_return_stmt(stmt, context, new_sub, get_dynamic_offset_value(),
                         loop_memory_position)
    ],
                             typ=None,
                             pos=getpos(stmt),
                             valency=0)
Beispiel #3
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 TypeMismatchException("Type mismatch: balance keyword expects an address as input", self.expr)
         return LLLnode.from_list(['balance', addr], typ=BaseType('uint256', {'wei': 1}), 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 TypeMismatchException("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))
     # self.x: global attribute
     elif isinstance(self.expr.value, 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, ast.Name) and self.expr.value.id in ("msg", "block", "tx"):
         key = self.expr.value.id + "." + self.expr.attr
         if key == "msg.sender":
             if self.context.is_private:
                 raise ParserException("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 NonPayableViolationException("Cannot use msg.value in a non-payable function", self.expr)
             return LLLnode.from_list(['callvalue'], typ=BaseType('uint256', {'wei': 1}), 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', {'sec': 1}, True), 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))
         else:
             raise ParserException("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 TypeMismatchException("Type mismatch: member variable access not expected", self.expr.value)
         attrs = list(sub.typ.members.keys())
         if self.expr.attr not in attrs:
             raise TypeMismatchException("Member %s not found. Only the following available: %s" % (self.expr.attr, " ".join(attrs)), self.expr)
         return add_variable_offset(sub, self.expr.attr, pos=getpos(self.expr))
Beispiel #4
0
def concat(expr, context):
    args = [Expr(arg, context).lll_node for arg in expr.args]
    if len(args) < 2:
        raise StructureException("Concat expects at least two arguments", expr)
    for expr_arg, arg in zip(expr.args, args):
        if not isinstance(arg.typ, ByteArrayType) and not is_base_type(
                arg.typ, 'bytes32'):
            raise TypeMismatchException(
                "Concat expects byte arrays or bytes32 objects", expr_arg)
    # Maximum length of the output
    total_maxlen = sum([
        arg.typ.maxlen if isinstance(arg.typ, ByteArrayType) else 32
        for arg in args
    ])
    # Node representing the position of the output in memory
    placeholder = context.new_placeholder(ByteArrayType(total_maxlen))
    # Object representing the output
    seq = []
    # For each argument we are concatenating...
    for arg in args:
        # Start pasting into a position the starts at zero, and keeps
        # incrementing as we concatenate arguments
        placeholder_node = LLLnode.from_list(['add', placeholder, '_poz'],
                                             typ=ByteArrayType(total_maxlen),
                                             location='memory')
        placeholder_node_plus_32 = LLLnode.from_list(
            ['add', ['add', placeholder, '_poz'], 32],
            typ=ByteArrayType(total_maxlen),
            location='memory')
        if isinstance(arg.typ, ByteArrayType):
            # Ignore empty strings
            if arg.typ.maxlen == 0:
                continue
            # Get the length of the current argument
            if arg.location == "memory":
                length = LLLnode.from_list(['mload', '_arg'],
                                           typ=BaseType('int128'))
                argstart = LLLnode.from_list(['add', '_arg', 32],
                                             typ=arg.typ,
                                             location=arg.location)
            elif arg.location == "storage":
                length = LLLnode.from_list(['sload', ['sha3_32', '_arg']],
                                           typ=BaseType('int128'))
                argstart = LLLnode.from_list(['add', ['sha3_32', '_arg'], 1],
                                             typ=arg.typ,
                                             location=arg.location)
            # Make a copier to copy over data from that argument
            seq.append([
                'with',
                '_arg',
                arg,
                [
                    'seq',
                    make_byte_slice_copier(placeholder_node_plus_32,
                                           argstart,
                                           length,
                                           arg.typ.maxlen,
                                           pos=getpos(expr)),
                    # Change the position to start at the correct
                    # place to paste the next value
                    ['set', '_poz', ['add', '_poz', length]]
                ]
            ])
        else:
            seq.append([
                'seq',
                [
                    'mstore', ['add', placeholder_node, 32],
                    unwrap_location(arg)
                ], ['set', '_poz', ['add', '_poz', 32]]
            ])
    # The position, after all arguments are processing, equals the total
    # length. Paste this in to make the output a proper bytearray
    seq.append(['mstore', placeholder, '_poz'])
    # Memory location of the output
    seq.append(placeholder)
    return LLLnode.from_list(['with', '_poz', 0, ['seq'] + seq],
                             typ=ByteArrayType(total_maxlen),
                             location='memory',
                             pos=getpos(expr),
                             annotation='concat')
Beispiel #5
0
def as_unitless_number(expr, args, kwargs, context):
    return LLLnode(value=args[0].value,
                   args=args[0].args,
                   typ=BaseType(args[0].typ.typ, {}),
                   pos=getpos(expr))
Beispiel #6
0
    def parse_for(self):
        # from .parser import (
        #     parse_body,
        # )
        # Type 0 for, e.g. for i in list(): ...
        if self._is_list_iter():
            return self.parse_for_list()

        is_invalid_for_statement = any((
            not isinstance(self.stmt.iter, ast.Call),
            not isinstance(self.stmt.iter.func, ast.Name),
            not isinstance(self.stmt.target, ast.Name),
            self.stmt.iter.func.id != "range",
            len(self.stmt.iter.args) not in {1, 2},
        ))
        if is_invalid_for_statement:
            raise StructureException(
                ("For statements must be of the form `for i in range(rounds): "
                 "..` or `for i in range(start, start + rounds): ..`"),
                self.stmt.iter)

        block_scope_id = id(self.stmt.orelse)
        with self.context.make_blockscope(block_scope_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='int128',
                                          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='int128',
                                          pos=getpos(self.stmt))
                rounds = LLLnode.from_list(arg1_val - arg0_val,
                                           typ='int128',
                                           pos=getpos(self.stmt))

            # Type 3 for, e.g. for i in range(x, x + 10): ...
            else:
                arg1 = self.stmt.iter.args[1]
                if not isinstance(arg1, ast.BinOp) or not isinstance(
                        arg1.op, ast.Add):
                    raise StructureException(
                        ("Two-arg for statements must be of the form `for i "
                         "in range(start, start + rounds): ...`"),
                        arg1,
                    )

                if ast.dump(arg0) != ast.dump(arg1.left):
                    raise StructureException(
                        ("Two-arg for statements of the form `for i in "
                         "range(x, x + y): ...` must have x identical in both "
                         "places: %r %r") %
                        (ast.dump(arg0), ast.dump(arg1.left)),
                        self.stmt.iter,
                    )

                rounds = self._get_range_const_value(arg1.right)
                start = Expr.parse_value_expr(arg0, self.context)

            varname = self.stmt.target.id
            pos = self.context.new_variable(varname,
                                            BaseType('int128'),
                                            pos=getpos(self.stmt))
            self.context.forvars[varname] = True
            o = LLLnode.from_list(
                [
                    'repeat', pos, start, rounds,
                    parse_body(self.stmt.body, self.context)
                ],
                typ=None,
                pos=getpos(self.stmt),
            )
            del self.context.vars[varname]
            del self.context.forvars[varname]

        return o
Beispiel #7
0
    def parse_return(self):
        if self.context.return_type is None:
            if self.stmt.value:
                raise TypeMismatchException("Not expecting to return a value",
                                            self.stmt)
            return LLLnode.from_list(
                make_return_stmt(self.stmt, self.context, 0, 0),
                typ=None,
                pos=getpos(self.stmt),
                valency=0,
            )
        if not self.stmt.value:
            raise TypeMismatchException("Expecting to return a value",
                                        self.stmt)

        def zero_pad(bytez_placeholder, maxlen):
            zero_padder = LLLnode.from_list(['pass'])
            if maxlen > 0:
                # Iterator used to zero pad memory.
                zero_pad_i = self.context.new_placeholder(BaseType('uint256'))
                zero_padder = LLLnode.from_list(
                    [
                        'with',
                        '_ceil32_end',
                        ['ceil32', ['mload', bytez_placeholder]],
                        [
                            'repeat',
                            zero_pad_i,
                            ['mload', bytez_placeholder],
                            maxlen,
                            [
                                'seq',
                                # stay within allocated bounds
                                [
                                    'if',
                                    [
                                        'gt', ['mload', zero_pad_i],
                                        '_ceil32_end'
                                    ], 'break'
                                ],
                                [
                                    'mstore8',
                                    [
                                        'add', ['add', 32, bytez_placeholder],
                                        ['mload', zero_pad_i]
                                    ], 0
                                ],
                            ],
                        ],
                    ],
                    annotation="Zero pad")
            return zero_padder

        sub = Expr(self.stmt.value, self.context).lll_node

        # Returning a value (most common case)
        if isinstance(sub.typ, BaseType):
            sub = unwrap_location(sub)

            if not isinstance(self.context.return_type, BaseType):
                raise TypeMismatchException(
                    "Return type units mismatch %r %r" % (
                        sub.typ,
                        self.context.return_type,
                    ), self.stmt.value)
            elif self.context.return_type != sub.typ and not sub.typ.is_literal:
                raise TypeMismatchException(
                    "Trying to return base type %r, output expecting %r" % (
                        sub.typ,
                        self.context.return_type,
                    ),
                    self.stmt.value,
                )
            elif sub.typ.is_literal and (
                    self.context.return_type.typ == sub.typ
                    or 'int' in self.context.return_type.typ
                    and 'int' in sub.typ.typ):  # noqa: E501
                if not SizeLimits.in_bounds(self.context.return_type.typ,
                                            sub.value):
                    raise InvalidLiteralException(
                        "Number out of range: " + str(sub.value), self.stmt)
                else:
                    return LLLnode.from_list(
                        [
                            'seq', ['mstore', 0, sub],
                            make_return_stmt(self.stmt, self.context, 0, 32)
                        ],
                        typ=None,
                        pos=getpos(self.stmt),
                        valency=0,
                    )
            elif is_base_type(sub.typ, self.context.return_type.typ) or (
                    is_base_type(sub.typ, 'int128') and is_base_type(
                        self.context.return_type, 'int256')):  # noqa: E501
                return LLLnode.from_list(
                    [
                        'seq', ['mstore', 0, sub],
                        make_return_stmt(self.stmt, self.context, 0, 32)
                    ],
                    typ=None,
                    pos=getpos(self.stmt),
                    valency=0,
                )
            else:
                raise TypeMismatchException(
                    "Unsupported type conversion: %r to %r" %
                    (sub.typ, self.context.return_type),
                    self.stmt.value,
                )
        # Returning a byte array
        elif isinstance(sub.typ, ByteArrayLike):
            if not sub.typ.eq_base(self.context.return_type):
                raise TypeMismatchException(
                    "Trying to return base type %r, output expecting %r" % (
                        sub.typ,
                        self.context.return_type,
                    ),
                    self.stmt.value,
                )
            if sub.typ.maxlen > self.context.return_type.maxlen:
                raise TypeMismatchException(
                    "Cannot cast from greater max-length %d to shorter max-length %d"
                    % (
                        sub.typ.maxlen,
                        self.context.return_type.maxlen,
                    ),
                    self.stmt.value,
                )

            # loop memory has to be allocated first.
            loop_memory_position = self.context.new_placeholder(
                typ=BaseType('uint256'))
            # len & bytez placeholder have to be declared after each other at all times.
            len_placeholder = self.context.new_placeholder(
                typ=BaseType('uint256'))
            bytez_placeholder = self.context.new_placeholder(typ=sub.typ)

            if sub.location in ('storage', 'memory'):
                return LLLnode.from_list([
                    'seq',
                    make_byte_array_copier(LLLnode(
                        bytez_placeholder, location='memory', typ=sub.typ),
                                           sub,
                                           pos=getpos(self.stmt)),
                    zero_pad(bytez_placeholder, sub.typ.maxlen),
                    ['mstore', len_placeholder, 32],
                    make_return_stmt(
                        self.stmt,
                        self.context,
                        len_placeholder,
                        ['ceil32', ['add', ['mload', bytez_placeholder], 64]],
                        loop_memory_position=loop_memory_position,
                    )
                ],
                                         typ=None,
                                         pos=getpos(self.stmt),
                                         valency=0)
            else:
                raise Exception("Invalid location: %s" % sub.location)

        elif isinstance(sub.typ, ListType):
            sub_base_type = re.split(r'\(|\[', str(sub.typ.subtype))[0]
            ret_base_type = re.split(r'\(|\[',
                                     str(self.context.return_type.subtype))[0]
            loop_memory_position = self.context.new_placeholder(
                typ=BaseType('uint256'))
            if sub_base_type != ret_base_type:
                raise TypeMismatchException(
                    "List return type %r does not match specified return type, expecting %r"
                    % (sub_base_type, ret_base_type), self.stmt)
            elif sub.location == "memory" and sub.value != "multi":
                return LLLnode.from_list(
                    make_return_stmt(
                        self.stmt,
                        self.context,
                        sub,
                        get_size_of_type(self.context.return_type) * 32,
                        loop_memory_position=loop_memory_position,
                    ),
                    typ=None,
                    pos=getpos(self.stmt),
                    valency=0,
                )
            else:
                new_sub = LLLnode.from_list(
                    self.context.new_placeholder(self.context.return_type),
                    typ=self.context.return_type,
                    location='memory',
                )
                setter = make_setter(new_sub,
                                     sub,
                                     'memory',
                                     pos=getpos(self.stmt))
                return LLLnode.from_list([
                    'seq', setter,
                    make_return_stmt(
                        self.stmt,
                        self.context,
                        new_sub,
                        get_size_of_type(self.context.return_type) * 32,
                        loop_memory_position=loop_memory_position,
                    )
                ],
                                         typ=None,
                                         pos=getpos(self.stmt))

        # Returning a struct
        elif isinstance(sub.typ, StructType):
            retty = self.context.return_type
            if not isinstance(retty, StructType) or retty.name != sub.typ.name:
                raise TypeMismatchException(
                    "Trying to return %r, output expecting %r" % (
                        sub.typ,
                        self.context.return_type,
                    ),
                    self.stmt.value,
                )
            return gen_tuple_return(self.stmt, self.context, sub)

        # Returning a tuple.
        elif isinstance(sub.typ, TupleType):
            if not isinstance(self.context.return_type, TupleType):
                raise TypeMismatchException(
                    "Trying to return tuple type %r, output expecting %r" % (
                        sub.typ,
                        self.context.return_type,
                    ),
                    self.stmt.value,
                )

            if len(self.context.return_type.members) != len(sub.typ.members):
                raise StructureException("Tuple lengths don't match!",
                                         self.stmt)

            # check return type matches, sub type.
            for i, ret_x in enumerate(self.context.return_type.members):
                s_member = sub.typ.members[i]
                sub_type = s_member if isinstance(s_member,
                                                  NodeType) else s_member.typ
                if type(sub_type) is not type(ret_x):
                    raise StructureException(
                        "Tuple return type does not match annotated return. {} != {}"
                        .format(type(sub_type), type(ret_x)), self.stmt)
            return gen_tuple_return(self.stmt, self.context, sub)

        else:
            raise TypeMismatchException("Can't return type %r" % sub.typ,
                                        self.stmt)
Beispiel #8
0
def to_decimal(expr, args, kwargs, context):
    input = args[0]
    return LLLnode.from_list(['mul', input, DECIMAL_DIVISOR],
                             typ=BaseType('decimal', input.typ.unit,
                                          input.typ.positional),
                             pos=getpos(expr))
Beispiel #9
0
def to_decimal(expr, args, kwargs, context):
    in_arg = args[0]
    input_type, _ = get_type(in_arg)

    if input_type == "bytes":
        if in_arg.typ.maxlen > 32:
            raise TypeMismatch(
                f"Cannot convert bytes array of max length {in_arg.typ.maxlen} to decimal",
                expr,
            )
        num = byte_array_to_num(in_arg, expr, "int128")
        return LLLnode.from_list(["mul", num, DECIMAL_DIVISOR],
                                 typ=BaseType("decimal"),
                                 pos=getpos(expr))

    else:
        if input_type == "uint256":
            if in_arg.typ.is_literal:
                if not SizeLimits.in_bounds("int128",
                                            (in_arg.value * DECIMAL_DIVISOR)):
                    raise InvalidLiteral(
                        f"Number out of range: {in_arg.value}",
                        expr,
                    )
                else:
                    return LLLnode.from_list(["mul", in_arg, DECIMAL_DIVISOR],
                                             typ=BaseType("decimal"),
                                             pos=getpos(expr))
            else:
                return LLLnode.from_list(
                    [
                        "uclample",
                        ["mul", in_arg, DECIMAL_DIVISOR],
                        ["mload", MemoryPositions.MAXDECIMAL],
                    ],
                    typ=BaseType("decimal"),
                    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"),
                pos=getpos(expr),
            )

        elif input_type == "bytes32":
            if in_arg.typ.is_literal:
                if not SizeLimits.in_bounds("int128",
                                            (in_arg.value * DECIMAL_DIVISOR)):
                    raise InvalidLiteral(
                        f"Number out of range: {in_arg.value}",
                        expr,
                    )
                else:
                    return LLLnode.from_list(["mul", in_arg, DECIMAL_DIVISOR],
                                             typ=BaseType("decimal"),
                                             pos=getpos(expr))
            else:
                return LLLnode.from_list(
                    [
                        "clamp",
                        ["mload", MemoryPositions.MINDECIMAL],
                        ["mul", in_arg, DECIMAL_DIVISOR],
                        ["mload", MemoryPositions.MAXDECIMAL],
                    ],
                    typ=BaseType("decimal"),
                    pos=getpos(expr),
                )

        elif input_type in ("int128", "bool"):
            return LLLnode.from_list(["mul", in_arg, DECIMAL_DIVISOR],
                                     typ=BaseType("decimal"),
                                     pos=getpos(expr))

        else:
            raise InvalidLiteral(f"Invalid input for decimal: {in_arg}", expr)
Beispiel #10
0
def add_globals_and_events(_custom_units, _contracts, _defs, _events, _getters,
                           _globals, item):
    item_attributes = {"public": False, "modifiable": False, "static": False}
    if not (isinstance(item.annotation, ast.Call)
            and item.annotation.func.id == "event"):
        item_name, item_attributes = get_item_name_and_attributes(
            item, item_attributes)
        if not all(
            [attr in valid_global_keywords
             for attr in item_attributes.keys()]):
            raise StructureException('Invalid global keyword used: %s' %
                                     item_attributes)
    if item.value is not None:
        raise StructureException('May not assign value whilst defining type',
                                 item)
    elif isinstance(item.annotation,
                    ast.Call) and item.annotation.func.id == "event":
        if _globals or len(_defs):
            raise StructureException(
                "Events must all come before global declarations and function definitions",
                item)
        _events.append(item)
    elif not isinstance(item.target, ast.Name):
        raise StructureException(
            "Can only assign type to variable in top-level statement", item)
    # Is this a custom unit definition.
    elif item.target.id == 'units':
        if not _custom_units:
            if not isinstance(item.annotation, ast.Dict):
                raise VariableDeclarationException(
                    "Define custom units using units: { }.", item.target)
            for key, value in zip(item.annotation.keys,
                                  item.annotation.values):
                if not isinstance(value, ast.Str):
                    raise VariableDeclarationException(
                        "Custom unit description must be a valid string.",
                        value)
                if not isinstance(key, ast.Name):
                    raise VariableDeclarationException(
                        "Custom unit name must be a valid string unquoted string.",
                        key)
                if key.id in _custom_units:
                    raise VariableDeclarationException(
                        "Custom unit may only be defined once", key)
                if not is_varname_valid(key.id, custom_units=_custom_units):
                    raise VariableDeclarationException(
                        "Custom unit may not be a reserved keyword", key)
                _custom_units.append(key.id)
        else:
            raise VariableDeclarationException(
                "Can units can only defined once.", item.target)
    # Check if variable name is reserved or invalid
    elif not is_varname_valid(item.target.id, custom_units=_custom_units):
        raise VariableDeclarationException(
            "Variable name invalid or reserved: ", item.target)
    # Check if global already exists, if so error
    elif item.target.id in _globals:
        raise VariableDeclarationException(
            "Cannot declare a persistent variable twice!", item.target)
    elif len(_defs):
        raise StructureException(
            "Global variables must all come before function definitions", item)
    # If the type declaration is of the form public(<type here>), then proceed with
    # the underlying type but also add getters
    elif isinstance(item.annotation,
                    ast.Call) and item.annotation.func.id == "address":
        if item.annotation.args[0].id not in premade_contracts:
            raise VariableDeclarationException(
                "Unsupported premade contract declaration",
                item.annotation.args[0])
        premade_contract = premade_contracts[item.annotation.args[0].id]
        _contracts[item.target.id] = add_contract(premade_contract.body)
        _globals[item.target.id] = VariableRecord(item.target.id,
                                                  len(_globals),
                                                  BaseType('address'), True)
    elif item_name in _contracts:
        if not item_attributes["modifiable"] and not item_attributes["static"]:
            raise StructureException(
                "All contracts must have `modifiable` or `static` keywords: %s"
                % item_attributes)
        _globals[item.target.id] = ContractRecord(
            item_attributes["modifiable"], item.target.id, len(_globals),
            BaseType('address', item_name), True)
        if item_attributes["public"]:
            typ = BaseType('address', item_name)
            for getter in mk_getter(item.target.id, typ):
                _getters.append(parse_line('\n' * (item.lineno - 1) + getter))
                _getters[-1].pos = getpos(item)
    elif isinstance(item.annotation,
                    ast.Call) and item.annotation.func.id == "public":
        if isinstance(item.annotation.args[0],
                      ast.Name) and item_name in _contracts:
            typ = BaseType('address', item_name)
        else:
            typ = parse_type(item.annotation.args[0], 'storage')
        _globals[item.target.id] = VariableRecord(item.target.id,
                                                  len(_globals), typ, True)
        # Adding getters here
        for getter in mk_getter(item.target.id, typ):
            _getters.append(parse_line('\n' * (item.lineno - 1) + getter))
            _getters[-1].pos = getpos(item)
    else:
        _globals[item.target.id] = VariableRecord(
            item.target.id, len(_globals),
            parse_type(item.annotation, 'storage', custom_units=_custom_units),
            True)
    return _custom_units, _contracts, _events, _globals, _getters
Beispiel #11
0
def pack_args_by_32(holder,
                    maxlen,
                    arg,
                    typ,
                    context,
                    placeholder,
                    *,
                    pos,
                    dynamic_offset_counter=None,
                    datamem_start=None):
    """
    Copy necessary variables to pre-allocated memory section.

    :param holder: Complete holder for all args
    :param maxlen: Total length in bytes of the full arg section (static + dynamic).
    :param arg: Current arg to pack
    :param context: Context of arg
    :param placeholder: Static placeholder for static argument part.
    :param dynamic_offset_counter: position counter stored in static args.
    :param dynamic_placeholder: pointer to current position in memory to write dynamic values to.
    :param datamem_start: position where the whole datemem section starts.
    """

    if isinstance(typ, BaseType):
        value = parse_expr(arg, context)
        value = base_type_conversion(value, value.typ, typ, pos)
        holder.append(
            LLLnode.from_list(['mstore', placeholder, value],
                              typ=typ,
                              location='memory'))
    elif isinstance(typ, ByteArrayType):
        bytez = b''

        source_expr = Expr(arg, context)
        if isinstance(arg, ast.Str):
            if len(arg.s) > typ.maxlen:
                raise TypeMismatchException(
                    "Data input bytes are to big: %r %r" % (len(arg.s), typ),
                    pos)
            for c in arg.s:
                if ord(c) >= 256:
                    raise InvalidLiteralException(
                        "Cannot insert special character %r into byte array" %
                        c, pos)
                bytez += bytes([ord(c)])

            holder.append(source_expr.lll_node)

        # Set static offset, in arg slot.
        holder.append(
            LLLnode.from_list(
                ['mstore', placeholder, ['mload', dynamic_offset_counter]]))
        # Get the biginning to write the ByteArray to.
        dest_placeholder = LLLnode.from_list(
            ['add', datamem_start, ['mload', dynamic_offset_counter]],
            typ=typ,
            location='memory',
            annotation="pack_args_by_32:dest_placeholder")
        copier = make_byte_array_copier(dest_placeholder, source_expr.lll_node)
        holder.append(copier)
        # Increment offset counter.
        increment_counter = LLLnode.from_list([
            'mstore', dynamic_offset_counter,
            [
                'add',
                [
                    'add', ['mload', dynamic_offset_counter],
                    ['ceil32', ['mload', dest_placeholder]]
                ], 32
            ]
        ])
        holder.append(increment_counter)
    elif isinstance(typ, ListType):
        maxlen += (typ.count - 1) * 32
        typ = typ.subtype

        def check_list_type_match(provided):  # Check list types match.
            if provided != typ:
                raise TypeMismatchException(
                    "Log list type '%s' does not match provided, expected '%s'"
                    % (provided, typ))

        # List from storage
        if isinstance(arg, ast.Attribute) and arg.value.id == 'self':
            stor_list = context.globals[arg.attr]
            check_list_type_match(stor_list.typ.subtype)
            size = stor_list.typ.count
            for offset in range(0, size):
                arg2 = LLLnode.from_list([
                    'sload',
                    ['add', ['sha3_32', Expr(arg, context).lll_node], offset]
                ],
                                         typ=typ)
                p_holder = context.new_placeholder(
                    BaseType(32)) if offset > 0 else placeholder
                holder, maxlen = pack_args_by_32(holder,
                                                 maxlen,
                                                 arg2,
                                                 typ,
                                                 context,
                                                 p_holder,
                                                 pos=pos)
        # List from variable.
        elif isinstance(arg, ast.Name):
            size = context.vars[arg.id].size
            pos = context.vars[arg.id].pos
            check_list_type_match(context.vars[arg.id].typ.subtype)
            for i in range(0, size):
                offset = 32 * i
                arg2 = LLLnode.from_list(pos + offset,
                                         typ=typ,
                                         location='memory')
                p_holder = context.new_placeholder(
                    BaseType(32)) if i > 0 else placeholder
                holder, maxlen = pack_args_by_32(holder,
                                                 maxlen,
                                                 arg2,
                                                 typ,
                                                 context,
                                                 p_holder,
                                                 pos=pos)
        # is list literal.
        else:
            holder, maxlen = pack_args_by_32(holder,
                                             maxlen,
                                             arg.elts[0],
                                             typ,
                                             context,
                                             placeholder,
                                             pos=pos)
            for j, arg2 in enumerate(arg.elts[1:]):
                holder, maxlen = pack_args_by_32(holder,
                                                 maxlen,
                                                 arg2,
                                                 typ,
                                                 context,
                                                 context.new_placeholder(
                                                     BaseType(32)),
                                                 pos=pos)

    return holder, maxlen
Beispiel #12
0
 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
Beispiel #13
0
    def build_in_comparator(self):
        left = Expr(self.expr.left, self.context).lll_node
        right = Expr(self.expr.right, self.context).lll_node

        result_placeholder = self.context.new_internal_variable(BaseType("bool"))
        setter = []

        # Load nth item from list in memory.
        if right.value == "multi":
            # Copy literal to memory to be compared.
            tmp_list = LLLnode.from_list(
                obj=self.context.new_internal_variable(
                    ListType(right.typ.subtype, right.typ.count)
                ),
                typ=ListType(right.typ.subtype, right.typ.count),
                location="memory",
            )
            setter = make_setter(tmp_list, right, "memory", pos=getpos(self.expr))
            load_i_from_list = [
                "mload",
                ["add", tmp_list, ["mul", 32, ["mload", MemoryPositions.FREE_LOOP_INDEX]]],
            ]
        elif right.location == "storage":
            load_i_from_list = [
                "sload",
                ["add", ["sha3_32", right], ["mload", MemoryPositions.FREE_LOOP_INDEX]],
            ]
        else:
            load_operation = "mload" if right.location == "memory" else "calldataload"
            load_i_from_list = [
                load_operation,
                ["add", right, ["mul", 32, ["mload", MemoryPositions.FREE_LOOP_INDEX]]],
            ]

        # Condition repeat loop has to break on.
        break_loop_condition = [
            "if",
            ["eq", unwrap_location(left), load_i_from_list],
            ["seq", ["mstore", "_result", 1], "break"],  # store true.
        ]

        # Repeat loop to loop-compare each item in the list.
        for_loop_sequence = [
            ["mstore", result_placeholder, 0],
            [
                "with",
                "_result",
                result_placeholder,
                [
                    "repeat",
                    MemoryPositions.FREE_LOOP_INDEX,
                    0,
                    right.typ.count,
                    break_loop_condition,
                ],
            ],
            ["mload", result_placeholder],
        ]

        # Save list to memory, so one can iterate over it,
        # used when literal was created with tmp_list.
        if setter:
            compare_sequence = ["seq", setter] + for_loop_sequence
        else:
            compare_sequence = ["seq"] + for_loop_sequence

        if isinstance(self.expr.op, vy_ast.NotIn):
            # for `not in`, invert the result
            compare_sequence = ["iszero", compare_sequence]

        return LLLnode.from_list(compare_sequence, typ="bool", annotation="in comparator")
Beispiel #14
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

        arithmetic_pair = {left.typ.typ, right.typ.typ}
        pos = getpos(self.expr)

        # Special case with uint256 were int literal may be casted.
        if arithmetic_pair == {"uint256", "int128"}:
            # Check right side literal.
            if right.typ.is_literal and SizeLimits.in_bounds("uint256", right.value):
                right = LLLnode.from_list(
                    right.value, typ=BaseType("uint256", None, is_literal=True), pos=pos,
                )

            # Check left side literal.
            elif left.typ.is_literal and SizeLimits.in_bounds("uint256", left.value):
                left = LLLnode.from_list(
                    left.value, typ=BaseType("uint256", None, is_literal=True), pos=pos,
                )

        if left.typ.typ == "decimal" and isinstance(self.expr.op, vy_ast.Pow):
            return

        # Only allow explicit conversions to occur.
        if left.typ.typ != right.typ.typ:
            return

        ltyp, rtyp = left.typ.typ, right.typ.typ
        arith = None
        if isinstance(self.expr.op, (vy_ast.Add, vy_ast.Sub)):
            new_typ = BaseType(ltyp)
            op = "add" if isinstance(self.expr.op, vy_ast.Add) else "sub"

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

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

            elif ltyp == rtyp:
                arith = [op, "l", "r"]

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

            elif ltyp == rtyp == "int128":
                # TODO should this be 'smul' (note edge cases in YP for smul)
                arith = ["mul", "l", "r"]

            elif ltyp == rtyp == "decimal":
                # TODO should this be smul
                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 == rtyp == "uint256":
                arith = ["div", "l", divisor]

            elif ltyp == rtyp == "int128":
                arith = ["sdiv", "l", divisor]

            elif ltyp == rtyp == "decimal":
                arith = [
                    "sdiv",
                    # TODO check overflow cases, also should it be smul
                    ["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 == rtyp == "uint256":
                arith = ["mod", "l", divisor]
            elif ltyp == rtyp:
                # TODO should this be regular mod
                arith = ["smod", "l", divisor]

        elif isinstance(self.expr.op, vy_ast.Pow):
            if ltyp != "int128" and ltyp != "uint256" and isinstance(self.expr.right, vy_ast.Name):
                return
            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
            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 == "uint256":
            p.append(arith)
        else:
            return

        p = ["with", "l", left, ["with", "r", right, p]]
        return LLLnode.from_list(p, typ=new_typ, pos=pos)
Beispiel #15
0
def add_variable_offset(parent, key, pos):
    typ, location = parent.typ, parent.location
    if isinstance(typ, (StructType, TupleType)):
        if isinstance(typ, StructType):
            if not isinstance(key, str):
                raise TypeMismatchException(
                    "Expecting a member variable access; cannot access element %r" % key, pos
                )
            if key not in typ.members:
                raise TypeMismatchException("Object does not have member variable %s" % key, pos)
            subtype = typ.members[key]
            attrs = list(typ.members.keys())

            if key not in attrs:
                raise TypeMismatchException(
                    "Member %s not found. Only the following available: %s" % (
                        key,
                        " ".join(attrs)
                    ),
                    pos
                )
            index = attrs.index(key)
            annotation = key
        else:
            if not isinstance(key, int):
                raise TypeMismatchException(
                    "Expecting a static index; cannot access element %r" % key, pos
                )
            attrs = list(range(len(typ.members)))
            index = key
            annotation = None
        if location == 'storage':
            return LLLnode.from_list(
                ['add', ['sha3_32', parent], LLLnode.from_list(index, annotation=annotation)],
                typ=subtype,
                location='storage',
            )
        elif location == 'storage_prehashed':
            return LLLnode.from_list(
                ['add', parent, LLLnode.from_list(index, annotation=annotation)],
                typ=subtype,
                location='storage',
            )
        elif location == 'memory':
            offset = 0
            for i in range(index):
                offset += 32 * get_size_of_type(typ.members[attrs[i]])
            return LLLnode.from_list(['add', offset, parent],
                                     typ=typ.members[key],
                                     location='memory',
                                     annotation=annotation)
        else:
            raise TypeMismatchException("Not expecting a member variable access", pos)

    elif isinstance(typ, MappingType):

        if isinstance(key.typ, ByteArrayLike):
            if not isinstance(typ.keytype, ByteArrayLike) or (typ.keytype.maxlen < key.typ.maxlen):
                raise TypeMismatchException(
                    'Mapping keys of bytes cannot be cast, use exact same bytes type of: %s' % (
                        str(typ.keytype),
                    ),
                    pos,
                )
            subtype = typ.valuetype
            if len(key.args[0].args) >= 3:  # handle bytes literal.
                sub = LLLnode.from_list([
                    'seq',
                    key,
                    ['sha3', ['add', key.args[0].args[-1], 32], ['mload', key.args[0].args[-1]]]
                ])
            else:
                sub = LLLnode.from_list(
                    ['sha3', ['add', key.args[0].value, 32], ['mload', key.args[0].value]]
                )
        else:
            subtype = typ.valuetype
            sub = base_type_conversion(key, key.typ, typ.keytype, pos=pos)

        if location == 'storage':
            return LLLnode.from_list(['sha3_64', parent, sub],
                                     typ=subtype,
                                     location='storage')
        elif location == 'memory':
            raise TypeMismatchException(
                "Can only have fixed-side arrays in memory, not mappings", pos
            )

    elif isinstance(typ, ListType):

        subtype = typ.subtype
        sub = [
            'uclamplt', base_type_conversion(key, key.typ, BaseType('int128'), pos=pos), typ.count
        ]

        if location == 'storage':
            return LLLnode.from_list(['add', ['sha3_32', parent], sub],
                                     typ=subtype,
                                     location='storage')
        elif location == 'storage_prehashed':
            return LLLnode.from_list(['add', parent, sub],
                                     typ=subtype,
                                     location='storage')
        elif location == 'memory':
            offset = 32 * get_size_of_type(subtype)
            return LLLnode.from_list(
                ['add', ['mul', offset, sub], parent],
                typ=subtype,
                location='memory',
            )
        else:
            raise TypeMismatchException("Not expecting an array access ", pos)
    else:
        raise TypeMismatchException("Cannot access the child of a constant variable! %r" % typ, pos)
Beispiel #16
0
def to_int128(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("int128", in_arg):
                raise InvalidLiteral(f"Number out of range: {in_arg}")
            return LLLnode.from_list(in_arg,
                                     typ=BaseType("int128"),
                                     pos=getpos(expr))
        elif isinstance(in_arg, Decimal):
            if not SizeLimits.in_bounds("int128", 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("int128"),
                                     pos=getpos(expr))
        else:
            raise InvalidLiteral(f"Unknown numeric literal type: {in_arg}")

    elif input_type == "bytes32":
        if in_arg.typ.is_literal:
            if not SizeLimits.in_bounds("int128", in_arg.value):
                raise InvalidLiteral(f"Number out of range: {in_arg.value}",
                                     expr)
            else:
                return LLLnode.from_list(in_arg,
                                         typ=BaseType("int128"),
                                         pos=getpos(expr))
        else:
            return LLLnode.from_list(
                [
                    "clamp",
                    ["mload", MemoryPositions.MINNUM],
                    in_arg,
                    ["mload", MemoryPositions.MAXNUM],
                ],
                typ=BaseType("int128"),
                pos=getpos(expr),
            )

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

    elif input_type in ("string", "bytes"):
        if in_arg.typ.maxlen > 32:
            raise TypeMismatch(
                f"Cannot convert bytes array of max length {in_arg.typ.maxlen} to int128",
                expr,
            )
        return byte_array_to_num(in_arg, expr, "int128")

    elif input_type == "uint256":
        if in_arg.typ.is_literal:
            if not SizeLimits.in_bounds("int128", in_arg.value):
                raise InvalidLiteral(f"Number out of range: {in_arg.value}",
                                     expr)
            else:
                return LLLnode.from_list(in_arg,
                                         typ=BaseType("int128"),
                                         pos=getpos(expr))

        else:
            return LLLnode.from_list(
                ["uclample", in_arg, ["mload", MemoryPositions.MAXNUM]],
                typ=BaseType("int128"),
                pos=getpos(expr),
            )

    elif input_type == "decimal":
        return LLLnode.from_list(
            [
                "clamp",
                ["mload", MemoryPositions.MINNUM],
                ["sdiv", in_arg, DECIMAL_DIVISOR],
                ["mload", MemoryPositions.MAXNUM],
            ],
            typ=BaseType("int128"),
            pos=getpos(expr),
        )

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

    else:
        raise InvalidLiteral(f"Invalid input for int128: {in_arg}", expr)
Beispiel #17
0
    def add_globals_and_events(self, item):
        item_attributes = {"public": False}

        # Handle constants.
        if isinstance(item.annotation,
                      ast.Call) and item.annotation.func.id == "constant":
            self._constants.add_constant(item, global_ctx=self)
            return

        # Handle events.
        if not (isinstance(item.annotation, ast.Call)
                and item.annotation.func.id == "event"):
            item_name, item_attributes = self.get_item_name_and_attributes(
                item, item_attributes)
            if not all([
                    attr in valid_global_keywords
                    for attr in item_attributes.keys()
            ]):
                raise StructureException(
                    'Invalid global keyword used: %s' % item_attributes, item)

        if item.value is not None:
            raise StructureException(
                'May not assign value whilst defining type', item)
        elif isinstance(item.annotation,
                        ast.Call) and item.annotation.func.id == "event":
            if self._globals or len(self._defs):
                raise EventDeclarationException(
                    "Events must all come before global declarations and function definitions",
                    item)
            self._events.append(item)
        elif not isinstance(item.target, ast.Name):
            raise StructureException(
                "Can only assign type to variable in top-level statement",
                item)

        # Is this a custom unit definition.
        elif item.target.id == 'units':
            if not self._custom_units:
                if not isinstance(item.annotation, ast.Dict):
                    raise VariableDeclarationException(
                        "Define custom units using units: { }.", item.target)
                for key, value in zip(item.annotation.keys,
                                      item.annotation.values):
                    if not isinstance(value, ast.Str):
                        raise VariableDeclarationException(
                            "Custom unit description must be a valid string",
                            value)
                    if not isinstance(key, ast.Name):
                        raise VariableDeclarationException(
                            "Custom unit name must be a valid string", key)
                    check_valid_varname(key.id, self._custom_units,
                                        self._structs, self._constants, key,
                                        "Custom unit invalid.")
                    self._custom_units.add(key.id)
                    self._custom_units_descriptions[key.id] = value.s
            else:
                raise VariableDeclarationException(
                    "Custom units can only be defined once", item.target)

        # Check if variable name is valid.
        # Don't move this check higher, as unit parsing has to happen first.
        elif not self.is_valid_varname(item.target.id, item):
            pass

        elif len(self._defs):
            raise StructureException(
                "Global variables must all come before function definitions",
                item)
        # If the type declaration is of the form public(<type here>), then proceed with
        # the underlying type but also add getters
        elif isinstance(item.annotation,
                        ast.Call) and item.annotation.func.id == "address":
            if item.annotation.args[0].id not in premade_contracts:
                raise VariableDeclarationException(
                    "Unsupported premade contract declaration",
                    item.annotation.args[0])
            premade_contract = premade_contracts[item.annotation.args[0].id]
            self._contracts[item.target.id] = self.make_contract(
                premade_contract.body)
            self._globals[item.target.id] = VariableRecord(
                item.target.id, len(self._globals), BaseType('address'), True)

        elif item_name in self._contracts:
            self._globals[item.target.id] = ContractRecord(
                item.target.id, len(self._globals), ContractType(item_name),
                True)
            if item_attributes["public"]:
                typ = ContractType(item_name)
                for getter in self.mk_getter(item.target.id, typ):
                    self._getters.append(
                        self.parse_line('\n' * (item.lineno - 1) + getter))
                    self._getters[-1].pos = getpos(item)

        elif isinstance(item.annotation,
                        ast.Call) and item.annotation.func.id == "public":
            if isinstance(item.annotation.args[0],
                          ast.Name) and item_name in self._contracts:
                typ = ContractType(item_name)
            else:
                typ = parse_type(item.annotation.args[0],
                                 'storage',
                                 custom_units=self._custom_units,
                                 custom_structs=self._structs,
                                 constants=self._constants)
            self._globals[item.target.id] = VariableRecord(
                item.target.id, len(self._globals), typ, True)
            # Adding getters here
            for getter in self.mk_getter(item.target.id, typ):
                self._getters.append(
                    self.parse_line('\n' * (item.lineno - 1) + getter))
                self._getters[-1].pos = getpos(item)

        else:
            self._globals[item.target.id] = VariableRecord(
                item.target.id, len(self._globals),
                parse_type(item.annotation,
                           'storage',
                           custom_units=self._custom_units,
                           custom_structs=self._structs,
                           constants=self._constants), True)
Beispiel #18
0
    def parse_for(self):
        # Type 0 for, e.g. for i in list(): ...
        if self._is_list_iter():
            return self.parse_for_list()

        if not isinstance(self.stmt.iter, ast.Call):
            if isinstance(self.stmt.iter, ast.Subscript):
                raise StructureException("Cannot iterate over a nested list",
                                         self.stmt.iter)
            raise StructureException(
                f"Cannot iterate over '{type(self.stmt.iter).__name__}' object",
                self.stmt.iter)
        if getattr(self.stmt.iter.func, 'id', None) != "range":
            raise StructureException(
                "Non-literals cannot be used as loop range",
                self.stmt.iter.func)
        if len(self.stmt.iter.args) not in {1, 2}:
            raise StructureException(
                f"Range expects between 1 and 2 arguments, got {len(self.stmt.iter.args)}",
                self.stmt.iter.func)

        block_scope_id = id(self.stmt)
        with self.context.make_blockscope(block_scope_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='int128',
                                          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='int128',
                                          pos=getpos(self.stmt))
                rounds = LLLnode.from_list(arg1_val - arg0_val,
                                           typ='int128',
                                           pos=getpos(self.stmt))

            # Type 3 for, e.g. for i in range(x, x + 10): ...
            else:
                arg1 = self.stmt.iter.args[1]
                if not isinstance(arg1, ast.BinOp) or not isinstance(
                        arg1.op, ast.Add):
                    raise StructureException(
                        ("Two-arg for statements must be of the form `for i "
                         "in range(start, start + rounds): ...`"),
                        arg1,
                    )

                if arg0 != arg1.left:
                    raise StructureException(
                        ("Two-arg for statements of the form `for i in "
                         "range(x, x + y): ...` must have x identical in both "
                         f"places: {ast_to_dict(arg0)} {ast_to_dict(arg1.left)}"
                         ),
                        self.stmt.iter,
                    )

                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:
                raise StructureException(
                    f"For loop has invalid number of iterations ({r}),"
                    " the value must be greater than zero", self.stmt.iter)

            varname = self.stmt.target.id
            pos = self.context.new_variable(varname,
                                            BaseType('int128'),
                                            pos=getpos(self.stmt))
            self.context.forvars[varname] = True
            o = LLLnode.from_list(
                [
                    'repeat', pos, start, rounds,
                    parse_body(self.stmt.body, self.context)
                ],
                typ=None,
                pos=getpos(self.stmt),
            )
            del self.context.vars[varname]
            del self.context.forvars[varname]

        return o
Beispiel #19
0
    def parse_for_list(self):
        iter_list_node = Expr(self.stmt.iter, self.context).lll_node
        if not isinstance(iter_list_node.typ.subtype,
                          BaseType):  # Sanity check on list subtype.
            raise StructureException(
                'For loops allowed only on basetype lists.', self.stmt.iter)
        iter_var_type = (self.context.vars.get(self.stmt.iter.id).typ
                         if isinstance(self.stmt.iter, ast.Name) else None)
        subtype = iter_list_node.typ.subtype.typ
        varname = self.stmt.target.id
        value_pos = self.context.new_variable(
            varname,
            BaseType(subtype, unit=iter_list_node.typ.subtype.unit),
        )
        i_pos = self.context.new_variable('_index_for_' + varname,
                                          BaseType(subtype))
        self.context.forvars[varname] = True

        # Is a list that is already allocated to memory.
        if iter_var_type:

            list_name = self.stmt.iter.id
            # make sure list cannot be altered whilst iterating.
            with self.context.in_for_loop_scope(list_name):
                iter_var = self.context.vars.get(self.stmt.iter.id)
                body = [
                    'seq',
                    [
                        'mstore',
                        value_pos,
                        [
                            'mload',
                            [
                                'add', iter_var.pos,
                                ['mul', ['mload', i_pos], 32]
                            ]
                        ],
                    ],
                    parse_body(self.stmt.body, self.context)
                ]
                o = LLLnode.from_list(
                    ['repeat', i_pos, 0, iter_var.size, body],
                    typ=None,
                    pos=getpos(self.stmt))

        # List gets defined in the for statement.
        elif isinstance(self.stmt.iter, ast.List):
            # Allocate list to memory.
            count = iter_list_node.typ.count
            tmp_list = LLLnode.from_list(obj=self.context.new_placeholder(
                ListType(iter_list_node.typ.subtype, count)),
                                         typ=ListType(
                                             iter_list_node.typ.subtype,
                                             count),
                                         location='memory')
            setter = make_setter(tmp_list,
                                 iter_list_node,
                                 'memory',
                                 pos=getpos(self.stmt))
            body = [
                'seq',
                [
                    'mstore', value_pos,
                    [
                        'mload',
                        ['add', tmp_list, ['mul', ['mload', i_pos], 32]]
                    ]
                ],
                parse_body(self.stmt.body, self.context)
            ]
            o = LLLnode.from_list(
                ['seq', setter, ['repeat', i_pos, 0, count, body]],
                typ=None,
                pos=getpos(self.stmt))

        # List contained in storage.
        elif isinstance(self.stmt.iter, ast.Attribute):
            count = iter_list_node.typ.count
            list_name = iter_list_node.annotation

            # make sure list cannot be altered whilst iterating.
            with self.context.in_for_loop_scope(list_name):
                body = [
                    'seq',
                    [
                        'mstore', value_pos,
                        [
                            'sload',
                            [
                                'add', ['sha3_32', iter_list_node],
                                ['mload', i_pos]
                            ]
                        ]
                    ],
                    parse_body(self.stmt.body, self.context),
                ]
                o = LLLnode.from_list(
                    ['seq', ['repeat', i_pos, 0, count, body]],
                    typ=None,
                    pos=getpos(self.stmt))

        del self.context.vars[varname]
        del self.context.vars['_index_for_' + varname]
        del self.context.forvars[varname]
        return o
Beispiel #20
0
    def parse_for_list(self):
        with self.context.range_scope():
            iter_list_node = Expr(self.stmt.iter, self.context).lll_node
        if not isinstance(iter_list_node.typ.subtype,
                          BaseType):  # Sanity check on list subtype.
            raise StructureException(
                'For loops allowed only on basetype lists.', self.stmt.iter)
        iter_var_type = (self.context.vars.get(self.stmt.iter.id).typ
                         if isinstance(self.stmt.iter, ast.Name) else None)
        subtype = iter_list_node.typ.subtype.typ
        varname = self.stmt.target.id
        value_pos = self.context.new_variable(
            varname,
            BaseType(subtype, unit=iter_list_node.typ.subtype.unit),
        )
        i_pos_raw_name = '_index_for_' + varname
        i_pos = self.context.new_internal_variable(
            i_pos_raw_name,
            BaseType(subtype),
        )
        self.context.forvars[varname] = True

        # Is a list that is already allocated to memory.
        if iter_var_type:

            list_name = self.stmt.iter.id
            # make sure list cannot be altered whilst iterating.
            with self.context.in_for_loop_scope(list_name):
                iter_var = self.context.vars.get(self.stmt.iter.id)
                if iter_var.location == 'calldata':
                    fetcher = 'calldataload'
                elif iter_var.location == 'memory':
                    fetcher = 'mload'
                else:
                    raise CompilerPanic(
                        f'List iteration only supported on in-memory types {self.expr}',
                    )
                body = [
                    'seq',
                    [
                        'mstore',
                        value_pos,
                        [
                            fetcher,
                            [
                                'add', iter_var.pos,
                                ['mul', ['mload', i_pos], 32]
                            ]
                        ],
                    ],
                    parse_body(self.stmt.body, self.context)
                ]
                o = LLLnode.from_list(
                    ['repeat', i_pos, 0, iter_var.size, body],
                    typ=None,
                    pos=getpos(self.stmt))

        # List gets defined in the for statement.
        elif isinstance(self.stmt.iter, ast.List):
            # Allocate list to memory.
            count = iter_list_node.typ.count
            tmp_list = LLLnode.from_list(obj=self.context.new_placeholder(
                ListType(iter_list_node.typ.subtype, count)),
                                         typ=ListType(
                                             iter_list_node.typ.subtype,
                                             count),
                                         location='memory')
            setter = make_setter(tmp_list,
                                 iter_list_node,
                                 'memory',
                                 pos=getpos(self.stmt))
            body = [
                'seq',
                [
                    'mstore', value_pos,
                    [
                        'mload',
                        ['add', tmp_list, ['mul', ['mload', i_pos], 32]]
                    ]
                ],
                parse_body(self.stmt.body, self.context)
            ]
            o = LLLnode.from_list(
                ['seq', setter, ['repeat', i_pos, 0, count, body]],
                typ=None,
                pos=getpos(self.stmt))

        # List contained in storage.
        elif isinstance(self.stmt.iter, ast.Attribute):
            count = iter_list_node.typ.count
            list_name = iter_list_node.annotation

            # make sure list cannot be altered whilst iterating.
            with self.context.in_for_loop_scope(list_name):
                body = [
                    'seq',
                    [
                        'mstore', value_pos,
                        [
                            'sload',
                            [
                                'add', ['sha3_32', iter_list_node],
                                ['mload', i_pos]
                            ]
                        ]
                    ],
                    parse_body(self.stmt.body, self.context),
                ]
                o = LLLnode.from_list(
                    ['seq', ['repeat', i_pos, 0, count, body]],
                    typ=None,
                    pos=getpos(self.stmt))

        del self.context.vars[varname]
        # this kind of open access to the vars dict should be disallowed.
        # we should use member functions to provide an API for these kinds
        # of operations.
        del self.context.vars[self.context._mangle(i_pos_raw_name)]
        del self.context.forvars[varname]
        return o
Beispiel #21
0
        if args[0].value <= 0:
            raise InvalidLiteralException("Negative wei value not allowed",
                                          expr)
        sub = ['mul', args[0].value, denomination]
    elif args[0].typ.typ == 'uint256':
        sub = ['mul', args[0], denomination]
    else:
        sub = ['div', ['mul', args[0], denomination], DECIMAL_DIVISOR]

    return LLLnode.from_list(sub,
                             typ=BaseType('uint256', {'wei': 1}),
                             location=None,
                             pos=getpos(expr))


zero_value = LLLnode.from_list(0, typ=BaseType('uint256', {'wei': 1}))
false_value = LLLnode.from_list(0, typ=BaseType('bool', is_literal=True))


@signature('address',
           'bytes',
           outsize='num_literal',
           gas='uint256',
           value=Optional('uint256', zero_value),
           delegate_call=Optional('bool', false_value))
def raw_call(expr, args, kwargs, context):
    to, data = args
    gas, value, outsize, delegate_call = kwargs['gas'], kwargs[
        'value'], kwargs['outsize'], kwargs['delegate_call']
    if delegate_call.typ.is_literal is False:
        raise TypeMismatchException(
Beispiel #22
0
    def parse_return(self):
        if self.context.return_type is None:
            if self.stmt.value:
                raise TypeMismatchException("Not expecting to return a value",
                                            self.stmt)
            return LLLnode.from_list(
                make_return_stmt(self.stmt, self.context, 0, 0),
                typ=None,
                pos=getpos(self.stmt),
                valency=0,
            )
        if not self.stmt.value:
            raise TypeMismatchException("Expecting to return a value",
                                        self.stmt)

        sub = Expr(self.stmt.value, self.context).lll_node

        # Returning a value (most common case)
        if isinstance(sub.typ, BaseType):
            sub = unwrap_location(sub)

            if not isinstance(self.context.return_type, BaseType):
                raise TypeMismatchException(
                    f"Return type units mismatch {sub.typ} {self.context.return_type}",
                    self.stmt.value)
            elif self.context.return_type != sub.typ and not sub.typ.is_literal:
                raise TypeMismatchException(
                    f"Trying to return base type {sub.typ}, output expecting "
                    f"{self.context.return_type}",
                    self.stmt.value,
                )
            elif sub.typ.is_literal and (
                    self.context.return_type.typ == sub.typ
                    or 'int' in self.context.return_type.typ
                    and 'int' in sub.typ.typ):  # noqa: E501
                if not SizeLimits.in_bounds(self.context.return_type.typ,
                                            sub.value):
                    raise InvalidLiteralException(
                        "Number out of range: " + str(sub.value), self.stmt)
                else:
                    return LLLnode.from_list(
                        [
                            'seq', ['mstore', 0, sub],
                            make_return_stmt(self.stmt, self.context, 0, 32)
                        ],
                        typ=None,
                        pos=getpos(self.stmt),
                        valency=0,
                    )
            elif is_base_type(sub.typ, self.context.return_type.typ) or (
                    is_base_type(sub.typ, 'int128') and is_base_type(
                        self.context.return_type, 'int256')):  # noqa: E501
                return LLLnode.from_list(
                    [
                        'seq', ['mstore', 0, sub],
                        make_return_stmt(self.stmt, self.context, 0, 32)
                    ],
                    typ=None,
                    pos=getpos(self.stmt),
                    valency=0,
                )
            else:
                raise TypeMismatchException(
                    f"Unsupported type conversion: {sub.typ} to {self.context.return_type}",
                    self.stmt.value,
                )
        # Returning a byte array
        elif isinstance(sub.typ, ByteArrayLike):
            if not sub.typ.eq_base(self.context.return_type):
                raise TypeMismatchException(
                    f"Trying to return base type {sub.typ}, output expecting "
                    f"{self.context.return_type}",
                    self.stmt.value,
                )
            if sub.typ.maxlen > self.context.return_type.maxlen:
                raise TypeMismatchException(
                    f"Cannot cast from greater max-length {sub.typ.maxlen} to shorter "
                    f"max-length {self.context.return_type.maxlen}",
                    self.stmt.value,
                )

            # loop memory has to be allocated first.
            loop_memory_position = self.context.new_placeholder(
                typ=BaseType('uint256'))
            # len & bytez placeholder have to be declared after each other at all times.
            len_placeholder = self.context.new_placeholder(
                typ=BaseType('uint256'))
            bytez_placeholder = self.context.new_placeholder(typ=sub.typ)

            if sub.location in ('storage', 'memory'):
                return LLLnode.from_list([
                    'seq',
                    make_byte_array_copier(LLLnode(
                        bytez_placeholder, location='memory', typ=sub.typ),
                                           sub,
                                           pos=getpos(self.stmt)),
                    zero_pad(bytez_placeholder),
                    ['mstore', len_placeholder, 32],
                    make_return_stmt(
                        self.stmt,
                        self.context,
                        len_placeholder,
                        ['ceil32', ['add', ['mload', bytez_placeholder], 64]],
                        loop_memory_position=loop_memory_position,
                    )
                ],
                                         typ=None,
                                         pos=getpos(self.stmt),
                                         valency=0)
            else:
                raise Exception(f"Invalid location: {sub.location}")

        elif isinstance(sub.typ, ListType):
            loop_memory_position = self.context.new_placeholder(
                typ=BaseType('uint256'))
            if sub.typ != self.context.return_type:
                raise TypeMismatchException(
                    f"List return type {sub.typ} does not match specified "
                    f"return type, expecting {self.context.return_type}",
                    self.stmt)
            elif sub.location == "memory" and sub.value != "multi":
                return LLLnode.from_list(
                    make_return_stmt(
                        self.stmt,
                        self.context,
                        sub,
                        get_size_of_type(self.context.return_type) * 32,
                        loop_memory_position=loop_memory_position,
                    ),
                    typ=None,
                    pos=getpos(self.stmt),
                    valency=0,
                )
            else:
                new_sub = LLLnode.from_list(
                    self.context.new_placeholder(self.context.return_type),
                    typ=self.context.return_type,
                    location='memory',
                )
                setter = make_setter(new_sub,
                                     sub,
                                     'memory',
                                     pos=getpos(self.stmt))
                return LLLnode.from_list([
                    'seq', setter,
                    make_return_stmt(
                        self.stmt,
                        self.context,
                        new_sub,
                        get_size_of_type(self.context.return_type) * 32,
                        loop_memory_position=loop_memory_position,
                    )
                ],
                                         typ=None,
                                         pos=getpos(self.stmt))

        # Returning a struct
        elif isinstance(sub.typ, StructType):
            retty = self.context.return_type
            if not isinstance(retty, StructType) or retty.name != sub.typ.name:
                raise TypeMismatchException(
                    f"Trying to return {sub.typ}, output expecting {self.context.return_type}",
                    self.stmt.value,
                )
            return gen_tuple_return(self.stmt, self.context, sub)

        # Returning a tuple.
        elif isinstance(sub.typ, TupleType):
            if not isinstance(self.context.return_type, TupleType):
                raise TypeMismatchException(
                    f"Trying to return tuple type {sub.typ}, output expecting "
                    f"{self.context.return_type}",
                    self.stmt.value,
                )

            if len(self.context.return_type.members) != len(sub.typ.members):
                raise StructureException("Tuple lengths don't match!",
                                         self.stmt)

            # check return type matches, sub type.
            for i, ret_x in enumerate(self.context.return_type.members):
                s_member = sub.typ.members[i]
                sub_type = s_member if isinstance(s_member,
                                                  NodeType) else s_member.typ
                if type(sub_type) is not type(ret_x):
                    raise StructureException(
                        "Tuple return type does not match annotated return. "
                        f"{type(sub_type)} != {type(ret_x)}", self.stmt)
            return gen_tuple_return(self.stmt, self.context, sub)

        else:
            raise TypeMismatchException(f"Can't return type {sub.typ}",
                                        self.stmt)
Beispiel #23
0
def extract32(expr, args, kwargs, context):
    sub, index = args
    ret_type = kwargs['type']
    # Get length and specific element
    if sub.location == "memory":
        lengetter = LLLnode.from_list(['mload', '_sub'],
                                      typ=BaseType('int128'))
        elementgetter = lambda index: LLLnode.from_list(
            ['mload', ['add', '_sub', ['add', 32, ['mul', 32, index]]]],
            typ=BaseType('int128'))
    elif sub.location == "storage":
        lengetter = LLLnode.from_list(['sload', ['sha3_32', '_sub']],
                                      typ=BaseType('int128'))
        elementgetter = lambda index: LLLnode.from_list(
            ['sload', ['add', ['sha3_32', '_sub'], ['add', 1, index]]],
            typ=BaseType('int128'))
    # Special case: index known to be a multiple of 32
    if isinstance(index.value, int) and not index.value % 32:
        o = LLLnode.from_list([
            'with', '_sub', sub,
            elementgetter(
                ['div', ['clamp', 0, index, ['sub', lengetter, 32]], 32])
        ],
                              typ=BaseType(ret_type),
                              annotation='extracting 32 bytes')
    # General case
    else:
        o = LLLnode.from_list([
            'with', '_sub', sub,
            [
                'with', '_len', lengetter,
                [
                    'with', '_index', ['clamp', 0, index, ['sub', '_len', 32]],
                    [
                        'with', '_mi32', ['mod', '_index', 32],
                        [
                            'with', '_di32', ['div', '_index', 32],
                            [
                                'if', '_mi32',
                                [
                                    'add',
                                    [
                                        'mul',
                                        elementgetter('_di32'),
                                        ['exp', 256, '_mi32']
                                    ],
                                    [
                                        'div',
                                        elementgetter(['add', '_di32', 1]),
                                        ['exp', 256, ['sub', 32, '_mi32']]
                                    ]
                                ],
                                elementgetter('_di32')
                            ]
                        ]
                    ]
                ]
            ]
        ],
                              typ=BaseType(ret_type),
                              pos=getpos(expr),
                              annotation='extracting 32 bytes')
    if ret_type == 'int128':
        return LLLnode.from_list([
            'clamp', ['mload', MemoryPositions.MINNUM], o,
            ['mload', MemoryPositions.MAXNUM]
        ],
                                 typ=BaseType('int128'),
                                 pos=getpos(expr))
    elif ret_type == 'address':
        return LLLnode.from_list(
            ['uclamplt', o, ['mload', MemoryPositions.ADDRSIZE]],
            typ=BaseType(ret_type),
            pos=getpos(expr))
    else:
        return o
Beispiel #24
0
    def parse_for(self):
        from .parser import (
            parse_body, )
        # Type 0 for, e.g. for i in list(): ...
        if self._is_list_iter():
            return self.parse_for_list()

        if not isinstance(self.stmt.iter, ast.Call) or \
            not isinstance(self.stmt.iter.func, ast.Name) or \
                not isinstance(self.stmt.target, ast.Name) or \
                    self.stmt.iter.func.id != "range" or \
                        len(self.stmt.iter.args) not in (1, 2):
            raise StructureException(
                "For statements must be of the form `for i in range(rounds): ..` or `for i in range(start, start + rounds): ..`",
                self.stmt.iter)  # noqa

        block_scope_id = id(self.stmt.orelse)
        self.context.start_blockscope(block_scope_id)
        # Type 1 for, e.g. for i in range(10): ...
        if len(self.stmt.iter.args) == 1:
            if not isinstance(self.stmt.iter.args[0], ast.Num):
                raise StructureException("Range only accepts literal values",
                                         self.stmt.iter)
            start = LLLnode.from_list(0, typ='int128', pos=getpos(self.stmt))
            rounds = self.stmt.iter.args[0].n
        elif isinstance(self.stmt.iter.args[0], ast.Num) and isinstance(
                self.stmt.iter.args[1], ast.Num):
            # Type 2 for, e.g. for i in range(100, 110): ...
            start = LLLnode.from_list(self.stmt.iter.args[0].n,
                                      typ='int128',
                                      pos=getpos(self.stmt))
            rounds = LLLnode.from_list(self.stmt.iter.args[1].n -
                                       self.stmt.iter.args[0].n,
                                       typ='int128',
                                       pos=getpos(self.stmt))
        else:
            # Type 3 for, e.g. for i in range(x, x + 10): ...
            if not isinstance(self.stmt.iter.args[1],
                              ast.BinOp) or not isinstance(
                                  self.stmt.iter.args[1].op, ast.Add):
                raise StructureException(
                    "Two-arg for statements must be of the form `for i in range(start, start + rounds): ...`",
                    self.stmt.iter.args[1])
            if ast.dump(self.stmt.iter.args[0]) != ast.dump(
                    self.stmt.iter.args[1].left):
                raise StructureException(
                    "Two-arg for statements of the form `for i in range(x, x + y): ...` must have x identical in both places: %r %r"
                    % (ast.dump(self.stmt.iter.args[0]),
                       ast.dump(self.stmt.iter.args[1].left)), self.stmt.iter)
            if not isinstance(self.stmt.iter.args[1].right, ast.Num):
                raise StructureException("Range only accepts literal values",
                                         self.stmt.iter.args[1])
            start = Expr.parse_value_expr(self.stmt.iter.args[0], self.context)
            rounds = self.stmt.iter.args[1].right.n
        varname = self.stmt.target.id
        pos = self.context.new_variable(varname, BaseType('int128'))
        self.context.forvars[varname] = True
        o = LLLnode.from_list([
            'repeat', pos, start, rounds,
            parse_body(self.stmt.body, self.context)
        ],
                              typ=None,
                              pos=getpos(self.stmt))
        del self.context.vars[varname]
        del self.context.forvars[varname]
        self.context.end_blockscope(block_scope_id)
        return o
Beispiel #25
0
def bitwise_not(expr, args, kwargs, context):
    return LLLnode.from_list(['not', args[0]],
                             typ=BaseType('uint256'),
                             pos=getpos(expr))
Beispiel #26
0
    def build_in_comparator(self):
        from vyper.parser.parser import make_setter
        left = Expr(self.expr.left, self.context).lll_node
        right = Expr(self.expr.comparators[0], self.context).lll_node

        if left.typ.typ != right.typ.subtype.typ:
            raise TypeMismatchException("%s cannot be in a list of %s" %
                                        (left.typ.typ, right.typ.subtype.typ))
        result_placeholder = self.context.new_placeholder(BaseType('bool'))
        setter = []

        # Load nth item from list in memory.
        if right.value == 'multi':
            # Copy literal to memory to be compared.
            tmp_list = LLLnode.from_list(obj=self.context.new_placeholder(
                ListType(right.typ.subtype, right.typ.count)),
                                         typ=ListType(right.typ.subtype,
                                                      right.typ.count),
                                         location='memory')
            setter = make_setter(tmp_list,
                                 right,
                                 'memory',
                                 pos=getpos(self.expr))
            load_i_from_list = [
                'mload',
                [
                    'add', tmp_list,
                    ['mul', 32, ['mload', MemoryPositions.FREE_LOOP_INDEX]]
                ]
            ]
        elif right.location == "storage":
            load_i_from_list = [
                'sload',
                [
                    'add', ['sha3_32', right],
                    ['mload', MemoryPositions.FREE_LOOP_INDEX]
                ]
            ]
        else:
            load_i_from_list = [
                'mload',
                [
                    'add', right,
                    ['mul', 32, ['mload', MemoryPositions.FREE_LOOP_INDEX]]
                ]
            ]

        # Condition repeat loop has to break on.
        break_loop_condition = [
            'if',
            ['eq', unwrap_location(left), load_i_from_list],
            [
                'seq',
                ['mstore', '_result', 1],  # store true.
                'break'
            ]
        ]

        # Repeat loop to loop-compare each item in the list.
        for_loop_sequence = [['mstore', result_placeholder, 0],
                             [
                                 'with', '_result', result_placeholder,
                                 [
                                     'repeat', MemoryPositions.FREE_LOOP_INDEX,
                                     0, right.typ.count, break_loop_condition
                                 ]
                             ], ['mload', result_placeholder]]

        # Save list to memory, so one can iterate over it,
        # used when literal was created with tmp_list.
        if setter:
            compare_sequence = ['seq', setter] + for_loop_sequence
        else:
            compare_sequence = ['seq'] + for_loop_sequence

        # Compare the result of the repeat loop to 1, to know if a match was found.
        o = LLLnode.from_list(['eq', 1, compare_sequence],
                              typ='bool',
                              annotation="in comporator")

        return o
Beispiel #27
0
def get_length(arg):
    if arg.location == "memory":
        return LLLnode.from_list(['mload', arg], typ=BaseType('int128'))
    elif arg.location == "storage":
        return LLLnode.from_list(['sload', ['sha3_32', arg]],
                                 typ=BaseType('int128'))
Beispiel #28
0
    def number(self):
        orignum = get_original_if_0_prefixed(self.expr, self.context)

        if orignum is None and isinstance(self.expr.n, int):
            # Literal (mostly likely) becomes int128
            if SizeLimits.in_bounds('int128', self.expr.n) or self.expr.n < 0:
                return LLLnode.from_list(self.expr.n,
                                         typ=BaseType('int128',
                                                      unit=None,
                                                      is_literal=True),
                                         pos=getpos(self.expr))
            # Literal is large enough (mostly likely) becomes uint256.
            else:
                return LLLnode.from_list(self.expr.n,
                                         typ=BaseType('uint256',
                                                      unit=None,
                                                      is_literal=True),
                                         pos=getpos(self.expr))

        elif isinstance(self.expr.n, float):
            numstring, num, den = get_number_as_fraction(
                self.expr, self.context)
            # if not SizeLimits.in_bounds('decimal', num // den):
            # if not SizeLimits.MINDECIMAL * den <= num <= SizeLimits.MAXDECIMAL * den:
            if not (SizeLimits.MINNUM * den < num < SizeLimits.MAXNUM * den):
                raise InvalidLiteralException(
                    "Number out of range: " + numstring, self.expr)
            if DECIMAL_DIVISOR % den:
                raise InvalidLiteralException(
                    "Too many decimal places: " + numstring, self.expr)
            return LLLnode.from_list(num * DECIMAL_DIVISOR // den,
                                     typ=BaseType('decimal', unit=None),
                                     pos=getpos(self.expr))
        # Binary literal.
        elif orignum[:2] == '0b':
            str_val = orignum[2:]
            total_bits = len(orignum[2:])
            total_bits = total_bits if total_bits % 8 == 0 else total_bits + 8 - (
                total_bits % 8)  # ceil8 to get byte length.
            if len(
                    orignum[2:]
            ) != total_bits:  # Support only full formed bit definitions.
                raise InvalidLiteralException(
                    "Bit notation requires a multiple of 8 bits / 1 byte. {} bit(s) are missing."
                    .format(total_bits - len(orignum[2:])), self.expr)
            byte_len = int(total_bits / 8)
            placeholder = self.context.new_placeholder(ByteArrayType(byte_len))
            seq = []
            seq.append(['mstore', placeholder, byte_len])
            for i in range(0, total_bits, 256):
                section = str_val[i:i + 256]
                int_val = int(section, 2) << (256 - len(section)
                                              )  # bytes are right padded.
                seq.append(['mstore', ['add', placeholder, i + 32], int_val])
            return LLLnode.from_list(
                ['seq'] + seq + [placeholder],
                typ=ByteArrayType(byte_len),
                location='memory',
                pos=getpos(self.expr),
                annotation='Create ByteArray (Binary literal): %s' % str_val)
        elif len(orignum) == 42:
            if checksum_encode(orignum) != orignum:
                raise InvalidLiteralException(
                    """Address checksum mismatch. If you are sure this is the
right address, the correct checksummed form is: %s""" %
                    checksum_encode(orignum), self.expr)
            return LLLnode.from_list(self.expr.n,
                                     typ=BaseType('address', is_literal=True),
                                     pos=getpos(self.expr))
        elif len(orignum) == 66:
            return LLLnode.from_list(self.expr.n,
                                     typ=BaseType('bytes32', is_literal=True),
                                     pos=getpos(self.expr))
        else:
            raise InvalidLiteralException(
                "Cannot read 0x value with length %d. Expecting 42 (address incl 0x) or 66 (bytes32 incl 0x)"
                % len(orignum), self.expr)
Beispiel #29
0
    def arithmetic(self):
        pre_alloc_left, left = self.arithmetic_get_reference(self.expr.left)
        pre_alloc_right, right = self.arithmetic_get_reference(self.expr.right)

        if not is_numeric_type(left.typ) or not is_numeric_type(right.typ):
            raise TypeMismatchException("Unsupported types for arithmetic op: %r %r" % (left.typ, right.typ), self.expr)

        arithmetic_pair = {left.typ.typ, right.typ.typ}

        # Special Case: Simplify any literal to literal arithmetic at compile time.
        if left.typ.is_literal and right.typ.is_literal and \
           isinstance(right.value, int) and isinstance(left.value, int):

            if isinstance(self.expr.op, ast.Add):
                val = left.value + right.value
            elif isinstance(self.expr.op, ast.Sub):
                val = left.value - right.value
            elif isinstance(self.expr.op, ast.Mult):
                val = left.value * right.value
            elif isinstance(self.expr.op, ast.Div):
                val = left.value // right.value
            elif isinstance(self.expr.op, ast.Mod):
                val = left.value % right.value
            elif isinstance(self.expr.op, ast.Pow):
                val = left.value ** right.value
            else:
                raise ParserException('Unsupported literal operator: %s' % str(type(self.expr.op)), self.expr)

            num = ast.Num(val)
            num.source_code = self.expr.source_code
            num.lineno = self.expr.lineno
            num.col_offset = self.expr.col_offset

            return Expr.parse_value_expr(num, self.context)

        # Special case with uint256 were int literal may be casted.
        if arithmetic_pair == {'uint256', 'int128'}:
            # Check right side literal.
            if right.typ.is_literal and SizeLimits.in_bounds('uint256', right.value):
                right = LLLnode.from_list(right.value, typ=BaseType('uint256', None, is_literal=True), pos=getpos(self.expr))
                arithmetic_pair = {left.typ.typ, right.typ.typ}
            # Check left side literal.
            elif left.typ.is_literal and SizeLimits.in_bounds('uint256', left.value):
                left = LLLnode.from_list(left.value, typ=BaseType('uint256', None, is_literal=True), pos=getpos(self.expr))
                arithmetic_pair = {left.typ.typ, right.typ.typ}

        # Only allow explicit conversions to occur.
        if left.typ.typ != right.typ.typ:
            raise TypeMismatchException("Cannot implicitly convert {} to {}.".format(left.typ.typ, right.typ.typ), self.expr)

        ltyp, rtyp = left.typ.typ, right.typ.typ
        if isinstance(self.expr.op, (ast.Add, ast.Sub)):
            if left.typ.unit != right.typ.unit and left.typ.unit != {} and right.typ.unit != {}:
                raise TypeMismatchException("Unit mismatch: %r %r" % (left.typ.unit, right.typ.unit), self.expr)
            if left.typ.positional and right.typ.positional and isinstance(self.expr.op, ast.Add):
                raise TypeMismatchException("Cannot add two positional units!", self.expr)
            new_unit = left.typ.unit or right.typ.unit
            new_positional = left.typ.positional ^ right.typ.positional  # xor, as subtracting two positionals gives a delta
            op = 'add' if isinstance(self.expr.op, ast.Add) else 'sub'
            if ltyp == 'uint256' and isinstance(self.expr.op, ast.Add):
                o = LLLnode.from_list(['seq',
                                # Checks that: a + b >= a
                                ['assert', ['ge', ['add', left, right], left]],
                                ['add', left, right]], typ=BaseType('uint256', new_unit, new_positional), pos=getpos(self.expr))
            elif ltyp == 'uint256' and isinstance(self.expr.op, ast.Sub):
                o = LLLnode.from_list(['seq',
                                # Checks that: a >= b
                                ['assert', ['ge', left, right]],
                                ['sub', left, right]], typ=BaseType('uint256', new_unit, new_positional), pos=getpos(self.expr))
            elif ltyp == rtyp:
                o = LLLnode.from_list([op, left, right], typ=BaseType(ltyp, new_unit, new_positional), pos=getpos(self.expr))
            else:
                raise Exception("Unsupported Operation '%r(%r, %r)'" % (op, ltyp, rtyp))
        elif isinstance(self.expr.op, ast.Mult):
            if left.typ.positional or right.typ.positional:
                raise TypeMismatchException("Cannot multiply positional values!", self.expr)
            new_unit = combine_units(left.typ.unit, right.typ.unit)
            if ltyp == rtyp == 'uint256':
                o = LLLnode.from_list(['if', ['eq', left, 0], [0],
                                      ['seq', ['assert', ['eq', ['div', ['mul', left, right], left], right]],
                                      ['mul', left, right]]], typ=BaseType('uint256', new_unit), pos=getpos(self.expr))
            elif ltyp == rtyp == 'int128':
                o = LLLnode.from_list(['mul', left, right], typ=BaseType('int128', new_unit), pos=getpos(self.expr))
            elif ltyp == rtyp == 'decimal':
                o = LLLnode.from_list(['with', 'r', right, ['with', 'l', left,
                                        ['with', 'ans', ['mul', 'l', 'r'],
                                            ['seq',
                                                ['assert', ['or', ['eq', ['sdiv', 'ans', 'l'], 'r'], ['iszero', 'l']]],
                                                ['sdiv', 'ans', DECIMAL_DIVISOR]]]]], typ=BaseType('decimal', new_unit), pos=getpos(self.expr))
            else:
                raise Exception("Unsupported Operation 'mul(%r, %r)'" % (ltyp, rtyp))
        elif isinstance(self.expr.op, ast.Div):
            if left.typ.positional or right.typ.positional:
                raise TypeMismatchException("Cannot divide positional values!", self.expr)
            new_unit = combine_units(left.typ.unit, right.typ.unit, div=True)
            if ltyp == rtyp == 'uint256':
                o = LLLnode.from_list(['seq',
                                # Checks that:  b != 0
                                ['assert', right],
                                ['div', left, right]], typ=BaseType('uint256', new_unit), pos=getpos(self.expr))
            elif ltyp == rtyp == 'int128':
                o = LLLnode.from_list(['sdiv', left, ['clamp_nonzero', right]], typ=BaseType('int128', new_unit), pos=getpos(self.expr))
            elif ltyp == rtyp == 'decimal':
                o = LLLnode.from_list(['with', 'l', left, ['with', 'r', ['clamp_nonzero', right],
                                            ['sdiv', ['mul', 'l', DECIMAL_DIVISOR], 'r']]],
                                      typ=BaseType('decimal', new_unit), pos=getpos(self.expr))
            else:
                raise Exception("Unsupported Operation 'div(%r, %r)'" % (ltyp, rtyp))
        elif isinstance(self.expr.op, ast.Mod):
            if left.typ.positional or right.typ.positional:
                raise TypeMismatchException("Cannot use positional values as modulus arguments!", self.expr)
            if not are_units_compatible(left.typ, right.typ) and not (left.typ.unit or right.typ.unit):
                raise TypeMismatchException("Modulus arguments must have same unit", self.expr)
            new_unit = left.typ.unit or right.typ.unit
            if ltyp == rtyp == 'uint256':
                o = LLLnode.from_list(['seq',
                                ['assert', right],
                                ['mod', left, right]], typ=BaseType('uint256', new_unit), pos=getpos(self.expr))
            elif ltyp == rtyp:
                o = LLLnode.from_list(['smod', left, ['clamp_nonzero', right]], typ=BaseType(ltyp, new_unit), pos=getpos(self.expr))
            else:
                raise Exception("Unsupported Operation 'mod(%r, %r)'" % (ltyp, rtyp))
        elif isinstance(self.expr.op, ast.Pow):
            if left.typ.positional or right.typ.positional:
                raise TypeMismatchException("Cannot use positional values as exponential arguments!", self.expr)
            if right.typ.unit:
                raise TypeMismatchException("Cannot use unit values as exponents", self.expr)
            if ltyp != 'int128' and ltyp != 'uint256' and isinstance(self.expr.right, ast.Name):
                raise TypeMismatchException("Cannot use dynamic values as exponents, for unit base types", self.expr)
            if ltyp == rtyp == 'uint256':
                o = LLLnode.from_list(['seq',
                                        ['assert', ['or', ['or', ['eq', right, 1], ['iszero', right]],
                                        ['lt', left, ['exp', left, right]]]],
                                        ['exp', left, right]], typ=BaseType('uint256'), pos=getpos(self.expr))
            elif ltyp == rtyp == 'int128':
                new_unit = left.typ.unit
                if left.typ.unit and not isinstance(self.expr.right, ast.Name):
                    new_unit = {left.typ.unit.copy().popitem()[0]: self.expr.right.n}
                o = LLLnode.from_list(['exp', left, right], typ=BaseType('int128', new_unit), pos=getpos(self.expr))
            else:
                raise TypeMismatchException('Only whole number exponents are supported', self.expr)
        else:
            raise ParserException("Unsupported binary operator: %r" % self.expr.op, self.expr)

        p = ['seq']

        if pre_alloc_left:
            p.append(pre_alloc_left)
        if pre_alloc_right:
            p.append(pre_alloc_right)

        if o.typ.typ == 'int128':
            p.append(['clamp', ['mload', MemoryPositions.MINNUM], o, ['mload', MemoryPositions.MAXNUM]])
            return LLLnode.from_list(p, typ=o.typ, pos=getpos(self.expr))
        elif o.typ.typ == 'decimal':
            p.append(['clamp', ['mload', MemoryPositions.MINDECIMAL], o, ['mload', MemoryPositions.MAXDECIMAL]])
            return LLLnode.from_list(p, typ=o.typ, pos=getpos(self.expr))
        if o.typ.typ == 'uint256':
            p.append(o)
            return LLLnode.from_list(p, typ=o.typ, pos=getpos(self.expr))
        else:
            raise Exception("%r %r" % (o, o.typ))
Beispiel #30
0
def uint256_mulmod(expr, args, kwargs, context):
    return LLLnode.from_list(['seq',
                                ['assert', args[2]],
                                ['assert', ['or', ['iszero', args[0]],
                                ['eq', ['div', ['mul', args[0], args[1]], args[0]], args[1]]]],
                                ['mulmod', args[0], args[1], args[2]]], typ=BaseType('uint256'), pos=getpos(expr))