Пример #1
0
 def parse_docblock(self):
     if '"""' not in self.context.origcode.splitlines()[self.stmt.lineno -
                                                        1]:
         raise InvalidLiteralException('Only valid """ docblocks allowed',
                                       self.stmt)
     return LLLnode.from_list('pass', typ=None, pos=getpos(self.stmt))
Пример #2
0
def _RLPlist(expr, args, kwargs, context):
    # Second argument must be a list of types
    if not isinstance(args[1], ast.List):
        raise TypeMismatchException(
            "Expecting list of types for second argument", args[1])
    if len(args[1].elts) == 0:
        raise TypeMismatchException("RLP list must have at least one item",
                                    expr)
    if len(args[1].elts) > 32:
        raise TypeMismatchException("RLP list must have at most 32 items",
                                    expr)
    # Get the output format
    _format = []
    for arg in args[1].elts:
        if isinstance(arg, ast.Name) and arg.id == "bytes":
            subtyp = ByteArrayType(args[0].typ.maxlen)
        else:
            subtyp = parse_type(arg, 'memory')
            if not isinstance(subtyp, BaseType):
                raise TypeMismatchException(
                    "RLP lists only accept BaseTypes and byte arrays", arg)
            if not is_base_type(
                    subtyp,
                ('int128', 'uint256', 'bytes32', 'address', 'bool')):
                raise TypeMismatchException(
                    "Unsupported base type: %s" % subtyp.typ, arg)
        _format.append(subtyp)
    output_type = TupleType(_format)
    output_placeholder_type = ByteArrayType(
        (2 * len(_format) + 1 + get_size_of_type(output_type)) * 32)
    output_placeholder = context.new_placeholder(output_placeholder_type)
    output_node = LLLnode.from_list(output_placeholder,
                                    typ=output_placeholder_type,
                                    location='memory')
    # Create a decoder for each element in the tuple
    decoder = []
    for i, typ in enumerate(_format):
        # Decoder for bytes32
        if is_base_type(typ, 'bytes32'):
            decoder.append(
                LLLnode.from_list(
                    [
                        'seq',
                        [
                            'assert',
                            [
                                'eq',
                                [
                                    'mload',
                                    [
                                        'add', output_node,
                                        [
                                            'mload',
                                            ['add', output_node, 32 * i]
                                        ]
                                    ]
                                ], 32
                            ]
                        ],
                        [
                            'mload',
                            [
                                'add', 32,
                                [
                                    'add', output_node,
                                    ['mload', ['add', output_node, 32 * i]]
                                ]
                            ]
                        ]
                    ],
                    typ,
                    annotation='getting and checking bytes32 item'))
        # Decoder for address
        elif is_base_type(typ, 'address'):
            decoder.append(
                LLLnode.from_list(
                    [
                        'seq',
                        [
                            'assert',
                            [
                                'eq',
                                [
                                    'mload',
                                    [
                                        'add', output_node,
                                        [
                                            'mload',
                                            ['add', output_node, 32 * i]
                                        ]
                                    ]
                                ], 20
                            ]
                        ],
                        [
                            'mod',
                            [
                                'mload',
                                [
                                    'add', 20,
                                    [
                                        'add', output_node,
                                        [
                                            'mload',
                                            ['add', output_node, 32 * i]
                                        ]
                                    ]
                                ]
                            ], ['mload', MemoryPositions.ADDRSIZE]
                        ]
                    ],
                    typ,
                    annotation='getting and checking address item'))
        # Decoder for bytes
        elif isinstance(typ, ByteArrayType):
            decoder.append(
                LLLnode.from_list([
                    'add', output_node,
                    ['mload', ['add', output_node, 32 * i]]
                ],
                                  typ,
                                  location='memory',
                                  annotation='getting byte array'))
        # Decoder for num and uint256
        elif is_base_type(typ, ('int128', 'uint256')):
            bytez = LLLnode.from_list(
                ['add', output_node, ['mload', ['add', output_node, 32 * i]]],
                typ,
                location='memory',
                annotation='getting and checking %s' % typ.typ)
            decoder.append(byte_array_to_num(bytez, expr, typ.typ))
        # Decoder for bools
        elif is_base_type(typ, ('bool')):
            # This is basically a really clever way to test for a length-prefixed one or zero. We take the 32 bytes
            # starting one byte *after* the start of the length declaration; this includes the last 31 bytes of the
            # length and the first byte of the value. 0 corresponds to length 0, first byte 0, and 257 corresponds
            # to length 1, first byte \x01
            decoder.append(
                LLLnode.from_list([
                    'with', '_ans',
                    [
                        'mload',
                        [
                            'add', 1,
                            [
                                'add', output_node,
                                ['mload', ['add', output_node, 32 * i]]
                            ]
                        ]
                    ],
                    [
                        'seq',
                        [
                            'assert',
                            ['or', ['eq', '_ans', 0], ['eq', '_ans', 257]]
                        ], ['div', '_ans', 257]
                    ]
                ],
                                  typ,
                                  annotation='getting and checking bool'))
        else:
            # Should never reach because of top level base level check.
            raise Exception("Type not yet supported")  # pragma: no cover
    # Copy the input data to memory
    if args[0].location == "memory":
        variable_pointer = args[0]
    elif args[0].location == "storage":
        placeholder = context.new_placeholder(args[0].typ)
        placeholder_node = LLLnode.from_list(placeholder,
                                             typ=args[0].typ,
                                             location='memory')
        copier = make_byte_array_copier(
            placeholder_node,
            LLLnode.from_list('_ptr',
                              typ=args[0].typ,
                              location=args[0].location))
        variable_pointer = [
            'with', '_ptr', args[0], ['seq', copier, placeholder_node]
        ]
    else:
        # Should never reach because of top level base level check.
        raise Exception("Location not yet supported")  # pragma: no cover
    # Decode the input data
    initial_setter = LLLnode.from_list([
        'seq',
        [
            'with', '_sub', variable_pointer,
            [
                'pop',
                [
                    'call', 1500 + 400 * len(_format) + 10 * len(args),
                    LLLnode.from_list(RLP_DECODER_ADDRESS,
                                      annotation='RLP decoder'), 0,
                    ['add', '_sub', 32], ['mload', '_sub'], output_node,
                    64 * len(_format) + 32 + 32 * get_size_of_type(output_type)
                ]
            ]
        ], ['assert', ['eq', ['mload', output_node], 32 * len(_format) + 32]]
    ],
                                       typ=None)
    # Shove the input data decoder in front of the first variable decoder
    decoder[0] = LLLnode.from_list(['seq', initial_setter, decoder[0]],
                                   typ=decoder[0].typ,
                                   location=decoder[0].location)
    return LLLnode.from_list(["multi"] + decoder,
                             typ=output_type,
                             location='memory',
                             pos=getpos(expr))
Пример #3
0
def bitwise_not(expr, args, kwargs, context):
    return LLLnode.from_list(['not', args[0]],
                             typ=BaseType('uint256'),
                             pos=getpos(expr))
Пример #4
0
        numstring, num, den = get_number_as_fraction(expr.args[0], context)
        if denomination % den:
            raise InvalidLiteralException(
                "Too many decimal places: %s" % numstring, expr.args[0])
        sub = num * denomination // den
    elif args[0].typ.typ == 'int128':
        sub = ['mul', args[0], denomination]
    else:
        sub = ['div', ['mul', args[0], denomination], DECIMAL_DIVISOR]
    return LLLnode.from_list(sub,
                             typ=BaseType('int128', {'wei': 1}),
                             location=None,
                             pos=getpos(expr))


zero_value = LLLnode.from_list(0, typ=BaseType('int128', {'wei': 1}))


@signature('address',
           'bytes',
           outsize='num_literal',
           gas='int128',
           value=Optional('int128', zero_value))
def raw_call(expr, args, kwargs, context):
    to, data = args
    gas, value, outsize = kwargs['gas'], kwargs['value'], kwargs['outsize']
    if context.is_constant:
        raise ConstancyViolationException(
            "Cannot make calls from a constant function", expr)
    if value != zero_value:
        enforce_units(value.typ, get_keyword(expr, 'value'),
Пример #5
0
def avo(arg, ind, pos):
    return unwrap_location(
        add_variable_offset(arg, LLLnode.from_list(ind, 'int128'), pos=pos))
Пример #6
0
def _memory_element_getter(index):
    return LLLnode.from_list(
        ['mload', ['add', '_sub', ['add', 32, ['mul', 32, index]]]],
        typ=BaseType('int128'),
    )
Пример #7
0
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(
            'The delegate_call parameter has to be a static/literal boolean value.'
        )
    if context.is_constant():
        raise ConstancyViolationException(
            "Cannot make calls from %s" % context.pp_constancy(),
            expr,
        )
    if value != zero_value:
        enforce_units(
            value.typ,
            get_keyword(expr, 'value'),
            BaseType('uint256', {'wei': 1}),
        )
    placeholder = context.new_placeholder(data.typ)
    placeholder_node = LLLnode.from_list(placeholder, typ=data.typ, location='memory')
    copier = make_byte_array_copier(placeholder_node, data, pos=getpos(expr))
    output_placeholder = context.new_placeholder(ByteArrayType(outsize))
    output_node = LLLnode.from_list(
        output_placeholder,
        typ=ByteArrayType(outsize),
        location='memory',
    )

    if delegate_call.value == 1:
        z = LLLnode.from_list(
            [
                'seq',
                copier,
                [
                    'assert',
                    [
                        'delegatecall',
                        gas,
                        to,
                        ['add', placeholder_node, 32],
                        ['mload', placeholder_node],
                        ['add', output_node, 32],
                        outsize,
                    ],
                ],
                ['mstore', output_node, outsize],
                output_node,
            ],
            typ=ByteArrayType(outsize),
            location='memory',
            pos=getpos(expr),
        )
    else:
        z = LLLnode.from_list(
            [
                'seq',
                copier,
                [
                    'assert',
                    [
                        'call',
                        gas,
                        to,
                        value,
                        ['add', placeholder_node, 32],
                        ['mload', placeholder_node],
                        ['add', output_node, 32],
                        outsize,
                    ],
                ],
                ['mstore', output_node, outsize],
                output_node,
            ],
            typ=ByteArrayType(outsize), location='memory', pos=getpos(expr)
        )
    return z
Пример #8
0
 def aug_assign(self):
     target = self.get_target(self.stmt.target)
     sub = Expr.parse_value_expr(self.stmt.value, self.context)
     if not isinstance(
             self.stmt.op,
         (vy_ast.Add, vy_ast.Sub, vy_ast.Mult, vy_ast.Div, vy_ast.Mod)):
         raise StructureException("Unsupported operator for augassign",
                                  self.stmt)
     if not isinstance(target.typ, BaseType):
         raise TypeMismatchException(
             "Can only use aug-assign operators with simple types!",
             self.stmt.target)
     if target.location == 'storage':
         o = Expr.parse_value_expr(
             vy_ast.BinOp(
                 left=LLLnode.from_list(['sload', '_stloc'],
                                        typ=target.typ,
                                        pos=target.pos),
                 right=sub,
                 op=self.stmt.op,
                 lineno=self.stmt.lineno,
                 col_offset=self.stmt.col_offset,
                 end_lineno=self.stmt.end_lineno,
                 end_col_offset=self.stmt.end_col_offset,
             ),
             self.context,
         )
         return LLLnode.from_list([
             'with',
             '_stloc',
             target,
             [
                 'sstore',
                 '_stloc',
                 base_type_conversion(
                     o, o.typ, target.typ, pos=getpos(self.stmt)),
             ],
         ],
                                  typ=None,
                                  pos=getpos(self.stmt))
     elif target.location == 'memory':
         o = Expr.parse_value_expr(
             vy_ast.BinOp(
                 left=LLLnode.from_list(['mload', '_mloc'],
                                        typ=target.typ,
                                        pos=target.pos),
                 right=sub,
                 op=self.stmt.op,
                 lineno=self.stmt.lineno,
                 col_offset=self.stmt.col_offset,
                 end_lineno=self.stmt.end_lineno,
                 end_col_offset=self.stmt.end_col_offset,
             ),
             self.context,
         )
         return LLLnode.from_list([
             'with',
             '_mloc',
             target,
             [
                 'mstore',
                 '_mloc',
                 base_type_conversion(
                     o, o.typ, target.typ, pos=getpos(self.stmt)),
             ],
         ],
                                  typ=None,
                                  pos=getpos(self.stmt))
Пример #9
0
 def parse_continue(self):
     return LLLnode.from_list('continue', typ=None, pos=getpos(self.stmt))
Пример #10
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, vy_ast.Call):
            if isinstance(self.stmt.iter, vy_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, vy_ast.BinOp) or not isinstance(
                        arg1.op, vy_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: {vy_ast.ast_to_dict(arg0)} {vy_ast.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
Пример #11
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, vy_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, vy_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, vy_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
Пример #12
0
 def _assert_unreachable(test_expr, msg):
     return LLLnode.from_list(['assert_unreachable', test_expr],
                              typ=None,
                              pos=getpos(msg))
Пример #13
0
    def call(self):
        is_self_function = (isinstance(
            self.stmt.func, vy_ast.Attribute)) and isinstance(
                self.stmt.func.value,
                vy_ast.Name) and self.stmt.func.value.id == "self"

        is_log_call = (isinstance(
            self.stmt.func, vy_ast.Attribute)) and isinstance(
                self.stmt.func.value,
                vy_ast.Name) and self.stmt.func.value.id == 'log'

        if isinstance(self.stmt.func, vy_ast.Name):
            if self.stmt.func.id in STMT_DISPATCH_TABLE:
                if self.stmt.func.id == 'clear':
                    return self._clear()
                else:
                    return STMT_DISPATCH_TABLE[self.stmt.func.id](self.stmt,
                                                                  self.context)
            elif self.stmt.func.id in DISPATCH_TABLE:
                raise StructureException(
                    f"Function {self.stmt.func.id} can not be called without being used.",
                    self.stmt,
                )
            else:
                raise StructureException(
                    f"Unknown function: '{self.stmt.func.id}'.",
                    self.stmt,
                )
        elif is_self_function:
            return self_call.make_call(self.stmt, self.context)
        elif is_log_call:
            if self.stmt.func.attr not in self.context.sigs['self']:
                raise EventDeclarationException(
                    f"Event not declared yet: {self.stmt.func.attr}")
            event = self.context.sigs['self'][self.stmt.func.attr]
            if len(event.indexed_list) != len(self.stmt.args):
                raise EventDeclarationException(
                    f"{event.name} received {len(self.stmt.args)} arguments but "
                    f"expected {len(event.indexed_list)}")
            expected_topics, topics = [], []
            expected_data, data = [], []
            for pos, is_indexed in enumerate(event.indexed_list):
                if is_indexed:
                    expected_topics.append(event.args[pos])
                    topics.append(self.stmt.args[pos])
                else:
                    expected_data.append(event.args[pos])
                    data.append(self.stmt.args[pos])
            topics = pack_logging_topics(
                event.event_id,
                topics,
                expected_topics,
                self.context,
                pos=getpos(self.stmt),
            )
            inargs, inargsize, inargsize_node, inarg_start = pack_logging_data(
                expected_data,
                data,
                self.context,
                pos=getpos(self.stmt),
            )

            if inargsize_node is None:
                sz = inargsize
            else:
                sz = ['mload', inargsize_node]

            return LLLnode.from_list([
                'seq', inargs,
                LLLnode.from_list(
                    ["log" + str(len(topics)), inarg_start, sz] + topics,
                    add_gas_estimate=inargsize * 10,
                )
            ],
                                     typ=None,
                                     pos=getpos(self.stmt))
        else:
            return external_call.make_external_call(self.stmt, self.context)
Пример #14
0
    def assign(self):
        # Assignment (e.g. x[4] = y)
        if len(self.stmt.targets) != 1:
            raise StructureException(
                "Assignment statement must have one target", self.stmt)

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

            # Disallow assignment to None
            if isinstance(sub.typ, NullType):
                raise InvalidLiteralException(
                    ('Assignment to None is not allowed, use a default value '
                     'or built-in `clear()`.'),
                    self.stmt,
                )

            is_valid_rlp_list_assign = (isinstance(
                self.stmt.value, vy_ast.Call)) and getattr(
                    self.stmt.value.func, 'id', '') == 'RLPList'

            # Determine if it's an RLPList assignment.
            if is_valid_rlp_list_assign:
                pos = self.context.new_variable(self.stmt.targets[0].id,
                                                sub.typ)
                variable_loc = LLLnode.from_list(
                    pos,
                    typ=sub.typ,
                    location='memory',
                    pos=getpos(self.stmt),
                    annotation=self.stmt.targets[0].id,
                )
                o = make_setter(variable_loc,
                                sub,
                                'memory',
                                pos=getpos(self.stmt))
            else:
                # Error check when assigning to declared variable
                if isinstance(self.stmt.targets[0], vy_ast.Name):
                    # Do not allow assignment to undefined variables without annotation
                    if self.stmt.targets[0].id not in self.context.vars:
                        raise VariableDeclarationException(
                            "Variable type not defined", self.stmt)

                    # Check against implicit conversion
                    self._check_implicit_conversion(self.stmt.targets[0].id,
                                                    sub)

                is_valid_tuple_assign = (isinstance(
                    self.stmt.targets[0], vy_ast.Tuple)) and isinstance(
                        self.stmt.value, vy_ast.Tuple)

                # Do no allow tuple-to-tuple assignment
                if is_valid_tuple_assign:
                    raise VariableDeclarationException(
                        "Tuple to tuple assignment not supported",
                        self.stmt,
                    )

                # Checks to see if assignment is valid
                target = self.get_target(self.stmt.targets[0])
                if isinstance(target.typ, ContractType) and not isinstance(
                        sub.typ, ContractType):
                    raise TypeMismatchException(
                        'Contract assignment expects casted address: '
                        f'{target.typ.unit}(<address_var>)', self.stmt)
                o = make_setter(target,
                                sub,
                                target.location,
                                pos=getpos(self.stmt))

            o.pos = getpos(self.stmt)

        return o
Пример #15
0
def _slice(expr, args, kwargs, context):

    sub, start, length = args[0], kwargs['start'], kwargs['len']
    if not are_units_compatible(start.typ, BaseType('int128')):
        raise TypeMismatchException("Type for slice start index must be a unitless number", expr)
    # Expression representing the length of the slice
    if not are_units_compatible(length.typ, BaseType('int128')):
        raise TypeMismatchException("Type for slice length must be a unitless number", expr)

    if is_base_type(sub.typ, 'bytes32'):
        if (start.typ.is_literal and length.typ.is_literal) and \
           not (0 <= start.value + length.value <= 32):
            raise InvalidLiteralException(
                'Invalid start / length values needs to be between 0 and 32.',
                expr,
            )
        sub_typ_maxlen = 32
    else:
        sub_typ_maxlen = sub.typ.maxlen

    # Get returntype string or bytes
    if isinstance(args[0].typ, ByteArrayType) or is_base_type(sub.typ, 'bytes32'):
        ReturnType = ByteArrayType
    else:
        ReturnType = StringType

    # Node representing the position of the output in memory
    np = context.new_placeholder(ReturnType(maxlen=sub_typ_maxlen + 32))
    placeholder_node = LLLnode.from_list(np, typ=sub.typ, location='memory')
    placeholder_plus_32_node = LLLnode.from_list(np + 32, typ=sub.typ, location='memory')
    # Copies over bytearray data
    if sub.location == 'storage':
        adj_sub = LLLnode.from_list(
            ['add', ['sha3_32', sub], ['add', ['div', '_start', 32], 1]],
            typ=sub.typ,
            location=sub.location,
        )
    else:
        adj_sub = LLLnode.from_list(
            ['add', sub, ['add', ['sub', '_start', ['mod', '_start', 32]], 32]],
            typ=sub.typ,
            location=sub.location,
        )

    if is_base_type(sub.typ, 'bytes32'):
        adj_sub = LLLnode.from_list(
            sub.args[0], typ=sub.typ, location="memory"
        )

    copier = make_byte_slice_copier(
        placeholder_plus_32_node,
        adj_sub,
        ['add', '_length', 32],
        sub_typ_maxlen,
        pos=getpos(expr),
    )
    # New maximum length in the type of the result
    newmaxlen = length.value if not len(length.args) else sub_typ_maxlen
    if is_base_type(sub.typ, 'bytes32'):
        maxlen = 32
    else:
        maxlen = ['mload', Expr(sub, context=context).lll_node]  # Retrieve length of the bytes.

    out = [
        'with', '_start', start, [
            'with', '_length', length, [
                'with', '_opos', ['add', placeholder_node, ['mod', '_start', 32]], [
                    'seq',
                    ['assert', ['le', ['add', '_start', '_length'], maxlen]],
                    copier,
                    ['mstore', '_opos', '_length'],
                    '_opos'
                ],
            ],
        ],
    ]
    return LLLnode.from_list(out, typ=ReturnType(newmaxlen), location='memory', pos=getpos(expr))
Пример #16
0
 def parse_break(self):
     return LLLnode.from_list('break', typ=None, pos=getpos(self.stmt))
Пример #17
0
def sha256(expr, args, kwargs, context):
    sub = args[0]
    # Literal input
    if isinstance(sub, bytes):
        return LLLnode.from_list(
            bytes_to_int(hashlib.sha256(sub).digest()),
            typ=BaseType('bytes32'),
            pos=getpos(expr)
        )
    # bytes32 input
    elif is_base_type(sub.typ, 'bytes32'):
        return LLLnode.from_list(
            [
                'seq',
                ['mstore', MemoryPositions.FREE_VAR_SPACE, sub],
                _make_sha256_call(
                    inp_start=MemoryPositions.FREE_VAR_SPACE,
                    inp_len=32,
                    out_start=MemoryPositions.FREE_VAR_SPACE,
                    out_len=32
                ),
                ['mload', MemoryPositions.FREE_VAR_SPACE]  # push value onto stack
            ],
            typ=BaseType('bytes32'),
            pos=getpos(expr),
            add_gas_estimate=SHA256_BASE_GAS + 1 * SHA256_PER_WORD_GAS
        )
    # bytearay-like input
    if sub.location == "storage":
        # Copy storage to memory
        placeholder = context.new_placeholder(sub.typ)
        placeholder_node = LLLnode.from_list(placeholder, typ=sub.typ, location='memory')
        copier = make_byte_array_copier(
            placeholder_node,
            LLLnode.from_list('_sub', typ=sub.typ, location=sub.location),
        )
        return LLLnode.from_list(
            [
                'with', '_sub', sub, [
                    'seq',
                    copier,
                    _make_sha256_call(
                        inp_start=['add', placeholder, 32],
                        inp_len=['mload', placeholder],
                        out_start=MemoryPositions.FREE_VAR_SPACE,
                        out_len=32
                    ),
                    ['mload', MemoryPositions.FREE_VAR_SPACE]
                ],
            ],
            typ=BaseType('bytes32'),
            pos=getpos(expr),
            add_gas_estimate=SHA256_BASE_GAS + sub.typ.maxlen * SHA256_PER_WORD_GAS
        )
    elif sub.location == "memory":
        return LLLnode.from_list(
            [
                'with', '_sub', sub, [
                    'seq',
                    _make_sha256_call(
                        inp_start=['add', '_sub', 32],
                        inp_len=['mload', '_sub'],
                        out_start=MemoryPositions.FREE_VAR_SPACE,
                        out_len=32
                    ),
                    ['mload', MemoryPositions.FREE_VAR_SPACE]
                ]
            ],
            typ=BaseType('bytes32'),
            pos=getpos(expr),
            add_gas_estimate=SHA256_BASE_GAS + sub.typ.maxlen * SHA256_PER_WORD_GAS
        )
    else:
        # This should never happen, but just left here for future compiler-writers.
        raise Exception("Unsupported location: %s" % sub.location)  # pragma: no test
Пример #18
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)
Пример #19
0
def _storage_element_getter(index):
    return LLLnode.from_list(
        ['sload', ['add', ['sha3_32', '_sub'], ['add', 1, index]]],
        typ=BaseType('int128'),
    )
Пример #20
0
 def parse_pass(self):
     return LLLnode.from_list('pass', typ=None, pos=getpos(self.stmt))
Пример #21
0
def blockhash(expr, args, kwargs, contact):
    return LLLnode.from_list(
        ['blockhash', ['uclamplt', ['clampge', args[0], ['sub', ['number'], 256]], 'number']],
        typ=BaseType('bytes32'),
        pos=getpos(expr),
    )
Пример #22
0
def to_uint256(expr, args, kwargs, context):
    in_arg = args[0]
    input_type, _ = get_type(in_arg)
    _unit = in_arg.typ.unit if input_type in ('int128', 'decimal') else None

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

    elif isinstance(in_arg, LLLnode) and input_type == 'int128':
        return LLLnode.from_list(
            ['clampge', in_arg, 0],
            typ=BaseType('uint256', _unit),
            pos=getpos(expr)
        )

    elif isinstance(in_arg, LLLnode) and input_type == 'decimal':
        return LLLnode.from_list(
            ['div', ['clampge', in_arg, 0], DECIMAL_DIVISOR],
            typ=BaseType('uint256', _unit),
            pos=getpos(expr)
        )

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

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

    elif isinstance(in_arg, LLLnode) and input_type == 'bytes':
        if in_arg.typ.maxlen > 32:
            raise InvalidLiteralException(
                f"Cannot convert bytes array of max length {in_arg.typ.maxlen} to uint256",
                expr,
            )
        return byte_array_to_num(in_arg, expr, 'uint256')

    else:
        raise InvalidLiteralException(f"Invalid input for uint256: {in_arg}", expr)
Пример #23
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') and not is_base_type(arg.typ, 'method_id'):
            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 argyument
            seq.append([
                'with',
                '_arg',
                arg,
                [
                    'seq',
                    make_byte_slice_copier(placeholder_node_plus_32, argstart,
                                           length, arg.typ.maxlen),
                    # Change the position to start at the correct
                    # place to paste the next value
                    ['set', '_poz', ['add', '_poz', length]]
                ]
            ])
        elif isinstance(arg.typ, BaseType) and arg.typ.typ == "method_id":
            seq.append([
                'seq',
                ['mstore', ['add', placeholder_node, 32], arg.value * 2**224],
                ['set', '_poz', ['add', '_poz', 4]]
            ])
        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')
Пример #24
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 TypeMismatchException(
                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:
        _unit = in_arg.typ.unit
        _positional = in_arg.typ.positional

        if input_type == 'uint256':
            if in_arg.typ.is_literal:
                if not SizeLimits.in_bounds('int128', (in_arg.value * DECIMAL_DIVISOR)):
                    raise InvalidLiteralException(
                        f"Number out of range: {in_arg.value}",
                        expr,
                    )
                else:
                    return LLLnode.from_list(
                        ['mul', in_arg, DECIMAL_DIVISOR],
                        typ=BaseType('decimal', _unit, _positional),
                        pos=getpos(expr)
                    )
            else:
                return LLLnode.from_list(
                    [
                        'uclample',
                        ['mul', in_arg, DECIMAL_DIVISOR],
                        ['mload', MemoryPositions.MAXDECIMAL]
                    ],
                    typ=BaseType('decimal', _unit, _positional),
                    pos=getpos(expr)
                )

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

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

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

        else:
            raise InvalidLiteralException(f"Invalid input for decimal: {in_arg}", expr)
Пример #25
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
Пример #26
0
def to_int128(expr, args, kwargs, context):
    in_arg = args[0]
    input_type, _ = get_type(in_arg)
    _unit = in_arg.typ.unit if input_type in ('uint256', 'decimal') else None

    if input_type == 'num_literal':
        if isinstance(in_arg, int):
            if not SizeLimits.in_bounds('int128', in_arg):
                raise InvalidLiteralException(f"Number out of range: {in_arg}")
            return LLLnode.from_list(
                in_arg,
                typ=BaseType('int128', _unit),
                pos=getpos(expr)
            )
        elif isinstance(in_arg, float):
            if not SizeLimits.in_bounds('int128', math.trunc(in_arg)):
                raise InvalidLiteralException(f"Number out of range: {math.trunc(in_arg)}")
            return LLLnode.from_list(
                math.trunc(in_arg),
                typ=BaseType('int128', _unit),
                pos=getpos(expr)
            )
        else:
            raise InvalidLiteralException(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 InvalidLiteralException(f"Number out of range: {in_arg.value}", expr)
            else:
                return LLLnode.from_list(
                    in_arg,
                    typ=BaseType('int128', _unit),
                    pos=getpos(expr)
                )
        else:
            return LLLnode.from_list(
                [
                    'clamp',
                    ['mload', MemoryPositions.MINNUM],
                    in_arg,
                    ['mload', MemoryPositions.MAXNUM],
                ],
                typ=BaseType('int128', _unit),
                pos=getpos(expr)
            )

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

    elif input_type in ('string', 'bytes'):
        if in_arg.typ.maxlen > 32:
            raise TypeMismatchException(
                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 InvalidLiteralException(f"Number out of range: {in_arg.value}", expr)
            else:
                return LLLnode.from_list(
                    in_arg,
                    typ=BaseType('int128', _unit),
                    pos=getpos(expr)
                )

        else:
            return LLLnode.from_list(
                ['uclample', in_arg, ['mload', MemoryPositions.MAXNUM]],
                typ=BaseType('int128', _unit),
                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', _unit),
            pos=getpos(expr)
        )

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

    else:
        raise InvalidLiteralException(f"Invalid input for int128: {in_arg}", expr)
Пример #27
0
def uint256_mod(expr, args, kwargs, context):
    return LLLnode.from_list(
        ['seq', ['assert', args[1]], ['mod', args[0], args[1]]],
        typ=BaseType('uint256'),
        pos=getpos(expr))
Пример #28
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'],
Пример #29
0
def uint256_le(expr, args, kwargs, context):
    return LLLnode.from_list(['le', args[0], args[1]],
                             typ=BaseType('bool'),
                             pos=getpos(expr))
rlp_decoder_lll = LLLnode.from_list(
    ['seq',
        ['return', [0],
            ['lll',
                ['seq',
                    ['mstore', position_index, 0],
                    ['mstore', data_pos, 0],
                    ['mstore', c, call_data_char(0)],
                    ['mstore', i, 0],
                    ['mstore', position_offset, 0],
                    ['assert', ['ge', ['mload', c], 192]],  # Must be a list
                    ['if', ['lt', ['mload', c], 248],  # if c < 248:
                        ['seq',
                            ['assert', ['eq', ['calldatasize'], sub(['mload', c], 191)]],  # assert ~calldatasize() == (c - 191)
                            ['mstore', i, 1]],  # i = 1
                        ['seq',
                            # assert ~calldatasize() == (c - 246) + calldatabytes_as_int(1, c - 247)
                            ['assert', ['eq', ['calldatasize'], add(sub(['mload', c], 246), call_data_bytes_as_int(1, sub(['mload', c], 247)))]],
                            ['mstore', i, sub(['mload', c], 246)]]],  # i = c - 246
                    # Main loop
                    # Here, we simultaneously build up data in two places:
                    # (i) starting from memory index 64, a list of 32-byte numbers
                    #     representing the start positions of each value
                    # (ii) starting from memory index 1088, the values, in format
                    #     <length as 32 byte int> <value>, packed one after the other
                    ['repeat', loop_memory_position, 1, 100,
                        ['seq',
                            ['if', ['ge', ['mload', i], 'calldatasize'], 'break'],
                            ['mstore', c, call_data_char(['mload', i])],
                            ['mstore', add(positions, ['mul', ['mload', position_index], 32]), ['mload', data_pos]],
                            ['mstore', position_index, add(['mload', position_index], 1)],
                            ['if', ['lt', ['mload', c], 128],
                                ['seq',
                                    ['mstore', add(data, ['mload', data_pos]), 1],
                                    ['calldatacopy', add(data + 32, ['mload', data_pos]), ['mload', i], 1],
                                    ['mstore', i, add(['mload', i], 1)],
                                    ['mstore', data_pos, add(['mload', data_pos], 33)]],
                                ['if', ['lt', ['mload', c], 184],
                                    ['seq',
                                        ['mstore', add(data, ['mload', data_pos]), sub(['mload', c], 128)],
                                        ['calldatacopy', add(data + 32, ['mload', data_pos]), add(['mload', i], 1), sub(['mload', c], 128)],
                                        ['if', ['eq', ['mload', c], 129],
                                            ['assert', ['ge', call_data_char(add(['mload', i], 1)), 128]]],
                                        ['mstore', i, add(['mload', i], sub(['mload', c], 127))],
                                        ['mstore', data_pos, add(['mload', data_pos], sub(['mload', c], 96))]],
                                    ['if', ['lt', ['mload', c], 192],
                                        ['seq',
                                            ['mstore', L, call_data_bytes_as_int(add(['mload', i], 1), sub(['mload', c], 183))],
                                            ['assert', ['mul', call_data_char(add(['mload', i], 1)), ['ge', ['mload', L], 56]]],
                                            ['mstore', add(data, ['mload', data_pos]), ['mload', L]],
                                            ['calldatacopy', add(data + 32, ['mload', data_pos]), add(['mload', i], sub(['mload', c], 182)), ['mload', L]],
                                            ['mstore', i, add(add(['mload', i], sub(['mload', c], 182)), ['mload', L])],
                                            ['mstore', data_pos, add(['mload', data_pos], add(['mload', L], 32))]],
                                        ['invalid']]]]]],
                    ['assert', ['le', ['mload', position_index], 31]],
                    ['mstore', position_offset, add(['mul', ['mload', position_index], 32], 32)],
                    ['mstore', i, sub(['mload', position_offset], 32)],
                    ['repeat', loop_memory_position, 1, 100,
                        ['seq',
                            ['if', ['slt', ['mload', i], 0], 'break'],
                            ['mstore', add(sub(data, ['mload', position_offset]), ['mload', i]), add(['mload', add(positions, ['mload', i])], ['mload', position_offset])],
                            # ~mstore(data - positionOffset + i, ~mload(positions + i) + positionOffset)
                            ['mstore', i, sub(['mload', i], 32)]]],
                    ['mstore', sub(data, 32), add(['mload', position_offset], ['mload', data_pos])],
                    ['return', sub(data, ['mload', position_offset]), add(['mload', position_offset], ['mload', data_pos])]],
                [0]]]]
)