Example #1
0
def gen_tuple_return(stmt, context, sub):
    # Is from a call expression.
    if sub.args and len(sub.args[0].args) > 0 and (
            sub.args[0].args[0].value == "call"
            or sub.args[0].args[0].value == "staticcall"):
        # self-call to external.
        mem_pos = sub
        mem_size = get_size_of_type(sub.typ) * 32
        return LLLnode.from_list(["return", mem_pos, mem_size], typ=sub.typ)

    elif sub.annotation and "Internal Call" in sub.annotation:
        mem_pos = sub.args[
            -1].value if sub.value == "seq_unchecked" else sub.args[0].args[-1]
        mem_size = get_size_of_type(sub.typ) * 32
        # Add zero padder if bytes are present in output.
        zero_padder = ["pass"]
        byte_arrays = [(i, x) for i, x in enumerate(sub.typ.tuple_members())
                       if isinstance(x, ByteArrayLike)]
        if byte_arrays:
            i, x = byte_arrays[-1]
            zero_padder = zero_pad(bytez_placeholder=[
                "add", mem_pos, ["mload", mem_pos + i * 32]
            ])
        return LLLnode.from_list(
            ["seq"] + [sub] + [zero_padder] +
            [make_return_stmt(stmt, context, mem_pos, mem_size)],
            typ=sub.typ,
            pos=getpos(stmt),
            valency=0,
        )

    abi_typ = abi_type_of(context.return_type)
    # according to the ABI, return types are ALWAYS tuples even if
    # only one element is being returned.
    # https://solidity.readthedocs.io/en/latest/abi-spec.html#function-selector-and-argument-encoding
    # "and the return values v_1, ..., v_k of f are encoded as
    #
    #    enc((v_1, ..., v_k))
    #    i.e. the values are combined into a tuple and encoded.
    # "
    # therefore, wrap it in a tuple if it's not already a tuple.
    # (big difference between returning `(bytes,)` and `bytes`.
    abi_typ = ensure_tuple(abi_typ)
    abi_bytes_needed = abi_typ.static_size() + abi_typ.dynamic_size_bound()
    dst, _ = context.memory_allocator.increase_memory(abi_bytes_needed)
    return_buffer = LLLnode(dst,
                            location="memory",
                            annotation="return_buffer",
                            typ=context.return_type)

    check_assign(return_buffer, sub, pos=getpos(stmt))

    encode_out = abi_encode(return_buffer, sub, pos=getpos(stmt), returns=True)
    load_return_len = ["mload", MemoryPositions.FREE_VAR_SPACE]
    os = [
        "seq",
        ["mstore", MemoryPositions.FREE_VAR_SPACE, encode_out],
        make_return_stmt(stmt, context, return_buffer, load_return_len),
    ]
    return LLLnode.from_list(os, typ=None, pos=getpos(stmt), valency=0)
    def calculate_arg_totals(self):
        """ Calculate base arguments, and totals. """

        code = self.func_ast_code
        self.base_args = []
        self.total_default_args = 0

        if hasattr(code.args, "defaults"):
            self.total_default_args = len(code.args.defaults)
            if self.total_default_args > 0:
                # all argument w/o defaults
                self.base_args = self.args[:-self.total_default_args]
            else:
                # No default args, so base_args = args.
                self.base_args = self.args
            # All default argument name/type definitions.
            self.default_args = code.args.args[
                -self.total_default_args:]  # noqa: E203
            # Keep all the value to assign to default parameters.
            self.default_values = dict(
                zip([arg.arg for arg in self.default_args],
                    code.args.defaults))

        # Calculate the total sizes in memory the function arguments will take use.
        # Total memory size of all arguments (base + default together).
        self.max_copy_size = sum([
            32 if isinstance(arg.typ, ByteArrayLike) else
            get_size_of_type(arg.typ) * 32 for arg in self.args
        ])
        # Total memory size of base arguments (arguments exclude default parameters).
        self.base_copy_size = sum([
            32 if isinstance(arg.typ, ByteArrayLike) else
            get_size_of_type(arg.typ) * 32 for arg in self.base_args
        ])
Example #3
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
Example #4
0
def external_contract_call_expr(expr, context, contract_name,
                                contract_address):
    if contract_name not in context.sigs:
        raise VariableDeclarationException("Contract not declared yet: %s" %
                                           contract_name)
    method_name = expr.func.attr
    if method_name not in context.sigs[contract_name]:
        raise VariableDeclarationException(
            "Function not declared yet: %s (reminder: "
            "function must be declared in the correct contract)" % method_name)
    sig = context.sigs[contract_name][method_name]
    inargs, inargsize = pack_arguments(
        sig, [parse_expr(arg, context) for arg in expr.args], context)
    output_placeholder = context.new_placeholder(typ=sig.output_type)
    if isinstance(sig.output_type, BaseType):
        returner = output_placeholder
    elif isinstance(sig.output_type, ByteArrayType):
        returner = output_placeholder + 32
    else:
        raise TypeMismatchException(
            "Invalid output type: %r" % sig.output_type, expr)
    sub = [
        'seq', ['assert', ['extcodesize', contract_address]],
        ['assert', ['ne', 'address', contract_address]]
    ]
    if context.is_constant:
        sub.append([
            'assert',
            [
                'staticcall', 'gas', contract_address, inargs, inargsize,
                output_placeholder,
                get_size_of_type(sig.output_type) * 32
            ]
        ])
    else:
        sub.append([
            'assert',
            [
                'call', 'gas', contract_address, 0, inargs, inargsize,
                output_placeholder,
                get_size_of_type(sig.output_type) * 32
            ]
        ])
    sub.extend([0, returner])
    o = LLLnode.from_list(sub,
                          typ=sig.output_type,
                          location='memory',
                          pos=getpos(expr))
    return o
Example #5
0
def _call_make_placeholder(stmt_expr, context, sig):
    if sig.output_type is None:
        return 0, 0, 0

    output_placeholder = context.new_placeholder(typ=sig.output_type)
    output_size = get_size_of_type(sig.output_type) * 32

    if isinstance(sig.output_type, BaseType):
        returner = output_placeholder
    elif isinstance(sig.output_type, ByteArrayLike):
        returner = output_placeholder
    elif isinstance(sig.output_type, TupleLike):
        # incase of struct we need to decode the output and then return it
        returner = ["seq"]
        decoded_placeholder = context.new_placeholder(typ=sig.output_type)
        decoded_node = LLLnode(decoded_placeholder,
                               typ=sig.output_type,
                               location="memory")
        output_node = LLLnode(output_placeholder,
                              typ=sig.output_type,
                              location="memory")
        returner.append(abi_decode(decoded_node, output_node))
        returner.extend([decoded_placeholder])
    elif isinstance(sig.output_type, ListType):
        returner = output_placeholder
    else:
        raise TypeCheckFailure(f"Invalid output type: {sig.output_type}")
    return output_placeholder, returner, output_size
Example #6
0
def serialise_var_rec(var_rec):
    if isinstance(var_rec.typ, ByteArrayType):
        type_str = 'bytes[%s]' % var_rec.typ.maxlen
        _size = get_size_of_type(var_rec.typ) * 32
    elif isinstance(var_rec.typ, TupleType):
        type_str = 'tuple'
        _size = get_size_of_type(var_rec.typ) * 32
    elif isinstance(var_rec.typ, MappingType):
        type_str = str(var_rec.typ)
        _size = 0
    else:
        type_str = var_rec.typ.typ
        _size = get_size_of_type(var_rec.typ) * 32

    out = {'type': type_str, 'size': _size, 'position': var_rec.pos}
    return out
Example #7
0
def make_clamper(datapos, mempos, typ, is_init=False):
    if not is_init:
        data_decl = ['calldataload', ['add', 4, datapos]]
        copier = lambda pos, sz: ['calldatacopy', mempos, ['add', 4, pos], sz]
    else:
        data_decl = ['codeload', ['add', '~codelen', datapos]]
        copier = lambda pos, sz: ['codecopy', mempos, ['add', '~codelen', pos], sz]
    # Numbers: make sure they're in range
    if is_base_type(typ, 'int128'):
        return LLLnode.from_list(['clamp', ['mload', MemoryPositions.MINNUM], data_decl, ['mload', MemoryPositions.MAXNUM]],
                                 typ=typ, annotation='checking int128 input')
    # Booleans: make sure they're zero or one
    elif is_base_type(typ, 'bool'):
        return LLLnode.from_list(['uclamplt', data_decl, 2], typ=typ, annotation='checking bool input')
    # Addresses: make sure they're in range
    elif is_base_type(typ, 'address'):
        return LLLnode.from_list(['uclamplt', data_decl, ['mload', MemoryPositions.ADDRSIZE]], typ=typ, annotation='checking address input')
    # Bytes: make sure they have the right size
    elif isinstance(typ, ByteArrayType):
        return LLLnode.from_list(['seq',
                                    copier(data_decl, 32 + typ.maxlen),
                                    ['assert', ['le', ['calldataload', ['add', 4, data_decl]], typ.maxlen]]],
                                 typ=None, annotation='checking bytearray input')
    # Lists: recurse
    elif isinstance(typ, ListType):
        o = []
        for i in range(typ.count):
            offset = get_size_of_type(typ.subtype) * 32 * i
            o.append(make_clamper(datapos + offset, mempos + offset, typ.subtype, is_init))
        return LLLnode.from_list(['seq'] + o, typ=None, annotation='checking list input')
    # Otherwise don't make any checks
    else:
        return LLLnode.from_list('pass')
 def size(self):
     if hasattr(self.typ, "size_in_bytes"):
         # temporary requirement to support both new and old type objects
         # we divide by 32 here because the returned value is denominated
         # in "slots" of 32 bytes each
         return math.ceil(self.typ.size_in_bytes / 32)
     return get_size_of_type(self.typ)
Example #9
0
    def _assert_reason(self, test_expr, msg):
        if isinstance(msg, vy_ast.Name) and msg.id == "UNREACHABLE":
            return LLLnode.from_list(["assert_unreachable", test_expr],
                                     typ=None,
                                     pos=getpos(msg))

        reason_str_type = ByteArrayType(len(msg.value.strip()))

        sig_placeholder = self.context.new_internal_variable(BaseType(32))
        arg_placeholder = self.context.new_internal_variable(BaseType(32))
        placeholder_bytes = Expr(msg, self.context).lll_node

        method_id = fourbytes_to_int(keccak256(b"Error(string)")[:4])

        revert_seq = [
            "seq",
            ["mstore", sig_placeholder, method_id],
            ["mstore", arg_placeholder, 32],
            placeholder_bytes,
            [
                "revert", sig_placeholder + 28,
                int(4 + get_size_of_type(reason_str_type) * 32)
            ],
        ]
        if test_expr:
            lll_node = ["if", ["iszero", test_expr], revert_seq]
        else:
            lll_node = revert_seq

        return LLLnode.from_list(lll_node, typ=None, pos=getpos(self.stmt))
Example #10
0
    def _assert_reason(self, test_expr, msg):
        if isinstance(msg, vy_ast.Name) and msg.id == "UNREACHABLE":
            return LLLnode.from_list(["assert_unreachable", test_expr],
                                     typ=None,
                                     pos=getpos(msg))

        reason_str = msg.s.strip()
        sig_placeholder = self.context.new_placeholder(BaseType(32))
        arg_placeholder = self.context.new_placeholder(BaseType(32))
        reason_str_type = ByteArrayType(len(reason_str))
        placeholder_bytes = Expr(msg, self.context).lll_node
        method_id = fourbytes_to_int(keccak256(b"Error(string)")[:4])
        assert_reason = [
            "seq",
            ["mstore", sig_placeholder, method_id],
            ["mstore", arg_placeholder, 32],
            placeholder_bytes,
            [
                "assert_reason",
                test_expr,
                int(sig_placeholder + 28),
                int(4 + get_size_of_type(reason_str_type) * 32),
            ],
        ]
        return LLLnode.from_list(assert_reason,
                                 typ=None,
                                 pos=getpos(self.stmt))
Example #11
0
    def new_internal_variable(self, typ: NodeType) -> int:
        """
        Allocate memory for an internal variable.

        Arguments
        ---------
        typ : NodeType
            Variable type, used to determine the size of memory allocation

        Returns
        -------
        int
            Memory offset for the variable
        """
        # internal variable names begin with a number sign so there is no chance for collision
        var_id = self._internal_var_iter
        self._internal_var_iter += 1
        name = f"#internal_{var_id}"

        if hasattr(typ, "size_in_bytes"):
            # temporary requirement to support both new and old type objects
            var_size = typ.size_in_bytes  # type: ignore
        else:
            var_size = 32 * get_size_of_type(typ)
        return self._new_variable(name, typ, var_size, True)
Example #12
0
def get_external_call_output(sig, context):
    if not sig.output_type:
        return 0, 0, []
    output_placeholder = context.new_internal_variable(typ=sig.output_type)
    output_size = get_size_of_type(sig.output_type) * 32
    if isinstance(sig.output_type, BaseType):
        returner = [0, output_placeholder]
    elif isinstance(sig.output_type, ByteArrayLike):
        returner = [0, output_placeholder + 32]
    elif isinstance(sig.output_type, TupleLike):
        # incase of struct we need to decode the output and then return it
        returner = ["seq"]
        decoded_placeholder = context.new_internal_variable(
            typ=sig.output_type)
        decoded_node = LLLnode(decoded_placeholder,
                               typ=sig.output_type,
                               location="memory")
        output_node = LLLnode(output_placeholder,
                              typ=sig.output_type,
                              location="memory")
        returner.append(abi_decode(decoded_node, output_node))
        returner.extend([0, decoded_placeholder])
    elif isinstance(sig.output_type, ListType):
        returner = [0, output_placeholder]
    else:
        raise TypeCheckFailure(f"Invalid output type: {sig.output_type}")
    return output_placeholder, output_size, returner
Example #13
0
 def new_variable(self, name, typ, pos=None):
     if self.is_valid_varname(name, pos):
         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
Example #14
0
File: stmt.py Project: agroce/vyper
    def _assert_reason(self, test_expr, msg):
        if isinstance(msg, ast.Name) and msg.id == 'UNREACHABLE':
            return self._assert_unreachable(test_expr, msg)

        if not isinstance(msg, ast.Str):
            raise StructureException(
                'Reason parameter of assert needs to be a literal string '
                '(or UNREACHABLE constant).', msg)
        if len(msg.s.strip()) == 0:
            raise StructureException('Empty reason string not allowed.',
                                     self.stmt)
        reason_str = msg.s.strip()
        sig_placeholder = self.context.new_placeholder(BaseType(32))
        arg_placeholder = self.context.new_placeholder(BaseType(32))
        reason_str_type = ByteArrayType(len(reason_str))
        placeholder_bytes = Expr(msg, self.context).lll_node
        method_id = fourbytes_to_int(keccak256(b"Error(string)")[:4])
        assert_reason = [
            'seq',
            ['mstore', sig_placeholder, method_id],
            ['mstore', arg_placeholder, 32],
            placeholder_bytes,
            [
                'assert_reason',
                test_expr,
                int(sig_placeholder + 28),
                int(4 + 32 + get_size_of_type(reason_str_type) * 32),
            ],
        ]
        return LLLnode.from_list(assert_reason,
                                 typ=None,
                                 pos=getpos(self.stmt))
Example #15
0
    def new_variable(self, name: str, typ: NodeType, pos: VyperNode = None) -> int:
        """
        Allocate memory for a user-defined variable.

        Arguments
        ---------
        name : str
            Name of the variable
        typ : NodeType
            Variable type, used to determine the size of memory allocation
        pos : VyperNode
            AST node corresponding to the location where the variable was created,
            used for annotating exceptions

        Returns
        -------
        int
            Memory offset for the variable
        """

        if hasattr(typ, "size_in_bytes"):
            # temporary requirement to support both new and old type objects
            var_size = typ.size_in_bytes  # type: ignore
        else:
            var_size = 32 * get_size_of_type(typ)
        return self._new_variable(name, typ, var_size, False)
Example #16
0
    def parse_assert(self):

        with self.context.assertion_scope():
            test_expr = Expr.parse_value_expr(self.stmt.test, self.context)

        if not self.is_bool_expr(test_expr):
            raise TypeMismatchException('Only boolean expressions allowed', self.stmt.test)
        if self.stmt.msg:
            if not isinstance(self.stmt.msg, ast.Str):
                raise StructureException(
                    'Reason parameter of assert needs to be a literal string.', self.stmt.msg
                )
            if len(self.stmt.msg.s.strip()) == 0:
                raise StructureException('Empty reason string not allowed.', self.stmt)
            reason_str = self.stmt.msg.s.strip()
            sig_placeholder = self.context.new_placeholder(BaseType(32))
            arg_placeholder = self.context.new_placeholder(BaseType(32))
            reason_str_type = ByteArrayType(len(reason_str))
            placeholder_bytes = Expr(self.stmt.msg, self.context).lll_node
            method_id = fourbytes_to_int(sha3(b"Error(string)")[:4])
            assert_reason = [
                'seq',
                ['mstore', sig_placeholder, method_id],
                ['mstore', arg_placeholder, 32],
                placeholder_bytes,
                [
                    'assert_reason',
                    test_expr,
                    int(sig_placeholder + 28),
                    int(4 + 32 + get_size_of_type(reason_str_type) * 32),
                ],
            ]
            return LLLnode.from_list(assert_reason, typ=None, pos=getpos(self.stmt))
        else:
            return LLLnode.from_list(['assert', test_expr], typ=None, pos=getpos(self.stmt))
Example #17
0
def pack_arguments(signature, args, context, pos):
    placeholder_typ = ByteArrayType(maxlen=sum([get_size_of_type(arg.typ) for arg in signature.args]) * 32 + 32)
    placeholder = context.new_placeholder(placeholder_typ)
    setters = [['mstore', placeholder, signature.method_id]]
    needpos = False
    staticarray_offset = 0
    expected_arg_count = len(signature.args)
    actual_arg_count = len(args)
    if actual_arg_count != expected_arg_count:
        raise StructureException("Wrong number of args for: %s (%s args, expected %s)" % (signature.name, actual_arg_count, expected_arg_count))

    for i, (arg, typ) in enumerate(zip(args, [arg.typ for arg in signature.args])):
        if isinstance(typ, BaseType):
            setters.append(make_setter(LLLnode.from_list(placeholder + staticarray_offset + 32 + i * 32, typ=typ), arg, 'memory', pos=pos))
        elif isinstance(typ, ByteArrayType):
            setters.append(['mstore', placeholder + staticarray_offset + 32 + i * 32, '_poz'])
            arg_copy = LLLnode.from_list('_s', typ=arg.typ, location=arg.location)
            target = LLLnode.from_list(['add', placeholder + 32, '_poz'], typ=typ, location='memory')
            setters.append(['with', '_s', arg, ['seq',
                                                    make_byte_array_copier(target, arg_copy),
                                                    ['set', '_poz', ['add', 32, ['add', '_poz', get_length(arg_copy)]]]]])
            needpos = True
        elif isinstance(typ, ListType):
            target = LLLnode.from_list([placeholder + 32 + staticarray_offset + i * 32], typ=typ, location='memory')
            setters.append(make_setter(target, arg, 'memory', pos=pos))
            staticarray_offset += 32 * (typ.count - 1)
        else:
            raise TypeMismatchException("Cannot pack argument of type %r" % typ)
    if needpos:
        return LLLnode.from_list(['with', '_poz', len(args) * 32 + staticarray_offset, ['seq'] + setters + [placeholder + 28]],
                                 typ=placeholder_typ, location='memory'), \
            placeholder_typ.maxlen - 28
    else:
        return LLLnode.from_list(['seq'] + setters + [placeholder + 28], typ=placeholder_typ, location='memory'), \
            placeholder_typ.maxlen - 28
Example #18
0
    def from_declaration(cls, code, custom_units=None):
        name = code.target.id
        pos = 0

        if not is_varname_valid(name, custom_units=custom_units):
            raise EventDeclarationException("Event name invalid: " + name)
        # Determine the arguments, expects something of the form def foo(arg1: num, arg2: num ...
        args = []
        indexed_list = []
        topics_count = 1
        if code.annotation.args:
            keys = code.annotation.args[0].keys
            values = code.annotation.args[0].values
            for i in range(len(keys)):
                typ = values[i]
                arg = keys[i].id
                is_indexed = False
                # Check to see if argument is a topic
                if isinstance(typ, ast.Call) and typ.func.id == 'indexed':
                    typ = values[i].args[0]
                    indexed_list.append(True)
                    topics_count += 1
                    is_indexed = True
                else:
                    indexed_list.append(False)
                if isinstance(typ, ast.Subscript) and getattr(
                        typ.value, 'id', None
                ) == 'bytes' and typ.slice.value.n > 32 and is_indexed:
                    raise EventDeclarationException(
                        "Indexed arguments are limited to 32 bytes")
                if topics_count > 4:
                    raise EventDeclarationException(
                        "Maximum of 3 topics {} given".format(topics_count -
                                                              1), arg)
                if not isinstance(arg, str):
                    raise VariableDeclarationException("Argument name invalid",
                                                       arg)
                if not typ:
                    raise InvalidTypeException("Argument must have type", arg)
                if not is_varname_valid(arg, custom_units):
                    raise VariableDeclarationException(
                        "Argument name invalid or reserved: " + arg, arg)
                if arg in (x.name for x in args):
                    raise VariableDeclarationException(
                        "Duplicate function argument name: " + arg, arg)
                parsed_type = parse_type(typ, None, custom_units=custom_units)
                args.append(VariableRecord(arg, pos, parsed_type, False))
                if isinstance(parsed_type, ByteArrayType):
                    pos += ceil32(typ.slice.value.n)
                else:
                    pos += get_size_of_type(parsed_type) * 32
        sig = name + '(' + ','.join([
            canonicalize_type(arg.typ, indexed_list[pos])
            for pos, arg in enumerate(args)
        ]) + ')'  # noqa F812
        event_id = bytes_to_int(sha3(bytes(sig, 'utf-8')))
        return cls(name, args, indexed_list, event_id, sig)
Example #19
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
Example #20
0
def test_get_size_of_type():
    assert get_size_of_type(BaseType('int128')) == 1
    assert get_size_of_type(ByteArrayType(12)) == 3
    assert get_size_of_type(ByteArrayType(33)) == 4
    assert get_size_of_type(ListType(BaseType('int128'), 10)) == 10

    _tuple = TupleType([BaseType('int128'), BaseType('decimal')])
    assert get_size_of_type(_tuple) == 2

    _struct = StructType({'a': BaseType('int128'), 'b': BaseType('decimal')})
    assert get_size_of_type(_struct) == 2

    # Don't allow unknow types.
    with raises(Exception):
        get_size_of_type(int)

    # Maps are not supported for function arguments or outputs
    with raises(Exception):
        get_size_of_type(MappingType(BaseType('int128'), BaseType('int128')))
Example #21
0
def _make_array_index_setter(target, target_token, pos, location, offset):
    if location == "memory" and isinstance(target.value, int):
        offset = target.value + 32 * get_size_of_type(target.typ.subtype) * offset
        return LLLnode.from_list([offset], typ=target.typ.subtype, location=location, pos=pos)
    else:
        return add_variable_offset(
            target_token,
            LLLnode.from_list(offset, typ="int128"),
            pos=pos,
            array_bounds_check=False,
        )
Example #22
0
def call_make_placeholder(stmt_expr, context, sig):
    if sig.output_type is None:
        return 0, 0, 0

    output_placeholder = context.new_placeholder(typ=sig.output_type)
    out_size = get_size_of_type(sig.output_type) * 32
    returner = output_placeholder

    if not sig.private and isinstance(sig.output_type, ByteArrayLike):
        returner = output_placeholder + 32

    return output_placeholder, returner, out_size
Example #23
0
def get_external_contract_call_output(sig, context):
    if not sig.output_type:
        return 0, 0, []
    output_placeholder = context.new_placeholder(typ=sig.output_type)
    output_size = get_size_of_type(sig.output_type) * 32
    if isinstance(sig.output_type, BaseType):
        returner = [0, output_placeholder]
    elif isinstance(sig.output_type, ByteArrayType):
        returner = [0, output_placeholder + 32]
    else:
        raise TypeMismatchException("Invalid output type: %s" % sig.output_type)
    return output_placeholder, output_size, returner
Example #24
0
 def new_variable(self, name, typ, internal_var=False, pos=None):
     # mangle internally generated variables so they cannot collide
     # with user variables.
     if internal_var:
         name = self._mangle(name)
     if internal_var or self.is_valid_varname(name, pos):
         var_size = 32 * get_size_of_type(typ)
         var_pos, _ = self.memory_allocator.increase_memory(var_size)
         self.vars[name] = VariableRecord(
             name=name, pos=var_pos, typ=typ, mutable=True, blockscopes=self.blockscopes.copy(),
         )
         return var_pos
Example #25
0
 def new_variable(self, name, typ, pos=None):
     if self.is_valid_varname(name, pos):
         var_size = 32 * get_size_of_type(typ)
         var_pos, _ = self.memory_allocator.increase_memory(var_size)
         self.vars[name] = VariableRecord(
             name,
             var_pos,
             typ,
             True,
             self.blockscopes.copy(),
         )
         return var_pos
Example #26
0
def serialise_var_rec(var_rec):
    if isinstance(var_rec.typ, ByteArrayType):
        type_str = "bytes[%s]" % var_rec.typ.maxlen
        _size = get_size_of_type(var_rec.typ) * 32
    elif isinstance(var_rec.typ, StringType):
        type_str = "string[%s]" % var_rec.typ.maxlen
        _size = get_size_of_type(var_rec.typ) * 32
    elif isinstance(var_rec.typ, StructType):
        type_str = "struct[%s]" % var_rec.typ.name
        _size = get_size_of_type(var_rec.typ) * 32
    elif isinstance(var_rec.typ, TupleType):
        type_str = "tuple"
        _size = get_size_of_type(var_rec.typ) * 32
    elif isinstance(var_rec.typ, ListType):
        type_str = str(var_rec.typ)
        _size = get_size_of_type(var_rec.typ) * 32
    elif isinstance(var_rec.typ, MappingType):
        type_str = str(var_rec.typ)
        _size = 0
    else:
        type_str = str(var_rec.typ)
        _size = get_size_of_type(var_rec.typ) * 32

    out = {"type": type_str, "size": _size, "position": var_rec.pos}
    return out
Example #27
0
    def from_declaration(cls, class_node, global_ctx):
        name = class_node.name
        pos = 0

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

        args = []
        indexed_list = []
        if len(class_node.body) != 1 or not isinstance(class_node.body[0],
                                                       vy_ast.Pass):
            for node in class_node.body:
                arg_item = node.target
                arg = node.target.id
                typ = node.annotation

                if isinstance(typ,
                              vy_ast.Call) and typ.get("func.id") == "indexed":
                    indexed_list.append(True)
                    typ = typ.args[0]
                else:
                    indexed_list.append(False)
                check_valid_varname(
                    arg,
                    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 TypeCheckFailure(
                        f"Duplicate function argument name: {arg}")
                # 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(keccak256(bytes(sig, "utf-8")))
        return cls(name, args, indexed_list, event_id, sig)
Example #28
0
def test_get_size_of_type():
    assert get_size_of_type(BaseType("int128")) == 1
    assert get_size_of_type(ByteArrayType(12)) == 3
    assert get_size_of_type(ByteArrayType(33)) == 4
    assert get_size_of_type(ListType(BaseType("int128"), 10)) == 10

    _tuple = TupleType([BaseType("int128"), BaseType("decimal")])
    assert get_size_of_type(_tuple) == 2

    _struct = StructType({
        "a": BaseType("int128"),
        "b": BaseType("decimal")
    }, "Foo")
    assert get_size_of_type(_struct) == 2

    # Don't allow unknown types.
    with raises(Exception):
        get_size_of_type(int)

    # Maps are not supported for function arguments or outputs
    with raises(Exception):
        get_size_of_type(MappingType(BaseType("int128"), BaseType("int128")))
Example #29
0
def pack_arguments(signature, args, context, pos, return_placeholder=True):
    placeholder_typ = ByteArrayType(maxlen=sum([get_size_of_type(arg.typ) for arg in signature.args]) * 32 + 32)
    placeholder = context.new_placeholder(placeholder_typ)
    setters = [['mstore', placeholder, signature.method_id]]
    needpos = False
    staticarray_offset = 0
    expected_arg_count = len(signature.args)
    actual_arg_count = len(args)
    if actual_arg_count != expected_arg_count:
        raise StructureException("Wrong number of args for: %s (%s args, expected %s)" % (signature.name, actual_arg_count, expected_arg_count))

    for i, (arg, typ) in enumerate(zip(args, [arg.typ for arg in signature.args])):
        if isinstance(typ, BaseType):
            setters.append(make_setter(LLLnode.from_list(placeholder + staticarray_offset + 32 + i * 32, typ=typ), arg, 'memory', pos=pos, in_function_call=True))
        elif isinstance(typ, ByteArrayType):
            setters.append(['mstore', placeholder + staticarray_offset + 32 + i * 32, '_poz'])
            arg_copy = LLLnode.from_list('_s', typ=arg.typ, location=arg.location)
            target = LLLnode.from_list(['add', placeholder + 32, '_poz'], typ=typ, location='memory')
            setters.append(['with', '_s', arg, ['seq',
                                                    make_byte_array_copier(target, arg_copy, pos),
                                                    ['set', '_poz', ['add', 32, ['ceil32', ['add', '_poz', get_length(arg_copy)]]]]]])
            needpos = True
        elif isinstance(typ, (StructType, ListType)):
            if has_dynamic_data(typ):
                raise TypeMismatchException("Cannot pack bytearray in struct")
            target = LLLnode.from_list([placeholder + 32 + staticarray_offset + i * 32], typ=typ, location='memory')
            setters.append(make_setter(target, arg, 'memory', pos=pos))
            if (isinstance(typ, ListType)):
                count = typ.count
            else:
                count = len(typ.tuple_items())
            staticarray_offset += 32 * (count - 1)
        else:
            raise TypeMismatchException("Cannot pack argument of type %r" % typ)

    # For private call usage, doesn't use a returner.
    returner = [[placeholder + 28]] if return_placeholder else []
    if needpos:
        return (
            LLLnode.from_list(['with', '_poz', len(args) * 32 + staticarray_offset, ['seq'] + setters + returner],
                                 typ=placeholder_typ, location='memory'),
            placeholder_typ.maxlen - 28,
            placeholder + 32
        )
    else:
        return (
            LLLnode.from_list(['seq'] + setters + returner, typ=placeholder_typ, location='memory'),
            placeholder_typ.maxlen - 28,
            placeholder + 32
        )
Example #30
0
def get_external_call_output(sig, context):
    if not sig.output_type:
        return 0, 0, []
    output_placeholder = context.new_placeholder(typ=sig.output_type)
    output_size = get_size_of_type(sig.output_type) * 32
    if isinstance(sig.output_type, BaseType):
        returner = [0, output_placeholder]
    elif isinstance(sig.output_type, ByteArrayLike):
        returner = [0, output_placeholder + 32]
    elif isinstance(sig.output_type, TupleLike):
        returner = [0, output_placeholder]
    elif isinstance(sig.output_type, ListType):
        returner = [0, output_placeholder]
    else:
        raise TypeCheckFailure(f"Invalid output type: {sig.output_type}")
    return output_placeholder, output_size, returner