Beispiel #1
0
 def hexstring(self):
     orignum = self.expr.value
     if len(orignum) == 42:
         if checksum_encode(orignum) != orignum:
             raise InvalidLiteral(
                 "Address checksum mismatch. If you are sure this is the "
                 f"right address, the correct checksummed form is: {checksum_encode(orignum)}",
                 self.expr
             )
         return LLLnode.from_list(
             int(self.expr.value, 16),
             typ=BaseType('address', is_literal=True),
             pos=getpos(self.expr),
         )
     elif len(orignum) == 66:
         return LLLnode.from_list(
             int(self.expr.value, 16),
             typ=BaseType('bytes32', is_literal=True),
             pos=getpos(self.expr),
         )
     else:
         raise InvalidLiteral(
             f"Cannot read 0x value with length {len(orignum)}. Expecting 42 (address "
             "incl 0x) or 66 (bytes32 incl 0x)",
             self.expr
         )
Beispiel #2
0
    def variables(self):

        if self.expr.id == 'self':
            return LLLnode.from_list(['address'], typ='address', pos=getpos(self.expr))
        elif self.expr.id in self.context.vars:
            var = self.context.vars[self.expr.id]
            return LLLnode.from_list(
                var.pos,
                typ=var.typ,
                location=var.location,  # either 'memory' or 'calldata' storage is handled above.
                pos=getpos(self.expr),
                annotation=self.expr.id,
                mutable=var.mutable,
            )

        elif self.expr.id in BUILTIN_CONSTANTS:
            obj, typ = BUILTIN_CONSTANTS[self.expr.id]
            return LLLnode.from_list(
                [obj],
                typ=BaseType(typ, is_literal=True),
                pos=getpos(self.expr))
        elif self.context.constants.ast_is_constant(self.expr):
            return self.context.constants.get_constant(self.expr.id, self.context)
        else:
            raise VariableDeclarationException(f"Undeclared variable: {self.expr.id}", self.expr)
Beispiel #3
0
    def unary_operations(self):
        operand = Expr.parse_value_expr(self.expr.operand, self.context)
        if isinstance(self.expr.op, sri_ast.Not):
            if isinstance(operand.typ, BaseType) and operand.typ.typ == 'bool':
                return LLLnode.from_list(["iszero", operand], typ='bool', pos=getpos(self.expr))
            else:
                raise TypeMismatch(
                    f"Only bool is supported for not operation, {operand.typ} supplied.",
                    self.expr,
                )
        elif isinstance(self.expr.op, sri_ast.USub):
            if not is_numeric_type(operand.typ):
                raise TypeMismatch(
                    f"Unsupported type for negation: {operand.typ}",
                    self.expr,
                )

            # Clamp on minimum integer value as we cannot negate that value
            # (all other integer values are fine)
            min_int_val = get_min_val_for_type(operand.typ.typ)
            return LLLnode.from_list(
                    ["sub", 0, ["clampgt", operand, min_int_val]],
                    typ=operand.typ,
                    pos=getpos(self.expr)
                )
        else:
            raise StructureException("Only the 'not' or 'neg' unary operators are supported")
Beispiel #4
0
def keccak256_helper(expr, args, kwargs, context):
    sub = args[0]
    # Can hash literals
    if isinstance(sub, bytes):
        return LLLnode.from_list(bytes_to_int(keccak256(sub)),
                                 typ=BaseType('bytes32'),
                                 pos=getpos(expr))
    # Can hash bytes32 objects
    if is_base_type(sub.typ, 'bytes32'):
        return LLLnode.from_list(
            [
                'seq', ['mstore', MemoryPositions.FREE_VAR_SPACE, sub],
                ['sha3', MemoryPositions.FREE_VAR_SPACE, 32]
            ],
            typ=BaseType('bytes32'),
            pos=getpos(expr),
        )
    # Copy the data to an in-memory array
    if sub.location == "memory":
        # If we are hashing a value in memory, no need to copy it, just hash in-place
        return LLLnode.from_list(
            [
                'with', '_sub', sub,
                ['sha3', ['add', '_sub', 32], ['mload', '_sub']]
            ],
            typ=BaseType('bytes32'),
            pos=getpos(expr),
        )
    elif sub.location == "storage":
        lengetter = LLLnode.from_list(['sload', ['sha3_32', '_sub']],
                                      typ=BaseType('int128'))
    else:
        # This should never happen, but just left here for future compiler-writers.
        raise Exception(
            f"Unsupported location: {sub.location}")  # pragma: no test
    placeholder = context.new_placeholder(sub.typ)
    placeholder_node = LLLnode.from_list(placeholder,
                                         typ=sub.typ,
                                         location='memory')
    copier = make_byte_array_copier(
        placeholder_node,
        LLLnode.from_list('_sub', typ=sub.typ, location=sub.location),
    )
    return LLLnode.from_list([
        'with',
        '_sub',
        sub,
        ['seq', copier, ['sha3', ['add', placeholder, 32], lengetter]],
    ],
                             typ=BaseType('bytes32'),
                             pos=getpos(expr))
Beispiel #5
0
 def integer(self):
     # Literal (mostly likely) becomes int128
     if SizeLimits.in_bounds('int128', self.expr.n) or self.expr.n < 0:
         return LLLnode.from_list(
             self.expr.n,
             typ=BaseType('int128', is_literal=True),
             pos=getpos(self.expr),
         )
     # Literal is large enough (mostly likely) becomes uint256.
     else:
         return LLLnode.from_list(
             self.expr.n,
             typ=BaseType('uint256', is_literal=True),
             pos=getpos(self.expr),
         )
Beispiel #6
0
    def boolean_operations(self):
        # Iterate through values
        for value in self.expr.values:
            # Check for calls at assignment
            if self.context.in_assignment and isinstance(value, sri_ast.Call):
                raise StructureException(
                    "Boolean operations with calls may not be performed on assignment",
                    self.expr,
                )

            # Check for boolean operations with non-boolean inputs
            _expr = Expr.parse_value_expr(value, self.context)
            if not is_base_type(_expr.typ, 'bool'):
                raise TypeMismatch(
                    "Boolean operations can only be between booleans!",
                    self.expr,
                )

            # TODO: Handle special case of literals and simplify at compile time

        # Check for valid ops
        if isinstance(self.expr.op, sri_ast.And):
            op = 'and'
        elif isinstance(self.expr.op, sri_ast.Or):
            op = 'or'
        else:
            raise Exception("Unsupported bool op: " + self.expr.op)

        # Handle different numbers of inputs
        count = len(self.expr.values)
        if count < 2:
            raise StructureException("Expected at least two arguments for a bool op", self.expr)
        elif count == 2:
            left = Expr.parse_value_expr(self.expr.values[0], self.context)
            right = Expr.parse_value_expr(self.expr.values[1], self.context)
            return LLLnode.from_list([op, left, right], typ='bool', pos=getpos(self.expr))
        else:
            left = Expr.parse_value_expr(self.expr.values[0], self.context)
            right = Expr.parse_value_expr(self.expr.values[1], self.context)

            p = ['seq', [op, left, right]]
            values = self.expr.values[2:]
            while len(values) > 0:
                value = Expr.parse_value_expr(values[0], self.context)
                p = [op, value, p]
                values = values[1:]

            return LLLnode.from_list(p, typ='bool', pos=getpos(self.expr))
Beispiel #7
0
def to_address(expr, args, kwargs, context):
    in_arg = args[0]

    return LLLnode(value=in_arg.value,
                   args=in_arg.args,
                   typ=BaseType('address'),
                   pos=getpos(expr))
Beispiel #8
0
    def _assert_reason(self, test_expr, msg):
        if isinstance(msg, sri_ast.Name) and msg.id == 'UNREACHABLE':
            return self._assert_unreachable(test_expr, msg)

        if not isinstance(msg, sri_ast.Str):
            raise StructureException(
                'Reason parameter of assert needs to be a literal string '
                '(or UNREACHABLE constant).', msg)
        if len(msg.s.strip()) == 0:
            raise StructureException('Empty reason string not allowed.',
                                     self.stmt)
        reason_str = msg.s.strip()
        sig_placeholder = self.context.new_placeholder(BaseType(32))
        arg_placeholder = self.context.new_placeholder(BaseType(32))
        reason_str_type = ByteArrayType(len(reason_str))
        placeholder_bytes = Expr(msg, self.context).lll_node
        method_id = fourbytes_to_int(keccak256(b"Error(string)")[:4])
        assert_reason = [
            'seq',
            ['mstore', sig_placeholder, method_id],
            ['mstore', arg_placeholder, 32],
            placeholder_bytes,
            [
                'assert_reason',
                test_expr,
                int(sig_placeholder + 28),
                int(4 + get_size_of_type(reason_str_type) * 32),
            ],
        ]
        return LLLnode.from_list(assert_reason,
                                 typ=None,
                                 pos=getpos(self.stmt))
Beispiel #9
0
    def ann_assign(self):
        with self.context.assignment_scope():
            typ = parse_type(
                self.stmt.annotation,
                location='memory',
                custom_structs=self.context.structs,
                constants=self.context.constants,
            )
            if isinstance(self.stmt.target, sri_ast.Attribute):
                raise TypeMismatch(
                    f'May not set type for field {self.stmt.target.attr}',
                    self.stmt,
                )
            varname = self.stmt.target.id
            pos = self.context.new_variable(varname, typ)
            if self.stmt.value is None:
                raise StructureException(
                    'New variables must be initialized explicitly', self.stmt)

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

            is_literal_bytes32_assign = (isinstance(sub.typ, ByteArrayType)
                                         and sub.typ.maxlen == 32
                                         and isinstance(typ, BaseType)
                                         and typ.typ == 'bytes32'
                                         and sub.typ.is_literal)

            # If bytes[32] to bytes32 assignment rewrite sub as bytes32.
            if is_literal_bytes32_assign:
                sub = LLLnode(
                    bytes_to_int(self.stmt.value.s),
                    typ=BaseType('bytes32'),
                    pos=getpos(self.stmt),
                )

            self._check_valid_assign(sub)
            self._check_same_variable_assign(sub)
            variable_loc = LLLnode.from_list(
                pos,
                typ=typ,
                location='memory',
                pos=getpos(self.stmt),
            )
            o = make_setter(variable_loc, sub, 'memory', pos=getpos(self.stmt))

            return o
Beispiel #10
0
 def tuple_literals(self):
     if not len(self.expr.elts):
         raise StructureException("Tuple must have elements", self.expr)
     o = []
     for elt in self.expr.elts:
         o.append(Expr(elt, self.context).lll_node)
     typ = TupleType([x.typ for x in o], is_literal=True)
     return LLLnode.from_list(["multi"] + o, typ=typ, pos=getpos(self.expr))
Beispiel #11
0
def parse_body(code, context):
    if not isinstance(code, list):
        return parse_stmt(code, context)

    o = ['seq']
    for stmt in code:
        lll = parse_stmt(stmt, context)
        o.append(lll)
    o.append('pass')  # force zerovalent, even last statement
    return LLLnode.from_list(o, pos=getpos(code[0]) if code else None)
Beispiel #12
0
    def assign(self):
        # Assignment (e.g. x[4] = y)

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

            # Error check when assigning to declared variable
            if isinstance(self.stmt.target, sri_ast.Name):
                # Do not allow assignment to undefined variables without annotation
                if self.stmt.target.id not in self.context.vars:
                    raise VariableDeclarationException(
                        "Variable type not defined", self.stmt)

                # Check against implicit conversion
                self._check_implicit_conversion(self.stmt.target.id, sub)

            is_valid_tuple_assign = (isinstance(
                self.stmt.target, sri_ast.Tuple)) and isinstance(
                    self.stmt.value, sri_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.target)
            if isinstance(target.typ, ContractType) and not isinstance(
                    sub.typ, ContractType):
                raise TypeMismatch(
                    'Contract assignment expects casted address: '
                    f'{target.typ}(<address_var>)', self.stmt)
            o = make_setter(target,
                            sub,
                            target.location,
                            pos=getpos(self.stmt))

            o.pos = getpos(self.stmt)

        return o
Beispiel #13
0
def to_bool(expr, args, kwargs, context):
    in_arg = args[0]
    input_type, _ = get_type(in_arg)

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

    else:
        return LLLnode.from_list(['iszero', ['iszero', in_arg]],
                                 typ=BaseType('bool'),
                                 pos=getpos(expr))
Beispiel #14
0
 def constants(self):
     if self.expr.value is True:
         return LLLnode.from_list(
             1,
             typ=BaseType('bool', is_literal=True),
             pos=getpos(self.expr),
         )
     elif self.expr.value is False:
         return LLLnode.from_list(
             0,
             typ=BaseType('bool', is_literal=True),
             pos=getpos(self.expr),
         )
     elif self.expr.value is None:
         # block None
         raise InvalidLiteral(
                 'None is not allowed in srilang'
                 '(use a default value or built-in `empty()`')
     else:
         raise Exception(f"Unknown name constant: {self.expr.value.value}")
Beispiel #15
0
    def parse_assert(self):

        with self.context.assertion_scope():
            test_expr = Expr.parse_value_expr(self.stmt.test, self.context)

        if not self.is_bool_expr(test_expr):
            raise TypeMismatch('Only boolean expressions allowed',
                               self.stmt.test)
        if self.stmt.msg:
            return self._assert_reason(test_expr, self.stmt.msg)
        else:
            return LLLnode.from_list(['assert', test_expr],
                                     typ=None,
                                     pos=getpos(self.stmt))
Beispiel #16
0
 def decimal(self):
     numstring, num, den = get_number_as_fraction(self.expr, self.context)
     # if not SizeLimits.in_bounds('decimal', num // den):
     # if not SizeLimits.MINDECIMAL * den <= num <= SizeLimits.MAXDECIMAL * den:
     if not (SizeLimits.MINNUM * den <= num <= SizeLimits.MAXNUM * den):
         raise InvalidLiteral("Number out of range: " + numstring, self.expr)
     if DECIMAL_DIVISOR % den:
         raise InvalidLiteral(
             "Type 'decimal' has maximum 10 decimal places",
             self.expr
         )
     return LLLnode.from_list(
         num * DECIMAL_DIVISOR // den,
         typ=BaseType('decimal', is_literal=True),
         pos=getpos(self.expr),
     )
Beispiel #17
0
 def _make_bytelike(self, btype, bytez, bytez_length):
     placeholder = self.context.new_placeholder(btype)
     seq = []
     seq.append(['mstore', placeholder, bytez_length])
     for i in range(0, len(bytez), 32):
         seq.append([
             'mstore',
             ['add', placeholder, i + 32],
             bytes_to_int((bytez + b'\x00' * 31)[i: i + 32])
         ])
     return LLLnode.from_list(
         ['seq'] + seq + [placeholder],
         typ=btype,
         location='memory',
         pos=getpos(self.expr),
         annotation=f'Create {btype}: {bytez}',
     )
Beispiel #18
0
def to_uint256(expr, args, kwargs, context):
    in_arg = args[0]
    input_type, _ = get_type(in_arg)

    if input_type == 'num_literal':
        if isinstance(in_arg, int):
            if not SizeLimits.in_bounds('uint256', in_arg):
                raise InvalidLiteral(f"Number out of range: {in_arg}")
            return LLLnode.from_list(in_arg,
                                     typ=BaseType('uint256', ),
                                     pos=getpos(expr))
        elif isinstance(in_arg, Decimal):
            if not SizeLimits.in_bounds('uint256', math.trunc(in_arg)):
                raise InvalidLiteral(
                    f"Number out of range: {math.trunc(in_arg)}")
            return LLLnode.from_list(math.trunc(in_arg),
                                     typ=BaseType('uint256'),
                                     pos=getpos(expr))
        else:
            raise InvalidLiteral(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'),
                                 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'),
            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 InvalidLiteral(
                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 InvalidLiteral(f"Invalid input for uint256: {in_arg}", expr)
Beispiel #19
0
 def subscript(self):
     sub = Expr.parse_variable_location(self.expr.value, self.context)
     if isinstance(sub.typ, (MappingType, ListType)):
         if not isinstance(self.expr.slice, sri_ast.Index):
             raise StructureException(
                 "Array access must access a single element, not a slice",
                 self.expr,
             )
         index = Expr.parse_value_expr(self.expr.slice.value, self.context)
     elif isinstance(sub.typ, TupleType):
         if not isinstance(self.expr.slice.value, sri_ast.Int) or self.expr.slice.value.n < 0 or self.expr.slice.value.n >= len(sub.typ.members):  # noqa: E501
             raise TypeMismatch("Tuple index invalid", self.expr.slice.value)
         index = self.expr.slice.value.n
     else:
         raise TypeMismatch("Bad subscript attempt", self.expr.value)
     o = add_variable_offset(sub, index, pos=getpos(self.expr))
     o.mutable = sub.mutable
     return o
Beispiel #20
0
    def parse_if(self):
        if self.stmt.orelse:
            block_scope_id = id(self.stmt.orelse)
            with self.context.make_blockscope(block_scope_id):
                add_on = [parse_body(self.stmt.orelse, self.context)]
        else:
            add_on = []

        block_scope_id = id(self.stmt)
        with self.context.make_blockscope(block_scope_id):
            test_expr = Expr.parse_value_expr(self.stmt.test, self.context)

            if not self.is_bool_expr(test_expr):
                raise TypeMismatch('Only boolean expressions allowed',
                                   self.stmt.test)
            body = ['if', test_expr,
                    parse_body(self.stmt.body, self.context)] + add_on
            o = LLLnode.from_list(body, typ=None, pos=getpos(self.stmt))
        return o
Beispiel #21
0
def _to_bytelike(expr, args, kwargs, context, bytetype):
    if bytetype == 'string':
        ReturnType = StringType
    elif bytetype == 'bytes':
        ReturnType = ByteArrayType
    else:
        raise TypeMismatch(f'Invalid {bytetype} supplied')

    in_arg = args[0]
    if in_arg.typ.maxlen > args[1].slice.value.n:
        raise TypeMismatch(
            f'Cannot convert as input {bytetype} are larger than max length',
            expr,
        )

    return LLLnode(value=in_arg.value,
                   args=in_arg.args,
                   typ=ReturnType(in_arg.typ.maxlen),
                   pos=getpos(expr),
                   location=in_arg.location)
Beispiel #22
0
def to_bytes32(expr, args, kwargs, context):
    in_arg = args[0]
    input_type, _len = get_type(in_arg)

    if input_type == 'bytes':
        if _len > 32:
            raise TypeMismatch(
                f"Unable to convert bytes[{_len}] to bytes32, max length is too "
                "large.")

        if in_arg.location == "memory":
            return LLLnode.from_list(['mload', ['add', in_arg, 32]],
                                     typ=BaseType('bytes32'))
        elif in_arg.location == "storage":
            return LLLnode.from_list(
                ['sload', ['add', ['sha3_32', in_arg], 1]],
                typ=BaseType('bytes32'))

    else:
        return LLLnode(value=in_arg.value,
                       args=in_arg.args,
                       typ=BaseType('bytes32'),
                       pos=getpos(expr))