Exemplo n.º 1
0
def external_contract_call(node,
                           context,
                           contract_name,
                           contract_address,
                           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 FunctionDeclarationException(
            "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 sig.const:
        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.º 2
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)
     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 variables(self):
     if self.expr.id == 'self':
         return LLLnode.from_list(['address'], typ='address', pos=getpos(self.expr))
     if self.expr.id == 'true':
         return LLLnode.from_list(1, typ='bool', pos=getpos(self.expr))
     if self.expr.id == 'false':
         return LLLnode.from_list(0, typ='bool', pos=getpos(self.expr))
     if self.expr.id == 'null':
         return LLLnode.from_list(None, typ=NullType(), 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.º 4
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.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.º 5
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.º 6
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.º 7
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.º 8
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.º 9
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.º 10
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)
    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.º 11
0
Arquivo: stmt.py Projeto: agroce/vyper
    def assign(self):
        # Assignment (e.g. x[4] = y)
        if len(self.stmt.targets) != 1:
            raise StructureException(
                "Assignment statement must have one target", self.stmt)

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

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

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

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

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

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

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

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

            o.pos = getpos(self.stmt)

        return o
Exemplo n.º 12
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 TypeMismatch(
                 "Type mismatch: balance keyword expects an address as input",
                 self.expr)
         if (isinstance(self.expr.value, vy_ast.Name)
                 and self.expr.value.id == "self"
                 and version_check(begin="istanbul")):
             seq = ['selfbalance']
         else:
             seq = ['balance', addr]
         return LLLnode.from_list(
             seq,
             typ=BaseType('uint256'),
             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 TypeMismatch(
                 "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),
         )
     # x.codehash: keccak of address x
     elif self.expr.attr == 'codehash':
         addr = Expr.parse_value_expr(self.expr.value, self.context)
         if not is_base_type(addr.typ, 'address'):
             raise TypeMismatch(
                 "codehash keyword expects an address as input",
                 self.expr,
             )
         if not version_check(begin="constantinople"):
             raise EvmVersionException(
                 "address.codehash is unavailable prior to constantinople ruleset",
                 self.expr)
         return LLLnode.from_list(['extcodehash', addr],
                                  typ=BaseType('bytes32'),
                                  location=None,
                                  pos=getpos(self.expr))
     # self.x: global attribute
     elif isinstance(self.expr.value,
                     vy_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, vy_ast.Name)
           and self.expr.value.id in ENVIRONMENT_VARIABLES):
         key = self.expr.value.id + "." + self.expr.attr
         if key == "msg.sender":
             if self.context.is_private:
                 raise StructureException(
                     "msg.sender not allowed in private functions.",
                     self.expr)
             return LLLnode.from_list(['caller'],
                                      typ='address',
                                      pos=getpos(self.expr))
         elif key == "msg.value":
             if not self.context.is_payable:
                 raise NonPayableViolation(
                     "Cannot use msg.value in a non-payable function",
                     self.expr,
                 )
             return LLLnode.from_list(
                 ['callvalue'],
                 typ=BaseType('uint256'),
                 pos=getpos(self.expr),
             )
         elif key == "msg.gas":
             return LLLnode.from_list(
                 ['gas'],
                 typ='uint256',
                 pos=getpos(self.expr),
             )
         elif key == "block.difficulty":
             return LLLnode.from_list(
                 ['difficulty'],
                 typ='uint256',
                 pos=getpos(self.expr),
             )
         elif key == "block.timestamp":
             return LLLnode.from_list(
                 ['timestamp'],
                 typ=BaseType('uint256'),
                 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='uint256',
                                      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))
         elif key == "chain.id":
             if not version_check(begin="istanbul"):
                 raise EvmVersionException(
                     "chain.id is unavailable prior to istanbul ruleset",
                     self.expr)
             return LLLnode.from_list(['chainid'],
                                      typ='uint256',
                                      pos=getpos(self.expr))
         else:
             raise StructureException("Unsupported keyword: " + key,
                                      self.expr)
     # Other variables
     else:
         sub = Expr.parse_variable_location(self.expr.value, self.context)
         # contract type
         if isinstance(sub.typ, ContractType):
             return sub
         if not isinstance(sub.typ, StructType):
             raise TypeMismatch(
                 "Type mismatch: member variable access not expected",
                 self.expr.value,
             )
         attrs = list(sub.typ.members.keys())
         if self.expr.attr not in attrs:
             raise TypeMismatch(
                 f"Member {self.expr.attr} not found. Only the following available: "
                 f"{' '.join(attrs)}",
                 self.expr,
             )
         return add_variable_offset(sub,
                                    self.expr.attr,
                                    pos=getpos(self.expr))
Exemplo n.º 13
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 == "event":
        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, ast.AnnAssign) and isinstance(
            item.annotation, ast.Name) and item.annotation.id in _contracts:
        _globals[item.target.id] = VariableRecord(
            item.target.id, len(_globals),
            BaseType('address', item.annotation.id), 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)")
        if isinstance(item.annotation.args[0],
                      ast.Name) and item.annotation.args[0].id in _contracts:
            typ = BaseType('address', item.annotation.args[0].id)
        else:
            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
Exemplo n.º 14
0
    def add_globals_and_events(self, item):
        item_attributes = {"public": False}

        if len(self._globals) > NONRENTRANT_STORAGE_OFFSET:
            raise ParserException(
                f"Too many globals defined, only {NONRENTRANT_STORAGE_OFFSET} globals are allowed",
                item,
            )

        # Make sure we have a valid variable name.
        if not isinstance(item.target, ast.Name):
            raise StructureException('Invalid global variable name',
                                     item.target)

        # Handle constants.
        if self.get_call_func_name(item) == "constant":
            self._constants.add_constant(item, global_ctx=self)
            return

        # Handle events.
        if not (self.get_call_func_name(item) == "event"):
            item_name, item_attributes = self.get_item_name_and_attributes(
                item, item_attributes)
            if not all([
                    attr in VALID_GLOBAL_KEYWORDS
                    for attr in item_attributes.keys()
            ]):
                raise StructureException(
                    f'Invalid global keyword used: {item_attributes}', item)

        if item.value is not None:
            raise StructureException(
                'May not assign value whilst defining type', item)
        elif self.get_call_func_name(item) == "event":
            if self._globals or len(self._defs):
                raise EventDeclarationException(
                    "Events must all come before global declarations and function definitions",
                    item)
            self._events.append(item)
        elif not isinstance(item.target, ast.Name):
            raise StructureException(
                "Can only assign type to variable in top-level statement",
                item)

        # Is this a custom unit definition.
        elif item.target.id == 'units':
            if not self._custom_units:
                if not isinstance(item.annotation, ast.Dict):
                    raise VariableDeclarationException(
                        "Define custom units using units: { }.", item.target)
                for key, value in zip(item.annotation.keys,
                                      item.annotation.values):
                    if not isinstance(value, ast.Str):
                        raise VariableDeclarationException(
                            "Custom unit description must be a valid string",
                            value)
                    if not isinstance(key, ast.Name):
                        raise VariableDeclarationException(
                            "Custom unit name must be a valid string", key)
                    check_valid_varname(key.id, self._custom_units,
                                        self._structs, self._constants, key,
                                        "Custom unit invalid.")
                    self._custom_units.add(key.id)
                    self._custom_units_descriptions[key.id] = value.s
            else:
                raise VariableDeclarationException(
                    "Custom units can only be defined once", item.target)

        # Check if variable name is valid.
        # Don't move this check higher, as unit parsing has to happen first.
        elif not self.is_valid_varname(item.target.id, item):
            pass

        elif len(self._defs):
            raise StructureException(
                "Global variables must all come before function definitions",
                item,
            )

        elif item_name in self._contracts or item_name in self._interfaces:
            if self.get_call_func_name(item) == "address":
                raise StructureException(
                    f"Persistent address({item_name}) style contract declarations "
                    "are not support anymore."
                    f" Use {item.target.id}: {item_name} instead")
            self._globals[item.target.id] = ContractRecord(
                item.target.id,
                len(self._globals),
                ContractType(item_name),
                True,
            )
            if item_attributes["public"]:
                typ = ContractType(item_name)
                for getter in self.mk_getter(item.target.id, typ):
                    self._getters.append(
                        self.parse_line('\n' * (item.lineno - 1) + getter))
                    self._getters[-1].pos = getpos(item)
        elif self.get_call_func_name(item) == "public":
            if isinstance(item.annotation.args[0],
                          ast.Name) and item_name in self._contracts:
                typ = ContractType(item_name)
            else:
                typ = parse_type(
                    item.annotation.args[0],
                    'storage',
                    custom_units=self._custom_units,
                    custom_structs=self._structs,
                    constants=self._constants,
                )
            self._globals[item.target.id] = VariableRecord(
                item.target.id,
                len(self._globals),
                typ,
                True,
            )
            # Adding getters here
            for getter in self.mk_getter(item.target.id, typ):
                self._getters.append(
                    self.parse_line('\n' * (item.lineno - 1) + getter))
                self._getters[-1].pos = getpos(item)

        elif isinstance(item.annotation, (ast.Name, ast.Call, ast.Subscript)):
            self._globals[item.target.id] = VariableRecord(
                item.target.id, len(self._globals),
                parse_type(item.annotation,
                           'storage',
                           custom_units=self._custom_units,
                           custom_structs=self._structs,
                           constants=self._constants), True)
        else:
            raise InvalidTypeException('Invalid global type specified', item)
Exemplo n.º 15
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

                    # generate function type and add to metadata
                    # we need this when builing the public getter
                    node._metadata[
                        "func_type"] = ContractFunction.from_AnnAssign(node)

                # 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)
        node._metadata["type"] = type_definition

        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.validate_assignment(name)
        except NamespaceCollision as exc:
            raise exc.with_annotation(node) from None
        try:
            self.namespace["self"].add_member(name, type_definition)
            node.target._metadata["type"] = 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.º 16
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('uint256', {'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('uint256', {'wei': 1}),
                                      pos=getpos(self.expr))
         elif key == "msg.gas":
             return LLLnode.from_list(['gas'],
                                      typ='uint256',
                                      pos=getpos(self.expr))
         elif key == "block.difficulty":
             return LLLnode.from_list(['difficulty'],
                                      typ='uint256',
                                      pos=getpos(self.expr))
         elif key == "block.timestamp":
             return LLLnode.from_list(['timestamp'],
                                      typ=BaseType('uint256', {'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='uint256',
                                      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)
         # contract type
         if isinstance(sub.typ, ContractType):
             return sub
         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.º 17
0
def external_contract_call(node,
                           context,
                           contract_name,
                           contract_address,
                           pos,
                           value=None,
                           gas=None):
    from vyper.parser.expr import (
        Expr, )
    if value is None:
        value = 0
    if gas is None:
        gas = 'gas'
    if not contract_name:
        raise StructureException(
            f'Invalid external contract call "{node.func.attr}".', node)
    if contract_name not in context.sigs:
        raise VariableDeclarationException(
            f'Contract "{contract_name}" not declared yet', node)
    if contract_address.value == "address":
        raise StructureException(f"External calls to self are not permitted.",
                                 node)
    method_name = node.func.attr
    if method_name not in context.sigs[contract_name]:
        raise FunctionDeclarationException((
            f"Function not declared yet: {method_name} (reminder: "
            "function must be declared in the correct contract)"
            f"The available methods are: {','.join(context.sigs[contract_name].keys())}"
        ), node.func)
    sig = context.sigs[contract_name][method_name]
    inargs, inargsize, _ = pack_arguments(
        sig,
        [Expr(arg, context).lll_node for arg in node.args],
        context,
        node.func,
    )
    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() and not sig.const:
        raise ConstancyViolationException(
            f"May not call non-constant function '{method_name}' within {context.pp_constancy()}."
            " For asserting the result of modifiable contract calls, try assert_modifiable.",
            node)

    if context.is_constant() or sig.const:
        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.º 18
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_constant, is_public, is_immutable = False, 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", "immutable"):
                validate_call_args(annotation, 1)
                if call_name == "constant":
                    # declaring a constant
                    is_constant = True

                elif call_name == "public":
                    # declaring a public variable
                    is_public = True

                    # generate function type and add to metadata
                    # we need this when builing the public getter
                    node._metadata["func_type"] = ContractFunction.from_AnnAssign(node)

                elif call_name == "immutable":
                    # declaring an immutable variable
                    is_immutable = True

                    # mutability is checked automatically preventing assignment
                    # outside of the constructor, here we just check a value is assigned,
                    # not necessarily where
                    assignments = self.ast.get_descendants(
                        vy_ast.Assign, filters={"target.id": node.target.id}
                    )
                    if not assignments:
                        # Special error message for common wrong usages via `self.<immutable name>`
                        wrong_self_attribute = self.ast.get_descendants(
                            vy_ast.Attribute, {"value.id": "self", "attr": node.target.id}
                        )
                        message = (
                            "Immutable variables must be accessed without 'self'"
                            if len(wrong_self_attribute) > 0
                            else "Immutable definition requires an assignment in the constructor"
                        )
                        raise SyntaxException(
                            message, node.node_source_code, node.lineno, node.col_offset
                        )

                # remove the outer call node, to handle cases such as `public(map(..))`
                annotation = annotation.args[0]

        data_loc = DataLocation.CODE if is_immutable else DataLocation.STORAGE
        type_definition = get_type_from_annotation(
            annotation, data_loc, is_constant, is_public, is_immutable
        )
        node._metadata["type"] = type_definition

        if is_constant:
            if not node.value:
                raise VariableDeclarationException("Constant must be declared with a value", node)
            if not check_constant(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:
            var_type = "Immutable" if is_immutable else "Storage"
            raise VariableDeclarationException(
                f"{var_type} variables cannot have an initial value", node.value
            )

        if is_immutable:
            try:
                # block immutable if storage variable already exists
                if name in self.namespace["self"].members:
                    raise NamespaceCollision(
                        f"Value '{name}' has already been declared", node
                    ) from None
                self.namespace[name] = type_definition
            except VyperException as exc:
                raise exc.with_annotation(node) from None
            return

        try:
            self.namespace.validate_assignment(name)
        except NamespaceCollision as exc:
            raise exc.with_annotation(node) from None
        try:
            self.namespace["self"].add_member(name, type_definition)
            node.target._metadata["type"] = 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.º 19
0
def external_contract_call(node,
                           context,
                           contract_name,
                           contract_address,
                           pos,
                           value=None,
                           gas=None):
    from vyper.parser.parser import parse_expr
    if value is None:
        value = 0
    if gas is None:
        gas = 'gas'
    if not contract_name:
        raise StructureException(
            f'Invalid external contract call "{node.func.attr}".',
            node
        )
    if contract_name not in context.sigs:
        raise VariableDeclarationException(
            f'Contract "{contract_name}" not declared yet',
            node
        )
    method_name = node.func.attr
    if method_name not in context.sigs[contract_name]:
        raise FunctionDeclarationException(
            (
                "Function not declared yet: %s (reminder: "
                "function must be declared in the correct contract)"
                " The available methods are: %s"
            ) % (method_name, ",".join(context.sigs[contract_name].keys())),
            node.func
        )
    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 sig.const:
        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.º 20
0
Arquivo: stmt.py Projeto: olwee/vyper
 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.º 21
0
def add_globals_and_events(_custom_units, _contracts, _defs, _events, _getters, _globals, item):
    item_attributes = {"public": False}
    if not (isinstance(item.annotation, ast.Call) and item.annotation.func.id == "event"):
        item_name, item_attributes = get_item_name_and_attributes(item, item_attributes)
        if not all([attr in valid_global_keywords for attr in item_attributes.keys()]):
            raise StructureException('Invalid global keyword used: %s' % item_attributes, 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 == "event":
        if _globals or len(_defs):
            raise EventDeclarationException("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)
    # Is this a custom unit definition.
    elif item.target.id == 'units':
        if not _custom_units:
            if not isinstance(item.annotation, ast.Dict):
                raise VariableDeclarationException("Define custom units using units: { }.", item.target)
            for key, value in zip(item.annotation.keys, item.annotation.values):
                if not isinstance(value, ast.Str):
                    raise VariableDeclarationException("Custom unit description must be a valid string.", value)
                if not isinstance(key, ast.Name):
                    raise VariableDeclarationException("Custom unit name must be a valid string unquoted string.", key)
                if key.id in _custom_units:
                    raise VariableDeclarationException("Custom unit may only be defined once", key)
                if not is_varname_valid(key.id, custom_units=_custom_units):
                    raise VariableDeclarationException("Custom unit may not be a reserved keyword", key)
                _custom_units.append(key.id)
        else:
            raise VariableDeclarationException("Can units can only defined once.", item.target)
    # Check if variable name is reserved or invalid
    elif not is_varname_valid(item.target.id, custom_units=_custom_units):
        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 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 item_name in _contracts:
        _globals[item.target.id] = ContractRecord(item.target.id, len(_globals), ContractType(item_name), True)
        if item_attributes["public"]:
            typ = ContractType(item_name)
            for getter in mk_getter(item.target.id, typ):
                _getters.append(parse_line('\n' * (item.lineno - 1) + getter))
                _getters[-1].pos = getpos(item)
    elif isinstance(item.annotation, ast.Call) and item.annotation.func.id == "public":
        if isinstance(item.annotation.args[0], ast.Name) and item_name in _contracts:
            typ = ContractType(item_name)
        else:
            typ = parse_type(item.annotation.args[0], 'storage', custom_units=_custom_units)
        _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', custom_units=_custom_units),
            True
        )
    return _custom_units, _contracts, _events, _globals, _getters
Exemplo n.º 22
0
def parse_func(code, _globals, sigs, origcode, _vars=None):
    if _vars is None:
        _vars = {}
    sig = FunctionSignature.from_definition(code, sigs)
    # 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)
    # 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.º 23
0
    def add_globals_and_events(self, item):
        item_attributes = {"public": False}

        # Make sure we have a valid variable name.
        if not isinstance(item.target, ast.Name):
            raise StructureException('Invalid global variable name',
                                     item.target)

        # Handle constants.
        if self.get_call_func_name(item) == "constant":
            self._constants.add_constant(item, global_ctx=self)
            return

        # Handle events.
        if not (self.get_call_func_name(item) == "event"):
            item_name, item_attributes = self.get_item_name_and_attributes(
                item, item_attributes)
            if not all([
                    attr in valid_global_keywords
                    for attr in item_attributes.keys()
            ]):
                raise StructureException(
                    'Invalid global keyword used: %s' % item_attributes, item)

        if item.value is not None:
            raise StructureException(
                'May not assign value whilst defining type', item)
        elif self.get_call_func_name(item) == "event":
            if self._globals or len(self._defs):
                raise EventDeclarationException(
                    "Events must all come before global declarations and function definitions",
                    item)
            self._events.append(item)
        elif not isinstance(item.target, ast.Name):
            raise StructureException(
                "Can only assign type to variable in top-level statement",
                item)

        # Is this a custom unit definition.
        elif item.target.id == 'units':
            if not self._custom_units:
                if not isinstance(item.annotation, ast.Dict):
                    raise VariableDeclarationException(
                        "Define custom units using units: { }.", item.target)
                for key, value in zip(item.annotation.keys,
                                      item.annotation.values):
                    if not isinstance(value, ast.Str):
                        raise VariableDeclarationException(
                            "Custom unit description must be a valid string",
                            value)
                    if not isinstance(key, ast.Name):
                        raise VariableDeclarationException(
                            "Custom unit name must be a valid string", key)
                    check_valid_varname(key.id, self._custom_units,
                                        self._structs, self._constants, key,
                                        "Custom unit invalid.")
                    self._custom_units.add(key.id)
                    self._custom_units_descriptions[key.id] = value.s
            else:
                raise VariableDeclarationException(
                    "Custom units can only be defined once", item.target)

        # Check if variable name is valid.
        # Don't move this check higher, as unit parsing has to happen first.
        elif not self.is_valid_varname(item.target.id, item):
            pass

        elif len(self._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 self.get_call_func_name(item) == "address":
            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]
            self._contracts[item.target.id] = self.make_contract(
                premade_contract.body)
            self._globals[item.target.id] = VariableRecord(
                item.target.id, len(self._globals), BaseType('address'), True)

        elif item_name in self._contracts:
            self._globals[item.target.id] = ContractRecord(
                item.target.id, len(self._globals), ContractType(item_name),
                True)
            if item_attributes["public"]:
                typ = ContractType(item_name)
                for getter in self.mk_getter(item.target.id, typ):
                    self._getters.append(
                        self.parse_line('\n' * (item.lineno - 1) + getter))
                    self._getters[-1].pos = getpos(item)

        elif self.get_call_func_name(item) == "public":
            if isinstance(item.annotation.args[0],
                          ast.Name) and item_name in self._contracts:
                typ = ContractType(item_name)
            else:
                typ = parse_type(item.annotation.args[0],
                                 'storage',
                                 custom_units=self._custom_units,
                                 custom_structs=self._structs,
                                 constants=self._constants)
            self._globals[item.target.id] = VariableRecord(
                item.target.id, len(self._globals), typ, True)
            # Adding getters here
            for getter in self.mk_getter(item.target.id, typ):
                self._getters.append(
                    self.parse_line('\n' * (item.lineno - 1) + getter))
                self._getters[-1].pos = getpos(item)

        elif isinstance(item.annotation, (ast.Name, ast.Call, ast.Subscript)):
            self._globals[item.target.id] = VariableRecord(
                item.target.id, len(self._globals),
                parse_type(item.annotation,
                           'storage',
                           custom_units=self._custom_units,
                           custom_structs=self._structs,
                           constants=self._constants), True)
        else:
            raise InvalidTypeException('Invalid global type specified', item)
Exemplo n.º 24
0
    def from_declaration(cls, code, global_ctx):
        name = code.target.id
        pos = 0

        check_valid_varname(
            name, global_ctx._custom_units, global_ctx._structs, global_ctx._constants,
            pos=code, error_prefix="Event name invalid. ", exc=EventDeclarationException
        )

        # 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]
                if not isinstance(keys[i], ast.Name):
                    raise EventDeclarationException(
                        'Invalid key type, expected a valid name.',
                        keys[i],
                    )
                if not isinstance(typ, (ast.Name, ast.Call, ast.Subscript)):
                    raise EventDeclarationException('Invalid event argument type.', typ)
                if isinstance(typ, ast.Call) and not isinstance(typ.func, ast.Name):
                    raise EventDeclarationException('Invalid event argument type', typ)
                arg = keys[i].id
                arg_item = keys[i]
                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:  # noqa: E501
                    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)
                check_valid_varname(
                    arg,
                    global_ctx._custom_units,
                    global_ctx._structs,
                    global_ctx._constants,
                    pos=arg_item,
                    error_prefix="Event argument name invalid or reserved.",
                )
                if arg in (x.name for x in args):
                    raise VariableDeclarationException(
                        "Duplicate function argument name: " + arg,
                        arg_item,
                    )
                # Can struct be logged?
                parsed_type = global_ctx.parse_type(typ, None)
                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.º 25
0
    def call(self):
        from .parser import (
            pack_arguments,
            pack_logging_data,
            pack_logging_topics,
            external_contract_call,
        )
        if isinstance(self.stmt.func,
                      ast.Name) and self.stmt.func.id in stmt_dispatch_table:
            return stmt_dispatch_table[self.stmt.func.id](self.stmt,
                                                          self.context)
        elif isinstance(self.stmt.func, ast.Attribute) and isinstance(
                self.stmt.func.value,
                ast.Name) and self.stmt.func.value.id == "self":
            method_name = self.stmt.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.stmt.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))
            add_gas = self.context.sigs['self'][method_name].gas
            inargs, inargsize = pack_arguments(
                sig,
                [Expr(arg, self.context).lll_node for arg in self.stmt.args],
                self.context,
                pos=getpos(self.stmt))
            return LLLnode.from_list([
                'assert',
                ['call', ['gas'], ['address'], 0, inargs, inargsize, 0, 0]
            ],
                                     typ=None,
                                     pos=getpos(self.stmt),
                                     add_gas_estimate=add_gas,
                                     annotation='Internal Call: %s' %
                                     method_name)
        elif isinstance(self.stmt.func, ast.Attribute) and isinstance(
                self.stmt.func.value, ast.Call):
            contract_name = self.stmt.func.value.func.id
            contract_address = Expr.parse_value_expr(
                self.stmt.func.value.args[0], self.context)
            return external_contract_call(self.stmt,
                                          self.context,
                                          contract_name,
                                          contract_address,
                                          pos=getpos(self.stmt))
        elif isinstance(self.stmt.func.value, ast.Attribute
                        ) and self.stmt.func.value.attr in self.context.sigs:
            contract_name = self.stmt.func.value.attr
            var = self.context.globals[self.stmt.func.value.attr]
            contract_address = unwrap_location(
                LLLnode.from_list(var.pos,
                                  typ=var.typ,
                                  location='storage',
                                  pos=getpos(self.stmt),
                                  annotation='self.' +
                                  self.stmt.func.value.attr))
            return external_contract_call(self.stmt,
                                          self.context,
                                          contract_name,
                                          contract_address,
                                          pos=getpos(self.stmt))
        elif isinstance(
                self.stmt.func.value, ast.Attribute
        ) and self.stmt.func.value.attr in self.context.globals:
            contract_name = self.context.globals[
                self.stmt.func.value.attr].typ.unit
            var = self.context.globals[self.stmt.func.value.attr]
            contract_address = unwrap_location(
                LLLnode.from_list(var.pos,
                                  typ=var.typ,
                                  location='storage',
                                  pos=getpos(self.stmt),
                                  annotation='self.' +
                                  self.stmt.func.value.attr))
            return external_contract_call(self.stmt,
                                          self.context,
                                          contract_name,
                                          contract_address,
                                          pos=getpos(self.stmt))
        elif isinstance(self.stmt.func,
                        ast.Attribute) and self.stmt.func.value.id == 'log':
            if self.stmt.func.attr not in self.context.sigs['self']:
                raise VariableDeclarationException(
                    "Event not declared yet: %s" % self.stmt.func.attr)
            event = self.context.sigs['self'][self.stmt.func.attr]
            if len(event.indexed_list) != len(self.stmt.args):
                raise VariableDeclarationException(
                    "%s received %s arguments but expected %s" %
                    (event.name, len(self.stmt.args), len(event.indexed_list)))
            expected_topics, topics = [], []
            expected_data, data = [], []
            for pos, is_indexed in enumerate(event.indexed_list):
                if is_indexed:
                    expected_topics.append(event.args[pos])
                    topics.append(self.stmt.args[pos])
                else:
                    expected_data.append(event.args[pos])
                    data.append(self.stmt.args[pos])
            topics = pack_logging_topics(event.event_id,
                                         topics,
                                         expected_topics,
                                         self.context,
                                         pos=getpos(self.stmt))
            inargs, inargsize, inargsize_node, inarg_start = pack_logging_data(
                expected_data, data, self.context, pos=getpos(self.stmt))

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

            return LLLnode.from_list([
                'seq', inargs,
                LLLnode.from_list(
                    ["log" + str(len(topics)), inarg_start, sz] + topics,
                    add_gas_estimate=inargsize * 10)
            ],
                                     typ=None,
                                     pos=getpos(self.stmt))
        else:
            raise StructureException(
                "Unsupported operator: %r" % ast.dump(self.stmt), self.stmt)
Exemplo n.º 26
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)
Exemplo n.º 27
0
def add_globals_and_events(_contracts, _defs, _events, _getters, _globals,
                           item):
    item_attributes = {"public": False, "modifiable": False, "static": False}
    if not (isinstance(item.annotation, ast.Call)
            and item.annotation.func.id == "event"):
        item_name, item_attributes = get_item_name_and_attributes(
            item, item_attributes)
        if not all(
            [attr in valid_global_keywords
             for attr in item_attributes.keys()]):
            raise StructureException('Invalid global keyword used: %s' %
                                     item_attributes)
    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 == "event":
        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 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 item_name in _contracts:
        if not item_attributes["modifiable"] and not item_attributes["static"]:
            raise StructureException(
                "All contracts must have `modifiable` or `static` keywords: %s"
                % item_attributes)
        _globals[item.target.id] = ContractRecord(
            item_attributes["modifiable"], item.target.id, len(_globals),
            BaseType('address', item_name), True)
        if item_attributes["public"]:
            typ = BaseType('address', item_name)
            for getter in mk_getter(item.target.id, typ):
                _getters.append(parse_line('\n' * (item.lineno - 1) + getter))
                _getters[-1].pos = getpos(item)
    elif isinstance(item.annotation,
                    ast.Call) and item.annotation.func.id == "public":
        if isinstance(item.annotation.args[0],
                      ast.Name) and item_name in _contracts:
            typ = BaseType('address', item_name)
        else:
            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