Skip to content

Test Jumpf Target

Documentation for tests/prague/eip7692_eof_v1/eip6206_jumpf/test_jumpf_target.py.

Generate fixtures for these test cases for Prague with:

Prague only:

fill -v tests/prague/eip7692_eof_v1/eip6206_jumpf/test_jumpf_target.py --fork=Prague --evm-bin=/path/to/evm-tool-dev-version
For all forks up to and including Prague:
fill -v tests/prague/eip7692_eof_v1/eip6206_jumpf/test_jumpf_target.py --until=Prague --evm-bin=/path/to/evm-tool-dev-version

EOF JUMPF tests covering JUMPF target rules.

test_jumpf_target_rules(eof_state_test, source_outputs, target_outputs)

Validate the target section rules of JUMPF, and execute valid cases. We are not testing stack so a lot of the logic is to get correct stack values.

Source code in tests/prague/eip7692_eof_v1/eip6206_jumpf/test_jumpf_target.py
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
@pytest.mark.parametrize(
    "target_outputs",
    [NON_RETURNING_SECTION, 0, 2, 4, 127],
    ids=lambda x: "to-%s" % ("N" if x == NON_RETURNING_SECTION else x),
)
@pytest.mark.parametrize(
    "source_outputs",
    [NON_RETURNING_SECTION, 0, 2, 4, 127],
    ids=lambda x: "so-%s" % ("N" if x == NON_RETURNING_SECTION else x),
)
def test_jumpf_target_rules(
    eof_state_test: EOFStateTestFiller,
    source_outputs: int,
    target_outputs: int,
):
    """
    Validate the target section rules of JUMPF, and execute valid cases.
    We are not testing stack so a lot of the logic is to get correct stack values.
    """
    source_non_returning = source_outputs == NON_RETURNING_SECTION
    source_height = 0 if source_non_returning else source_outputs
    source_section_index = 1

    target_non_returning = target_outputs == NON_RETURNING_SECTION
    target_height = 0 if target_non_returning else target_outputs
    target_section_index = 2

    # Because we are testing the target and not the stack height validation we need to do some work
    # to make sure the stack passes validation.

    # `source_extra_push` is how many more pushes we need to match our stack commitments
    source_extra_push = max(0, source_height - target_height)
    source_section = Section.Code(
        code=Op.PUSH0 * (source_height)
        + Op.CALLDATALOAD(0)
        + Op.RJUMPI[1]
        + (Op.STOP if source_non_returning else Op.RETF)
        + Op.PUSH0 * source_extra_push
        + Op.JUMPF[target_section_index],
        code_inputs=0,
        code_outputs=source_outputs,
        max_stack_height=source_height + max(1, source_extra_push),
    )

    # `delta` is how many stack items the target output is from the input height, and tracks the
    # number of pushes or (if negative) pops the target needs to do to match output commitments
    delta = 0 if target_non_returning or source_non_returning else target_outputs - source_height
    target_section = Section.Code(
        code=((Op.PUSH0 * delta) if delta >= 0 else (Op.POP * -delta))
        + Op.CALLF[3]
        + (Op.STOP if target_non_returning else Op.RETF),
        code_inputs=source_height,
        code_outputs=target_outputs,
        max_stack_height=max(source_height, source_height + delta),
    )

    base_code = (
        Op.JUMPF[source_section_index]
        if source_non_returning
        else (Op.CALLF[source_section_index](0, 0) + Op.STOP)
    )
    base_height = 0 if source_non_returning else 2 + source_outputs
    container = Container(
        name="so-%s_to-%s"
        % (
            "N" if source_non_returning else source_outputs,
            "N" if target_non_returning else target_outputs,
        ),
        sections=[
            Section.Code(
                code=base_code,
                max_stack_height=base_height,
            ),
            source_section,
            target_section,
            Section.Code(
                code=Op.SSTORE(slot_code_worked, value_code_worked) + Op.RETF,
                code_outputs=0,
            ),
        ],
    )
    if target_non_returning or source_non_returning:
        if not target_non_returning and source_non_returning:
            # both as non-returning handled above
            container.validity_error = EOFException.INVALID_NON_RETURNING_FLAG
    elif source_outputs < target_outputs:
        container.validity_error = EOFException.JUMPF_DESTINATION_INCOMPATIBLE_OUTPUTS

    eof_state_test(
        data=container,
        container_post=Account(storage={slot_code_worked: value_code_worked}),
        tx_data=b"\1",
    )

test_jumpf_multi_target_rules(eof_state_test)

NOT IMPLEMENTED: Test a section that contains multiple JUMPF to different targets with different outputs.

Source code in tests/prague/eip7692_eof_v1/eip6206_jumpf/test_jumpf_target.py
116
117
118
119
120
121
122
123
124
@pytest.mark.skip("Not implemented")
def test_jumpf_multi_target_rules(
    eof_state_test: EOFStateTestFiller,
):
    """
    NOT IMPLEMENTED:
    Test a section that contains multiple JUMPF to different targets with different outputs.
    """
    pass