Пример #1
0
def parse_other_functions(o,
                          otherfuncs,
                          sigs,
                          external_contracts,
                          origcode,
                          global_ctx,
                          default_function):
    sub = ['seq', func_init_lll()]
    add_gas = func_init_lll().gas

    for _def in otherfuncs:
        sub.append(
            parse_function(_def, {**{'self': sigs}, **external_contracts}, origcode, global_ctx)
        )
        sub[-1].total_gas += add_gas
        add_gas += 30
        for sig in sig_utils.generate_default_arg_sigs(_def, external_contracts, global_ctx):
            sig.gas = sub[-1].total_gas
            sigs[sig.sig] = sig

    # Add fallback function
    if default_function:
        default_func = parse_function(
            default_function[0],
            {**{'self': sigs}, **external_contracts},
            origcode,
            global_ctx,
        )
        fallback = default_func
    else:
        fallback = LLLnode.from_list(['revert', 0, 0], typ=None, annotation='Default function')
    sub.append(['seq_unchecked', ['label', 'fallback'], fallback])
    o.append(['return', 0, ['lll', sub, 0]])
    return o, sub
Пример #2
0
def parse_other_functions(
    o, otherfuncs, sigs, external_interfaces, origcode, global_ctx, default_function
):
    sub = ["seq", func_init_lll()]
    add_gas = func_init_lll().gas

    for _def in otherfuncs:
        sub.append(
            parse_function(_def, {**{"self": sigs}, **external_interfaces}, origcode, global_ctx)
        )
        sub[-1].total_gas += add_gas
        add_gas += 30
        for sig in sig_utils.generate_default_arg_sigs(_def, external_interfaces, global_ctx):
            sig.gas = sub[-1].total_gas
            sigs[sig.sig] = sig

    # Add fallback function
    if default_function:
        default_func = parse_function(
            default_function[0], {**{"self": sigs}, **external_interfaces}, origcode, global_ctx,
        )
        fallback = default_func
    else:
        fallback = LLLnode.from_list(["revert", 0, 0], typ=None, annotation="Default function")
    sub.append(["seq_unchecked", ["label", "fallback"], fallback])
    o.append(["return", 0, ["lll", sub, 0]])
    return o, sub
Пример #3
0
def parse_tree_to_lll(code, origcode, runtime_only=False, interface_codes=None):
    global_ctx = GlobalContext.get_global_context(code, interface_codes=interface_codes)
    _names_def = [_def.name for _def in global_ctx._defs]
    # Checks for duplicate function names
    if len(set(_names_def)) < len(_names_def):
        raise FunctionDeclarationException(
            "Duplicate function name: %s" % (
                [name for name in _names_def if _names_def.count(name) > 1][0]
            )
        )
    _names_events = [_event.target.id for _event in global_ctx._events]
    # Checks for duplicate event names
    if len(set(_names_events)) < len(_names_events):
        raise EventDeclarationException(
            "Duplicate event name: %s" % (
                [name for name in _names_events if _names_events.count(name) > 1][0]
            )
        )
    # Initialization function
    initfunc = [_def for _def in global_ctx._defs if is_initializer(_def)]
    # Default function
    defaultfunc = [_def for _def in global_ctx._defs if is_default_func(_def)]
    # Regular functions
    otherfuncs = [
        _def
        for _def
        in global_ctx._defs
        if not is_initializer(_def) and not is_default_func(_def)
    ]
    sigs = {}
    external_contracts = {}
    # Create the main statement
    o = ['seq']
    if global_ctx._events:
        sigs = parse_events(sigs, global_ctx)
    if global_ctx._contracts or global_ctx._interfaces:
        external_contracts = parse_external_contracts(external_contracts, global_ctx)
    # If there is an init func...
    if initfunc:
        o.append(INITIALIZER_LLL)
        o.append(
            parse_function(
                initfunc[0],
                {**{'self': sigs}, **external_contracts},
                origcode,
                global_ctx,
            )
        )
    # If there are regular functions...
    if otherfuncs or defaultfunc:
        o = parse_other_functions(
            o, otherfuncs, sigs, external_contracts, origcode, global_ctx, defaultfunc, runtime_only
        )

    # Check if interface of contract is correct.
    check_valid_contract_interface(global_ctx, sigs)

    return LLLnode.from_list(o, typ=None)
Пример #4
0
def parse_other_functions(o, otherfuncs, sigs, external_contracts, origcode,
                          global_ctx, default_function, runtime_only):
    sub = ['seq', FUNC_INIT_LLL]
    add_gas = FUNC_INIT_LLL.gas

    for _def in otherfuncs:
        sub.append(
            parse_function(_def, {
                **{
                    'self': sigs
                },
                **external_contracts
            }, origcode, global_ctx))
        sub[-1].total_gas += add_gas
        add_gas += 30
        for sig in sig_utils.generate_default_arg_sigs(_def,
                                                       external_contracts,
                                                       global_ctx):
            sig.gas = sub[-1].total_gas
            sigs[sig.sig] = sig

    # Add fallback function
    if default_function:
        default_func = parse_function(
            default_function[0],
            {
                **{
                    'self': sigs
                },
                **external_contracts
            },
            origcode,
            global_ctx,
        )
        sub.append(default_func)
    else:
        sub.append(
            LLLnode.from_list(['revert', 0, 0],
                              typ=None,
                              annotation='Default function'))
    if runtime_only:
        return sub
    else:
        o.append(['return', 0, ['lll', sub, 0]])
        return o
Пример #5
0
def parse_tree_to_lll(source_code: str, global_ctx: GlobalContext) -> Tuple[LLLnode, LLLnode]:
    _names_def = [_def.name for _def in global_ctx._defs]
    # Checks for duplicate function names
    if len(set(_names_def)) < len(_names_def):
        raise FunctionDeclarationException(
            "Duplicate function name: "
            f"{[name for name in _names_def if _names_def.count(name) > 1][0]}"
        )
    _names_events = [_event.name for _event in global_ctx._events]
    # Checks for duplicate event names
    if len(set(_names_events)) < len(_names_events):
        raise EventDeclarationException(
            f"""Duplicate event name:
            {[name for name in _names_events if _names_events.count(name) > 1][0]}"""
        )
    # Initialization function
    initfunc = [_def for _def in global_ctx._defs if is_initializer(_def)]
    # Default function
    defaultfunc = [_def for _def in global_ctx._defs if is_default_func(_def)]
    # Regular functions
    otherfuncs = [
        _def for _def in global_ctx._defs if not is_initializer(_def) and not is_default_func(_def)
    ]
    sigs: dict = {}
    external_interfaces: dict = {}
    # Create the main statement
    o = ["seq"]
    if global_ctx._events:
        sigs = parse_events(sigs, global_ctx)
    if global_ctx._contracts or global_ctx._interfaces:
        external_interfaces = parse_external_interfaces(external_interfaces, global_ctx)
    # If there is an init func...
    if initfunc:
        o.append(init_func_init_lll())
        o.append(
            parse_function(
                initfunc[0], {**{"self": sigs}, **external_interfaces}, source_code, global_ctx,
            )
        )

    # If there are regular functions...
    if otherfuncs or defaultfunc:
        o, runtime = parse_other_functions(
            o, otherfuncs, sigs, external_interfaces, source_code, global_ctx, defaultfunc
        )
    else:
        runtime = o.copy()

    # Check if interface of contract is correct.
    check_valid_contract_interface(global_ctx, sigs)

    return LLLnode.from_list(o, typ=None), LLLnode.from_list(runtime, typ=None)
Пример #6
0
def parse_tree_to_lll(global_ctx: GlobalContext) -> Tuple[LLLnode, LLLnode]:
    _names_def = [_def.name for _def in global_ctx._defs]
    # Checks for duplicate function names
    if len(set(_names_def)) < len(_names_def):
        raise FunctionDeclarationException(
            "Duplicate function name: "
            f"{[name for name in _names_def if _names_def.count(name) > 1][0]}"
        )
    _names_events = [_event.name for _event in global_ctx._events]
    # Checks for duplicate event names
    if len(set(_names_events)) < len(_names_events):
        raise EventDeclarationException(f"""Duplicate event name:
            {[name for name in _names_events if _names_events.count(name) > 1][0]}"""
                                        )
    # Initialization function
    initfunc = [_def for _def in global_ctx._defs if is_initializer(_def)]
    # Default function
    defaultfunc = [_def for _def in global_ctx._defs if is_default_func(_def)]
    # Regular functions
    otherfuncs = [
        _def for _def in global_ctx._defs
        if not is_initializer(_def) and not is_default_func(_def)
    ]

    # check if any functions in the contract are payable - if not, we do a single
    # ASSERT CALLVALUE ISZERO at the start of the bytecode rather than at the start
    # of each function
    is_contract_payable = next(
        (True for i in global_ctx._defs if FunctionSignature.from_definition(
            i, custom_structs=global_ctx._structs).mutability == "payable"),
        False,
    )

    sigs: dict = {}
    external_interfaces: dict = {}
    # Create the main statement
    o = ["seq"]
    if global_ctx._contracts or global_ctx._interfaces:
        external_interfaces = parse_external_interfaces(
            external_interfaces, global_ctx)
    # If there is an init func...
    if initfunc:
        o.append(init_func_init_lll())
        o.append(
            parse_function(
                initfunc[0],
                {
                    **{
                        "self": sigs
                    },
                    **external_interfaces
                },
                global_ctx,
                False,
            ))

    # If there are regular functions...
    if otherfuncs or defaultfunc:
        o, runtime = parse_other_functions(
            o,
            otherfuncs,
            sigs,
            external_interfaces,
            global_ctx,
            defaultfunc,
            is_contract_payable,
        )
    else:
        runtime = o.copy()

    if not is_contract_payable:
        # if no functions in the contract are payable, assert that callvalue is
        # zero at the beginning of the bytecode
        runtime.insert(1, ["assert", ["iszero", "callvalue"]])

    return LLLnode.from_list(o, typ=None), LLLnode.from_list(runtime, typ=None)
Пример #7
0
def parse_other_functions(o, otherfuncs, sigs, external_interfaces, global_ctx,
                          default_function):
    # check for payable/nonpayable external functions to optimize nonpayable assertions
    func_types = [i._metadata["type"] for i in global_ctx._defs]
    mutabilities = [
        i.mutability for i in func_types
        if i.visibility == FunctionVisibility.EXTERNAL
    ]
    has_payable = next(
        (True for i in mutabilities if i == StateMutability.PAYABLE), False)
    has_nonpayable = next(
        (True for i in mutabilities if i != StateMutability.PAYABLE), False)
    is_default_payable = (default_function is not None
                          and default_function._metadata["type"].mutability
                          == StateMutability.PAYABLE)
    # when a contract has a payable default function and at least one nonpayable
    # external function, we must perform the nonpayable check on every function
    check_per_function = is_default_payable and has_nonpayable

    # generate LLL for regular functions
    payable_func_sub = ["seq"]
    external_func_sub = ["seq"]
    internal_func_sub = ["seq"]
    add_gas = func_init_lll().gas

    for func_node in otherfuncs:
        func_type = func_node._metadata["type"]
        func_lll = parse_function(func_node, {
            **{
                "self": sigs
            },
            **external_interfaces
        }, global_ctx, check_per_function)
        if func_type.visibility == FunctionVisibility.INTERNAL:
            internal_func_sub.append(func_lll)
        elif func_type.mutability == StateMutability.PAYABLE:
            add_gas += 30
            payable_func_sub.append(func_lll)
        else:
            external_func_sub.append(func_lll)
            add_gas += 30
        func_lll.total_gas += add_gas
        for sig in sig_utils.generate_default_arg_sigs(func_node,
                                                       external_interfaces,
                                                       global_ctx):
            sig.gas = func_lll.total_gas
            sigs[sig.sig] = sig

    # generate LLL for fallback function
    if default_function:
        fallback_lll = parse_function(
            default_function,
            {
                **{
                    "self": sigs
                },
                **external_interfaces
            },
            global_ctx,
            # include a nonpayble check here if the contract only has a default function
            check_per_function or not otherfuncs,
        )
    else:
        fallback_lll = LLLnode.from_list(["revert", 0, 0],
                                         typ=None,
                                         annotation="Default function")

    if check_per_function:
        external_seq = ["seq", payable_func_sub, external_func_sub]
    else:
        # payable functions are placed prior to nonpayable functions
        # and seperated by a nonpayable assertion
        external_seq = ["seq"]
        if has_payable:
            external_seq.append(payable_func_sub)
        if has_nonpayable:
            external_seq.extend([["assert", ["iszero", "callvalue"]],
                                 external_func_sub])

    # bytecode is organized by: external functions, fallback fn, internal functions
    # this way we save gas and reduce bytecode by not jumping over internal functions
    main_seq = [
        "seq",
        func_init_lll(),
        ["with", "_func_sig", ["mload", 0], external_seq],
        ["seq_unchecked", ["label", "fallback"], fallback_lll],
        internal_func_sub,
    ]

    o.append(["return", 0, ["lll", main_seq, 0]])
    return o, main_seq