Exemplo n.º 1
0
def external_contract_call_stmt(stmt, context, contract_name,
                                contract_address):
    if contract_name not in context.sigs:
        raise VariableDeclarationException("Contract not declared yet: %s" %
                                           contract_name)
    method_name = stmt.func.attr
    if method_name not in context.sigs[contract_name]:
        raise VariableDeclarationException(
            "Function not declared yet: %s (reminder: "
            "function must be declared in the correct contract)" % method_name)
    sig = context.sigs[contract_name][method_name]
    inargs, inargsize = pack_arguments(
        sig, [parse_expr(arg, context) for arg in stmt.args], context)
    sub = [
        'seq', ['assert', ['extcodesize', contract_address]],
        ['assert', ['ne', 'address', contract_address]]
    ]
    if context.is_constant:
        sub.append([
            'assert',
            ['staticcall', 'gas', contract_address, inargs, inargsize, 0, 0]
        ])
    else:
        sub.append([
            'assert',
            ['call', 'gas', contract_address, 0, inargs, inargsize, 0, 0]
        ])
    o = LLLnode.from_list(sub,
                          typ=sig.output_type,
                          location='memory',
                          pos=getpos(stmt))
    return o
Exemplo n.º 2
0
Arquivo: stmt.py Projeto: zutobg/vyper
 def assign(self):
     from .parser import (
         make_setter,
     )
     # Assignment (e.g. x[4] = y)
     if len(self.stmt.targets) != 1:
         raise StructureException("Assignment statement must have one target", self.stmt)
     self.context.set_in_assignment(True)
     sub = Expr(self.stmt.value, self.context).lll_node
     # Determine if it's an RLPList assignment.
     if isinstance(self.stmt.value, ast.Call) and getattr(self.stmt.value.func, 'id', '') is 'RLPList':
         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))
     # All other assignments are forbidden.
     elif isinstance(self.stmt.targets[0], ast.Name) and self.stmt.targets[0].id not in self.context.vars:
         raise VariableDeclarationException("Variable type not defined", self.stmt)
     elif isinstance(self.stmt.targets[0], ast.Tuple) and isinstance(self.stmt.value, ast.Tuple):
         raise VariableDeclarationException("Tuple to tuple assignment not supported", self.stmt)
     else:
         # Checks to see if assignment is valid
         target = self.get_target(self.stmt.targets[0])
         o = make_setter(target, sub, target.location, pos=getpos(self.stmt))
     o.pos = getpos(self.stmt)
     self.context.set_in_assignment(False)
     return o
Exemplo n.º 3
0
    def fetch_call_return(self, node: vy_ast.Call) -> StructDefinition:
        validate_call_args(node, 1)
        if not isinstance(node.args[0], vy_ast.Dict):
            raise VariableDeclarationException(
                "Struct values must be declared via dictionary", node.args[0])
        if next(
            (i for i in self.members.values()
             if isinstance(i, MappingDefinition)),
                False,
        ):
            raise VariableDeclarationException(
                "Struct contains a mapping and so cannot be declared as a literal",
                node)

        members = self.members.copy()
        for key, value in zip(node.args[0].keys, node.args[0].values):
            if key is None or key.get("id") not in members:
                raise UnknownAttribute("Unknown or duplicate struct member",
                                       key or value)
            validate_expected_type(value, members.pop(key.id))
        if members:
            raise VariableDeclarationException(
                f"Struct declaration does not define all fields: {', '.join(list(members))}",
                node,
            )

        return StructDefinition(self._id, self.members)
Exemplo n.º 4
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)

            # Determine if it's an RLPList assignment.
            if isinstance(self.stmt.value, ast.Call) and getattr(
                    self.stmt.value.func, 'id', '') == 'RLPList':
                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)

                # Do no allow tuple-to-tuple assignment
                if isinstance(self.stmt.targets[0], ast.Tuple) and isinstance(
                        self.stmt.value, ast.Tuple):
                    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])
                o = make_setter(target,
                                sub,
                                target.location,
                                pos=getpos(self.stmt))

            o.pos = getpos(self.stmt)

        return o
Exemplo n.º 5
0
    def from_declaration(cls, code, custom_units=None):
        name = code.target.id
        pos = 0

        if not is_varname_valid(name, custom_units=custom_units):
            raise EventDeclarationException("Event name invalid: " + name)
        # Determine the arguments, expects something of the form def foo(arg1: num, arg2: num ...
        args = []
        indexed_list = []
        topics_count = 1
        if code.annotation.args:
            keys = code.annotation.args[0].keys
            values = code.annotation.args[0].values
            for i in range(len(keys)):
                typ = values[i]
                arg = keys[i].id
                is_indexed = False
                # Check to see if argument is a topic
                if isinstance(typ, ast.Call) and typ.func.id == 'indexed':
                    typ = values[i].args[0]
                    indexed_list.append(True)
                    topics_count += 1
                    is_indexed = True
                else:
                    indexed_list.append(False)
                if isinstance(typ, ast.Subscript) and getattr(
                        typ.value, 'id', None
                ) == 'bytes' and typ.slice.value.n > 32 and is_indexed:
                    raise EventDeclarationException(
                        "Indexed arguments are limited to 32 bytes")
                if topics_count > 4:
                    raise EventDeclarationException(
                        "Maximum of 3 topics {} given".format(topics_count -
                                                              1), arg)
                if not isinstance(arg, str):
                    raise VariableDeclarationException("Argument name invalid",
                                                       arg)
                if not typ:
                    raise InvalidTypeException("Argument must have type", arg)
                if not is_varname_valid(arg, custom_units):
                    raise VariableDeclarationException(
                        "Argument name invalid or reserved: " + arg, arg)
                if arg in (x.name for x in args):
                    raise VariableDeclarationException(
                        "Duplicate function argument name: " + arg, arg)
                parsed_type = parse_type(typ, None, custom_units=custom_units)
                args.append(VariableRecord(arg, pos, parsed_type, False))
                if isinstance(parsed_type, ByteArrayType):
                    pos += ceil32(typ.slice.value.n)
                else:
                    pos += get_size_of_type(parsed_type) * 32
        sig = name + '(' + ','.join([
            canonicalize_type(arg.typ, indexed_list[pos])
            for pos, arg in enumerate(args)
        ]) + ')'  # noqa F812
        event_id = bytes_to_int(sha3(bytes(sig, 'utf-8')))
        return cls(name, args, indexed_list, event_id, sig)
Exemplo n.º 6
0
 def new_variable(self, name, typ):
     if not is_varname_valid(name, custom_units=self.custom_units):
         raise VariableDeclarationException("Variable name invalid or reserved: " + name)
     if name in self.vars or name in self.globals:
         raise VariableDeclarationException("Duplicate variable name: %s" % name)
     self.vars[name] = VariableRecord(name, self.next_mem, typ, True, self.blockscopes.copy())
     pos = self.next_mem
     self.next_mem += 32 * get_size_of_type(typ)
     return pos
Exemplo n.º 7
0
    def visit_AnnAssign(self, node):
        name = node.get("target.id")
        if name is None:
            raise VariableDeclarationException(
                "Invalid module-level assignment", node)

        if name == "implements":
            interface_name = node.annotation.id
            self.namespace[interface_name].validate_implements(node)
            return

        is_immutable, is_public = False, False
        annotation = node.annotation
        if isinstance(annotation, vy_ast.Call):
            # the annotation is a function call, e.g. `foo: constant(uint256)`
            call_name = annotation.get("func.id")
            if call_name in ("constant", "public"):
                validate_call_args(annotation, 1)
                if call_name == "constant":
                    # declaring a constant
                    is_immutable = True

                elif call_name == "public":
                    # declaring a public variable
                    is_public = True
                # remove the outer call node, to handle cases such as `public(map(..))`
                annotation = annotation.args[0]
        type_definition = get_type_from_annotation(annotation,
                                                   DataLocation.STORAGE,
                                                   is_immutable, is_public)

        if is_immutable:
            if not node.value:
                raise VariableDeclarationException(
                    "Constant must be declared with a value", node)
            if not check_literal(node.value):
                raise StateAccessViolation("Value must be a literal",
                                           node.value)

            validate_expected_type(node.value, type_definition)
            try:
                self.namespace[name] = type_definition
            except VyperException as exc:
                raise exc.with_annotation(node) from None
            return

        if node.value:
            raise VariableDeclarationException(
                "Storage variables cannot have an initial value", node.value)
        try:
            self.namespace["self"].add_member(name, type_definition)
        except NamespaceCollision:
            raise NamespaceCollision(
                f"Value '{name}' has already been declared", node) from None
        except VyperException as exc:
            raise exc.with_annotation(node) from None
Exemplo n.º 8
0
Arquivo: stmt.py Projeto: 6pakla/vyper
    def assign(self):
        # Assignment (e.g. x[4] = y)

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

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

            # Determine if it's an RLPList assignment.
            if is_valid_rlp_list_assign:
                pos = self.context.new_variable(self.stmt.target.id, sub.typ)
                variable_loc = LLLnode.from_list(
                    pos,
                    typ=sub.typ,
                    location='memory',
                    pos=getpos(self.stmt),
                    annotation=self.stmt.target.id,
                )
                o = make_setter(variable_loc, sub, 'memory', pos=getpos(self.stmt))
            else:
                # Error check when assigning to declared variable
                if isinstance(self.stmt.target, vy_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, vy_ast.Tuple)
                ) and isinstance(self.stmt.value, vy_ast.Tuple)

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

                # Checks to see if assignment is valid
                target = self.get_target(self.stmt.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
Exemplo n.º 9
0
    def is_valid_varname(self, name, item):
        if not is_varname_valid(name, custom_units=self._custom_units, custom_structs=self._structs):
            raise VariableDeclarationException('Invalid name "%s"' % name, item)
        if name in self._globals:
            raise VariableDeclarationException('Invalid name "%s", previously defined as global.' % name, item)
        if name in self._constants:
            raise VariableDeclarationException('Invalid name "%s", previously defined as constant.' % name, item)
        if name in self._custom_units:
            raise VariableDeclarationException('Invalid name "%s", previously defined as custom unit.' % name, item)

        return True
Exemplo n.º 10
0
def external_contract_call(node,
                           context,
                           contract_name,
                           contract_address,
                           is_modifiable,
                           pos,
                           value=None,
                           gas=None):
    if value is None:
        value = 0
    if gas is None:
        gas = 'gas'
    if contract_name not in context.sigs:
        raise VariableDeclarationException("Contract not declared yet: %s" %
                                           contract_name)
    method_name = node.func.attr
    if method_name not in context.sigs[contract_name]:
        raise VariableDeclarationException(
            "Function not declared yet: %s (reminder: "
            "function must be declared in the correct contract)" % method_name,
            pos)
    sig = context.sigs[contract_name][method_name]
    inargs, inargsize = pack_arguments(
        sig, [parse_expr(arg, context) for arg in node.args], context, pos=pos)
    output_placeholder, output_size, returner = get_external_contract_call_output(
        sig, context)
    sub = [
        'seq', ['assert', ['extcodesize', contract_address]],
        ['assert', ['ne', 'address', contract_address]]
    ]
    if context.is_constant or not is_modifiable:
        sub.append([
            'assert',
            [
                'staticcall', gas, contract_address, inargs, inargsize,
                output_placeholder, output_size
            ]
        ])
    else:
        sub.append([
            'assert',
            [
                'call', gas, contract_address, value, inargs, inargsize,
                output_placeholder, output_size
            ]
        ])
    sub.extend(returner)
    o = LLLnode.from_list(sub,
                          typ=sig.output_type,
                          location='memory',
                          pos=getpos(node))
    return o
Exemplo n.º 11
0
def external_contract_call_expr(expr, context, contract_name,
                                contract_address):
    if contract_name not in context.sigs:
        raise VariableDeclarationException("Contract not declared yet: %s" %
                                           contract_name)
    method_name = expr.func.attr
    if method_name not in context.sigs[contract_name]:
        raise VariableDeclarationException(
            "Function not declared yet: %s (reminder: "
            "function must be declared in the correct contract)" % method_name)
    sig = context.sigs[contract_name][method_name]
    inargs, inargsize = pack_arguments(
        sig, [parse_expr(arg, context) for arg in expr.args], context)
    output_placeholder = context.new_placeholder(typ=sig.output_type)
    if isinstance(sig.output_type, BaseType):
        returner = output_placeholder
    elif isinstance(sig.output_type, ByteArrayType):
        returner = output_placeholder + 32
    else:
        raise TypeMismatchException(
            "Invalid output type: %r" % sig.output_type, expr)
    sub = [
        'seq', ['assert', ['extcodesize', contract_address]],
        ['assert', ['ne', 'address', contract_address]]
    ]
    if context.is_constant:
        sub.append([
            'assert',
            [
                'staticcall', 'gas', contract_address, inargs, inargsize,
                output_placeholder,
                get_size_of_type(sig.output_type) * 32
            ]
        ])
    else:
        sub.append([
            'assert',
            [
                'call', 'gas', contract_address, 0, inargs, inargsize,
                output_placeholder,
                get_size_of_type(sig.output_type) * 32
            ]
        ])
    sub.extend([0, returner])
    o = LLLnode.from_list(sub,
                          typ=sig.output_type,
                          location='memory',
                          pos=getpos(expr))
    return o
Exemplo n.º 12
0
def get_contracts_and_defs_and_globals(code):
    _contracts = {}
    _events = []
    _globals = {}
    _defs = []
    _getters = []
    _custom_units = []

    for item in code:
        # Contract references
        if isinstance(item, ast.ClassDef):
            if _events or _globals or _defs:
                raise StructureException("External contract declarations must come before event declarations, global declarations, and function definitions", item)
            _contracts[item.name] = add_contract(item.body)
        # Statements of the form:
        # variable_name: type
        elif isinstance(item, ast.AnnAssign):
            _custom_units, _contracts, _events, _globals, _getters = add_globals_and_events(_custom_units, _contracts, _defs, _events, _getters, _globals, item)
        # Function definitions
        elif isinstance(item, ast.FunctionDef):
            if item.name in _globals:
                raise VariableDeclarationException("Function name shadowing a variable name: %s" % item.name)
            _defs.append(item)
        else:
            raise StructureException("Invalid top-level statement", item)
    return _contracts, _events, _defs + _getters, _globals, _custom_units
Exemplo n.º 13
0
def parse_tree_to_lll(code, origcode, runtime_only=False):
    _contracts, _events, _defs, _globals, _custom_units = get_contracts_and_defs_and_globals(code)
    _names = [_def.name for _def in _defs] + [_event.target.id for _event in _events]
    # Checks for duplicate function / event names
    if len(set(_names)) < len(_names):
        raise VariableDeclarationException("Duplicate function or event name: %s" % [name for name in _names if _names.count(name) > 1][0])
    # Initialization function
    initfunc = [_def for _def in _defs if is_initializer(_def)]
    # Regular functions
    otherfuncs = [_def for _def in _defs if not is_initializer(_def)]
    sigs = {}
    external_contracts = {}
    # Create the main statement
    o = ['seq']
    if _events:
        sigs = parse_events(sigs, _events, _custom_units)
    if _contracts:
        external_contracts = parse_external_contracts(external_contracts, _contracts)
    # If there is an init func...
    if initfunc:
        o.append(['seq', initializer_lll])
        o.append(parse_func(initfunc[0], _globals, {**{'self': sigs}, **external_contracts}, origcode, _custom_units))
    # If there are regular functions...
    if otherfuncs:
        o = parse_other_functions(o, otherfuncs, _globals, sigs, external_contracts, origcode, _custom_units, runtime_only)
    return LLLnode.from_list(o, typ=None)
Exemplo n.º 14
0
 def is_valid_varname(self, name, item):
     """ Valid variable name, checked against global context. """
     check_valid_varname(name, self._structs, self._constants, item)
     if name in self._globals:
         raise VariableDeclarationException(
             f'Invalid name "{name}", previously defined as global.', item)
     return True
Exemplo n.º 15
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)
Exemplo n.º 16
0
 def _check_same_variable_assign(self, sub):
     lhs_var_name = self.stmt.target.id
     rhs_names = self._check_rhs_var_assn_recur(self.stmt.value)
     if lhs_var_name in rhs_names:
         raise VariableDeclarationException(
             'Invalid variable assignment, same variable not allowed on LHS and RHS: %s'
             % lhs_var_name)
Exemplo n.º 17
0
 def attribute(self):
     # x.balance: balance of address x
     if self.expr.attr == 'balance':
         addr = Expr.parse_value_expr(self.expr.value, self.context)
         if not is_base_type(addr.typ, 'address'):
             raise TypeMismatchException("Type mismatch: balance keyword expects an address as input", self.expr)
         return LLLnode.from_list(['balance', addr], typ=BaseType('int128', {'wei': 1}), location=None, pos=getpos(self.expr))
     # x.codesize: codesize of address x
     elif self.expr.attr == 'codesize' or self.expr.attr == 'is_contract':
         addr = Expr.parse_value_expr(self.expr.value, self.context)
         if not is_base_type(addr.typ, 'address'):
             raise TypeMismatchException("Type mismatch: codesize keyword expects an address as input", self.expr)
         if self.expr.attr == 'codesize':
             eval_code = ['extcodesize', addr]
             output_type = 'int128'
         else:
             eval_code = ['gt', ['extcodesize', addr], 0]
             output_type = 'bool'
         return LLLnode.from_list(eval_code, typ=BaseType(output_type), location=None, pos=getpos(self.expr))
     # self.x: global attribute
     elif isinstance(self.expr.value, ast.Name) and self.expr.value.id == "self":
         if self.expr.attr not in self.context.globals:
             raise VariableDeclarationException("Persistent variable undeclared: " + self.expr.attr, self.expr)
         var = self.context.globals[self.expr.attr]
         return LLLnode.from_list(var.pos, typ=var.typ, location='storage', pos=getpos(self.expr), annotation='self.' + self.expr.attr)
     # Reserved keywords
     elif isinstance(self.expr.value, ast.Name) and self.expr.value.id in ("msg", "block", "tx"):
         key = self.expr.value.id + "." + self.expr.attr
         if key == "msg.sender":
             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('int128', {'wei': 1}), pos=getpos(self.expr))
         elif key == "msg.gas":
             return LLLnode.from_list(['gas'], typ='int128', pos=getpos(self.expr))
         elif key == "block.difficulty":
             return LLLnode.from_list(['difficulty'], typ='int128', pos=getpos(self.expr))
         elif key == "block.timestamp":
             return LLLnode.from_list(['timestamp'], typ=BaseType('int128', {'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='int128', 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, pos=getpos(self.expr))
Exemplo n.º 18
0
 def variables(self):
     if self.expr.id == 'self':
         return LLLnode.from_list(['address'], typ='address', pos=getpos(self.expr))
     if self.expr.id in self.context.vars:
         var = self.context.vars[self.expr.id]
         return LLLnode.from_list(var.pos, typ=var.typ, location='memory', pos=getpos(self.expr), annotation=self.expr.id, mutable=var.mutable)
     else:
         raise VariableDeclarationException("Undeclared variable: " + self.expr.id, self.expr)
Exemplo n.º 19
0
    def visit_AnnAssign(self, node):
        name = node.get("target.id")
        if name is None:
            raise VariableDeclarationException("Invalid assignment", node)

        if not node.value:
            raise VariableDeclarationException(
                "Memory variables must be declared with an initial value", node
            )

        type_definition = get_type_from_annotation(node.annotation, DataLocation.MEMORY)
        validate_expected_type(node.value, type_definition)

        try:
            self.namespace[name] = type_definition
        except VyperException as exc:
            raise exc.with_annotation(node) from None
Exemplo n.º 20
0
 def is_valid_varname(self, name, pos):
     # Global context check first.
     if self.global_ctx.is_valid_varname(name, pos):
         check_valid_varname(name, custom_units=self.custom_units, custom_structs=self.structs, constants=self.constants, pos=pos)
         # Local context duplicate context check.
         if any((name in self.vars, name in self.globals, name in self.constants)):
             raise VariableDeclarationException("Duplicate variable name: %s" % name, name)
     return True
Exemplo n.º 21
0
    def variables(self):
        builtin_constants = {
            'EMPTY_BYTES32':
            LLLnode.from_list([0],
                              typ=BaseType('bytes32', None, is_literal=True),
                              pos=getpos(self.expr)),
            'ZERO_ADDRESS':
            LLLnode.from_list([0],
                              typ=BaseType('address', None, is_literal=True),
                              pos=getpos(self.expr)),
            'MAX_INT128':
            LLLnode.from_list([SizeLimits.MAXNUM],
                              typ=BaseType('int128', None, is_literal=True),
                              pos=getpos(self.expr)),
            'MIN_INT128':
            LLLnode.from_list([SizeLimits.MINNUM],
                              typ=BaseType('int128', None, is_literal=True),
                              pos=getpos(self.expr)),
            'MAX_DECIMAL':
            LLLnode.from_list([SizeLimits.MAXDECIMAL],
                              typ=BaseType('decimal', None, is_literal=True),
                              pos=getpos(self.expr)),
            'MIN_DECIMAL':
            LLLnode.from_list([SizeLimits.MINDECIMAL],
                              typ=BaseType('decimal', None, is_literal=True),
                              pos=getpos(self.expr)),
            'MAX_UINT256':
            LLLnode.from_list([SizeLimits.MAX_UINT256],
                              typ=BaseType('uint256', None, is_literal=True),
                              pos=getpos(self.expr)),
        }

        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='memory',
                                     pos=getpos(self.expr),
                                     annotation=self.expr.id,
                                     mutable=var.mutable)
        elif self.expr.id in builtin_constants:
            return builtin_constants[self.expr.id]
        elif self.expr.id in self.context.constants:
            # check if value is compatible with
            const = self.context.constants[self.expr.id]
            if isinstance(const, ast.AnnAssign):  # Handle ByteArrays.
                expr = Expr(const.value, self.context).lll_node
                return expr
            # Other types are already unwrapped, no need
            return self.context.constants[self.expr.id]
        else:
            raise VariableDeclarationException(
                "Undeclared variable: " + self.expr.id, self.expr)
Exemplo n.º 22
0
    def variables(self):
        builtin_constants = {
            'EMPTY_BYTES32': LLLnode.from_list(
                [0],
                typ=BaseType('bytes32', None, is_literal=True),
                pos=getpos(self.expr)
            ),
            'ZERO_ADDRESS': LLLnode.from_list(
                [0],
                typ=BaseType('address', None, is_literal=True),
                pos=getpos(self.expr)
            ),
            'MAX_INT128': LLLnode.from_list(
                [SizeLimits.MAXNUM],
                typ=BaseType('int128', None, is_literal=True),
                pos=getpos(self.expr)
            ),
            'MIN_INT128': LLLnode.from_list(
                [SizeLimits.MINNUM],
                typ=BaseType('int128', None, is_literal=True),
                pos=getpos(self.expr)
            ),
            'MAX_DECIMAL': LLLnode.from_list(
                [SizeLimits.MAXDECIMAL],
                typ=BaseType('decimal', None, is_literal=True),
                pos=getpos(self.expr)
            ),
            'MIN_DECIMAL': LLLnode.from_list(
                [SizeLimits.MINDECIMAL],
                typ=BaseType('decimal', None, is_literal=True),
                pos=getpos(self.expr)
            ),
            'MAX_UINT256': LLLnode.from_list(
                [SizeLimits.MAX_UINT256],
                typ=BaseType('uint256', None, is_literal=True),
                pos=getpos(self.expr)
            ),
        }

        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:
            return builtin_constants[self.expr.id]
        elif self.context.constants.ast_is_constant(self.expr):
            return self.context.constants.get_constant(self.expr.id, self.context)
        else:
            raise VariableDeclarationException("Undeclared variable: " + self.expr.id, self.expr)
Exemplo n.º 23
0
def parse_func(code, _globals, sigs, origcode, _custom_units, _vars=None):
    if _vars is None:
        _vars = {}
    sig = FunctionSignature.from_definition(code, sigs=sigs, custom_units=_custom_units)
    # Check for duplicate variables with globals
    for arg in sig.args:
        if arg.name in _globals:
            raise VariableDeclarationException("Variable name duplicated between function arguments and globals: " + arg.name)
    # Create a context
    context = Context(vars=_vars, globals=_globals, sigs=sigs,
                      return_type=sig.output_type, is_constant=sig.const, is_payable=sig.payable, origcode=origcode, custom_units=_custom_units)
    # Copy calldata to memory for fixed-size arguments
    copy_size = sum([32 if isinstance(arg.typ, ByteArrayType) else get_size_of_type(arg.typ) * 32 for arg in sig.args])
    context.next_mem += copy_size
    if not len(sig.args):
        copier = 'pass'
    elif sig.name == '__init__':
        copier = ['codecopy', MemoryPositions.RESERVED_MEMORY, '~codelen', copy_size]
    else:
        copier = ['calldatacopy', MemoryPositions.RESERVED_MEMORY, 4, copy_size]
    clampers = [copier]
    # Add asserts for payable and internal
    if not sig.payable:
        clampers.append(['assert', ['iszero', 'callvalue']])
    if sig.private:
        clampers.append(['assert', ['eq', 'caller', 'address']])
    # Fill in variable positions
    for arg in sig.args:
        clampers.append(make_clamper(arg.pos, context.next_mem, arg.typ, sig.name == '__init__'))
        if isinstance(arg.typ, ByteArrayType):
            context.vars[arg.name] = VariableRecord(arg.name, context.next_mem, arg.typ, False)
            context.next_mem += 32 * get_size_of_type(arg.typ)
        else:
            context.vars[arg.name] = VariableRecord(arg.name, MemoryPositions.RESERVED_MEMORY + arg.pos, arg.typ, False)
    # Create "clampers" (input well-formedness checkers)
    # Return function body
    if sig.name == '__init__':
        o = LLLnode.from_list(['seq'] + clampers + [parse_body(code.body, context)], pos=getpos(code))
    else:
        method_id_node = LLLnode.from_list(sig.method_id, pos=getpos(code), annotation='%s' % sig.name)
        o = LLLnode.from_list(['if',
                                  ['eq', ['mload', 0], method_id_node],
                                  ['seq'] + clampers + [parse_body(c, context) for c in code.body] + ['stop']
                               ], typ=None, pos=getpos(code))

    # Check for at leasts one return statement if necessary.
    if context.return_type and context.function_return_count == 0:
        raise StructureException(
            "Missing return statement in function '%s' " % sig.name, code
        )

    o.context = context
    o.total_gas = o.gas + calc_mem_gas(o.context.next_mem)
    o.func_name = sig.name
    return o
Exemplo n.º 24
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, vy_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, vy_ast.Tuple)) and isinstance(
                    self.stmt.value, vy_ast.Tuple)

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

            # Checks to see if assignment is valid
            target = self.get_target(self.stmt.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
Exemplo n.º 25
0
def parse_external_contracts(external_contracts, _contracts):
    for _contractname in _contracts:
        _contract_defs = _contracts[_contractname]
        _defnames = [_def.name for _def in _contract_defs]
        contract = {}
        if len(set(_defnames)) < len(_contract_defs):
            raise VariableDeclarationException("Duplicate function name: %s" % [name for name in _defnames if _defnames.count(name) > 1][0])
        for _def in _contract_defs:
            sig = FunctionSignature.from_definition(_def)
            contract[sig.name] = sig
        external_contracts[_contractname] = contract
    return external_contracts
Exemplo n.º 26
0
    def fetch_call_return(self, node: vy_ast.Call) -> StructDefinition:
        validate_call_args(node, 1)
        if not isinstance(node.args[0], vy_ast.Dict):
            raise VariableDeclarationException(
                "Struct values must be declared via dictionary", node.args[0])
        if next((i for i in self.members.values()
                 if isinstance(i, MappingDefinition)), False):
            raise VariableDeclarationException(
                "Struct contains a mapping and so cannot be declared as a literal",
                node)

        members = self.members.copy()
        keys = list(self.members.keys())
        for i, (key,
                value) in enumerate(zip(node.args[0].keys,
                                        node.args[0].values)):
            if key is None or key.get("id") not in members:
                suggestions_str = get_levenshtein_error_suggestions(
                    key.get("id"), members, 1.0)
                raise UnknownAttribute(
                    f"Unknown or duplicate struct member. {suggestions_str}",
                    key or value)
            expected_key = keys[i]
            if key.id != expected_key:
                raise InvalidAttribute(
                    "Struct keys are required to be in order, but got "
                    f"`{key.id}` instead of `{expected_key}`. (Reminder: the "
                    f"keys in this struct are {list(self.members.items())})",
                    key,
                )

            validate_expected_type(value, members.pop(key.id))

        if members:
            raise VariableDeclarationException(
                f"Struct declaration does not define all fields: {', '.join(list(members))}",
                node)

        return StructDefinition(self._id, self.members)
Exemplo n.º 27
0
    def visit_AnnAssign(self, node):
        if not node.value:
            raise VariableDeclarationException(
                "Memory variables must be declared with an initial value", node
            )
        name = node.target.id
        if name in self.namespace["self"].members:
            raise NamespaceCollision("Variable name shadows an existing storage-scoped value", node)

        type_definition = get_type_from_annotation(node.annotation, DataLocation.MEMORY)
        validate_expected_type(node.value, type_definition)

        try:
            self.namespace[name] = type_definition
        except VyperException as exc:
            raise exc.with_annotation(node) from None
Exemplo n.º 28
0
    def get_constant(self, const_name, context):
        """ Return unrolled const """

        # check if value is compatible with
        const = self._constants[const_name]

        if isinstance(const, ast.AnnAssign):  # Handle ByteArrays.
            if context:
                expr = Expr(const.value, context).lll_node
                return expr
            else:
                raise VariableDeclarationException(
                    "ByteArray: Can not be used outside of a function context: %s"
                    % const_name)

        # Other types are already unwrapped, no need
        return self._constants[const_name]
Exemplo n.º 29
0
    def variables(self):
        constants = {
            'ZERO_ADDRESS':
            LLLnode.from_list([0],
                              typ=BaseType('address', None, is_literal=True),
                              pos=getpos(self.expr)),
            'MAX_INT128':
            LLLnode.from_list(['mload', MemoryPositions.MAXNUM],
                              typ=BaseType('int128', None, is_literal=True),
                              pos=getpos(self.expr)),
            'MIN_INT128':
            LLLnode.from_list(['mload', MemoryPositions.MINNUM],
                              typ=BaseType('int128', None, is_literal=True),
                              pos=getpos(self.expr)),
            'MAX_DECIMAL':
            LLLnode.from_list(['mload', MemoryPositions.MAXDECIMAL],
                              typ=BaseType('decimal', None, is_literal=True),
                              pos=getpos(self.expr)),
            'MIN_DECIMAL':
            LLLnode.from_list(['mload', MemoryPositions.MINDECIMAL],
                              typ=BaseType('decimal', None, is_literal=True),
                              pos=getpos(self.expr)),
            'MAX_UINT256':
            LLLnode.from_list([2**256 - 1],
                              typ=BaseType('uint256', None, is_literal=True),
                              pos=getpos(self.expr)),
        }

        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='memory',
                                     pos=getpos(self.expr),
                                     annotation=self.expr.id,
                                     mutable=var.mutable)
        elif self.expr.id in constants:
            return constants[self.expr.id]
        else:
            raise VariableDeclarationException(
                "Undeclared variable: " + self.expr.id, self.expr)
Exemplo n.º 30
0
    def call(self):
        from .parser import (
            external_contract_call,
            pack_arguments,
        )
        from vyper.functions import (
            dispatch_table, )
        if isinstance(self.expr.func, ast.Name):
            function_name = self.expr.func.id
            if function_name in dispatch_table:
                return dispatch_table[function_name](self.expr, self.context)
            else:
                err_msg = "Not a top-level function: {}".format(function_name)
                if function_name in self.context.sigs['self']:
                    err_msg += ". Did you mean self.{}?".format(function_name)
                raise StructureException(err_msg, self.expr)
        elif isinstance(self.expr.func, ast.Attribute) and isinstance(
                self.expr.func.value,
                ast.Name) and self.expr.func.value.id == "self":
            method_name = self.expr.func.attr
            if method_name not in self.context.sigs['self']:
                raise VariableDeclarationException(
                    "Function not declared yet (reminder: functions cannot "
                    "call functions later in code than themselves): %s" %
                    self.expr.func.attr)

            sig = self.context.sigs['self'][method_name]
            if self.context.is_constant and not sig.const:
                raise ConstancyViolationException(
                    "May not call non-constant function '%s' within a constant function."
                    % (method_name), getpos(self.expr))
            add_gas = self.context.sigs['self'][method_name].gas  # gas of call
            inargs, inargsize = pack_arguments(
                sig,
                [Expr(arg, self.context).lll_node for arg in self.expr.args],
                self.context,
                pos=getpos(self.expr))
            output_placeholder = self.context.new_placeholder(
                typ=sig.output_type)
            multi_arg = []
            if isinstance(sig.output_type, BaseType):
                returner = output_placeholder
            elif isinstance(sig.output_type, ByteArrayType):
                returner = output_placeholder + 32
            elif self.context.in_assignment and isinstance(
                    sig.output_type, TupleType):
                returner = output_placeholder
            else:
                raise TypeMismatchException(
                    "Invalid output type: %r" % sig.output_type, self.expr)
            o = LLLnode.from_list(multi_arg + [
                'seq',
                [
                    'assert',
                    [
                        'call', ['gas'], ['address'], 0, inargs, inargsize,
                        output_placeholder,
                        get_size_of_type(sig.output_type) * 32
                    ]
                ], returner
            ],
                                  typ=sig.output_type,
                                  location='memory',
                                  pos=getpos(self.expr),
                                  add_gas_estimate=add_gas,
                                  annotation='Internal Call: %s' % method_name)
            o.gas += sig.gas
            return o
        elif isinstance(self.expr.func, ast.Attribute) and isinstance(
                self.expr.func.value, ast.Call):
            contract_name = self.expr.func.value.func.id
            contract_address = Expr.parse_value_expr(
                self.expr.func.value.args[0], self.context)
            value, gas = self._get_external_contract_keywords()
            return external_contract_call(self.expr,
                                          self.context,
                                          contract_name,
                                          contract_address,
                                          pos=getpos(self.expr),
                                          value=value,
                                          gas=gas)
        elif isinstance(self.expr.func.value, ast.Attribute
                        ) and self.expr.func.value.attr in self.context.sigs:
            contract_name = self.expr.func.value.attr
            var = self.context.globals[self.expr.func.value.attr]
            contract_address = unwrap_location(
                LLLnode.from_list(var.pos,
                                  typ=var.typ,
                                  location='storage',
                                  pos=getpos(self.expr),
                                  annotation='self.' +
                                  self.expr.func.value.attr))
            value, gas = self._get_external_contract_keywords()
            return external_contract_call(self.expr,
                                          self.context,
                                          contract_name,
                                          contract_address,
                                          pos=getpos(self.expr),
                                          value=value,
                                          gas=gas)
        elif isinstance(
                self.expr.func.value, ast.Attribute
        ) and self.expr.func.value.attr in self.context.globals:
            contract_name = self.context.globals[
                self.expr.func.value.attr].typ.unit
            var = self.context.globals[self.expr.func.value.attr]
            contract_address = unwrap_location(
                LLLnode.from_list(var.pos,
                                  typ=var.typ,
                                  location='storage',
                                  pos=getpos(self.expr),
                                  annotation='self.' +
                                  self.expr.func.value.attr))
            value, gas = self._get_external_contract_keywords()
            return external_contract_call(self.expr,
                                          self.context,
                                          contract_name,
                                          contract_address,
                                          pos=getpos(self.expr),
                                          value=value,
                                          gas=gas)
        else:
            raise StructureException(
                "Unsupported operator: %r" % ast.dump(self.expr), self.expr)