Example #1
0
def _pack_arguments(contract_sig, args, context, pos):
    # abi encoding just treats all args as a big tuple
    args_tuple_t = TupleType([x.typ for x in args])
    args_as_tuple = LLLnode.from_list(["multi"] + [x for x in args],
                                      typ=args_tuple_t)
    args_abi_t = args_tuple_t.abi_type

    # sanity typecheck - make sure the arguments can be assigned
    dst_tuple_t = TupleType([arg.typ for arg in contract_sig.args][:len(args)])
    check_assign(dummy_node_for_type(dst_tuple_t), args_as_tuple)

    if contract_sig.return_type is not None:
        return_abi_t = calculate_type_for_external_return(
            contract_sig.return_type).abi_type

        # we use the same buffer for args and returndata,
        # so allocate enough space here for the returndata too.
        buflen = max(args_abi_t.size_bound(), return_abi_t.size_bound())
    else:
        buflen = args_abi_t.size_bound()

    buflen += 32  # padding for the method id

    buf_t = get_type_for_exact_size(buflen)
    buf = context.new_internal_variable(buf_t)

    args_ofst = buf + 28
    args_len = args_abi_t.size_bound() + 4

    abi_signature = contract_sig.name + dst_tuple_t.abi_type.selector_name()

    # layout:
    # 32 bytes                 | args
    # 0x..00<method_id_4bytes> | args
    # the reason for the left padding is just so the alignment is easier.
    # if we were only targeting constantinople, we could align
    # to buf (and also keep code size small) by using
    # (mstore buf (shl signature.method_id 224))
    mstore_method_id = [["mstore", buf, util.abi_method_id(abi_signature)]]

    if len(args) == 0:
        encode_args = ["pass"]
    else:
        encode_args = abi_encode(buf + 32,
                                 args_as_tuple,
                                 context,
                                 pos,
                                 bufsz=buflen)

    return buf, mstore_method_id + [encode_args], args_ofst, args_len
Example #2
0
 def parse_Tuple(self):
     tuple_elements = [
         Expr(x, self.context).ir_node for x in self.expr.elements
     ]
     typ = TupleType([x.typ for x in tuple_elements], is_literal=True)
     multi_ir = IRnode.from_list(["multi"] + tuple_elements, typ=typ)
     return multi_ir
Example #3
0
 def parse_Tuple(self):
     tuple_elements = [
         Expr(x, self.context).lll_node for x in self.expr.elements
     ]
     typ = TupleType([x.typ for x in tuple_elements], is_literal=True)
     multi_lll = LLLnode.from_list(["multi"] + tuple_elements,
                                   typ=typ,
                                   pos=getpos(self.expr))
     return multi_lll
Example #4
0
def test_type_storage_sizes():
    assert BaseType("int128").storage_size_in_words == 1
    assert ByteArrayType(12).storage_size_in_words == 2
    assert ByteArrayType(33).storage_size_in_words == 3
    assert SArrayType(BaseType("int128"), 10).storage_size_in_words == 10

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

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

    # Don't allow unknown types.
    with raises(Exception):
        _ = int.storage_size_in_words

    # Maps are not supported for function arguments or outputs
    with raises(Exception):
        _ = MappingType(BaseType("int128"),
                        BaseType("int128")).storage_size_in_words
Example #5
0
def test_canonicalize_type():
    # TODO add more types

    # Test ABI format of multiple args.
    c = TupleType([BaseType("int128"), BaseType("address")])
    assert c.abi_type.selector_name() == "(int128,address)"
Example #6
0
def test_tuple_node_types():
    node1 = TupleType([BaseType("int128"), BaseType("decimal")])
    node2 = TupleType([BaseType("int128"), BaseType("decimal")])

    assert node1 == node2
    assert str(node1) == "(int128, decimal)"
Example #7
0
def calculate_type_for_external_return(ir_typ):
    if needs_external_call_wrap(ir_typ):
        return TupleType([ir_typ])
    return ir_typ
Example #8
0
def ir_tuple_from_args(args):
    typ = TupleType([x.typ for x in args])
    return IRnode.from_list(["multi"] + [x for x in args], typ=typ)
Example #9
0
def lll_for_self_call(stmt_expr, context):
    from vyper.codegen.expr import Expr  # TODO rethink this circular import

    pos = getpos(stmt_expr)

    # ** Internal Call **
    # Steps:
    # - copy arguments into the soon-to-be callee
    # - allocate return buffer
    # - push jumpdest (callback ptr) and return buffer location
    # - jump to label
    # - (private function will fill return buffer and jump back)

    method_name = stmt_expr.func.attr

    pos_args_lll = [Expr(x, context).lll_node for x in stmt_expr.args]

    sig, kw_vals = context.lookup_internal_function(method_name, pos_args_lll)

    kw_args_lll = [Expr(x, context).lll_node for x in kw_vals]

    args_lll = pos_args_lll + kw_args_lll

    args_tuple_t = TupleType([x.typ for x in args_lll])
    args_as_tuple = LLLnode.from_list(["multi"] + [x for x in args_lll], typ=args_tuple_t)

    # register callee to help calculate our starting frame offset
    context.register_callee(sig.frame_size)

    if context.is_constant() and sig.mutability not in ("view", "pure"):
        raise StateAccessViolation(
            f"May not call state modifying function "
            f"'{method_name}' within {context.pp_constancy()}.",
            getpos(stmt_expr),
        )

    # TODO move me to type checker phase
    if not sig.internal:
        raise StructureException("Cannot call external functions via 'self'", stmt_expr)

    return_label = _generate_label(f"{sig.internal_function_label}_call")

    # allocate space for the return buffer
    # TODO allocate in stmt and/or expr.py
    if sig.return_type is not None:
        return_buffer = LLLnode.from_list(
            context.new_internal_variable(sig.return_type), annotation=f"{return_label}_return_buf"
        )
    else:
        return_buffer = None

    # note: dst_tuple_t != args_tuple_t
    dst_tuple_t = TupleType([arg.typ for arg in sig.args])
    args_dst = LLLnode(sig.frame_start, typ=dst_tuple_t, location="memory")

    # if one of the arguments is a self call, the argument
    # buffer could get borked. to prevent against that,
    # write args to a temporary buffer until all the arguments
    # are fully evaluated.
    if args_as_tuple.contains_self_call:
        copy_args = ["seq"]
        # TODO deallocate me
        tmp_args_buf = LLLnode(
            context.new_internal_variable(dst_tuple_t),
            typ=dst_tuple_t,
            location="memory",
        )
        copy_args.append(
            # --> args evaluate here <--
            make_setter(tmp_args_buf, args_as_tuple, pos)
        )

        copy_args.append(make_setter(args_dst, tmp_args_buf, pos))

    else:
        copy_args = make_setter(args_dst, args_as_tuple, pos)

    goto_op = ["goto", sig.internal_function_label]
    # pass return buffer to subroutine
    if return_buffer is not None:
        goto_op += [return_buffer]
    # pass return label to subroutine
    goto_op += [push_label_to_stack(return_label)]

    call_sequence = [
        "seq",
        copy_args,
        goto_op,
        ["label", return_label, ["var_list"], "pass"],
    ]
    if return_buffer is not None:
        # push return buffer location to stack
        call_sequence += [return_buffer]

    o = LLLnode.from_list(
        call_sequence,
        typ=sig.return_type,
        location="memory",
        pos=pos,
        annotation=stmt_expr.get("node_source_code"),
        add_gas_estimate=sig.gas,
    )
    o.is_self_call = True
    return o
Example #10
0
def calculate_type_for_external_return(lll_typ):
    if _needs_external_call_wrap(lll_typ):
        return TupleType([lll_typ])
    return lll_typ