Ejemplo n.º 1
0
    def __init__(self, vyper_module: vy_ast.Module,
                 fn_node: vy_ast.FunctionDef, namespace: dict) -> None:
        self.vyper_module = vyper_module
        self.fn_node = fn_node
        self.namespace = namespace
        self.func = fn_node._metadata["type"]
        self.annotation_visitor = StatementAnnotationVisitor(
            fn_node, namespace)
        namespace.update(self.func.arguments)

        if self.func.visibility is FunctionVisibility.INTERNAL:
            node_list = fn_node.get_descendants(vy_ast.Attribute, {
                "value.id": "msg",
                "attr": {"data", "sender"}
            })
            if node_list:
                raise StateAccessViolation(
                    f"msg.{node_list[0].attr} is not allowed in internal functions",
                    node_list[0])
        if self.func.mutability == StateMutability.PURE:
            node_list = fn_node.get_descendants(
                vy_ast.Attribute,
                {
                    "value.id":
                    set(CONSTANT_ENVIRONMENT_VARS.keys()).union(
                        set(MUTABLE_ENVIRONMENT_VARS.keys()))
                },
            )
            if node_list:
                raise StateAccessViolation(
                    "not allowed to query contract or environment variables in pure functions",
                    node_list[0],
                )
        if self.func.mutability is not StateMutability.PAYABLE:
            node_list = fn_node.get_descendants(vy_ast.Attribute, {
                "value.id": "msg",
                "attr": "value"
            })
            if node_list:
                raise NonPayableViolation(
                    "msg.value is not allowed in non-payable functions",
                    node_list[0])

        for node in fn_node.body:
            self.visit(node)
        if self.func.return_type:
            if not check_for_terminus(fn_node.body):
                raise FunctionDeclarationException(
                    f"Missing or unmatched return statements in function '{fn_node.name}'",
                    fn_node,
                )
Ejemplo n.º 2
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))