Пример #1
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
Пример #2
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):
            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(
                    f"List return type {sub_base_type} does not match specified "
                    f"return type, expecting {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(
                    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)
Пример #3
0
 def parse_name(self):
     if self.stmt.id == "vdb":
         return LLLnode('debugger', typ=None, pos=getpos(self.stmt))
     else:
         raise StructureException(
             f"Unsupported statement type: {type(self.stmt)}", self.stmt)
Пример #4
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(
                        '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
Пример #5
0
 def parse_continue(self):
     return LLLnode.from_list('continue', typ=None, pos=getpos(self.stmt))
Пример #6
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, 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], 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], ast.Tuple)) and isinstance(
                        self.stmt.value, 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
Пример #7
0
 def _assert_unreachable(test_expr, msg):
     return LLLnode.from_list(['assert_unreachable', test_expr],
                              typ=None,
                              pos=getpos(msg))
Пример #8
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

    # Node representing the position of the output in memory
    np = context.new_placeholder(ByteArrayType(maxlen=sub_typ_maxlen + 32))

    # 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))
Пример #9
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)

    prev_type = ''
    for i, (expr_arg, arg) in enumerate(zip(expr.args, args)):
        if not isinstance(arg.typ, ByteArrayLike) and not is_base_type(arg.typ, 'bytes32'):
            raise TypeMismatchException("Concat expects string, bytes or bytes32 objects", expr_arg)

        current_type = 'bytes' if isinstance(arg.typ, ByteArrayType) or is_base_type(arg.typ, 'bytes32') else 'string'
        if prev_type and current_type != prev_type:
            raise TypeMismatchException("Concat expects consistant use of string or byte types, user either bytes or string.", expr_arg)
        prev_type = current_type

    if current_type == 'string':
        ReturnType = StringType
    else:
        ReturnType = ByteArrayType

    # 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(ReturnType(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=ReturnType(total_maxlen), location='memory')
        placeholder_node_plus_32 = LLLnode.from_list(['add', ['add', placeholder, '_poz'], 32], typ=ReturnType(total_maxlen), location='memory')
        if isinstance(arg.typ, ReturnType):
            # 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=ReturnType(total_maxlen), location='memory', pos=getpos(expr), annotation='concat'
    )
Пример #10
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))
Пример #11
0
        if denomination % den:
            raise InvalidLiteralException("Too many decimal places: %s" % numstring, expr.args[0])
        sub = num * denomination // den
    elif args[0].typ.is_literal:
        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('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)
Пример #12
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)
Пример #13
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)
Пример #14
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)
Пример #15
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))
Пример #16
0
def avo(arg, ind, pos):
    return unwrap_location(add_variable_offset(arg, LLLnode.from_list(ind, 'int128'), pos=pos))
Пример #17
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))
Пример #18
0
def send(expr, args, kwargs, context):
    to, value = args
    if context.is_constant():
        raise ConstancyViolationException("Cannot send ether inside %s!" % context.pp_constancy(), expr)
    enforce_units(value.typ, expr.args[1], BaseType('uint256', {'wei': 1}))
    return LLLnode.from_list(['assert', ['call', 0, to, value, 0, 0, 0, 0]], typ=None, pos=getpos(expr))
Пример #19
0
    def call(self):
        is_self_function = (isinstance(
            self.stmt.func, ast.Attribute)) and isinstance(
                self.stmt.func.value,
                ast.Name) and self.stmt.func.value.id == "self"

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

        if isinstance(self.stmt.func, 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)
Пример #20
0
def selfdestruct(expr, args, kwargs, context):
    if context.is_constant():
        raise ConstancyViolationException("Cannot %s inside %s!" % (expr.func.id, context.pp_constancy()), expr.func)
    return LLLnode.from_list(['selfdestruct', args[0]], typ=None, pos=getpos(expr))
Пример #21
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)
        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)

            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
Пример #22
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))
Пример #23
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,
                       (ast.Add, ast.Sub, ast.Mult, ast.Div, 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(
             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(
             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))
Пример #24
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 = context.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))
Пример #25
0
 def parse_break(self):
     return LLLnode.from_list('break', typ=None, pos=getpos(self.stmt))
Пример #26
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))
Пример #27
0
 def parse_pass(self):
     return LLLnode.from_list('pass', typ=None, pos=getpos(self.stmt))
Пример #28
0
def bitwise_not(expr, args, kwargs, context):
    return LLLnode.from_list(['not', args[0]], typ=BaseType('uint256'), pos=getpos(expr))
Пример #29
0
def compile_vyper_lll(vyper_code: List[Any]) -> Tuple[bytes, Dict[str, Any]]:
    lll_node = LLLnode.from_list(vyper_code)
    assembly = compile_to_assembly(lll_node)
    code = assembly_to_evm(assembly)
    return code
Пример #30
0
def method_id(expr, args, kwargs, context):
    method_id = fourbytes_to_int(sha3(args[0])[:4])
    return LLLnode(method_id, typ=BaseType('method_id'), pos=getpos(expr))