Exemplo n.º 1
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 == "__log__":
        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.annotation,
                    ast.Call) and item.annotation.func.id == "public":
        if len(item.annotation.args) != 1:
            raise StructureException("Public expects one arg (the type)")
        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.º 2
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)
Exemplo n.º 3
0
 def new_variable(self, name, typ):
     if not is_varname_valid(name):
         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)
     pos = self.next_mem
     self.next_mem += 32 * get_size_of_type(typ)
     return pos
Exemplo n.º 4
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