Example #1
0
def base_type_conversion(orig, frm, to, pos=None):
    orig = unwrap_location(orig)
    if not isinstance(frm,
                      (BaseType, NullType)) or not isinstance(to, BaseType):
        raise TypeMismatchException(
            "Base type conversion from or to non-base type: %r %r" % (frm, to),
            pos)
    elif is_base_type(frm, to.typ) and are_units_compatible(frm, to):
        return LLLnode(orig.value,
                       orig.args,
                       typ=to,
                       add_gas_estimate=orig.add_gas_estimate)
    elif is_base_type(frm, 'num') and is_base_type(
            to, 'decimal') and are_units_compatible(frm, to):
        return LLLnode.from_list(['mul', orig, DECIMAL_DIVISOR],
                                 typ=BaseType('decimal', to.unit,
                                              to.positional))
    elif is_base_type(frm, 'num256') and is_base_type(
            to, 'num') and are_units_compatible(frm, to):
        return LLLnode.from_list(
            ['uclample', orig, ['mload', MemoryPositions.MAXNUM]],
            typ=BaseType("num"))
    elif isinstance(frm, NullType):
        if to.typ not in ('num', 'bool', 'num256', 'address', 'bytes32',
                          'decimal'):
            raise TypeMismatchException(
                "Cannot convert null-type object to type %r" % to, pos)
        return LLLnode.from_list(0, typ=to)
    else:
        raise TypeMismatchException(
            "Typecasting from base type %r to %r unavailable" % (frm, to), pos)
Example #2
0
File: expr.py Project: sdtsui/viper
 def attribute(self):
     # x.balance: balance of address x
     if self.expr.attr == 'balance':
         addr = Expr.parse_value_expr(self.expr.value, self.context)
         if not is_base_type(addr.typ, 'address'):
             raise TypeMismatchException("Type mismatch: balance keyword expects an address as input", self.expr)
         return LLLnode.from_list(['balance', addr], typ=BaseType('num', {'wei': 1}), location=None, pos=getpos(self.expr))
     # x.codesize: codesize of address x
     elif self.expr.attr == 'codesize' or self.expr.attr == 'is_contract':
         addr = Expr.parse_value_expr(self.expr.value, self.context)
         if not is_base_type(addr.typ, 'address'):
             raise TypeMismatchException("Type mismatch: codesize keyword expects an address as input", self.expr)
         if self.expr.attr == 'codesize':
             output_type = 'num'
         else:
             output_type = 'bool'
         return LLLnode.from_list(['extcodesize', addr], typ=BaseType(output_type), location=None, pos=getpos(self.expr))
     # self.x: global attribute
     elif isinstance(self.expr.value, ast.Name) and self.expr.value.id == "self":
         if self.expr.attr not in self.context.globals:
             raise VariableDeclarationException("Persistent variable undeclared: " + self.expr.attr, self.expr)
         var = self.context.globals[self.expr.attr]
         return LLLnode.from_list(var.pos, typ=var.typ, location='storage', pos=getpos(self.expr), annotation='self.' + self.expr.attr)
     # Reserved keywords
     elif isinstance(self.expr.value, ast.Name) and self.expr.value.id in ("msg", "block", "tx"):
         key = self.expr.value.id + "." + self.expr.attr
         if key == "msg.sender":
             return LLLnode.from_list(['caller'], typ='address', pos=getpos(self.expr))
         elif key == "msg.value":
             if not self.context.is_payable:
                 raise NonPayableViolationException("Cannot use msg.value in a non-payable function", self.expr)
             return LLLnode.from_list(['callvalue'], typ=BaseType('num', {'wei': 1}), pos=getpos(self.expr))
         elif key == "msg.gas":
             return LLLnode.from_list(['gas'], typ='num', pos=getpos(self.expr))
         elif key == "block.difficulty":
             return LLLnode.from_list(['difficulty'], typ='num', pos=getpos(self.expr))
         elif key == "block.timestamp":
             return LLLnode.from_list(['timestamp'], typ=BaseType('num', {'sec': 1}, True), pos=getpos(self.expr))
         elif key == "block.coinbase":
             return LLLnode.from_list(['coinbase'], typ='address', pos=getpos(self.expr))
         elif key == "block.number":
             return LLLnode.from_list(['number'], typ='num', pos=getpos(self.expr))
         elif key == "block.prevhash":
             return LLLnode.from_list(['blockhash', ['sub', 'number', 1]], typ='bytes32', pos=getpos(self.expr))
         elif key == "tx.origin":
             return LLLnode.from_list(['origin'], typ='address', pos=getpos(self.expr))
         else:
             raise Exception("Unsupported keyword: " + key)
     # Other variables
     else:
         sub = Expr.parse_variable_location(self.expr.value, self.context)
         if not isinstance(sub.typ, StructType):
             raise TypeMismatchException("Type mismatch: member variable access not expected", self.expr.value)
         attrs = sorted(sub.typ.members.keys())
         if self.expr.attr not in attrs:
             raise TypeMismatchException("Member %s not found. Only the following available: %s" % (self.expr.attr, " ".join(attrs)), self.expr)
         return add_variable_offset(sub, self.expr.attr)
Example #3
0
def pack_logging_data(expected_data, args, context):
    # Checks to see if there's any data
    if not args:
        return ['seq'], 0, None, 0
    holder = ['seq']
    maxlen = len(args) * 32  # total size of all packed args (upper limit)
    dynamic_offset_counter = context.new_placeholder(BaseType(32))
    dynamic_placeholder = context.new_placeholder(BaseType(32))

    # Populate static placeholders.
    placeholder_map = {}
    for i, (arg, data) in enumerate(zip(args, expected_data)):
        typ = data.typ
        placeholder = context.new_placeholder(BaseType(32))
        placeholder_map[i] = placeholder
        if not isinstance(typ, ByteArrayType):
            holder, maxlen = pack_args_by_32(holder, maxlen, arg, typ, context,
                                             placeholder)

    # Dynamic position starts right after the static args.
    holder.append(LLLnode.from_list(['mstore', dynamic_offset_counter,
                                     maxlen]))

    # Calculate maximum dynamic offset placeholders, used for gas estimation.
    for i, (arg, data) in enumerate(zip(args, expected_data)):
        typ = data.typ
        if isinstance(typ, ByteArrayType):
            maxlen += 32 + ceil32(typ.maxlen)

    # Obtain the start of the arg section.
    if isinstance(expected_data[0].typ, ListType):
        datamem_start = holder[1].to_list()[1][0]
    else:
        datamem_start = dynamic_placeholder + 32

    # Copy necessary data into allocated dynamic section.
    for i, (arg, data) in enumerate(zip(args, expected_data)):
        typ = data.typ
        pack_args_by_32(holder=holder,
                        maxlen=maxlen,
                        arg=arg,
                        typ=typ,
                        context=context,
                        placeholder=placeholder_map[i],
                        datamem_start=datamem_start,
                        dynamic_offset_counter=dynamic_offset_counter)

    return holder, maxlen, dynamic_offset_counter, datamem_start
Example #4
0
 def from_list(cls,
               obj,
               typ=None,
               location=None,
               pos=None,
               annotation=None,
               mutable=True,
               add_gas_estimate=0):
     if isinstance(typ, str):
         typ = BaseType(typ)
     if isinstance(obj, LLLnode):
         if obj.pos is None:
             obj.pos = pos
         if obj.location is None:
             obj.location = location
         return obj
     elif not isinstance(obj, list):
         return cls(obj, [],
                    typ,
                    location,
                    pos,
                    annotation,
                    mutable,
                    add_gas_estimate=add_gas_estimate)
     else:
         return cls(obj[0], [cls.from_list(o, pos=pos) for o in obj[1:]],
                    typ,
                    location,
                    pos,
                    annotation,
                    mutable,
                    add_gas_estimate=add_gas_estimate)
Example #5
0
def pack_args_by_32(holder, maxlen, arg, typ, context, placeholder):
    if isinstance(typ, BaseType):
        input = parse_expr(arg, context)
        input = base_type_conversion(input, input.typ, typ)
        holder.append(
            LLLnode.from_list(['mstore', placeholder, input],
                              typ=typ,
                              location='memory'))
    elif isinstance(typ, ByteArrayType):
        bytez = b''
        # String literals
        if isinstance(arg, ast.Str):
            if len(arg.s) > typ.maxlen:
                raise TypeMismatchException(
                    "Data input bytes are to big: %r %r" % (len(arg.s), typ))
            for c in arg.s:
                if ord(c) >= 256:
                    raise InvalidLiteralException(
                        "Cannot insert special character %r into byte array" %
                        c)
                bytez += bytes([ord(c)])
            bytez_length = len(bytez)
            if len(bytez) > 32:
                raise InvalidLiteralException(
                    "Can only log a maximum of 32 bytes at a time.")
            holder.append(
                LLLnode.from_list([
                    'mstore', placeholder,
                    bytes_to_int(bytez + b'\x00' * (32 - bytez_length))
                ],
                                  typ=typ,
                                  location='memory'))
        # Variables
        else:
            input = parse_expr(arg, context)
            if input.typ.maxlen > typ.maxlen:
                raise TypeMismatchException(
                    "Data input bytes are to big: %r %r" % (input.typ, typ))
            if arg.id in context.vars:
                size = context.vars[arg.id].size
                holder.append(
                    LLLnode.from_list([
                        'mstore', placeholder,
                        byte_array_to_num(parse_expr(arg, context), arg,
                                          'num256', size)
                    ],
                                      typ=typ,
                                      location='memory'))
    elif isinstance(typ, ListType):
        maxlen += (typ.count - 1) * 32
        typ = typ.subtype
        holder, maxlen = pack_args_by_32(holder, maxlen, arg.elts[0], typ,
                                         context, placeholder)
        for j, arg2 in enumerate(arg.elts[1:]):
            holder, maxlen = pack_args_by_32(
                holder, maxlen, arg2, typ, context,
                context.new_placeholder(BaseType(32)))
    return holder, maxlen
Example #6
0
def byte_array_to_num(
    arg,
    expr,
    out_type,
    offset=32,
):
    if arg.location == "memory":
        lengetter = LLLnode.from_list(['mload', '_sub'], typ=BaseType('num'))
        first_el_getter = LLLnode.from_list(['mload', ['add', 32, '_sub']],
                                            typ=BaseType('num'))
    elif arg.location == "storage":
        lengetter = LLLnode.from_list(['sload', ['sha3_32', '_sub']],
                                      typ=BaseType('num'))
        first_el_getter = LLLnode.from_list(
            ['sload', ['add', 1, ['sha3_32', '_sub']]], typ=BaseType('num'))
    if out_type == 'num':
        result = [
            'clamp', ['mload', MemoryPositions.MINNUM],
            ['div', '_el1', ['exp', 256, ['sub', 32, '_len']]],
            ['mload', MemoryPositions.MAXNUM]
        ]
    elif out_type == 'num256':
        result = ['div', '_el1', ['exp', 256, ['sub', offset, '_len']]]
    return LLLnode.from_list(
        [
            'with', '_sub', arg,
            [
                'with', '_el1', first_el_getter,
                [
                    'with', '_len', ['clamp', 0, lengetter, 32],
                    [
                        'seq',
                        [
                            'assert',
                            [
                                'or', ['iszero', '_len'],
                                ['div', '_el1', ['exp', 256, 31]]
                            ]
                        ], result
                    ]
                ]
            ]
        ],
        typ=BaseType(out_type),
        annotation='bytearray to number, verify no leading zbytes')
Example #7
0
def add_globals_and_events(_contracts, _defs, _events, _getters, _globals,
                           item):
    if item.value is not None:
        raise StructureException('May not assign value whilst defining type',
                                 item)
    elif isinstance(item.annotation,
                    ast.Call) and item.annotation.func.id == "__log__":
        if _globals or len(_defs):
            raise StructureException(
                "Events must all come before global declarations and function definitions",
                item)
        _events.append(item)
    elif not isinstance(item.target, ast.Name):
        raise StructureException(
            "Can only assign type to variable in top-level statement", item)
    # Check if variable name is reserved or invalid
    elif not is_varname_valid(item.target.id):
        raise VariableDeclarationException(
            "Variable name invalid or reserved: ", item.target)
    # Check if global already exists, if so error
    elif item.target.id in _globals:
        raise VariableDeclarationException(
            "Cannot declare a persistent variable twice!", item.target)
    elif len(_defs):
        raise StructureException(
            "Global variables must all come before function definitions", item)
    # If the type declaration is of the form public(<type here>), then proceed with
    # the underlying type but also add getters
    elif isinstance(item.annotation,
                    ast.Call) and item.annotation.func.id == "address":
        if len(item.annotation.args) != 1:
            raise StructureException("Address expects one arg (the type)")
        if item.annotation.args[0].id not in premade_contracts:
            raise VariableDeclarationException(
                "Unsupported premade contract declaration",
                item.annotation.args[0])
        premade_contract = premade_contracts[item.annotation.args[0].id]
        _contracts[item.target.id] = add_contract(premade_contract.body)
        _globals[item.target.id] = VariableRecord(item.target.id,
                                                  len(_globals),
                                                  BaseType('address'), True)
    elif isinstance(item.annotation,
                    ast.Call) and item.annotation.func.id == "public":
        if len(item.annotation.args) != 1:
            raise StructureException("Public expects one arg (the type)")
        typ = parse_type(item.annotation.args[0], 'storage')
        _globals[item.target.id] = VariableRecord(item.target.id,
                                                  len(_globals), typ, True)
        # Adding getters here
        for getter in mk_getter(item.target.id, typ):
            _getters.append(parse_line('\n' * (item.lineno - 1) + getter))
            _getters[-1].pos = getpos(item)
    else:
        _globals[item.target.id] = VariableRecord(
            item.target.id, len(_globals),
            parse_type(item.annotation, 'storage'), True)
    return _contracts, _events, _globals, _getters
Example #8
0
File: expr.py Project: sdtsui/viper
    def build_in_comparator(self):
        from viper.parser.parser import make_setter
        left = Expr(self.expr.left, self.context).lll_node
        right = Expr(self.expr.comparators[0], self.context).lll_node

        result_placeholder = self.context.new_placeholder(BaseType('bool'))
        setter = []

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

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

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

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

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

        return o
Example #9
0
def pack_logging_data(types, args, context):
    # Checks to see if there's any data
    if not args:
        return ['seq'], 0, 0
    holder = ['seq']
    maxlen = len(args) * 32
    for i, (arg, typ) in enumerate(zip(args, types)):
        holder, maxlen = pack_args_by_32(holder, maxlen, arg, typ, context,
                                         context.new_placeholder(BaseType(32)))
    return holder, maxlen, holder[1].to_list()[1][0]
Example #10
0
 def number(self):
     orignum = get_original_if_0x_prefixed(self.expr, self.context)
     if orignum is None and isinstance(self.expr.n, int):
         if not (SizeLimits.MINNUM <= self.expr.n <= SizeLimits.MAXNUM):
             raise InvalidLiteralException(
                 "Number out of range: " + str(self.expr.n), self.expr)
         return LLLnode.from_list(self.expr.n,
                                  typ=BaseType('num', None),
                                  pos=getpos(self.expr))
     elif isinstance(self.expr.n, float):
         numstring, num, den = get_number_as_fraction(
             self.expr, self.context)
         if not (SizeLimits.MINNUM * den < num < SizeLimits.MAXNUM * den):
             raise InvalidLiteralException(
                 "Number out of range: " + numstring, self.expr)
         if DECIMAL_DIVISOR % den:
             raise InvalidLiteralException(
                 "Too many decimal places: " + numstring, self.expr)
         return LLLnode.from_list(num * DECIMAL_DIVISOR // den,
                                  typ=BaseType('decimal', None),
                                  pos=getpos(self.expr))
     elif len(orignum) == 42:
         if checksum_encode(orignum) != orignum:
             raise InvalidLiteralException(
                 "Address checksum mismatch. If you are sure this is the "
                 "right address, the correct checksummed form is: " +
                 checksum_encode(orignum), self.expr)
         return LLLnode.from_list(self.expr.n,
                                  typ=BaseType('address'),
                                  pos=getpos(self.expr))
     elif len(orignum) == 66:
         return LLLnode.from_list(self.expr.n,
                                  typ=BaseType('bytes32'),
                                  pos=getpos(self.expr))
     else:
         raise InvalidLiteralException(
             "Cannot read 0x value with length %d. Expecting 42 (address incl 0x) or 66 (bytes32 incl 0x)"
             % len(orignum), self.expr)
Example #11
0
 def arithmetic(self):
     left = Expr.parse_value_expr(self.expr.left, self.context)
     right = Expr.parse_value_expr(self.expr.right, self.context)
     if not is_numeric_type(left.typ) or not is_numeric_type(right.typ):
         raise TypeMismatchException(
             "Unsupported types for arithmetic op: %r %r" %
             (left.typ, right.typ), self.expr)
     ltyp, rtyp = left.typ.typ, right.typ.typ
     if isinstance(self.expr.op, (ast.Add, ast.Sub)):
         if left.typ.unit != right.typ.unit and left.typ.unit is not None and right.typ.unit is not None:
             raise TypeMismatchException(
                 "Unit mismatch: %r %r" % (left.typ.unit, right.typ.unit),
                 self.expr)
         if left.typ.positional and right.typ.positional and isinstance(
                 self.expr.op, ast.Add):
             raise TypeMismatchException("Cannot add two positional units!",
                                         self.expr)
         new_unit = left.typ.unit or right.typ.unit
         new_positional = left.typ.positional ^ right.typ.positional  # xor, as subtracting two positionals gives a delta
         op = 'add' if isinstance(self.expr.op, ast.Add) else 'sub'
         if ltyp == rtyp:
             o = LLLnode.from_list([op, left, right],
                                   typ=BaseType(ltyp, new_unit,
                                                new_positional),
                                   pos=getpos(self.expr))
         elif ltyp == 'num' and rtyp == 'decimal':
             o = LLLnode.from_list(
                 [op, ['mul', left, DECIMAL_DIVISOR], right],
                 typ=BaseType('decimal', new_unit, new_positional),
                 pos=getpos(self.expr))
         elif ltyp == 'decimal' and rtyp == 'num':
             o = LLLnode.from_list(
                 [op, left, ['mul', right, DECIMAL_DIVISOR]],
                 typ=BaseType('decimal', new_unit, new_positional),
                 pos=getpos(self.expr))
         else:
             raise Exception("How did I get here? %r %r" % (ltyp, rtyp))
     elif isinstance(self.expr.op, ast.Mult):
         if left.typ.positional or right.typ.positional:
             raise TypeMismatchException(
                 "Cannot multiply positional values!", self.expr)
         new_unit = combine_units(left.typ.unit, right.typ.unit)
         if ltyp == rtyp == 'num':
             o = LLLnode.from_list(['mul', left, right],
                                   typ=BaseType('num', new_unit),
                                   pos=getpos(self.expr))
         elif ltyp == rtyp == 'decimal':
             o = LLLnode.from_list([
                 'with', 'r', right,
                 [
                     'with', 'l', left,
                     [
                         'with', 'ans', ['mul', 'l', 'r'],
                         [
                             'seq',
                             [
                                 'assert',
                                 [
                                     'or', [
                                         'eq', ['sdiv', 'ans', 'l'], 'r'
                                     ], ['not', 'l']
                                 ]
                             ], ['sdiv', 'ans', DECIMAL_DIVISOR]
                         ]
                     ]
                 ]
             ],
                                   typ=BaseType('decimal', new_unit),
                                   pos=getpos(self.expr))
         elif (ltyp == 'num' and rtyp == 'decimal') or (ltyp == 'decimal'
                                                        and rtyp == 'num'):
             o = LLLnode.from_list([
                 'with', 'r', right,
                 [
                     'with', 'l', left,
                     [
                         'with', 'ans', ['mul', 'l', 'r'],
                         [
                             'seq',
                             [
                                 'assert',
                                 [
                                     'or', [
                                         'eq', ['sdiv', 'ans', 'l'], 'r'
                                     ], ['not', 'l']
                                 ]
                             ], 'ans'
                         ]
                     ]
                 ]
             ],
                                   typ=BaseType('decimal', new_unit),
                                   pos=getpos(self.expr))
     elif isinstance(self.expr.op, ast.Div):
         if left.typ.positional or right.typ.positional:
             raise TypeMismatchException("Cannot divide positional values!",
                                         self.expr)
         new_unit = combine_units(left.typ.unit, right.typ.unit, div=True)
         if rtyp == 'num':
             o = LLLnode.from_list(['sdiv', left, ['clamp_nonzero', right]],
                                   typ=BaseType(ltyp, new_unit),
                                   pos=getpos(self.expr))
         elif ltyp == rtyp == 'decimal':
             o = LLLnode.from_list([
                 'with', 'l', left,
                 [
                     'with', 'r', ['clamp_nonzero', right],
                     ['sdiv', ['mul', 'l', DECIMAL_DIVISOR], 'r']
                 ]
             ],
                                   typ=BaseType('decimal', new_unit),
                                   pos=getpos(self.expr))
         elif ltyp == 'num' and rtyp == 'decimal':
             o = LLLnode.from_list([
                 'sdiv', ['mul', left, DECIMAL_DIVISOR**2],
                 ['clamp_nonzero', right]
             ],
                                   typ=BaseType('decimal', new_unit),
                                   pos=getpos(self.expr))
     elif isinstance(self.expr.op, ast.Mod):
         if left.typ.positional or right.typ.positional:
             raise TypeMismatchException(
                 "Cannot use positional values as modulus arguments!",
                 self.expr)
         if left.typ.unit != right.typ.unit and left.typ.unit is not None and right.typ.unit is not None:
             raise TypeMismatchException(
                 "Modulus arguments must have same unit", self.expr)
         new_unit = left.typ.unit or right.typ.unit
         if ltyp == rtyp:
             o = LLLnode.from_list(['smod', left, ['clamp_nonzero', right]],
                                   typ=BaseType(ltyp, new_unit),
                                   pos=getpos(self.expr))
         elif ltyp == 'decimal' and rtyp == 'num':
             o = LLLnode.from_list([
                 'smod', left,
                 ['mul', ['clamp_nonzero', right], DECIMAL_DIVISOR]
             ],
                                   typ=BaseType('decimal', new_unit),
                                   pos=getpos(self.expr))
         elif ltyp == 'num' and rtyp == 'decimal':
             o = LLLnode.from_list([
                 'smod', ['mul', left, DECIMAL_DIVISOR],
                 ['clamp_nonzero', right]
             ],
                                   typ=BaseType('decimal', new_unit),
                                   pos=getpos(self.expr))
     elif isinstance(self.expr.op, ast.Pow):
         if left.typ.positional or right.typ.positional:
             raise TypeMismatchException(
                 "Cannot use positional values as exponential arguments!",
                 self.expr)
         if right.typ.unit:
             raise TypeMismatchException(
                 "Cannot use unit values as exponents", self.expr)
         if ltyp != 'num' and isinstance(self.expr.right, ast.Name):
             raise TypeMismatchException(
                 "Cannot use dynamic values as exponents, for unit base types",
                 self.expr)
         if ltyp == rtyp == 'num':
             new_unit = left.typ.unit
             if left.typ.unit and not isinstance(self.expr.right, ast.Name):
                 new_unit = {
                     left.typ.unit.copy().popitem()[0]: self.expr.right.n
                 }
             o = LLLnode.from_list(['exp', left, right],
                                   typ=BaseType('num', new_unit),
                                   pos=getpos(self.expr))
         else:
             raise TypeMismatchException(
                 'Only whole number exponents are supported', self.expr)
     else:
         raise Exception("Unsupported binop: %r" % self.expr.op)
     if o.typ.typ == 'num':
         return LLLnode.from_list([
             'clamp', ['mload', MemoryPositions.MINNUM], o,
             ['mload', MemoryPositions.MAXNUM]
         ],
                                  typ=o.typ,
                                  pos=getpos(self.expr))
     elif o.typ.typ == 'decimal':
         return LLLnode.from_list([
             'clamp', ['mload', MemoryPositions.MINDECIMAL], o,
             ['mload', MemoryPositions.MAXDECIMAL]
         ],
                                  typ=o.typ,
                                  pos=getpos(self.expr))
     else:
         raise Exception("%r %r" % (o, o.typ))
Example #12
0
    def parse_for_list(self):
        from .parser import (parse_body, make_setter)

        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))
        i_pos = self.context.new_variable('_index_for_' + varname,
                                          BaseType(subtype))
        self.context.forvars[varname] = True
        if iter_var_type:  # Is a list that is already allocated to memory.
            self.context.set_in_for_loop(
                self.stmt.iter.id
            )  # make sure list cannot be altered whilst iterating.
            iter_var = self.context.vars.get(self.stmt.iter.id)
            body = [
                'seq',
                [
                    'mstore', value_pos,
                    [
                        'mload',
                        ['add', iter_var.pos, ['mul', ['mload', i_pos], 32]]
                    ]
                ],
                parse_body(self.stmt.body, self.context)
            ]
            o = LLLnode.from_list(['repeat', i_pos, 0, iter_var.size, body],
                                  typ=None,
                                  pos=getpos(self.stmt))
            self.context.remove_in_for_loop(self.stmt.iter.id)
        elif isinstance(self.stmt.iter,
                        ast.List):  # List gets defined in the for statement.
            # 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')
            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))
        elif isinstance(self.stmt.iter,
                        ast.Attribute):  # List is contained in storage.
            count = iter_list_node.typ.count
            self.context.set_in_for_loop(
                iter_list_node.annotation
            )  # make sure list cannot be altered whilst iterating.
            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))
            self.context.remove_in_for_loop(iter_list_node.annotation)
        del self.context.vars[varname]
        del self.context.vars['_index_for_' + varname]
        del self.context.forvars[varname]
        return o
Example #13
0
def add_variable_offset(parent, key):
    typ, location = parent.typ, parent.location
    if isinstance(typ, (StructType, TupleType)):
        if isinstance(typ, StructType):
            if not isinstance(key, str):
                raise TypeMismatchException("Expecting a member variable access; cannot access element %r" % key)
            if key not in typ.members:
                raise TypeMismatchException("Object does not have member variable %s" % key)
            subtype = typ.members[key]
            attrs = sorted(typ.members.keys())

            if key not in attrs:
                raise TypeMismatchException("Member %s not found. Only the following available: %s" % (key, " ".join(attrs)))
            index = attrs.index(key)
            annotation = key
        else:
            if not isinstance(key, int):
                raise TypeMismatchException("Expecting a static index; cannot access element %r" % key)
            attrs = list(range(len(typ.members)))
            index = key
            annotation = None
        if location == 'storage':
            return LLLnode.from_list(['add', ['sha3_32', parent], LLLnode.from_list(index, annotation=annotation)],
                                     typ=subtype,
                                     location='storage')
        elif location == 'storage_prehashed':
            return LLLnode.from_list(['add', parent, LLLnode.from_list(index, annotation=annotation)],
                                     typ=subtype,
                                     location='storage')
        elif location == 'memory':
            offset = 0
            for i in range(index):
                offset += 32 * get_size_of_type(typ.members[attrs[i]])
            return LLLnode.from_list(['add', offset, parent],
                                     typ=typ.members[key],
                                     location='memory',
                                     annotation=annotation)
        else:
            raise TypeMismatchException("Not expecting a member variable access")
    elif isinstance(typ, (ListType, MappingType)):
        if isinstance(typ, ListType):
            subtype = typ.subtype
            sub = ['uclamplt', base_type_conversion(key, key.typ, BaseType('num')), typ.count]
        elif isinstance(typ, MappingType) and isinstance(key.typ, ByteArrayType):
            if not isinstance(typ.keytype, ByteArrayType) or (typ.keytype.maxlen < key.typ.maxlen):
                raise TypeMismatchException('Mapping keys of bytes cannot be cast, use exact same bytes type of: %s', str(typ.keytype))
            subtype = typ.valuetype
            if len(key.args[0].args) == 3:  # handle bytes literal.
                sub = LLLnode.from_list([
                    'seq',
                    key,
                    ['sha3', ['add', key.args[0].args[-1], 32], ceil32(key.typ.maxlen)]
                ])
            else:
                sub = LLLnode.from_list(['sha3', ['add', key.args[0].value, 32], ceil32(key.typ.maxlen)])
        else:
            subtype = typ.valuetype
            sub = base_type_conversion(key, key.typ, typ.keytype)
        if location == 'storage':
            return LLLnode.from_list(['add', ['sha3_32', parent], sub],
                                     typ=subtype,
                                     location='storage')
        elif location == 'storage_prehashed':
            return LLLnode.from_list(['add', parent, sub],
                                     typ=subtype,
                                     location='storage')
        elif location == 'memory':
            if isinstance(typ, MappingType):
                raise TypeMismatchException("Can only have fixed-side arrays in memory, not mappings")
            offset = 32 * get_size_of_type(subtype)
            return LLLnode.from_list(['add', ['mul', offset, sub], parent],
                                      typ=subtype,
                                      location='memory')
        else:
            raise TypeMismatchException("Not expecting an array access ")
    else:
        raise TypeMismatchException("Cannot access the child of a constant variable! %r" % typ)
Example #14
0
def get_length(arg):
    if arg.location == "memory":
        return LLLnode.from_list(['mload', arg], typ=BaseType('num'))
    elif arg.location == "storage":
        return LLLnode.from_list(['sload', ['sha3_32', arg]], typ=BaseType('num'))
Example #15
0
def pack_args_by_32(holder,
                    maxlen,
                    arg,
                    typ,
                    context,
                    placeholder,
                    dynamic_offset_counter=None,
                    datamem_start=None):
    """
    Copy necessary variables to pre-allocated memory section.

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

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

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

            holder.append(source_expr.lll_node)

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

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

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

    return holder, maxlen
Example #16
0
    def parse_for(self):
        from .parser import (
            parse_body, )
        # Type 0 for, eg. for i in list(): ...
        if self._is_list_iter():
            return self.parse_for_list()

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

        # Type 1 for, eg. for i in range(10): ...
        if len(self.stmt.iter.args) == 1:
            if not isinstance(self.stmt.iter.args[0], ast.Num):
                raise StructureException("Range only accepts literal values",
                                         self.stmt.iter)
            start = LLLnode.from_list(0, typ='num', pos=getpos(self.stmt))
            rounds = self.stmt.iter.args[0].n
        elif isinstance(self.stmt.iter.args[0], ast.Num) and isinstance(
                self.stmt.iter.args[1], ast.Num):
            # Type 2 for, eg. for i in range(100, 110): ...
            start = LLLnode.from_list(self.stmt.iter.args[0].n,
                                      typ='num',
                                      pos=getpos(self.stmt))
            rounds = LLLnode.from_list(self.stmt.iter.args[1].n -
                                       self.stmt.iter.args[0].n,
                                       typ='num',
                                       pos=getpos(self.stmt))
        else:
            # Type 3 for, eg. for i in range(x, x + 10): ...
            if not isinstance(self.stmt.iter.args[1],
                              ast.BinOp) or not isinstance(
                                  self.stmt.iter.args[1].op, ast.Add):
                raise StructureException(
                    "Two-arg for statements must be of the form `for i in range(start, start + rounds): ...`",
                    self.stmt.iter.args[1])
            if ast.dump(self.stmt.iter.args[0]) != ast.dump(
                    self.stmt.iter.args[1].left):
                raise StructureException(
                    "Two-arg for statements of the form `for i in range(x, x + y): ...` must have x identical in both places: %r %r"
                    % (ast.dump(self.stmt.iter.args[0]),
                       ast.dump(self.stmt.iter.args[1].left)), self.stmt.iter)
            if not isinstance(self.stmt.iter.args[1].right, ast.Num):
                raise StructureException("Range only accepts literal values",
                                         self.stmt.iter.args[1])
            start = Expr.parse_value_expr(self.stmt.iter.args[0], self.context)
            rounds = self.stmt.iter.args[1].right.n
        varname = self.stmt.target.id
        pos = self.context.new_variable(varname, BaseType('num'))
        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
Example #17
0
def pack_args_by_32(holder, maxlen, arg, typ, context, placeholder):
    if isinstance(typ, BaseType):
        value = parse_expr(arg, context)
        value = base_type_conversion(value, value.typ, typ)
        holder.append(
            LLLnode.from_list(['mstore', placeholder, value],
                              typ=typ,
                              location='memory'))
    elif isinstance(typ, ByteArrayType):
        bytez = b''
        # Bytes from Storage
        if isinstance(arg, ast.Attribute) and arg.value.id == 'self':
            stor_bytes = context.globals[arg.attr]
            if stor_bytes.typ.maxlen > 32:
                raise TypeMismatchException(
                    "Can only log a maximum of 32 bytes at a time.")
            arg2 = LLLnode.from_list([
                'sload', ['add', ['sha3_32',
                                  Expr(arg, context).lll_node], 1]
            ],
                                     typ=BaseType(32))
            holder, maxlen = pack_args_by_32(
                holder, maxlen, arg2, BaseType(32), context,
                context.new_placeholder(BaseType(32)))
        # String literals
        elif isinstance(arg, ast.Str):
            if len(arg.s) > typ.maxlen:
                raise TypeMismatchException(
                    "Data input bytes are to big: %r %r" % (len(arg.s), typ))
            for c in arg.s:
                if ord(c) >= 256:
                    raise InvalidLiteralException(
                        "Cannot insert special character %r into byte array" %
                        c)
                bytez += bytes([ord(c)])
            bytez_length = len(bytez)
            if len(bytez) > 32:
                raise InvalidLiteralException(
                    "Can only log a maximum of 32 bytes at a time.")
            holder.append(
                LLLnode.from_list([
                    'mstore', placeholder,
                    bytes_to_int(bytez + b'\x00' * (32 - bytez_length))
                ],
                                  typ=typ,
                                  location='memory'))
        # Variables
        else:
            value = parse_expr(arg, context)
            if value.typ.maxlen > typ.maxlen:
                raise TypeMismatchException(
                    "Data input bytes are to big: %r %r" % (value.typ, typ))
            holder.append(
                LLLnode.from_list(
                    ['mstore', placeholder, ['mload', ['add', value, 32]]],
                    typ=typ,
                    location='memory'))
    elif isinstance(typ, ListType):
        maxlen += (typ.count - 1) * 32
        typ = typ.subtype

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

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

    return holder, maxlen
Example #18
0
def pack_args_by_32(holder, maxlen, arg, typ, context, placeholder):
    if isinstance(typ, BaseType):
        value = parse_expr(arg, context)
        value = base_type_conversion(value, value.typ, typ)
        holder.append(
            LLLnode.from_list(['mstore', placeholder, value],
                              typ=typ,
                              location='memory'))
    elif isinstance(typ, ByteArrayType):
        bytez = b''
        # String literals
        if isinstance(arg, ast.Str):
            if len(arg.s) > typ.maxlen:
                raise TypeMismatchException(
                    "Data input bytes are to big: %r %r" % (len(arg.s), typ))
            for c in arg.s:
                if ord(c) >= 256:
                    raise InvalidLiteralException(
                        "Cannot insert special character %r into byte array" %
                        c)
                bytez += bytes([ord(c)])
            bytez_length = len(bytez)
            if len(bytez) > 32:
                raise InvalidLiteralException(
                    "Can only log a maximum of 32 bytes at a time.")
            holder.append(
                LLLnode.from_list([
                    'mstore', placeholder,
                    bytes_to_int(bytez + b'\x00' * (32 - bytez_length))
                ],
                                  typ=typ,
                                  location='memory'))
        # Variables
        else:
            value = parse_expr(arg, context)
            if value.typ.maxlen > typ.maxlen:
                raise TypeMismatchException(
                    "Data input bytes are to big: %r %r" % (value.typ, typ))
            holder.append(
                LLLnode.from_list(
                    ['mstore', placeholder, ['mload', ['add', value, 32]]],
                    typ=typ,
                    location='memory'))
    elif isinstance(typ, ListType):
        maxlen += (typ.count - 1) * 32
        typ = typ.subtype

        if isinstance(arg, ast.Name):
            size = context.vars[arg.id].size
            pos = context.vars[arg.id].pos
            for i in range(0, size):
                offset = 32 * i
                arg2 = LLLnode.from_list(pos + offset,
                                         typ=typ,
                                         location='memory')
                holder, maxlen = pack_args_by_32(
                    holder, maxlen, arg2, typ, context,
                    context.new_placeholder(BaseType(32)))
        else:  # is list literal.
            holder, maxlen = pack_args_by_32(holder, maxlen, arg.elts[0], typ,
                                             context, placeholder)
            for j, arg2 in enumerate(arg.elts[1:]):
                holder, maxlen = pack_args_by_32(
                    holder, maxlen, arg2, typ, context,
                    context.new_placeholder(BaseType(32)))

    return holder, maxlen