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

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

    o.context = context
    o.total_gas = o.gas + calc_mem_gas(o.context.next_mem)
    o.func_name = sig.name
    return o
Esempio n. 2
0
 def new_variable(self, name, typ):
     if not is_varname_valid(name, custom_units=self.custom_units):
         raise VariableDeclarationException("Variable name invalid or reserved: " + name)
     if name in self.vars or name in self.globals:
         raise VariableDeclarationException("Duplicate variable name: %s" % name)
     self.vars[name] = VariableRecord(name, self.next_mem, typ, True, self.blockscopes.copy())
     pos = self.next_mem
     self.next_mem += 32 * get_size_of_type(typ)
     return pos
Esempio n. 3
0
 def from_declaration(cls, code):
     name = code.target.id
     pos = 0
     # Determine the arguments, expects something of the form def foo(arg1: num, arg2: num ...
     args = []
     indexed_list = []
     topics_count = 1
     if code.annotation.args:
         keys = code.annotation.args[0].keys
         values = code.annotation.args[0].values
         for i in range(len(keys)):
             typ = values[i]
             arg = keys[i].id
             is_indexed = False
             # Check to see if argument is a topic
             if isinstance(typ, ast.Call) and typ.func.id == 'indexed':
                 typ = values[i].args[0]
                 indexed_list.append(True)
                 topics_count += 1
                 is_indexed = True
             else:
                 indexed_list.append(False)
             if hasattr(
                     typ,
                     'left') and typ.left.id == 'bytes' and typ.comparators[
                         0].n > 32 and is_indexed:
                 raise VariableDeclarationException(
                     "Indexed arguments are limited to 32 bytes")
             if topics_count > 4:
                 raise VariableDeclarationException(
                     "Maximum of 3 topics {} given".format(topics_count -
                                                           1), arg)
             if not isinstance(arg, str):
                 raise VariableDeclarationException("Argument name invalid",
                                                    arg)
             if not typ:
                 raise InvalidTypeException("Argument must have type", arg)
             if not is_varname_valid(arg):
                 raise VariableDeclarationException(
                     "Argument name invalid or reserved: " + arg, arg)
             if arg in (x.name for x in args):
                 raise VariableDeclarationException(
                     "Duplicate function argument name: " + arg, arg)
             parsed_type = parse_type(typ, None)
             args.append(VariableRecord(arg, pos, parsed_type, False))
             if isinstance(parsed_type, ByteArrayType):
                 pos += ceil32(typ.comparators[0].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)
     ]) + ')'
     event_id = bytes_to_int(sha3(bytes(sig, 'utf-8')))
     return cls(name, args, indexed_list, event_id, sig)
Esempio n. 4
0
def add_globals_and_events(_custom_units, _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, 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)
    # 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:
        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), 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
Esempio n. 5
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